001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software GmbH & Co. KG, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.publish; 029 030import org.opencms.db.CmsDbContext; 031import org.opencms.db.CmsDriverManager; 032import org.opencms.db.CmsPublishList; 033import org.opencms.db.CmsUserSettings; 034import org.opencms.db.I_CmsDbContextFactory; 035import org.opencms.file.CmsDataAccessException; 036import org.opencms.file.CmsObject; 037import org.opencms.file.CmsRequestContext; 038import org.opencms.file.CmsResource; 039import org.opencms.file.CmsUser; 040import org.opencms.lock.CmsLockType; 041import org.opencms.main.CmsEvent; 042import org.opencms.main.CmsException; 043import org.opencms.main.CmsInitException; 044import org.opencms.main.CmsLog; 045import org.opencms.main.I_CmsEventListener; 046import org.opencms.main.OpenCms; 047import org.opencms.monitor.CmsMemoryMonitor; 048import org.opencms.report.I_CmsReport; 049import org.opencms.security.CmsAuthentificationException; 050import org.opencms.security.CmsRole; 051import org.opencms.util.CmsUUID; 052 053import java.util.HashMap; 054import java.util.Iterator; 055import java.util.List; 056import java.util.Map; 057 058import org.apache.commons.logging.Log; 059 060/** 061 * This class is responsible for the publish process.<p> 062 * 063 * @since 6.5.5 064 */ 065public final class CmsPublishEngine { 066 067 /** The log object for this class. */ 068 private static final Log LOG = CmsLog.getLog(CmsPublishEngine.class); 069 070 /** The id of the admin user. */ 071 private CmsUUID m_adminUserId; 072 073 /** The current running publish job. */ 074 private CmsPublishThread m_currentPublishThread; 075 076 /** The runtime info factory used during publishing. */ 077 private final I_CmsDbContextFactory m_dbContextFactory; 078 079 /** The driver manager instance. */ 080 private CmsDriverManager m_driverManager; 081 082 /** The engine state. */ 083 private CmsPublishEngineState m_engineState; 084 085 /** The publish listeners. */ 086 private final CmsPublishListenerCollection m_listeners; 087 088 /** The publish history list with already published jobs. */ 089 private final CmsPublishHistory m_publishHistory; 090 091 /** The queue with still waiting publish job. */ 092 private final CmsPublishQueue m_publishQueue; 093 094 /** The amount of time the system will wait for a running publish job during shutdown. */ 095 private int m_publishQueueShutdowntime; 096 097 /** Is set during shutdown. */ 098 private boolean m_shuttingDown; 099 100 /** 101 * Default constructor.<p> 102 * 103 * @param dbContextFactory the initialized OpenCms runtime info factory 104 * 105 * @throws CmsInitException if the configured path to store the publish reports is not accessible 106 */ 107 public CmsPublishEngine(I_CmsDbContextFactory dbContextFactory) 108 throws CmsInitException { 109 110 if (OpenCms.getRunLevel() > OpenCms.RUNLEVEL_2_INITIALIZING) { 111 // OpenCms is already initialized 112 throw new CmsInitException( 113 org.opencms.main.Messages.get().container(org.opencms.main.Messages.ERR_ALREADY_INITIALIZED_0)); 114 } 115 if (dbContextFactory == null) { 116 throw new CmsInitException( 117 org.opencms.main.Messages.get().container(org.opencms.main.Messages.ERR_CRITICAL_NO_DB_CONTEXT_0)); 118 } 119 // initialize the db context factory 120 m_dbContextFactory = dbContextFactory; 121 // initialize publish queue 122 m_publishQueue = new CmsPublishQueue(this); 123 // initialize publish history 124 m_publishHistory = new CmsPublishHistory(this); 125 // initialize event handling 126 m_listeners = new CmsPublishListenerCollection(this); 127 // set engine state to normal processing 128 m_engineState = CmsPublishEngineState.ENGINE_STARTED; 129 if (CmsLog.INIT.isInfoEnabled()) { 130 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_PUBLISH_ENGINE_READY_0)); 131 } 132 } 133 134 /** 135 * Abandons the given publish thread.<p> 136 */ 137 public void abandonThread() { 138 139 if (!m_currentPublishThread.isAlive()) { 140 // thread is dead 141 if (LOG.isDebugEnabled()) { 142 LOG.debug(Messages.get().getBundle().key(Messages.LOG_PUBLISH_ENGINE_DEAD_JOB_0)); 143 } 144 } else { 145 // thread is not dead, and we suppose it hangs :( 146 if (LOG.isWarnEnabled()) { 147 LOG.warn( 148 Messages.get().getBundle().key( 149 Messages.LOG_THREADSTORE_PUBLISH_THREAD_INTERRUPT_2, 150 m_currentPublishThread.getName(), 151 m_currentPublishThread.getUUID())); 152 } 153 m_currentPublishThread.interrupt(); 154 } 155 // just throw it away 156 m_currentPublishThread = null; 157 // and try again 158 checkCurrentPublishJobThread(); 159 } 160 161 /** 162 * Controls the publish process.<p> 163 */ 164 public synchronized void checkCurrentPublishJobThread() { 165 166 // give the finishing publish thread enough time to clean up 167 try { 168 Thread.sleep(200); 169 } catch (InterruptedException e) { 170 // ignore 171 } 172 173 // create a publish thread only if engine is started 174 if (m_engineState != CmsPublishEngineState.ENGINE_STARTED) { 175 return; 176 } 177 178 if (LOG.isDebugEnabled()) { 179 LOG.debug(Messages.get().getBundle().key(Messages.LOG_PUBLISH_ENGINE_RUNNING_0)); 180 } 181 182 // check the driver manager 183 if ((m_driverManager == null) || (m_dbContextFactory == null)) { 184 LOG.error(Messages.get().getBundle().key(Messages.ERR_PUBLISH_ENGINE_NOT_INITIALIZED_0)); 185 // without these there is nothing we can do 186 return; 187 } 188 189 // there is no running publish job 190 if (m_currentPublishThread == null) { 191 // but something is waiting in the queue 192 if (!m_publishQueue.isEmpty()) { 193 // start the next waiting publish job 194 CmsPublishJobInfoBean publishJob = m_publishQueue.next(); 195 m_currentPublishThread = new CmsPublishThread(this, publishJob); 196 m_currentPublishThread.start(); 197 } else { 198 // nothing to do 199 if (LOG.isDebugEnabled()) { 200 LOG.debug(Messages.get().getBundle().key(Messages.LOG_PUBLISH_ENGINE_NO_RUNNING_JOB_0)); 201 } 202 } 203 return; 204 } 205 if (m_currentPublishThread.isAlive()) { 206 // normal running 207 // wait until it is finished 208 if (LOG.isDebugEnabled()) { 209 LOG.debug(Messages.get().getBundle().key(Messages.LOG_PUBLISH_ENGINE_WAITING_0)); 210 } 211 } else { 212 // clean up the dead thread 213 abandonThread(); 214 } 215 } 216 217 /** 218 * Enqueues a new publish job with the given information in publish queue.<p> 219 * 220 * All resources should already be locked.<p> 221 * 222 * If possible, the publish job starts immediately.<p> 223 * 224 * @param cms the cms context to publish for 225 * @param publishList the resources to publish 226 * @param report the report to write to 227 * 228 * @throws CmsException if something goes wrong while cloning the cms context 229 */ 230 public void enqueuePublishJob(CmsObject cms, CmsPublishList publishList, I_CmsReport report) throws CmsException { 231 232 // check the driver manager 233 if ((m_driverManager == null) || (m_dbContextFactory == null)) { 234 // the resources are unlocked in the driver manager 235 throw new CmsPublishException(Messages.get().container(Messages.ERR_PUBLISH_ENGINE_NOT_INITIALIZED_0)); 236 } 237 // prevent new jobs if the engine is disabled 238 if (m_shuttingDown || (!isEnabled() && !OpenCms.getRoleManager().hasRole(cms, CmsRole.ROOT_ADMIN))) { 239 // the resources are unlocked in the driver manager 240 throw new CmsPublishException(Messages.get().container(Messages.ERR_PUBLISH_ENGINE_DISABLED_0)); 241 } 242 243 // create the publish job 244 CmsPublishJobInfoBean publishJob = new CmsPublishJobInfoBean(cms, publishList, report); 245 try { 246 // enqueue it and 247 m_publishQueue.add(publishJob); 248 // notify all listeners 249 m_listeners.fireEnqueued(new CmsPublishJobBase(publishJob)); 250 } catch (Throwable t) { 251 // we really really need to catch everything here, or else the queue status is broken 252 if (m_publishQueue.contains(publishJob)) { 253 m_publishQueue.remove(publishJob); 254 } 255 // throw the exception again 256 throw new CmsException( 257 Messages.get().container(Messages.ERR_PUBLISH_ENGINE_QUEUE_1, publishJob.getPublishHistoryId()), 258 t); 259 } 260 // try to start the publish job immediately 261 checkCurrentPublishJobThread(); 262 } 263 264 /** 265 * Returns a publish job based on its publish history id.<p> 266 * 267 * The returned publish job may be an enqueued, running or finished publish job.<p> 268 * 269 * @param publishHistoryId the publish history id to search for 270 * 271 * @return the publish job with the given publish history id, or <code>null</code> 272 */ 273 public CmsPublishJobBase getJobByPublishHistoryId(CmsUUID publishHistoryId) { 274 275 // try current running job 276 if ((m_currentPublishThread != null) 277 && m_currentPublishThread.getPublishJob().getPublishHistoryId().equals(publishHistoryId)) { 278 return new CmsPublishJobRunning(m_currentPublishThread.getPublishJob()); 279 } 280 // try enqueued jobs 281 Iterator<CmsPublishJobEnqueued> itEnqueuedJobs = getPublishQueue().asList().iterator(); 282 while (itEnqueuedJobs.hasNext()) { 283 CmsPublishJobEnqueued enqueuedJob = itEnqueuedJobs.next(); 284 if (enqueuedJob.getPublishList().getPublishHistoryId().equals(publishHistoryId)) { 285 return enqueuedJob; 286 } 287 } 288 // try finished jobs 289 Iterator<CmsPublishJobFinished> itFinishedJobs = getPublishHistory().asList().iterator(); 290 while (itFinishedJobs.hasNext()) { 291 CmsPublishJobFinished finishedJob = itFinishedJobs.next(); 292 if (finishedJob.getPublishHistoryId().equals(publishHistoryId)) { 293 return finishedJob; 294 } 295 } 296 return null; 297 } 298 299 /** 300 * Sets the driver manager instance.<p> 301 * 302 * @param driverManager the driver manager instance 303 */ 304 public void setDriverManager(CmsDriverManager driverManager) { 305 306 m_driverManager = driverManager; 307 CmsDbContext dbc = m_dbContextFactory.getDbContext(); 308 try { 309 m_adminUserId = m_driverManager.readUser(dbc, OpenCms.getDefaultUsers().getUserAdmin()).getId(); 310 } catch (CmsException e) { 311 dbc.rollback(); 312 LOG.error(e.getLocalizedMessage(), e); 313 } finally { 314 dbc.clear(); 315 } 316 } 317 318 /** 319 * Shuts down all this static export manager.<p> 320 * 321 * NOTE: this method may or may NOT be called (i.e. kill -9 in the stop script), if a system is stopped.<p> 322 * 323 * This is required since there may still be a thread running when the system is being shut down.<p> 324 */ 325 public synchronized void shutDown() { 326 327 if (CmsLog.INIT.isInfoEnabled()) { 328 CmsLog.INIT.info( 329 org.opencms.main.Messages.get().getBundle().key( 330 org.opencms.main.Messages.INIT_SHUTDOWN_START_1, 331 this.getClass().getName())); 332 } 333 334 // prevent new publish jobs are accepted 335 m_shuttingDown = true; 336 337 // if a job is currently running, 338 // wait the specified amount of time, 339 // then write an abort message to the report 340 if (m_currentPublishThread != null) { 341 342 // if a shutdown time is defined, wait if a publish process is running 343 if (m_publishQueueShutdowntime > 0) { 344 synchronized (this) { 345 try { 346 Thread.sleep(m_publishQueueShutdowntime * 1000); 347 } catch (InterruptedException exc) { 348 // ignore 349 } 350 } 351 } 352 353 if (m_currentPublishThread != null) { 354 CmsPublishJobInfoBean publishJob = m_currentPublishThread.getPublishJob(); 355 try { 356 abortPublishJob(m_adminUserId, new CmsPublishJobEnqueued(publishJob), false); 357 } catch (CmsException e) { 358 if (LOG.isErrorEnabled()) { 359 LOG.error(e.getLocalizedMessage(), e); 360 } 361 } 362 } 363 } 364 365 // write the log 366 CmsDbContext dbc = getDbContext(null); 367 try { 368 m_driverManager.updateLog(dbc); 369 } catch (CmsDataAccessException e) { 370 if (LOG.isErrorEnabled()) { 371 LOG.error(e.getLocalizedMessage(), e); 372 } 373 } finally { 374 dbc.clear(); 375 } 376 377 if (CmsLog.INIT.isInfoEnabled()) { 378 CmsLog.INIT.info( 379 org.opencms.staticexport.Messages.get().getBundle().key( 380 org.opencms.staticexport.Messages.INIT_SHUTDOWN_1, 381 this.getClass().getName())); 382 } 383 } 384 385 /** 386 * Aborts the given publish job.<p> 387 * 388 * @param userId the id of user that wants to abort the given publish job 389 * @param publishJob the publish job to abort 390 * @param removeJob indicates if the job will be removed or added to history 391 * 392 * @throws CmsException if there is some problem during unlocking the resources 393 * @throws CmsPublishException if the publish job can not be aborted 394 */ 395 protected void abortPublishJob(CmsUUID userId, CmsPublishJobEnqueued publishJob, boolean removeJob) 396 throws CmsException, CmsPublishException { 397 398 // abort event should be raised before the job is removed implicitly 399 m_listeners.fireAbort(userId, publishJob); 400 401 if ((m_currentPublishThread == null) 402 || !publishJob.m_publishJob.equals(m_currentPublishThread.getPublishJob())) { 403 // engine is currently publishing another job or is not publishing 404 if (!m_publishQueue.abortPublishJob(publishJob.m_publishJob)) { 405 // job not found 406 throw new CmsPublishException( 407 Messages.get().container(Messages.ERR_PUBLISH_ENGINE_MISSING_PUBLISH_JOB_0)); 408 } 409 } else if (!m_shuttingDown) { 410 // engine is currently publishing the job to abort 411 m_currentPublishThread.abort(); 412 } else if (m_shuttingDown && (m_currentPublishThread != null)) { 413 // aborting the current job during shut down 414 I_CmsReport report = m_currentPublishThread.getReport(); 415 report.println(); 416 report.println(); 417 report.println( 418 Messages.get().container(Messages.RPT_PUBLISH_JOB_ABORT_SHUTDOWN_0), 419 I_CmsReport.FORMAT_ERROR); 420 report.println(); 421 } 422 423 // unlock all resources 424 if (publishJob.getPublishList() != null) { 425 unlockPublishList(publishJob.m_publishJob); 426 } 427 // keep job if requested 428 if (!removeJob) { 429 // set finish info 430 publishJob.m_publishJob.finish(); 431 getPublishHistory().add(publishJob.m_publishJob); 432 } else { 433 getPublishQueue().remove(publishJob.m_publishJob); 434 } 435 } 436 437 /** 438 * Adds a publish listener to listen on publish events.<p> 439 * 440 * @param listener the publish listener to add 441 */ 442 protected void addPublishListener(I_CmsPublishEventListener listener) { 443 444 m_listeners.add(listener); 445 } 446 447 /** 448 * Disables the publish engine, i.e. publish jobs are not accepted.<p> 449 */ 450 protected void disableEngine() { 451 452 m_engineState = CmsPublishEngineState.ENGINE_DISABLED; 453 } 454 455 /** 456 * Enables the publish engine, i.e. publish jobs are accepted.<p> 457 */ 458 protected void enableEngine() { 459 460 m_engineState = CmsPublishEngineState.ENGINE_STARTED; 461 // start publish job if jobs waiting 462 if ((m_currentPublishThread == null) && !m_publishQueue.isEmpty()) { 463 checkCurrentPublishJobThread(); 464 } 465 } 466 467 /** 468 * Returns the current running publish job.<p> 469 * 470 * @return the current running publish job 471 */ 472 protected CmsPublishThread getCurrentPublishJob() { 473 474 return m_currentPublishThread; 475 } 476 477 /** 478 * Returns the a new db context object.<p> 479 * 480 * @param ctx optional request context, can be <code>null</code> 481 * 482 * @return the a new db context object 483 */ 484 protected CmsDbContext getDbContext(CmsRequestContext ctx) { 485 486 return m_dbContextFactory.getDbContext(ctx); 487 } 488 489 /** 490 * Returns the driver manager instance.<p> 491 * 492 * @return the driver manager instance 493 */ 494 protected CmsDriverManager getDriverManager() { 495 496 return m_driverManager; 497 } 498 499 /** 500 * Returns the publish history list with already publish job.<p> 501 * 502 * @return the publish history list with already publish job 503 */ 504 protected CmsPublishHistory getPublishHistory() { 505 506 return m_publishHistory; 507 } 508 509 /** 510 * Returns the queue with still waiting publish job.<p> 511 * 512 * @return the queue with still waiting publish job 513 */ 514 protected CmsPublishQueue getPublishQueue() { 515 516 return m_publishQueue; 517 } 518 519 /** 520 * Returns the content of the publish report assigned to the given publish job.<p> 521 * 522 * @param publishJob the published job 523 * @return the content of the assigned publish report 524 * 525 * @throws CmsException if something goes wrong 526 */ 527 protected byte[] getReportContents(CmsPublishJobFinished publishJob) throws CmsException { 528 529 byte[] result = null; 530 CmsDbContext dbc = m_dbContextFactory.getDbContext(); 531 try { 532 result = m_driverManager.readPublishReportContents(dbc, publishJob.getPublishHistoryId()); 533 } catch (CmsException e) { 534 dbc.rollback(); 535 LOG.error(e.getLocalizedMessage(), e); 536 throw e; 537 } finally { 538 dbc.clear(); 539 } 540 return result; 541 } 542 543 /** 544 * Returns the user identified by the given id.<p> 545 * 546 * @param userId the id of the user to retrieve 547 * 548 * @return the user identified by the given id 549 */ 550 protected CmsUser getUser(CmsUUID userId) { 551 552 CmsDbContext dbc = m_dbContextFactory.getDbContext(); 553 try { 554 return m_driverManager.readUser(dbc, userId); 555 } catch (CmsException e) { 556 dbc.rollback(); 557 LOG.error(e.getLocalizedMessage(), e); 558 } finally { 559 dbc.clear(); 560 } 561 return null; 562 } 563 564 /** 565 * Initializes the publish engine.<p> 566 * 567 * @param adminCms the admin cms 568 * @param publishQueuePersistance flag if the queue is persisted 569 * @param publishQueueShutdowntime amount of time to wait for a publish job during shutdown 570 * 571 * @throws CmsException if something goes wrong 572 */ 573 protected void initialize(CmsObject adminCms, boolean publishQueuePersistance, int publishQueueShutdowntime) 574 throws CmsException { 575 576 // check the driver manager 577 if ((m_driverManager == null) || (m_dbContextFactory == null)) { 578 throw new CmsPublishException(Messages.get().container(Messages.ERR_PUBLISH_ENGINE_NOT_INITIALIZED_0)); 579 } 580 581 m_publishQueueShutdowntime = publishQueueShutdowntime; 582 583 // initially the engine is stopped, must be restartet after full system initialization 584 m_engineState = CmsPublishEngineState.ENGINE_STOPPED; 585 // read the publish history from the repository 586 m_publishHistory.initialize(); 587 // read the queue from the repository 588 m_publishQueue.initialize(adminCms, publishQueuePersistance); 589 } 590 591 /** 592 * Returns the working state, that is if no publish job 593 * is waiting to be processed and there is no current running 594 * publish job.<p> 595 * 596 * @return the working state 597 */ 598 protected boolean isRunning() { 599 600 return (((m_engineState == CmsPublishEngineState.ENGINE_STARTED) && !m_publishQueue.isEmpty()) 601 || (m_currentPublishThread != null)); 602 } 603 604 /** 605 * Sets publish locks of resources in a publish list.<p> 606 * 607 * @param publishJob the publish job 608 * @throws CmsException if something goes wrong 609 */ 610 protected void lockPublishList(CmsPublishJobInfoBean publishJob) throws CmsException { 611 612 CmsPublishList publishList = publishJob.getPublishList(); 613 // lock them 614 CmsDbContext dbc = getDbContext(publishJob.getCmsObject().getRequestContext()); 615 try { 616 Iterator<CmsResource> itResources = publishList.getAllResources().iterator(); 617 while (itResources.hasNext()) { 618 CmsResource resource = itResources.next(); 619 m_driverManager.lockResource(dbc, resource, CmsLockType.PUBLISH); 620 } 621 } catch (CmsException e) { 622 dbc.rollback(); 623 LOG.error(e.getLocalizedMessage(), e); 624 throw e; 625 } finally { 626 dbc.clear(); 627 } 628 } 629 630 /** 631 * Signalizes that the publish thread finishes.<p> 632 * 633 * @param publishJob the finished publish job 634 */ 635 protected void publishJobFinished(CmsPublishJobInfoBean publishJob) { 636 637 // in order to avoid not removable publish locks, unlock all assigned resources again 638 try { 639 unlockPublishList(publishJob); 640 } catch (Throwable t) { 641 // log failure, most likely a database problem 642 LOG.error(t.getLocalizedMessage(), t); 643 } 644 645 // trigger the old event mechanism 646 CmsDbContext dbc = m_dbContextFactory.getDbContext(publishJob.getCmsObject().getRequestContext()); 647 try { 648 // fire an event that a project has been published 649 Map<String, Object> eventData = new HashMap<String, Object>(); 650 eventData.put(I_CmsEventListener.KEY_REPORT, publishJob.getPublishReport()); 651 eventData.put( 652 I_CmsEventListener.KEY_PUBLISHID, 653 publishJob.getPublishList().getPublishHistoryId().toString()); 654 eventData.put(I_CmsEventListener.KEY_PROJECTID, dbc.currentProject().getUuid()); 655 eventData.put(I_CmsEventListener.KEY_DBCONTEXT, dbc); 656 CmsEvent afterPublishEvent = new CmsEvent(I_CmsEventListener.EVENT_PUBLISH_PROJECT, eventData); 657 OpenCms.fireCmsEvent(afterPublishEvent); 658 } catch (Throwable t) { 659 if (dbc != null) { 660 dbc.rollback(); 661 } 662 LOG.error(t.getLocalizedMessage(), t); 663 // catch every thing including runtime exceptions 664 publishJob.getPublishReport().println(t); 665 } finally { 666 if (dbc != null) { 667 try { 668 dbc.clear(); 669 } catch (Throwable t) { 670 // ignore 671 } 672 dbc = null; 673 } 674 } 675 try { 676 // fire the publish finish event 677 m_listeners.fireFinish(new CmsPublishJobRunning(publishJob)); 678 } catch (Throwable t) { 679 // log failure, most likely a database problem 680 LOG.error(t.getLocalizedMessage(), t); 681 } 682 try { 683 // finish the job 684 publishJob.finish(); 685 } catch (Throwable t) { 686 // log failure, most likely a database problem 687 LOG.error(t.getLocalizedMessage(), t); 688 } 689 try { 690 // put the publish job into the history list 691 m_publishHistory.add(publishJob); 692 } catch (Throwable t) { 693 // log failure, most likely a database problem 694 LOG.error(t.getLocalizedMessage(), t); 695 } 696 if (Thread.currentThread() == m_currentPublishThread) { 697 // wipe the dead thread, only if this thread has not been abandoned 698 m_currentPublishThread = null; 699 } 700 // clear the published resources cache 701 OpenCms.getMemoryMonitor().flushCache(CmsMemoryMonitor.CacheType.PUBLISHED_RESOURCES); 702 // try to start a new publish job 703 checkCurrentPublishJobThread(); 704 } 705 706 /** 707 * A publish job has been permanently removed from the history.<p> 708 * 709 * @param publishJob the removed publish job 710 */ 711 protected void publishJobRemoved(CmsPublishJobInfoBean publishJob) { 712 713 // a publish job has been removed 714 m_listeners.fireRemove(new CmsPublishJobFinished(publishJob)); 715 } 716 717 /** 718 * Signalizes that the publish thread starts.<p> 719 * 720 * @param publishJob the started publish job 721 */ 722 protected void publishJobStarted(CmsPublishJobInfoBean publishJob) { 723 724 // update the job 725 m_publishQueue.update(publishJob); 726 727 // fire the publish start event 728 m_listeners.fireStart(new CmsPublishJobEnqueued(publishJob)); 729 } 730 731 /** 732 * Removes the given publish listener.<p> 733 * 734 * @param listener the publish listener to remove 735 */ 736 protected void removePublishListener(I_CmsPublishEventListener listener) { 737 738 m_listeners.remove(listener); 739 } 740 741 /** 742 * Sends a message to the given user, if publish notification is enabled or an error is shown in the message.<p> 743 * 744 * @param toUserId the id of the user to send the message to 745 * @param message the message to send 746 * @param hasErrors flag to determine if the message to send shows an error 747 */ 748 protected void sendMessage(CmsUUID toUserId, String message, boolean hasErrors) { 749 750 CmsDbContext dbc = m_dbContextFactory.getDbContext(); 751 try { 752 CmsUser toUser = m_driverManager.readUser(dbc, toUserId); 753 CmsUserSettings settings = new CmsUserSettings(toUser); 754 if (settings.getShowPublishNotification() || hasErrors) { 755 // only show message if publish notification is enabled or the message shows an error 756 OpenCms.getSessionManager().sendBroadcast(null, message, toUser); 757 } 758 } catch (CmsException e) { 759 dbc.rollback(); 760 LOG.error(e.getLocalizedMessage(), e); 761 } finally { 762 dbc.clear(); 763 } 764 } 765 766 /** 767 * Starts the publish engine, i.e. publish jobs are accepted and processed.<p> 768 */ 769 protected void startEngine() { 770 771 if (m_engineState != CmsPublishEngineState.ENGINE_STARTED) { 772 m_engineState = CmsPublishEngineState.ENGINE_STARTED; 773 // start publish job if jobs waiting 774 if ((m_currentPublishThread == null) && !m_publishQueue.isEmpty()) { 775 checkCurrentPublishJobThread(); 776 } 777 } 778 } 779 780 /** 781 * Stops the publish engine, i.e. publish jobs are still accepted but not published.<p> 782 */ 783 protected void stopEngine() { 784 785 m_engineState = CmsPublishEngineState.ENGINE_STOPPED; 786 } 787 788 /** 789 * Removes all publish locks of resources in a publish list of a publish job.<p> 790 * 791 * @param publishJob the publish job 792 * @throws CmsException if something goes wrong 793 */ 794 protected void unlockPublishList(CmsPublishJobInfoBean publishJob) throws CmsException { 795 796 CmsPublishList publishList = publishJob.getPublishList(); 797 List<CmsResource> allResources = publishList.getAllResources(); 798 // unlock them 799 CmsDbContext dbc = getDbContext(publishJob.getCmsObject().getRequestContext()); 800 try { 801 Iterator<CmsResource> itResources = allResources.iterator(); 802 while (itResources.hasNext()) { 803 CmsResource resource = itResources.next(); 804 m_driverManager.unlockResource(dbc, resource, true, true); 805 } 806 } catch (CmsException e) { 807 dbc.rollback(); 808 LOG.error(e.getLocalizedMessage(), e); 809 throw e; 810 } finally { 811 dbc.clear(); 812 } 813 } 814 815 /** 816 * Returns <code>true</code> if the login manager allows login.<p> 817 * 818 * @return if enabled 819 */ 820 private boolean isEnabled() { 821 822 try { 823 if ((m_engineState == CmsPublishEngineState.ENGINE_STOPPED) 824 || (m_engineState == CmsPublishEngineState.ENGINE_STARTED)) { 825 OpenCms.getLoginManager().checkLoginAllowed(); 826 return true; 827 } else { 828 return false; 829 } 830 } catch (CmsAuthentificationException e) { 831 return false; 832 } 833 } 834}