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