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