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