summaryrefslogtreecommitdiff
path: root/framework/source/jobs/job.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'framework/source/jobs/job.cxx')
-rw-r--r--framework/source/jobs/job.cxx944
1 files changed, 944 insertions, 0 deletions
diff --git a/framework/source/jobs/job.cxx b/framework/source/jobs/job.cxx
new file mode 100644
index 000000000000..e0f2fd063f5e
--- /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 <sal_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