summaryrefslogtreecommitdiff
path: root/framework/source/jobs/jobexecutor.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'framework/source/jobs/jobexecutor.cxx')
-rw-r--r--framework/source/jobs/jobexecutor.cxx364
1 files changed, 364 insertions, 0 deletions
diff --git a/framework/source/jobs/jobexecutor.cxx b/framework/source/jobs/jobexecutor.cxx
new file mode 100644
index 000000000000..e3a6122d4938
--- /dev/null
+++ b/framework/source/jobs/jobexecutor.cxx
@@ -0,0 +1,364 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_framework.hxx"
+
+//________________________________
+// my own includes
+#include <jobs/jobexecutor.hxx>
+#include <jobs/job.hxx>
+#include <jobs/joburl.hxx>
+
+#ifndef __FRAMEWORK_CLASS_CONVERTER_HXX_
+#include <classes/converter.hxx>
+#endif
+#include <threadhelp/transactionguard.hxx>
+#include <threadhelp/readguard.hxx>
+#include <threadhelp/writeguard.hxx>
+#include <general.h>
+#include <services.h>
+
+//________________________________
+// interface includes
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/container/XContainer.hpp>
+
+//________________________________
+// includes of other projects
+#include <unotools/configpathes.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <vcl/svapp.hxx>
+
+#include <rtl/logfile.hxx>
+
+//________________________________
+// namespace
+
+namespace framework{
+
+//________________________________
+// non exported const
+
+//________________________________
+// non exported definitions
+
+//________________________________
+// declarations
+
+DEFINE_XINTERFACE_6( JobExecutor ,
+ OWeakObject ,
+ DIRECT_INTERFACE(css::lang::XTypeProvider ),
+ DIRECT_INTERFACE(css::lang::XServiceInfo ),
+ DIRECT_INTERFACE(css::task::XJobExecutor ),
+ DIRECT_INTERFACE(css::container::XContainerListener ),
+ DIRECT_INTERFACE(css::document::XEventListener ),
+ DERIVED_INTERFACE(css::lang::XEventListener,css::document::XEventListener)
+ )
+
+DEFINE_XTYPEPROVIDER_6( JobExecutor ,
+ css::lang::XTypeProvider ,
+ css::lang::XServiceInfo ,
+ css::task::XJobExecutor ,
+ css::container::XContainerListener,
+ css::document::XEventListener ,
+ css::lang::XEventListener
+ )
+
+DEFINE_XSERVICEINFO_ONEINSTANCESERVICE( JobExecutor ,
+ ::cppu::OWeakObject ,
+ SERVICENAME_JOBEXECUTOR ,
+ IMPLEMENTATIONNAME_JOBEXECUTOR
+ )
+
+DEFINE_INIT_SERVICE( JobExecutor,
+ {
+ /*Attention
+ I think we don't need any mutex or lock here ... because we are called by our own static method impl_createInstance()
+ to create a new instance of this class by our own supported service factory.
+ see macro DEFINE_XSERVICEINFO_MULTISERVICE and "impl_initService()" for further informations!
+ */
+ // read the list of all currently registered events inside configuration.
+ // e.g. "/org.openoffice.Office.Jobs/Events/<event name>"
+ // We need it later to check if an incoming event request can be executed successfully
+ // or must be rejected. It's an optimization! Of course we must implement updating of this
+ // list too ... Be listener at the configuration.
+
+ m_aConfig.open(ConfigAccess::E_READONLY);
+ if (m_aConfig.getMode() == ConfigAccess::E_READONLY)
+ {
+ css::uno::Reference< css::container::XNameAccess > xRegistry(m_aConfig.cfg(), css::uno::UNO_QUERY);
+ if (xRegistry.is())
+ m_lEvents = Converter::convert_seqOUString2OUStringList(xRegistry->getElementNames());
+
+ css::uno::Reference< css::container::XContainer > xNotifier(m_aConfig.cfg(), css::uno::UNO_QUERY);
+ if (xNotifier.is())
+ {
+ css::uno::Reference< css::container::XContainerListener > xThis(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY);
+ xNotifier->addContainerListener(xThis);
+ }
+
+ // don't close cfg here!
+ // It will be done inside disposing ...
+ }
+ }
+ )
+
+//________________________________
+
+/**
+ @short standard ctor
+ @descr It initialize this new instance.
+
+ @param xSMGR
+ reference to the uno service manager
+ */
+JobExecutor::JobExecutor( /*IN*/ const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR )
+ : ThreadHelpBase (&Application::GetSolarMutex() )
+ , ::cppu::OWeakObject ( )
+ , m_xSMGR (xSMGR )
+ , m_aConfig (xSMGR, ::rtl::OUString::createFromAscii(JobData::EVENTCFG_ROOT) )
+{
+ // Don't do any reference related code here! Do it inside special
+ // impl_ method() ... see DEFINE_INIT_SERVICE() macro for further informations.
+}
+
+JobExecutor::~JobExecutor()
+{
+ LOG_ASSERT(m_aConfig.getMode() == ConfigAccess::E_CLOSED, "JobExecutor::~JobExecutor()\nConfiguration don't send dispoing() message!\n")
+}
+
+//________________________________
+
+/**
+ @short implementation of XJobExecutor interface
+ @descr We use the given event to locate any registered job inside our configuration
+ and execute it. Further we control the lifetime of it and supress
+ shutdown of the office till all jobs was finished.
+
+ @param sEvent
+ is used to locate registered jobs
+ */
+void SAL_CALL JobExecutor::trigger( const ::rtl::OUString& sEvent ) throw(css::uno::RuntimeException)
+{
+ RTL_LOGFILE_CONTEXT(aLog, "fwk (as96863) JobExecutor::trigger()");
+
+ /* SAFE { */
+ ReadGuard aReadLock(m_aLock);
+
+ // Optimization!
+ // Check if the given event name exist inside configuration and reject wrong requests.
+ // This optimization supress using of the cfg api for getting event and job descriptions ...
+ if (m_lEvents.find(sEvent) == m_lEvents.end())
+ return;
+
+ // get list of all enabled jobs
+ // The called static helper methods read it from the configuration and
+ // filter disabled jobs using it's time stamp values.
+ css::uno::Sequence< ::rtl::OUString > lJobs = JobData::getEnabledJobsForEvent(m_xSMGR, sEvent);
+
+ aReadLock.unlock();
+ /* } SAFE */
+
+ // step over all enabled jobs and execute it
+ sal_Int32 c = lJobs.getLength();
+ for (sal_Int32 j=0; j<c; ++j)
+ {
+ /* SAFE { */
+ aReadLock.lock();
+
+ JobData aCfg(m_xSMGR);
+ aCfg.setEvent(sEvent, lJobs[j]);
+ aCfg.setEnvironment(JobData::E_EXECUTION);
+
+ /*Attention!
+ Jobs implements interfaces and dies by ref count!
+ And freeing of such uno object is done by uno itself.
+ So we have to use dynamic memory everytimes.
+ */
+ Job* pJob = new Job(m_xSMGR, css::uno::Reference< css::frame::XFrame >());
+ css::uno::Reference< css::uno::XInterface > xJob(static_cast< ::cppu::OWeakObject* >(pJob), css::uno::UNO_QUERY);
+ pJob->setJobData(aCfg);
+
+ aReadLock.unlock();
+ /* } SAFE */
+
+ pJob->execute(css::uno::Sequence< css::beans::NamedValue >());
+ }
+}
+
+//________________________________
+
+void SAL_CALL JobExecutor::notifyEvent( const css::document::EventObject& aEvent ) throw(css::uno::RuntimeException)
+{
+ static ::rtl::OUString EVENT_ON_NEW = DECLARE_ASCII("OnNew" ); // Doc UI event
+ static ::rtl::OUString EVENT_ON_LOAD = DECLARE_ASCII("OnLoad" ); // Doc UI event
+ static ::rtl::OUString EVENT_ON_CREATE = DECLARE_ASCII("OnCreate" ); // Doc API event
+ static ::rtl::OUString EVENT_ON_LOAD_FINISHED = DECLARE_ASCII("OnLoadFinished" ); // Doc API event
+ static ::rtl::OUString EVENT_ON_DOCUMENT_OPENED = DECLARE_ASCII("onDocumentOpened" ); // Job UI event : OnNew or OnLoad
+ static ::rtl::OUString EVENT_ON_DOCUMENT_ADDED = DECLARE_ASCII("onDocumentAdded" ); // Job API event : OnCreate or OnLoadFinished
+
+ /* SAFE { */
+ ReadGuard aReadLock(m_aLock);
+
+ ::comphelper::SequenceAsVector< JobData::TJob2DocEventBinding > lJobs;
+
+ // Optimization!
+ // Check if the given event name exist inside configuration and reject wrong requests.
+ // This optimization supress using of the cfg api for getting event and job descriptions.
+ // see using of m_lEvents.find() below ...
+
+ // Special feature: If the events "OnNew" or "OnLoad" occures - we generate our own event "onDocumentOpened".
+ if (
+ (aEvent.EventName.equals(EVENT_ON_NEW )) ||
+ (aEvent.EventName.equals(EVENT_ON_LOAD))
+ )
+ {
+ if (m_lEvents.find(EVENT_ON_DOCUMENT_OPENED) != m_lEvents.end())
+ JobData::appendEnabledJobsForEvent(m_xSMGR, EVENT_ON_DOCUMENT_OPENED, lJobs);
+ }
+
+ // Special feature: If the events "OnCreate" or "OnLoadFinished" occures - we generate our own event "onDocumentAdded".
+ if (
+ (aEvent.EventName.equals(EVENT_ON_CREATE )) ||
+ (aEvent.EventName.equals(EVENT_ON_LOAD_FINISHED))
+ )
+ {
+ if (m_lEvents.find(EVENT_ON_DOCUMENT_ADDED) != m_lEvents.end())
+ JobData::appendEnabledJobsForEvent(m_xSMGR, EVENT_ON_DOCUMENT_ADDED, lJobs);
+ }
+
+ // Add all jobs for "real" notified event too .-)
+ if (m_lEvents.find(aEvent.EventName) != m_lEvents.end())
+ JobData::appendEnabledJobsForEvent(m_xSMGR, aEvent.EventName, lJobs);
+
+ aReadLock.unlock();
+ /* } SAFE */
+
+ // step over all enabled jobs and execute it
+ ::comphelper::SequenceAsVector< JobData::TJob2DocEventBinding >::const_iterator pIt;
+ for ( pIt = lJobs.begin();
+ pIt != lJobs.end() ;
+ ++pIt )
+ {
+ /* SAFE { */
+ aReadLock.lock();
+
+ const JobData::TJob2DocEventBinding& rBinding = *pIt;
+
+ JobData aCfg(m_xSMGR);
+ aCfg.setEvent(rBinding.m_sDocEvent, rBinding.m_sJobName);
+ aCfg.setEnvironment(JobData::E_DOCUMENTEVENT);
+
+ /*Attention!
+ Jobs implements interfaces and dies by ref count!
+ And freeing of such uno object is done by uno itself.
+ So we have to use dynamic memory everytimes.
+ */
+ css::uno::Reference< css::frame::XModel > xModel(aEvent.Source, css::uno::UNO_QUERY);
+ Job* pJob = new Job(m_xSMGR, xModel);
+ css::uno::Reference< css::uno::XInterface > xJob(static_cast< ::cppu::OWeakObject* >(pJob), css::uno::UNO_QUERY);
+ pJob->setJobData(aCfg);
+
+ aReadLock.unlock();
+ /* } SAFE */
+
+ pJob->execute(css::uno::Sequence< css::beans::NamedValue >());
+ }
+}
+
+//________________________________
+
+void SAL_CALL JobExecutor::elementInserted( const css::container::ContainerEvent& aEvent ) throw(css::uno::RuntimeException)
+{
+ ::rtl::OUString sValue;
+ if (aEvent.Accessor >>= sValue)
+ {
+ ::rtl::OUString sEvent = ::utl::extractFirstFromConfigurationPath(sValue);
+ if (sEvent.getLength() > 0)
+ {
+ OUStringList::iterator pEvent = m_lEvents.find(sEvent);
+ if (pEvent == m_lEvents.end())
+ m_lEvents.push_back(sEvent);
+ }
+ }
+}
+
+void SAL_CALL JobExecutor::elementRemoved ( const css::container::ContainerEvent& aEvent ) throw(css::uno::RuntimeException)
+{
+ ::rtl::OUString sValue;
+ if (aEvent.Accessor >>= sValue)
+ {
+ ::rtl::OUString sEvent = ::utl::extractFirstFromConfigurationPath(sValue);
+ if (sEvent.getLength() > 0)
+ {
+ OUStringList::iterator pEvent = m_lEvents.find(sEvent);
+ if (pEvent != m_lEvents.end())
+ m_lEvents.erase(pEvent);
+ }
+ }
+}
+
+void SAL_CALL JobExecutor::elementReplaced( const css::container::ContainerEvent& ) throw(css::uno::RuntimeException)
+{
+ // I'm not interested on changed items :-)
+}
+
+//________________________________
+
+/** @short the used cfg changes notifier wish to be released in its reference.
+
+ @descr We close our internal used configuration instance to
+ free this reference.
+
+ @attention For the special feature "bind global document event broadcaster to job execution"
+ this job executor instance was registered from outside code as
+ css.document.XEventListener. So it can be, that this disposing call comes from
+ the global event broadcaster service. But we don't hold any reference to this service
+ which can or must be released. Because this broadcaster itself is an one instance service
+ too, we can ignore this request. On the other side we must relase our internal CFG
+ reference ... SOLUTION => check the given event source and react only, if it's our internal
+ hold configuration object!
+ */
+void SAL_CALL JobExecutor::disposing( const css::lang::EventObject& aEvent ) throw(css::uno::RuntimeException)
+{
+ /* SAFE { */
+ ReadGuard aReadLock(m_aLock);
+ css::uno::Reference< css::uno::XInterface > xCFG(m_aConfig.cfg(), css::uno::UNO_QUERY);
+ if (
+ (xCFG == aEvent.Source ) &&
+ (m_aConfig.getMode() != ConfigAccess::E_CLOSED)
+ )
+ {
+ m_aConfig.close();
+ }
+ aReadLock.unlock();
+ /* } SAFE */
+}
+
+} // namespace framework