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