LCOV - code coverage report
Current view: top level - libreoffice/framework/source/jobs - jobexecutor.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 51 107 47.7 %
Date: 2012-12-27 Functions: 13 22 59.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include <jobs/jobexecutor.hxx>
      21             : #include <jobs/job.hxx>
      22             : #include <jobs/joburl.hxx>
      23             : 
      24             : #include <classes/converter.hxx>
      25             : #include <threadhelp/transactionguard.hxx>
      26             : #include <threadhelp/readguard.hxx>
      27             : #include <threadhelp/writeguard.hxx>
      28             : #include <general.h>
      29             : #include <services.h>
      30             : 
      31             : #include "helper/mischelper.hxx"
      32             : 
      33             : #include <com/sun/star/beans/XPropertySet.hpp>
      34             : #include <com/sun/star/container/XNameAccess.hpp>
      35             : #include <com/sun/star/container/XContainer.hpp>
      36             : #include <com/sun/star/frame/ModuleManager.hpp>
      37             : 
      38             : #include <unotools/configpaths.hxx>
      39             : #include <rtl/ustrbuf.hxx>
      40             : #include <vcl/svapp.hxx>
      41             : 
      42             : #include <rtl/logfile.hxx>
      43             : 
      44             : namespace framework{
      45             : 
      46         526 : DEFINE_XINTERFACE_6( JobExecutor                                                               ,
      47             :                      OWeakObject                                                               ,
      48             :                      DIRECT_INTERFACE(css::lang::XTypeProvider                                ),
      49             :                      DIRECT_INTERFACE(css::lang::XServiceInfo                                 ),
      50             :                      DIRECT_INTERFACE(css::task::XJobExecutor                                 ),
      51             :                      DIRECT_INTERFACE(css::container::XContainerListener                      ),
      52             :                      DIRECT_INTERFACE(css::document::XEventListener                           ),
      53             :                      DERIVED_INTERFACE(css::lang::XEventListener,css::document::XEventListener)
      54             :                    )
      55             : 
      56           0 : DEFINE_XTYPEPROVIDER_6( JobExecutor                       ,
      57             :                         css::lang::XTypeProvider          ,
      58             :                         css::lang::XServiceInfo           ,
      59             :                         css::task::XJobExecutor           ,
      60             :                         css::container::XContainerListener,
      61             :                         css::document::XEventListener     ,
      62             :                         css::lang::XEventListener
      63             :                       )
      64             : 
      65         273 : DEFINE_XSERVICEINFO_ONEINSTANCESERVICE( JobExecutor                   ,
      66             :                                         ::cppu::OWeakObject           ,
      67             :                                         "com.sun.star.task.JobExecutor",
      68             :                                         IMPLEMENTATIONNAME_JOBEXECUTOR
      69             :                                       )
      70             : 
      71          18 : DEFINE_INIT_SERVICE( JobExecutor,
      72             :                      {
      73             :                          m_xModuleManager = css::frame::ModuleManager::create( comphelper::getComponentContext(m_xSMGR) );
      74             : 
      75             :                          /*Attention
      76             :                              I think we don't need any mutex or lock here ... because we are called by our own static method impl_createInstance()
      77             :                              to create a new instance of this class by our own supported service factory.
      78             :                              see macro DEFINE_XSERVICEINFO_MULTISERVICE and "impl_initService()" for further informations!
      79             :                          */
      80             :                         // read the list of all currently registered events inside configuration.
      81             :                         // e.g. "/org.openoffice.Office.Jobs/Events/<event name>"
      82             :                         // We need it later to check if an incoming event request can be executed successfully
      83             :                         // or must be rejected. It's an optimization! Of course we must implement updating of this
      84             :                         // list too ... Be listener at the configuration.
      85             : 
      86             :                         m_aConfig.open(ConfigAccess::E_READONLY);
      87             :                         if (m_aConfig.getMode() == ConfigAccess::E_READONLY)
      88             :                         {
      89             :                             css::uno::Reference< css::container::XNameAccess > xRegistry(m_aConfig.cfg(), css::uno::UNO_QUERY);
      90             :                             if (xRegistry.is())
      91             :                                 m_lEvents = Converter::convert_seqOUString2OUStringList(xRegistry->getElementNames());
      92             : 
      93             :                             css::uno::Reference< css::container::XContainer > xNotifier(m_aConfig.cfg(), css::uno::UNO_QUERY);
      94             :                             if (xNotifier.is())
      95             :                             {
      96             :                                 m_xConfigListener = new WeakContainerListener(this);
      97             :                                 xNotifier->addContainerListener(m_xConfigListener);
      98             :                             }
      99             : 
     100             :                             // don't close cfg here!
     101             :                             // It will be done inside disposing ...
     102             :                         }
     103             :                      }
     104             :                    )
     105             : 
     106             : //________________________________
     107             : 
     108             : /**
     109             :     @short      standard ctor
     110             :     @descr      It initialize this new instance.
     111             : 
     112             :     @param      xSMGR
     113             :                     reference to the uno service manager
     114             :  */
     115          18 : JobExecutor::JobExecutor( /*IN*/ const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR )
     116          18 :     : ThreadHelpBase      (&Application::GetSolarMutex()                                   )
     117             :     , ::cppu::OWeakObject (                                                                )
     118             :     , m_xSMGR             (xSMGR                                                           )
     119             :     , m_xModuleManager    (                                                                )
     120          36 :     , m_aConfig           (comphelper::getComponentContext(xSMGR), ::rtl::OUString::createFromAscii(JobData::EVENTCFG_ROOT) )
     121             : {
     122             :     // Don't do any reference related code here! Do it inside special
     123             :     // impl_ method() ... see DEFINE_INIT_SERVICE() macro for further informations.
     124          18 : }
     125             : 
     126           6 : JobExecutor::~JobExecutor()
     127             : {
     128           2 :     css::uno::Reference< css::container::XContainer > xNotifier(m_aConfig.cfg(), css::uno::UNO_QUERY);
     129           2 :     if (xNotifier.is())
     130           2 :         xNotifier->removeContainerListener(m_xConfigListener);
     131           4 : }
     132             : 
     133             : //________________________________
     134             : 
     135             : /**
     136             :     @short  implementation of XJobExecutor interface
     137             :     @descr  We use the given event to locate any registered job inside our configuration
     138             :             and execute it. Further we control the lifetime of it and supress
     139             :             shutdown of the office till all jobs was finished.
     140             : 
     141             :     @param  sEvent
     142             :                 is used to locate registered jobs
     143             :  */
     144           8 : void SAL_CALL JobExecutor::trigger( const ::rtl::OUString& sEvent ) throw(css::uno::RuntimeException)
     145             : {
     146             :     RTL_LOGFILE_CONTEXT(aLog, "fwk (as96863) JobExecutor::trigger()");
     147             : 
     148             :     /* SAFE { */
     149           8 :     ReadGuard aReadLock(m_aLock);
     150             : 
     151             :     // Optimization!
     152             :     // Check if the given event name exist inside configuration and reject wrong requests.
     153             :     // This optimization supress using of the cfg api for getting event and job descriptions ...
     154           8 :     if (m_lEvents.find(sEvent) == m_lEvents.end())
     155           8 :         return;
     156             : 
     157             :     // get list of all enabled jobs
     158             :     // The called static helper methods read it from the configuration and
     159             :     // filter disabled jobs using it's time stamp values.
     160           0 :     css::uno::Sequence< ::rtl::OUString > lJobs = JobData::getEnabledJobsForEvent(comphelper::getComponentContext(m_xSMGR), sEvent);
     161             : 
     162           0 :     aReadLock.unlock();
     163             :     /* } SAFE */
     164             : 
     165             :     // step over all enabled jobs and execute it
     166           0 :     sal_Int32 c = lJobs.getLength();
     167           0 :     for (sal_Int32 j=0; j<c; ++j)
     168             :     {
     169             :         /* SAFE { */
     170           0 :         aReadLock.lock();
     171             : 
     172           0 :         JobData aCfg(comphelper::getComponentContext(m_xSMGR));
     173           0 :         aCfg.setEvent(sEvent, lJobs[j]);
     174           0 :         aCfg.setEnvironment(JobData::E_EXECUTION);
     175             : 
     176             :         /*Attention!
     177             :             Jobs implements interfaces and dies by ref count!
     178             :             And freeing of such uno object is done by uno itself.
     179             :             So we have to use dynamic memory everytimes.
     180             :          */
     181           0 :         Job* pJob = new Job(m_xSMGR, css::uno::Reference< css::frame::XFrame >());
     182           0 :         css::uno::Reference< css::uno::XInterface > xJob(static_cast< ::cppu::OWeakObject* >(pJob), css::uno::UNO_QUERY);
     183           0 :         pJob->setJobData(aCfg);
     184             : 
     185           0 :         aReadLock.unlock();
     186             :         /* } SAFE */
     187             : 
     188           0 :         pJob->execute(css::uno::Sequence< css::beans::NamedValue >());
     189           0 :     }
     190             : }
     191             : 
     192             : //________________________________
     193             : 
     194        4809 : void SAL_CALL JobExecutor::notifyEvent( const css::document::EventObject& aEvent ) throw(css::uno::RuntimeException)
     195             : {
     196        4809 :     const char EVENT_ON_NEW[] = "OnNew";                            // Doc UI  event
     197        4809 :     const char EVENT_ON_LOAD[] = "OnLoad";                          // Doc UI  event
     198        4809 :     const char EVENT_ON_CREATE[] = "OnCreate";                      // Doc API event
     199        4809 :     const char EVENT_ON_LOAD_FINISHED[] = "OnLoadFinished";         // Doc API event
     200        4809 :     ::rtl::OUString EVENT_ON_DOCUMENT_OPENED("onDocumentOpened");   // Job UI  event : OnNew    or OnLoad
     201        4809 :     ::rtl::OUString EVENT_ON_DOCUMENT_ADDED("onDocumentAdded");     // Job API event : OnCreate or OnLoadFinished
     202             : 
     203             :     /* SAFE { */
     204        4809 :     ReadGuard aReadLock(m_aLock);
     205             : 
     206        4809 :     ::comphelper::SequenceAsVector< JobData::TJob2DocEventBinding > lJobs;
     207             : 
     208             :     // Optimization!
     209             :     // Check if the given event name exist inside configuration and reject wrong requests.
     210             :     // This optimization supress using of the cfg api for getting event and job descriptions.
     211             :     // see using of m_lEvents.find() below ...
     212             : 
     213             :     // retrieve event context from event source
     214        4809 :     rtl::OUString aModuleIdentifier;
     215             :     try
     216             :     {
     217        4809 :         aModuleIdentifier = m_xModuleManager->identify( aEvent.Source );
     218             :     }
     219         109 :     catch( const css::uno::Exception& )
     220             :     {}
     221             : 
     222             :     // Special feature: If the events "OnNew" or "OnLoad" occures - we generate our own event "onDocumentOpened".
     223        9617 :     if (
     224        4809 :         (aEvent.EventName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(EVENT_ON_NEW))) ||
     225        4808 :         (aEvent.EventName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(EVENT_ON_LOAD)))
     226             :        )
     227             :     {
     228         124 :         if (m_lEvents.find(EVENT_ON_DOCUMENT_OPENED) != m_lEvents.end())
     229         124 :             JobData::appendEnabledJobsForEvent(comphelper::getComponentContext(m_xSMGR), EVENT_ON_DOCUMENT_OPENED, lJobs);
     230             :     }
     231             : 
     232             :     // Special feature: If the events "OnCreate" or "OnLoadFinished" occures - we generate our own event "onDocumentAdded".
     233        9457 :     if (
     234        4809 :         (aEvent.EventName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(EVENT_ON_CREATE))) ||
     235        4648 :         (aEvent.EventName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(EVENT_ON_LOAD_FINISHED)))
     236             :        )
     237             :     {
     238         501 :         if (m_lEvents.find(EVENT_ON_DOCUMENT_ADDED) != m_lEvents.end())
     239           0 :             JobData::appendEnabledJobsForEvent(comphelper::getComponentContext(m_xSMGR), EVENT_ON_DOCUMENT_ADDED, lJobs);
     240             :     }
     241             : 
     242             :     // Add all jobs for "real" notified event too .-)
     243        4809 :     if (m_lEvents.find(aEvent.EventName) != m_lEvents.end())
     244           0 :         JobData::appendEnabledJobsForEvent(comphelper::getComponentContext(m_xSMGR), aEvent.EventName, lJobs);
     245             : 
     246        4809 :     aReadLock.unlock();
     247             :     /* } SAFE */
     248             : 
     249             :     // step over all enabled jobs and execute it
     250        4809 :     ::comphelper::SequenceAsVector< JobData::TJob2DocEventBinding >::const_iterator pIt;
     251       14799 :     for (  pIt  = lJobs.begin();
     252        9866 :            pIt != lJobs.end()  ;
     253             :          ++pIt                 )
     254             :     {
     255             :         /* SAFE { */
     256         124 :         aReadLock.lock();
     257             : 
     258         124 :         const JobData::TJob2DocEventBinding& rBinding = *pIt;
     259             : 
     260         124 :         JobData aCfg(comphelper::getComponentContext(m_xSMGR));
     261         124 :         aCfg.setEvent(rBinding.m_sDocEvent, rBinding.m_sJobName);
     262         124 :         aCfg.setEnvironment(JobData::E_DOCUMENTEVENT);
     263             : 
     264         124 :         if (!aCfg.hasCorrectContext(aModuleIdentifier))
     265         124 :             continue;
     266             : 
     267             :         /*Attention!
     268             :             Jobs implements interfaces and dies by ref count!
     269             :             And freeing of such uno object is done by uno itself.
     270             :             So we have to use dynamic memory everytimes.
     271             :          */
     272           0 :         css::uno::Reference< css::frame::XModel > xModel(aEvent.Source, css::uno::UNO_QUERY);
     273           0 :         Job* pJob = new Job(m_xSMGR, xModel);
     274           0 :         css::uno::Reference< css::uno::XInterface > xJob(static_cast< ::cppu::OWeakObject* >(pJob), css::uno::UNO_QUERY);
     275           0 :         pJob->setJobData(aCfg);
     276             : 
     277           0 :         aReadLock.unlock();
     278             :         /* } SAFE */
     279             : 
     280           0 :         pJob->execute(css::uno::Sequence< css::beans::NamedValue >());
     281        4809 :     }
     282        4809 : }
     283             : 
     284             : //________________________________
     285             : 
     286           0 : void SAL_CALL JobExecutor::elementInserted( const css::container::ContainerEvent& aEvent ) throw(css::uno::RuntimeException)
     287             : {
     288           0 :     ::rtl::OUString sValue;
     289           0 :     if (aEvent.Accessor >>= sValue)
     290             :     {
     291           0 :         ::rtl::OUString sEvent = ::utl::extractFirstFromConfigurationPath(sValue);
     292           0 :         if (!sEvent.isEmpty())
     293             :         {
     294           0 :             OUStringList::iterator pEvent = m_lEvents.find(sEvent);
     295           0 :             if (pEvent == m_lEvents.end())
     296           0 :                 m_lEvents.push_back(sEvent);
     297           0 :         }
     298           0 :     }
     299           0 : }
     300             : 
     301           0 : void SAL_CALL JobExecutor::elementRemoved ( const css::container::ContainerEvent& aEvent ) throw(css::uno::RuntimeException)
     302             : {
     303           0 :     ::rtl::OUString sValue;
     304           0 :     if (aEvent.Accessor >>= sValue)
     305             :     {
     306           0 :         ::rtl::OUString sEvent = ::utl::extractFirstFromConfigurationPath(sValue);
     307           0 :         if (!sEvent.isEmpty())
     308             :         {
     309           0 :             OUStringList::iterator pEvent = m_lEvents.find(sEvent);
     310           0 :             if (pEvent != m_lEvents.end())
     311           0 :                 m_lEvents.erase(pEvent);
     312           0 :         }
     313           0 :     }
     314           0 : }
     315             : 
     316           0 : void SAL_CALL JobExecutor::elementReplaced( const css::container::ContainerEvent& ) throw(css::uno::RuntimeException)
     317             : {
     318             :     // I'm not interested on changed items :-)
     319           0 : }
     320             : 
     321             : //________________________________
     322             : 
     323             : /** @short  the used cfg changes notifier wish to be released in its reference.
     324             : 
     325             :     @descr  We close our internal used configuration instance to
     326             :             free this reference.
     327             : 
     328             :     @attention  For the special feature "bind global document event broadcaster to job execution"
     329             :                 this job executor instance was registered from outside code as
     330             :                 css.document.XEventListener. So it can be, that this disposing call comes from
     331             :                 the global event broadcaster service. But we don't hold any reference to this service
     332             :                 which can or must be released. Because this broadcaster itself is an one instance service
     333             :                 too, we can ignore this request. On the other side we must relase our internal CFG
     334             :                 reference ... SOLUTION => check the given event source and react only, if it's our internal
     335             :                 hold configuration object!
     336             :  */
     337           0 : void SAL_CALL JobExecutor::disposing( const css::lang::EventObject& aEvent ) throw(css::uno::RuntimeException)
     338             : {
     339             :     /* SAFE { */
     340           0 :     ReadGuard aReadLock(m_aLock);
     341           0 :     css::uno::Reference< css::uno::XInterface > xCFG(m_aConfig.cfg(), css::uno::UNO_QUERY);
     342           0 :     if (
     343           0 :         (xCFG                == aEvent.Source        ) &&
     344           0 :         (m_aConfig.getMode() != ConfigAccess::E_CLOSED)
     345             :        )
     346             :     {
     347           0 :         m_aConfig.close();
     348             :     }
     349           0 :     aReadLock.unlock();
     350             :     /* } SAFE */
     351           0 : }
     352             : 
     353             : } // namespace framework
     354             : 
     355             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10