xref: /aoo41x/main/framework/source/jobs/job.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_framework.hxx"
30 
31 //________________________________
32 //	my own includes
33 #include <jobs/job.hxx>
34 #include <threadhelp/readguard.hxx>
35 #include <threadhelp/writeguard.hxx>
36 #include <general.h>
37 #include <services.h>
38 
39 //________________________________
40 //	interface includes
41 #include <com/sun/star/task/XJob.hpp>
42 #include <com/sun/star/task/XAsyncJob.hpp>
43 #include <com/sun/star/util/XCloseBroadcaster.hpp>
44 #include <com/sun/star/util/XCloseable.hpp>
45 #include <com/sun/star/lang/DisposedException.hpp>
46 
47 //________________________________
48 //	includes of other projects
49 #include <rtl/ustrbuf.hxx>
50 #include <vcl/svapp.hxx>
51 
52 //________________________________
53 //	namespace
54 
55 namespace framework{
56 
57 //________________________________
58 //	non exported const
59 
60 //________________________________
61 //	non exported definitions
62 
63 //________________________________
64 //	declarations
65 
66 DEFINE_XINTERFACE_4( Job                                             ,
67                      OWeakObject                                     ,
68                      DIRECT_INTERFACE(css::lang::XTypeProvider      ),
69                      DIRECT_INTERFACE(css::task::XJobListener       ),
70                      DIRECT_INTERFACE(css::frame::XTerminateListener),
71                      DIRECT_INTERFACE(css::util::XCloseListener     )
72                    )
73 
74 DEFINE_XTYPEPROVIDER_4( Job                           ,
75                         css::lang::XTypeProvider      ,
76                         css::task::XJobListener       ,
77                         css::frame::XTerminateListener,
78                         css::util::XCloseListener
79                       )
80 
81 //________________________________
82 /**
83     @short      standard ctor
84     @descr      It initialize this new instance. But it set some generic parameters here only.
85                 Specialized informations (e.g. the alias or service name ofthis job) will be set
86                 later using the method setJobData().
87 
88     @param      xSMGR
89                 reference to the uno service manager
90 
91     @param      xFrame
92                 reference to the frame, in which environment we run
93                 (May be null!)
94 */
95 Job::Job( /*IN*/ const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR  ,
96           /*IN*/ const css::uno::Reference< css::frame::XFrame >&              xFrame )
97     : ThreadHelpBase       (&Application::GetSolarMutex())
98     , ::cppu::OWeakObject  (                             )
99     , m_aJobCfg            (xSMGR                        )
100     , m_xSMGR              (xSMGR                        )
101     , m_xFrame             (xFrame                       )
102     , m_bListenOnDesktop   (sal_False                    )
103     , m_bListenOnFrame     (sal_False                    )
104     , m_bListenOnModel     (sal_False                    )
105     , m_bPendingCloseFrame (sal_False                    )
106     , m_bPendingCloseModel (sal_False                    )
107     , m_eRunState          (E_NEW                        )
108 {
109 }
110 
111 //________________________________
112 /**
113     @short      standard ctor
114     @descr      It initialize this new instance. But it set some generic parameters here only.
115                 Specialized informations (e.g. the alias or service name ofthis job) will be set
116                 later using the method setJobData().
117 
118     @param      xSMGR
119                 reference to the uno service manager
120 
121     @param      xModel
122                 reference to the model, in which environment we run
123                 (May be null!)
124 */
125 Job::Job( /*IN*/ const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR  ,
126           /*IN*/ const css::uno::Reference< css::frame::XModel >&              xModel )
127     : ThreadHelpBase       (&Application::GetSolarMutex())
128     , ::cppu::OWeakObject  (                             )
129     , m_aJobCfg            (xSMGR                        )
130     , m_xSMGR              (xSMGR                        )
131     , m_xModel             (xModel                       )
132     , m_bListenOnDesktop   (sal_False                    )
133     , m_bListenOnFrame     (sal_False                    )
134     , m_bListenOnModel     (sal_False                    )
135     , m_bPendingCloseFrame (sal_False                    )
136     , m_bPendingCloseModel (sal_False                    )
137     , m_eRunState          (E_NEW                        )
138 {
139 }
140 
141 //________________________________
142 /**
143     @short  superflous!
144     @descr  Releasing of memory and reference must be done inside die() call.
145             Otherwhise it's a bug.
146 */
147 Job::~Job()
148 {
149 }
150 
151 //________________________________
152 /**
153     @short  set (or delete) a listener for sending dispatch result events
154     @descr  Because this object is used in a wrapped mode ... the original listener
155             for such events can't be registered here directly. Because the
156             listener expect to get the original object given as source of the event.
157             That's why we get this source here too, to fake(!) it at sending time!
158 
159     @param  xListener
160                 the original listener for dispatch result events
161 
162     @param  xSourceFake
163                 our user, which got the registration request for this listener
164 */
165 void Job::setDispatchResultFake( /*IN*/ const css::uno::Reference< css::frame::XDispatchResultListener >& xListener   ,
166                                  /*IN*/ const css::uno::Reference< css::uno::XInterface >&                xSourceFake )
167 {
168     /* SAFE { */
169     WriteGuard aWriteLock(m_aLock);
170 
171     // reject dangerous calls
172     if (m_eRunState != E_NEW)
173     {
174         LOG_WARNING("Job::setJobData()", "job may still running or already finished")
175         return;
176     }
177 
178     m_xResultListener   = xListener  ;
179     m_xResultSourceFake = xSourceFake;
180     aWriteLock.unlock();
181     /* } SAFE */
182 }
183 
184 void Job::setJobData( const JobData& aData )
185 {
186     /* SAFE { */
187     WriteGuard aWriteLock(m_aLock);
188 
189     // reject dangerous calls
190     if (m_eRunState != E_NEW)
191     {
192         LOG_WARNING("Job::setJobData()", "job may still running or already finished")
193         return;
194     }
195 
196     m_aJobCfg = aData;
197     aWriteLock.unlock();
198     /* } SAFE */
199 }
200 
201 //________________________________
202 /**
203     @short  runs the job
204     @descr  It doesn't matter, if the job is an asynchronous or
205             synchronous one. This method returns only if it was finished
206             or cancelled.
207 
208     @param  lDynamicArgs
209                 optional arguments for job execution
210                 In case the represented job is a configured one (which uses static
211                 arguments too) all informations will be merged!
212 */
213 void Job::execute( /*IN*/ const css::uno::Sequence< css::beans::NamedValue >& lDynamicArgs )
214 {
215     /* SAFE { */
216     WriteGuard aWriteLock(m_aLock);
217 
218     // reject dangerous calls
219     if (m_eRunState != E_NEW)
220     {
221         LOG_WARNING("Job::execute()", "job may still running or already finished")
222         return;
223     }
224 
225     // create the environment and mark this job as running ...
226     m_eRunState = E_RUNNING;
227     impl_startListening();
228 
229     css::uno::Reference< css::task::XAsyncJob >  xAJob;
230     css::uno::Reference< css::task::XJob >       xSJob;
231     css::uno::Sequence< css::beans::NamedValue > lJobArgs = impl_generateJobArgs(lDynamicArgs);
232 
233     // It's neccessary to hold us self alive!
234     // Otherwhise we might die by ref count ...
235     css::uno::Reference< css::task::XJobListener > xThis(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY);
236 
237     try
238     {
239         // create the job
240         // We must check for the supported interface on demand!
241         // But we preferr the synchronous one ...
242         m_xJob = m_xSMGR->createInstance(m_aJobCfg.getService());
243         xSJob  = css::uno::Reference< css::task::XJob >(m_xJob, css::uno::UNO_QUERY);
244         if (!xSJob.is())
245             xAJob = css::uno::Reference< css::task::XAsyncJob >(m_xJob, css::uno::UNO_QUERY);
246 
247         // execute it asynchron
248         if (xAJob.is())
249         {
250             m_aAsyncWait.reset();
251             aWriteLock.unlock();
252             /* } SAFE */
253             xAJob->executeAsync(lJobArgs, xThis);
254             // wait for finishing this job - so this method
255             // does the same for synchronous and asynchronous jobs!
256             m_aAsyncWait.wait();
257             aWriteLock.lock();
258             /* SAFE { */
259             // Note: Result handling was already done inside the callback!
260         }
261         // execute it synchron
262         else if (xSJob.is())
263         {
264             aWriteLock.unlock();
265             /* } SAFE */
266             css::uno::Any aResult = xSJob->execute(lJobArgs);
267             aWriteLock.lock();
268             /* SAFE { */
269             impl_reactForJobResult(aResult);
270         }
271     }
272     #if OSL_DEBUG_LEVEL > 0
273     catch(const css::uno::Exception& ex)
274     {
275         ::rtl::OUStringBuffer sMsg(256);
276         sMsg.appendAscii("Got exception during job execution. Original Message was:\n\"");
277         sMsg.append     (ex.Message);
278         sMsg.appendAscii("\"");
279         LOG_WARNING("Job::execute()", U2B(sMsg.makeStringAndClear()).getStr())
280     }
281     #else
282     catch(const css::uno::Exception&)
283         {}
284     #endif
285 
286     // deinitialize the environment and mark this job as finished ...
287     // but don't overwrite any informations about STOPPED or might DISPOSED jobs!
288     impl_stopListening();
289     if (m_eRunState == E_RUNNING)
290         m_eRunState = E_STOPPED_OR_FINISHED;
291 
292     // If we got a close request from our frame or model ...
293     // but we disagreed wit that by throwing a veto exception...
294     // and got the ownership ...
295     // we have to close the resource frame or model now -
296     // and to disable ourself!
297     if (m_bPendingCloseFrame)
298     {
299         m_bPendingCloseFrame = sal_False;
300         css::uno::Reference< css::util::XCloseable > xClose(m_xFrame, css::uno::UNO_QUERY);
301         if (xClose.is())
302         {
303             try
304             {
305                 xClose->close(sal_True);
306             }
307             catch(const css::util::CloseVetoException&) {}
308         }
309     }
310 
311     if (m_bPendingCloseModel)
312     {
313         m_bPendingCloseModel = sal_False;
314         css::uno::Reference< css::util::XCloseable > xClose(m_xModel, css::uno::UNO_QUERY);
315         if (xClose.is())
316         {
317             try
318             {
319                 xClose->close(sal_True);
320             }
321             catch(const css::util::CloseVetoException&) {}
322         }
323     }
324 
325     aWriteLock.unlock();
326     /* SAFE { */
327 
328     // release this instance ...
329     die();
330 }
331 
332 //________________________________
333 /**
334     @short  kill this job
335     @descr  It doesn't matter if this request is called from inside or
336             from outside. We release our internal structures and stop
337             avary activity. After doing so - this instance will not be
338             useable any longer! Of course we try to handle further requests
339             carefully. May somehwere else hold a reference to us ...
340 */
341 void Job::die()
342 {
343     /* SAFE { */
344     WriteGuard aWriteLock(m_aLock);
345 
346     impl_stopListening();
347 
348     if (m_eRunState != E_DISPOSED)
349     {
350         try
351         {
352             css::uno::Reference< css::lang::XComponent > xDispose(m_xJob, css::uno::UNO_QUERY);
353             if (xDispose.is())
354             {
355                 xDispose->dispose();
356                 m_eRunState = E_DISPOSED;
357             }
358         }
359         catch(const css::lang::DisposedException&)
360         {
361             m_eRunState = E_DISPOSED;
362         }
363     }
364 
365     m_xJob               = css::uno::Reference< css::uno::XInterface >();
366     m_xFrame             = css::uno::Reference< css::frame::XFrame >();
367     m_xModel             = css::uno::Reference< css::frame::XModel >();
368     m_xDesktop           = css::uno::Reference< css::frame::XDesktop >();
369     m_xResultListener    = css::uno::Reference< css::frame::XDispatchResultListener >();
370     m_xResultSourceFake  = css::uno::Reference< css::uno::XInterface >();
371     m_bPendingCloseFrame = sal_False;
372     m_bPendingCloseModel = sal_False;
373 
374     aWriteLock.unlock();
375     /* SAFE { */
376 }
377 
378 //________________________________
379 /**
380     @short  generates list of arguments for job execute
381     @descr  There exist a set of informations, which can be needed by a job.
382                 a) it's static configuration data   (Equals for all jobs.    )
383                 b) it's specific configuration data (Different for every job.)
384                 c) some environment values          (e.g. the frame, for which this job was started)
385                 d) any other dynamic data           (e.g. parameters of a dispatch() request)
386             We collect all these informations and generate one list which include all others.
387 
388     @param  lDynamicArgs
389                 list of dynamic arguments (given by a corresponding dispatch() call)
390                 Can be empty too.
391 
392     @return A list which includes all mentioned sub lists.
393 */
394 css::uno::Sequence< css::beans::NamedValue > Job::impl_generateJobArgs( /*IN*/ const css::uno::Sequence< css::beans::NamedValue >& lDynamicArgs )
395 {
396     css::uno::Sequence< css::beans::NamedValue > lAllArgs;
397 
398     /* SAFE { */
399     ReadGuard aReadLock(m_aLock);
400 
401     // the real structure of the returned list depends from the environment of this job!
402     JobData::EMode eMode = m_aJobCfg.getMode();
403 
404     // Create list of environment variables. This list must be part of the
405     // returned structure everytimes ... but some of its members are opetional!
406     css::uno::Sequence< css::beans::NamedValue > lEnvArgs(1);
407     lEnvArgs[0].Name    = ::rtl::OUString::createFromAscii(JobData::PROP_ENVTYPE);
408     lEnvArgs[0].Value <<= m_aJobCfg.getEnvironmentDescriptor();
409 
410     if (m_xFrame.is())
411     {
412         sal_Int32 c = lEnvArgs.getLength();
413         lEnvArgs.realloc(c+1);
414         lEnvArgs[c].Name    = ::rtl::OUString::createFromAscii(JobData::PROP_FRAME);
415         lEnvArgs[c].Value <<= m_xFrame;
416     }
417     if (m_xModel.is())
418     {
419         sal_Int32 c = lEnvArgs.getLength();
420         lEnvArgs.realloc(c+1);
421         lEnvArgs[c].Name    = ::rtl::OUString::createFromAscii(JobData::PROP_MODEL);
422         lEnvArgs[c].Value <<= m_xModel;
423     }
424     if (eMode==JobData::E_EVENT)
425     {
426         sal_Int32 c = lEnvArgs.getLength();
427         lEnvArgs.realloc(c+1);
428         lEnvArgs[c].Name    = ::rtl::OUString::createFromAscii(JobData::PROP_EVENTNAME);
429         lEnvArgs[c].Value <<= m_aJobCfg.getEvent();
430     }
431 
432     // get the configuration data from the job data container ... if possible
433     // Means: if this job has any configuration data. Note: only realy
434     // filled lists will be set to the return structure at the end of this method.
435     css::uno::Sequence< css::beans::NamedValue > lConfigArgs   ;
436     css::uno::Sequence< css::beans::NamedValue > lJobConfigArgs;
437     if (eMode==JobData::E_ALIAS || eMode==JobData::E_EVENT)
438     {
439         lConfigArgs    = m_aJobCfg.getConfig();
440         lJobConfigArgs = m_aJobCfg.getJobConfig();
441     }
442 
443     aReadLock.unlock();
444     /* } SAFE */
445 
446     // Add all valid (not empty) lists to the return list
447     if (lConfigArgs.getLength()>0)
448     {
449         sal_Int32 nLength = lAllArgs.getLength();
450         lAllArgs.realloc(nLength+1);
451         lAllArgs[nLength].Name    = ::rtl::OUString::createFromAscii(JobData::PROPSET_CONFIG);
452         lAllArgs[nLength].Value <<= lConfigArgs;
453     }
454     if (lJobConfigArgs.getLength()>0)
455     {
456         sal_Int32 nLength = lAllArgs.getLength();
457         lAllArgs.realloc(nLength+1);
458         lAllArgs[nLength].Name    = ::rtl::OUString::createFromAscii(JobData::PROPSET_OWNCONFIG);
459         lAllArgs[nLength].Value <<= lJobConfigArgs;
460     }
461     if (lEnvArgs.getLength()>0)
462     {
463         sal_Int32 nLength = lAllArgs.getLength();
464         lAllArgs.realloc(nLength+1);
465         lAllArgs[nLength].Name    = ::rtl::OUString::createFromAscii(JobData::PROPSET_ENVIRONMENT);
466         lAllArgs[nLength].Value <<= lEnvArgs;
467     }
468     if (lDynamicArgs.getLength()>0)
469     {
470         sal_Int32 nLength = lAllArgs.getLength();
471         lAllArgs.realloc(nLength+1);
472         lAllArgs[nLength].Name    = ::rtl::OUString::createFromAscii(JobData::PROPSET_DYNAMICDATA);
473         lAllArgs[nLength].Value <<= lDynamicArgs;
474     }
475 
476     return lAllArgs;
477 }
478 
479 //________________________________
480 /**
481     @short  analyze the given job result and change the job configuration
482     @descr  Note: Some results can be handled only, if this job has a valid configuration!
483             For "not configured jobs" (means pure services) they can be ignored.
484             But these cases are handled by our JobData member. We can call it everytime.
485             It does the right things automaticly. E.g. if the job has no configuration ...
486             it does nothing during setJobConfig()!
487 
488     @param  aResult
489                 the job result for analyzing
490 */
491 void Job::impl_reactForJobResult( /*IN*/ const css::uno::Any& aResult )
492 {
493     /* SAFE { */
494     WriteGuard aWriteLock(m_aLock);
495 
496     // analyze the result set ...
497     JobResult aAnalyzedResult(aResult);
498 
499     // some of the following operations will be supported for different environments
500     // or different type of jobs only.
501     JobData::EEnvironment eEnvironment = m_aJobCfg.getEnvironment();
502 
503     // write back the job specific configuration data ...
504     // If the environment allow it and if this job has a configuration!
505     if (
506         (m_aJobCfg.hasConfig()                            ) &&
507         (aAnalyzedResult.existPart(JobResult::E_ARGUMENTS))
508        )
509     {
510         m_aJobCfg.setJobConfig(aAnalyzedResult.getArguments());
511     }
512 
513     // disable a job for further executions.
514     // Note: this option is available inside the environment EXECUTOR only
515     if (
516 //        (eEnvironment == JobData::E_EXECUTION              ) &&
517         (m_aJobCfg.hasConfig()                             ) &&
518         (aAnalyzedResult.existPart(JobResult::E_DEACTIVATE))
519        )
520     {
521         m_aJobCfg.disableJob();
522     }
523 
524     // notify any interested listener with the may given result state.
525     // Note: this option is available inside the environment DISPATCH only
526     if (
527         (eEnvironment == JobData::E_DISPATCH                   ) &&
528         (m_xResultListener.is()                                ) &&
529         (aAnalyzedResult.existPart(JobResult::E_DISPATCHRESULT))
530        )
531     {
532         m_aJobCfg.setResult(aAnalyzedResult);
533         // Attention: Because the listener expect that the original object send this event ...
534         // and we nor the job are the right ones ...
535         // our user has set itself before. So we can fake this source address!
536         css::frame::DispatchResultEvent aEvent        = aAnalyzedResult.getDispatchResult();
537                                         aEvent.Source = m_xResultSourceFake;
538         m_xResultListener->dispatchFinished(aEvent);
539     }
540 
541     aWriteLock.unlock();
542     /* SAFE { */
543 }
544 
545 //________________________________
546 /**
547     @short  starts listening for office shutdown and closing of our
548             given target frame (if its a valid reference)
549     @descr  We will reghister ourself as terminate listener
550             at the global desktop instance. That will hold us
551             alive and additional we get the information, if the
552             office whish to shutdown. If then an internal job
553             is running we will have the chance to supress that
554             by throwing a veto exception. If our internal wrapped
555             job finished his work, we can release this listener
556             connection.
557 
558             Further we are listener for closing of the (possible valid)
559             given frame. We must be shure, that this ressource won't be gone
560             if our internal job is still running.
561 */
562 void Job::impl_startListening()
563 {
564     /* SAFE { */
565     WriteGuard aWriteLock(m_aLock);
566 
567     // listening for office shutdown
568     if (!m_xDesktop.is() && !m_bListenOnDesktop)
569     {
570         try
571         {
572             m_xDesktop = css::uno::Reference< css::frame::XDesktop >(m_xSMGR->createInstance(SERVICENAME_DESKTOP), css::uno::UNO_QUERY);
573             css::uno::Reference< css::frame::XTerminateListener > xThis(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY);
574             if (m_xDesktop.is())
575             {
576                 m_xDesktop->addTerminateListener(xThis);
577                 m_bListenOnDesktop = sal_True;
578             }
579         }
580         catch(css::uno::Exception&)
581         {
582             m_xDesktop = css::uno::Reference< css::frame::XDesktop >();
583         }
584     }
585 
586     // listening for frame closing
587     if (m_xFrame.is() && !m_bListenOnFrame)
588     {
589         try
590         {
591             css::uno::Reference< css::util::XCloseBroadcaster > xCloseable(m_xFrame                                 , css::uno::UNO_QUERY);
592             css::uno::Reference< css::util::XCloseListener >    xThis     (static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY);
593             if (xCloseable.is())
594             {
595                 xCloseable->addCloseListener(xThis);
596                 m_bListenOnFrame = sal_True;
597             }
598         }
599         catch(css::uno::Exception&)
600         {
601             m_bListenOnFrame = sal_False;
602         }
603     }
604 
605     // listening for model closing
606     if (m_xModel.is() && !m_bListenOnModel)
607     {
608         try
609         {
610             css::uno::Reference< css::util::XCloseBroadcaster > xCloseable(m_xModel                                 , css::uno::UNO_QUERY);
611             css::uno::Reference< css::util::XCloseListener >    xThis     (static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY);
612             if (xCloseable.is())
613             {
614                 xCloseable->addCloseListener(xThis);
615                 m_bListenOnModel = sal_True;
616             }
617         }
618         catch(css::uno::Exception&)
619         {
620             m_bListenOnModel = sal_False;
621         }
622     }
623 
624     aWriteLock.unlock();
625     /* } SAFE */
626 }
627 
628 //________________________________
629 /**
630     @short  release listener connection for office shutdown
631     @descr  see description of impl_startListening()
632 */
633 void Job::impl_stopListening()
634 {
635     /* SAFE { */
636     WriteGuard aWriteLock(m_aLock);
637 
638     // stop listening for office shutdown
639     if (m_xDesktop.is() && m_bListenOnDesktop)
640     {
641         try
642         {
643             css::uno::Reference< css::frame::XTerminateListener > xThis(static_cast< ::cppu::OWeakObject* >(this)   , css::uno::UNO_QUERY);
644             m_xDesktop->removeTerminateListener(xThis);
645             m_xDesktop = css::uno::Reference< css::frame::XDesktop >();
646             m_bListenOnDesktop = sal_False;
647         }
648         catch(css::uno::Exception&)
649         {
650         }
651     }
652 
653     // stop listening for frame closing
654     if (m_xFrame.is() && m_bListenOnFrame)
655     {
656         try
657         {
658             css::uno::Reference< css::util::XCloseBroadcaster > xCloseable(m_xFrame                                 , css::uno::UNO_QUERY);
659             css::uno::Reference< css::util::XCloseListener >    xThis     (static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY);
660             if (xCloseable.is())
661             {
662                 xCloseable->removeCloseListener(xThis);
663                 m_bListenOnFrame = sal_False;
664             }
665         }
666         catch(css::uno::Exception&)
667         {
668         }
669     }
670 
671     // stop listening for model closing
672     if (m_xModel.is() && m_bListenOnModel)
673     {
674         try
675         {
676             css::uno::Reference< css::util::XCloseBroadcaster > xCloseable(m_xModel                                 , css::uno::UNO_QUERY);
677             css::uno::Reference< css::util::XCloseListener >    xThis     (static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY);
678             if (xCloseable.is())
679             {
680                 xCloseable->removeCloseListener(xThis);
681                 m_bListenOnModel = sal_False;
682             }
683         }
684         catch(css::uno::Exception&)
685         {
686         }
687     }
688 
689     aWriteLock.unlock();
690     /* } SAFE */
691 }
692 
693 //________________________________
694 /**
695     @short  callback from any asynchronous executed job
696 
697     @descr  Our execute() method waits for this callback.
698             We have to react for the possible results here,
699             to kill the running job and disable the blocked condition
700             so execute() can be finished too.
701 
702     @param  xJob
703                 the job, which was running and inform us now
704 
705     @param  aResult
706                 it's results
707 */
708 void SAL_CALL Job::jobFinished( /*IN*/ const css::uno::Reference< css::task::XAsyncJob >& xJob    ,
709                                 /*IN*/ const css::uno::Any&                               aResult ) throw(css::uno::RuntimeException)
710 {
711     /* SAFE { */
712     WriteGuard aWriteLock(m_aLock);
713 
714     // It's neccessary to check this.
715     // May this job was cancelled by any other reason
716     // some milliseconds before. :-)
717     if (m_xJob.is() && m_xJob==xJob)
718     {
719         // react for his results
720         // (means enable/disable it for further requests
721         // or save arguments or notify listener ...)
722         impl_reactForJobResult(aResult);
723 
724         // Let the job die!
725         m_xJob = css::uno::Reference< css::uno::XInterface >();
726     }
727 
728     // And let the start method "execute()" finishing it's job.
729     // But do it everytime. So any outside blocking code can finish
730     // his work too.
731     m_aAsyncWait.set();
732 
733     aWriteLock.unlock();
734     /* } SAFE */
735 }
736 
737 //________________________________
738 /**
739     @short  prevent internal wrapped job against office termination
740     @descr  This event is broadcasted by the desktop instance and ask for an office termination.
741             If the internal wrapped job is still in progress, we disagree with that by throwing the
742             right veto exception. If not - we agree. But then we must be aware, that another event
743             notifyTermination() can follow. Then we have no chance to do the same. Then we have to
744             accept that and stop our work instandly.
745 
746     @param  aEvent
747                 describes the broadcaster and must be the desktop instance
748 
749     @throw  TerminateVetoException
750                 if our internal wrapped job is still running.
751  */
752 void SAL_CALL Job::queryTermination( /*IN*/ const css::lang::EventObject& ) throw(css::frame::TerminationVetoException,
753                                                                                          css::uno::RuntimeException          )
754 {
755     /* SAFE { */
756     ReadGuard aReadLock(m_aLock);
757 
758     // don't disagree with this request if job was already stopped or finished it's work
759     // if (m_eRunState != E_RUNNING)
760     //    return;
761 
762     // Otherwhise try to close() it
763     css::uno::Reference< css::util::XCloseable > xClose(m_xJob, css::uno::UNO_QUERY);
764     if (xClose.is())
765     {
766         try
767         {
768             xClose->close(sal_False);
769             m_eRunState = E_STOPPED_OR_FINISHED;
770         }
771         catch(const css::util::CloseVetoException&) {}
772     }
773 
774     if (m_eRunState != E_STOPPED_OR_FINISHED)
775     {
776         css::uno::Reference< css::uno::XInterface > xThis(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY);
777         throw css::frame::TerminationVetoException(DECLARE_ASCII("job still in progress"), xThis);
778     }
779 
780     aReadLock.unlock();
781     /* } SAFE */
782 }
783 
784 
785 //________________________________
786 /**
787     @short  inform us about office termination
788     @descr  Instead of the method queryTermination(), here is no chance to disagree with that.
789             We have to accept it and cancel all current processes inside.
790             It can occure only, if job was not already started if queryTermination() was called here ..
791             Then we had not throwed a veto exception. But now we must agree with this situation and break
792             all our internal processes. Its not a good idea to mark this instance as non startable any longer
793             inside queryTermination() if no job was unning too. Because that would disable this job and may
794             the office does not realy shutdownm, because another listener has thrown the suitable exception.
795 
796     @param  aEvent
797                 describes the broadcaster and must be the desktop instance
798  */
799 void SAL_CALL Job::notifyTermination( /*IN*/ const css::lang::EventObject& ) throw(css::uno::RuntimeException)
800 {
801     die();
802     // Do nothing else here. Our internal ressources was released ...
803 }
804 
805 //________________________________
806 /**
807     @short  prevent internal wrapped job against frame closing
808     @descr  This event is broadcasted by the frame instance and ask for closing.
809             If the internal wrapped job is still in progress, we disagree with that by throwing the
810             right veto exception. If not - we agree. But then we must be aware, that another event
811             notifyClosing() can follow. Then we have no chance to do the same. Then we have to
812             accept that and stop our work instandly.
813 
814     @param  aEvent
815                 describes the broadcaster and must be the frame instance
816 
817     @param  bGetsOwnerShip
818                 If it's set to <sal_True> and we throw the right veto excepion, we have to close this frame later
819                 if our internal processes will be finished. If it's set to <FALSE/> we can ignore it.
820 
821     @throw  CloseVetoException
822                 if our internal wrapped job is still running.
823  */
824 void SAL_CALL Job::queryClosing( const css::lang::EventObject& aEvent         ,
825                                        sal_Bool                bGetsOwnership ) throw(css::util::CloseVetoException,
826                                                                                       css::uno::RuntimeException   )
827 {
828     /* SAFE { */
829     WriteGuard aWriteLock(m_aLock);
830 
831     // do nothing, if no internal job is still running ...
832     // The frame or model can be closed then successfully.
833     if (m_eRunState != E_RUNNING)
834         return;
835 
836     // try close() first at the job.
837     // The job can agree or disagree with this request.
838     css::uno::Reference< css::util::XCloseable > xClose(m_xJob, css::uno::UNO_QUERY);
839     if (xClose.is())
840     {
841         xClose->close(bGetsOwnership);
842         // Here we can say: "this job was stopped successfully". Because
843         // no veto exception was thrown!
844         m_eRunState = E_STOPPED_OR_FINISHED;
845         return;
846     }
847 
848     // try dispose() then
849     // Here the job has no chance for a veto.
850     // But we must be aware of an "already disposed exception"...
851     try
852     {
853         css::uno::Reference< css::lang::XComponent > xDispose(m_xJob, css::uno::UNO_QUERY);
854         if (xDispose.is())
855         {
856             xDispose->dispose();
857             m_eRunState = E_DISPOSED;
858         }
859     }
860     catch(const css::lang::DisposedException&)
861     {
862         // the job was already disposed by any other mechanism !?
863         // But it's not interesting for us. For us this job is stopped now.
864         m_eRunState = E_DISPOSED;
865     }
866 
867     if (m_eRunState != E_DISPOSED)
868     {
869         // analyze event source - to find out, which resource called queryClosing() at this
870         // job wrapper. We must bind a "pending close" request to this resource.
871         // Closing of the corresponding resource will be done if our internal job finish it's work.
872         m_bPendingCloseFrame = (m_xFrame.is() && aEvent.Source == m_xFrame);
873         m_bPendingCloseModel = (m_xModel.is() && aEvent.Source == m_xModel);
874 
875         // throw suitable veto exception - because the internal job could not be cancelled.
876         css::uno::Reference< css::uno::XInterface > xThis(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY);
877         throw css::util::CloseVetoException(DECLARE_ASCII("job still in progress"), xThis);
878     }
879 
880     // No veto ...
881     // But don't call die() here or free our internal member.
882     // This must be done inside notifyClosing() only. Otherwhise the
883     // might stopped job has no chance to return it's results or
884     // call us back. We must give him the chance to finish it's work successfully.
885 
886     aWriteLock.unlock();
887     /* } SAFE */
888 }
889 
890 //________________________________
891 /**
892     @short  inform us about frame closing
893     @descr  Instead of the method queryClosing(), here is no chance to disagree with that.
894             We have to accept it and cancel all current processes inside.
895 
896     @param  aEvent
897             describes the broadcaster and must be the frame or model instance we know
898  */
899 void SAL_CALL Job::notifyClosing( const css::lang::EventObject& ) throw(css::uno::RuntimeException)
900 {
901     die();
902     // Do nothing else here. Our internal ressources was released ...
903 }
904 
905 //________________________________
906 /**
907     @short      shouldn't be called normaly
908     @descr      But it doesn't matter, who called it. We have to kill our internal
909                 running processes hardly.
910 
911     @param      aEvent
912                 describe the broadcaster
913 */
914 void SAL_CALL Job::disposing( const css::lang::EventObject& aEvent ) throw(css::uno::RuntimeException)
915 {
916     /* SAFE { */
917     WriteGuard aWriteLock(m_aLock);
918 
919     if (m_xDesktop.is() && aEvent.Source == m_xDesktop)
920     {
921         m_xDesktop = css::uno::Reference< css::frame::XDesktop >();
922         m_bListenOnDesktop = sal_False;
923     }
924     else
925     if (m_xFrame.is() && aEvent.Source == m_xFrame)
926     {
927         m_xFrame = css::uno::Reference< css::frame::XFrame >();
928         m_bListenOnFrame = sal_False;
929     }
930     else
931     if (m_xModel.is() && aEvent.Source == m_xModel)
932     {
933         m_xModel = css::uno::Reference< css::frame::XModel >();
934         m_bListenOnModel = sal_False;
935     }
936 
937     aWriteLock.unlock();
938     /* } SAFE */
939 
940     die();
941     // Do nothing else here. Our internal ressources was released ...
942 }
943 
944 } // namespace framework
945