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