1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_comphelper.hxx"
26 
27 #include <comphelper/logging.hxx>
28 #include <comphelper/componentcontext.hxx>
29 
30 /** === begin UNO includes === **/
31 #include <com/sun/star/logging/LoggerPool.hpp>
32 #include <com/sun/star/logging/LogLevel.hpp>
33 #include <com/sun/star/resource/XResourceBundle.hpp>
34 #include <com/sun/star/resource/XResourceBundleLoader.hpp>
35 /** === end UNO includes === **/
36 
37 #include <rtl/ustrbuf.hxx>
38 
39 //........................................................................
40 namespace comphelper
41 {
42 //........................................................................
43 
44 	/** === begin UNO using === **/
45     using ::com::sun::star::uno::Reference;
46     using ::com::sun::star::uno::XComponentContext;
47     using ::com::sun::star::logging::XLoggerPool;
48     using ::com::sun::star::logging::LoggerPool;
49     using ::com::sun::star::logging::XLogger;
50     using ::com::sun::star::uno::UNO_QUERY_THROW;
51     using ::com::sun::star::uno::Exception;
52     using ::com::sun::star::logging::XLogHandler;
53     using ::com::sun::star::resource::XResourceBundle;
54     using ::com::sun::star::resource::XResourceBundleLoader;
55 	/** === end UNO using === **/
56     namespace LogLevel = ::com::sun::star::logging::LogLevel;
57 
58 	//====================================================================
59 	//= EventLogger_Impl - declaration
60 	//====================================================================
61     class EventLogger_Impl
62     {
63     private:
64         ::comphelper::ComponentContext  m_aContext;
65         ::rtl::OUString                 m_sLoggerName;
66         Reference< XLogger >            m_xLogger;
67 
68     public:
EventLogger_Impl(const Reference<XComponentContext> & _rxContext,const::rtl::OUString & _rLoggerName)69         EventLogger_Impl( const Reference< XComponentContext >& _rxContext, const ::rtl::OUString& _rLoggerName )
70             :m_aContext( _rxContext )
71             ,m_sLoggerName( _rLoggerName )
72         {
73             impl_createLogger_nothrow();
74         }
75 
isValid() const76         inline bool isValid() const { return m_xLogger.is(); }
getName() const77         inline const ::rtl::OUString&  getName() const { return m_sLoggerName; }
getLogger() const78         inline const Reference< XLogger >& getLogger() const { return m_xLogger; }
getContext() const79         inline const ::comphelper::ComponentContext& getContext() const { return m_aContext; }
80 
81     private:
82         void    impl_createLogger_nothrow();
83     };
84 
85 	//====================================================================
86 	//= EventLogger_Impl - implementation
87 	//====================================================================
88 	//--------------------------------------------------------------------
impl_createLogger_nothrow()89     void EventLogger_Impl::impl_createLogger_nothrow()
90     {
91         try
92         {
93             Reference< XLoggerPool > xPool( LoggerPool::get( m_aContext.getUNOContext() ), UNO_QUERY_THROW );
94             if ( !m_sLoggerName.isEmpty() )
95                 m_xLogger = xPool->getNamedLogger( m_sLoggerName );
96             else
97                 m_xLogger = xPool->getDefaultLogger();
98         }
99         catch( const Exception& e )
100         {
101             (void)e;
102             OSL_ENSURE( false, "EventLogger_Impl::impl_createLogger_nothrow: caught an exception!" );
103         }
104     }
105 
106 	//====================================================================
107 	//= EventLogger
108 	//====================================================================
109 	//--------------------------------------------------------------------
EventLogger(const Reference<XComponentContext> & _rxContext,const::rtl::OUString & _rLoggerName)110     EventLogger::EventLogger( const Reference< XComponentContext >& _rxContext, const ::rtl::OUString& _rLoggerName )
111         :m_pImpl( new EventLogger_Impl( _rxContext, _rLoggerName ) )
112     {
113     }
114 
115 	//--------------------------------------------------------------------
EventLogger(const Reference<XComponentContext> & _rxContext,const sal_Char * _pAsciiLoggerName)116     EventLogger::EventLogger( const Reference< XComponentContext >& _rxContext, const sal_Char* _pAsciiLoggerName )
117         :m_pImpl( new EventLogger_Impl( _rxContext, ::rtl::OUString::createFromAscii( _pAsciiLoggerName ) ) )
118     {
119     }
120 
121 	//--------------------------------------------------------------------
~EventLogger()122     EventLogger::~EventLogger()
123     {
124     }
125 
126 	//--------------------------------------------------------------------
getName() const127     const ::rtl::OUString& EventLogger::getName() const
128     {
129         return m_pImpl->getName();
130     }
131 
132 	//--------------------------------------------------------------------
getLogLevel() const133     sal_Int32 EventLogger::getLogLevel() const
134     {
135         try
136         {
137             if ( m_pImpl->isValid() )
138                 return m_pImpl->getLogger()->getLevel();
139         }
140         catch( const Exception& e )
141         {
142             (void)e;
143             OSL_ENSURE( false, "EventLogger::getLogLevel: caught an exception!" );
144         }
145 
146         return LogLevel::OFF;
147     }
148 
149 	//--------------------------------------------------------------------
setLogLevel(const sal_Int32 _nLogLevel) const150     void EventLogger::setLogLevel( const sal_Int32 _nLogLevel ) const
151     {
152         try
153         {
154             if ( m_pImpl->isValid() )
155                 m_pImpl->getLogger()->setLevel( _nLogLevel );
156         }
157         catch( const Exception& e )
158         {
159             (void)e;
160             OSL_ENSURE( false, "EventLogger::setLogLevel: caught an exception!" );
161         }
162     }
163 
164 	//--------------------------------------------------------------------
isLoggable(const sal_Int32 _nLogLevel) const165     bool EventLogger::isLoggable( const sal_Int32 _nLogLevel ) const
166     {
167         if ( !m_pImpl->isValid() )
168             return false;
169 
170         try
171         {
172             return m_pImpl->getLogger()->isLoggable( _nLogLevel );
173         }
174         catch( const Exception& e )
175         {
176             (void)e;
177             OSL_ENSURE( false, "EventLogger::isLoggable: caught an exception!" );
178         }
179 
180         return false;
181     }
182 
183 	//--------------------------------------------------------------------
addLogHandler(const Reference<XLogHandler> & _rxLogHandler)184     bool EventLogger::addLogHandler( const Reference< XLogHandler >& _rxLogHandler )
185     {
186         try
187         {
188             if ( m_pImpl->isValid() )
189             {
190                 m_pImpl->getLogger()->addLogHandler( _rxLogHandler );
191                 return true;
192             }
193         }
194         catch( const Exception& e )
195         {
196             (void)e;
197             OSL_ENSURE( false, "EventLogger::addLogHandler: caught an exception!" );
198         }
199         return false;
200     }
201 
202 	//--------------------------------------------------------------------
removeLogHandler(const Reference<XLogHandler> & _rxLogHandler)203     bool EventLogger::removeLogHandler( const Reference< XLogHandler >& _rxLogHandler )
204     {
205         try
206         {
207             if ( m_pImpl->isValid() )
208             {
209                 m_pImpl->getLogger()->removeLogHandler( _rxLogHandler );
210                 return true;
211             }
212         }
213         catch( const Exception& e )
214         {
215             (void)e;
216             OSL_ENSURE( false, "EventLogger::removeLogHandler: caught an exception!" );
217         }
218         return false;
219     }
220 
221     //--------------------------------------------------------------------
222     namespace
223     {
lcl_replaceParameter(::rtl::OUString & _inout_Message,const::rtl::OUString & _rPlaceHolder,const::rtl::OUString & _rReplacement)224         void    lcl_replaceParameter( ::rtl::OUString& _inout_Message, const ::rtl::OUString& _rPlaceHolder, const ::rtl::OUString& _rReplacement )
225         {
226             sal_Int32 nPlaceholderPosition = _inout_Message.indexOf( _rPlaceHolder );
227             OSL_ENSURE( nPlaceholderPosition >= 0, "lcl_replaceParameter: placeholder not found!" );
228             if ( nPlaceholderPosition < 0 )
229                 return;
230 
231             _inout_Message = _inout_Message.replaceAt( nPlaceholderPosition, _rPlaceHolder.getLength(), _rReplacement );
232         }
233     }
234 
235 	//--------------------------------------------------------------------
impl_log(const sal_Int32 _nLogLevel,const sal_Char * _pSourceClass,const sal_Char * _pSourceMethod,const::rtl::OUString & _rMessage,const OptionalString & _rArgument1,const OptionalString & _rArgument2,const OptionalString & _rArgument3,const OptionalString & _rArgument4,const OptionalString & _rArgument5,const OptionalString & _rArgument6) const236     bool EventLogger::impl_log( const sal_Int32 _nLogLevel,
237         const sal_Char* _pSourceClass, const sal_Char* _pSourceMethod, const ::rtl::OUString& _rMessage,
238         const OptionalString& _rArgument1, const OptionalString& _rArgument2,
239         const OptionalString& _rArgument3, const OptionalString& _rArgument4,
240         const OptionalString& _rArgument5, const OptionalString& _rArgument6 ) const
241     {
242         // (if ::rtl::OUString had an indexOfAscii, we could save those ugly statics ...)
243         static ::rtl::OUString sPH1( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "$1$" ) ) );
244         static ::rtl::OUString sPH2( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "$2$" ) ) );
245         static ::rtl::OUString sPH3( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "$3$" ) ) );
246         static ::rtl::OUString sPH4( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "$4$" ) ) );
247         static ::rtl::OUString sPH5( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "$5$" ) ) );
248         static ::rtl::OUString sPH6( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "$6$" ) ) );
249 
250         ::rtl::OUString sMessage( _rMessage );
251         if ( !!_rArgument1 )
252             lcl_replaceParameter( sMessage, sPH1, *_rArgument1 );
253 
254         if ( !!_rArgument2 )
255             lcl_replaceParameter( sMessage, sPH2, *_rArgument2 );
256 
257         if ( !!_rArgument3 )
258             lcl_replaceParameter( sMessage, sPH3, *_rArgument3 );
259 
260         if ( !!_rArgument4 )
261             lcl_replaceParameter( sMessage, sPH4, *_rArgument4 );
262 
263         if ( !!_rArgument5 )
264             lcl_replaceParameter( sMessage, sPH5, *_rArgument5 );
265 
266         if ( !!_rArgument6 )
267             lcl_replaceParameter( sMessage, sPH6, *_rArgument6 );
268 
269         try
270         {
271             Reference< XLogger > xLogger( m_pImpl->getLogger() );
272             OSL_PRECOND( xLogger.is(), "EventLogger::impl_log: should never be called without a logger!" );
273             if ( _pSourceClass && _pSourceMethod )
274             {
275                 xLogger->logp(
276                     _nLogLevel,
277                     ::rtl::OUString::createFromAscii( _pSourceClass ),
278                     ::rtl::OUString::createFromAscii( _pSourceMethod ),
279                     sMessage
280                 );
281             }
282             else
283             {
284                 xLogger->log( _nLogLevel, sMessage );
285             }
286         }
287         catch( const Exception& e )
288         {
289             (void)e;
290             OSL_ENSURE( false, "EventLogger::impl_log: caught an exception!" );
291         }
292 
293         return false;
294     }
295 
296 	//====================================================================
297 	//= ResourceBasedEventLogger_Data
298 	//====================================================================
299     struct ResourceBasedEventLogger_Data
300     {
301         /// the base name of the resource bundle
302         ::rtl::OUString                 sBundleBaseName;
303         /// did we already attempt to load the bundle?
304         bool                            bBundleLoaded;
305         /// the lazily loaded bundle
306         Reference< XResourceBundle >    xBundle;
307 
ResourceBasedEventLogger_Datacomphelper::ResourceBasedEventLogger_Data308         ResourceBasedEventLogger_Data()
309             :sBundleBaseName()
310             ,bBundleLoaded( false )
311             ,xBundle()
312         {
313         }
314     };
315 
316     //--------------------------------------------------------------------
lcl_loadBundle_nothrow(const ComponentContext & _rContext,ResourceBasedEventLogger_Data & _rLoggerData)317     bool    lcl_loadBundle_nothrow( const ComponentContext& _rContext, ResourceBasedEventLogger_Data& _rLoggerData )
318     {
319         if ( _rLoggerData.bBundleLoaded )
320             return _rLoggerData.xBundle.is();
321 
322         // no matter what happens below, don't attempt creation ever again
323         _rLoggerData.bBundleLoaded = true;
324 
325         try
326         {
327             Reference< XResourceBundleLoader > xLoader( _rContext.getSingleton( "com.sun.star.resource.OfficeResourceLoader" ), UNO_QUERY_THROW );
328             _rLoggerData.xBundle = Reference< XResourceBundle >( xLoader->loadBundle_Default( _rLoggerData.sBundleBaseName ), UNO_QUERY_THROW );
329         }
330         catch( const Exception& e )
331         {
332             (void)e;
333             OSL_ENSURE( false, "lcl_loadBundle_nothrow: caught an exception!" );
334         }
335 
336         return _rLoggerData.xBundle.is();
337     }
338 
339     //--------------------------------------------------------------------
lcl_loadString_nothrow(const Reference<XResourceBundle> & _rxBundle,const sal_Int32 _nMessageResID)340     ::rtl::OUString lcl_loadString_nothrow( const Reference< XResourceBundle >& _rxBundle, const sal_Int32 _nMessageResID )
341     {
342         OSL_PRECOND( _rxBundle.is(), "lcl_loadString_nothrow: this will crash!" );
343         ::rtl::OUString sMessage;
344         try
345         {
346             ::rtl::OUStringBuffer aBuffer;
347             aBuffer.appendAscii( "string:" );
348             aBuffer.append( _nMessageResID );
349             OSL_VERIFY( _rxBundle->getDirectElement( aBuffer.makeStringAndClear() ) >>= sMessage );
350         }
351         catch( const Exception& e )
352         {
353             (void)e;
354             OSL_ENSURE( false, "lcl_loadString_nothrow: caught an exception!" );
355         }
356         return sMessage;
357     }
358 
359 	//====================================================================
360 	//= ResourceBasedEventLogger
361 	//====================================================================
362 	//--------------------------------------------------------------------
ResourceBasedEventLogger(const Reference<XComponentContext> & _rxContext,const::rtl::OUString & _rResourceBundleBaseName,const::rtl::OUString & _rLoggerName)363     ResourceBasedEventLogger::ResourceBasedEventLogger( const Reference< XComponentContext >& _rxContext, const ::rtl::OUString& _rResourceBundleBaseName,
364         const ::rtl::OUString& _rLoggerName )
365         :EventLogger( _rxContext, _rLoggerName )
366         ,m_pData( new ResourceBasedEventLogger_Data )
367     {
368         m_pData->sBundleBaseName = _rResourceBundleBaseName;
369     }
370 
371 	//--------------------------------------------------------------------
ResourceBasedEventLogger(const Reference<XComponentContext> & _rxContext,const sal_Char * _pResourceBundleBaseName,const sal_Char * _pAsciiLoggerName)372     ResourceBasedEventLogger::ResourceBasedEventLogger( const Reference< XComponentContext >& _rxContext, const sal_Char* _pResourceBundleBaseName,
373         const sal_Char* _pAsciiLoggerName )
374         :EventLogger( _rxContext, _pAsciiLoggerName )
375         ,m_pData( new ResourceBasedEventLogger_Data )
376     {
377         m_pData->sBundleBaseName = ::rtl::OUString::createFromAscii( _pResourceBundleBaseName );
378     }
379 
380 	//--------------------------------------------------------------------
impl_loadStringMessage_nothrow(const sal_Int32 _nMessageResID) const381     ::rtl::OUString ResourceBasedEventLogger::impl_loadStringMessage_nothrow( const sal_Int32 _nMessageResID ) const
382     {
383         ::rtl::OUString sMessage;
384         if ( lcl_loadBundle_nothrow( m_pImpl->getContext(), *m_pData ) )
385             sMessage = lcl_loadString_nothrow( m_pData->xBundle, _nMessageResID );
386         if ( sMessage.isEmpty() )
387         {
388             ::rtl::OUStringBuffer aBuffer;
389             aBuffer.appendAscii( "<invalid event resource: '" );
390             aBuffer.append( m_pData->sBundleBaseName );
391             aBuffer.appendAscii( ":" );
392             aBuffer.append( _nMessageResID );
393             aBuffer.appendAscii( "'>" );
394             sMessage = aBuffer.makeStringAndClear();
395         }
396         return sMessage;
397     }
398 
399 //........................................................................
400 } // namespace comphelper
401 //........................................................................
402