fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / framework / source / jobs / jobexecutor.cxx
blob5ce6b99bad3e02a9a81413d8d8b79c29db0e9bcb
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/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>
27 #include "helper/mischelper.hxx"
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>
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>
48 using namespace framework;
50 namespace {
52 typedef cppu::WeakComponentImplHelper4<
53 css::lang::XServiceInfo
54 , css::task::XJobExecutor
55 , css::container::XContainerListener // => lang.XEventListener
56 , css::document::XEventListener >
57 Base;
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 lifetime of such jobs too.
65 class JobExecutor : private cppu::BaseMutex, public Base
67 private:
69 /** reference to the uno service manager */
70 css::uno::Reference< css::uno::XComponentContext > m_xContext;
72 /** cached list of all registered event names of cfg for call optimization. */
73 OUStringList m_lEvents;
75 /** we listen at the configuration for changes at the event list. */
76 ConfigAccess m_aConfig;
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;
81 virtual void SAL_CALL disposing() SAL_OVERRIDE;
83 public:
85 JobExecutor( const css::uno::Reference< css::uno::XComponentContext >& xContext );
86 virtual ~JobExecutor();
88 virtual OUString SAL_CALL getImplementationName()
89 throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
91 return OUString("com.sun.star.comp.framework.JobExecutor");
94 virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName)
95 throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
97 return cppu::supportsService(this, ServiceName);
100 virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames()
101 throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
103 css::uno::Sequence< OUString > aSeq(1);
104 aSeq[0] = "com.sun.star.task.JobExecutor";
105 return aSeq;
108 // task.XJobExecutor
109 virtual void SAL_CALL trigger( const OUString& sEvent ) throw(css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
111 /// Initialization function after having acquire()'d.
112 void initListeners();
114 // document.XEventListener
115 virtual void SAL_CALL notifyEvent( const css::document::EventObject& aEvent ) throw(css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
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;
122 // lang.XEventListener
123 virtual void SAL_CALL disposing( const css::lang::EventObject& aEvent ) throw(css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
127 @short standard ctor
128 @descr It initialize this new instance.
130 @param xContext
131 reference to the uno service manager
133 JobExecutor::JobExecutor( /*IN*/ const css::uno::Reference< css::uno::XComponentContext >& xContext )
134 : Base (m_aMutex)
135 , m_xContext (xContext )
136 , m_aConfig (xContext, "/org.openoffice.Office.Jobs/Events")
140 void JobExecutor::initListeners()
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.
148 m_aConfig.open(ConfigAccess::E_READONLY);
149 if (m_aConfig.getMode() == ConfigAccess::E_READONLY)
151 css::uno::Reference< css::container::XNameAccess > xRegistry(
152 m_aConfig.cfg(), css::uno::UNO_QUERY);
153 if (xRegistry.is())
154 m_lEvents = Converter::convert_seqOUString2OUStringList(
155 xRegistry->getElementNames());
157 css::uno::Reference< css::container::XContainer > xNotifier(
158 m_aConfig.cfg(), css::uno::UNO_QUERY);
159 if (xNotifier.is())
161 m_xConfigListener = new WeakContainerListener(this);
162 xNotifier->addContainerListener(m_xConfigListener);
165 // don't close cfg here!
166 // It will be done inside disposing ...
170 JobExecutor::~JobExecutor()
172 disposing();
175 void JobExecutor::disposing() {
176 css::uno::Reference<css::container::XContainer> notifier;
177 css::uno::Reference<css::container::XContainerListener> listener;
179 osl::MutexGuard g(rBHelper.rMutex);
180 if (m_aConfig.getMode() != ConfigAccess::E_CLOSED) {
181 notifier.set(m_aConfig.cfg(), css::uno::UNO_QUERY);
182 listener = m_xConfigListener;
183 m_aConfig.close();
185 m_xConfigListener.clear();
187 if (notifier.is()) {
188 notifier->removeContainerListener(listener);
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.
198 @param sEvent
199 is used to locate registered jobs
201 void SAL_CALL JobExecutor::trigger( const OUString& sEvent ) throw(css::uno::RuntimeException, std::exception)
203 SAL_INFO( "fwk", "JobExecutor::trigger()");
205 css::uno::Sequence< OUString > lJobs;
207 /* SAFE */ {
208 osl::MutexGuard g(rBHelper.rMutex);
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 if (framework::find(m_lEvents, sEvent) == m_lEvents.end())
214 return;
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 lJobs = JobData::getEnabledJobsForEvent(m_xContext, sEvent);
220 } /* SAFE */
222 // step over all enabled jobs and execute it
223 sal_Int32 c = lJobs.getLength();
224 for (sal_Int32 j=0; j<c; ++j)
226 rtl::Reference<Job> pJob;
228 /* SAFE */ {
229 SolarMutexGuard g2;
231 JobData aCfg(m_xContext);
232 aCfg.setEvent(sEvent, lJobs[j]);
233 aCfg.setEnvironment(JobData::E_EXECUTION);
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.
240 pJob = new Job(m_xContext, css::uno::Reference< css::frame::XFrame >());
241 pJob->setJobData(aCfg);
242 } /* SAFE */
244 pJob->execute(css::uno::Sequence< css::beans::NamedValue >());
248 void SAL_CALL JobExecutor::notifyEvent( const css::document::EventObject& aEvent ) throw(css::uno::RuntimeException, std::exception)
250 const char EVENT_ON_NEW[] = "OnNew"; // Doc UI event
251 const char EVENT_ON_LOAD[] = "OnLoad"; // Doc UI event
252 const char EVENT_ON_CREATE[] = "OnCreate"; // Doc API event
253 const char EVENT_ON_LOAD_FINISHED[] = "OnLoadFinished"; // Doc API event
254 OUString EVENT_ON_DOCUMENT_OPENED("onDocumentOpened"); // Job UI event : OnNew or OnLoad
255 OUString EVENT_ON_DOCUMENT_ADDED("onDocumentAdded"); // Job API event : OnCreate or OnLoadFinished
257 OUString aModuleIdentifier;
258 ::std::vector< JobData::TJob2DocEventBinding > lJobs;
260 /* SAFE */ {
261 osl::MutexGuard g(rBHelper.rMutex);
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 ...
268 // retrieve event context from event source
271 aModuleIdentifier = css::frame::ModuleManager::create( m_xContext )->identify( aEvent.Source );
273 catch( const css::uno::Exception& )
276 // Special feature: If the events "OnNew" or "OnLoad" occurs - we generate our own event "onDocumentOpened".
277 if (
278 (aEvent.EventName == EVENT_ON_NEW) ||
279 (aEvent.EventName == EVENT_ON_LOAD)
282 if (find(m_lEvents, EVENT_ON_DOCUMENT_OPENED) != m_lEvents.end())
283 JobData::appendEnabledJobsForEvent(m_xContext, EVENT_ON_DOCUMENT_OPENED, lJobs);
286 // Special feature: If the events "OnCreate" or "OnLoadFinished" occurs - we generate our own event "onDocumentAdded".
287 if (
288 (aEvent.EventName == EVENT_ON_CREATE) ||
289 (aEvent.EventName == EVENT_ON_LOAD_FINISHED)
292 if (find(m_lEvents, EVENT_ON_DOCUMENT_ADDED) != m_lEvents.end())
293 JobData::appendEnabledJobsForEvent(m_xContext, EVENT_ON_DOCUMENT_ADDED, lJobs);
296 // Add all jobs for "real" notified event too .-)
297 if (find(m_lEvents, aEvent.EventName) != m_lEvents.end())
298 JobData::appendEnabledJobsForEvent(m_xContext, aEvent.EventName, lJobs);
299 } /* SAFE */
301 // step over all enabled jobs and execute it
302 ::std::vector< JobData::TJob2DocEventBinding >::const_iterator pIt;
303 for ( pIt = lJobs.begin();
304 pIt != lJobs.end();
305 ++pIt )
307 rtl::Reference<Job> pJob;
309 /* SAFE */ {
310 SolarMutexGuard g2;
312 const JobData::TJob2DocEventBinding& rBinding = *pIt;
314 JobData aCfg(m_xContext);
315 aCfg.setEvent(rBinding.m_sDocEvent, rBinding.m_sJobName);
316 aCfg.setEnvironment(JobData::E_DOCUMENTEVENT);
318 if (!aCfg.hasCorrectContext(aModuleIdentifier))
319 continue;
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.
326 css::uno::Reference< css::frame::XModel > xModel(aEvent.Source, css::uno::UNO_QUERY);
327 pJob = new Job(m_xContext, xModel);
328 pJob->setJobData(aCfg);
329 } /* SAFE */
331 pJob->execute(css::uno::Sequence< css::beans::NamedValue >());
335 void SAL_CALL JobExecutor::elementInserted( const css::container::ContainerEvent& aEvent ) throw(css::uno::RuntimeException, std::exception)
337 OUString sValue;
338 if (aEvent.Accessor >>= sValue)
340 OUString sEvent = ::utl::extractFirstFromConfigurationPath(sValue);
341 if (!sEvent.isEmpty())
343 OUStringList::iterator pEvent = find(m_lEvents, sEvent);
344 if (pEvent == m_lEvents.end())
345 m_lEvents.push_back(sEvent);
350 void SAL_CALL JobExecutor::elementRemoved ( const css::container::ContainerEvent& aEvent ) throw(css::uno::RuntimeException, std::exception)
352 OUString sValue;
353 if (aEvent.Accessor >>= sValue)
355 OUString sEvent = ::utl::extractFirstFromConfigurationPath(sValue);
356 if (!sEvent.isEmpty())
358 OUStringList::iterator pEvent = find(m_lEvents, sEvent);
359 if (pEvent != m_lEvents.end())
360 m_lEvents.erase(pEvent);
365 void SAL_CALL JobExecutor::elementReplaced( const css::container::ContainerEvent& ) throw(css::uno::RuntimeException, std::exception)
367 // I'm not interested on changed items :-)
370 /** @short the used cfg changes notifier wish to be released in its reference.
372 @descr We close our internal used configuration instance to
373 free this reference.
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!
384 void SAL_CALL JobExecutor::disposing( const css::lang::EventObject& aEvent ) throw(css::uno::RuntimeException, std::exception)
386 /* SAFE { */
387 osl::MutexGuard g(rBHelper.rMutex);
388 css::uno::Reference< css::uno::XInterface > xCFG(m_aConfig.cfg(), css::uno::UNO_QUERY);
389 if (
390 (xCFG == aEvent.Source ) &&
391 (m_aConfig.getMode() != ConfigAccess::E_CLOSED)
394 m_aConfig.close();
396 /* } SAFE */
399 struct Instance {
400 explicit Instance(
401 css::uno::Reference<css::uno::XComponentContext> const & context):
402 instance(
403 static_cast<cppu::OWeakObject *>(new JobExecutor(context)))
405 // 2nd phase initialization needed
406 static_cast<JobExecutor *>(static_cast<cppu::OWeakObject *>
407 (instance.get()))->initListeners();
410 rtl::Reference<css::uno::XInterface> instance;
413 struct Singleton:
414 public rtl::StaticWithArg<
415 Instance, css::uno::Reference<css::uno::XComponentContext>, Singleton>
420 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * SAL_CALL
421 com_sun_star_comp_framework_JobExecutor_get_implementation(
422 css::uno::XComponentContext *context,
423 css::uno::Sequence<css::uno::Any> const &)
425 return cppu::acquire(static_cast<cppu::OWeakObject *>(
426 Singleton::get(context).instance.get()));
429 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */