1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_framework.hxx"
26
27 //________________________________
28 // my own includes
29 #include <jobs/jobdispatch.hxx>
30 #include <jobs/joburl.hxx>
31 #include <jobs/job.hxx>
32 #include <threadhelp/readguard.hxx>
33 #include <threadhelp/writeguard.hxx>
34 #include <threadhelp/resetableguard.hxx>
35 #include <classes/converter.hxx>
36 #include <general.h>
37 #include <services.h>
38
39 //________________________________
40 // interface includes
41 #include <com/sun/star/beans/XPropertySet.hpp>
42 #include <com/sun/star/frame/DispatchResultState.hpp>
43 #include <com/sun/star/frame/XModuleManager.hpp>
44
45 //________________________________
46 // includes of other projects
47 #include <rtl/ustrbuf.hxx>
48 #include <vcl/svapp.hxx>
49
50 //________________________________
51 // namespace
52
53 namespace framework{
54
55 //________________________________
56 // non exported const
57
58 //________________________________
59 // non exported definitions
60
61 //________________________________
62 // declarations
63
DEFINE_XINTERFACE_6(JobDispatch,OWeakObject,DIRECT_INTERFACE (css::lang::XTypeProvider),DIRECT_INTERFACE (css::frame::XDispatchProvider),DIRECT_INTERFACE (css::lang::XInitialization),DIRECT_INTERFACE (css::lang::XServiceInfo),DIRECT_INTERFACE (css::frame::XNotifyingDispatch),DIRECT_INTERFACE (css::frame::XDispatch))64 DEFINE_XINTERFACE_6( JobDispatch ,
65 OWeakObject ,
66 DIRECT_INTERFACE(css::lang::XTypeProvider ),
67 DIRECT_INTERFACE(css::frame::XDispatchProvider ),
68 DIRECT_INTERFACE(css::lang::XInitialization ),
69 DIRECT_INTERFACE(css::lang::XServiceInfo),
70 DIRECT_INTERFACE(css::frame::XNotifyingDispatch),
71 DIRECT_INTERFACE(css::frame::XDispatch )
72 )
73
74 DEFINE_XTYPEPROVIDER_6( JobDispatch ,
75 css::lang::XTypeProvider ,
76 css::frame::XDispatchProvider ,
77 css::frame::XNotifyingDispatch,
78 css::lang::XInitialization,
79 css::lang::XServiceInfo,
80 css::frame::XDispatch
81 )
82
83 DEFINE_XSERVICEINFO_MULTISERVICE( JobDispatch ,
84 ::cppu::OWeakObject ,
85 SERVICENAME_PROTOCOLHANDLER ,
86 IMPLEMENTATIONNAME_JOBDISPATCH
87 )
88
89 DEFINE_INIT_SERVICE( JobDispatch,
90 {
91 /*Attention
92 I think we don't need any mutex or lock here ... because we are called by our own static method impl_createInstance()
93 to create a new instance of this class by our own supported service factory.
94 see macro DEFINE_XSERVICEINFO_MULTISERVICE and "impl_initService()" for further informations!
95 */
96 }
97 )
98
99 //________________________________
100 /**
101 @short standard ctor
102 @descr It initialize this new instance.
103
104 @param xSMGR
105 reference to the uno service manager
106 */
107 JobDispatch::JobDispatch( /*IN*/ const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR )
108 : ThreadHelpBase(&Application::GetSolarMutex())
109 , OWeakObject ( )
110 , m_xSMGR (xSMGR )
111 {
112 }
113
114 //________________________________
115 /**
116 @short let this instance die
117 @descr We have to release all used ressources and free used memory.
118 */
~JobDispatch()119 JobDispatch::~JobDispatch()
120 {
121 // release all used ressources
122 m_xSMGR = css::uno::Reference< css::lang::XMultiServiceFactory >();
123 m_xFrame = css::uno::Reference< css::frame::XFrame >();
124 }
125
126 //________________________________
127 /**
128 @short implementation of XInitalization
129 @descr A protocol handler can provide this functionality, if it wish to get additional informations
130 about the context it runs. In this case the frame reference would be given by the outside code.
131
132 @param lArguments
133 the list of initialization arguments
134 First parameter should be the frame reference we need.
135 */
initialize(const css::uno::Sequence<css::uno::Any> & lArguments)136 void SAL_CALL JobDispatch::initialize( const css::uno::Sequence< css::uno::Any >& lArguments ) throw(css::uno::Exception ,
137 css::uno::RuntimeException)
138 {
139 /* SAFE { */
140 WriteGuard aWriteLock(m_aLock);
141
142 for (int a=0; a<lArguments.getLength(); ++a)
143 {
144 if (a==0)
145 {
146 lArguments[a] >>= m_xFrame;
147
148 css::uno::Reference< css::frame::XModuleManager > xModuleManager(
149 m_xSMGR->createInstance(
150 SERVICENAME_MODULEMANAGER ),
151 css::uno::UNO_QUERY_THROW );
152 try
153 {
154 m_sModuleIdentifier = xModuleManager->identify( m_xFrame );
155 }
156 catch( css::uno::Exception& )
157 {}
158 }
159 }
160
161 aWriteLock.unlock();
162 /* } SAFE */
163 }
164
165 //________________________________
166 /**
167 @short implementation of XDispatchProvider::queryDispatches()
168 @descr Every protocol handler will be asked for his agreement, if an URL was queried
169 for which this handler is registered. It's the chance for this handler to validate
170 the given URL and return a dispatch object (may be itself) or not.
171
172 @param aURL
173 the queried URL, which should be checked
174
175 @param sTargetFrameName
176 describes the target frame, in which context this handler will be used
177 Is mostly set to "", "_self", "_blank", "_default" or a non special one
178 using SELF/CREATE as search flags.
179
180 @param nSearchFlags
181 Can be SELF or CREATE only and are set only if sTargetFrameName isn't a special target
182 */
queryDispatch(const css::util::URL & aURL,const::rtl::OUString &,sal_Int32)183 css::uno::Reference< css::frame::XDispatch > SAL_CALL JobDispatch::queryDispatch( /*IN*/ const css::util::URL& aURL ,
184 /*IN*/ const ::rtl::OUString& /*sTargetFrameName*/ ,
185 /*IN*/ sal_Int32 /*nSearchFlags*/ ) throw(css::uno::RuntimeException)
186 {
187 css::uno::Reference< css::frame::XDispatch > xDispatch;
188
189 JobURL aAnalyzedURL(aURL.Complete);
190 if (aAnalyzedURL.isValid())
191 xDispatch = css::uno::Reference< css::frame::XDispatch >( static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY );
192
193 return xDispatch;
194 }
195
196 //________________________________
197 /**
198 @short implementation of XDispatchProvider::queryDispatches()
199 @descr It's an optimized access for remote, so you can ask for
200 multiple dispatch objects at the same time.
201
202 @param lDescriptor
203 a list of queryDispatch() parameter
204
205 @return A list of corresponding dispatch objects.
206 NULL references are not skipped. Every result
207 match to one given descriptor item.
208 */
queryDispatches(const css::uno::Sequence<css::frame::DispatchDescriptor> & lDescriptor)209 css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL JobDispatch::queryDispatches( const css::uno::Sequence< css::frame::DispatchDescriptor >& lDescriptor ) throw(css::uno::RuntimeException)
210 {
211 // don't pack resulting list!
212 sal_Int32 nCount = lDescriptor.getLength();
213 css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > lDispatches(nCount);
214
215 for (sal_Int32 i=0; i<nCount; ++i)
216 lDispatches[i] = queryDispatch( lDescriptor[i].FeatureURL ,
217 lDescriptor[i].FrameName ,
218 lDescriptor[i].SearchFlags );
219 return lDispatches;
220 }
221
222 //________________________________
223 /**
224 @short implementation of XNotifyingDispatch::dispatchWithNotification()
225 @descr It creates the job service implementation and call execute on it.
226 Further it starts the life time control of it. (important for async job)
227 For synchonrous job we react for the returned result directly ... for asynchronous
228 ones we do it later inside our callback method. But we use the same impl method
229 doing that to share the code. (see impl_finishJob())
230
231 If a job is already running, (it can only occure for asynchronous jobs)
232 don't start the same job a second time. Queue in the given dispatch parameter
233 and return immediatly. If the current running job call us back, we will start this
234 new dispatch request.
235 If no job is running - queue the parameter too! But then start the new job immediatly.
236 We have to queue it every time - because it hold us alive by ref count!
237
238 @param aURL
239 describe the job(s), which should be started
240
241 @param lArgs
242 optional arguments for this request
243
244 @param xListener
245 an interested listener for possible results of this operation
246 */
dispatchWithNotification(const css::util::URL & aURL,const css::uno::Sequence<css::beans::PropertyValue> & lArgs,const css::uno::Reference<css::frame::XDispatchResultListener> & xListener)247 void SAL_CALL JobDispatch::dispatchWithNotification( /*IN*/ const css::util::URL& aURL ,
248 /*IN*/ const css::uno::Sequence< css::beans::PropertyValue >& lArgs ,
249 /*IN*/ const css::uno::Reference< css::frame::XDispatchResultListener >& xListener ) throw(css::uno::RuntimeException)
250 {
251 JobURL aAnalyzedURL(aURL.Complete);
252 if (aAnalyzedURL.isValid())
253 {
254 ::rtl::OUString sRequest;
255 if (aAnalyzedURL.getEvent(sRequest))
256 impl_dispatchEvent(sRequest, lArgs, xListener);
257 else
258 if (aAnalyzedURL.getService(sRequest))
259 impl_dispatchService(sRequest, lArgs, xListener);
260 else
261 if (aAnalyzedURL.getAlias(sRequest))
262 impl_dispatchAlias(sRequest, lArgs, xListener);
263 }
264 }
265
266 //________________________________
267 /**
268 @short dispatch an event
269 @descr We search all registered jobs for this event and execute it.
270 After doing so, we inform the given listener about the results.
271 (There will be one notify for every executed job!)
272
273 @param sEvent
274 the event, for which jobs can be registered
275
276 @param lArgs
277 optional arguments for this request
278 Currently not used!
279
280 @param xListener
281 an interested listener for possible results of this operation
282 */
impl_dispatchEvent(const::rtl::OUString & sEvent,const css::uno::Sequence<css::beans::PropertyValue> & lArgs,const css::uno::Reference<css::frame::XDispatchResultListener> & xListener)283 void JobDispatch::impl_dispatchEvent( /*IN*/ const ::rtl::OUString& sEvent ,
284 /*IN*/ const css::uno::Sequence< css::beans::PropertyValue >& lArgs ,
285 /*IN*/ const css::uno::Reference< css::frame::XDispatchResultListener >& xListener )
286 {
287 // get list of all enabled jobs
288 // The called static helper methods read it from the configuration and
289 // filter disabled jobs using it's time stamp values.
290 /* SAFE { */
291 ReadGuard aReadLock(m_aLock);
292 css::uno::Sequence< ::rtl::OUString > lJobs = JobData::getEnabledJobsForEvent(m_xSMGR, sEvent);
293 aReadLock.unlock();
294 /* } SAFE */
295
296 css::uno::Reference< css::frame::XDispatchResultListener > xThis( static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY );
297
298 // no jobs ... no execution
299 // But a may given listener will know something ...
300 // I think this operaton was finished successfully.
301 // It's not realy an error, if no registered jobs could be located.
302 // Step over all found jobs and execute it
303 int nExecutedJobs=0;
304 for (int j=0; j<lJobs.getLength(); ++j)
305 {
306 /* SAFE { */
307 aReadLock.lock();
308
309 JobData aCfg(m_xSMGR);
310 aCfg.setEvent(sEvent, lJobs[j]);
311 aCfg.setEnvironment(JobData::E_DISPATCH);
312 const bool bIsEnabled=aCfg.hasCorrectContext(m_sModuleIdentifier);
313
314 /*Attention!
315 Jobs implements interfaces and dies by ref count!
316 And freeing of such uno object is done by uno itself.
317 So we have to use dynamic memory everytimes.
318 */
319 Job* pJob = new Job(m_xSMGR, m_xFrame);
320 css::uno::Reference< css::uno::XInterface > xJob(static_cast< ::cppu::OWeakObject* >(pJob), css::uno::UNO_QUERY);
321 pJob->setJobData(aCfg);
322
323 aReadLock.unlock();
324 /* } SAFE */
325
326 if (!bIsEnabled)
327 continue;
328
329 // Special mode for listener.
330 // We dont notify it directly here. We delegate that
331 // to the job implementation. But we must set ourself there too.
332 // Because this job must fake the source adress of the event.
333 // Otherwhise the listener may will ignore it.
334 if (xListener.is())
335 pJob->setDispatchResultFake(xListener, xThis);
336 pJob->execute(Converter::convert_seqPropVal2seqNamedVal(lArgs));
337 ++nExecutedJobs;
338 }
339
340 if (nExecutedJobs<1 && xListener.is())
341 {
342 css::frame::DispatchResultEvent aEvent;
343 aEvent.Source = xThis;
344 aEvent.State = css::frame::DispatchResultState::SUCCESS;
345 xListener->dispatchFinished(aEvent);
346 }
347 }
348
349 //________________________________
350 /**
351 @short dispatch a service
352 @descr We use the given name only to create and if possible to initialize
353 it as an uno service. It can be usefully for creating (caching?)
354 of e.g. one instance services.
355
356 @param sService
357 the uno implementation or service name of the job, which should be instanciated
358
359 @param lArgs
360 optional arguments for this request
361 Currently not used!
362
363 @param xListener
364 an interested listener for possible results of this operation
365 */
impl_dispatchService(const::rtl::OUString & sService,const css::uno::Sequence<css::beans::PropertyValue> & lArgs,const css::uno::Reference<css::frame::XDispatchResultListener> & xListener)366 void JobDispatch::impl_dispatchService( /*IN*/ const ::rtl::OUString& sService ,
367 /*IN*/ const css::uno::Sequence< css::beans::PropertyValue >& lArgs ,
368 /*IN*/ const css::uno::Reference< css::frame::XDispatchResultListener >& xListener )
369 {
370 /* SAFE { */
371 ReadGuard aReadLock(m_aLock);
372
373 JobData aCfg(m_xSMGR);
374 aCfg.setService(sService);
375 aCfg.setEnvironment(JobData::E_DISPATCH);
376
377 /*Attention!
378 Jobs implements interfaces and dies by ref count!
379 And freeing of such uno object is done by uno itself.
380 So we have to use dynamic memory everytimes.
381 */
382 Job* pJob = new Job(m_xSMGR, m_xFrame);
383 css::uno::Reference< css::uno::XInterface > xJob(static_cast< ::cppu::OWeakObject* >(pJob), css::uno::UNO_QUERY);
384 pJob->setJobData(aCfg);
385
386 aReadLock.unlock();
387 /* } SAFE */
388
389 css::uno::Reference< css::frame::XDispatchResultListener > xThis( static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY );
390
391 // Special mode for listener.
392 // We dont notify it directly here. We delegate that
393 // to the job implementation. But we must set ourself there too.
394 // Because this job must fake the source adress of the event.
395 // Otherwhise the listener may will ignore it.
396 if (xListener.is())
397 pJob->setDispatchResultFake(xListener, xThis);
398 pJob->execute(Converter::convert_seqPropVal2seqNamedVal(lArgs));
399 }
400
401 //________________________________
402 /**
403 @short dispatch an alias
404 @descr We use this alias to locate a job inside the configuration
405 and execute it. Further we inform the given listener about the results.
406
407 @param sAlias
408 the alias name of the configured job
409
410 @param lArgs
411 optional arguments for this request
412 Currently not used!
413
414 @param xListener
415 an interested listener for possible results of this operation
416 */
impl_dispatchAlias(const::rtl::OUString & sAlias,const css::uno::Sequence<css::beans::PropertyValue> & lArgs,const css::uno::Reference<css::frame::XDispatchResultListener> & xListener)417 void JobDispatch::impl_dispatchAlias( /*IN*/ const ::rtl::OUString& sAlias ,
418 /*IN*/ const css::uno::Sequence< css::beans::PropertyValue >& lArgs ,
419 /*IN*/ const css::uno::Reference< css::frame::XDispatchResultListener >& xListener )
420 {
421 /* SAFE { */
422 ReadGuard aReadLock(m_aLock);
423
424 JobData aCfg(m_xSMGR);
425 aCfg.setAlias(sAlias);
426 aCfg.setEnvironment(JobData::E_DISPATCH);
427
428 /*Attention!
429 Jobs implements interfaces and dies by ref count!
430 And freeing of such uno object is done by uno itself.
431 So we have to use dynamic memory everytimes.
432 */
433 Job* pJob = new Job(m_xSMGR, m_xFrame);
434 css::uno::Reference< css::uno::XInterface > xJob(static_cast< ::cppu::OWeakObject* >(pJob), css::uno::UNO_QUERY);
435 pJob->setJobData(aCfg);
436
437 aReadLock.unlock();
438 /* } SAFE */
439
440 css::uno::Reference< css::frame::XDispatchResultListener > xThis( static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY );
441
442 // Special mode for listener.
443 // We dont notify it directly here. We delegate that
444 // to the job implementation. But we must set ourself there too.
445 // Because this job must fake the source adress of the event.
446 // Otherwhise the listener may will ignore it.
447 if (xListener.is())
448 pJob->setDispatchResultFake(xListener, xThis);
449 pJob->execute(Converter::convert_seqPropVal2seqNamedVal(lArgs));
450 }
451
452 //________________________________
453 /**
454 @short implementation of XDispatch::dispatch()
455 @descr Because the methods dispatch() and dispatchWithNotification() are different in her parameters
456 only, we can forward this request to dispatchWithNotification() by using an empty listener!
457
458 @param aURL
459 describe the job(s), which should be started
460
461 @param lArgs
462 optional arguments for this request
463
464 @see dispatchWithNotification()
465 */
dispatch(const css::util::URL & aURL,const css::uno::Sequence<css::beans::PropertyValue> & lArgs)466 void SAL_CALL JobDispatch::dispatch( /*IN*/ const css::util::URL& aURL ,
467 /*IN*/ const css::uno::Sequence< css::beans::PropertyValue >& lArgs ) throw(css::uno::RuntimeException)
468 {
469 dispatchWithNotification(aURL, lArgs, css::uno::Reference< css::frame::XDispatchResultListener >());
470 }
471
472 //________________________________
473 /**
474 @short not supported
475 */
addStatusListener(const css::uno::Reference<css::frame::XStatusListener> &,const css::util::URL &)476 void SAL_CALL JobDispatch::addStatusListener( /*IN*/ const css::uno::Reference< css::frame::XStatusListener >&,
477 /*IN*/ const css::util::URL& ) throw(css::uno::RuntimeException)
478 {
479 }
480
481 //________________________________
482 /**
483 @short not supported
484 */
removeStatusListener(const css::uno::Reference<css::frame::XStatusListener> &,const css::util::URL &)485 void SAL_CALL JobDispatch::removeStatusListener( /*IN*/ const css::uno::Reference< css::frame::XStatusListener >&,
486 /*IN*/ const css::util::URL& ) throw(css::uno::RuntimeException)
487 {
488 }
489
490 } // namespace framework
491