1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: jobexecutor.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_framework.hxx"
34 //________________________________
36 #include <jobs/jobexecutor.hxx>
37 #include <jobs/job.hxx>
38 #include <jobs/joburl.hxx>
40 #ifndef __FRAMEWORK_CLASS_CONVERTER_HXX_
41 #include <classes/converter.hxx>
43 #include <threadhelp/transactionguard.hxx>
44 #include <threadhelp/readguard.hxx>
45 #include <threadhelp/writeguard.hxx>
49 //________________________________
51 #include <com/sun/star/beans/XPropertySet.hpp>
52 #include <com/sun/star/container/XNameAccess.hpp>
53 #include <com/sun/star/container/XContainer.hpp>
55 //________________________________
56 // includes of other projects
57 #include <unotools/configpathes.hxx>
58 #include <rtl/ustrbuf.hxx>
59 #include <vcl/svapp.hxx>
61 #include <rtl/logfile.hxx>
63 //________________________________
68 //________________________________
71 //________________________________
72 // non exported definitions
74 //________________________________
77 DEFINE_XINTERFACE_6( JobExecutor
,
79 DIRECT_INTERFACE(css::lang::XTypeProvider
),
80 DIRECT_INTERFACE(css::lang::XServiceInfo
),
81 DIRECT_INTERFACE(css::task::XJobExecutor
),
82 DIRECT_INTERFACE(css::container::XContainerListener
),
83 DIRECT_INTERFACE(css::document::XEventListener
),
84 DERIVED_INTERFACE(css::lang::XEventListener
,css::document::XEventListener
)
87 DEFINE_XTYPEPROVIDER_6( JobExecutor
,
88 css::lang::XTypeProvider
,
89 css::lang::XServiceInfo
,
90 css::task::XJobExecutor
,
91 css::container::XContainerListener
,
92 css::document::XEventListener
,
93 css::lang::XEventListener
96 DEFINE_XSERVICEINFO_ONEINSTANCESERVICE( JobExecutor
,
98 SERVICENAME_JOBEXECUTOR
,
99 IMPLEMENTATIONNAME_JOBEXECUTOR
102 DEFINE_INIT_SERVICE( JobExecutor
,
105 I think we don't need any mutex or lock here ... because we are called by our own static method impl_createInstance()
106 to create a new instance of this class by our own supported service factory.
107 see macro DEFINE_XSERVICEINFO_MULTISERVICE and "impl_initService()" for further informations!
109 // read the list of all currently registered events inside configuration.
110 // e.g. "/org.openoffice.Office.Jobs/Events/<event name>"
111 // We need it later to check if an incoming event request can be executed successfully
112 // or must be rejected. It's an optimization! Of course we must implement updating of this
113 // list too ... Be listener at the configuration.
115 m_aConfig
.open(ConfigAccess::E_READONLY
);
116 if (m_aConfig
.getMode() == ConfigAccess::E_READONLY
)
118 css::uno::Reference
< css::container::XNameAccess
> xRegistry(m_aConfig
.cfg(), css::uno::UNO_QUERY
);
120 m_lEvents
= Converter::convert_seqOUString2OUStringList(xRegistry
->getElementNames());
122 css::uno::Reference
< css::container::XContainer
> xNotifier(m_aConfig
.cfg(), css::uno::UNO_QUERY
);
125 css::uno::Reference
< css::container::XContainerListener
> xThis(static_cast< ::cppu::OWeakObject
* >(this), css::uno::UNO_QUERY
);
126 xNotifier
->addContainerListener(xThis
);
129 // don't close cfg here!
130 // It will be done inside disposing ...
135 //________________________________
139 @descr It initialize this new instance.
142 reference to the uno service manager
144 JobExecutor::JobExecutor( /*IN*/ const css::uno::Reference
< css::lang::XMultiServiceFactory
>& xSMGR
)
145 : ThreadHelpBase (&Application::GetSolarMutex() )
146 , ::cppu::OWeakObject ( )
148 , m_aConfig (xSMGR
, ::rtl::OUString::createFromAscii(JobData::EVENTCFG_ROOT
) )
150 // Don't do any reference related code here! Do it inside special
151 // impl_ method() ... see DEFINE_INIT_SERVICE() macro for further informations.
154 JobExecutor::~JobExecutor()
156 LOG_ASSERT(m_aConfig
.getMode() == ConfigAccess::E_CLOSED
, "JobExecutor::~JobExecutor()\nConfiguration don't send dispoing() message!\n")
159 //________________________________
162 @short implementation of XJobExecutor interface
163 @descr We use the given event to locate any registered job inside our configuration
164 and execute it. Further we control the lifetime of it and supress
165 shutdown of the office till all jobs was finished.
168 is used to locate registered jobs
170 void SAL_CALL
JobExecutor::trigger( const ::rtl::OUString
& sEvent
) throw(css::uno::RuntimeException
)
172 RTL_LOGFILE_CONTEXT(aLog
, "fwk (as96863) JobExecutor::trigger()");
175 ReadGuard
aReadLock(m_aLock
);
178 // Check if the given event name exist inside configuration and reject wrong requests.
179 // This optimization supress using of the cfg api for getting event and job descriptions ...
180 if (m_lEvents
.find(sEvent
) == m_lEvents
.end())
183 // get list of all enabled jobs
184 // The called static helper methods read it from the configuration and
185 // filter disabled jobs using it's time stamp values.
186 css::uno::Sequence
< ::rtl::OUString
> lJobs
= JobData::getEnabledJobsForEvent(m_xSMGR
, sEvent
);
191 // step over all enabled jobs and execute it
192 sal_Int32 c
= lJobs
.getLength();
193 for (sal_Int32 j
=0; j
<c
; ++j
)
198 JobData
aCfg(m_xSMGR
);
199 aCfg
.setEvent(sEvent
, lJobs
[j
]);
200 aCfg
.setEnvironment(JobData::E_EXECUTION
);
203 Jobs implements interfaces and dies by ref count!
204 And freeing of such uno object is done by uno itself.
205 So we have to use dynamic memory everytimes.
207 Job
* pJob
= new Job(m_xSMGR
, css::uno::Reference
< css::frame::XFrame
>());
208 css::uno::Reference
< css::uno::XInterface
> xJob(static_cast< ::cppu::OWeakObject
* >(pJob
), css::uno::UNO_QUERY
);
209 pJob
->setJobData(aCfg
);
214 pJob
->execute(css::uno::Sequence
< css::beans::NamedValue
>());
218 //________________________________
220 void SAL_CALL
JobExecutor::notifyEvent( const css::document::EventObject
& aEvent
) throw(css::uno::RuntimeException
)
222 static ::rtl::OUString EVENT_ON_NEW
= DECLARE_ASCII("OnNew" ); // Doc UI event
223 static ::rtl::OUString EVENT_ON_LOAD
= DECLARE_ASCII("OnLoad" ); // Doc UI event
224 static ::rtl::OUString EVENT_ON_CREATE
= DECLARE_ASCII("OnCreate" ); // Doc API event
225 static ::rtl::OUString EVENT_ON_LOAD_FINISHED
= DECLARE_ASCII("OnLoadFinished" ); // Doc API event
226 static ::rtl::OUString EVENT_ON_DOCUMENT_OPENED
= DECLARE_ASCII("onDocumentOpened" ); // Job UI event : OnNew or OnLoad
227 static ::rtl::OUString EVENT_ON_DOCUMENT_ADDED
= DECLARE_ASCII("onDocumentAdded" ); // Job API event : OnCreate or OnLoadFinished
230 ReadGuard
aReadLock(m_aLock
);
232 ::comphelper::SequenceAsVector
< JobData::TJob2DocEventBinding
> lJobs
;
235 // Check if the given event name exist inside configuration and reject wrong requests.
236 // This optimization supress using of the cfg api for getting event and job descriptions.
237 // see using of m_lEvents.find() below ...
239 // Special feature: If the events "OnNew" or "OnLoad" occures - we generate our own event "onDocumentOpened".
241 (aEvent
.EventName
.equals(EVENT_ON_NEW
)) ||
242 (aEvent
.EventName
.equals(EVENT_ON_LOAD
))
245 if (m_lEvents
.find(EVENT_ON_DOCUMENT_OPENED
) != m_lEvents
.end())
246 JobData::appendEnabledJobsForEvent(m_xSMGR
, EVENT_ON_DOCUMENT_OPENED
, lJobs
);
249 // Special feature: If the events "OnCreate" or "OnLoadFinished" occures - we generate our own event "onDocumentAdded".
251 (aEvent
.EventName
.equals(EVENT_ON_CREATE
)) ||
252 (aEvent
.EventName
.equals(EVENT_ON_LOAD_FINISHED
))
255 if (m_lEvents
.find(EVENT_ON_DOCUMENT_ADDED
) != m_lEvents
.end())
256 JobData::appendEnabledJobsForEvent(m_xSMGR
, EVENT_ON_DOCUMENT_ADDED
, lJobs
);
259 // Add all jobs for "real" notified event too .-)
260 if (m_lEvents
.find(aEvent
.EventName
) != m_lEvents
.end())
261 JobData::appendEnabledJobsForEvent(m_xSMGR
, aEvent
.EventName
, lJobs
);
266 // step over all enabled jobs and execute it
267 ::comphelper::SequenceAsVector
< JobData::TJob2DocEventBinding
>::const_iterator pIt
;
268 for ( pIt
= lJobs
.begin();
275 const JobData::TJob2DocEventBinding
& rBinding
= *pIt
;
277 JobData
aCfg(m_xSMGR
);
278 aCfg
.setEvent(rBinding
.m_sDocEvent
, rBinding
.m_sJobName
);
279 aCfg
.setEnvironment(JobData::E_DOCUMENTEVENT
);
282 Jobs implements interfaces and dies by ref count!
283 And freeing of such uno object is done by uno itself.
284 So we have to use dynamic memory everytimes.
286 css::uno::Reference
< css::frame::XModel
> xModel(aEvent
.Source
, css::uno::UNO_QUERY
);
287 Job
* pJob
= new Job(m_xSMGR
, xModel
);
288 css::uno::Reference
< css::uno::XInterface
> xJob(static_cast< ::cppu::OWeakObject
* >(pJob
), css::uno::UNO_QUERY
);
289 pJob
->setJobData(aCfg
);
294 pJob
->execute(css::uno::Sequence
< css::beans::NamedValue
>());
298 //________________________________
300 void SAL_CALL
JobExecutor::elementInserted( const css::container::ContainerEvent
& aEvent
) throw(css::uno::RuntimeException
)
302 ::rtl::OUString sValue
;
303 if (aEvent
.Accessor
>>= sValue
)
305 ::rtl::OUString sEvent
= ::utl::extractFirstFromConfigurationPath(sValue
);
306 if (sEvent
.getLength() > 0)
308 OUStringList::iterator pEvent
= m_lEvents
.find(sEvent
);
309 if (pEvent
== m_lEvents
.end())
310 m_lEvents
.push_back(sEvent
);
315 void SAL_CALL
JobExecutor::elementRemoved ( const css::container::ContainerEvent
& aEvent
) throw(css::uno::RuntimeException
)
317 ::rtl::OUString sValue
;
318 if (aEvent
.Accessor
>>= sValue
)
320 ::rtl::OUString sEvent
= ::utl::extractFirstFromConfigurationPath(sValue
);
321 if (sEvent
.getLength() > 0)
323 OUStringList::iterator pEvent
= m_lEvents
.find(sEvent
);
324 if (pEvent
!= m_lEvents
.end())
325 m_lEvents
.erase(pEvent
);
330 void SAL_CALL
JobExecutor::elementReplaced( const css::container::ContainerEvent
& ) throw(css::uno::RuntimeException
)
332 // I'm not interested on changed items :-)
335 //________________________________
337 /** @short the used cfg changes notifier wish to be released in its reference.
339 @descr We close our internal used configuration instance to
342 @attention For the special feature "bind global document event broadcaster to job execution"
343 this job executor instance was registered from outside code as
344 css.document.XEventListener. So it can be, that this disposing call comes from
345 the global event broadcaster service. But we don't hold any reference to this service
346 which can or must be released. Because this broadcaster itself is an one instance service
347 too, we can ignore this request. On the other side we must relase our internal CFG
348 reference ... SOLUTION => check the given event source and react only, if it's our internal
349 hold configuration object!
351 void SAL_CALL
JobExecutor::disposing( const css::lang::EventObject
& aEvent
) throw(css::uno::RuntimeException
)
354 ReadGuard
aReadLock(m_aLock
);
355 css::uno::Reference
< css::uno::XInterface
> xCFG(m_aConfig
.cfg(), css::uno::UNO_QUERY
);
357 (xCFG
== aEvent
.Source
) &&
358 (m_aConfig
.getMode() != ConfigAccess::E_CLOSED
)
367 } // namespace framework