bump product version to 4.1.6.2
[LibreOffice.git] / framework / source / jobs / jobexecutor.cxx
blob54fe8469ae08d48274060271ed95f59695887bc1
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <jobs/jobexecutor.hxx>
21 #include <jobs/job.hxx>
22 #include <jobs/joburl.hxx>
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>
31 #include "helper/mischelper.hxx"
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>
38 #include <unotools/configpaths.hxx>
39 #include <rtl/ustrbuf.hxx>
40 #include <vcl/svapp.hxx>
42 #include <rtl/logfile.hxx>
44 namespace framework{
46 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)
56 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
65 DEFINE_XSERVICEINFO_ONEINSTANCESERVICE( JobExecutor ,
66 ::cppu::OWeakObject ,
67 "com.sun.star.task.JobExecutor",
68 IMPLEMENTATIONNAME_JOBEXECUTOR
71 DEFINE_INIT_SERVICE( JobExecutor,
73 m_xModuleManager = css::frame::ModuleManager::create( comphelper::getComponentContext(m_xSMGR) );
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 information!
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.
86 m_aConfig.open(ConfigAccess::E_READONLY);
87 if (m_aConfig.getMode() == ConfigAccess::E_READONLY)
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());
93 css::uno::Reference< css::container::XContainer > xNotifier(m_aConfig.cfg(), css::uno::UNO_QUERY);
94 if (xNotifier.is())
96 m_xConfigListener = new WeakContainerListener(this);
97 xNotifier->addContainerListener(m_xConfigListener);
100 // don't close cfg here!
101 // It will be done inside disposing ...
106 //________________________________
109 @short standard ctor
110 @descr It initialize this new instance.
112 @param xSMGR
113 reference to the uno service manager
115 JobExecutor::JobExecutor( /*IN*/ const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR )
116 : ThreadHelpBase (&Application::GetSolarMutex() )
117 , ::cppu::OWeakObject ( )
118 , m_xSMGR (xSMGR )
119 , m_xModuleManager ( )
120 , m_aConfig (comphelper::getComponentContext(xSMGR), OUString::createFromAscii(JobData::EVENTCFG_ROOT) )
122 // Don't do any reference related code here! Do it inside special
123 // impl_ method() ... see DEFINE_INIT_SERVICE() macro for further information.
126 JobExecutor::~JobExecutor()
128 css::uno::Reference< css::container::XContainer > xNotifier(m_aConfig.cfg(), css::uno::UNO_QUERY);
129 if (xNotifier.is())
130 xNotifier->removeContainerListener(m_xConfigListener);
133 //________________________________
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.
141 @param sEvent
142 is used to locate registered jobs
144 void SAL_CALL JobExecutor::trigger( const OUString& sEvent ) throw(css::uno::RuntimeException)
146 RTL_LOGFILE_CONTEXT(aLog, "fwk (as96863) JobExecutor::trigger()");
148 /* SAFE { */
149 ReadGuard aReadLock(m_aLock);
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 if (m_lEvents.find(sEvent) == m_lEvents.end())
155 return;
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 css::uno::Sequence< OUString > lJobs = JobData::getEnabledJobsForEvent(comphelper::getComponentContext(m_xSMGR), sEvent);
162 aReadLock.unlock();
163 /* } SAFE */
165 // step over all enabled jobs and execute it
166 sal_Int32 c = lJobs.getLength();
167 for (sal_Int32 j=0; j<c; ++j)
169 /* SAFE { */
170 aReadLock.lock();
172 JobData aCfg(comphelper::getComponentContext(m_xSMGR));
173 aCfg.setEvent(sEvent, lJobs[j]);
174 aCfg.setEnvironment(JobData::E_EXECUTION);
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.
181 Job* pJob = new Job(m_xSMGR, css::uno::Reference< css::frame::XFrame >());
182 css::uno::Reference< css::uno::XInterface > xJob(static_cast< ::cppu::OWeakObject* >(pJob), css::uno::UNO_QUERY);
183 pJob->setJobData(aCfg);
185 aReadLock.unlock();
186 /* } SAFE */
188 pJob->execute(css::uno::Sequence< css::beans::NamedValue >());
192 //________________________________
194 void SAL_CALL JobExecutor::notifyEvent( const css::document::EventObject& aEvent ) throw(css::uno::RuntimeException)
196 const char EVENT_ON_NEW[] = "OnNew"; // Doc UI event
197 const char EVENT_ON_LOAD[] = "OnLoad"; // Doc UI event
198 const char EVENT_ON_CREATE[] = "OnCreate"; // Doc API event
199 const char EVENT_ON_LOAD_FINISHED[] = "OnLoadFinished"; // Doc API event
200 OUString EVENT_ON_DOCUMENT_OPENED("onDocumentOpened"); // Job UI event : OnNew or OnLoad
201 OUString EVENT_ON_DOCUMENT_ADDED("onDocumentAdded"); // Job API event : OnCreate or OnLoadFinished
203 /* SAFE { */
204 ReadGuard aReadLock(m_aLock);
206 ::comphelper::SequenceAsVector< JobData::TJob2DocEventBinding > lJobs;
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 ...
213 // retrieve event context from event source
214 OUString aModuleIdentifier;
217 aModuleIdentifier = m_xModuleManager->identify( aEvent.Source );
219 catch( const css::uno::Exception& )
222 // Special feature: If the events "OnNew" or "OnLoad" occures - we generate our own event "onDocumentOpened".
223 if (
224 (aEvent.EventName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(EVENT_ON_NEW))) ||
225 (aEvent.EventName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(EVENT_ON_LOAD)))
228 if (m_lEvents.find(EVENT_ON_DOCUMENT_OPENED) != m_lEvents.end())
229 JobData::appendEnabledJobsForEvent(comphelper::getComponentContext(m_xSMGR), EVENT_ON_DOCUMENT_OPENED, lJobs);
232 // Special feature: If the events "OnCreate" or "OnLoadFinished" occures - we generate our own event "onDocumentAdded".
233 if (
234 (aEvent.EventName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(EVENT_ON_CREATE))) ||
235 (aEvent.EventName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(EVENT_ON_LOAD_FINISHED)))
238 if (m_lEvents.find(EVENT_ON_DOCUMENT_ADDED) != m_lEvents.end())
239 JobData::appendEnabledJobsForEvent(comphelper::getComponentContext(m_xSMGR), EVENT_ON_DOCUMENT_ADDED, lJobs);
242 // Add all jobs for "real" notified event too .-)
243 if (m_lEvents.find(aEvent.EventName) != m_lEvents.end())
244 JobData::appendEnabledJobsForEvent(comphelper::getComponentContext(m_xSMGR), aEvent.EventName, lJobs);
246 aReadLock.unlock();
247 /* } SAFE */
249 // step over all enabled jobs and execute it
250 ::comphelper::SequenceAsVector< JobData::TJob2DocEventBinding >::const_iterator pIt;
251 for ( pIt = lJobs.begin();
252 pIt != lJobs.end() ;
253 ++pIt )
255 /* SAFE { */
256 aReadLock.lock();
258 const JobData::TJob2DocEventBinding& rBinding = *pIt;
260 JobData aCfg(comphelper::getComponentContext(m_xSMGR));
261 aCfg.setEvent(rBinding.m_sDocEvent, rBinding.m_sJobName);
262 aCfg.setEnvironment(JobData::E_DOCUMENTEVENT);
264 if (!aCfg.hasCorrectContext(aModuleIdentifier))
265 continue;
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.
272 css::uno::Reference< css::frame::XModel > xModel(aEvent.Source, css::uno::UNO_QUERY);
273 Job* pJob = new Job(m_xSMGR, xModel);
274 css::uno::Reference< css::uno::XInterface > xJob(static_cast< ::cppu::OWeakObject* >(pJob), css::uno::UNO_QUERY);
275 pJob->setJobData(aCfg);
277 aReadLock.unlock();
278 /* } SAFE */
280 pJob->execute(css::uno::Sequence< css::beans::NamedValue >());
284 //________________________________
286 void SAL_CALL JobExecutor::elementInserted( const css::container::ContainerEvent& aEvent ) throw(css::uno::RuntimeException)
288 OUString sValue;
289 if (aEvent.Accessor >>= sValue)
291 OUString sEvent = ::utl::extractFirstFromConfigurationPath(sValue);
292 if (!sEvent.isEmpty())
294 OUStringList::iterator pEvent = m_lEvents.find(sEvent);
295 if (pEvent == m_lEvents.end())
296 m_lEvents.push_back(sEvent);
301 void SAL_CALL JobExecutor::elementRemoved ( const css::container::ContainerEvent& aEvent ) throw(css::uno::RuntimeException)
303 OUString sValue;
304 if (aEvent.Accessor >>= sValue)
306 OUString sEvent = ::utl::extractFirstFromConfigurationPath(sValue);
307 if (!sEvent.isEmpty())
309 OUStringList::iterator pEvent = m_lEvents.find(sEvent);
310 if (pEvent != m_lEvents.end())
311 m_lEvents.erase(pEvent);
316 void SAL_CALL JobExecutor::elementReplaced( const css::container::ContainerEvent& ) throw(css::uno::RuntimeException)
318 // I'm not interested on changed items :-)
321 //________________________________
323 /** @short the used cfg changes notifier wish to be released in its reference.
325 @descr We close our internal used configuration instance to
326 free this reference.
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!
337 void SAL_CALL JobExecutor::disposing( const css::lang::EventObject& aEvent ) throw(css::uno::RuntimeException)
339 /* SAFE { */
340 ReadGuard aReadLock(m_aLock);
341 css::uno::Reference< css::uno::XInterface > xCFG(m_aConfig.cfg(), css::uno::UNO_QUERY);
342 if (
343 (xCFG == aEvent.Source ) &&
344 (m_aConfig.getMode() != ConfigAccess::E_CLOSED)
347 m_aConfig.close();
349 aReadLock.unlock();
350 /* } SAFE */
353 } // namespace framework
355 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */