/* * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ package com.arsdigita.cms.publishToFile; import com.arsdigita.cms.ContentSection; import com.arsdigita.cms.Template; import com.arsdigita.initializer.Configuration; import com.arsdigita.initializer.InitializationException; import com.arsdigita.domain.DomainObject; import com.arsdigita.domain.DomainObjectInstantiator; import com.arsdigita.domain.DomainObjectFactory; import com.arsdigita.persistence.DataObject; import com.arsdigita.persistence.SessionManager; import com.arsdigita.persistence.TransactionContext; import com.arsdigita.persistence.metadata.MetadataRoot; import com.arsdigita.persistence.metadata.ObjectType; import com.arsdigita.runtime.CCMResourceManager; import com.arsdigita.util.UncheckedWrapperException; import org.apache.log4j.Logger; import java.io.*; // import java.io.File; import java.util.List; import java.util.Iterator; /** * Initializes the publish-to-file service. The configuration is described in * the {@link com.arsdigita.cms.publishToFile} page. * * (pboy) ToDo: Adjusting the initialisation to the new configuration method * without enterprise.init file. * * @author Jeff Teeters (teeters@arsdigita.com) * @version $Revision: #24 $ $Date: 2004/08/17 $ */ public class LegacyInitializer implements com.arsdigita.initializer.Initializer { private static Logger s_log = Logger.getLogger(LegacyInitializer.class); private final static String PUBLISH_DESTINATIONS = "destination"; private final static String PUBLISH_TO_FILE_LISTENER = "publishListener"; private final static String QUEUE_POLL_STARTUP_DELAY = "startupDelay"; private final static String QUEUE_POLL_DELAY = "pollDelay"; private final static String RETRY_DELAY = "retryDelay"; private final static String REQUEST_TIMEOUT = "requestTimeout"; private final static String BLOCK_SIZE = "blockSize"; private final static String BLOCK_SELECT_METHOD = "blockSelectMethod"; private final static String MAXIMUM_FAIL_COUNT = "maximumFailCount"; private Configuration m_conf = new Configuration(); public LegacyInitializer() throws InitializationException { m_conf.initParameter( PUBLISH_DESTINATIONS, "List of publish destinations for content types" + "Each element is a four-element list in the format " + "'{ \"content type\", \"root directory\", \"shared storage\", " + "\"url stub\" }'. " + "Content type is the object type of the content type." + "Root directory must be a path to a writable directory, relative" + "to the webapp root. Shared storage must be true if the root " + "directory is shared NFS storage, false otherwise. URL stub is " + "must be the path component of the URL from which the live server " + "will serve from this directory.", List.class); m_conf.initParameter( PUBLISH_TO_FILE_LISTENER, "Class which implements PublishToFileListener used to " + "perform additional actions when publishing or unpublishing " + "to the file system.", String.class); m_conf.initParameter( QUEUE_POLL_STARTUP_DELAY, "Time (in seconds) after system startup to wait before " + "starting to monitor publishToFile queue. A value < 0 " + "disables processing of the queue on this server.", Integer.class, new Integer(30)); m_conf.initParameter( QUEUE_POLL_DELAY, "Time (in seconds) between checking if there are entries " + "in the publishToFile queue. A value <= 0 disables processing " + "the queue on this server.", Integer.class, new Integer(1)); m_conf.initParameter( RETRY_DELAY, "Time to wait (seconds) before retrying to process a " + "failed entry.", Integer.class, new Integer(120)); m_conf.initParameter( REQUEST_TIMEOUT, "Time to wait (seconds) before aborting item request.", Integer.class, new Integer(PublishToFile.DEFAULT_TIMEOUT)); m_conf.initParameter( BLOCK_SIZE, "number of queue entries to process in one txn." , Integer.class, new Integer(20)); m_conf.initParameter( BLOCK_SELECT_METHOD, "Method used to select entries for processing. " + "'QueuedOrder'-in queued order. 'GroupByParent'-group " + "entries according to parent when selecting items " + "(allows optimizations if a listener task required for " + "all elements in a folder can be done only once for the " + "folder).", String.class, "QueuedOrder"); m_conf.initParameter( MAXIMUM_FAIL_COUNT, "Maximum Fail Count for actions in Queue Manager. " + "If Fail Count in Database is more than Specified " + "Limit, Queue Manager will ignore the action. The " + "Default Value -1 will ignore this parameter.", Integer.class, new Integer(-1)); } public Configuration getConfiguration() { return m_conf; } public void startup() { TransactionContext txn = SessionManager.getSession().getTransactionContext(); txn.beginTxn(); setupPublishToFileSystem(); // QueueManager.requeueMissingFiles(); txn.commitTxn(); } public void shutdown() { QueueManager.stopWatchingQueue(); } /** * initialize source and destinations for publishing to the file system */ private void setupPublishToFileSystem() throws InitializationException { DomainObjectInstantiator inst = new DomainObjectInstantiator() { public DomainObject doNewInstance(DataObject dobj) { return new PublishedFile(dobj); } }; DomainObjectFactory.registerInstantiator( PublishedFile.BASE_DATA_OBJECT_TYPE, inst); // PublishToFileConfig ptfConf = PublishToFileConfig.getConfig(); // processDestination((List) m_conf.getParameter(PUBLISH_DESTINATIONS)); // processDestination((List) ptfConf.getPublishDestinations()); // setupQueueManager(); } /** * Prepare Queuemanager and start Queue processing. */ private void setupQueueManager(){ PublishToFileConfig ptfConf = PublishToFileConfig.getConfig(); // PublishToFile.setRequestTimeout(getInteger(REQUEST_TIMEOUT).intValue()); PublishToFile.setRequestTimeout(ptfConf.getRequestTimeout()); // QueueManager.setRetryDelay(getInteger(RETRY_DELAY)); QueueManager.setRetryDelay(ptfConf.getRetryDelay()); // QueueManager.setBlockSize(getInteger(BLOCK_SIZE)); QueueManager.setBlockSize(ptfConf.getBlockSize()); // QueueManager.setBlockSelectMethod(getString(BLOCK_SELECT_METHOD)); QueueManager.setBlockSelectMethod(ptfConf.getBlockSelectMethod()); // QueueManager.setMaximumFailCount(getInteger(MAXIMUM_FAIL_COUNT)); QueueManager.setMaximumFailCount(ptfConf.getMaximumFailCount()); // setup listener if specified /* String listenerName = getString( PUBLISH_TO_FILE_LISTENER ); if (listenerName != null) { PublishToFileListener listener = null; Class listenerClass = null; try { listenerClass = Class.forName(listenerName); } catch (ClassNotFoundException ex) { invalidParam(PUBLISH_TO_FILE_LISTENER, "could not find listener class " + listenerClass); } try { listener = (PublishToFileListener)listenerClass.newInstance(); } catch (InstantiationException ex) { invalidParam(PUBLISH_TO_FILE_LISTENER, "could not find instantiate listener class " + listenerClass + " (" + ex.getMessage() + ")"); } catch (IllegalAccessException ex) { invalidParam(PUBLISH_TO_FILE_LISTENER, "could not find instantiate listener class " + listenerClass + " (" + ex.getMessage() + ")"); } QueueManager.setListener(listener); } */ // Just set the class implementing methods run when for publishing // or unpublishing to file. No initialisation of the class here. try { QueueManager.setListener((PublishToFileListener) ptfConf.getpublishListenerClass() .newInstance()); } catch (InstantiationException ex) { throw new UncheckedWrapperException ("Failed to instantiate the listener class", ex); } catch (IllegalAccessException ex) { throw new UncheckedWrapperException ("Couldn't access the listener class", ex); } // start thread for monitoring queue // int startupDelay = getInteger(QUEUE_POLL_STARTUP_DELAY).intValue(); int startupDelay = ptfConf.getStartupDelay(); // int pollDelay = getInteger(QUEUE_POLL_DELAY).intValue(); int pollDelay = ptfConf.getPollDelay(); QueueManager.startWatchingQueue(startupDelay, pollDelay); } // // Process publishing destinations // private static void processDestination(List dest) throws InitializationException { if (dest == null) { invalidParam(PUBLISH_DESTINATIONS, "publish destinations must not be null"); } if (dest.size() < 1) { invalidParam(PUBLISH_DESTINATIONS, "publish destinations must contain at " + "least one entry"); } Iterator entries = dest.iterator(); while (entries.hasNext()) { processDestinationEntry((List)entries.next()); } } private static void processDestinationEntry(List entry) throws InitializationException { if ( entry.size() != 4 ) { invalidParam(PUBLISH_DESTINATIONS, "publish destinations entry must contain " + "four elements: '{ \n" + " \"content type\",\n" + " \"root directory\", \n" + " \"is shared\", \n" + " \"url stub\" \n" + "};\n"); } String contentType = (String)entry.get(0); // destRoot is here relative to webapp root! String destRoot = (String) entry.get(1); Boolean sharedRoot = (Boolean) entry.get(2); String destURL = (String) entry.get(3); if ( contentType == null || contentType.trim().length() == 0) { invalidParam(PUBLISH_DESTINATIONS, "the destination content type must not be null"); } ObjectType type = MetadataRoot.getMetadataRoot().getObjectType(contentType); if (type == null) { invalidParam(PUBLISH_DESTINATIONS, "the destination content type cannot be found"); } if (destRoot == null || destRoot.trim().length() == 0) { invalidParam(PUBLISH_DESTINATIONS, "the destination root must not be null"); } if (destRoot.endsWith("/")) { invalidParam(PUBLISH_DESTINATIONS, "the destination root '" + destRoot + "' must not end with a '/'"); } // Does destRoot really now turns into an absolute fully pathname destRoot = new File(CCMResourceManager.getBaseDirectory().getPath(), destRoot).getPath(); s_log.info("Destination Root is set to : " + destRoot); if (sharedRoot == null) { invalidParam(PUBLISH_DESTINATIONS, "the destination shared flag must not be null"); } if (destURL == null || "".equals(destURL.trim())) { invalidParam(PUBLISH_DESTINATIONS, "the destination URL must not be null"); } if (!destURL.startsWith("/")) { invalidParam(PUBLISH_DESTINATIONS, "the destination URL '" + destURL + "' must start with a '/'"); } if (destURL.endsWith("/")) { invalidParam(PUBLISH_DESTINATIONS, "the destination URL '" + destURL + "' must not end with a '/'"); } DestinationStub dest = new DestinationStub(destRoot, sharedRoot.booleanValue(), destURL); File file = dest.getFile(); if (!file.exists()) { file.mkdirs(); s_log.info(file.getPath() + " created"); } boolean writable = false; FileWriter fl; File fname = new File(file.getPath(),"placeholder.txt"); s_log.info("Try to create : " + destRoot); try { writable = file.canWrite() && file.isDirectory(); try { fl = new FileWriter(fname.getPath()); fl.write("Location for the p2fs module to store static content. \n"); fl.close(); } catch ( IOException e ) { // Will be reported as an initalization error s_log.warn("Error creating file " + fname.getPath()); } } catch ( SecurityException ex ) { // Will be reported as an initalization error } if ( ! writable ) { // HACK: Let's see if we can write to the config directory. If we can, // then we're running as ccmadmin inside of ccm load, and there is no // need to thrown an exception. File conf = CCMResourceManager.getConfigDirectory(); if (conf.isDirectory() && conf.canWrite()) { // we're ok } else { invalidParam(PUBLISH_DESTINATIONS, " the document root '" + file +"' must be a writable directory"); } } if (Template.BASE_DATA_OBJECT_TYPE.equals(contentType) || !ContentSection.getConfig().getDisableItemPfs()) { PublishToFile.addDestination(contentType, dest); } } private Integer getInteger(String paramName) { return (Integer) m_conf.getParameter(paramName); } private String getString(String paramName) { return (String) m_conf.getParameter(paramName); } private static void invalidParam(String param, String msg) throws InitializationException { throw new InitializationException( "publishToFile: parameter " + param +": " + msg); } }