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