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