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_extensions.hxx" 26 27 #include "loggerconfig.hxx" 28 29 /** === begin UNO includes === **/ 30 #include <com/sun/star/lang/XMultiServiceFactory.hpp> 31 #include <com/sun/star/container/XNameContainer.hpp> 32 #include <com/sun/star/lang/XSingleServiceFactory.hpp> 33 #include <com/sun/star/util/XChangesBatch.hpp> 34 #include <com/sun/star/logging/LogLevel.hpp> 35 #include <com/sun/star/lang/NullPointerException.hpp> 36 #include <com/sun/star/lang/ServiceNotRegisteredException.hpp> 37 #include <com/sun/star/beans/NamedValue.hpp> 38 #include <com/sun/star/logging/XLogHandler.hpp> 39 #include <com/sun/star/logging/XLogFormatter.hpp> 40 /** === end UNO includes === **/ 41 42 #include <tools/diagnose_ex.h> 43 44 #include <comphelper/componentcontext.hxx> 45 46 #include <cppuhelper/component_context.hxx> 47 48 #include <vector> 49 50 //........................................................................ 51 namespace logging 52 { 53 //........................................................................ 54 55 /** === begin UNO using === **/ 56 using ::com::sun::star::uno::Reference; 57 using ::com::sun::star::logging::XLogger; 58 using ::com::sun::star::lang::XMultiServiceFactory; 59 using ::com::sun::star::uno::Sequence; 60 using ::com::sun::star::uno::Any; 61 using ::com::sun::star::container::XNameContainer; 62 using ::com::sun::star::uno::UNO_QUERY_THROW; 63 using ::com::sun::star::lang::XSingleServiceFactory; 64 using ::com::sun::star::uno::XInterface; 65 using ::com::sun::star::util::XChangesBatch; 66 using ::com::sun::star::uno::makeAny; 67 using ::com::sun::star::lang::NullPointerException; 68 using ::com::sun::star::uno::Exception; 69 using ::com::sun::star::lang::ServiceNotRegisteredException; 70 using ::com::sun::star::beans::NamedValue; 71 using ::com::sun::star::logging::XLogHandler; 72 using ::com::sun::star::logging::XLogFormatter; 73 using ::com::sun::star::container::XNameAccess; 74 using ::com::sun::star::uno::XComponentContext; 75 /** === end UNO using === **/ 76 namespace LogLevel = ::com::sun::star::logging::LogLevel; 77 78 namespace 79 { 80 //---------------------------------------------------------------- 81 typedef void (*SettingTranslation)( const Reference< XLogger >&, const ::rtl::OUString&, Any& ); 82 83 //---------------------------------------------------------------- 84 void lcl_substituteFileHandlerURLVariables_nothrow( const Reference< XLogger >& _rxLogger, ::rtl::OUString& _inout_rFileURL ) 85 { 86 struct Variable 87 { 88 const sal_Char* pVariablePattern; 89 const sal_Int32 nPatternLength; 90 rtl_TextEncoding eEncoding; 91 const ::rtl::OUString sVariableValue; 92 93 Variable( const sal_Char* _pVariablePattern, const sal_Int32 _nPatternLength, rtl_TextEncoding _eEncoding, 94 const ::rtl::OUString& _rVariableValue ) 95 :pVariablePattern( _pVariablePattern ) 96 ,nPatternLength( _nPatternLength ) 97 ,eEncoding( _eEncoding ) 98 ,sVariableValue( _rVariableValue ) 99 { 100 } 101 }; 102 103 ::rtl::OUString sLoggerName; 104 try { sLoggerName = _rxLogger->getName(); } 105 catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); } 106 107 Variable aVariables[] = 108 { 109 Variable( RTL_CONSTASCII_USTRINGPARAM( "$(loggername)" ), sLoggerName ) 110 }; 111 112 for ( size_t i = 0; i < sizeof( aVariables ) / sizeof( aVariables[0] ); ++i ) 113 { 114 ::rtl::OUString sPattern( aVariables[i].pVariablePattern, aVariables[i].nPatternLength, aVariables[i].eEncoding ); 115 sal_Int32 nVariableIndex = _inout_rFileURL.indexOf( sPattern ); 116 if ( ( nVariableIndex == 0 ) 117 || ( ( nVariableIndex > 0 ) 118 && ( sPattern[ nVariableIndex - 1 ] != '$' ) 119 ) 120 ) 121 { 122 // found an (unescaped) variable 123 _inout_rFileURL = _inout_rFileURL.replaceAt( nVariableIndex, sPattern.getLength(), aVariables[i].sVariableValue ); 124 } 125 } 126 } 127 128 //---------------------------------------------------------------- 129 void lcl_transformFileHandlerSettings_nothrow( const Reference< XLogger >& _rxLogger, const ::rtl::OUString& _rSettingName, Any& _inout_rSettingValue ) 130 { 131 if ( !_rSettingName.equalsAscii( "FileURL" ) ) 132 // not interested in this setting 133 return; 134 135 ::rtl::OUString sURL; 136 OSL_VERIFY( _inout_rSettingValue >>= sURL ); 137 lcl_substituteFileHandlerURLVariables_nothrow( _rxLogger, sURL ); 138 _inout_rSettingValue <<= sURL; 139 } 140 141 //---------------------------------------------------------------- 142 Reference< XInterface > lcl_createInstanceFromSetting_throw( 143 const ::comphelper::ComponentContext& _rContext, 144 const Reference< XLogger >& _rxLogger, 145 const Reference< XNameAccess >& _rxLoggerSettings, 146 const sal_Char* _pServiceNameAsciiNodeName, 147 const sal_Char* _pServiceSettingsAsciiNodeName, 148 SettingTranslation _pSettingTranslation = NULL 149 ) 150 { 151 Reference< XInterface > xInstance; 152 153 // read the settings for the to-be-created service 154 Reference< XNameAccess > xServiceSettingsNode( _rxLoggerSettings->getByName( 155 ::rtl::OUString::createFromAscii( _pServiceSettingsAsciiNodeName ) ), UNO_QUERY_THROW ); 156 157 Sequence< ::rtl::OUString > aSettingNames( xServiceSettingsNode->getElementNames() ); 158 size_t nServiceSettingCount( aSettingNames.getLength() ); 159 Sequence< NamedValue > aSettings( nServiceSettingCount ); 160 if ( nServiceSettingCount ) 161 { 162 const ::rtl::OUString* pSettingNames = aSettingNames.getConstArray(); 163 const ::rtl::OUString* pSettingNamesEnd = aSettingNames.getConstArray() + aSettingNames.getLength(); 164 NamedValue* pSetting = aSettings.getArray(); 165 166 for ( ; 167 pSettingNames != pSettingNamesEnd; 168 ++pSettingNames, ++pSetting 169 ) 170 { 171 pSetting->Name = *pSettingNames; 172 pSetting->Value = xServiceSettingsNode->getByName( *pSettingNames ); 173 174 if ( _pSettingTranslation ) 175 (_pSettingTranslation)( _rxLogger, pSetting->Name, pSetting->Value ); 176 } 177 } 178 179 ::rtl::OUString sServiceName; 180 _rxLoggerSettings->getByName( ::rtl::OUString::createFromAscii( _pServiceNameAsciiNodeName ) ) >>= sServiceName; 181 if ( sServiceName.getLength() ) 182 { 183 bool bSuccess = false; 184 if ( aSettings.getLength() ) 185 { 186 Sequence< Any > aConstructionArgs(1); 187 aConstructionArgs[0] <<= aSettings; 188 bSuccess = _rContext.createComponentWithArguments( sServiceName, aConstructionArgs, xInstance ); 189 } 190 else 191 { 192 bSuccess = _rContext.createComponent( sServiceName, xInstance ); 193 } 194 195 if ( !bSuccess ) 196 throw ServiceNotRegisteredException( sServiceName, NULL ); 197 } 198 199 return xInstance; 200 } 201 } 202 203 //-------------------------------------------------------------------- 204 void initializeLoggerFromConfiguration( const ::comphelper::ComponentContext& _rContext, const Reference< XLogger >& _rxLogger ) 205 { 206 try 207 { 208 if ( !_rxLogger.is() ) 209 throw NullPointerException(); 210 211 // the configuration provider 212 Reference< XMultiServiceFactory > xConfigProvider; 213 ::rtl::OUString sConfigProvServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.configuration.ConfigurationProvider" ) ); 214 if ( !_rContext.createComponent( sConfigProvServiceName, xConfigProvider ) ) 215 throw ServiceNotRegisteredException( sConfigProvServiceName, _rxLogger ); 216 217 // write access to the "Settings" node (which includes settings for all loggers) 218 Sequence< Any > aArguments(1); 219 aArguments[0] <<= NamedValue( 220 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "nodepath" ) ), 221 makeAny( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/org.openoffice.Office.Logging/Settings" ) ) ) 222 ); 223 Reference< XNameContainer > xAllSettings( xConfigProvider->createInstanceWithArguments( 224 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.configuration.ConfigurationUpdateAccess" ) ), 225 aArguments 226 ), UNO_QUERY_THROW ); 227 228 ::rtl::OUString sLoggerName( _rxLogger->getName() ); 229 if ( !xAllSettings->hasByName( sLoggerName ) ) 230 { 231 // no node yet for this logger. Create default settings. 232 Reference< XSingleServiceFactory > xNodeFactory( xAllSettings, UNO_QUERY_THROW ); 233 Reference< XInterface > xLoggerSettings( xNodeFactory->createInstance(), UNO_QUERY_THROW ); 234 xAllSettings->insertByName( sLoggerName, makeAny( xLoggerSettings ) ); 235 Reference< XChangesBatch > xChanges( xAllSettings, UNO_QUERY_THROW ); 236 xChanges->commitChanges(); 237 } 238 239 // actually read and forward the settings 240 Reference< XNameAccess > xLoggerSettings( xAllSettings->getByName( sLoggerName ), UNO_QUERY_THROW ); 241 242 // the log level 243 sal_Int32 nLogLevel( LogLevel::OFF ); 244 OSL_VERIFY( xLoggerSettings->getByName( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "LogLevel" ) ) ) >>= nLogLevel ); 245 _rxLogger->setLevel( nLogLevel ); 246 247 // the default handler, if any 248 Reference< XInterface > xUntyped( lcl_createInstanceFromSetting_throw( _rContext, _rxLogger, xLoggerSettings, "DefaultHandler", "HandlerSettings", &lcl_transformFileHandlerSettings_nothrow ) ); 249 if ( !xUntyped.is() ) 250 // no handler -> we're done 251 return; 252 Reference< XLogHandler > xHandler( xUntyped, UNO_QUERY_THROW ); 253 _rxLogger->addLogHandler( xHandler ); 254 255 // The newly created handler might have an own (default) level. Ensure that it uses 256 // the same level as the logger. 257 xHandler->setLevel( nLogLevel ); 258 259 // the default formatter for the handler 260 xUntyped = lcl_createInstanceFromSetting_throw( _rContext, _rxLogger, xLoggerSettings, "DefaultFormatter", "FormatterSettings" ); 261 if ( !xUntyped.is() ) 262 // no formatter -> we're done 263 return; 264 Reference< XLogFormatter > xFormatter( xUntyped, UNO_QUERY_THROW ); 265 xHandler->setFormatter( xFormatter ); 266 267 // TODO: we could first create the formatter, then the handler. This would allow 268 // passing the formatter as value in the component context, so the handler would 269 // not create an own default formatter 270 } 271 catch( const Exception& ) 272 { 273 DBG_UNHANDLED_EXCEPTION(); 274 } 275 } 276 277 //........................................................................ 278 } // namespace logging 279 //........................................................................ 280