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