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