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