/* * Copyright (C) 2002-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.themedirector.util; import com.arsdigita.themedirector.Theme; import com.arsdigita.themedirector.ThemeFile; import com.arsdigita.themedirector.ThemeFileCollection; import java.io.File; import org.apache.log4j.Logger; /** * Class for polling the database to look for new/updated development files * in the ThemeFile table. * * For "development" files, it looks at every file in the db and, if the * timestamp is after the timestamp of the file on the file system (or * there is no file on the file system) then it writes out the new file. * If the timestamp on the file system is newer, it ignores the file. * * @author Randy Graebner */ public class ThemeDevelopmentFileManager extends ThemeFileManager { /** Internal logger instance to faciliate debugging. Enable logging output * by editing /WEB-INF/conf/log4j.properties in the runtime environment and * set com.arsdigita.themedirector.util.ThemeDevelopmentFileManager=DEBUG * by uncommenting or adding the line. */ private static final Logger s_log = Logger .getLogger(ThemeDevelopmentFileManager.class); // The code in this class borrows heavily from // com.arsdigita.cms.publishToFile.FileManager private static ThemeFileManager s_manager; /** * Constructor just delegates to super class. * * Usually Themedirector's Initializer() will setup a background thread to * continuously watch for modifications and synchronize. Specifically the * Initializer() provides null as baseDirectory parameter because it * doesn't know about servlet context and can not determine the directory. * * * @param startupDelay number of seconds to wait before starting to process * the file. A startupDelay of 0 means this is a no-op * @param pollDelay number of seconds to wait between checks if the file * has any entries. * @param baseDirectory String with the file system path to document root * for the application context ThemeDirector is running. * (the directory containing WEB-INF subdir) * May be null! (Specificall if invokel by Initializer!) */ protected ThemeDevelopmentFileManager(int startupDelay, int pollDelay, String baseDirectory) { super(s_log, // Injects it's own logger startupDelay, pollDelay, baseDirectory); // to the parent class methods! } // is there a way to move this code up in to the parent class? /** * Start watching the files. This method spawns a background thread that * looks for changes in files in the database if there is not already a * thread that has been spawned. If there is already a running thread then * this is a no-op that returns a reference to the running thread. * * Specifically it is used by Themedirector's Initializer() to start a * continuous background process to synchronize database and filesystem. * * The thread starts processing after startupDelay seconds. The * db is checked for new/updated files every pollDelay seconds. * * This will not start up multiple threads...if there is already a thread * running, it will return that thread to you. * * @param startupDelay number of seconds to wait before starting to process * the file. A startupDelay of 0 means this is a no-op * @param pollDelay number of seconds to wait between checks if the file * has any entries. * @param baseDirectory String with the file system path to document root * for the application context ThemeDirector is running. * (the directory containing WEB-INF subdir) * May be null! (Specificall if invokel by Initializer!) * @return */ public static ThemeFileManager startWatchingFiles(int startupDelay, int pollDelay, String baseDirectory) { if (s_manager == null) { s_log.info("Starting Theme File Manager Thread with the base " + "directory of " + baseDirectory); if ( startupDelay > 0 ) { s_manager = new ThemeDevelopmentFileManager(startupDelay, pollDelay, baseDirectory); s_manager.setDaemon(true); s_manager.setName("theme-dev-files"); s_manager.start(); } else { s_log.warn("Theme Development File Manager Thread is not starting " + "because the startup delay is <= 0"); } } return s_manager; } /** * This returns the current thread or null if the thread has not * yet been started. * * @return */ public static ThemeFileManager getInstance() { return s_manager; } /** * This typically returns something like "getBaseDirectory() + PROD_DIR". * * @return */ @Override protected String getManagerSpecificDirectory() { String devDir = getBaseDirectory() + DEV_THEMES_BASE_DIR; s_log.info(devDir + " is the development themes directory used."); return devDir; } // TODO // if we run the updateDatabaseFiles every time this runs then // it ends up doing an insert pretty much every time. So, // we only place the dev files in the db when the user specifically // tells us to by publishing the files or by clicking on the link // to place them in the db. I am leaving this code here since // it works if we want the thread to auto-update things for us. // if we decide that we definitely do not want the auto-update // then we should remove this. @Override protected void updateTheme(Theme theme) { // the first step is to make sure that all files from the theme // are in the db. String stub = getManagerSpecificDirectory(); File themeDir = new File(stub + theme.getURL() + "/"); if (themeDir.exists()) { ThemeFileUtil.updateDatabaseFiles(themeDir, theme, themeDir.getAbsolutePath(), false, ThemeFile.DRAFT); } // the call to super makes sure that the file system has everything // from the database. super.updateTheme(theme); } /** * This allows subclasses to filter the collection as appropriate. * (e.g. only return "live" files or only "draft" files). * @return */ @Override protected ThemeFileCollection getThemeFilesCollection(Theme theme) { return theme.getDraftThemeFiles(); } }