001: /*
002: * File : $Source: /usr/local/cvs/opencms/src/org/opencms/publish/CmsPublishManager.java,v $
003: * Date : $Date: 2008-02-27 12:05:27 $
004: * Version: $Revision: 1.7 $
005: *
006: * This library is part of OpenCms -
007: * the Open Source Content Management System
008: *
009: * Copyright (c) 2002 - 2008 Alkacon Software GmbH (http://www.alkacon.com)
010: *
011: * This library is free software; you can redistribute it and/or
012: * modify it under the terms of the GNU Lesser General Public
013: * License as published by the Free Software Foundation; either
014: * version 2.1 of the License, or (at your option) any later version.
015: *
016: * This library is distributed in the hope that it will be useful,
017: * but WITHOUT ANY WARRANTY; without even the implied warranty of
018: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
019: * Lesser General Public License for more details.
020: *
021: * For further information about Alkacon Software GmbH, please see the
022: * company website: http://www.alkacon.com
023: *
024: * For further information about OpenCms, please see the
025: * project website: http://www.opencms.org
026: *
027: * You should have received a copy of the GNU Lesser General Public
028: * License along with this library; if not, write to the Free Software
029: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
030: */
031:
032: package org.opencms.publish;
033:
034: import org.opencms.db.CmsPublishList;
035: import org.opencms.db.CmsSecurityManager;
036: import org.opencms.file.CmsObject;
037: import org.opencms.file.CmsResource;
038: import org.opencms.file.CmsResourceFilter;
039: import org.opencms.file.CmsUser;
040: import org.opencms.main.CmsException;
041: import org.opencms.main.CmsRuntimeException;
042: import org.opencms.main.OpenCms;
043: import org.opencms.relations.CmsRelationFilter;
044: import org.opencms.report.CmsShellReport;
045: import org.opencms.report.I_CmsReport;
046: import org.opencms.security.CmsRole;
047: import org.opencms.security.CmsSecurityException;
048: import org.opencms.util.CmsUUID;
049:
050: import java.util.ArrayList;
051: import java.util.Iterator;
052: import java.util.List;
053: import java.util.Map;
054:
055: /**
056: * This manager provide access to the publish engine runtime information.<p>
057: *
058: * @author Michael Moossen
059: *
060: * @version $Revision: 1.7 $
061: *
062: * @since 6.5.5
063: */
064: public class CmsPublishManager {
065:
066: /** The default history size. */
067: public static final int DEFAULT_HISTORY_SIZE = 100;
068:
069: /** The default persistance setting for the publish queue. */
070: public static final boolean DEFAULT_QUEUE_PERSISTANCE = false;
071:
072: /** The default shutdown time for the running publish job. */
073: public static final int DEFAULT_QUEUE_SHUTDOWNTIME = 1;
074:
075: /** Milliseconds in a second. */
076: private static final int MS_ONE_SECOND = 1000;
077:
078: /** Indicates if the configuration can be modified. */
079: private boolean m_frozen;
080:
081: /** The underlying publish engine. */
082: private CmsPublishEngine m_publishEngine;
083:
084: /** The maximum size of the publish history. */
085: private int m_publishHistorySize;
086:
087: /** Indicates if the publish queue is re-initialized on statup. */
088: private boolean m_publishQueuePersistance;
089:
090: /** The amount of time to wait for a publish job during shutdown. */
091: private int m_publishQueueShutdowntime;
092:
093: /** The security manager. */
094: private CmsSecurityManager m_securityManager;
095:
096: /**
097: * Default constructor used in digester initialization.<p>
098: */
099: public CmsPublishManager() {
100:
101: m_publishEngine = null;
102: m_frozen = false;
103: }
104:
105: /**
106: * Constructor used to create a pre-initialized instance.<p>
107: *
108: * @param historySize the size of the publish history
109: * @param queuePersistance indicates if the queue is re-initialized on startup
110: * @param queueShutdowntime the amount of time to wait for a publish job during shutdown
111: */
112: public CmsPublishManager(int historySize, boolean queuePersistance,
113: int queueShutdowntime) {
114:
115: m_publishEngine = null;
116: m_publishHistorySize = historySize;
117: m_publishQueuePersistance = queuePersistance;
118: m_publishQueueShutdowntime = queueShutdowntime;
119: m_frozen = false;
120: }
121:
122: /**
123: * Aborts the given publish job.<p>
124: *
125: * @param cms the cms context
126: * @param publishJob the publish job to abort
127: * @param removeJob indicates if the job will be removed or added to history
128: *
129: * @throws CmsException if there is some problem during unlocking the resources
130: * @throws CmsSecurityException if the current user has not enough permissions
131: * @throws CmsPublishException if the publish job can not been aborted
132: */
133: public void abortPublishJob(CmsObject cms,
134: CmsPublishJobEnqueued publishJob, boolean removeJob)
135: throws CmsException, CmsSecurityException,
136: CmsPublishException {
137:
138: if (!OpenCms.getRoleManager().hasRole(cms,
139: CmsRole.PROJECT_MANAGER)
140: && !cms.getRequestContext().currentUser().getId()
141: .equals(publishJob.getUserId())) {
142: // Can only be executed by somebody with the role CmsRole#PROJECT_MANAGER or the owner of the job
143: throw new CmsSecurityException(Messages.get().container(
144: Messages.ERR_PUBLISH_ENGINE_ABORT_DENIED_1,
145: cms.getRequestContext().currentUser().getName()));
146: }
147: m_publishEngine.abortPublishJob(cms.getRequestContext()
148: .currentUser().getId(), publishJob, removeJob);
149: }
150:
151: /**
152: * Adds a publish listener to listen on publish events.<p>
153: *
154: * @param listener the publish listener to add
155: */
156: public void addPublishListener(I_CmsPublishEventListener listener) {
157:
158: m_publishEngine.addPublishListener(listener);
159: }
160:
161: /**
162: * Check if the thread for the current publish job is stil active or was interrupted
163: * and so the next job in the queue can be started.<p>
164: */
165: public void checkCurrentPublishJobThread() {
166:
167: m_publishEngine.run();
168: }
169:
170: /**
171: * Disables the publishing of resources.<p>
172: */
173: public void disablePublishing() {
174:
175: m_publishEngine.disableEngine();
176: }
177:
178: /**
179: * Enables the enqeueing of resources for publishing.<p>
180: */
181: public void enablePublishing() {
182:
183: m_publishEngine.enableEngine();
184: }
185:
186: /**
187: * Returns the current running publish job.<p>
188: *
189: * @return the current running publish job
190: */
191: public CmsPublishJobRunning getCurrentPublishJob() {
192:
193: if (m_publishEngine.getCurrentPublishJob() == null) {
194: return null;
195: }
196: return new CmsPublishJobRunning(m_publishEngine
197: .getCurrentPublishJob().getPublishJob());
198: }
199:
200: /**
201: * Returns a publish job based on its publish history id.<p>
202: *
203: * The returned publish job may be an enqueued, running or finished publish job.<p>
204: *
205: * @param publishHistoryId the publish hostory id to search for
206: *
207: * @return the publish job with the given publish history id, or <code>null</code>
208: */
209: public CmsPublishJobBase getJobByPublishHistoryId(
210: CmsUUID publishHistoryId) {
211:
212: return m_publishEngine
213: .getJobByPublishHistoryId(publishHistoryId);
214: }
215:
216: /**
217: * Returns the publish history list with already publish jobs.<p>
218: *
219: * @return a list of {@link CmsPublishJobFinished} objects
220: */
221: public List getPublishHistory() {
222:
223: return m_publishEngine.getPublishHistory().asList();
224: }
225:
226: /**
227: * Returns the publish history list with already publish jobs, filtered by the given user.<p>
228: *
229: * @param user the user to filter the jobs with
230: *
231: * @return a list of {@link CmsPublishJobFinished} objects
232: */
233: public List getPublishHistory(CmsUser user) {
234:
235: List result = new ArrayList();
236: Iterator it = getPublishHistory().iterator();
237: while (it.hasNext()) {
238: CmsPublishJobFinished publishJob = (CmsPublishJobFinished) it
239: .next();
240: if (publishJob.getUserId().equals(user.getId())) {
241: result.add(publishJob);
242: }
243: }
244: return result;
245: }
246:
247: /**
248: * Returns the publish History Size.<p>
249: *
250: * @return the publish History Size
251: */
252: public int getPublishHistorySize() {
253:
254: return m_publishHistorySize;
255: }
256:
257: /**
258: * Returns a publish list with all new/changed/deleted resources of the current (offline)
259: * project that actually get published.<p>
260: *
261: * @param cms the cms request context
262: *
263: * @return a publish list
264: *
265: * @throws CmsException if something goes wrong
266: */
267: public CmsPublishList getPublishList(CmsObject cms)
268: throws CmsException {
269:
270: return m_securityManager.fillPublishList(cms
271: .getRequestContext(), new CmsPublishList(cms
272: .getRequestContext().currentProject()));
273: }
274:
275: /**
276: * Returns a publish list with all new/changed/deleted resources of the current (offline)
277: * project that actually get published for a direct publish of a single resource.<p>
278: *
279: * @param cms the cms request context
280: * @param directPublishResource the resource which will be directly published
281: * @param directPublishSiblings <code>true</code>, if all eventual siblings of the direct
282: * published resource should also get published.
283: *
284: * @return a publish list
285: *
286: * @throws CmsException if something goes wrong
287: */
288: public CmsPublishList getPublishList(CmsObject cms,
289: CmsResource directPublishResource,
290: boolean directPublishSiblings) throws CmsException {
291:
292: return m_securityManager.fillPublishList(cms
293: .getRequestContext(), new CmsPublishList(
294: directPublishResource, directPublishSiblings));
295: }
296:
297: /**
298: * Returns a publish list with all new/changed/deleted resources of the current (offline)
299: * project that actually get published for a direct publish of a List of resources.<p>
300: *
301: * @param cms the cms request context
302: * @param directPublishResources the resources which will be directly published
303: * @param directPublishSiblings <code>true</code>, if all eventual siblings of the direct
304: * published resources should also get published.
305: *
306: * @return a publish list
307: *
308: * @throws CmsException if something goes wrong
309: */
310: public CmsPublishList getPublishList(CmsObject cms,
311: List directPublishResources, boolean directPublishSiblings)
312: throws CmsException {
313:
314: return getPublishList(cms, directPublishResources,
315: directPublishSiblings, true);
316: }
317:
318: /**
319: * Returns a publish list with all new/changed/deleted resources of the current (offline)
320: * project that actually get published for a direct publish of a List of resources.<p>
321: *
322: * @param cms the cms request context
323: * @param directPublishResources the {@link CmsResource} objects which will be directly published
324: * @param directPublishSiblings <code>true</code>, if all eventual siblings of the direct
325: * published resources should also get published.
326: * @param publishSubResources indicates if sub-resources in folders should be published (for direct publish only)
327: *
328: * @return a publish list
329: *
330: * @throws CmsException if something goes wrong
331: */
332: public CmsPublishList getPublishList(CmsObject cms,
333: List directPublishResources, boolean directPublishSiblings,
334: boolean publishSubResources) throws CmsException {
335:
336: return m_securityManager.fillPublishList(cms
337: .getRequestContext(), new CmsPublishList(
338: directPublishResources, directPublishSiblings,
339: publishSubResources));
340: }
341:
342: /**
343: * Returns the queue with still waiting publish jobs.<p>
344: *
345: * @return a list of {@link CmsPublishJobEnqueued} objects
346: */
347: public List getPublishQueue() {
348:
349: return m_publishEngine.getPublishQueue().asList();
350: }
351:
352: /**
353: * Returns the amount of time in seconds the system will wait during shutdown for a running publish job.<p>
354: *
355: * @return the shutdown time for a running publish job
356: */
357: public int getPublishQueueShutdowntime() {
358:
359: return m_publishQueueShutdowntime;
360: }
361:
362: /**
363: * Returns a new publish list that contains the unpublished resources related
364: * to all resources in the given publish list, the related resources exclude
365: * all resources in the given publish list and also locked (by other users) resources.<p>
366: *
367: * @param cms the cms request context
368: * @param publishList the publish list to exclude from result
369: *
370: * @return a new publish list that contains the related resources
371: *
372: * @throws CmsException if something goes wrong
373: */
374: public CmsPublishList getRelatedResourcesToPublish(CmsObject cms,
375: CmsPublishList publishList) throws CmsException {
376:
377: return m_securityManager.getRelatedResourcesToPublish(cms
378: .getRequestContext(), publishList,
379: CmsRelationFilter.TARGETS.filterStrong());
380: }
381:
382: /**
383: * Returns the content of the publish report assigned to the given publish job.<p>
384: *
385: * @param publishJob the published job
386: * @return the content of the assigned publish report
387: *
388: * @throws CmsException if somethign goes wrong
389: */
390: public byte[] getReportContents(CmsPublishJobFinished publishJob)
391: throws CmsException {
392:
393: return m_publishEngine.getReportContents(publishJob);
394: }
395:
396: /**
397: * Initializes the publish manager and the publish engine finally.<p>
398: *
399: * @param cms an admin cms object
400: *
401: * @throws CmsException if something goes wrong
402: */
403: public void initialize(CmsObject cms) throws CmsException {
404:
405: m_publishEngine.initialize(cms, m_publishQueuePersistance,
406: m_publishQueueShutdowntime);
407: m_frozen = true;
408: }
409:
410: /**
411: * Returns if the publish queue is persisted an will be re-initialized on startup.<p>
412: *
413: * @return <code>true</code> if the publish queue is persisted
414: */
415: public boolean isPublishQueuePersistanceEnabled() {
416:
417: return m_publishQueuePersistance;
418: }
419:
420: /**
421: * Returns the working state, that is if no publish job
422: * is waiting to be processed and there is no current running
423: * publish job.<p>
424: *
425: * @return the working state
426: */
427: public boolean isRunning() {
428:
429: return m_publishEngine.isRunning();
430: }
431:
432: /**
433: * Returns a new publish list that contains all resources of both given publish lists.<p>
434: *
435: * @param cms the cms request context
436: * @param pubList1 the first publish list
437: * @param pubList2 the second publish list
438: *
439: * @return a new publish list that contains all resources of both given publish lists
440: *
441: * @throws CmsException if something goes wrong
442: */
443: public CmsPublishList mergePublishLists(CmsObject cms,
444: CmsPublishList pubList1, CmsPublishList pubList2)
445: throws CmsException {
446:
447: return m_securityManager.mergePublishLists(cms
448: .getRequestContext(), pubList1, pubList2);
449: }
450:
451: /**
452: * Publishes the current project, printing messages to a shell report.<p>
453: *
454: * @param cms the cms request context
455: * @return the publish history id of the published project
456: *
457: * @throws Exception if something goes wrong
458: *
459: * @see CmsShellReport
460: */
461: public CmsUUID publishProject(CmsObject cms) throws Exception {
462:
463: return publishProject(cms, new CmsShellReport(cms
464: .getRequestContext().getLocale()));
465: }
466:
467: /**
468: * Publishes the current project.<p>
469: *
470: * @param cms the cms request context
471: * @param report an instance of <code>{@link I_CmsReport}</code> to print messages
472: *
473: * @return the publish history id of the published project
474: *
475: * @throws CmsException if something goes wrong
476: */
477: public CmsUUID publishProject(CmsObject cms, I_CmsReport report)
478: throws CmsException {
479:
480: return publishProject(cms, report, getPublishList(cms));
481: }
482:
483: /**
484: * Validates the relations for the given resources.<p>
485: *
486: * @param cms the cms request context
487: * @param publishList the publish list to validate against the online project
488: * @param report a report to write the messages to
489: *
490: * @return a map with lists of invalid links
491: * (<code>{@link org.opencms.relations.CmsRelation}}</code> objects)
492: * keyed by root paths
493: *
494: * TODO: change return value to List of CmsRelation
495: *
496: * @throws Exception if something goes wrong
497: */
498: public Map validateRelations(CmsObject cms,
499: CmsPublishList publishList, I_CmsReport report)
500: throws Exception {
501:
502: return m_securityManager.validateRelations(cms
503: .getRequestContext(), publishList, report);
504: }
505:
506: /**
507: * Publishes the resources of a specified publish list.<p>
508: *
509: * @param cms the cms request context
510: * @param report an instance of <code>{@link I_CmsReport}</code> to print messages
511: * @param publishList a publish list
512: *
513: * @return the publish history id of the published project
514: *
515: * @throws CmsException if something goes wrong
516: *
517: * @see #getPublishList(CmsObject)
518: * @see #getPublishList(CmsObject, CmsResource, boolean)
519: * @see #getPublishList(CmsObject, List, boolean)
520: */
521: public CmsUUID publishProject(CmsObject cms, I_CmsReport report,
522: CmsPublishList publishList) throws CmsException {
523:
524: return m_securityManager.publishProject(cms, publishList,
525: report);
526: }
527:
528: /**
529: * Direct publishes a specified resource.<p>
530: *
531: * @param cms the cms request context
532: * @param report an instance of <code>{@link I_CmsReport}</code> to print messages
533: * @param directPublishResource a <code>{@link CmsResource}</code> that gets directly published;
534: * or <code>null</code> if an entire project gets published.
535: * @param directPublishSiblings if a <code>{@link CmsResource}</code> that should get published directly is
536: * provided as an argument, all eventual siblings of this resource
537: * get publish too, if this flag is <code>true</code>.
538: *
539: * @return the publish history id of the published project
540: *
541: * @throws CmsException if something goes wrong
542: */
543: public CmsUUID publishProject(CmsObject cms, I_CmsReport report,
544: CmsResource directPublishResource,
545: boolean directPublishSiblings) throws CmsException {
546:
547: return publishProject(cms, report, getPublishList(cms,
548: directPublishResource, directPublishSiblings));
549: }
550:
551: /**
552: * Publishes a single resource, printing messages to a shell report.<p>
553: *
554: * The siblings of the resource will not be published.<p>
555: *
556: * @param cms the cms request context
557: * @param resourcename the name of the resource to be published
558: *
559: * @return the publish history id of the published project
560: *
561: * @throws Exception if something goes wrong
562: *
563: * @see CmsShellReport
564: */
565: public CmsUUID publishResource(CmsObject cms, String resourcename)
566: throws Exception {
567:
568: return publishResource(cms, resourcename, false,
569: new CmsShellReport(cms.getRequestContext().getLocale()));
570: }
571:
572: /**
573: * Publishes a single resource.<p>
574: *
575: * @param cms the cms request context
576: * @param resourcename the name of the resource to be published
577: * @param publishSiblings if <code>true</code>, all siblings of the resource are also published
578: * @param report the report to write the progress information to
579: *
580: * @return the publish history id of the published project
581: *
582: * @throws Exception if something goes wrong
583: */
584: public CmsUUID publishResource(CmsObject cms, String resourcename,
585: boolean publishSiblings, I_CmsReport report)
586: throws Exception {
587:
588: CmsResource resource = cms.readResource(resourcename,
589: CmsResourceFilter.ALL);
590: return publishProject(cms, report, resource, publishSiblings);
591: }
592:
593: /**
594: * Removes the given publish listener.<p>
595: *
596: * @param listener the publish listener to remove
597: */
598: public void removePublishListener(I_CmsPublishEventListener listener) {
599:
600: m_publishEngine.removePublishListener(listener);
601: }
602:
603: /**
604: * Sets the publish engine during initialization.<p>
605: *
606: * @param publishEngine the publish engine instance
607: */
608: public void setPublishEngine(CmsPublishEngine publishEngine) {
609:
610: if (m_frozen) {
611: throw new CmsRuntimeException(Messages.get().container(
612: Messages.ERR_CONFIG_FROZEN_0));
613: }
614: m_publishEngine = publishEngine;
615: }
616:
617: /**
618: * Sets the publish History Size.<p>
619: *
620: * @param publishHistorySize the publish History Size to set
621: */
622: public void setPublishHistorySize(String publishHistorySize) {
623:
624: if (m_frozen) {
625: throw new CmsRuntimeException(Messages.get().container(
626: Messages.ERR_CONFIG_FROZEN_0));
627: }
628: m_publishHistorySize = Integer.parseInt(publishHistorySize);
629: }
630:
631: /**
632: * Sets if the publish queue is re-initialized on startup.<p>
633: *
634: * @param publishQueuePersistance the persistance flag, parsed as <code>boolean</code>
635: */
636: public void setPublishQueuePersistance(
637: String publishQueuePersistance) {
638:
639: if (m_frozen) {
640: throw new CmsRuntimeException(Messages.get().container(
641: Messages.ERR_CONFIG_FROZEN_0));
642: }
643: m_publishQueuePersistance = Boolean.valueOf(
644: publishQueuePersistance).booleanValue();
645: }
646:
647: /**
648: * Sets the publish queue shutdown time.
649: *
650: * @param publishQueueShutdowntime the shutdowntime to set, parsed as <code>int</code>
651: */
652: public void setPublishQueueShutdowntime(
653: String publishQueueShutdowntime) {
654:
655: if (m_frozen) {
656: throw new CmsRuntimeException(Messages.get().container(
657: Messages.ERR_CONFIG_FROZEN_0));
658: }
659: m_publishQueueShutdowntime = Integer
660: .parseInt(publishQueueShutdowntime);
661: }
662:
663: /**
664: * Sets the security manager during initialization.<p>
665: *
666: * @param securityManager the security manager
667: */
668: public void setSecurityManager(CmsSecurityManager securityManager) {
669:
670: if (m_frozen) {
671: throw new CmsRuntimeException(Messages.get().container(
672: Messages.ERR_CONFIG_FROZEN_0));
673: }
674: m_securityManager = securityManager;
675: }
676:
677: /**
678: * Starts publishing of enqueued publish jobs.<p>
679: */
680: public void startPublishing() {
681:
682: m_publishEngine.startEngine();
683: }
684:
685: /**
686: * Stops the publishing of enqueued publish jobs.<p>
687: */
688: public void stopPublishing() {
689:
690: m_publishEngine.stopEngine();
691: }
692:
693: /**
694: * Waits until no publish jobs remain.<p>
695: */
696: public void waitWhileRunning() {
697:
698: waitWhileRunning(Long.MAX_VALUE);
699: }
700:
701: /**
702: * Waits until no publish jobs remain or the given max milliseconds.<p>
703: *
704: * @param ms the max milliseconds to wait
705: */
706: public void waitWhileRunning(long ms) {
707:
708: int i = 0;
709: // wait until it is done or time is over
710: synchronized (this ) {
711: while (isRunning() && ((MS_ONE_SECOND * i) <= ms)) {
712: try {
713: this .wait(MS_ONE_SECOND); // wait a second
714: } catch (InterruptedException e) {
715: // ignore
716: e.printStackTrace();
717: }
718: i++;
719: }
720: }
721: }
722:
723: /**
724: * Returns the currently used publish engine.<p>
725: *
726: * @return the publish engine
727: */
728: protected CmsPublishEngine getEngine() {
729:
730: return m_publishEngine;
731: }
732: }
|