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