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