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