LCOV - code coverage report
Current view: top level - framework/source/jobs - jobexecutor.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 84 139 60.4 %
Date: 2014-11-03 Functions: 12 19 63.2 %
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/job.hxx>
      21             : #include <jobs/joburl.hxx>
      22             : #include <jobs/configaccess.hxx>
      23             : #include <classes/converter.hxx>
      24             : #include <general.h>
      25             : #include <stdtypes.h>
      26             : 
      27             : #include "helper/mischelper.hxx"
      28             : 
      29             : #include <com/sun/star/beans/XPropertySet.hpp>
      30             : #include <com/sun/star/container/XNameAccess.hpp>
      31             : #include <com/sun/star/container/XContainer.hpp>
      32             : #include <com/sun/star/frame/ModuleManager.hpp>
      33             : #include <com/sun/star/task/XJobExecutor.hpp>
      34             : #include <com/sun/star/container/XContainerListener.hpp>
      35             : #include <com/sun/star/lang/XEventListener.hpp>
      36             : #include <com/sun/star/lang/XServiceInfo.hpp>
      37             : #include <com/sun/star/document/XEventListener.hpp>
      38             : #include <com/sun/star/frame/XModuleManager2.hpp>
      39             : 
      40             : #include <cppuhelper/basemutex.hxx>
      41             : #include <cppuhelper/compbase4.hxx>
      42             : #include <cppuhelper/supportsservice.hxx>
      43             : #include <unotools/configpaths.hxx>
      44             : #include <rtl/ref.hxx>
      45             : #include <rtl/ustrbuf.hxx>
      46             : #include <vcl/svapp.hxx>
      47             : 
      48             : using namespace framework;
      49             : 
      50             : namespace {
      51             : 
      52             : typedef cppu::WeakComponentImplHelper4<
      53             :           css::lang::XServiceInfo
      54             :         , css::task::XJobExecutor
      55             :         , css::container::XContainerListener // => lang.XEventListener
      56             :         , css::document::XEventListener >
      57             :     Base;
      58             : 
      59             : /**
      60             :     @short  implements a job executor, which can be triggered from any code
      61             :     @descr  It uses the given trigger event to locate any registered job service
      62             :             inside the configuration and execute it. Of course it controls the
      63             :             liftime of such jobs too.
      64             :  */
      65             : class JobExecutor : private cppu::BaseMutex, public Base
      66             : {
      67             : private:
      68             : 
      69             :     /** reference to the uno service manager */
      70             :     css::uno::Reference< css::uno::XComponentContext > m_xContext;
      71             : 
      72             :     /** cached list of all registered event names of cfg for call optimization. */
      73             :     OUStringList m_lEvents;
      74             : 
      75             :     /** we listen at the configuration for changes at the event list. */
      76             :     ConfigAccess m_aConfig;
      77             : 
      78             :     /** helper to allow us listen to the configuration without a cyclic dependency */
      79             :     com::sun::star::uno::Reference<com::sun::star::container::XContainerListener> m_xConfigListener;
      80             : 
      81             :     virtual void SAL_CALL disposing() SAL_OVERRIDE;
      82             : 
      83             : public:
      84             : 
      85             :              JobExecutor( const css::uno::Reference< css::uno::XComponentContext >& xContext );
      86             :     virtual ~JobExecutor();
      87             : 
      88           0 :     virtual OUString SAL_CALL getImplementationName()
      89             :         throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
      90             :     {
      91           0 :         return OUString("com.sun.star.comp.framework.JobExecutor");
      92             :     }
      93             : 
      94           0 :     virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName)
      95             :         throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
      96             :     {
      97           0 :         return cppu::supportsService(this, ServiceName);
      98             :     }
      99             : 
     100           0 :     virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames()
     101             :         throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
     102             :     {
     103           0 :         css::uno::Sequence< OUString > aSeq(1);
     104           0 :         aSeq[0] = OUString("com.sun.star.task.JobExecutor");
     105           0 :         return aSeq;
     106             :     }
     107             : 
     108             :     // task.XJobExecutor
     109             :     virtual void SAL_CALL trigger( const OUString& sEvent ) throw(css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
     110             : 
     111             :     /// Initialization function after having acquire()'d.
     112             :     void initListeners();
     113             : 
     114             :     // document.XEventListener
     115             :     virtual void SAL_CALL notifyEvent( const css::document::EventObject& aEvent ) throw(css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
     116             : 
     117             :     // container.XContainerListener
     118             :     virtual void SAL_CALL elementInserted( const css::container::ContainerEvent& aEvent ) throw(css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
     119             :     virtual void SAL_CALL elementRemoved ( const css::container::ContainerEvent& aEvent ) throw(css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
     120             :     virtual void SAL_CALL elementReplaced( const css::container::ContainerEvent& aEvent ) throw(css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
     121             : 
     122             :     // lang.XEventListener
     123             :     virtual void SAL_CALL disposing( const css::lang::EventObject& aEvent ) throw(css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
     124             : };
     125             : 
     126             : /**
     127             :     @short      standard ctor
     128             :     @descr      It initialize this new instance.
     129             : 
     130             :     @param      xContext
     131             :                     reference to the uno service manager
     132             :  */
     133         290 : JobExecutor::JobExecutor( /*IN*/ const css::uno::Reference< css::uno::XComponentContext >& xContext )
     134             :     : Base                (m_aMutex)
     135             :     , m_xContext          (xContext                                                        )
     136         290 :     , m_aConfig           (xContext, "/org.openoffice.Office.Jobs/Events")
     137             : {
     138         290 : }
     139             : 
     140         290 : void JobExecutor::initListeners()
     141             : {
     142             :     // read the list of all currently registered events inside configuration.
     143             :     // e.g. "/org.openoffice.Office.Jobs/Events/<event name>"
     144             :     // We need it later to check if an incoming event request can be executed successfully
     145             :     // or must be rejected. It's an optimization! Of course we must implement updating of this
     146             :     // list too ... Be listener at the configuration.
     147             : 
     148         290 :     m_aConfig.open(ConfigAccess::E_READONLY);
     149         290 :     if (m_aConfig.getMode() == ConfigAccess::E_READONLY)
     150             :     {
     151             :         css::uno::Reference< css::container::XNameAccess > xRegistry(
     152         290 :                 m_aConfig.cfg(), css::uno::UNO_QUERY);
     153         290 :         if (xRegistry.is())
     154         580 :             m_lEvents = Converter::convert_seqOUString2OUStringList(
     155         580 :                     xRegistry->getElementNames());
     156             : 
     157             :         css::uno::Reference< css::container::XContainer > xNotifier(
     158         580 :                 m_aConfig.cfg(), css::uno::UNO_QUERY);
     159         290 :         if (xNotifier.is())
     160             :         {
     161         290 :             m_xConfigListener = new WeakContainerListener(this);
     162         290 :             xNotifier->addContainerListener(m_xConfigListener);
     163         290 :         }
     164             : 
     165             :         // don't close cfg here!
     166             :         // It will be done inside disposing ...
     167             :     }
     168         290 : }
     169             : 
     170         855 : JobExecutor::~JobExecutor()
     171             : {
     172         285 :     disposing();
     173         570 : }
     174             : 
     175         571 : void JobExecutor::disposing() {
     176         571 :     css::uno::Reference<css::container::XContainer> notifier;
     177        1142 :     css::uno::Reference<css::container::XContainerListener> listener;
     178             :     {
     179         571 :         osl::MutexGuard g(rBHelper.rMutex);
     180         571 :         if (m_aConfig.getMode() != ConfigAccess::E_CLOSED) {
     181         286 :             notifier.set(m_aConfig.cfg(), css::uno::UNO_QUERY);
     182         286 :             listener = m_xConfigListener;
     183         286 :             m_aConfig.close();
     184             :         }
     185         571 :         m_xConfigListener.clear();
     186             :     }
     187         571 :     if (notifier.is()) {
     188         286 :         notifier->removeContainerListener(listener);
     189         571 :     }
     190         571 : }
     191             : 
     192             : /**
     193             :     @short  implementation of XJobExecutor interface
     194             :     @descr  We use the given event to locate any registered job inside our configuration
     195             :             and execute it. Further we control the lifetime of it and suppress
     196             :             shutdown of the office till all jobs was finished.
     197             : 
     198             :     @param  sEvent
     199             :                 is used to locate registered jobs
     200             :  */
     201         191 : void SAL_CALL JobExecutor::trigger( const OUString& sEvent ) throw(css::uno::RuntimeException, std::exception)
     202             : {
     203             :     SAL_INFO( "fwk", "fwk (as96863) JobExecutor::trigger()");
     204             : 
     205         191 :     css::uno::Sequence< OUString > lJobs;
     206             : 
     207             :     /* SAFE */ {
     208         191 :     osl::MutexGuard g(rBHelper.rMutex);
     209             : 
     210             :     // Optimization!
     211             :     // Check if the given event name exist inside configuration and reject wrong requests.
     212             :     // This optimization suppress using of the cfg api for getting event and job descriptions ...
     213         191 :     if (m_lEvents.find(sEvent) == m_lEvents.end())
     214         382 :         return;
     215             : 
     216             :     // get list of all enabled jobs
     217             :     // The called static helper methods read it from the configuration and
     218             :     // filter disabled jobs using it's time stamp values.
     219           0 :     lJobs = JobData::getEnabledJobsForEvent(m_xContext, sEvent);
     220             :     } /* SAFE */
     221             : 
     222             :     // step over all enabled jobs and execute it
     223           0 :     sal_Int32 c = lJobs.getLength();
     224           0 :     for (sal_Int32 j=0; j<c; ++j)
     225             :     {
     226           0 :         rtl::Reference<Job> pJob;
     227             : 
     228             :         /* SAFE */ {
     229           0 :         SolarMutexGuard g2;
     230             : 
     231           0 :         JobData aCfg(m_xContext);
     232           0 :         aCfg.setEvent(sEvent, lJobs[j]);
     233           0 :         aCfg.setEnvironment(JobData::E_EXECUTION);
     234             : 
     235             :         /*Attention!
     236             :             Jobs implements interfaces and dies by ref count!
     237             :             And freeing of such uno object is done by uno itself.
     238             :             So we have to use dynamic memory everytimes.
     239             :          */
     240           0 :         pJob = new Job(m_xContext, css::uno::Reference< css::frame::XFrame >());
     241           0 :         pJob->setJobData(aCfg);
     242             :         } /* SAFE */
     243             : 
     244           0 :        pJob->execute(css::uno::Sequence< css::beans::NamedValue >());
     245           0 :     }
     246             : }
     247             : 
     248       70573 : void SAL_CALL JobExecutor::notifyEvent( const css::document::EventObject& aEvent ) throw(css::uno::RuntimeException, std::exception)
     249             : {
     250       70573 :     const char EVENT_ON_NEW[] = "OnNew";                            // Doc UI  event
     251       70573 :     const char EVENT_ON_LOAD[] = "OnLoad";                          // Doc UI  event
     252       70573 :     const char EVENT_ON_CREATE[] = "OnCreate";                      // Doc API event
     253       70573 :     const char EVENT_ON_LOAD_FINISHED[] = "OnLoadFinished";         // Doc API event
     254       70573 :     OUString EVENT_ON_DOCUMENT_OPENED("onDocumentOpened");   // Job UI  event : OnNew    or OnLoad
     255      141140 :     OUString EVENT_ON_DOCUMENT_ADDED("onDocumentAdded");     // Job API event : OnCreate or OnLoadFinished
     256             : 
     257      141146 :     OUString aModuleIdentifier;
     258      141144 :     ::comphelper::SequenceAsVector< JobData::TJob2DocEventBinding > lJobs;
     259             : 
     260             :     /* SAFE */ {
     261       70569 :     osl::MutexGuard g(rBHelper.rMutex);
     262             : 
     263             :     // Optimization!
     264             :     // Check if the given event name exist inside configuration and reject wrong requests.
     265             :     // This optimization suppress using of the cfg api for getting event and job descriptions.
     266             :     // see using of m_lEvents.find() below ...
     267             : 
     268             :     // retrieve event context from event source
     269             :     try
     270             :     {
     271       71062 :         aModuleIdentifier = css::frame::ModuleManager::create( m_xContext )->identify( aEvent.Source );
     272             :     }
     273         496 :     catch( const css::uno::Exception& )
     274             :     {}
     275             : 
     276             :     // Special feature: If the events "OnNew" or "OnLoad" occurs - we generate our own event "onDocumentOpened".
     277       70574 :     if (
     278      139956 :         (aEvent.EventName == EVENT_ON_NEW) ||
     279       69382 :         (aEvent.EventName == EVENT_ON_LOAD)
     280             :        )
     281             :     {
     282        1288 :         if (m_lEvents.find(EVENT_ON_DOCUMENT_OPENED) != m_lEvents.end())
     283        1288 :             JobData::appendEnabledJobsForEvent(m_xContext, EVENT_ON_DOCUMENT_OPENED, lJobs);
     284             :     }
     285             : 
     286             :     // Special feature: If the events "OnCreate" or "OnLoadFinished" occurs - we generate our own event "onDocumentAdded".
     287       70574 :     if (
     288      138762 :         (aEvent.EventName == EVENT_ON_CREATE) ||
     289       68188 :         (aEvent.EventName == EVENT_ON_LOAD_FINISHED)
     290             :        )
     291             :     {
     292        7182 :         if (m_lEvents.find(EVENT_ON_DOCUMENT_ADDED) != m_lEvents.end())
     293           0 :             JobData::appendEnabledJobsForEvent(m_xContext, EVENT_ON_DOCUMENT_ADDED, lJobs);
     294             :     }
     295             : 
     296             :     // Add all jobs for "real" notified event too .-)
     297       70574 :     if (m_lEvents.find(aEvent.EventName) != m_lEvents.end())
     298           0 :         JobData::appendEnabledJobsForEvent(m_xContext, aEvent.EventName, lJobs);
     299             :     } /* SAFE */
     300             : 
     301             :     // step over all enabled jobs and execute it
     302       70574 :     ::comphelper::SequenceAsVector< JobData::TJob2DocEventBinding >::const_iterator pIt;
     303      215580 :     for (  pIt  = lJobs.begin();
     304      143720 :            pIt != lJobs.end();
     305             :          ++pIt                 )
     306             :     {
     307        1288 :         rtl::Reference<Job> pJob;
     308             : 
     309             :         /* SAFE */ {
     310        1288 :         SolarMutexGuard g2;
     311             : 
     312        1286 :         const JobData::TJob2DocEventBinding& rBinding = *pIt;
     313             : 
     314        1310 :         JobData aCfg(m_xContext);
     315        1286 :         aCfg.setEvent(rBinding.m_sDocEvent, rBinding.m_sJobName);
     316        1286 :         aCfg.setEnvironment(JobData::E_DOCUMENTEVENT);
     317             : 
     318        1286 :         if (!aCfg.hasCorrectContext(aModuleIdentifier))
     319        1262 :             continue;
     320             : 
     321             :         /*Attention!
     322             :             Jobs implements interfaces and dies by ref count!
     323             :             And freeing of such uno object is done by uno itself.
     324             :             So we have to use dynamic memory everytimes.
     325             :          */
     326          48 :         css::uno::Reference< css::frame::XModel > xModel(aEvent.Source, css::uno::UNO_QUERY);
     327          24 :         pJob = new Job(m_xContext, xModel);
     328          48 :         pJob->setJobData(aCfg);
     329             :         } /* SAFE */
     330             : 
     331          24 :         pJob->execute(css::uno::Sequence< css::beans::NamedValue >());
     332       70596 :     }
     333       70572 : }
     334             : 
     335           0 : void SAL_CALL JobExecutor::elementInserted( const css::container::ContainerEvent& aEvent ) throw(css::uno::RuntimeException, std::exception)
     336             : {
     337           0 :     OUString sValue;
     338           0 :     if (aEvent.Accessor >>= sValue)
     339             :     {
     340           0 :         OUString sEvent = ::utl::extractFirstFromConfigurationPath(sValue);
     341           0 :         if (!sEvent.isEmpty())
     342             :         {
     343           0 :             OUStringList::iterator pEvent = m_lEvents.find(sEvent);
     344           0 :             if (pEvent == m_lEvents.end())
     345           0 :                 m_lEvents.push_back(sEvent);
     346           0 :         }
     347           0 :     }
     348           0 : }
     349             : 
     350           0 : void SAL_CALL JobExecutor::elementRemoved ( const css::container::ContainerEvent& aEvent ) throw(css::uno::RuntimeException, std::exception)
     351             : {
     352           0 :     OUString sValue;
     353           0 :     if (aEvent.Accessor >>= sValue)
     354             :     {
     355           0 :         OUString sEvent = ::utl::extractFirstFromConfigurationPath(sValue);
     356           0 :         if (!sEvent.isEmpty())
     357             :         {
     358           0 :             OUStringList::iterator pEvent = m_lEvents.find(sEvent);
     359           0 :             if (pEvent != m_lEvents.end())
     360           0 :                 m_lEvents.erase(pEvent);
     361           0 :         }
     362           0 :     }
     363           0 : }
     364             : 
     365           0 : void SAL_CALL JobExecutor::elementReplaced( const css::container::ContainerEvent& ) throw(css::uno::RuntimeException, std::exception)
     366             : {
     367             :     // I'm not interested on changed items :-)
     368           0 : }
     369             : 
     370             : /** @short  the used cfg changes notifier wish to be released in its reference.
     371             : 
     372             :     @descr  We close our internal used configuration instance to
     373             :             free this reference.
     374             : 
     375             :     @attention  For the special feature "bind global document event broadcaster to job execution"
     376             :                 this job executor instance was registered from outside code as
     377             :                 css.document.XEventListener. So it can be, that this disposing call comes from
     378             :                 the global event broadcaster service. But we don't hold any reference to this service
     379             :                 which can or must be released. Because this broadcaster itself is an one instance service
     380             :                 too, we can ignore this request. On the other side we must relase our internal CFG
     381             :                 reference ... SOLUTION => check the given event source and react only, if it's our internal
     382             :                 hold configuration object!
     383             :  */
     384           0 : void SAL_CALL JobExecutor::disposing( const css::lang::EventObject& aEvent ) throw(css::uno::RuntimeException, std::exception)
     385             : {
     386             :     /* SAFE { */
     387           0 :     osl::MutexGuard g(rBHelper.rMutex);
     388           0 :     css::uno::Reference< css::uno::XInterface > xCFG(m_aConfig.cfg(), css::uno::UNO_QUERY);
     389           0 :     if (
     390           0 :         (xCFG                == aEvent.Source        ) &&
     391           0 :         (m_aConfig.getMode() != ConfigAccess::E_CLOSED)
     392             :        )
     393             :     {
     394           0 :         m_aConfig.close();
     395           0 :     }
     396             :     /* } SAFE */
     397           0 : }
     398             : 
     399         290 : struct Instance {
     400         290 :     explicit Instance(
     401             :         css::uno::Reference<css::uno::XComponentContext> const & context):
     402             :         instance(
     403         290 :             static_cast<cppu::OWeakObject *>(new JobExecutor(context)))
     404             :     {
     405             :         // 2nd phase initialization needed
     406             :         static_cast<JobExecutor *>(static_cast<cppu::OWeakObject *>
     407         290 :                 (instance.get()))->initListeners();
     408         290 :     }
     409             : 
     410             :     rtl::Reference<css::uno::XInterface> instance;
     411             : };
     412             : 
     413             : struct Singleton:
     414             :     public rtl::StaticWithArg<
     415             :         Instance, css::uno::Reference<css::uno::XComponentContext>, Singleton>
     416             : {};
     417             : 
     418             : }
     419             : 
     420             : extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * SAL_CALL
     421         292 : com_sun_star_comp_framework_JobExecutor_get_implementation(
     422             :     css::uno::XComponentContext *context,
     423             :     css::uno::Sequence<css::uno::Any> const &)
     424             : {
     425             :     return cppu::acquire(static_cast<cppu::OWeakObject *>(
     426         292 :                 Singleton::get(context).instance.get()));
     427         951 : }
     428             : 
     429             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10