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 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 */ 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 */ 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 */ 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 */ 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 immediately. 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 immediately. 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 */ 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 */ 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 really 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 address 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 */ 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 address 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 */ 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 address 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 */ 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 */ 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 */ 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