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 "log_module.hxx" 32 #include "methodguard.hxx" 33 #include "loghandler.hxx" 34 35 /** === begin UNO includes === **/ 36 #include <com/sun/star/logging/XLogHandler.hpp> 37 #include <com/sun/star/lang/XServiceInfo.hpp> 38 #include <com/sun/star/ucb/AlreadyInitializedException.hpp> 39 #include <com/sun/star/lang/XInitialization.hpp> 40 #include <com/sun/star/lang/IllegalArgumentException.hpp> 41 #include <com/sun/star/util/XStringSubstitution.hpp> 42 /** === end UNO includes === **/ 43 44 #include <tools/diagnose_ex.h> 45 46 #include <comphelper/componentcontext.hxx> 47 48 #include <cppuhelper/compbase3.hxx> 49 #include <cppuhelper/basemutex.hxx> 50 51 #include <osl/thread.h> 52 #include <osl/file.hxx> 53 54 #include <rtl/strbuf.hxx> 55 56 #include <memory> 57 58 //........................................................................ 59 namespace logging 60 { 61 //........................................................................ 62 63 /** === begin UNO using === **/ 64 using ::com::sun::star::uno::Reference; 65 using ::com::sun::star::logging::LogRecord; 66 using ::com::sun::star::uno::RuntimeException; 67 using ::com::sun::star::logging::XLogFormatter; 68 using ::com::sun::star::uno::Sequence; 69 using ::com::sun::star::uno::XInterface; 70 using ::com::sun::star::uno::XComponentContext; 71 using ::com::sun::star::logging::XLogHandler; 72 using ::com::sun::star::lang::XServiceInfo; 73 using ::com::sun::star::ucb::AlreadyInitializedException; 74 using ::com::sun::star::lang::XInitialization; 75 using ::com::sun::star::uno::Any; 76 using ::com::sun::star::uno::Exception; 77 using ::com::sun::star::lang::IllegalArgumentException; 78 using ::com::sun::star::uno::UNO_QUERY_THROW; 79 using ::com::sun::star::util::XStringSubstitution; 80 using ::com::sun::star::beans::NamedValue; 81 /** === end UNO using === **/ 82 83 //==================================================================== 84 //= FileHandler - declaration 85 //==================================================================== 86 typedef ::cppu::WeakComponentImplHelper3 < XLogHandler 87 , XServiceInfo 88 , XInitialization 89 > FileHandler_Base; 90 class FileHandler :public ::cppu::BaseMutex 91 ,public FileHandler_Base 92 { 93 private: 94 enum FileValidity 95 { 96 /// never attempted to open the file 97 eUnknown, 98 /// file is valid 99 eValid, 100 /// file is invalid 101 eInvalid 102 }; 103 104 private: 105 ::comphelper::ComponentContext m_aContext; 106 LogHandlerHelper m_aHandlerHelper; 107 ::rtl::OUString m_sFileURL; 108 ::std::auto_ptr< ::osl::File > m_pFile; 109 FileValidity m_eFileValidity; 110 111 protected: 112 FileHandler( const Reference< XComponentContext >& _rxContext ); 113 virtual ~FileHandler(); 114 115 // XLogHandler 116 virtual ::rtl::OUString SAL_CALL getEncoding() throw (RuntimeException); 117 virtual void SAL_CALL setEncoding( const ::rtl::OUString& _encoding ) throw (RuntimeException); 118 virtual Reference< XLogFormatter > SAL_CALL getFormatter() throw (RuntimeException); 119 virtual void SAL_CALL setFormatter( const Reference< XLogFormatter >& _formatter ) throw (RuntimeException); 120 virtual ::sal_Int32 SAL_CALL getLevel() throw (RuntimeException); 121 virtual void SAL_CALL setLevel( ::sal_Int32 _level ) throw (RuntimeException); 122 virtual void SAL_CALL flush( ) throw (RuntimeException); 123 virtual ::sal_Bool SAL_CALL publish( const LogRecord& Record ) throw (RuntimeException); 124 125 // XInitialization 126 virtual void SAL_CALL initialize( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& aArguments ) throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); 127 128 // XServiceInfo 129 virtual ::rtl::OUString SAL_CALL getImplementationName() throw(RuntimeException); 130 virtual ::sal_Bool SAL_CALL supportsService( const ::rtl::OUString& _rServiceName ) throw(RuntimeException); 131 virtual Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames() throw(RuntimeException); 132 133 // OComponentHelper 134 virtual void SAL_CALL disposing(); 135 136 public: 137 // XServiceInfo - static version 138 static ::rtl::OUString SAL_CALL getImplementationName_static(); 139 static Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames_static(); 140 static Reference< XInterface > Create( const Reference< XComponentContext >& _rxContext ); 141 142 public: 143 typedef ComponentMethodGuard< FileHandler > MethodGuard; 144 void enterMethod( MethodGuard::Access ); 145 void leaveMethod( MethodGuard::Access ); 146 147 private: 148 /** prepares our output file for writing 149 */ 150 bool impl_prepareFile_nothrow(); 151 152 /// writes the given string to our file 153 void impl_writeString_nothrow( const ::rtl::OString& _rEntry ); 154 155 /** does string substitution on a (usually externally provided) file url 156 */ 157 void impl_doStringsubstitution_nothrow( ::rtl::OUString& _inout_rURL ); 158 }; 159 160 //==================================================================== 161 //= FileHandler - implementation 162 //==================================================================== 163 //-------------------------------------------------------------------- 164 FileHandler::FileHandler( const Reference< XComponentContext >& _rxContext ) 165 :FileHandler_Base( m_aMutex ) 166 ,m_aContext( _rxContext ) 167 ,m_aHandlerHelper( _rxContext, m_aMutex, rBHelper ) 168 ,m_sFileURL( ) 169 ,m_pFile( ) 170 ,m_eFileValidity( eUnknown ) 171 { 172 } 173 174 //-------------------------------------------------------------------- 175 FileHandler::~FileHandler() 176 { 177 if ( !rBHelper.bDisposed ) 178 { 179 acquire(); 180 dispose(); 181 } 182 } 183 184 //-------------------------------------------------------------------- 185 bool FileHandler::impl_prepareFile_nothrow() 186 { 187 if ( m_eFileValidity == eUnknown ) 188 { 189 m_pFile.reset( new ::osl::File( m_sFileURL ) ); 190 // check whether the log file already exists 191 ::osl::DirectoryItem aFileItem; 192 ::osl::DirectoryItem::get( m_sFileURL, aFileItem ); 193 ::osl::FileStatus aStatus( FileStatusMask_Validate ); 194 if ( ::osl::FileBase::E_None == aFileItem.getFileStatus( aStatus ) ) 195 ::osl::File::remove( m_sFileURL ); 196 197 ::osl::FileBase::RC res = m_pFile->open( osl_File_OpenFlag_Write | osl_File_OpenFlag_Create ); 198 m_eFileValidity = res == ::osl::FileBase::E_None 199 ? eValid 200 : eInvalid; 201 #if OSL_DEBUG_LEVEL > 0 202 if ( m_eFileValidity == eInvalid ) 203 { 204 ::rtl::OStringBuffer sMessage; 205 sMessage.append( "FileHandler::impl_prepareFile_nothrow: could not open the designated log file:" ); 206 sMessage.append( "\nURL: " ); 207 sMessage.append( ::rtl::OString( m_sFileURL.getStr(), m_sFileURL.getLength(), osl_getThreadTextEncoding() ) ); 208 sMessage.append( "\nerror code: " ); 209 sMessage.append( (sal_Int32)res ); 210 OSL_ENSURE( false, sMessage.makeStringAndClear() ); 211 } 212 #endif 213 if ( m_eFileValidity == eValid ) 214 { 215 ::rtl::OString sHead; 216 if ( m_aHandlerHelper.getEncodedHead( sHead ) ) 217 impl_writeString_nothrow( sHead ); 218 } 219 } 220 221 return m_eFileValidity == eValid; 222 } 223 224 //-------------------------------------------------------------------- 225 void FileHandler::impl_writeString_nothrow( const ::rtl::OString& _rEntry ) 226 { 227 OSL_PRECOND( m_pFile.get(), "FileHandler::impl_writeString_nothrow: no file!" ); 228 229 sal_uInt64 nBytesToWrite( _rEntry.getLength() ); 230 sal_uInt64 nBytesWritten( 0 ); 231 #if OSL_DEBUG_LEVEL > 0 232 ::osl::FileBase::RC res = 233 #endif 234 m_pFile->write( _rEntry.getStr(), nBytesToWrite, nBytesWritten ); 235 OSL_ENSURE( ( res == ::osl::FileBase::E_None ) && ( nBytesWritten == nBytesToWrite ), 236 "FileHandler::impl_writeString_nothrow: could not write the log entry!" ); 237 } 238 239 //-------------------------------------------------------------------- 240 void FileHandler::impl_doStringsubstitution_nothrow( ::rtl::OUString& _inout_rURL ) 241 { 242 try 243 { 244 Reference< XStringSubstitution > xStringSubst; 245 if ( m_aContext.createComponent( "com.sun.star.util.PathSubstitution", xStringSubst ) ) 246 _inout_rURL = xStringSubst->substituteVariables( _inout_rURL, true ); 247 } 248 catch( const Exception& ) 249 { 250 DBG_UNHANDLED_EXCEPTION(); 251 } 252 } 253 254 //-------------------------------------------------------------------- 255 void SAL_CALL FileHandler::disposing() 256 { 257 if ( m_eFileValidity == eValid ) 258 { 259 ::rtl::OString sTail; 260 if ( m_aHandlerHelper.getEncodedTail( sTail ) ) 261 impl_writeString_nothrow( sTail ); 262 } 263 264 m_pFile.reset( NULL ); 265 m_aHandlerHelper.setFormatter( NULL ); 266 } 267 268 //-------------------------------------------------------------------- 269 void FileHandler::enterMethod( MethodGuard::Access ) 270 { 271 m_aHandlerHelper.enterMethod(); 272 } 273 274 //-------------------------------------------------------------------- 275 void FileHandler::leaveMethod( MethodGuard::Access ) 276 { 277 m_aMutex.release(); 278 } 279 280 //-------------------------------------------------------------------- 281 ::rtl::OUString SAL_CALL FileHandler::getEncoding() throw (RuntimeException) 282 { 283 MethodGuard aGuard( *this ); 284 ::rtl::OUString sEncoding; 285 OSL_VERIFY( m_aHandlerHelper.getEncoding( sEncoding ) ); 286 return sEncoding; 287 } 288 289 //-------------------------------------------------------------------- 290 void SAL_CALL FileHandler::setEncoding( const ::rtl::OUString& _rEncoding ) throw (RuntimeException) 291 { 292 MethodGuard aGuard( *this ); 293 OSL_VERIFY( m_aHandlerHelper.setEncoding( _rEncoding ) ); 294 } 295 296 //-------------------------------------------------------------------- 297 Reference< XLogFormatter > SAL_CALL FileHandler::getFormatter() throw (RuntimeException) 298 { 299 MethodGuard aGuard( *this ); 300 return m_aHandlerHelper.getFormatter(); 301 } 302 303 //-------------------------------------------------------------------- 304 void SAL_CALL FileHandler::setFormatter( const Reference< XLogFormatter >& _rxFormatter ) throw (RuntimeException) 305 { 306 MethodGuard aGuard( *this ); 307 m_aHandlerHelper.setFormatter( _rxFormatter ); 308 } 309 310 //-------------------------------------------------------------------- 311 ::sal_Int32 SAL_CALL FileHandler::getLevel() throw (RuntimeException) 312 { 313 MethodGuard aGuard( *this ); 314 return m_aHandlerHelper.getLevel(); 315 } 316 317 //-------------------------------------------------------------------- 318 void SAL_CALL FileHandler::setLevel( ::sal_Int32 _nLevel ) throw (RuntimeException) 319 { 320 MethodGuard aGuard( *this ); 321 m_aHandlerHelper.setLevel( _nLevel ); 322 } 323 324 //-------------------------------------------------------------------- 325 void SAL_CALL FileHandler::flush( ) throw (RuntimeException) 326 { 327 MethodGuard aGuard( *this ); 328 if(!m_pFile.get()) 329 { 330 OSL_PRECOND(false, "FileHandler::flush: no file!"); 331 return; 332 } 333 #if OSL_DEBUG_LEVEL > 0 334 ::osl::FileBase::RC res = 335 #endif 336 m_pFile->sync(); 337 OSL_ENSURE(res == ::osl::FileBase::E_None, "FileHandler::flush: Could not sync logfile to filesystem."); 338 } 339 340 //-------------------------------------------------------------------- 341 ::sal_Bool SAL_CALL FileHandler::publish( const LogRecord& _rRecord ) throw (RuntimeException) 342 { 343 MethodGuard aGuard( *this ); 344 345 if ( !impl_prepareFile_nothrow() ) 346 return sal_False; 347 348 ::rtl::OString sEntry; 349 if ( !m_aHandlerHelper.formatForPublishing( _rRecord, sEntry ) ) 350 return sal_False; 351 352 impl_writeString_nothrow( sEntry ); 353 return sal_True; 354 } 355 356 //-------------------------------------------------------------------- 357 void SAL_CALL FileHandler::initialize( const Sequence< Any >& _rArguments ) throw (Exception, RuntimeException) 358 { 359 ::osl::MutexGuard aGuard( m_aMutex ); 360 361 if ( m_aHandlerHelper.getIsInitialized() ) 362 throw AlreadyInitializedException(); 363 364 if ( _rArguments.getLength() != 1 ) 365 throw IllegalArgumentException( ::rtl::OUString(), *this, 1 ); 366 367 Sequence< NamedValue > aSettings; 368 if ( _rArguments[0] >>= m_sFileURL ) 369 { 370 // create( [in] string URL ); 371 impl_doStringsubstitution_nothrow( m_sFileURL ); 372 } 373 else if ( _rArguments[0] >>= aSettings ) 374 { 375 // createWithSettings( [in] sequence< ::com::sun::star::beans::NamedValue > Settings ) 376 ::comphelper::NamedValueCollection aTypedSettings( aSettings ); 377 m_aHandlerHelper.initFromSettings( aTypedSettings ); 378 379 if ( aTypedSettings.get_ensureType( "FileURL", m_sFileURL ) ) 380 impl_doStringsubstitution_nothrow( m_sFileURL ); 381 } 382 else 383 throw IllegalArgumentException( ::rtl::OUString(), *this, 1 ); 384 385 m_aHandlerHelper.setIsInitialized(); 386 } 387 388 //-------------------------------------------------------------------- 389 ::rtl::OUString SAL_CALL FileHandler::getImplementationName() throw(RuntimeException) 390 { 391 return getImplementationName_static(); 392 } 393 394 //-------------------------------------------------------------------- 395 ::sal_Bool SAL_CALL FileHandler::supportsService( const ::rtl::OUString& _rServiceName ) throw(RuntimeException) 396 { 397 const Sequence< ::rtl::OUString > aServiceNames( getSupportedServiceNames() ); 398 for ( const ::rtl::OUString* pServiceNames = aServiceNames.getConstArray(); 399 pServiceNames != aServiceNames.getConstArray() + aServiceNames.getLength(); 400 ++pServiceNames 401 ) 402 if ( _rServiceName == *pServiceNames ) 403 return sal_True; 404 return sal_False; 405 } 406 407 //-------------------------------------------------------------------- 408 Sequence< ::rtl::OUString > SAL_CALL FileHandler::getSupportedServiceNames() throw(RuntimeException) 409 { 410 return getSupportedServiceNames_static(); 411 } 412 413 //-------------------------------------------------------------------- 414 ::rtl::OUString SAL_CALL FileHandler::getImplementationName_static() 415 { 416 return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.extensions.FileHandler" ) ); 417 } 418 419 //-------------------------------------------------------------------- 420 Sequence< ::rtl::OUString > SAL_CALL FileHandler::getSupportedServiceNames_static() 421 { 422 Sequence< ::rtl::OUString > aServiceNames(1); 423 aServiceNames[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.logging.FileHandler" ) ); 424 return aServiceNames; 425 } 426 427 //-------------------------------------------------------------------- 428 Reference< XInterface > FileHandler::Create( const Reference< XComponentContext >& _rxContext ) 429 { 430 return *( new FileHandler( _rxContext ) ); 431 } 432 433 //-------------------------------------------------------------------- 434 void createRegistryInfo_FileHandler() 435 { 436 static OAutoRegistration< FileHandler > aAutoRegistration; 437 } 438 439 //........................................................................ 440 } // namespace logging 441 //........................................................................ 442