summaryrefslogtreecommitdiff
path: root/framework/source/jobs
diff options
context:
space:
mode:
Diffstat (limited to 'framework/source/jobs')
-rw-r--r--framework/source/jobs/configaccess.cxx242
-rw-r--r--framework/source/jobs/helponstartup.cxx423
-rw-r--r--framework/source/jobs/job.cxx944
-rw-r--r--framework/source/jobs/jobconst.cxx74
-rw-r--r--framework/source/jobs/jobdata.cxx714
-rw-r--r--framework/source/jobs/jobdispatch.cxx475
-rw-r--r--framework/source/jobs/jobexecutor.cxx364
-rw-r--r--framework/source/jobs/jobresult.cxx261
-rw-r--r--framework/source/jobs/joburl.cxx657
-rw-r--r--framework/source/jobs/makefile.mk53
-rw-r--r--framework/source/jobs/shelljob.cxx214
11 files changed, 4421 insertions, 0 deletions
diff --git a/framework/source/jobs/configaccess.cxx b/framework/source/jobs/configaccess.cxx
new file mode 100644
index 000000000000..95226268ce2b
--- /dev/null
+++ b/framework/source/jobs/configaccess.cxx
@@ -0,0 +1,242 @@
+ /*************************************************************************
+ *
+ * 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/configaccess.hxx>
+#include <threadhelp/readguard.hxx>
+#include <threadhelp/writeguard.hxx>
+#include <threadhelp/resetableguard.hxx>
+#include <general.h>
+#include <services.h>
+
+//________________________________
+// interface includes
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XMultiHierarchicalPropertySet.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/util/XChangesBatch.hpp>
+
+//________________________________
+// includes of other projects
+#include <unotools/configpathes.hxx>
+#include <rtl/ustrbuf.hxx>
+
+//________________________________
+// namespace
+
+namespace framework{
+
+//________________________________
+// non exported const
+
+//________________________________
+// non exported definitions
+
+//________________________________
+// declarations
+
+//________________________________
+/**
+ @short open the configuration of this job
+ @descr We open the configuration of this job only. Not the whole package or the whole
+ job set. We are interested on our own properties only.
+ We set the opened configuration access as our member. So any following method,
+ which needs cfg access, can use it. That prevent us against multiple open/close requests.
+ But you can use this method to upgrade an already opened configuration too.
+
+ @param eMode
+ force opening of the configuration access in readonly or in read/write mode
+ */
+ConfigAccess::ConfigAccess( /*IN*/ const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR ,
+ /*IN*/ const ::rtl::OUString& sRoot )
+ : ThreadHelpBase( )
+ , m_xSMGR ( xSMGR )
+ , m_sRoot ( sRoot )
+ , m_eMode ( E_CLOSED )
+{
+}
+
+//________________________________
+/**
+ @short last chance to close an open configuration access point
+ @descr In case our user forgot to close this configuration point
+ in the right way, normaly he will run into some trouble -
+ e.g. losing data.
+ */
+ConfigAccess::~ConfigAccess()
+{
+ close();
+}
+
+//________________________________
+/**
+ @short return the internal mode of this instance
+ @descr May be the outside user need any information about successfully opened
+ or closed config access point objects. He can control the internal mode to do so.
+
+ @return The internal open state of this object.
+ */
+ConfigAccess::EOpenMode ConfigAccess::getMode() const
+{
+ /* SAFE { */
+ ReadGuard aReadLock(m_aLock);
+ return m_eMode;
+ /* } SAFE */
+}
+
+//________________________________
+/**
+ @short open the configuration access in the specified mode
+ @descr We set the opened configuration access as our member. So any following method,
+ which needs cfg access, can use it. That prevent us against multiple open/close requests.
+ But you can use this method to upgrade an already opened configuration too.
+ It's possible to open a config access in READONLY mode first and "open" it at a second
+ time within the mode READWRITE. Then we will upgrade it. Dowgrade will be possible too.
+
+ But note: closing will be done explicitly by calling method close() ... not by
+ downgrading with mode CLOSED!
+
+ @param eMode
+ force (re)opening of the configuration access in readonly or in read/write mode
+ */
+void ConfigAccess::open( /*IN*/ EOpenMode eMode )
+{
+ /* SAFE { */
+ // We must lock the whole method to be shure, that nobody
+ // outside uses our internal member m_xAccess!
+ WriteGuard aWriteLock(m_aLock);
+
+ // check if configuration is already open in the right mode.
+ // By the way: Don't allow closing by using this method!
+ if (
+ (eMode !=E_CLOSED) &&
+ (m_eMode!=eMode )
+ )
+ {
+ // We have to close the old access point without any question here.
+ // It will be open again using the new mode.
+ // can be called without checks! It does the checks by itself ...
+ // e.g. for already closed or not opened configuration.
+ // Flushing of all made changes will be done here too.
+ close();
+
+ // create the configuration provider, which provides sub access points
+ css::uno::Reference< css::lang::XMultiServiceFactory > xConfigProvider(m_xSMGR->createInstance(SERVICENAME_CFGPROVIDER), css::uno::UNO_QUERY);
+ if (xConfigProvider.is())
+ {
+ css::beans::PropertyValue aParam;
+ aParam.Name = DECLARE_ASCII("nodepath");
+ aParam.Value <<= m_sRoot;
+
+ css::uno::Sequence< css::uno::Any > lParams(1);
+ lParams[0] <<= aParam;
+
+ // open it
+ try
+ {
+ if (eMode==E_READONLY)
+ m_xConfig = xConfigProvider->createInstanceWithArguments(SERVICENAME_CFGREADACCESS , lParams);
+ else
+ if (eMode==E_READWRITE)
+ m_xConfig = xConfigProvider->createInstanceWithArguments(SERVICENAME_CFGUPDATEACCESS, lParams);
+ }
+ catch(css::uno::Exception& ex)
+ {
+ (void) ex; // avoid warning
+ LOG_WARNING("open config ...", U2B(ex.Message))
+ }
+
+ m_eMode = E_CLOSED;
+ if (m_xConfig.is())
+ m_eMode = eMode;
+ }
+ }
+
+ aWriteLock.unlock();
+ /* } SAFE */
+}
+
+//________________________________
+/**
+ @short close the internal opened configuration access and flush all changes
+ @descr It checks, if the given access is valid and react in the right way.
+ It flushes all changes ... so nobody else must know this state.
+ */
+void ConfigAccess::close()
+{
+ /* SAFE { */
+ // Lock the whole method, to be shure that nobody else uses our internal members
+ // during this time.
+ WriteGuard aWriteLock(m_aLock);
+
+ // check already closed configuration
+ if (m_xConfig.is())
+ {
+ css::uno::Reference< css::util::XChangesBatch > xFlush(m_xConfig, css::uno::UNO_QUERY);
+ if (xFlush.is())
+ xFlush->commitChanges();
+ m_xConfig = css::uno::Reference< css::uno::XInterface >();
+ m_eMode = E_CLOSED;
+ }
+
+ aWriteLock.unlock();
+ /* } SAFE */
+}
+
+//________________________________
+/**
+ @short provides an access to the internal wrapped configuration access
+ @descr It's not allowed to safe this c++ (!) reference outside. You have
+ to use it directly. Further you must use our public lock member m_aLock
+ to synchronize your code with our internal structures and our interface
+ methods. Acquire it before you call cfg() and release it afterwards immediatly.
+
+ E.g.: ConfigAccess aAccess(...);
+ ReadGuard aReadLock(aAccess.m_aLock);
+ Reference< XPropertySet > xSet(aAccess.cfg(), UNO_QUERY);
+ Any aProp = xSet->getPropertyValue("...");
+ aReadLock.unlock();
+
+ @attention During this time it's not allowed to call the methods open() or close()!
+ Otherwhise you will change your own referenced config access. Anything will
+ be possible then.
+
+ @return A c++(!) reference to the uno instance of the configuration access point.
+ */
+const css::uno::Reference< css::uno::XInterface >& ConfigAccess::cfg()
+{
+ // must be synchronized from outside!
+ // => no lock here ...
+ return m_xConfig;
+}
+
+} // namespace framework
diff --git a/framework/source/jobs/helponstartup.cxx b/framework/source/jobs/helponstartup.cxx
new file mode 100644
index 000000000000..93ea64e94cb4
--- /dev/null
+++ b/framework/source/jobs/helponstartup.cxx
@@ -0,0 +1,423 @@
+/*************************************************************************
+ *
+ * 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"
+
+//_______________________________________________
+// include own header
+#include <jobs/helponstartup.hxx>
+#include <threadhelp/resetableguard.hxx>
+#include <loadenv/targethelper.hxx>
+#include <services.h>
+
+//_______________________________________________
+// include others
+#include <comphelper/configurationhelper.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+#include <unotools/configmgr.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/help.hxx>
+#include <rtl/ustrbuf.hxx>
+
+//_______________________________________________
+// include interfaces
+#include <com/sun/star/frame/FrameSearchFlag.hpp>
+#include <com/sun/star/frame/XFramesSupplier.hpp>
+#include <com/sun/star/frame/XDesktop.hpp>
+
+//_______________________________________________
+// namespace
+
+namespace framework{
+
+//_______________________________________________
+// definitions
+
+// path to module config
+static ::rtl::OUString CFG_PACKAGE_MODULES = ::rtl::OUString::createFromAscii("/org.openoffice.Setup/Office/Factories");
+static ::rtl::OUString CFG_PACKAGE_SETUP = ::rtl::OUString::createFromAscii("/org.openoffice.Setup" );
+static ::rtl::OUString CFG_PACKAGE_COMMON = ::rtl::OUString::createFromAscii("/org.openoffice.Office.Common" );
+static ::rtl::OUString CFG_PATH_L10N = ::rtl::OUString::createFromAscii("L10N" );
+static ::rtl::OUString CFG_PATH_HELP = ::rtl::OUString::createFromAscii("Help" );
+static ::rtl::OUString CFG_KEY_LOCALE = ::rtl::OUString::createFromAscii("ooLocale" );
+static ::rtl::OUString CFG_KEY_HELPSYSTEM = ::rtl::OUString::createFromAscii("System" );
+
+// props of job environment
+static ::rtl::OUString PROP_ENVIRONMENT = ::rtl::OUString::createFromAscii("Environment" );
+static ::rtl::OUString PROP_JOBCONFIG = ::rtl::OUString::createFromAscii("JobConfig" );
+static ::rtl::OUString PROP_ENVTYPE = ::rtl::OUString::createFromAscii("EnvType" );
+static ::rtl::OUString PROP_MODEL = ::rtl::OUString::createFromAscii("Model" );
+
+// props of module config
+static ::rtl::OUString PROP_HELP_BASEURL = ::rtl::OUString::createFromAscii("ooSetupFactoryHelpBaseURL" );
+static ::rtl::OUString PROP_AUTOMATIC_HELP = ::rtl::OUString::createFromAscii("ooSetupFactoryHelpOnOpen" );
+
+// special value of job environment
+static ::rtl::OUString ENVTYPE_DOCUMENTEVENT = ::rtl::OUString::createFromAscii("DOCUMENTEVENT" );
+
+//-----------------------------------------------
+
+DEFINE_XSERVICEINFO_MULTISERVICE(HelpOnStartup ,
+ ::cppu::OWeakObject ,
+ SERVICENAME_JOB ,
+ IMPLEMENTATIONNAME_HELPONSTARTUP)
+
+DEFINE_INIT_SERVICE(HelpOnStartup,
+ {
+ /* 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!
+ */
+ // create some needed uno services and cache it
+ m_xModuleManager = css::uno::Reference< css::frame::XModuleManager >(
+ m_xSMGR->createInstance(SERVICENAME_MODULEMANAGER),
+ css::uno::UNO_QUERY_THROW);
+
+ m_xDesktop = css::uno::Reference< css::frame::XFrame >(
+ m_xSMGR->createInstance(SERVICENAME_DESKTOP),
+ css::uno::UNO_QUERY_THROW);
+
+ m_xConfig = css::uno::Reference< css::container::XNameAccess >(
+ ::comphelper::ConfigurationHelper::openConfig(
+ m_xSMGR,
+ CFG_PACKAGE_MODULES,
+ ::comphelper::ConfigurationHelper::E_READONLY),
+ css::uno::UNO_QUERY_THROW);
+
+ // ask for office locale
+ ::comphelper::ConfigurationHelper::readDirectKey(
+ m_xSMGR,
+ CFG_PACKAGE_SETUP,
+ CFG_PATH_L10N,
+ CFG_KEY_LOCALE,
+ ::comphelper::ConfigurationHelper::E_READONLY) >>= m_sLocale;
+
+ // detect system
+ ::comphelper::ConfigurationHelper::readDirectKey(
+ m_xSMGR,
+ CFG_PACKAGE_COMMON,
+ CFG_PATH_HELP,
+ CFG_KEY_HELPSYSTEM,
+ ::comphelper::ConfigurationHelper::E_READONLY) >>= m_sSystem;
+
+ // Start listening for disposing events of these services,
+ // so we can react e.g. for an office shutdown
+ css::uno::Reference< css::lang::XComponent > xComponent;
+ xComponent = css::uno::Reference< css::lang::XComponent >(m_xModuleManager, css::uno::UNO_QUERY);
+ if (xComponent.is())
+ xComponent->addEventListener(static_cast< css::lang::XEventListener* >(this));
+ xComponent = css::uno::Reference< css::lang::XComponent >(m_xDesktop, css::uno::UNO_QUERY);
+ if (xComponent.is())
+ xComponent->addEventListener(static_cast< css::lang::XEventListener* >(this));
+ xComponent = css::uno::Reference< css::lang::XComponent >(m_xConfig, css::uno::UNO_QUERY);
+ if (xComponent.is())
+ xComponent->addEventListener(static_cast< css::lang::XEventListener* >(this));
+ }
+ )
+
+//-----------------------------------------------
+HelpOnStartup::HelpOnStartup(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR)
+ : ThreadHelpBase( )
+ , m_xSMGR (xSMGR)
+{
+}
+
+//-----------------------------------------------
+HelpOnStartup::~HelpOnStartup()
+{
+}
+
+//-----------------------------------------------
+// css.task.XJob
+css::uno::Any SAL_CALL HelpOnStartup::execute(const css::uno::Sequence< css::beans::NamedValue >& lArguments)
+ throw(css::lang::IllegalArgumentException,
+ css::uno::Exception ,
+ css::uno::RuntimeException )
+{
+ // Analyze the given arguments; try to locate a model there and
+ // classify it's used application module.
+ ::rtl::OUString sModule = its_getModuleIdFromEnv(lArguments);
+
+ // Attention: We are bound to events for openeing any document inside the office.
+ // That includes e.g. the help module itself. But we have to do nothing then!
+ if (!sModule.getLength())
+ return css::uno::Any();
+
+ // check current state of the help module
+ // a) help isnt open => show default page for the detected module
+ // b) help shows any other default page(!) => show default page for the detected module
+ // c) help shows any other content => do nothing (user travelled to any other content and leaved the set of default pages)
+ ::rtl::OUString sCurrentHelpURL = its_getCurrentHelpURL();
+ sal_Bool bCurrentHelpURLIsAnyDefaultURL = its_isHelpUrlADefaultOne(sCurrentHelpURL);
+ sal_Bool bShowIt = sal_False;
+
+ // a)
+ if (!sCurrentHelpURL.getLength())
+ bShowIt = sal_True;
+ else
+ // b)
+ if (bCurrentHelpURLIsAnyDefaultURL)
+ bShowIt = sal_True;
+
+ if (bShowIt)
+ {
+ // retrieve the help URL for the detected application module
+ ::rtl::OUString sModuleDependendHelpURL = its_checkIfHelpEnabledAndGetURL(sModule);
+ if (sModuleDependendHelpURL.getLength())
+ {
+ // Show this help page.
+ // Note: The help window brings itself to front ...
+ Help* pHelp = Application::GetHelp();
+ if (pHelp)
+ pHelp->Start(sModuleDependendHelpURL, 0);
+ }
+ }
+
+ return css::uno::Any();
+}
+
+//-----------------------------------------------
+void SAL_CALL HelpOnStartup::disposing(const css::lang::EventObject& aEvent)
+ throw(css::uno::RuntimeException)
+{
+ // SAFE ->
+ ResetableGuard aLock(m_aLock);
+
+ if (aEvent.Source == m_xModuleManager)
+ m_xModuleManager.clear();
+ else
+ if (aEvent.Source == m_xDesktop)
+ m_xDesktop.clear();
+ else
+ if (aEvent.Source == m_xConfig)
+ m_xConfig.clear();
+
+ aLock.unlock();
+ // <- SAFE
+}
+
+//-----------------------------------------------
+::rtl::OUString HelpOnStartup::its_getModuleIdFromEnv(const css::uno::Sequence< css::beans::NamedValue >& lArguments)
+{
+ ::comphelper::SequenceAsHashMap lArgs (lArguments);
+ ::comphelper::SequenceAsHashMap lEnvironment = lArgs.getUnpackedValueOrDefault(PROP_ENVIRONMENT, css::uno::Sequence< css::beans::NamedValue >());
+ ::comphelper::SequenceAsHashMap lJobConfig = lArgs.getUnpackedValueOrDefault(PROP_JOBCONFIG , css::uno::Sequence< css::beans::NamedValue >());
+
+ // check for right environment.
+ // If its not a DocumentEvent, which triggered this job,
+ // we cant work correctly! => return immediatly and do nothing
+ ::rtl::OUString sEnvType = lEnvironment.getUnpackedValueOrDefault(PROP_ENVTYPE, ::rtl::OUString());
+ if (!sEnvType.equals(ENVTYPE_DOCUMENTEVENT))
+ return ::rtl::OUString();
+
+ css::uno::Reference< css::frame::XModel > xDoc = lEnvironment.getUnpackedValueOrDefault(PROP_MODEL, css::uno::Reference< css::frame::XModel >());
+ if (!xDoc.is())
+ return ::rtl::OUString();
+
+ // be sure that we work on top level documents only, which are registered
+ // on the desktop instance. Ignore e.g. life previews, which are top frames too ...
+ // but not registered at this global desktop instance.
+ css::uno::Reference< css::frame::XDesktop > xDesktopCheck;
+ css::uno::Reference< css::frame::XFrame > xFrame ;
+ css::uno::Reference< css::frame::XController > xController = xDoc->getCurrentController();
+ if (xController.is())
+ xFrame = xController->getFrame();
+ if (xFrame.is() && xFrame->isTop())
+ xDesktopCheck = css::uno::Reference< css::frame::XDesktop >(xFrame->getCreator(), css::uno::UNO_QUERY);
+ if (!xDesktopCheck.is())
+ return ::rtl::OUString();
+
+ // OK - now we are sure this document is a top level document.
+ // Classify it.
+ // SAFE ->
+ ResetableGuard aLock(m_aLock);
+ css::uno::Reference< css::frame::XModuleManager > xModuleManager = m_xModuleManager;
+ aLock.unlock();
+ // <- SAFE
+
+ if (!xModuleManager.is())
+ return ::rtl::OUString();
+
+ ::rtl::OUString sModuleId;
+ try
+ {
+ sModuleId = xModuleManager->identify(xDoc);
+ }
+ catch(const css::uno::RuntimeException& exRun)
+ { throw exRun; }
+ catch(const css::uno::Exception&)
+ { sModuleId = ::rtl::OUString(); }
+
+ return sModuleId;
+}
+
+//-----------------------------------------------
+::rtl::OUString HelpOnStartup::its_getCurrentHelpURL()
+{
+ // SAFE ->
+ ResetableGuard aLock(m_aLock);
+ css::uno::Reference< css::frame::XFrame > xDesktop = m_xDesktop;
+ aLock.unlock();
+ // <- SAFE
+
+ if (!xDesktop.is())
+ return ::rtl::OUString();
+
+ css::uno::Reference< css::frame::XFrame > xHelp = xDesktop->findFrame(SPECIALTARGET_HELPTASK, css::frame::FrameSearchFlag::CHILDREN);
+ if (!xHelp.is())
+ return ::rtl::OUString();
+
+ ::rtl::OUString sCurrentHelpURL;
+ try
+ {
+ css::uno::Reference< css::frame::XFramesSupplier > xHelpRoot (xHelp , css::uno::UNO_QUERY_THROW);
+ css::uno::Reference< css::container::XIndexAccess > xHelpChilds(xHelpRoot->getFrames(), css::uno::UNO_QUERY_THROW);
+
+ css::uno::Reference< css::frame::XFrame > xHelpChild ;
+ css::uno::Reference< css::frame::XController > xHelpView ;
+ css::uno::Reference< css::frame::XModel > xHelpContent;
+
+ xHelpChilds->getByIndex(0) >>= xHelpChild;
+ if (xHelpChild.is())
+ xHelpView = xHelpChild->getController();
+ if (xHelpView.is())
+ xHelpContent = xHelpView->getModel();
+ if (xHelpContent.is())
+ sCurrentHelpURL = xHelpContent->getURL();
+ }
+ catch(css::uno::RuntimeException& exRun)
+ { throw exRun; }
+ catch(css::uno::Exception&)
+ { sCurrentHelpURL = ::rtl::OUString(); }
+
+ return sCurrentHelpURL;
+}
+
+//-----------------------------------------------
+::sal_Bool HelpOnStartup::its_isHelpUrlADefaultOne(const ::rtl::OUString& sHelpURL)
+{
+ if (!sHelpURL.getLength())
+ return sal_False;
+
+ // SAFE ->
+ ResetableGuard aLock(m_aLock);
+ css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR (m_xSMGR, css::uno::UNO_QUERY_THROW);
+ css::uno::Reference< css::container::XNameAccess > xConfig = m_xConfig;
+ ::rtl::OUString sLocale = m_sLocale;
+ ::rtl::OUString sSystem = m_sSystem;
+ aLock.unlock();
+ // <- SAFE
+
+ if (!xConfig.is())
+ return sal_False;
+
+ // check given help url against all default ones
+ const css::uno::Sequence< ::rtl::OUString > lModules = xConfig->getElementNames();
+ const ::rtl::OUString* pModules = lModules.getConstArray();
+ ::sal_Int32 c = lModules.getLength();
+ ::sal_Int32 i = 0;
+
+ for (i=0; i<c; ++i)
+ {
+ try
+ {
+ css::uno::Reference< css::container::XNameAccess > xModuleConfig;
+ xConfig->getByName(pModules[i]) >>= xModuleConfig;
+ if (!xModuleConfig.is())
+ continue;
+
+ ::rtl::OUString sHelpBaseURL;
+ xModuleConfig->getByName(PROP_HELP_BASEURL) >>= sHelpBaseURL;
+ ::rtl::OUString sHelpURLForModule = HelpOnStartup::ist_createHelpURL(sHelpBaseURL, sLocale, sSystem);
+ if (sHelpURL.equals(sHelpURLForModule))
+ return sal_True;
+ }
+ catch(const css::uno::RuntimeException& exRun)
+ { throw exRun; }
+ catch(const css::uno::Exception&)
+ {}
+ }
+
+ return sal_False;
+}
+
+//-----------------------------------------------
+::rtl::OUString HelpOnStartup::its_checkIfHelpEnabledAndGetURL(const ::rtl::OUString& sModule)
+{
+ // SAFE ->
+ ResetableGuard aLock(m_aLock);
+ css::uno::Reference< css::container::XNameAccess > xConfig = m_xConfig;
+ ::rtl::OUString sLocale = m_sLocale;
+ ::rtl::OUString sSystem = m_sSystem;
+ aLock.unlock();
+ // <- SAFE
+
+ ::rtl::OUString sHelpURL;
+
+ try
+ {
+ css::uno::Reference< css::container::XNameAccess > xModuleConfig;
+ if (xConfig.is())
+ xConfig->getByName(sModule) >>= xModuleConfig;
+
+ sal_Bool bHelpEnabled = sal_False;
+ if (xModuleConfig.is())
+ xModuleConfig->getByName(PROP_AUTOMATIC_HELP) >>= bHelpEnabled;
+
+ if (bHelpEnabled)
+ {
+ ::rtl::OUString sHelpBaseURL;
+ xModuleConfig->getByName(PROP_HELP_BASEURL) >>= sHelpBaseURL;
+ sHelpURL = HelpOnStartup::ist_createHelpURL(sHelpBaseURL, sLocale, sSystem);
+ }
+ }
+ catch(const css::uno::RuntimeException& exRun)
+ { throw exRun; }
+ catch(const css::uno::Exception&)
+ { sHelpURL = ::rtl::OUString(); }
+
+ return sHelpURL;
+}
+
+//-----------------------------------------------
+::rtl::OUString HelpOnStartup::ist_createHelpURL(const ::rtl::OUString& sBaseURL,
+ const ::rtl::OUString& sLocale ,
+ const ::rtl::OUString& sSystem )
+{
+ ::rtl::OUStringBuffer sHelpURL(256);
+ sHelpURL.append (sBaseURL );
+ sHelpURL.appendAscii("?Language=");
+ sHelpURL.append (sLocale );
+ sHelpURL.appendAscii("&System=" );
+ sHelpURL.append (sSystem );
+
+ return sHelpURL.makeStringAndClear();
+}
+
+} // namespace framework
diff --git a/framework/source/jobs/job.cxx b/framework/source/jobs/job.cxx
new file mode 100644
index 000000000000..7ae2452874be
--- /dev/null
+++ b/framework/source/jobs/job.cxx
@@ -0,0 +1,944 @@
+/*************************************************************************
+ *
+ * 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/job.hxx>
+#include <threadhelp/readguard.hxx>
+#include <threadhelp/writeguard.hxx>
+#include <general.h>
+#include <services.h>
+
+//________________________________
+// interface includes
+#include <com/sun/star/task/XJob.hpp>
+#include <com/sun/star/task/XAsyncJob.hpp>
+#include <com/sun/star/util/XCloseBroadcaster.hpp>
+#include <com/sun/star/util/XCloseable.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+
+//________________________________
+// includes of other projects
+#include <rtl/ustrbuf.hxx>
+#include <vcl/svapp.hxx>
+
+//________________________________
+// namespace
+
+namespace framework{
+
+//________________________________
+// non exported const
+
+//________________________________
+// non exported definitions
+
+//________________________________
+// declarations
+
+DEFINE_XINTERFACE_4( Job ,
+ OWeakObject ,
+ DIRECT_INTERFACE(css::lang::XTypeProvider ),
+ DIRECT_INTERFACE(css::task::XJobListener ),
+ DIRECT_INTERFACE(css::frame::XTerminateListener),
+ DIRECT_INTERFACE(css::util::XCloseListener )
+ )
+
+DEFINE_XTYPEPROVIDER_4( Job ,
+ css::lang::XTypeProvider ,
+ css::task::XJobListener ,
+ css::frame::XTerminateListener,
+ css::util::XCloseListener
+ )
+
+//________________________________
+/**
+ @short standard ctor
+ @descr It initialize this new instance. But it set some generic parameters here only.
+ Specialized informations (e.g. the alias or service name ofthis job) will be set
+ later using the method setJobData().
+
+ @param xSMGR
+ reference to the uno service manager
+
+ @param xFrame
+ reference to the frame, in which environment we run
+ (May be null!)
+*/
+Job::Job( /*IN*/ const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR ,
+ /*IN*/ const css::uno::Reference< css::frame::XFrame >& xFrame )
+ : ThreadHelpBase (&Application::GetSolarMutex())
+ , ::cppu::OWeakObject ( )
+ , m_aJobCfg (xSMGR )
+ , m_xSMGR (xSMGR )
+ , m_xFrame (xFrame )
+ , m_bListenOnDesktop (sal_False )
+ , m_bListenOnFrame (sal_False )
+ , m_bListenOnModel (sal_False )
+ , m_bPendingCloseFrame (sal_False )
+ , m_bPendingCloseModel (sal_False )
+ , m_eRunState (E_NEW )
+{
+}
+
+//________________________________
+/**
+ @short standard ctor
+ @descr It initialize this new instance. But it set some generic parameters here only.
+ Specialized informations (e.g. the alias or service name ofthis job) will be set
+ later using the method setJobData().
+
+ @param xSMGR
+ reference to the uno service manager
+
+ @param xModel
+ reference to the model, in which environment we run
+ (May be null!)
+*/
+Job::Job( /*IN*/ const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR ,
+ /*IN*/ const css::uno::Reference< css::frame::XModel >& xModel )
+ : ThreadHelpBase (&Application::GetSolarMutex())
+ , ::cppu::OWeakObject ( )
+ , m_aJobCfg (xSMGR )
+ , m_xSMGR (xSMGR )
+ , m_xModel (xModel )
+ , m_bListenOnDesktop (sal_False )
+ , m_bListenOnFrame (sal_False )
+ , m_bListenOnModel (sal_False )
+ , m_bPendingCloseFrame (sal_False )
+ , m_bPendingCloseModel (sal_False )
+ , m_eRunState (E_NEW )
+{
+}
+
+//________________________________
+/**
+ @short superflous!
+ @descr Releasing of memory and reference must be done inside die() call.
+ Otherwhise it's a bug.
+*/
+Job::~Job()
+{
+}
+
+//________________________________
+/**
+ @short set (or delete) a listener for sending dispatch result events
+ @descr Because this object is used in a wrapped mode ... the original listener
+ for such events can't be registered here directly. Because the
+ listener expect to get the original object given as source of the event.
+ That's why we get this source here too, to fake(!) it at sending time!
+
+ @param xListener
+ the original listener for dispatch result events
+
+ @param xSourceFake
+ our user, which got the registration request for this listener
+*/
+void Job::setDispatchResultFake( /*IN*/ const css::uno::Reference< css::frame::XDispatchResultListener >& xListener ,
+ /*IN*/ const css::uno::Reference< css::uno::XInterface >& xSourceFake )
+{
+ /* SAFE { */
+ WriteGuard aWriteLock(m_aLock);
+
+ // reject dangerous calls
+ if (m_eRunState != E_NEW)
+ {
+ LOG_WARNING("Job::setJobData()", "job may still running or already finished")
+ return;
+ }
+
+ m_xResultListener = xListener ;
+ m_xResultSourceFake = xSourceFake;
+ aWriteLock.unlock();
+ /* } SAFE */
+}
+
+void Job::setJobData( const JobData& aData )
+{
+ /* SAFE { */
+ WriteGuard aWriteLock(m_aLock);
+
+ // reject dangerous calls
+ if (m_eRunState != E_NEW)
+ {
+ LOG_WARNING("Job::setJobData()", "job may still running or already finished")
+ return;
+ }
+
+ m_aJobCfg = aData;
+ aWriteLock.unlock();
+ /* } SAFE */
+}
+
+//________________________________
+/**
+ @short runs the job
+ @descr It doesn't matter, if the job is an asynchronous or
+ synchronous one. This method returns only if it was finished
+ or cancelled.
+
+ @param lDynamicArgs
+ optional arguments for job execution
+ In case the represented job is a configured one (which uses static
+ arguments too) all informations will be merged!
+*/
+void Job::execute( /*IN*/ const css::uno::Sequence< css::beans::NamedValue >& lDynamicArgs )
+{
+ /* SAFE { */
+ WriteGuard aWriteLock(m_aLock);
+
+ // reject dangerous calls
+ if (m_eRunState != E_NEW)
+ {
+ LOG_WARNING("Job::execute()", "job may still running or already finished")
+ return;
+ }
+
+ // create the environment and mark this job as running ...
+ m_eRunState = E_RUNNING;
+ impl_startListening();
+
+ css::uno::Reference< css::task::XAsyncJob > xAJob;
+ css::uno::Reference< css::task::XJob > xSJob;
+ css::uno::Sequence< css::beans::NamedValue > lJobArgs = impl_generateJobArgs(lDynamicArgs);
+
+ // It's neccessary to hold us self alive!
+ // Otherwhise we might die by ref count ...
+ css::uno::Reference< css::task::XJobListener > xThis(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY);
+
+ try
+ {
+ // create the job
+ // We must check for the supported interface on demand!
+ // But we preferr the synchronous one ...
+ m_xJob = m_xSMGR->createInstance(m_aJobCfg.getService());
+ xSJob = css::uno::Reference< css::task::XJob >(m_xJob, css::uno::UNO_QUERY);
+ if (!xSJob.is())
+ xAJob = css::uno::Reference< css::task::XAsyncJob >(m_xJob, css::uno::UNO_QUERY);
+
+ // execute it asynchron
+ if (xAJob.is())
+ {
+ m_aAsyncWait.reset();
+ aWriteLock.unlock();
+ /* } SAFE */
+ xAJob->executeAsync(lJobArgs, xThis);
+ // wait for finishing this job - so this method
+ // does the same for synchronous and asynchronous jobs!
+ m_aAsyncWait.wait();
+ aWriteLock.lock();
+ /* SAFE { */
+ // Note: Result handling was already done inside the callback!
+ }
+ // execute it synchron
+ else if (xSJob.is())
+ {
+ aWriteLock.unlock();
+ /* } SAFE */
+ css::uno::Any aResult = xSJob->execute(lJobArgs);
+ aWriteLock.lock();
+ /* SAFE { */
+ impl_reactForJobResult(aResult);
+ }
+ }
+ #if OSL_DEBUG_LEVEL > 0
+ catch(const css::uno::Exception& ex)
+ {
+ ::rtl::OUStringBuffer sMsg(256);
+ sMsg.appendAscii("Got exception during job execution. Original Message was:\n\"");
+ sMsg.append (ex.Message);
+ sMsg.appendAscii("\"");
+ LOG_WARNING("Job::execute()", U2B(sMsg.makeStringAndClear()).getStr())
+ }
+ #else
+ catch(const css::uno::Exception&)
+ {}
+ #endif
+
+ // deinitialize the environment and mark this job as finished ...
+ // but don't overwrite any informations about STOPPED or might DISPOSED jobs!
+ impl_stopListening();
+ if (m_eRunState == E_RUNNING)
+ m_eRunState = E_STOPPED_OR_FINISHED;
+
+ // If we got a close request from our frame or model ...
+ // but we disagreed wit that by throwing a veto exception...
+ // and got the ownership ...
+ // we have to close the resource frame or model now -
+ // and to disable ourself!
+ if (m_bPendingCloseFrame)
+ {
+ m_bPendingCloseFrame = sal_False;
+ css::uno::Reference< css::util::XCloseable > xClose(m_xFrame, css::uno::UNO_QUERY);
+ if (xClose.is())
+ {
+ try
+ {
+ xClose->close(sal_True);
+ }
+ catch(const css::util::CloseVetoException&) {}
+ }
+ }
+
+ if (m_bPendingCloseModel)
+ {
+ m_bPendingCloseModel = sal_False;
+ css::uno::Reference< css::util::XCloseable > xClose(m_xModel, css::uno::UNO_QUERY);
+ if (xClose.is())
+ {
+ try
+ {
+ xClose->close(sal_True);
+ }
+ catch(const css::util::CloseVetoException&) {}
+ }
+ }
+
+ aWriteLock.unlock();
+ /* SAFE { */
+
+ // release this instance ...
+ die();
+}
+
+//________________________________
+/**
+ @short kill this job
+ @descr It doesn't matter if this request is called from inside or
+ from outside. We release our internal structures and stop
+ avary activity. After doing so - this instance will not be
+ useable any longer! Of course we try to handle further requests
+ carefully. May somehwere else hold a reference to us ...
+*/
+void Job::die()
+{
+ /* SAFE { */
+ WriteGuard aWriteLock(m_aLock);
+
+ impl_stopListening();
+
+ if (m_eRunState != E_DISPOSED)
+ {
+ try
+ {
+ css::uno::Reference< css::lang::XComponent > xDispose(m_xJob, css::uno::UNO_QUERY);
+ if (xDispose.is())
+ {
+ xDispose->dispose();
+ m_eRunState = E_DISPOSED;
+ }
+ }
+ catch(const css::lang::DisposedException&)
+ {
+ m_eRunState = E_DISPOSED;
+ }
+ }
+
+ m_xJob = css::uno::Reference< css::uno::XInterface >();
+ m_xFrame = css::uno::Reference< css::frame::XFrame >();
+ m_xModel = css::uno::Reference< css::frame::XModel >();
+ m_xDesktop = css::uno::Reference< css::frame::XDesktop >();
+ m_xResultListener = css::uno::Reference< css::frame::XDispatchResultListener >();
+ m_xResultSourceFake = css::uno::Reference< css::uno::XInterface >();
+ m_bPendingCloseFrame = sal_False;
+ m_bPendingCloseModel = sal_False;
+
+ aWriteLock.unlock();
+ /* SAFE { */
+}
+
+//________________________________
+/**
+ @short generates list of arguments for job execute
+ @descr There exist a set of informations, which can be needed by a job.
+ a) it's static configuration data (Equals for all jobs. )
+ b) it's specific configuration data (Different for every job.)
+ c) some environment values (e.g. the frame, for which this job was started)
+ d) any other dynamic data (e.g. parameters of a dispatch() request)
+ We collect all these informations and generate one list which include all others.
+
+ @param lDynamicArgs
+ list of dynamic arguments (given by a corresponding dispatch() call)
+ Can be empty too.
+
+ @return A list which includes all mentioned sub lists.
+*/
+css::uno::Sequence< css::beans::NamedValue > Job::impl_generateJobArgs( /*IN*/ const css::uno::Sequence< css::beans::NamedValue >& lDynamicArgs )
+{
+ css::uno::Sequence< css::beans::NamedValue > lAllArgs;
+
+ /* SAFE { */
+ ReadGuard aReadLock(m_aLock);
+
+ // the real structure of the returned list depends from the environment of this job!
+ JobData::EMode eMode = m_aJobCfg.getMode();
+
+ // Create list of environment variables. This list must be part of the
+ // returned structure everytimes ... but some of its members are opetional!
+ css::uno::Sequence< css::beans::NamedValue > lEnvArgs(1);
+ lEnvArgs[0].Name = ::rtl::OUString::createFromAscii(JobData::PROP_ENVTYPE);
+ lEnvArgs[0].Value <<= m_aJobCfg.getEnvironmentDescriptor();
+
+ if (m_xFrame.is())
+ {
+ sal_Int32 c = lEnvArgs.getLength();
+ lEnvArgs.realloc(c+1);
+ lEnvArgs[c].Name = ::rtl::OUString::createFromAscii(JobData::PROP_FRAME);
+ lEnvArgs[c].Value <<= m_xFrame;
+ }
+ if (m_xModel.is())
+ {
+ sal_Int32 c = lEnvArgs.getLength();
+ lEnvArgs.realloc(c+1);
+ lEnvArgs[c].Name = ::rtl::OUString::createFromAscii(JobData::PROP_MODEL);
+ lEnvArgs[c].Value <<= m_xModel;
+ }
+ if (eMode==JobData::E_EVENT)
+ {
+ sal_Int32 c = lEnvArgs.getLength();
+ lEnvArgs.realloc(c+1);
+ lEnvArgs[c].Name = ::rtl::OUString::createFromAscii(JobData::PROP_EVENTNAME);
+ lEnvArgs[c].Value <<= m_aJobCfg.getEvent();
+ }
+
+ // get the configuration data from the job data container ... if possible
+ // Means: if this job has any configuration data. Note: only realy
+ // filled lists will be set to the return structure at the end of this method.
+ css::uno::Sequence< css::beans::NamedValue > lConfigArgs ;
+ css::uno::Sequence< css::beans::NamedValue > lJobConfigArgs;
+ if (eMode==JobData::E_ALIAS || eMode==JobData::E_EVENT)
+ {
+ lConfigArgs = m_aJobCfg.getConfig();
+ lJobConfigArgs = m_aJobCfg.getJobConfig();
+ }
+
+ aReadLock.unlock();
+ /* } SAFE */
+
+ // Add all valid (not empty) lists to the return list
+ if (lConfigArgs.getLength()>0)
+ {
+ sal_Int32 nLength = lAllArgs.getLength();
+ lAllArgs.realloc(nLength+1);
+ lAllArgs[nLength].Name = ::rtl::OUString::createFromAscii(JobData::PROPSET_CONFIG);
+ lAllArgs[nLength].Value <<= lConfigArgs;
+ }
+ if (lJobConfigArgs.getLength()>0)
+ {
+ sal_Int32 nLength = lAllArgs.getLength();
+ lAllArgs.realloc(nLength+1);
+ lAllArgs[nLength].Name = ::rtl::OUString::createFromAscii(JobData::PROPSET_OWNCONFIG);
+ lAllArgs[nLength].Value <<= lJobConfigArgs;
+ }
+ if (lEnvArgs.getLength()>0)
+ {
+ sal_Int32 nLength = lAllArgs.getLength();
+ lAllArgs.realloc(nLength+1);
+ lAllArgs[nLength].Name = ::rtl::OUString::createFromAscii(JobData::PROPSET_ENVIRONMENT);
+ lAllArgs[nLength].Value <<= lEnvArgs;
+ }
+ if (lDynamicArgs.getLength()>0)
+ {
+ sal_Int32 nLength = lAllArgs.getLength();
+ lAllArgs.realloc(nLength+1);
+ lAllArgs[nLength].Name = ::rtl::OUString::createFromAscii(JobData::PROPSET_DYNAMICDATA);
+ lAllArgs[nLength].Value <<= lDynamicArgs;
+ }
+
+ return lAllArgs;
+}
+
+//________________________________
+/**
+ @short analyze the given job result and change the job configuration
+ @descr Note: Some results can be handled only, if this job has a valid configuration!
+ For "not configured jobs" (means pure services) they can be ignored.
+ But these cases are handled by our JobData member. We can call it everytime.
+ It does the right things automaticly. E.g. if the job has no configuration ...
+ it does nothing during setJobConfig()!
+
+ @param aResult
+ the job result for analyzing
+*/
+void Job::impl_reactForJobResult( /*IN*/ const css::uno::Any& aResult )
+{
+ /* SAFE { */
+ WriteGuard aWriteLock(m_aLock);
+
+ // analyze the result set ...
+ JobResult aAnalyzedResult(aResult);
+
+ // some of the following operations will be supported for different environments
+ // or different type of jobs only.
+ JobData::EEnvironment eEnvironment = m_aJobCfg.getEnvironment();
+
+ // write back the job specific configuration data ...
+ // If the environment allow it and if this job has a configuration!
+ if (
+ (m_aJobCfg.hasConfig() ) &&
+ (aAnalyzedResult.existPart(JobResult::E_ARGUMENTS))
+ )
+ {
+ m_aJobCfg.setJobConfig(aAnalyzedResult.getArguments());
+ }
+
+ // disable a job for further executions.
+ // Note: this option is available inside the environment EXECUTOR only
+ if (
+// (eEnvironment == JobData::E_EXECUTION ) &&
+ (m_aJobCfg.hasConfig() ) &&
+ (aAnalyzedResult.existPart(JobResult::E_DEACTIVATE))
+ )
+ {
+ m_aJobCfg.disableJob();
+ }
+
+ // notify any interested listener with the may given result state.
+ // Note: this option is available inside the environment DISPATCH only
+ if (
+ (eEnvironment == JobData::E_DISPATCH ) &&
+ (m_xResultListener.is() ) &&
+ (aAnalyzedResult.existPart(JobResult::E_DISPATCHRESULT))
+ )
+ {
+ m_aJobCfg.setResult(aAnalyzedResult);
+ // Attention: Because the listener expect that the original object send this event ...
+ // and we nor the job are the right ones ...
+ // our user has set itself before. So we can fake this source address!
+ css::frame::DispatchResultEvent aEvent = aAnalyzedResult.getDispatchResult();
+ aEvent.Source = m_xResultSourceFake;
+ m_xResultListener->dispatchFinished(aEvent);
+ }
+
+ aWriteLock.unlock();
+ /* SAFE { */
+}
+
+//________________________________
+/**
+ @short starts listening for office shutdown and closing of our
+ given target frame (if its a valid reference)
+ @descr We will reghister ourself as terminate listener
+ at the global desktop instance. That will hold us
+ alive and additional we get the information, if the
+ office whish to shutdown. If then an internal job
+ is running we will have the chance to supress that
+ by throwing a veto exception. If our internal wrapped
+ job finished his work, we can release this listener
+ connection.
+
+ Further we are listener for closing of the (possible valid)
+ given frame. We must be shure, that this ressource won't be gone
+ if our internal job is still running.
+*/
+void Job::impl_startListening()
+{
+ /* SAFE { */
+ WriteGuard aWriteLock(m_aLock);
+
+ // listening for office shutdown
+ if (!m_xDesktop.is() && !m_bListenOnDesktop)
+ {
+ try
+ {
+ m_xDesktop = css::uno::Reference< css::frame::XDesktop >(m_xSMGR->createInstance(SERVICENAME_DESKTOP), css::uno::UNO_QUERY);
+ css::uno::Reference< css::frame::XTerminateListener > xThis(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY);
+ if (m_xDesktop.is())
+ {
+ m_xDesktop->addTerminateListener(xThis);
+ m_bListenOnDesktop = sal_True;
+ }
+ }
+ catch(css::uno::Exception&)
+ {
+ m_xDesktop = css::uno::Reference< css::frame::XDesktop >();
+ }
+ }
+
+ // listening for frame closing
+ if (m_xFrame.is() && !m_bListenOnFrame)
+ {
+ try
+ {
+ css::uno::Reference< css::util::XCloseBroadcaster > xCloseable(m_xFrame , css::uno::UNO_QUERY);
+ css::uno::Reference< css::util::XCloseListener > xThis (static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY);
+ if (xCloseable.is())
+ {
+ xCloseable->addCloseListener(xThis);
+ m_bListenOnFrame = sal_True;
+ }
+ }
+ catch(css::uno::Exception&)
+ {
+ m_bListenOnFrame = sal_False;
+ }
+ }
+
+ // listening for model closing
+ if (m_xModel.is() && !m_bListenOnModel)
+ {
+ try
+ {
+ css::uno::Reference< css::util::XCloseBroadcaster > xCloseable(m_xModel , css::uno::UNO_QUERY);
+ css::uno::Reference< css::util::XCloseListener > xThis (static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY);
+ if (xCloseable.is())
+ {
+ xCloseable->addCloseListener(xThis);
+ m_bListenOnModel = sal_True;
+ }
+ }
+ catch(css::uno::Exception&)
+ {
+ m_bListenOnModel = sal_False;
+ }
+ }
+
+ aWriteLock.unlock();
+ /* } SAFE */
+}
+
+//________________________________
+/**
+ @short release listener connection for office shutdown
+ @descr see description of impl_startListening()
+*/
+void Job::impl_stopListening()
+{
+ /* SAFE { */
+ WriteGuard aWriteLock(m_aLock);
+
+ // stop listening for office shutdown
+ if (m_xDesktop.is() && m_bListenOnDesktop)
+ {
+ try
+ {
+ css::uno::Reference< css::frame::XTerminateListener > xThis(static_cast< ::cppu::OWeakObject* >(this) , css::uno::UNO_QUERY);
+ m_xDesktop->removeTerminateListener(xThis);
+ m_xDesktop = css::uno::Reference< css::frame::XDesktop >();
+ m_bListenOnDesktop = sal_False;
+ }
+ catch(css::uno::Exception&)
+ {
+ }
+ }
+
+ // stop listening for frame closing
+ if (m_xFrame.is() && m_bListenOnFrame)
+ {
+ try
+ {
+ css::uno::Reference< css::util::XCloseBroadcaster > xCloseable(m_xFrame , css::uno::UNO_QUERY);
+ css::uno::Reference< css::util::XCloseListener > xThis (static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY);
+ if (xCloseable.is())
+ {
+ xCloseable->removeCloseListener(xThis);
+ m_bListenOnFrame = sal_False;
+ }
+ }
+ catch(css::uno::Exception&)
+ {
+ }
+ }
+
+ // stop listening for model closing
+ if (m_xModel.is() && m_bListenOnModel)
+ {
+ try
+ {
+ css::uno::Reference< css::util::XCloseBroadcaster > xCloseable(m_xModel , css::uno::UNO_QUERY);
+ css::uno::Reference< css::util::XCloseListener > xThis (static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY);
+ if (xCloseable.is())
+ {
+ xCloseable->removeCloseListener(xThis);
+ m_bListenOnModel = sal_False;
+ }
+ }
+ catch(css::uno::Exception&)
+ {
+ }
+ }
+
+ aWriteLock.unlock();
+ /* } SAFE */
+}
+
+//________________________________
+/**
+ @short callback from any asynchronous executed job
+
+ @descr Our execute() method waits for this callback.
+ We have to react for the possible results here,
+ to kill the running job and disable the blocked condition
+ so execute() can be finished too.
+
+ @param xJob
+ the job, which was running and inform us now
+
+ @param aResult
+ it's results
+*/
+void SAL_CALL Job::jobFinished( /*IN*/ const css::uno::Reference< css::task::XAsyncJob >& xJob ,
+ /*IN*/ const css::uno::Any& aResult ) throw(css::uno::RuntimeException)
+{
+ /* SAFE { */
+ WriteGuard aWriteLock(m_aLock);
+
+ // It's neccessary to check this.
+ // May this job was cancelled by any other reason
+ // some milliseconds before. :-)
+ if (m_xJob.is() && m_xJob==xJob)
+ {
+ // react for his results
+ // (means enable/disable it for further requests
+ // or save arguments or notify listener ...)
+ impl_reactForJobResult(aResult);
+
+ // Let the job die!
+ m_xJob = css::uno::Reference< css::uno::XInterface >();
+ }
+
+ // And let the start method "execute()" finishing it's job.
+ // But do it everytime. So any outside blocking code can finish
+ // his work too.
+ m_aAsyncWait.set();
+
+ aWriteLock.unlock();
+ /* } SAFE */
+}
+
+//________________________________
+/**
+ @short prevent internal wrapped job against office termination
+ @descr This event is broadcasted by the desktop instance and ask for an office termination.
+ If the internal wrapped job is still in progress, we disagree with that by throwing the
+ right veto exception. If not - we agree. But then we must be aware, that another event
+ notifyTermination() can follow. Then we have no chance to do the same. Then we have to
+ accept that and stop our work instandly.
+
+ @param aEvent
+ describes the broadcaster and must be the desktop instance
+
+ @throw TerminateVetoException
+ if our internal wrapped job is still running.
+ */
+void SAL_CALL Job::queryTermination( /*IN*/ const css::lang::EventObject& ) throw(css::frame::TerminationVetoException,
+ css::uno::RuntimeException )
+{
+ /* SAFE { */
+ ReadGuard aReadLock(m_aLock);
+
+ // don't disagree with this request if job was already stopped or finished it's work
+ // if (m_eRunState != E_RUNNING)
+ // return;
+
+ // Otherwhise try to close() it
+ css::uno::Reference< css::util::XCloseable > xClose(m_xJob, css::uno::UNO_QUERY);
+ if (xClose.is())
+ {
+ try
+ {
+ xClose->close(sal_False);
+ m_eRunState = E_STOPPED_OR_FINISHED;
+ }
+ catch(const css::util::CloseVetoException&) {}
+ }
+
+ if (m_eRunState != E_STOPPED_OR_FINISHED)
+ {
+ css::uno::Reference< css::uno::XInterface > xThis(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY);
+ throw css::frame::TerminationVetoException(DECLARE_ASCII("job still in progress"), xThis);
+ }
+
+ aReadLock.unlock();
+ /* } SAFE */
+}
+
+
+//________________________________
+/**
+ @short inform us about office termination
+ @descr Instead of the method queryTermination(), here is no chance to disagree with that.
+ We have to accept it and cancel all current processes inside.
+ It can occure only, if job was not already started if queryTermination() was called here ..
+ Then we had not throwed a veto exception. But now we must agree with this situation and break
+ all our internal processes. Its not a good idea to mark this instance as non startable any longer
+ inside queryTermination() if no job was unning too. Because that would disable this job and may
+ the office does not realy shutdownm, because another listener has thrown the suitable exception.
+
+ @param aEvent
+ describes the broadcaster and must be the desktop instance
+ */
+void SAL_CALL Job::notifyTermination( /*IN*/ const css::lang::EventObject& ) throw(css::uno::RuntimeException)
+{
+ die();
+ // Do nothing else here. Our internal ressources was released ...
+}
+
+//________________________________
+/**
+ @short prevent internal wrapped job against frame closing
+ @descr This event is broadcasted by the frame instance and ask for closing.
+ If the internal wrapped job is still in progress, we disagree with that by throwing the
+ right veto exception. If not - we agree. But then we must be aware, that another event
+ notifyClosing() can follow. Then we have no chance to do the same. Then we have to
+ accept that and stop our work instandly.
+
+ @param aEvent
+ describes the broadcaster and must be the frame instance
+
+ @param bGetsOwnerShip
+ If it's set to <TRUE> and we throw the right veto excepion, we have to close this frame later
+ if our internal processes will be finished. If it's set to <FALSE/> we can ignore it.
+
+ @throw CloseVetoException
+ if our internal wrapped job is still running.
+ */
+void SAL_CALL Job::queryClosing( const css::lang::EventObject& aEvent ,
+ sal_Bool bGetsOwnership ) throw(css::util::CloseVetoException,
+ css::uno::RuntimeException )
+{
+ /* SAFE { */
+ WriteGuard aWriteLock(m_aLock);
+
+ // do nothing, if no internal job is still running ...
+ // The frame or model can be closed then successfully.
+ if (m_eRunState != E_RUNNING)
+ return;
+
+ // try close() first at the job.
+ // The job can agree or disagree with this request.
+ css::uno::Reference< css::util::XCloseable > xClose(m_xJob, css::uno::UNO_QUERY);
+ if (xClose.is())
+ {
+ xClose->close(bGetsOwnership);
+ // Here we can say: "this job was stopped successfully". Because
+ // no veto exception was thrown!
+ m_eRunState = E_STOPPED_OR_FINISHED;
+ return;
+ }
+
+ // try dispose() then
+ // Here the job has no chance for a veto.
+ // But we must be aware of an "already disposed exception"...
+ try
+ {
+ css::uno::Reference< css::lang::XComponent > xDispose(m_xJob, css::uno::UNO_QUERY);
+ if (xDispose.is())
+ {
+ xDispose->dispose();
+ m_eRunState = E_DISPOSED;
+ }
+ }
+ catch(const css::lang::DisposedException&)
+ {
+ // the job was already disposed by any other mechanism !?
+ // But it's not interesting for us. For us this job is stopped now.
+ m_eRunState = E_DISPOSED;
+ }
+
+ if (m_eRunState != E_DISPOSED)
+ {
+ // analyze event source - to find out, which resource called queryClosing() at this
+ // job wrapper. We must bind a "pending close" request to this resource.
+ // Closing of the corresponding resource will be done if our internal job finish it's work.
+ m_bPendingCloseFrame = (m_xFrame.is() && aEvent.Source == m_xFrame);
+ m_bPendingCloseModel = (m_xModel.is() && aEvent.Source == m_xModel);
+
+ // throw suitable veto exception - because the internal job could not be cancelled.
+ css::uno::Reference< css::uno::XInterface > xThis(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY);
+ throw css::util::CloseVetoException(DECLARE_ASCII("job still in progress"), xThis);
+ }
+
+ // No veto ...
+ // But don't call die() here or free our internal member.
+ // This must be done inside notifyClosing() only. Otherwhise the
+ // might stopped job has no chance to return it's results or
+ // call us back. We must give him the chance to finish it's work successfully.
+
+ aWriteLock.unlock();
+ /* } SAFE */
+}
+
+//________________________________
+/**
+ @short inform us about frame closing
+ @descr Instead of the method queryClosing(), here is no chance to disagree with that.
+ We have to accept it and cancel all current processes inside.
+
+ @param aEvent
+ describes the broadcaster and must be the frame or model instance we know
+ */
+void SAL_CALL Job::notifyClosing( const css::lang::EventObject& ) throw(css::uno::RuntimeException)
+{
+ die();
+ // Do nothing else here. Our internal ressources was released ...
+}
+
+//________________________________
+/**
+ @short shouldn't be called normaly
+ @descr But it doesn't matter, who called it. We have to kill our internal
+ running processes hardly.
+
+ @param aEvent
+ describe the broadcaster
+*/
+void SAL_CALL Job::disposing( const css::lang::EventObject& aEvent ) throw(css::uno::RuntimeException)
+{
+ /* SAFE { */
+ WriteGuard aWriteLock(m_aLock);
+
+ if (m_xDesktop.is() && aEvent.Source == m_xDesktop)
+ {
+ m_xDesktop = css::uno::Reference< css::frame::XDesktop >();
+ m_bListenOnDesktop = sal_False;
+ }
+ else
+ if (m_xFrame.is() && aEvent.Source == m_xFrame)
+ {
+ m_xFrame = css::uno::Reference< css::frame::XFrame >();
+ m_bListenOnFrame = sal_False;
+ }
+ else
+ if (m_xModel.is() && aEvent.Source == m_xModel)
+ {
+ m_xModel = css::uno::Reference< css::frame::XModel >();
+ m_bListenOnModel = sal_False;
+ }
+
+ aWriteLock.unlock();
+ /* } SAFE */
+
+ die();
+ // Do nothing else here. Our internal ressources was released ...
+}
+
+} // namespace framework
diff --git a/framework/source/jobs/jobconst.cxx b/framework/source/jobs/jobconst.cxx
new file mode 100644
index 000000000000..b71a68342a69
--- /dev/null
+++ b/framework/source/jobs/jobconst.cxx
@@ -0,0 +1,74 @@
+/*************************************************************************
+ *
+ * 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/jobconst.hxx>
+
+//________________________________
+// interface includes
+
+//________________________________
+// includes of other projects
+
+//________________________________
+// namespace
+
+namespace framework{
+
+//________________________________
+// non exported const
+
+//________________________________
+// non exported definitions
+
+//________________________________
+// declarations
+
+const ::rtl::OUString JobConst::ANSWER_DEACTIVATE_JOB()
+{
+ static const ::rtl::OUString PROP = ::rtl::OUString::createFromAscii("Deactivate");
+ return PROP;
+}
+
+const ::rtl::OUString JobConst::ANSWER_SAVE_ARGUMENTS()
+{
+ static const ::rtl::OUString PROP = ::rtl::OUString::createFromAscii("SaveArguments");
+ return PROP;
+}
+
+const ::rtl::OUString JobConst::ANSWER_SEND_DISPATCHRESULT()
+{
+ static const ::rtl::OUString PROP = ::rtl::OUString::createFromAscii("SendDispatchResult");
+ return PROP;
+}
+
+} // namespace framework
diff --git a/framework/source/jobs/jobdata.cxx b/framework/source/jobs/jobdata.cxx
new file mode 100644
index 000000000000..4acbce44f831
--- /dev/null
+++ b/framework/source/jobs/jobdata.cxx
@@ -0,0 +1,714 @@
+ /*************************************************************************
+ *
+ * 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/jobdata.hxx>
+#include <threadhelp/readguard.hxx>
+#include <threadhelp/writeguard.hxx>
+#include <classes/converter.hxx>
+#include <general.h>
+#include <services.h>
+
+//________________________________
+// interface includes
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XMultiHierarchicalPropertySet.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
+
+//________________________________
+// includes of other projects
+#include <tools/wldcrd.hxx>
+#include <unotools/configpathes.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <vcl/svapp.hxx>
+
+//________________________________
+// namespace
+
+namespace framework{
+
+//________________________________
+// exported const
+
+const sal_Char* JobData::JOBCFG_ROOT = "/org.openoffice.Office.Jobs/Jobs/" ;
+const sal_Char* JobData::JOBCFG_PROP_SERVICE = "Service" ;
+const sal_Char* JobData::JOBCFG_PROP_ARGUMENTS = "Arguments" ;
+
+const sal_Char* JobData::EVENTCFG_ROOT = "/org.openoffice.Office.Jobs/Events/" ;
+const sal_Char* JobData::EVENTCFG_PATH_JOBLIST = "/JobList" ;
+const sal_Char* JobData::EVENTCFG_PROP_ADMINTIME = "AdminTime" ;
+const sal_Char* JobData::EVENTCFG_PROP_USERTIME = "UserTime" ;
+
+const sal_Char* JobData::PROPSET_CONFIG = "Config" ;
+const sal_Char* JobData::PROPSET_OWNCONFIG = "JobConfig" ;
+const sal_Char* JobData::PROPSET_ENVIRONMENT = "Environment" ;
+const sal_Char* JobData::PROPSET_DYNAMICDATA = "DynamicData" ;
+
+const sal_Char* JobData::PROP_ALIAS = "Alias" ;
+const sal_Char* JobData::PROP_EVENTNAME = "EventName" ;
+const sal_Char* JobData::PROP_ENVTYPE = "EnvType" ;
+const sal_Char* JobData::PROP_FRAME = "Frame" ;
+const sal_Char* JobData::PROP_MODEL = "Model" ;
+const sal_Char* JobData::PROP_SERVICE = "Service" ;
+
+//________________________________
+// non exported definitions
+
+//________________________________
+// declarations
+
+//________________________________
+/**
+ @short standard ctor
+ @descr It initialize this new instance.
+ But for real working it's neccessary to call setAlias() or setService() later.
+ Because we need the job data ...
+
+ @param xSMGR
+ reference to the uno service manager
+*/
+JobData::JobData( const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR )
+ : ThreadHelpBase(&Application::GetSolarMutex())
+ , m_xSMGR (xSMGR )
+{
+ // share code for member initialization with defaults!
+ impl_reset();
+}
+
+//________________________________
+/**
+ @short copy ctor
+ @descr Sometimes such job data container must be moved from one using place
+ to another one. Then a copy ctor and copy operator must be available.
+
+ @param rCopy
+ the original instance, from which we must copy all data
+*/
+JobData::JobData( const JobData& rCopy )
+ : ThreadHelpBase(&Application::GetSolarMutex())
+{
+ // use the copy operator to share the same code
+ *this = rCopy;
+}
+
+//________________________________
+/**
+ @short operator for coping JobData instances
+ @descr Sometimes such job data container must be moved from one using place
+ to another one. Then a copy ctor and copy operator must be available.
+
+ @param rCopy
+ the original instance, from which we must copy all data
+*/
+void JobData::operator=( const JobData& rCopy )
+{
+ /* SAFE { */
+ WriteGuard aWriteLock(m_aLock);
+ // Please don't copy the uno service manager reference.
+ // That can change the uno context, which isn't a good idea!
+ m_eMode = rCopy.m_eMode ;
+ m_eEnvironment = rCopy.m_eEnvironment ;
+ m_sAlias = rCopy.m_sAlias ;
+ m_sService = rCopy.m_sService ;
+ m_sEvent = rCopy.m_sEvent ;
+ m_lArguments = rCopy.m_lArguments ;
+ m_aLastExecutionResult = rCopy.m_aLastExecutionResult;
+ aWriteLock.unlock();
+ /* } SAFE */
+}
+
+//________________________________
+/**
+ @short let this instance die
+ @descr There is no chance any longer to work. We have to
+ release all used ressources and free used memory.
+*/
+JobData::~JobData()
+{
+ impl_reset();
+}
+
+//________________________________
+/**
+ @short initalize this instance as a job with configuration
+ @descr They given alias can be used to adress some configuraton data.
+ We read it and fill our internal structures. Of course old informations
+ will be lost doing so.
+
+ @param sAlias
+ the alias name of this job, used to locate job properties inside cfg
+*/
+void JobData::setAlias( const ::rtl::OUString& sAlias )
+{
+ /* SAFE { */
+ WriteGuard aWriteLock(m_aLock);
+ // delete all old informations! Otherwhise we mix it with the new one ...
+ impl_reset();
+
+ // take over the new informations
+ m_sAlias = sAlias;
+ m_eMode = E_ALIAS;
+
+ // try to open the configuration set of this job directly and get a property access to it
+ // We open it readonly here
+ ::rtl::OUString sKey;
+ sKey = ::rtl::OUString::createFromAscii(JOBCFG_ROOT);
+ sKey += ::utl::wrapConfigurationElementName(m_sAlias);
+
+ ConfigAccess aConfig(m_xSMGR, sKey);
+ aConfig.open(ConfigAccess::E_READONLY);
+ if (aConfig.getMode()==ConfigAccess::E_CLOSED)
+ {
+ impl_reset();
+ return;
+ }
+
+ css::uno::Reference< css::beans::XPropertySet > xJobProperties(aConfig.cfg(), css::uno::UNO_QUERY);
+ if (xJobProperties.is())
+ {
+ css::uno::Any aValue;
+
+ // read uno implementation name
+ aValue = xJobProperties->getPropertyValue(::rtl::OUString::createFromAscii(JOBCFG_PROP_SERVICE));
+ aValue >>= m_sService;
+
+ // read whole argument list
+ aValue = xJobProperties->getPropertyValue(::rtl::OUString::createFromAscii(JOBCFG_PROP_ARGUMENTS));
+ css::uno::Reference< css::container::XNameAccess > xArgumentList;
+ if (
+ (aValue >>= xArgumentList) &&
+ (xArgumentList.is() )
+ )
+ {
+ css::uno::Sequence< ::rtl::OUString > lArgumentNames = xArgumentList->getElementNames();
+ sal_Int32 nCount = lArgumentNames.getLength();
+ m_lArguments.realloc(nCount);
+ for (sal_Int32 i=0; i<nCount; ++i)
+ {
+ m_lArguments[i].Name = lArgumentNames[i];
+ m_lArguments[i].Value = xArgumentList->getByName(m_lArguments[i].Name);
+ }
+ }
+ }
+
+ aConfig.close();
+ aWriteLock.unlock();
+ /* } SAFE */
+}
+
+//________________________________
+/**
+ @short initalize this instance as a job without configuration
+ @descr This job has no configuration data. We have to forget all old informations
+ and set only some of them new, so this instance can work.
+
+ @param sService
+ the uno service name of this "non configured" job
+*/
+void JobData::setService( const ::rtl::OUString& sService )
+{
+ /* SAFE { */
+ WriteGuard aWriteLock(m_aLock);
+
+ // delete all old informations! Otherwhise we mix it with the new one ...
+ impl_reset();
+ // take over the new informations
+ m_sService = sService;
+ m_eMode = E_SERVICE;
+
+ aWriteLock.unlock();
+ /* } SAFE */
+}
+
+//________________________________
+/**
+ @short initialize this instance with new job values.
+ @descr It reads automaticly all properties of the specified
+ job (using it's alias name) and "register it" for the
+ given event. This registration will not be validated against
+ the underlying configuration! (That must be done from outside.
+ Because the caller must have the configuration already open to
+ get the values for sEvent and sAlias! And doing so it can perform
+ only, if the time stanp values are readed outside too.
+ Further it make no sense to initialize and start a disabled job.
+ So this initialization method will be called for enabled jobs only.)
+
+ @param sEvent
+ the triggered event, for which this job should be started
+
+ @param sAlias
+ mark the required job inside event registration list
+*/
+void JobData::setEvent( const ::rtl::OUString& sEvent ,
+ const ::rtl::OUString& sAlias )
+{
+ // share code to read all job properties!
+ setAlias(sAlias);
+
+ /* SAFE { */
+ WriteGuard aWriteLock(m_aLock);
+
+ // take over the new informations - which differ against set on of method setAlias()!
+ m_sEvent = sEvent;
+ m_eMode = E_EVENT;
+
+ aWriteLock.unlock();
+ /* } SAFE */
+}
+
+//________________________________
+/**
+ @short set the new job specific arguments
+ @descr If a job finish his work, it can give us a new list of arguments (which
+ will not interpreted by us). We write it back to the configuration only
+ (if this job has it's own configuration!).
+ So a job can have persistent data without implementing anything
+ or define own config areas for that.
+
+ @param lArguments
+ list of arguments, which should be set for this job
+ */
+void JobData::setJobConfig( const css::uno::Sequence< css::beans::NamedValue >& lArguments )
+{
+ /* SAFE { */
+ WriteGuard aWriteLock(m_aLock);
+
+ // update member
+ m_lArguments = lArguments;
+
+ // update the configuration ... if possible!
+ if (m_eMode==E_ALIAS)
+ {
+ // It doesn't matter if this config object was already opened before.
+ // It doesn nothing here then ... or it change the mode automaticly, if
+ // it was opened using another one before.
+ ::rtl::OUString sKey;
+ sKey = ::rtl::OUString::createFromAscii(JOBCFG_ROOT);
+ sKey += ::utl::wrapConfigurationElementName(m_sAlias);
+
+ ConfigAccess aConfig(m_xSMGR, sKey);
+ aConfig.open(ConfigAccess::E_READWRITE);
+ if (aConfig.getMode()==ConfigAccess::E_CLOSED)
+ return;
+
+ css::uno::Reference< css::beans::XMultiHierarchicalPropertySet > xArgumentList(aConfig.cfg(), css::uno::UNO_QUERY);
+ if (xArgumentList.is())
+ {
+ sal_Int32 nCount = m_lArguments.getLength();
+ css::uno::Sequence< ::rtl::OUString > lNames (nCount);
+ css::uno::Sequence< css::uno::Any > lValues(nCount);
+
+ for (sal_Int32 i=0; i<nCount; ++i)
+ {
+ lNames [i] = m_lArguments[i].Name ;
+ lValues[i] = m_lArguments[i].Value;
+ }
+
+ xArgumentList->setHierarchicalPropertyValues(lNames, lValues);
+ }
+ aConfig.close();
+ }
+
+ aWriteLock.unlock();
+ /* } SAFE */
+}
+
+//________________________________
+/**
+ @short set a new excution result
+ @descr Every executed job can have returned a result.
+ We set it here, so our user can use it may be later.
+ But the outside code can use it too, to analyze it and
+ adopt the configuration of this job too. Because the
+ result uses a protocol, which allow that. And we provide
+ right functionality to save it.
+
+ @param aResult
+ the result of last execution
+ */
+void JobData::setResult( const JobResult& aResult )
+{
+ /* SAFE { */
+ WriteGuard aWriteLock(m_aLock);
+
+ // overwrite the last saved result
+ m_aLastExecutionResult = aResult;
+
+ // Don't use his informations to update
+ // e.g. the arguments of this job. It must be done
+ // from outside! Here we save this information only.
+
+ aWriteLock.unlock();
+ /* } SAFE */
+}
+
+//________________________________
+/**
+ @short set a new environment descriptor for this job
+ @descr It must(!) be done everytime this container is initialized
+ with new job datas e.g.: setAlias()/setEvent()/setService() ...
+ Otherwhise the environment will be unknown!
+ */
+void JobData::setEnvironment( EEnvironment eEnvironment )
+{
+ /* SAFE { */
+ WriteGuard aWriteLock(m_aLock);
+ m_eEnvironment = eEnvironment;
+ aWriteLock.unlock();
+ /* } SAFE */
+}
+
+//________________________________
+/**
+ @short these functions provides access to our internal members
+ @descr These member represent any information about the job
+ and can be used from outside to e.g. start a job.
+ */
+JobData::EMode JobData::getMode() const
+{
+ /* SAFE { */
+ ReadGuard aReadLock(m_aLock);
+ return m_eMode;
+ /* } SAFE */
+}
+
+//________________________________
+
+JobData::EEnvironment JobData::getEnvironment() const
+{
+ /* SAFE { */
+ ReadGuard aReadLock(m_aLock);
+ return m_eEnvironment;
+ /* } SAFE */
+}
+
+//________________________________
+
+::rtl::OUString JobData::getEnvironmentDescriptor() const
+{
+ ::rtl::OUString sDescriptor;
+ /* SAFE { */
+ ReadGuard aReadLock(m_aLock);
+ switch(m_eEnvironment)
+ {
+ case E_EXECUTION :
+ sDescriptor = ::rtl::OUString::createFromAscii("EXECUTOR");
+ break;
+
+ case E_DISPATCH :
+ sDescriptor = ::rtl::OUString::createFromAscii("DISPATCH");
+ break;
+
+ case E_DOCUMENTEVENT :
+ sDescriptor = ::rtl::OUString::createFromAscii("DOCUMENTEVENT");
+ break;
+ default:
+ break;
+ }
+ /* } SAFE */
+ return sDescriptor;
+}
+
+//________________________________
+
+::rtl::OUString JobData::getService() const
+{
+ /* SAFE { */
+ ReadGuard aReadLock(m_aLock);
+ return m_sService;
+ /* } SAFE */
+}
+
+//________________________________
+
+::rtl::OUString JobData::getEvent() const
+{
+ /* SAFE { */
+ ReadGuard aReadLock(m_aLock);
+ return m_sEvent;
+ /* } SAFE */
+}
+
+//________________________________
+
+css::uno::Sequence< css::beans::NamedValue > JobData::getJobConfig() const
+{
+ /* SAFE { */
+ ReadGuard aReadLock(m_aLock);
+ return m_lArguments;
+ /* } SAFE */
+}
+
+//________________________________
+
+css::uno::Sequence< css::beans::NamedValue > JobData::getConfig() const
+{
+ /* SAFE { */
+ ReadGuard aReadLock(m_aLock);
+ css::uno::Sequence< css::beans::NamedValue > lConfig;
+ if (m_eMode==E_ALIAS)
+ {
+ lConfig.realloc(2);
+ sal_Int32 i = 0;
+
+ lConfig[i].Name = ::rtl::OUString::createFromAscii(PROP_ALIAS);
+ lConfig[i].Value <<= m_sAlias;
+ ++i;
+
+ lConfig[i].Name = ::rtl::OUString::createFromAscii(PROP_SERVICE);
+ lConfig[i].Value <<= m_sService;
+ ++i;
+ }
+ aReadLock.unlock();
+ /* } SAFE */
+ return lConfig;
+}
+
+//________________________________
+/**
+ @short return information, if this job is part of the global configuration package
+ org.openoffice.Office.Jobs
+ @descr Because jobs can be executed by the dispatch framework using an uno service name
+ directly - an executed job must not have any configuration realy. Such jobs
+ must provide the right interfaces only! But after finishing jobs can return
+ some informations (e.g. for updating her configuration ...). We must know
+ if such request is valid or not then.
+
+ @return TRUE if the represented job is part of the underlying configuration package.
+ */
+sal_Bool JobData::hasConfig() const
+{
+ /* SAFE { */
+ ReadGuard aReadLock(m_aLock);
+ return (m_eMode==E_ALIAS || m_eMode==E_EVENT);
+ /* } SAFE */
+}
+
+//________________________________
+/**
+ @short mark a job as non startable for further requests
+ @descr We don't remove the configuration entry! We set a timestamp value only.
+ And there exist two of them: one for an administrator ... and one for the
+ current user. We change it for the user layer only. So this JobDispatch can't be
+ started any more ... till the administrator change his timestamp.
+ That can be usefull for post setup scenarios, which must run one time only.
+
+ Note: This method don't do anything, if ths represented job doesn't have a configuration!
+ */
+void JobData::disableJob()
+{
+ /* SAFE { */
+ WriteGuard aWriteLock(m_aLock);
+
+ // No configuration - not used from EXECUTOR and not triggered from an event => no chance!
+ if (m_eMode!=E_EVENT)
+ return;
+
+ // update the configuration
+ // It doesn't matter if this config object was already opened before.
+ // It doesn nothing here then ... or it change the mode automaticly, if
+ // it was opened using another one before.
+ ::rtl::OUStringBuffer sKey(256);
+ sKey.appendAscii(JobData::EVENTCFG_ROOT );
+ sKey.append (::utl::wrapConfigurationElementName(m_sEvent));
+ sKey.appendAscii(JobData::EVENTCFG_PATH_JOBLIST );
+ sKey.appendAscii("/" );
+ sKey.append (::utl::wrapConfigurationElementName(m_sAlias));
+
+ ConfigAccess aConfig(m_xSMGR, sKey.makeStringAndClear());
+ aConfig.open(ConfigAccess::E_READWRITE);
+ if (aConfig.getMode()==ConfigAccess::E_CLOSED)
+ return;
+
+ css::uno::Reference< css::beans::XPropertySet > xPropSet(aConfig.cfg(), css::uno::UNO_QUERY);
+ if (xPropSet.is())
+ {
+ // Convert and write the user timestamp to the configuration.
+ css::uno::Any aValue;
+ aValue <<= Converter::convert_DateTime2ISO8601(DateTime());
+ xPropSet->setPropertyValue(::rtl::OUString::createFromAscii(EVENTCFG_PROP_USERTIME), aValue);
+ }
+
+ aConfig.close();
+
+ aWriteLock.unlock();
+ /* } SAFE */
+}
+
+//________________________________
+/**
+ */
+sal_Bool isEnabled( const ::rtl::OUString& sAdminTime ,
+ const ::rtl::OUString& sUserTime )
+{
+ /*Attention!
+ To prevent interpreting of TriGraphs inside next const string value,
+ we have to encode all '?' signs. Otherwhise e.g. "??-" will be translated
+ to "~" ...
+ */
+ static ::rtl::OUString PATTERN_ISO8601 = ::rtl::OUString::createFromAscii("\?\?\?\?-\?\?-\?\?*\0");
+ WildCard aISOPattern(PATTERN_ISO8601);
+
+ sal_Bool bValidAdmin = aISOPattern.Matches(sAdminTime);
+ sal_Bool bValidUser = aISOPattern.Matches(sUserTime );
+
+ // We check for "isEnabled()" here only.
+ // Note further: ISO8601 formated strings can be compared as strings directly!
+ return (
+ (!bValidAdmin && !bValidUser ) ||
+ ( bValidAdmin && bValidUser && sAdminTime>=sUserTime)
+ );
+}
+
+//________________________________
+/**
+ */
+void JobData::appendEnabledJobsForEvent( const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR ,
+ const ::rtl::OUString& sEvent ,
+ ::comphelper::SequenceAsVector< JobData::TJob2DocEventBinding >& lJobs )
+{
+ css::uno::Sequence< ::rtl::OUString > lAdditionalJobs = JobData::getEnabledJobsForEvent(xSMGR, sEvent);
+ sal_Int32 c = lAdditionalJobs.getLength();
+ sal_Int32 i = 0;
+
+ for (i=0; i<c; ++i)
+ {
+ JobData::TJob2DocEventBinding aBinding(lAdditionalJobs[i], sEvent);
+ lJobs.push_back(aBinding);
+ }
+}
+
+//________________________________
+/**
+ */
+css::uno::Sequence< ::rtl::OUString > JobData::getEnabledJobsForEvent( const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR ,
+ const ::rtl::OUString& sEvent )
+{
+ // these static values may perform following loop for reading time stamp values ...
+ static ::rtl::OUString ADMINTIME = ::rtl::OUString::createFromAscii(JobData::EVENTCFG_PROP_ADMINTIME);
+ static ::rtl::OUString USERTIME = ::rtl::OUString::createFromAscii(JobData::EVENTCFG_PROP_USERTIME );
+ static ::rtl::OUString ROOT = ::rtl::OUString::createFromAscii(JobData::EVENTCFG_ROOT );
+ static ::rtl::OUString JOBLIST = ::rtl::OUString::createFromAscii(JobData::EVENTCFG_PATH_JOBLIST );
+
+ // create a config access to "/org.openoffice.Office.Jobs/Events"
+ ConfigAccess aConfig(xSMGR,ROOT);
+ aConfig.open(ConfigAccess::E_READONLY);
+ if (aConfig.getMode()==ConfigAccess::E_CLOSED)
+ return css::uno::Sequence< ::rtl::OUString >();
+
+ css::uno::Reference< css::container::XHierarchicalNameAccess > xEventRegistry(aConfig.cfg(), css::uno::UNO_QUERY);
+ if (!xEventRegistry.is())
+ return css::uno::Sequence< ::rtl::OUString >();
+
+ // check if the given event exist inside list of registered ones
+ ::rtl::OUString sPath(sEvent);
+ sPath += JOBLIST;
+ if (!xEventRegistry->hasByHierarchicalName(sPath))
+ return css::uno::Sequence< ::rtl::OUString >();
+
+ // step to the job list, which is a child of the event node inside cfg
+ // e.g. "/org.openoffice.Office.Jobs/Events/<event name>/JobList"
+ css::uno::Any aJobList = xEventRegistry->getByHierarchicalName(sPath);
+ css::uno::Reference< css::container::XNameAccess > xJobList;
+ if (!(aJobList >>= xJobList) || !xJobList.is())
+ return css::uno::Sequence< ::rtl::OUString >();
+
+ // get all alias names of jobs, which are part of this job list
+ // But Some of them can be disabled by it's time stamp values.
+ // We create an additional job name list iwth the same size, then the original list ...
+ // step over all job entries ... check her time stamps ... and put only job names to the
+ // destination list, which represent an enabled job.
+ css::uno::Sequence< ::rtl::OUString > lAllJobs = xJobList->getElementNames();
+ ::rtl::OUString* pAllJobs = lAllJobs.getArray();
+ sal_Int32 c = lAllJobs.getLength();
+
+ css::uno::Sequence< ::rtl::OUString > lEnabledJobs(c);
+ ::rtl::OUString* pEnabledJobs = lEnabledJobs.getArray();
+ sal_Int32 d = 0;
+
+ for (sal_Int32 s=0; s<c; ++s)
+ {
+ css::uno::Reference< css::beans::XPropertySet > xJob;
+ if (
+ !(xJobList->getByName(pAllJobs[s]) >>= xJob) ||
+ !(xJob.is() )
+ )
+ {
+ continue;
+ }
+
+ ::rtl::OUString sAdminTime;
+ xJob->getPropertyValue(ADMINTIME) >>= sAdminTime;
+
+ ::rtl::OUString sUserTime;
+ xJob->getPropertyValue(USERTIME) >>= sUserTime;
+
+ if (!isEnabled(sAdminTime, sUserTime))
+ continue;
+
+ pEnabledJobs[d] = pAllJobs[s];
+ ++d;
+ }
+ lEnabledJobs.realloc(d);
+
+ aConfig.close();
+
+ return lEnabledJobs;
+}
+
+//________________________________
+/**
+ @short reset all internal structures
+ @descr If somehwere recycle this instance, he can switch from one
+ using mode to another one. But then we have to reset all currently
+ used informations. Otherwhise we mix it and they can make trouble.
+
+ But note: that does not set defaults for internal used members, which
+ does not relate to any job property! e.g. the reference to the global
+ uno service manager. Such informations are used for internal processes only
+ and are neccessary for our work.
+ */
+void JobData::impl_reset()
+{
+ /* SAFE { */
+ WriteGuard aWriteLock(m_aLock);
+ m_eMode = E_UNKNOWN_MODE;
+ m_eEnvironment = E_UNKNOWN_ENVIRONMENT;
+ m_sAlias = ::rtl::OUString();
+ m_sService = ::rtl::OUString();
+ m_sEvent = ::rtl::OUString();
+ m_lArguments = css::uno::Sequence< css::beans::NamedValue >();
+ aWriteLock.unlock();
+ /* } SAFE */
+}
+
+} // namespace framework
diff --git a/framework/source/jobs/jobdispatch.cxx b/framework/source/jobs/jobdispatch.cxx
new file mode 100644
index 000000000000..b2c5399d0216
--- /dev/null
+++ b/framework/source/jobs/jobdispatch.cxx
@@ -0,0 +1,475 @@
+ /*************************************************************************
+ *
+ * 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/jobdispatch.hxx>
+#include <jobs/joburl.hxx>
+#include <jobs/job.hxx>
+#include <threadhelp/readguard.hxx>
+#include <threadhelp/writeguard.hxx>
+#include <threadhelp/resetableguard.hxx>
+#include <classes/converter.hxx>
+#include <general.h>
+#include <services.h>
+
+//________________________________
+// interface includes
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/frame/DispatchResultState.hpp>
+
+//________________________________
+// includes of other projects
+#include <rtl/ustrbuf.hxx>
+#include <vcl/svapp.hxx>
+
+//________________________________
+// namespace
+
+namespace framework{
+
+//________________________________
+// non exported const
+
+//________________________________
+// non exported definitions
+
+//________________________________
+// declarations
+
+DEFINE_XINTERFACE_6( JobDispatch ,
+ OWeakObject ,
+ DIRECT_INTERFACE(css::lang::XTypeProvider ),
+ DIRECT_INTERFACE(css::frame::XDispatchProvider ),
+ DIRECT_INTERFACE(css::lang::XInitialization ),
+ DIRECT_INTERFACE(css::lang::XServiceInfo),
+ DIRECT_INTERFACE(css::frame::XNotifyingDispatch),
+ DIRECT_INTERFACE(css::frame::XDispatch )
+ )
+
+DEFINE_XTYPEPROVIDER_6( JobDispatch ,
+ css::lang::XTypeProvider ,
+ css::frame::XDispatchProvider ,
+ css::frame::XNotifyingDispatch,
+ css::lang::XInitialization,
+ css::lang::XServiceInfo,
+ css::frame::XDispatch
+ )
+
+DEFINE_XSERVICEINFO_MULTISERVICE( JobDispatch ,
+ ::cppu::OWeakObject ,
+ SERVICENAME_PROTOCOLHANDLER ,
+ IMPLEMENTATIONNAME_JOBDISPATCH
+ )
+
+DEFINE_INIT_SERVICE( JobDispatch,
+ {
+ /*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!
+ */
+ }
+ )
+
+//________________________________
+/**
+ @short standard ctor
+ @descr It initialize this new instance.
+
+ @param xSMGR
+ reference to the uno service manager
+*/
+JobDispatch::JobDispatch( /*IN*/ const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR )
+ : ThreadHelpBase(&Application::GetSolarMutex())
+ , OWeakObject ( )
+ , m_xSMGR (xSMGR )
+{
+}
+
+//________________________________
+/**
+ @short let this instance die
+ @descr We have to release all used ressources and free used memory.
+*/
+JobDispatch::~JobDispatch()
+{
+ // release all used ressources
+ m_xSMGR = css::uno::Reference< css::lang::XMultiServiceFactory >();
+ m_xFrame = css::uno::Reference< css::frame::XFrame >();
+}
+
+//________________________________
+/**
+ @short implementation of XInitalization
+ @descr A protocol handler can provide this functionality, if it wish to get additional informations
+ about the context it runs. In this case the frame reference would be given by the outside code.
+
+ @param lArguments
+ the list of initialization arguments
+ First parameter should be the frame reference we need.
+*/
+void SAL_CALL JobDispatch::initialize( const css::uno::Sequence< css::uno::Any >& lArguments ) throw(css::uno::Exception ,
+ css::uno::RuntimeException)
+{
+ /* SAFE { */
+ WriteGuard aWriteLock(m_aLock);
+
+ for (int a=0; a<lArguments.getLength(); ++a)
+ {
+ if (a==0)
+ lArguments[a] >>= m_xFrame;
+ }
+
+ aWriteLock.unlock();
+ /* } SAFE */
+}
+
+//________________________________
+/**
+ @short implementation of XDispatchProvider::queryDispatches()
+ @descr Every protocol handler will be asked for his agreement, if an URL was queried
+ for which this handler is registered. It's the chance for this handler to validate
+ the given URL and return a dispatch object (may be itself) or not.
+
+ @param aURL
+ the queried URL, which should be checked
+
+ @param sTargetFrameName
+ describes the target frame, in which context this handler will be used
+ Is mostly set to "", "_self", "_blank", "_default" or a non special one
+ using SELF/CREATE as search flags.
+
+ @param nSearchFlags
+ Can be SELF or CREATE only and are set only if sTargetFrameName isn't a special target
+*/
+css::uno::Reference< css::frame::XDispatch > SAL_CALL JobDispatch::queryDispatch( /*IN*/ const css::util::URL& aURL ,
+ /*IN*/ const ::rtl::OUString& /*sTargetFrameName*/ ,
+ /*IN*/ sal_Int32 /*nSearchFlags*/ ) throw(css::uno::RuntimeException)
+{
+ css::uno::Reference< css::frame::XDispatch > xDispatch;
+
+ JobURL aAnalyzedURL(aURL.Complete);
+ if (aAnalyzedURL.isValid())
+ xDispatch = css::uno::Reference< css::frame::XDispatch >( static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY );
+
+ return xDispatch;
+}
+
+//________________________________
+/**
+ @short implementation of XDispatchProvider::queryDispatches()
+ @descr It's an optimized access for remote, so you can ask for
+ multiple dispatch objects at the same time.
+
+ @param lDescriptor
+ a list of queryDispatch() parameter
+
+ @return A list of corresponding dispatch objects.
+ NULL references are not skipped. Every result
+ match to one given descriptor item.
+*/
+css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL JobDispatch::queryDispatches( const css::uno::Sequence< css::frame::DispatchDescriptor >& lDescriptor ) throw(css::uno::RuntimeException)
+{
+ // don't pack resulting list!
+ sal_Int32 nCount = lDescriptor.getLength();
+ css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > lDispatches(nCount);
+
+ for (sal_Int32 i=0; i<nCount; ++i)
+ lDispatches[i] = queryDispatch( lDescriptor[i].FeatureURL ,
+ lDescriptor[i].FrameName ,
+ lDescriptor[i].SearchFlags );
+ return lDispatches;
+}
+
+//________________________________
+/**
+ @short implementation of XNotifyingDispatch::dispatchWithNotification()
+ @descr It creates the job service implementation and call execute on it.
+ Further it starts the life time control of it. (important for async job)
+ For synchonrous job we react for the returned result directly ... for asynchronous
+ ones we do it later inside our callback method. But we use the same impl method
+ doing that to share the code. (see impl_finishJob())
+
+ If a job is already running, (it can only occure for asynchronous jobs)
+ don't start the same job a second time. Queue in the given dispatch parameter
+ and return immediatly. If the current running job call us back, we will start this
+ new dispatch request.
+ If no job is running - queue the parameter too! But then start the new job immediatly.
+ We have to queue it every time - because it hold us alive by ref count!
+
+ @param aURL
+ describe the job(s), which should be started
+
+ @param lArgs
+ optional arguments for this request
+
+ @param xListener
+ an interested listener for possible results of this operation
+*/
+void SAL_CALL JobDispatch::dispatchWithNotification( /*IN*/ const css::util::URL& aURL ,
+ /*IN*/ const css::uno::Sequence< css::beans::PropertyValue >& lArgs ,
+ /*IN*/ const css::uno::Reference< css::frame::XDispatchResultListener >& xListener ) throw(css::uno::RuntimeException)
+{
+ JobURL aAnalyzedURL(aURL.Complete);
+ if (aAnalyzedURL.isValid())
+ {
+ ::rtl::OUString sRequest;
+ if (aAnalyzedURL.getEvent(sRequest))
+ impl_dispatchEvent(sRequest, lArgs, xListener);
+ else
+ if (aAnalyzedURL.getService(sRequest))
+ impl_dispatchService(sRequest, lArgs, xListener);
+ else
+ if (aAnalyzedURL.getAlias(sRequest))
+ impl_dispatchAlias(sRequest, lArgs, xListener);
+ }
+}
+
+//________________________________
+/**
+ @short dispatch an event
+ @descr We search all registered jobs for this event and execute it.
+ After doing so, we inform the given listener about the results.
+ (There will be one notify for every executed job!)
+
+ @param sEvent
+ the event, for which jobs can be registered
+
+ @param lArgs
+ optional arguments for this request
+ Currently not used!
+
+ @param xListener
+ an interested listener for possible results of this operation
+*/
+void JobDispatch::impl_dispatchEvent( /*IN*/ const ::rtl::OUString& sEvent ,
+ /*IN*/ const css::uno::Sequence< css::beans::PropertyValue >& lArgs ,
+ /*IN*/ const css::uno::Reference< css::frame::XDispatchResultListener >& xListener )
+{
+ // 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.
+ /* SAFE { */
+ ReadGuard aReadLock(m_aLock);
+ css::uno::Sequence< ::rtl::OUString > lJobs = JobData::getEnabledJobsForEvent(m_xSMGR, sEvent);
+ aReadLock.unlock();
+ /* } SAFE */
+
+ css::uno::Reference< css::frame::XDispatchResultListener > xThis( static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY );
+
+ // no jobs ... no execution
+ // But a may given listener will know something ...
+ // I think this operaton was finished successfully.
+ // It's not realy an error, if no registered jobs could be located.
+ if (lJobs.getLength()<1 && xListener.is())
+ {
+ css::frame::DispatchResultEvent aEvent;
+ aEvent.Source = xThis;
+ aEvent.State = css::frame::DispatchResultState::SUCCESS;
+ xListener->dispatchFinished(aEvent);
+ return;
+ }
+
+ // Step over all found jobs and execute it
+ for (int j=0; j<lJobs.getLength(); ++j)
+ {
+ /* SAFE { */
+ aReadLock.lock();
+
+ JobData aCfg(m_xSMGR);
+ aCfg.setEvent(sEvent, lJobs[j]);
+ aCfg.setEnvironment(JobData::E_DISPATCH);
+
+ /*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, m_xFrame);
+ css::uno::Reference< css::uno::XInterface > xJob(static_cast< ::cppu::OWeakObject* >(pJob), css::uno::UNO_QUERY);
+ pJob->setJobData(aCfg);
+
+ aReadLock.unlock();
+ /* } SAFE */
+
+ // Special mode for listener.
+ // We dont notify it directly here. We delegate that
+ // to the job implementation. But we must set ourself there too.
+ // Because this job must fake the source adress of the event.
+ // Otherwhise the listener may will ignore it.
+ if (xListener.is())
+ pJob->setDispatchResultFake(xListener, xThis);
+ pJob->execute(Converter::convert_seqPropVal2seqNamedVal(lArgs));
+ }
+}
+
+//________________________________
+/**
+ @short dispatch a service
+ @descr We use the given name only to create and if possible to initialize
+ it as an uno service. It can be usefully for creating (caching?)
+ of e.g. one instance services.
+
+ @param sService
+ the uno implementation or service name of the job, which should be instanciated
+
+ @param lArgs
+ optional arguments for this request
+ Currently not used!
+
+ @param xListener
+ an interested listener for possible results of this operation
+*/
+void JobDispatch::impl_dispatchService( /*IN*/ const ::rtl::OUString& sService ,
+ /*IN*/ const css::uno::Sequence< css::beans::PropertyValue >& lArgs ,
+ /*IN*/ const css::uno::Reference< css::frame::XDispatchResultListener >& xListener )
+{
+ /* SAFE { */
+ ReadGuard aReadLock(m_aLock);
+
+ JobData aCfg(m_xSMGR);
+ aCfg.setService(sService);
+ aCfg.setEnvironment(JobData::E_DISPATCH);
+
+ /*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, m_xFrame);
+ css::uno::Reference< css::uno::XInterface > xJob(static_cast< ::cppu::OWeakObject* >(pJob), css::uno::UNO_QUERY);
+ pJob->setJobData(aCfg);
+
+ aReadLock.unlock();
+ /* } SAFE */
+
+ css::uno::Reference< css::frame::XDispatchResultListener > xThis( static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY );
+
+ // Special mode for listener.
+ // We dont notify it directly here. We delegate that
+ // to the job implementation. But we must set ourself there too.
+ // Because this job must fake the source adress of the event.
+ // Otherwhise the listener may will ignore it.
+ if (xListener.is())
+ pJob->setDispatchResultFake(xListener, xThis);
+ pJob->execute(Converter::convert_seqPropVal2seqNamedVal(lArgs));
+}
+
+//________________________________
+/**
+ @short dispatch an alias
+ @descr We use this alias to locate a job inside the configuration
+ and execute it. Further we inform the given listener about the results.
+
+ @param sAlias
+ the alias name of the configured job
+
+ @param lArgs
+ optional arguments for this request
+ Currently not used!
+
+ @param xListener
+ an interested listener for possible results of this operation
+*/
+void JobDispatch::impl_dispatchAlias( /*IN*/ const ::rtl::OUString& sAlias ,
+ /*IN*/ const css::uno::Sequence< css::beans::PropertyValue >& lArgs ,
+ /*IN*/ const css::uno::Reference< css::frame::XDispatchResultListener >& xListener )
+{
+ /* SAFE { */
+ ReadGuard aReadLock(m_aLock);
+
+ JobData aCfg(m_xSMGR);
+ aCfg.setAlias(sAlias);
+ aCfg.setEnvironment(JobData::E_DISPATCH);
+
+ /*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, m_xFrame);
+ css::uno::Reference< css::uno::XInterface > xJob(static_cast< ::cppu::OWeakObject* >(pJob), css::uno::UNO_QUERY);
+ pJob->setJobData(aCfg);
+
+ aReadLock.unlock();
+ /* } SAFE */
+
+ css::uno::Reference< css::frame::XDispatchResultListener > xThis( static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY );
+
+ // Special mode for listener.
+ // We dont notify it directly here. We delegate that
+ // to the job implementation. But we must set ourself there too.
+ // Because this job must fake the source adress of the event.
+ // Otherwhise the listener may will ignore it.
+ if (xListener.is())
+ pJob->setDispatchResultFake(xListener, xThis);
+ pJob->execute(Converter::convert_seqPropVal2seqNamedVal(lArgs));
+}
+
+//________________________________
+/**
+ @short implementation of XDispatch::dispatch()
+ @descr Because the methods dispatch() and dispatchWithNotification() are different in her parameters
+ only, we can forward this request to dispatchWithNotification() by using an empty listener!
+
+ @param aURL
+ describe the job(s), which should be started
+
+ @param lArgs
+ optional arguments for this request
+
+ @see dispatchWithNotification()
+*/
+void SAL_CALL JobDispatch::dispatch( /*IN*/ const css::util::URL& aURL ,
+ /*IN*/ const css::uno::Sequence< css::beans::PropertyValue >& lArgs ) throw(css::uno::RuntimeException)
+{
+ dispatchWithNotification(aURL, lArgs, css::uno::Reference< css::frame::XDispatchResultListener >());
+}
+
+//________________________________
+/**
+ @short not supported
+*/
+void SAL_CALL JobDispatch::addStatusListener( /*IN*/ const css::uno::Reference< css::frame::XStatusListener >&,
+ /*IN*/ const css::util::URL& ) throw(css::uno::RuntimeException)
+{
+}
+
+//________________________________
+/**
+ @short not supported
+*/
+void SAL_CALL JobDispatch::removeStatusListener( /*IN*/ const css::uno::Reference< css::frame::XStatusListener >&,
+ /*IN*/ const css::util::URL& ) throw(css::uno::RuntimeException)
+{
+}
+
+} // namespace framework
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
diff --git a/framework/source/jobs/jobresult.cxx b/framework/source/jobs/jobresult.cxx
new file mode 100644
index 000000000000..375a3e5fc4d6
--- /dev/null
+++ b/framework/source/jobs/jobresult.cxx
@@ -0,0 +1,261 @@
+ /*************************************************************************
+ *
+ * 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/jobresult.hxx>
+#include <jobs/jobconst.hxx>
+#include <threadhelp/readguard.hxx>
+#include <threadhelp/writeguard.hxx>
+#include <general.h>
+#include <services.h>
+
+//________________________________
+// interface includes
+
+//________________________________
+// includes of other projects
+
+#include <rtl/ustrbuf.hxx>
+#include <vcl/svapp.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+
+//________________________________
+// namespace
+
+namespace framework{
+
+//________________________________
+// non exported const
+
+//________________________________
+// non exported definitions
+
+//________________________________
+// declarations
+
+//________________________________
+/**
+ @short standard dtor
+ @descr It does nothing else ...
+ but it marks this new instance as non valid!
+*/
+JobResult::JobResult()
+ : ThreadHelpBase(&Application::GetSolarMutex())
+{
+ // reset the flag mask!
+ // It will reset the accessible state of this object.
+ // That can be usefull if something will fail here ...
+ m_eParts = E_NOPART;
+}
+
+//________________________________
+/**
+ @short special ctor
+ @descr It initialize this new instance with a pure job execution result
+ and analyze it. Doing so, we update our other members.
+
+ <p>
+ It's a list of named values, packed inside this any.
+ Following protocol is used:
+ <p>
+ <ul>
+ <li>
+ "SaveArguments" [sequence< css.beans.NamedValue >]
+ <br>
+ The returned list of (for this generic implementation unknown!)
+ properties, will be written directly to the configuration and replace
+ any old values there. There will no check for changes and we doesn't
+ support any mege feature here. They are written only. The job has
+ to modify this list.
+ </li>
+ <li>
+ "SendDispatchResult" [css.frame.DispatchResultEvent]
+ <br>
+ The given event is send to all current registered listener.
+ But it's not guaranteed. In case no listener are available or
+ this job isn't part of the dispatch environment (because it was used
+ by the css..task.XJobExecutor->trigger() implementation) this option
+ will be ignored.
+ </li>
+ <li>
+ "Deactivate" [boolean]
+ <br>
+ The job whish to be disabled. But note: There is no way, to enable it later
+ again by using this implementation. It can be done by using the configuration
+ only. (Means to register this job again.)
+ If a job knows, that there exist some status or result listener, it must use
+ the options "SendDispatchStatus" and "SendDispatchResult" (see before) too, to
+ inform it about the deactivation of this service.
+ </li>
+ </ul>
+
+ @param aResult
+ the job result
+*/
+JobResult::JobResult( /*IN*/ const css::uno::Any& aResult )
+ : ThreadHelpBase(&Application::GetSolarMutex())
+{
+ // safe the pure result
+ // May someone need it later ...
+ m_aPureResult = aResult;
+
+ // reset the flag mask!
+ // It will reset the accessible state of this object.
+ // That can be usefull if something will fail here ...
+ m_eParts = E_NOPART;
+
+ // analyze the result and update our other members
+ ::comphelper::SequenceAsHashMap aProtocol(aResult);
+ if ( aProtocol.empty() )
+ return;
+
+ ::comphelper::SequenceAsHashMap::const_iterator pIt = aProtocol.end();
+
+ pIt = aProtocol.find(JobConst::ANSWER_DEACTIVATE_JOB());
+ if (pIt != aProtocol.end())
+ {
+ pIt->second >>= m_bDeactivate;
+ if (m_bDeactivate)
+ m_eParts |= E_DEACTIVATE;
+ }
+
+ pIt = aProtocol.find(JobConst::ANSWER_SAVE_ARGUMENTS());
+ if (pIt != aProtocol.end())
+ {
+ pIt->second >>= m_lArguments;
+ if (m_lArguments.getLength() > 0)
+ m_eParts |= E_ARGUMENTS;
+ }
+
+ pIt = aProtocol.find(JobConst::ANSWER_SEND_DISPATCHRESULT());
+ if (pIt != aProtocol.end())
+ {
+ if (pIt->second >>= m_aDispatchResult)
+ m_eParts |= E_DISPATCHRESULT;
+ }
+}
+
+//________________________________
+/**
+ @short copy dtor
+ @descr -
+*/
+JobResult::JobResult( const JobResult& rCopy )
+ : ThreadHelpBase(&Application::GetSolarMutex())
+{
+ m_aPureResult = rCopy.m_aPureResult ;
+ m_eParts = rCopy.m_eParts ;
+ m_lArguments = rCopy.m_lArguments ;
+ m_bDeactivate = rCopy.m_bDeactivate ;
+ m_aDispatchResult = rCopy.m_aDispatchResult ;
+}
+
+//________________________________
+/**
+ @short standard dtor
+ @descr Free all internaly used ressources at the end of living.
+*/
+JobResult::~JobResult()
+{
+ // Nothing realy to do here.
+}
+
+//________________________________
+/**
+ @short =operator
+ @descr Must be implemented to overwrite this instance with another one.
+
+ @param rCopy
+ reference to the other instance, which should be used for copying.
+*/
+void JobResult::operator=( const JobResult& rCopy )
+{
+ /* SAFE { */
+ WriteGuard aWriteLock(m_aLock);
+ m_aPureResult = rCopy.m_aPureResult ;
+ m_eParts = rCopy.m_eParts ;
+ m_lArguments = rCopy.m_lArguments ;
+ m_bDeactivate = rCopy.m_bDeactivate ;
+ m_aDispatchResult = rCopy.m_aDispatchResult ;
+ aWriteLock.unlock();
+ /* } SAFE */
+}
+
+//________________________________
+/**
+ @short checks for existing parts of the analyzed result
+ @descr The internal flag mask was set after analyzing of the pure result.
+ An user of us can check here, if the required part was realy part
+ of this result. Otherwhise it would use invalid informations ...
+ by using our other members!
+
+ @param eParts
+ a flag mask too, which will be compared with our internaly set one.
+
+ @return We return true only, if any set flag of the given mask match.
+*/
+sal_Bool JobResult::existPart( sal_uInt32 eParts ) const
+{
+ /* SAFE { */
+ ReadGuard aReadLock(m_aLock);
+ return ((m_eParts & eParts) == eParts);
+ /* } SAFE */
+}
+
+//________________________________
+/**
+ @short provides access to our internal members
+ @descr The return value will be valid only in case a call of
+ existPart(E_...) before returned true!
+
+ @return It returns the state of the internal member
+ without any checks!
+*/
+css::uno::Sequence< css::beans::NamedValue > JobResult::getArguments() const
+{
+ /* SAFE { */
+ ReadGuard aReadLock(m_aLock);
+ return m_lArguments;
+ /* } SAFE */
+}
+
+//________________________________
+
+css::frame::DispatchResultEvent JobResult::getDispatchResult() const
+{
+ /* SAFE { */
+ ReadGuard aReadLock(m_aLock);
+ return m_aDispatchResult;
+ /* } SAFE */
+}
+
+} // namespace framework
diff --git a/framework/source/jobs/joburl.cxx b/framework/source/jobs/joburl.cxx
new file mode 100644
index 000000000000..59e6384a0e93
--- /dev/null
+++ b/framework/source/jobs/joburl.cxx
@@ -0,0 +1,657 @@
+/*************************************************************************
+ *
+ * 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/joburl.hxx>
+#include <threadhelp/readguard.hxx>
+#include <threadhelp/writeguard.hxx>
+#include <general.h>
+
+//________________________________
+// interface includes
+
+//________________________________
+// includes of other projects
+#include <rtl/ustrbuf.hxx>
+#include <vcl/svapp.hxx>
+
+//________________________________
+// namespace
+
+namespace framework{
+
+//________________________________
+// non exported const
+
+//________________________________
+// non exported definitions
+
+//________________________________
+// declarations
+
+//________________________________
+/**
+ @short special ctor
+ @descr It initialize this new instance with a (hopyfully) valid job URL.
+ This URL will be parsed. After that we set our members right,
+ so other interface methods of this class can be used to get
+ all items of this URL. Of course it will be possible to know,
+ if this URL was valid too.
+
+ @param sURL
+ the job URL for parsing
+*/
+JobURL::JobURL( /*IN*/ const ::rtl::OUString& sURL )
+ : ThreadHelpBase( &Application::GetSolarMutex() )
+{
+ #ifdef ENABLE_COMPONENT_SELF_CHECK
+ JobURL::impldbg_checkIt();
+ #endif
+
+ m_eRequest = E_UNKNOWN;
+
+ // syntax: vnd.sun.star.job:{[event=<name>],[alias=<name>],[service=<name>]}
+
+ // check for "vnd.sun.star.job:"
+ if (sURL.matchIgnoreAsciiCaseAsciiL(JOBURL_PROTOCOL_STR,JOBURL_PROTOCOL_LEN,0))
+ {
+ sal_Int32 t = JOBURL_PROTOCOL_LEN;
+ do
+ {
+ // seperate all token of "{[event=<name>],[alias=<name>],[service=<name>]}"
+ ::rtl::OUString sToken = sURL.getToken(0, JOBURL_PART_SEPERATOR, t);
+ ::rtl::OUString sPartValue ;
+ ::rtl::OUString sPartArguments;
+
+ // check for "event="
+ if (
+ (JobURL::implst_split(sToken,JOBURL_EVENT_STR,JOBURL_EVENT_LEN,sPartValue,sPartArguments)) &&
+ (sPartValue.getLength()>0 )
+ )
+ {
+ // set the part value
+ m_sEvent = sPartValue ;
+ m_sEventArgs = sPartArguments;
+ m_eRequest |= E_EVENT ;
+ }
+ else
+ // check for "alias="
+ if (
+ (JobURL::implst_split(sToken,JOBURL_ALIAS_STR,JOBURL_ALIAS_LEN,sPartValue,sPartArguments)) &&
+ (sPartValue.getLength()>0 )
+ )
+ {
+ // set the part value
+ m_sAlias = sPartValue ;
+ m_sAliasArgs = sPartArguments;
+ m_eRequest |= E_ALIAS ;
+ }
+ else
+ // check for "service="
+ if (
+ (JobURL::implst_split(sToken,JOBURL_SERVICE_STR,JOBURL_SERVICE_LEN,sPartValue,sPartArguments)) &&
+ (sPartValue.getLength()>0 )
+ )
+ {
+ // set the part value
+ m_sService = sPartValue ;
+ m_sServiceArgs = sPartArguments;
+ m_eRequest |= E_SERVICE ;
+ }
+ }
+ while(t!=-1);
+ }
+}
+
+//________________________________
+/**
+ @short knows, if this job URL object hold a valid URL inside
+
+ @return <TRUE/> if it represent a valid job URL.
+*/
+sal_Bool JobURL::isValid() const
+{
+ /* SAFE { */
+ ReadGuard aReadLock(m_aLock);
+ return (m_eRequest!=E_UNKNOWN);
+}
+
+//________________________________
+/**
+ @short get the event item of this job URL
+ @descr Because the three possible parts of such URL (event, alias, service)
+ can't be combined, this method can(!) return a valid value - but it's
+ not a must. Thats why the return value must be used too, to detect a missing
+ event value.
+
+ @param sEvent
+ returns the possible existing event value
+ e.g. "vnd.sun.star.job:event=myEvent" returns "myEvent"
+
+ @return <TRUE/> if an event part of the job URL exist and the out parameter
+ sEvent was filled.
+
+ @attention The out parameter will be reseted everytime. Don't use it if method returns <FALSE/>!
+*/
+sal_Bool JobURL::getEvent( /*OUT*/ ::rtl::OUString& sEvent ) const
+{
+ /* SAFE { */
+ ReadGuard aReadLock(m_aLock);
+
+ sEvent = ::rtl::OUString();
+ sal_Bool bSet = ((m_eRequest & E_EVENT) == E_EVENT);
+ if (bSet)
+ sEvent = m_sEvent;
+
+ aReadLock.unlock();
+ /* } SAFE */
+
+ return bSet;
+}
+
+//________________________________
+/**
+ @short get the alias item of this job URL
+ @descr Because the three possible parts of such URL (event, alias, service)
+ can't be combined, this method can(!) return a valid value - but it's
+ not a must. Thats why the return value must be used too, to detect a missing
+ alias value.
+
+ @param sAlias
+ returns the possible existing alias value
+ e.g. "vnd.sun.star.job:alias=myAlias" returns "myAlias"
+
+ @return <TRUE/> if an alias part of the job URL exist and the out parameter
+ sAlias was filled.
+
+ @attention The out parameter will be reseted everytime. Don't use it if method returns <FALSE/>!
+*/
+sal_Bool JobURL::getAlias( /*OUT*/ ::rtl::OUString& sAlias ) const
+{
+ /* SAFE { */
+ ReadGuard aReadLock(m_aLock);
+
+ sAlias = ::rtl::OUString();
+ sal_Bool bSet = ((m_eRequest & E_ALIAS) == E_ALIAS);
+ if (bSet)
+ sAlias = m_sAlias;
+
+ aReadLock.unlock();
+ /* } SAFE */
+
+ return bSet;
+}
+
+//________________________________
+/**
+ @short get the service item of this job URL
+ @descr Because the three possible parts of such URL (event, service, service)
+ can't be combined, this method can(!) return a valid value - but it's
+ not a must. Thats why the return value must be used too, to detect a missing
+ service value.
+
+ @param sAlias
+ returns the possible existing service value
+ e.g. "vnd.sun.star.job:service=com.sun.star.Service" returns "com.sun.star.Service"
+
+ @return <TRUE/> if an service part of the job URL exist and the out parameter
+ sService was filled.
+
+ @attention The out parameter will be reseted everytime. Don't use it if method returns <FALSE/>!
+*/
+sal_Bool JobURL::getService( /*OUT*/ ::rtl::OUString& sService ) const
+{
+ /* SAFE { */
+ ReadGuard aReadLock(m_aLock);
+
+ sService = ::rtl::OUString();
+ sal_Bool bSet = ((m_eRequest & E_SERVICE) == E_SERVICE);
+ if (bSet)
+ sService = m_sService;
+
+ aReadLock.unlock();
+ /* } SAFE */
+
+ return bSet;
+}
+
+//________________________________
+/**
+ @short searches for a special identifier in the given string and split it
+ @descr If the given identifier could be found at the beginning of the given string,
+ this method split it into different parts and return it.
+ Following schema is used: <partidentifier>=<partvalue>[?<partarguments>]
+
+ @param sPart
+ the string, which should be analyzed
+
+ @param pPartIdentifier
+ the part identifier value, which must be found at the beginning of the
+ parameter <var>sPart</var>
+
+ @param nPartLength
+ the length of the ascii value <var>pPartIdentifier</var>
+
+ @param rPartValue
+ returns the part value if <var>sPart</var> was splitted successfully
+
+ @param rPartArguments
+ returns the part arguments if <var>sPart</var> was splitted successfully
+
+ @return <TRUE/> if the identifier could be found and the string was splitted.
+ <FALSE/> otherwhise.
+*/
+sal_Bool JobURL::implst_split( /*IN*/ const ::rtl::OUString& sPart ,
+ /*IN*/ const sal_Char* pPartIdentifier ,
+ /*IN*/ sal_Int32 nPartLength ,
+ /*OUT*/ ::rtl::OUString& rPartValue ,
+ /*OUT*/ ::rtl::OUString& rPartArguments )
+{
+ // first search for the given identifier
+ sal_Bool bPartFound = (sPart.matchIgnoreAsciiCaseAsciiL(pPartIdentifier,nPartLength,0));
+
+ // If it exist - we can split the part and return TRUE.
+ // Otherwhise we do nothing and return FALSE.
+ if (bPartFound)
+ {
+ // But may the part has optional arguments - seperated by a "?".
+ // Do so - we set the return value with the whole part string.
+ // Arguments will be set to an empty string as default.
+ // If we detect the right sign - we split the arguments and overwrite the default.
+ ::rtl::OUString sValueAndArguments = sPart.copy(nPartLength);
+ ::rtl::OUString sValue = sValueAndArguments ;
+ ::rtl::OUString sArguments;
+
+ sal_Int32 nArgStart = sValueAndArguments.indexOf('?',0);
+ if (nArgStart!=-1)
+ {
+ sValue = sValueAndArguments.copy(0,nArgStart);
+ ++nArgStart; // ignore '?'!
+ sArguments = sValueAndArguments.copy(nArgStart);
+ }
+
+ rPartValue = sValue ;
+ rPartArguments = sArguments;
+ }
+
+ return bPartFound;
+}
+
+//________________________________
+/**
+ @short special debug method
+ @descr It's the entry point method to start a self component check for this class.
+ It's used for internal purposes only and never a part of a legal product.
+ Use it for testing and debug only!
+*/
+#ifdef ENABLE_COMPONENT_SELF_CHECK
+
+#define LOGFILE_JOBURL "joburl.log"
+
+void JobURL::impldbg_checkIt()
+{
+ // check simple URL's
+ JobURL::impldbg_checkURL("vnd.sun.star.job:event=onMyEvent" , E_EVENT , "onMyEvent", "" , "" , NULL, NULL, NULL);
+ JobURL::impldbg_checkURL("vnd.sun.star.job:alias=myAlias" , E_ALIAS , "" , "myAlias", "" , NULL, NULL, NULL);
+ JobURL::impldbg_checkURL("vnd.sun.star.job:service=css.Service", E_SERVICE, "" , "" , "css.Service", NULL, NULL, NULL);
+ JobURL::impldbg_checkURL("vnd.sun.star.job:service=;" , E_UNKNOWN, "" , "" , "" , NULL, NULL, NULL);
+
+ // check combinations
+ // Note: No additional spaces or tabs are allowed after a seperator occured.
+ // Tab and spaces before a seperator will be used as value!
+ JobURL::impldbg_checkURL("vnd.sun.star.job:event=onMyEvent;alias=myAlias;service=css.Service" , E_EVENT | E_ALIAS | E_SERVICE , "onMyEvent", "myAlias", "css.Service" , NULL, NULL, NULL);
+ JobURL::impldbg_checkURL("vnd.sun.star.job:service=css.Service;alias=myAlias" , E_ALIAS | E_SERVICE , "" , "myAlias", "css.Service" , NULL, NULL, NULL);
+ JobURL::impldbg_checkURL("vnd.sun.star.job:service=css.Service ;alias=myAlias" , E_ALIAS | E_SERVICE , "" , "myAlias", "css.Service ", NULL, NULL, NULL);
+ JobURL::impldbg_checkURL("vnd.sun.star.job:service=css.Service; alias=myAlias" , E_UNKNOWN , "" , "" , "" , NULL, NULL, NULL);
+ JobURL::impldbg_checkURL("vnd.sun.star.job : event=onMyEvent" , E_UNKNOWN , "" , "" , "" , NULL, NULL, NULL);
+ JobURL::impldbg_checkURL("vnd.sun.star.job:event=onMyEvent;event=onMyEvent;service=css.Service", E_UNKNOWN , "" , "" , "" , NULL, NULL, NULL);
+
+ // check upper/lower case
+ // fix parts of the URL are case insensitive (e.g. "vnd.SUN.star.job:eVEnt=")
+ // values are case sensitive (e.g. "myAlias" )
+ JobURL::impldbg_checkURL("vnd.SUN.star.job:eVEnt=onMyEvent;aliAs=myAlias;serVice=css.Service", E_EVENT | E_ALIAS | E_SERVICE , "onMyEvent", "myAlias", "css.Service" , NULL, NULL, NULL);
+ JobURL::impldbg_checkURL("vnd.SUN.star.job:eVEnt=onMyEVENT;aliAs=myALIAS;serVice=css.SERVICE", E_EVENT | E_ALIAS | E_SERVICE , "onMyEVENT", "myALIAS", "css.SERVICE" , NULL, NULL, NULL);
+
+ // check stupid URLs
+ JobURL::impldbg_checkURL("vnd.sun.star.jobs:service=css.Service" , E_UNKNOWN, "", "", "", NULL, NULL, NULL);
+ JobURL::impldbg_checkURL("vnd.sun.star.job service=css.Service" , E_UNKNOWN, "", "", "", NULL, NULL, NULL);
+ JobURL::impldbg_checkURL("vnd.sun.star.job:service;css.Service" , E_UNKNOWN, "", "", "", NULL, NULL, NULL);
+ JobURL::impldbg_checkURL("vnd.sun.star.job:service;" , E_UNKNOWN, "", "", "", NULL, NULL, NULL);
+ JobURL::impldbg_checkURL("vnd.sun.star.job:;alias;service;event=" , E_UNKNOWN, "", "", "", NULL, NULL, NULL);
+ JobURL::impldbg_checkURL("vnd.sun.star.job:alias=a;service=s;event=", E_UNKNOWN, "", "", "", NULL, NULL, NULL);
+
+ // check argument handling
+ JobURL::impldbg_checkURL("vnd.sun.star.job:event=onMyEvent?eventArg1,eventArg2=3,eventArg4," , E_EVENT , "onMyEvent", "" , "" , "eventArg1,eventArg2=3,eventArg4,", NULL , NULL );
+ JobURL::impldbg_checkURL("vnd.sun.star.job:alias=myAlias?aliasArg1,aliasarg2" , E_EVENT , "" , "myAlias", "" , NULL , "aliasArg1,aliasarg2", NULL );
+ JobURL::impldbg_checkURL("vnd.sun.star.job:service=css.myService?serviceArg1" , E_EVENT , "" , "" , "css.myService", NULL , NULL , "serviceArg1" );
+ JobURL::impldbg_checkURL("vnd.sun.star.job:service=css.myService?serviceArg1;alias=myAlias?aliasArg=564", E_EVENT | E_ALIAS, "" , "myAlias", "css.myService", NULL , "aliasArg=564" , "serviceArg1" );
+}
+
+//________________________________
+/**
+ @short helper debug method
+ @descr It uses the given parameter to create a new instance of a JobURL.
+ They results will be compared with the exepected ones.
+ The a log will be written, which contains some detailed informations
+ for this sub test.
+
+ @param pURL
+ the job URL, which should be checked
+
+ @param eExpectedPart
+ the expected result
+
+ @param pExpectedEvent
+ the expected event value
+
+ @param pExpectedAlias
+ the expected alias value
+
+ @param pExpectedService
+ the expected service value
+
+ @param pExpectedEventArgs
+ the expected event arguments
+
+ @param pExpectedAliasArgs
+ the expected alias arguments
+
+ @param pExpectedServiceArgs
+ the expected service arguments
+*/
+void JobURL::impldbg_checkURL( /*IN*/ const sal_Char* pURL ,
+ /*IN*/ sal_uInt32 eExpectedPart ,
+ /*IN*/ const sal_Char* pExpectedEvent ,
+ /*IN*/ const sal_Char* pExpectedAlias ,
+ /*IN*/ const sal_Char* pExpectedService ,
+ /*IN*/ const sal_Char* pExpectedEventArgs ,
+ /*IN*/ const sal_Char* pExpectedAliasArgs ,
+ /*IN*/ const sal_Char* pExpectedServiceArgs )
+{
+ ::rtl::OUString sEvent ;
+ ::rtl::OUString sAlias ;
+ ::rtl::OUString sService ;
+ ::rtl::OUString sEventArgs ;
+ ::rtl::OUString sAliasArgs ;
+ ::rtl::OUString sServiceArgs;
+ ::rtl::OUString sURL (::rtl::OUString::createFromAscii(pURL));
+ sal_Bool bOK = sal_True;
+
+ JobURL aURL(sURL);
+
+ // check if URL is invalid
+ if (eExpectedPart==E_UNKNOWN)
+ bOK = !aURL.isValid();
+
+ // check if URL has the expected event part
+ if (
+ (bOK ) &&
+ ((eExpectedPart & E_EVENT) == E_EVENT)
+ )
+ {
+ bOK = (
+ (aURL.isValid() ) &&
+ (aURL.getEvent(sEvent) ) &&
+ (sEvent.getLength()>0 ) &&
+ (sEvent.compareToAscii(pExpectedEvent)==0)
+ );
+
+ if (bOK && pExpectedEventArgs!=NULL)
+ {
+ bOK = (
+ (aURL.getEventArgs(sEventArgs) ) &&
+ (sEventArgs.compareToAscii(pExpectedEventArgs)==0)
+ );
+ };
+ }
+
+ // check if URL has no event part
+ if (
+ (bOK ) &&
+ ((eExpectedPart & E_EVENT) != E_EVENT)
+ )
+ {
+ bOK = (
+ (!aURL.getEvent(sEvent) ) &&
+ (sEvent.getLength()==0 ) &&
+ (!aURL.getEventArgs(sEventArgs)) &&
+ (sEventArgs.getLength()==0 )
+ );
+ }
+
+ // check if URL has the expected alias part
+ if (
+ (bOK ) &&
+ ((eExpectedPart & E_ALIAS) == E_ALIAS)
+ )
+ {
+ bOK = (
+ (aURL.isValid() ) &&
+ (aURL.getAlias(sAlias) ) &&
+ (sAlias.getLength()>0 ) &&
+ (sAlias.compareToAscii(pExpectedAlias)==0)
+ );
+
+ if (bOK && pExpectedAliasArgs!=NULL)
+ {
+ bOK = (
+ (aURL.getAliasArgs(sAliasArgs) ) &&
+ (sAliasArgs.compareToAscii(pExpectedAliasArgs)==0)
+ );
+ };
+ }
+
+ // check if URL has the no alias part
+ if (
+ (bOK ) &&
+ ((eExpectedPart & E_ALIAS) != E_ALIAS)
+ )
+ {
+ bOK = (
+ (!aURL.getAlias(sAlias) ) &&
+ (sAlias.getLength()==0 ) &&
+ (!aURL.getAliasArgs(sAliasArgs)) &&
+ (sAliasArgs.getLength()==0 )
+ );
+ }
+
+ // check if URL has the expected service part
+ if (
+ (bOK ) &&
+ ((eExpectedPart & E_SERVICE) == E_SERVICE)
+ )
+ {
+ bOK = (
+ (aURL.isValid() ) &&
+ (aURL.getService(sService) ) &&
+ (sService.getLength()>0 ) &&
+ (sService.compareToAscii(pExpectedService)==0)
+ );
+
+ if (bOK && pExpectedServiceArgs!=NULL)
+ {
+ bOK = (
+ (aURL.getServiceArgs(sServiceArgs) ) &&
+ (sServiceArgs.compareToAscii(pExpectedServiceArgs)==0)
+ );
+ };
+ }
+
+ // check if URL has the no service part
+ if (
+ (bOK ) &&
+ ((eExpectedPart & E_SERVICE) != E_SERVICE)
+ )
+ {
+ bOK = (
+ (!aURL.getService(sService) ) &&
+ (sService.getLength()==0 ) &&
+ (!aURL.getServiceArgs(sServiceArgs)) &&
+ (sServiceArgs.getLength()==0 )
+ );
+ }
+
+ ::rtl::OUStringBuffer sMsg(256);
+
+ sMsg.appendAscii("\"" );
+ sMsg.append (sURL );
+ sMsg.appendAscii("\" ");
+
+ if (bOK)
+ {
+ sMsg.appendAscii("... OK\n");
+ }
+ else
+ {
+ sMsg.appendAscii("... failed\n");
+ sMsg.appendAscii("expected was: ");
+ if (eExpectedPart==E_UNKNOWN)
+ sMsg.appendAscii("E_UNKNOWN");
+ if ((eExpectedPart & E_EVENT) == E_EVENT)
+ {
+ sMsg.appendAscii("| E_EVENT e=\"");
+ sMsg.appendAscii(pExpectedEvent );
+ sMsg.appendAscii("\"" );
+ }
+ if ((eExpectedPart & E_ALIAS) == E_ALIAS)
+ {
+ sMsg.appendAscii("| E_ALIAS a=\"");
+ sMsg.appendAscii(pExpectedAlias );
+ sMsg.appendAscii("\"" );
+ }
+ if ((eExpectedPart & E_SERVICE) == E_SERVICE)
+ {
+ sMsg.appendAscii("| E_SERVICE s=\"");
+ sMsg.appendAscii(pExpectedService );
+ sMsg.appendAscii("\"" );
+ }
+ sMsg.appendAscii("\tbut it was : " );
+ sMsg.append (aURL.impldbg_toString());
+ sMsg.appendAscii("\n" );
+ }
+
+ WRITE_LOGFILE(LOGFILE_JOBURL, U2B(sMsg.makeStringAndClear()))
+}
+
+//________________________________
+/**
+ @short helper debug method
+ @descr It returns a representation of the internal object state
+ as string notation.
+
+ @returns The formated string representation.
+*/
+::rtl::OUString JobURL::impldbg_toString() const
+{
+ /* SAFE { */
+ ReadGuard aReadLock(m_aLock);
+
+ ::rtl::OUStringBuffer sBuffer(256);
+
+ if (m_eRequest==E_UNKNOWN)
+ sBuffer.appendAscii("E_UNKNOWN");
+ if ((m_eRequest & E_EVENT) == E_EVENT)
+ sBuffer.appendAscii("| E_EVENT");
+ if ((m_eRequest & E_ALIAS) == E_ALIAS)
+ sBuffer.appendAscii("| E_ALIAS");
+ if ((m_eRequest & E_SERVICE) == E_SERVICE)
+ sBuffer.appendAscii("| E_SERVICE");
+ sBuffer.appendAscii("{ e=\"" );
+ sBuffer.append (m_sEvent );
+ sBuffer.appendAscii("\" - a=\"");
+ sBuffer.append (m_sAlias );
+ sBuffer.appendAscii("\" - s=\"");
+ sBuffer.append (m_sService );
+ sBuffer.appendAscii("\" }" );
+
+ aReadLock.unlock();
+ /* } SAFE */
+
+ return sBuffer.makeStringAndClear();
+}
+
+//________________________________
+
+sal_Bool JobURL::getServiceArgs( /*OUT*/ ::rtl::OUString& sServiceArgs ) const
+{
+ /* SAFE { */
+ ReadGuard aReadLock(m_aLock);
+
+ sServiceArgs = ::rtl::OUString();
+ sal_Bool bSet = ((m_eRequest & E_SERVICE) == E_SERVICE);
+ if (bSet)
+ sServiceArgs = m_sServiceArgs;
+
+ aReadLock.unlock();
+ /* } SAFE */
+
+ return bSet;
+}
+
+//________________________________
+
+sal_Bool JobURL::getEventArgs( /*OUT*/ ::rtl::OUString& sEventArgs ) const
+{
+ /* SAFE { */
+ ReadGuard aReadLock(m_aLock);
+
+ sEventArgs = ::rtl::OUString();
+ sal_Bool bSet = ((m_eRequest & E_EVENT) == E_EVENT);
+ if (bSet)
+ sEventArgs = m_sEventArgs;
+
+ aReadLock.unlock();
+ /* } SAFE */
+
+ return bSet;
+}
+
+//________________________________
+
+sal_Bool JobURL::getAliasArgs( /*OUT*/ ::rtl::OUString& sAliasArgs ) const
+{
+ /* SAFE { */
+ ReadGuard aReadLock(m_aLock);
+
+ sAliasArgs = ::rtl::OUString();
+ sal_Bool bSet = ((m_eRequest & E_ALIAS) == E_ALIAS);
+ if (bSet)
+ sAliasArgs = m_sAliasArgs;
+
+ aReadLock.unlock();
+ /* } SAFE */
+
+ return bSet;
+}
+
+#endif // ENABLE_COMPONENT_SELF_CHECK
+
+} // namespace framework
diff --git a/framework/source/jobs/makefile.mk b/framework/source/jobs/makefile.mk
new file mode 100644
index 000000000000..ee5cc637664a
--- /dev/null
+++ b/framework/source/jobs/makefile.mk
@@ -0,0 +1,53 @@
+#*************************************************************************
+#
+# 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.
+#
+#*************************************************************************
+PRJ=..$/..
+
+PRJNAME= framework
+TARGET= fwk_jobs
+ENABLE_EXCEPTIONS= TRUE
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+
+# --- Generate -----------------------------------------------------
+
+SLOFILES= $(SLO)$/jobexecutor.obj \
+ $(SLO)$/jobdispatch.obj \
+ $(SLO)$/job.obj \
+ $(SLO)$/jobdata.obj \
+ $(SLO)$/jobresult.obj \
+ $(SLO)$/joburl.obj \
+ $(SLO)$/jobconst.obj \
+ $(SLO)$/helponstartup.obj \
+ $(SLO)$/shelljob.obj \
+ $(SLO)$/configaccess.obj
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
diff --git a/framework/source/jobs/shelljob.cxx b/framework/source/jobs/shelljob.cxx
new file mode 100644
index 000000000000..b7b6d370bb40
--- /dev/null
+++ b/framework/source/jobs/shelljob.cxx
@@ -0,0 +1,214 @@
+/*************************************************************************
+ *
+ * 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"
+
+//_______________________________________________
+// include own header
+
+#include <jobs/shelljob.hxx>
+#include <jobs/jobconst.hxx>
+#include <threadhelp/readguard.hxx>
+#include <services.h>
+
+//_______________________________________________
+// include others
+
+#include <osl/file.hxx>
+#include <osl/process.h>
+#include <vcl/svapp.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+
+//_______________________________________________
+// include interfaces
+
+#include <com/sun/star/system/XSystemShellExecute.hpp>
+#include <com/sun/star/system/SystemShellExecuteFlags.hpp>
+#include <com/sun/star/util/XStringSubstitution.hpp>
+
+//_______________________________________________
+// namespace
+
+namespace framework{
+
+//_______________________________________________
+// definitions
+
+/** adress job configuration inside argument set provided on method execute(). */
+static const ::rtl::OUString PROP_JOBCONFIG = ::rtl::OUString::createFromAscii("JobConfig");
+
+/** adress job configuration property "Command". */
+static const ::rtl::OUString PROP_COMMAND = ::rtl::OUString::createFromAscii("Command");
+
+/** adress job configuration property "Arguments". */
+static const ::rtl::OUString PROP_ARGUMENTS = ::rtl::OUString::createFromAscii("Arguments");
+
+/** adress job configuration property "DeactivateJobIfDone". */
+static const ::rtl::OUString PROP_DEACTIVATEJOBIFDONE = ::rtl::OUString::createFromAscii("DeactivateJobIfDone");
+
+/** adress job configuration property "CheckExitCode". */
+static const ::rtl::OUString PROP_CHECKEXITCODE = ::rtl::OUString::createFromAscii("CheckExitCode");
+
+//-----------------------------------------------
+
+DEFINE_XSERVICEINFO_MULTISERVICE(ShellJob ,
+ ::cppu::OWeakObject ,
+ SERVICENAME_JOB ,
+ IMPLEMENTATIONNAME_SHELLJOB)
+
+DEFINE_INIT_SERVICE(ShellJob,
+ {
+ /* 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!
+ */
+ }
+ )
+
+//-----------------------------------------------
+ShellJob::ShellJob(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR)
+ : ThreadHelpBase( )
+ , m_xSMGR (xSMGR)
+{
+}
+
+//-----------------------------------------------
+ShellJob::~ShellJob()
+{
+}
+
+//-----------------------------------------------
+css::uno::Any SAL_CALL ShellJob::execute(const css::uno::Sequence< css::beans::NamedValue >& lJobArguments)
+ throw(css::lang::IllegalArgumentException,
+ css::uno::Exception ,
+ css::uno::RuntimeException )
+{
+ ::comphelper::SequenceAsHashMap lArgs (lJobArguments);
+ ::comphelper::SequenceAsHashMap lOwnCfg(lArgs.getUnpackedValueOrDefault(PROP_JOBCONFIG, css::uno::Sequence< css::beans::NamedValue >()));
+
+ const ::rtl::OUString sCommand = lOwnCfg.getUnpackedValueOrDefault(PROP_COMMAND , ::rtl::OUString());
+ const css::uno::Sequence< ::rtl::OUString > lCommandArguments = lOwnCfg.getUnpackedValueOrDefault(PROP_ARGUMENTS , css::uno::Sequence< ::rtl::OUString >());
+ const ::sal_Bool bDeactivateJobIfDone = lOwnCfg.getUnpackedValueOrDefault(PROP_DEACTIVATEJOBIFDONE , sal_True );
+ const ::sal_Bool bCheckExitCode = lOwnCfg.getUnpackedValueOrDefault(PROP_CHECKEXITCODE , sal_True );
+
+ // replace all might existing place holder.
+ ::rtl::OUString sRealCommand = impl_substituteCommandVariables(sCommand);
+
+ // Command is required as minimum.
+ // If it does not exists ... we cant do our job.
+ // Deactivate such miss configured job silently .-)
+ if (sRealCommand.getLength() < 1)
+ return ShellJob::impl_generateAnswer4Deactivation();
+
+ // do it
+ ::sal_Bool bDone = impl_execute(sRealCommand, lCommandArguments, bCheckExitCode);
+ if (! bDone)
+ return css::uno::Any();
+
+ // Job was done ... user configured deactivation of this job
+ // in such case.
+ if (bDeactivateJobIfDone)
+ return ShellJob::impl_generateAnswer4Deactivation();
+
+ // There was no decision about deactivation of this job.
+ // So we have to return nothing here !
+ return css::uno::Any();
+}
+
+//-----------------------------------------------
+css::uno::Any ShellJob::impl_generateAnswer4Deactivation()
+{
+ css::uno::Sequence< css::beans::NamedValue > aAnswer(1);
+ aAnswer[0].Name = JobConst::ANSWER_DEACTIVATE_JOB();
+ aAnswer[0].Value = css::uno::makeAny(sal_True);
+
+ return css::uno::makeAny(aAnswer);
+}
+
+//-----------------------------------------------
+::rtl::OUString ShellJob::impl_substituteCommandVariables(const ::rtl::OUString& sCommand)
+{
+ // SYNCHRONIZED ->
+ ReadGuard aReadLock(m_aLock);
+ css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
+ aReadLock.unlock();
+ // <- SYNCHRONIZED
+
+ try
+ {
+ css::uno::Reference< css::util::XStringSubstitution > xSubst ( xSMGR->createInstance(SERVICENAME_SUBSTITUTEPATHVARIABLES), css::uno::UNO_QUERY_THROW);
+ const ::sal_Bool bSubstRequired = sal_True;
+ const ::rtl::OUString sCompleteCommand = xSubst->substituteVariables(sCommand, bSubstRequired);
+
+ return sCompleteCommand;
+ }
+ catch(const css::uno::Exception&)
+ {}
+
+ return ::rtl::OUString();
+}
+
+//-----------------------------------------------
+::sal_Bool ShellJob::impl_execute(const ::rtl::OUString& sCommand ,
+ const css::uno::Sequence< ::rtl::OUString >& lArguments ,
+ ::sal_Bool bCheckExitCode)
+{
+ ::rtl_uString** pArgs = NULL;
+ const ::sal_Int32 nArgs = lArguments.getLength ();
+ oslProcessOption nOptions = osl_Process_WAIT;
+ oslProcess hProcess(0);
+
+ if (nArgs > 0)
+ pArgs = reinterpret_cast< ::rtl_uString** >(const_cast< ::rtl::OUString* >(lArguments.getConstArray()));
+
+ oslProcessError eError = osl_executeProcess(sCommand.pData, pArgs, nArgs, nOptions, NULL, NULL, NULL, 0, &hProcess);
+
+ // executable not found or couldnt be started
+ if (eError != osl_Process_E_None)
+ return sal_False;
+
+ ::sal_Bool bRet = sal_True;
+ if (bCheckExitCode)
+ {
+ // check its return codes ...
+ oslProcessInfo aInfo;
+ aInfo.Size = sizeof (oslProcessInfo);
+ eError = osl_getProcessInfo(hProcess, osl_Process_EXITCODE, &aInfo);
+
+ if (eError != osl_Process_E_None)
+ bRet = sal_False;
+ else
+ bRet = (aInfo.Code == 0);
+ }
+ osl_freeProcessHandle(hProcess);
+ return bRet;
+}
+
+} // namespace framework