diff --git a/ccm-core/src/com/arsdigita/web/BaseApplicationServlet.java b/ccm-core/src/com/arsdigita/web/BaseApplicationServlet.java
index 44de6bfbe..b8b8dcc0f 100755
--- a/ccm-core/src/com/arsdigita/web/BaseApplicationServlet.java
+++ b/ccm-core/src/com/arsdigita/web/BaseApplicationServlet.java
@@ -65,7 +65,10 @@ import org.apache.log4j.Logger;
*/
public abstract class BaseApplicationServlet extends BaseServlet {
- /** Logger instance for debugging purpose. */
+ /** Internal logger instance to faciliate debugging. Enable logging output
+ * by editing /WEB-INF/conf/log4j.properties int hte runtime environment
+ * and set com.arsdigita.web.BaseApplicationServlet=DEBUG by uncommenting
+ * or adding the line. */
private static final Logger s_log = Logger.getLogger(BaseApplicationServlet.class);
/**
diff --git a/ccm-core/src/com/arsdigita/web/CCMApplicationContextListener.java b/ccm-core/src/com/arsdigita/web/CCMApplicationContextListener.java
index 5558a66de..818edb241 100644
--- a/ccm-core/src/com/arsdigita/web/CCMApplicationContextListener.java
+++ b/ccm-core/src/com/arsdigita/web/CCMApplicationContextListener.java
@@ -34,13 +34,14 @@ import org.apache.log4j.LogManager;
import org.apache.log4j.PropertyConfigurator;
/**
- * Web application lifecycle listener, used to perform central initialisation tasks at CCM startup
- * in a Servlet container / web application server, expecially setting the runtime context (file
- * locations) and (in the future) the database connection.
+ * Web application lifecycle listener, used to perform central initialisation
+ * tasks at CCM startup in a Servlet container / web application server,
+ * expecially setting the runtime context (file locations) and (in the future)
+ * the database connection.
*
- * The methods of this classes are by definition only invoked by the Servlet container / web
- * application server, not by any Servlet or java class of the application itself! Invocation is
- * managed by the deployment descriptor.
+ * The methods of this classes are by definition only invoked by the Servlet
+ * container / web application server, not by any Servlet or java class of the
+ * application itself! Invocation is managed by the deployment descriptor.
*
* Note! Don't forget to configure it in web.xml deployment descriptor!
*
@@ -48,25 +49,31 @@ import org.apache.log4j.PropertyConfigurator;
* com.arsdigita.runtime.CCMApplicationContextListener
*
*
- * According to the 2.3 specification these tags must be placed after the filter tags and before the
- * Servlet tags!
+ * According to the 2.3 specification these tags must be placed after the
+ * filter tags and before the Servlet tags!
*
* @author pboy
* @version $Id: $
*/
public class CCMApplicationContextListener implements ServletContextListener {
- private static Logger s_log = Logger.getLogger(CCMApplicationContextListener.class);
+ /** Internal logger instance to faciliate debugging. Enable logging output
+ * by editing /WEB-INF/conf/log4j.properties int hte runtime environment
+ * and set com.arsdigita.web.CCMApplicationContextListener=DEBUG by
+ * uncommenting or adding the line. */
+ private static final Logger s_log = Logger.getLogger(
+ CCMApplicationContextListener.class);
private static Runtime runtime;
/**
- * Used to initialise classes at startup of the application, most of which needs to be plain
- * java objects (because they are also used by command line interface - installation,
- * configuration, maintenance).
+ * Used to initialise classes at startup of the application, most of which
+ * needs to be plain java objects (because they are also used by command
+ * line interface - installation, configuration, maintenance).
*
- * Here we provide one of the two supported ways to bring up the CCM application. This handles
- * the startup inside a Servlet container. The command line utilities handle the startup there.
+ * Here we provide one of the two supported ways to bring up the CCM
+ * application. This handles the startup inside a Servlet container.
+ * The command line utilities handle the startup there.
* Both initialise the same set of classes needed for CCM operations
*
* @param applicationStartEvent
@@ -124,6 +131,7 @@ public class CCMApplicationContextListener implements ServletContextListener {
*
* @param applicationEndEvent
*/
+ @Override
public void contextDestroyed(ServletContextEvent applicationEndEvent) {
s_log.info("Shutdown procedure started.");
diff --git a/ccm-core/src/com/arsdigita/web/Web.java b/ccm-core/src/com/arsdigita/web/Web.java
index 023f59a18..3f24d3d92 100755
--- a/ccm-core/src/com/arsdigita/web/Web.java
+++ b/ccm-core/src/com/arsdigita/web/Web.java
@@ -115,8 +115,7 @@ public class Web {
/**
* Gets the servlet request object of the current thread.
*
- * @return The current HttpServletRequest; it can be
- * null
+ * @return The current HttpServletRequest; it can be null
*/
public static HttpServletRequest getRequest() {
return (HttpServletRequest) s_request.get();
@@ -126,7 +125,6 @@ public class Web {
* Gets the servlet context of the current thread.
*
* @return The current ServletContext; it can be null
- *
*/
public static ServletContext getServletContext() {
return (ServletContext) s_servletContext.get();
diff --git a/ccm-themedirector/src/com/arsdigita/themedirector/ThemeDirectorConfig.java b/ccm-themedirector/src/com/arsdigita/themedirector/ThemeDirectorConfig.java
index 3b973899d..05f7c9d5b 100755
--- a/ccm-themedirector/src/com/arsdigita/themedirector/ThemeDirectorConfig.java
+++ b/ccm-themedirector/src/com/arsdigita/themedirector/ThemeDirectorConfig.java
@@ -65,7 +65,8 @@ public class ThemeDirectorConfig extends AbstractConfig {
return s_conf;
}
- // set of configuration parameters
+ // /////////////////////////////////////////////////////////////////
+ // Set of Configuration Parameters
// /////////////////////////////////////////////////////////////////
/** Directory that all of the default themes are copied from. */
@@ -74,19 +75,19 @@ public class ThemeDirectorConfig extends AbstractConfig {
("themedirector.default_theme_path",
Parameter.OPTIONAL, "/themes/master/");
- /** Servlet context path containing the default theme.
- * Previously ccm-themedirector used to be installed in its own
- * web context. In this case the appropriate web context should
- * be specified.
- * Currently, it is installed as part of the main application,
- * therefore it is empty by default.
- * @deprecated without direct replacement. Themedirector's Webapp context
- * has to be determined at runtime.
- */
- private final Parameter m_defaultThemeContext =
- new StringParameter
- ("themedirector.default_theme_context",
- Parameter.OPTIONAL, "");
+// /** Servlet context path containing the default theme.
+// * Previously ccm-themedirector used to be installed in its own
+// * web context. In this case the appropriate web context should
+// * be specified.
+// * Currently, it is installed as part of the main application,
+// * therefore it is empty by default.
+// * @deprecated without direct replacement. Themedirector's Webapp context
+// * has to be determined at runtime.
+// */
+// private final Parameter m_defaultThemeContext =
+// new StringParameter
+// ("themedirector.default_theme_context",
+// Parameter.OPTIONAL, "");
// Parameter.OPTIONAL, "/ccm-themedirector/");
/** File containing the default themes directory. Used in conjuntion with
@@ -143,10 +144,11 @@ public class ThemeDirectorConfig extends AbstractConfig {
*/
public ThemeDirectorConfig() {
- register(m_fileExtParam);
- register(m_defaultThemeContext);
- register(m_defaultThemeManifest);
register(m_defaultThemePath);
+// register(m_defaultThemeContext);
+ register(m_defaultThemeManifest);
+ register(m_fileExtParam);
+
register(m_themeDevFileWatchStartupDelay);
register(m_themeDevFileWatchPollDelay);
register(m_themePubFileWatchStartupDelay);
@@ -155,6 +157,88 @@ public class ThemeDirectorConfig extends AbstractConfig {
loadInfo();
}
+
+ // /////////////////////////////////////////////////////////////////
+ // Set of Configuration Parameters
+ // /////////////////////////////////////////////////////////////////
+
+
+ /**
+ * Retrieves the path to a directory containing a complete set of theme
+ * files to copy into a new theme as a default implementation.
+ * By default it is set to a master directory containing the distribution's
+ * default theme. When creating a new theme it is copied over to provide
+ * a default for the new theme.
+ *
+ * Developer's note:
+ * Previously it was used as a string to filter a files directory stored in
+ * the Manifest file. Matching files were copied to the new theme's directory.
+ * The reason to use this approach is not documented. As a guess: it enables
+ * to copy from more than one directory, if those directories share a common
+ * name part which is specified here. But because all files must be present
+ * at deploy time to be included into the Manifest file it makes no sense.
+ * From original comment: "Specifically, if this is not null
+ * (or the empty string) than any file that is used as part of
+ * the default directory must start with this string."
+ *
+ * @return name of a directory containing a default theme implementation
+ */
+ public String getDefaultThemePath() {
+ String defaultThemePath = (String)get(m_defaultThemePath);
+ if (defaultThemePath == null || defaultThemePath.trim().length() == 0) {
+ return null;
+ }
+ // remove leading slashwhich is already included in themedirector's
+ // constants of the directory layout.
+ if (defaultThemePath.startsWith("/")) {
+ defaultThemePath = defaultThemePath.substring(1);
+ }
+ return defaultThemePath;
+ }
+
+// /**
+// * This returns the name of the servlet context containing
+// * the default theme.
+// *
+// * @return
+// * @deprecated without direct replacement, See note above
+// */
+// public String getDefaultThemeContext() {
+// String ctx = (String)get(m_defaultThemeContext);
+// if (ctx == null) {
+// ctx = "/";
+// }
+// if (!ctx.endsWith("/")) {
+// ctx = ctx + "/";
+// }
+// if (!ctx.startsWith("/")) {
+// ctx = "/" + ctx;
+// }
+// return ctx;
+// }
+
+ /**
+ * This returns the name of the manifest file containing a list of default
+ * theme.
+ *
+ * @return
+ * @deprecated replaced by a direct copy from the default directory
+ */
+ public String getDefaultThemeManifest() {
+ return (String)get(m_defaultThemeManifest);
+ }
+
+
+ private static final String DEFAULT_THEME_URL =
+ ThemeDirector.DEFAULT_THEME + "." + Theme.URL;
+ private static final String DEFAULT_THEME_URL_ATTRIBUTE =
+ "defaultThemeURLAttribute";
+
+ /**
+ * Purpose uncodumented.
+ *
+ * @return
+ */
public Collection getDownloadFileExtensions() {
if (m_downloadFileExtensions == null) {
String extensions = (String)get(m_fileExtParam);
@@ -170,90 +254,8 @@ public class ThemeDirectorConfig extends AbstractConfig {
}
- /**
- * The number of seconds to wait before checking the database
- * for the first time. A value of 0 means that the thread
- * should not be started. This checks for published files.
- */
- public Integer getThemePubFileWatchStartupDelay() {
- return (Integer)get(m_themePubFileWatchStartupDelay);
- }
-
- /**
- * Returns the number of seconds between checking for updated
- * files in the file system. This checks for published files.
- */
- public Integer getThemePubFileWatchPollDelay() {
- return (Integer)get(m_themePubFileWatchPollDelay);
- }
-
- /**
- * The number of seconds to wait before checking the database
- * for the first time. A value of 0 means that the thread
- * should not be started. This checks for development files.
- */
- public Integer getThemeDevFileWatchStartupDelay() {
- return (Integer)get(m_themeDevFileWatchStartupDelay);
- }
-
- /**
- * Returns the number of seconds between checking for updated
- * files in the file system. This checks for development files.
- */
- public Integer getThemeDevFileWatchPollDelay() {
- return (Integer)get(m_themeDevFileWatchPollDelay);
- }
-
- /**
- * This returns the name of the servlet context containing
- * the default theme
- */
- public String getDefaultThemeContext() {
- String ctx = (String)get(m_defaultThemeContext);
- if (ctx == null) {
- ctx = "/";
- }
- if (!ctx.endsWith("/")) {
- ctx = ctx + "/";
- }
- if (!ctx.startsWith("/")) {
- ctx = "/" + ctx;
- }
- return ctx;
- }
-
- /**
- * This returns the name of the manifest file containing
- * the default theme.
- */
- public String getDefaultThemeManifest() {
- return (String)get(m_defaultThemeManifest);
- }
-
- /**
- * This returns a string that can be used as a file filter for
- * the default directory. Specifically, if this is not null
- * (or the empty string) than any file that is used as part of
- * the default directory must start with this string
- */
- public String getDefaultThemePath() {
- String defaultThemePath = (String)get(m_defaultThemePath);
- if (defaultThemePath == null || defaultThemePath.trim().length() == 0) {
- return null;
- }
- if (defaultThemePath.startsWith("/")) {
- defaultThemePath = defaultThemePath.substring(1);
- }
- return defaultThemePath;
- }
-
-
- private static final String DEFAULT_THEME_URL =
- ThemeDirector.DEFAULT_THEME + "." + Theme.URL;
- private static final String DEFAULT_THEME_URL_ATTRIBUTE =
- "defaultThemeURLAttribute";
-
/**
+ * Purpose undocumented.
*
* @param req
* @return
@@ -285,4 +287,45 @@ public class ThemeDirectorConfig extends AbstractConfig {
req.setAttribute( DEFAULT_THEME_URL_ATTRIBUTE, themeURL );
return themeURL;
}
+
+
+ /**
+ * The number of seconds to wait before checking the database
+ * for the first time. A value of 0 means that the thread
+ * should not be started. This checks for published files.
+ *
+ * @return
+ */
+ public Integer getThemePubFileWatchStartupDelay() {
+ return (Integer)get(m_themePubFileWatchStartupDelay);
+ }
+
+ /**
+ * Returns the number of seconds between checking for updated
+ * files in the file system. This checks for published files.
+ *
+ * @return
+ */
+ public Integer getThemePubFileWatchPollDelay() {
+ return (Integer)get(m_themePubFileWatchPollDelay);
+ }
+
+ /**
+ * The number of seconds to wait before checking the database
+ * for the first time. A value of 0 means that the thread
+ * should not be started. This checks for development files.
+ * @return
+ */
+ public Integer getThemeDevFileWatchStartupDelay() {
+ return (Integer)get(m_themeDevFileWatchStartupDelay);
+ }
+
+ /**
+ * Returns the number of seconds between checking for updated
+ * files in the file system. This checks for development files.
+ * @return
+ */
+ public Integer getThemeDevFileWatchPollDelay() {
+ return (Integer)get(m_themeDevFileWatchPollDelay);
+ }
}
diff --git a/ccm-themedirector/src/com/arsdigita/themedirector/ThemeDirectorConstants.java b/ccm-themedirector/src/com/arsdigita/themedirector/ThemeDirectorConstants.java
index e8f0d97ff..37ac40cd6 100755
--- a/ccm-themedirector/src/com/arsdigita/themedirector/ThemeDirectorConstants.java
+++ b/ccm-themedirector/src/com/arsdigita/themedirector/ThemeDirectorConstants.java
@@ -35,27 +35,29 @@ public interface ThemeDirectorConstants {
public final static String DEV_DIR_STUB = "/devel-themedir";
/** Path stub into directory for production themes (sub-dir of THEMES_DIR).
- * According to JavaEE spec with leading but without trailing "/"! */
+ * According to JavaEE spec with leading "/", but deviating from the
+ * JavaEE spec we add a trailing "/" for backwards compatibility to
+ * versions of CCM! */
public final static String
- PROD_THEMES_BASE_DIR = THEMES_DIR + PROD_DIR_STUB;
+ PROD_THEMES_BASE_DIR = THEMES_DIR + PROD_DIR_STUB + "/";
/** Path stub into directory for production themes (sub-dir of THEMES_DIR).
- * According to JavaEE spec with leading but without trailing "/"! */
+ * According to JavaEE spec with leading "/", but deviating from the
+ * JavaEE spec we add a trailing "/" for backwards compatibility to
+ * versions of CCM! */
public final static String
- DEV_THEMES_BASE_DIR = THEMES_DIR + DEV_DIR_STUB ;
+ DEV_THEMES_BASE_DIR = THEMES_DIR + DEV_DIR_STUB + "/";
- // ccm-themedirector (formerly ccm-ldn-theme) is no longer installed in its
- // own web context (ROOT or ccm-ldn-theme/ccm-themedirector) so it is not
- // needed anymore. We we want to install it in its own context again, we
- // should find a way to determin the context from a central configuration.
- // public final static String WEB_APP_NAME = "ROOT";
+ // Developers NOTE:
+ // ================
+ // We should consider to use the theme's url as entered by the user with
+ // a leading slash according to the specification and for sake of
+ // consistency within CCM.
+ // We would have to adjust the validation listener and the process listener
+ // in class ui/ThemeForm and to update the existing themes in the database.
/** The location of the sync jsp used to sync up the multiple servers. */
public final static String SYNC_JSP = "sync-theme.jsp";
- /** This can be used to find the root webapp directory that is used
- by default for most of the applications in CCM */
- public final static String ROOT_WEBAPP_PATH = "/ROOT";
-
public static final String THEME_XML_PREFIX = "theme:";
public final static String XML_NS =
"http://ccm.redhat.com/themedirector/1.0";
diff --git a/ccm-themedirector/src/com/arsdigita/themedirector/ThemeDirectorResources.properties b/ccm-themedirector/src/com/arsdigita/themedirector/ThemeDirectorResources.properties
index 49be7ac6e..42831555a 100755
--- a/ccm-themedirector/src/com/arsdigita/themedirector/ThemeDirectorResources.properties
+++ b/ccm-themedirector/src/com/arsdigita/themedirector/ThemeDirectorResources.properties
@@ -32,3 +32,9 @@ theme.undo.default_style=Default Style
theme.none=None
theme.save=Save
theme.set_default_theme=Default Theme
+theme.title_hint=Enter the title of the theme, up to 80 characters.
+theme.description_hint=Enter a short description for the theme, up to 4000 characters.
+theme.url_hint=Enter the LAST part of the url for the theme, eg 'holiday'. Should NOT include a leading nor a trailing slash!
+theme.save_button_hint=Save the details in the form
+theme.cancel_button_hint=Abort changes & reset the form.
+theme.cancel_button_pressed_msg=cancel pressed
diff --git a/ccm-themedirector/src/com/arsdigita/themedirector/ThemeDirectorResources_de.properties b/ccm-themedirector/src/com/arsdigita/themedirector/ThemeDirectorResources_de.properties
index 46fe59358..db835f2f1 100755
--- a/ccm-themedirector/src/com/arsdigita/themedirector/ThemeDirectorResources_de.properties
+++ b/ccm-themedirector/src/com/arsdigita/themedirector/ThemeDirectorResources_de.properties
@@ -32,3 +32,9 @@ theme.undo.default_style=Standard-Theme
theme.none=Keines
theme.save=Speichern
theme.set_default_theme=Standard-Theme
+theme.title_hint=Der Titel des Themes, kann bis zu 80 Zeichen lang sein.
+theme.description_hint=Geben Sie eine kurze Beschreibung ein, bis zu 4000 Zeichen lang.
+theme.url_hint=Geben Sie den LETZTEN Teil der URL ein, z.B. 'ferien'. Der Eintrag darf weder ein f\u00fchrendes noch ein abschlie\u00dfendes '/' enthalten!
+theme.save_button_hint=Speichern der Angaben in dem Formular.
+theme.cancel_button_hint=Verwerfen der Eintragungen und R\u00fccksetzen des Formulars.
+theme.cancel_button_pressed_msg=Vorgang abgebrochen
diff --git a/ccm-themedirector/src/com/arsdigita/themedirector/ThemeDirectorResources_en.properties b/ccm-themedirector/src/com/arsdigita/themedirector/ThemeDirectorResources_en.properties
index 49be7ac6e..d04943938 100755
--- a/ccm-themedirector/src/com/arsdigita/themedirector/ThemeDirectorResources_en.properties
+++ b/ccm-themedirector/src/com/arsdigita/themedirector/ThemeDirectorResources_en.properties
@@ -32,3 +32,9 @@ theme.undo.default_style=Default Style
theme.none=None
theme.save=Save
theme.set_default_theme=Default Theme
+theme.title_hint=Enter the title of the theme, up to 80 characters.
+theme.description_hint=Enter a short description for the theme, up to 4000 characters.
+theme.url_hint=Enter the LAST part of tht url for the theme, eg 'holiday'. Should NOT include a leading nor a trailing slash!
+theme.save_button_hint=Save the details in the form
+theme.cancel_button_hint=Abort changes & reset the form.
+theme.cancel_button_pressed_msg=cancel pressed
diff --git a/ccm-themedirector/src/com/arsdigita/themedirector/ThemeDirectorResources_fr.properties b/ccm-themedirector/src/com/arsdigita/themedirector/ThemeDirectorResources_fr.properties
index 49be7ac6e..d04943938 100755
--- a/ccm-themedirector/src/com/arsdigita/themedirector/ThemeDirectorResources_fr.properties
+++ b/ccm-themedirector/src/com/arsdigita/themedirector/ThemeDirectorResources_fr.properties
@@ -32,3 +32,9 @@ theme.undo.default_style=Default Style
theme.none=None
theme.save=Save
theme.set_default_theme=Default Theme
+theme.title_hint=Enter the title of the theme, up to 80 characters.
+theme.description_hint=Enter a short description for the theme, up to 4000 characters.
+theme.url_hint=Enter the LAST part of tht url for the theme, eg 'holiday'. Should NOT include a leading nor a trailing slash!
+theme.save_button_hint=Save the details in the form
+theme.cancel_button_hint=Abort changes & reset the form.
+theme.cancel_button_pressed_msg=cancel pressed
diff --git a/ccm-themedirector/src/com/arsdigita/themedirector/ui/ThemeForm.java b/ccm-themedirector/src/com/arsdigita/themedirector/ui/ThemeForm.java
index 13e6ab72a..3072f8490 100755
--- a/ccm-themedirector/src/com/arsdigita/themedirector/ui/ThemeForm.java
+++ b/ccm-themedirector/src/com/arsdigita/themedirector/ui/ThemeForm.java
@@ -52,6 +52,8 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.filefilter.DirectoryFileFilter;
import org.apache.log4j.Logger;
@@ -64,50 +66,68 @@ import org.apache.log4j.Logger;
*/
public class ThemeForm extends Form implements Cancellable, ThemeDirectorConstants {
+ /** Internal logger instance to faciliate debugging. Enable logging output
+ * by editing /WEB-INF/conf/log4j.properties int hte runtime environment
+ * and set com.arsdigita.themedirector.ui.ThemeForm=DEBUG by uncommenting
+ * or adding the line. */
private static final Logger s_log = Logger.getLogger(ThemeForm.class);
- private ThemeSelectionModel m_theme;
- private TextField m_title;
- private TextArea m_description;
- private TextField m_url;
- private SaveCancelSection m_buttons;
+ private final ThemeSelectionModel m_theme;
+ private final TextField m_title;
+ private final TextArea m_description;
+ private final TextField m_url;
+ private final SaveCancelSection m_buttons;
+ /**
+ * Constructor creats the input form to create a new theme or edit an
+ * existing one.
+ *
+ * @param name
+ * @param theme
+ */
public ThemeForm(String name,
ThemeSelectionModel theme) {
super(name, new GridPanel(2));
setClassAttr("simpleThemeForm");
setRedirecting(true);
- m_theme = theme;
+ m_theme = theme; // Initialize ThemeSelectionModel
+ // Add the Title input field
add(new Label(GlobalizationUtil.globalize("theme.title")));
m_title = new TextField(new StringParameter("title"));
+ // Experimental. We are migrating the Label if a widget as part of the
+ // widgets's xml properties.
+ m_title.setLabel(GlobalizationUtil.globalize("theme.title"));
m_title.addValidationListener(new NotEmptyValidationListener());
- m_title.setHint("Enter the title of the theme, up to 80 characters");
+ m_title.setHint(GlobalizationUtil.globalize("theme.title_hint"));
m_title.setSize(40);
add(m_title);
add(new Label(GlobalizationUtil.globalize("theme.description")));
m_description = new TextArea(new StringParameter("description"));
+ // Experimental, see above
+ m_description.setLabel(GlobalizationUtil.globalize("theme.description"));
m_description.setCols(40);
m_description.setRows(4);
- m_description.setHint(
- "Enter a short description for the theme, up to 4000 characters"
- );
+ m_description.setHint(GlobalizationUtil
+ .globalize("theme.description_hint"));
add(m_description);
add(new Label(GlobalizationUtil.globalize("theme.url")));
m_url = new TextField(new StringParameter("url"));
+ // Experimental, see above
+ m_url.setLabel(GlobalizationUtil.globalize("theme.url"));
m_url.addValidationListener(new NotEmptyValidationListener());
m_title.setSize(40);
- m_url.setHint(
- "Enter the url for the theme, eg 'holiday'"
- );
+ m_url.setHint(GlobalizationUtil.globalize("theme.url_hint"));
add(m_url);
m_buttons = new SaveCancelSection();
- m_buttons.getSaveButton().setHint("Save the details in the form");
- m_buttons.getCancelButton().setHint("Abort changes & reset the form");
+ m_buttons.getSaveButton().setHint(GlobalizationUtil
+ .globalize("theme.save_button_hint"));
+ m_buttons.getCancelButton().setHint(GlobalizationUtil
+ .globalize("theme.cancel_button_hint"));
add(m_buttons);
addSubmissionListener(new ThemeSubmissionListener());
@@ -116,23 +136,47 @@ public class ThemeForm extends Form implements Cancellable, ThemeDirectorConstan
addValidationListener(new ThemeValidationListener());
}
- // if this form is cancelled
+ /**
+ * Processed if this form is cancelled.
+ *
+ * @param s
+ * @return
+ */
+ @Override
public boolean isCancelled(PageState s) {
return m_buttons.getCancelButton().isSelected(s);
}
+ /**
+ *
+ */
private class ThemeSubmissionListener implements FormSubmissionListener {
+
+ /**
+ *
+ * @param e
+ * @throws FormProcessException
+ */
+ @Override
public void submitted(FormSectionEvent e)
- throws FormProcessException {
+ throws FormProcessException {
PageState state = e.getPageState();
if (m_buttons.getCancelButton().isSelected(state)) {
- throw new FormProcessException("cancel pressed");
+ throw new FormProcessException(
+ "cancel pressed",
+ GlobalizationUtil.globalize("theme.cancel_button_hint")
+ );
}
}
}
+ /**
+ * Initializes the theme form with appropriate values if theme already
+ * exists.
+ */
private class ThemeInitListener implements FormInitListener {
+ @Override
public void init(FormSectionEvent e)
throws FormProcessException {
PageState state = e.getPageState();
@@ -150,15 +194,34 @@ public class ThemeForm extends Form implements Cancellable, ThemeDirectorConstan
}
}
+ /**
+ * ProcessListener class to act upon the themedirector form input (after
+ * successful input validation if any). It's process method is the entry
+ * point.
+ */
private class ThemeProcessListener implements FormProcessListener {
+
+ /**
+ * Process the form input data. The data are first stored into the
+ * database and than the file system is synced if required. In case of
+ * a new theme the default theme files (if existent) are copied. If for
+ * an existing theme the name (url) has changed, the filesystem
+ * directories are modified accordingly.
+ *
+ * @param e
+ * @throws FormProcessException
+ */
+ @Override
public void process(FormSectionEvent e)
- throws FormProcessException {
+ throws FormProcessException {
+
PageState state = e.getPageState();
Theme theme = m_theme.getSelectedTheme(state);
String oldURL = null;
String newURL = null;
if (theme == null) {
+ /* We handle a new (created) theme. No previous values exist.*/
newURL = (String)m_url.getValue(state);
theme = new Theme((String)m_title.getValue(state),
(String)m_description.getValue(state),
@@ -171,7 +234,7 @@ public class ThemeForm extends Form implements Cancellable, ThemeDirectorConstan
theme.setURL(newURL);
}
- // only add the theme if it is published
+ // only add to the theme if it is published
if (theme.getLastPublishedUser() != null) {
Subsite.getConfig().addTheme(theme.getURL(), theme.getTitle());
}
@@ -180,24 +243,23 @@ public class ThemeForm extends Form implements Cancellable, ThemeDirectorConstan
Subsite.getConfig().removeTheme(oldURL);
}
- theme.save();
+ theme.save(); // save theme to database
m_theme.setSelectedObject(state, theme);
// now that the db part is done, we do the file IO
File newDirectory = null;
File oldDirectory = null;
try {
- // The WebAppRoot should be something like this:
- // /var/ccm-devel/web///webapps/ccm-ldn-theme;
+ // Determine the WebAppRoot should be something like this:
+ // /var/ccm-devel/web///webapps/libreccm;
File currentRoot = new File(Web.getServletContext().getRealPath("/"));
newDirectory = new File(currentRoot, DEV_THEMES_BASE_DIR +
newURL);
if (newDirectory.exists() && !newURL.equals(oldURL)) {
- // this means there is a file in the file system
- // but not in the database
- // this should never happen because "validate" should
- // catch it.
+ // this means there is a file in the file system but not in
+ // the database this should never happen because "validate"
+ // should catch it.
throw new UncheckedWrapperException
("The file " + newDirectory.getName() + " already " +
"exists in the file system but not in the " +
@@ -210,16 +272,17 @@ public class ThemeForm extends Form implements Cancellable, ThemeDirectorConstan
oldURL);
}
- if (oldURL == null || !oldDirectory.exists()) {
- // we make sure that the base directory exists and
- // then we copy the files over.
+ if ( oldURL == null || !oldDirectory.exists()) {
+ // we make sure that the base directory exists and then we
+ // copy the files over.
File baseDirectory = new File(currentRoot,
DEV_THEMES_BASE_DIR);
if (!baseDirectory.exists()) {
baseDirectory.mkdirs();
}
- copyDefaultFiles(newDirectory);
+ copyDefaultTheme(newDirectory,null);
+ // copyDefaultFiles(newDirectory);
if (oldDirectory != null && !oldDirectory.exists()) {
s_log.warn("We were asked to move files from " +
@@ -251,8 +314,9 @@ public class ThemeForm extends Form implements Cancellable, ThemeDirectorConstan
// the old directory...we need them to point to the
// new directory
DataCollection collection =
- SessionManager.getSession().retrieve
- (Site.BASE_DATA_OBJECT_TYPE);
+ SessionManager
+ .getSession()
+ .retrieve(Site.BASE_DATA_OBJECT_TYPE);
collection.addEqualsFilter(Site.STYLE_DIRECTORY,
oldURL);
while (collection.next()) {
@@ -270,10 +334,23 @@ public class ThemeForm extends Form implements Cancellable, ThemeDirectorConstan
}
}
+ /**
+ * ValöidatgionListener class to check the themedirector form input data.
+ * It's validate method is the entry point and executed when submitting
+ * the form.
+ */
private class ThemeValidationListener implements FormValidationListener {
+
+ /**
+ *
+ * @param e
+ * @throws FormProcessException
+ */
+ @Override
public void validate(FormSectionEvent e)
- throws FormProcessException {
+ throws FormProcessException {
PageState state = e.getPageState();
+
String url = (String)m_url.getValue(state);
validateURLForm(state, url);
validateURLUniqueness(state, url);
@@ -298,6 +375,9 @@ public class ThemeForm extends Form implements Cancellable, ThemeDirectorConstan
/**
* This checks the form of the url...specifically, we are only allowing
* [A-Z,a-z,0-9,_,-].
+ * @param state
+ * @param url
+ * @throws com.arsdigita.bebop.FormProcessException
*/
public void validateURLForm(PageState state, String url)
throws FormProcessException {
@@ -316,13 +396,14 @@ public class ThemeForm extends Form implements Cancellable, ThemeDirectorConstan
}
}
-
-
/**
- * This makes sure no other theme has the same URL
+ * This makes sure no other theme has the same URL
+ * @param state
+ * @param url
+ * @throws com.arsdigita.bebop.FormProcessException
*/
public void validateURLUniqueness(PageState state, String url)
- throws FormProcessException {
+ throws FormProcessException {
if ( url != null ) {
DataCollection collection = SessionManager.getSession()
@@ -341,10 +422,39 @@ public class ThemeForm extends Form implements Cancellable, ThemeDirectorConstan
}
}
+ /**
+ * Copies a complete directory containing the default theme to a newly
+ * created theme's directory without any filtering or other processing.
+ * It assumes, that the source directory contains a complete and working
+ * set of theme files.
+ *
+ * @param newThemeDirectory specifies the target directory. Must not
+ * be null.
+ * @param defaultThemeDirectory Directory containing a complete set of
+ * theme files intended as default theme.
+ * If null the default theme directory is
+ * retrieved from ThemeDirector config
+ *
+ * @throws IOException
+ */
+ private void copyDefaultTheme(File newThemeDirectory,
+ File defaultThemeDirectory) throws IOException {
+ if (defaultThemeDirectory == null) {
+ defaultThemeDirectory = new File(
+ Web.getServletContext().getRealPath("/")
+ + ThemeDirector.getConfig().getDefaultThemePath());
+ }
+
+ FileUtils.copyDirectory(defaultThemeDirectory,
+ newThemeDirectory);
+ }
/**
- * This copies the default theme files to the new directory that
- * is specified by the pass in File
+ * Copies the default theme files to the new directory using a
+ * Manifest file to determine the files to copy.
+ *
+ * @param newDirectory specifies the target directory
+ * @throws IOException
*/
private void copyDefaultFiles(File newDirectory) throws IOException {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
@@ -358,7 +468,8 @@ public class ThemeForm extends Form implements Cancellable, ThemeDirectorConstan
}
if ( !newDirectory.mkdirs() ) {
- throw new UncheckedWrapperException("Cannot create theme directory "+newDirectory.getAbsolutePath());
+ throw new UncheckedWrapperException("Cannot create theme directory "
+ +newDirectory.getAbsolutePath());
}
ManifestReader reader =
@@ -367,10 +478,19 @@ public class ThemeForm extends Form implements Cancellable, ThemeDirectorConstan
}
+ /**
+ *
+ */
private class FileWriterManifestReader extends ManifestReader {
- private File m_newDirectory;
- private String m_directoryFilter;
+ private final File m_newDirectory;
+ private final String m_directoryFilter;
+ /**
+ * Constructor.
+ *
+ * @param stream
+ * @param newDirectory
+ */
FileWriterManifestReader(InputStream stream, File newDirectory) {
super(stream);
m_newDirectory = newDirectory;
@@ -378,6 +498,13 @@ public class ThemeForm extends Form implements Cancellable, ThemeDirectorConstan
m_directoryFilter = ThemeDirector.getConfig().getDefaultThemePath();
}
+ /**
+ *
+ * @param is
+ * @param filePath
+ * @param isStyleFile
+ */
+ @Override
public void processManifestFileLine(InputStream is,
String filePath,
boolean isStyleFile) {
diff --git a/ccm-themedirector/src/com/arsdigita/themedirector/ui/ThemeValidationPanel.java b/ccm-themedirector/src/com/arsdigita/themedirector/ui/ThemeValidationPanel.java
index c333d3a5d..e21773686 100755
--- a/ccm-themedirector/src/com/arsdigita/themedirector/ui/ThemeValidationPanel.java
+++ b/ccm-themedirector/src/com/arsdigita/themedirector/ui/ThemeValidationPanel.java
@@ -42,6 +42,7 @@ import java.util.Collection;
import java.util.Iterator;
import com.arsdigita.templating.XSLTemplate;
import com.arsdigita.templating.WrappedTransformerException;
+import java.net.MalformedURLException;
import javax.xml.transform.ErrorListener;
import javax.xml.transform.TransformerException;
@@ -49,14 +50,19 @@ import javax.xml.transform.TransformerException;
import org.apache.log4j.Logger;
/**
- * This displays information about the results of running a validation
- * test on all of the stylesheets for a given theme. It also includes
- * links to "revalidate" and to return the viewing the theme.
+ * This displays information about the results of running a validation test
+ * on all of the stylesheets for a given theme. It also includes
+ * links to "revalidate" and to return the viewing the theme.
*
- * @author Randy Graebner <randyg@redhat.com>
+ * @author Randy Graebner <randyg@redhat.com>
*/
class ThemeValidationPanel extends GridPanel implements ThemeDirectorConstants {
+ /** Internal logger instance to faciliate debugging. Enable logging output
+ * by editing /WEB-INF/conf/log4j.properties int the runtime environment
+ * and set
+ * com.arsdigita.themedirector.ui.ThemeValidationPanel=DEBUG
+ * by uncommenting or adding the line. */
private static final Logger s_log =
Logger.getLogger(ThemeValidationPanel.class);
@@ -65,14 +71,16 @@ class ThemeValidationPanel extends GridPanel implements ThemeDirectorConstants {
RequestLocal m_listener;
/**
- * This creates a new validation panel
+ * This creates a new validation panel.
+ *
* @param model This is the selection model so that the panel knows
- * which theme to operation on
+ * which theme to operation on
* @param container This is the parent container that holds this theme.
- * When the user wants to quit validation and return to where they were,
- * the visibility of the passed in container inverted (if it is visible
- * then it becomes invisible, if it is invisible, it becomes visible) and
- * this item becomes invisible.
+ * When the user wants to quit validation and return
+ * to where they were, the visibility of the passed in
+ * container inverted (if it is visible then it becomes
+ * invisible, if it is invisible, it becomes visible) and
+ * this item becomes invisible.
*/
// TODO: passing in the container is a hackish way to do the visibility...
// is there a better way to do this?
@@ -80,8 +88,8 @@ class ThemeValidationPanel extends GridPanel implements ThemeDirectorConstants {
SimpleComponent parentContainer) {
super(1);
m_model = model;
- Label results =
- new Label(GlobalizationUtil.globalize("theme.validation_results"));
+ Label results = new Label(GlobalizationUtil
+ .globalize("theme.validation_results"));
results.setFontWeight(Label.BOLD);
add(results);
m_listener = new RequestLocal();
@@ -92,14 +100,16 @@ class ThemeValidationPanel extends GridPanel implements ThemeDirectorConstants {
new ActionLink(new Label(GlobalizationUtil.globalize
("theme.revalidate_theme")));
revalidateLink.addActionListener(new ActionListener() {
+ @Override
public void actionPerformed(ActionEvent e) {
validateStylesheets(e.getPageState());
}
});
add(revalidateLink);
- ToggleActionLink returnLink = new ToggleActionLink
- (new Label(GlobalizationUtil.globalize("theme.return_to_previous")));
+ ToggleActionLink returnLink = new ToggleActionLink(new Label(
+ GlobalizationUtil
+ .globalize("theme.return_to_previous")));
returnLink.addToggleComponent(this);
returnLink.addToggleComponent(parentContainer);
add(returnLink);
@@ -112,7 +122,7 @@ class ThemeValidationPanel extends GridPanel implements ThemeDirectorConstants {
* class but this is more clear as to what is being done.
*/
private class ToggleActionLink extends ActionLink implements ActionListener {
- private ArrayList m_components;
+ private final ArrayList m_components;
ToggleActionLink(Label name) {
super(name);
@@ -120,6 +130,7 @@ class ThemeValidationPanel extends GridPanel implements ThemeDirectorConstants {
addActionListener(this);
}
+ @Override
public void actionPerformed(ActionEvent e) {
Iterator iter = m_components.iterator();
PageState state = e.getPageState();
@@ -149,35 +160,45 @@ class ThemeValidationPanel extends GridPanel implements ThemeDirectorConstants {
/**
- * This method sets up the validation by finding the correct base
- * directory and setting up other necessary initialization variables
+ * This method sets up the validation by finding the correct base
+ * directory and setting up other necessary initialization variables.
+ *
+ * @param state
+ * @param listener
*/
private boolean validateStylesheets(PageState state,
LoggingErrorListener listener) {
- // this should verify the stylesheets and then present
- // any error messages that are found
+
+ /* Determine the theme to check */
Theme theme = m_model.getSelectedTheme(state);
-
- // The call to resolve returns a url similar to this:
- // http://localhost:9008/resource/ccm-ldn-theme,ROOT/themes/heirloom/apps/theme/xsl/index.xs
- //
- // TODO: This is VERY UGLY! Bad style to code a path into source code!
- // String base = "http://" + Web.getConfig().getHost().toString() +
- // "/resource/ccm-ldn-theme/";
- String base = "http://" + Web.getConfig().getHost().toString() +
- "/resource/ROOT/";
+
+ /* Determine the location in the servers file system */
File currentRoot = new File(Web.getServletContext().getRealPath("/"));
- File devDir = new File(currentRoot, DEV_THEMES_BASE_DIR +
- theme.getURL());
+ File devDir = new File(currentRoot,
+ DEV_THEMES_BASE_DIR + theme.getURL() );
- // TODO: There has to be a better way to do this
- String stylesheetPath = base +
- DEV_THEMES_BASE_DIR + theme.getURL();
+ /* Determine the URL to the stylesheets. Usually the URL is determined
+ by the templating system, based on a stylesheetPath.txt file
+ containing patterns to search for.
+
+ Developer's Note:
+ We used to use a 'resource' tag involing a resource servlet to
+ deliver the correct file either from database or filesystem. Ir would
+ require an URL similar to
+ http://localhost:9008/libreccm/resource/themes/heirloom/apps/theme/xsl/index.xs
+ where librecms is the context ccm happpens to be installed in.
+ Currently we bypass the resource servlet and access the filesystem
+ directly. Must be modified as soon as we deliver the theme from db. */
+ String stylesheetPath = "http://" + Web.getConfig().getHost().toString()
+ + Web.getWebappContextPath()
+ + DEV_THEMES_BASE_DIR + theme.getURL() ;
if (s_log.isDebugEnabled()) {
s_log.debug("Path is " + stylesheetPath);
}
+ // this should verify the stylesheets and then present
+ // any error messages that are found
checkFiles(devDir, stylesheetPath, listener);
return !listener.hasErrors();
@@ -189,7 +210,8 @@ class ThemeValidationPanel extends GridPanel implements ThemeDirectorConstants {
* the entire folder subtree, loading every single available xsl
* file.
*/
- private void checkFiles(File baseDirectory, String basePath,
+ private void checkFiles(File baseDirectory,
+ String basePath,
ErrorListener listener) {
File[] list = baseDirectory.listFiles(new XSLFileFilter());
if (list == null) {
@@ -203,43 +225,39 @@ class ThemeValidationPanel extends GridPanel implements ThemeDirectorConstants {
// future caught errors. This is sort of a hack but I am not
// sure of a better way around it
boolean transformUsesListener = true;
-
- for (int i = 0; i < list.length; i ++) {
- if (list[i].isDirectory()) {
- // Only check top level XSL - the rest are xsl:import'd
- //checkFiles(list[i], basePath + "/" + list[i].getName(),
- // listener);
+ for (File list1 : list) {
+ if (list1.isDirectory()) {
} else {
- String filePath = basePath + "/" + list[i].getName();
+ String filePath = basePath + "/" + list1.getName();
try {
URL stylesheetURL = new URL(filePath);
if (s_log.isDebugEnabled()) {
s_log.debug("Validating " + stylesheetURL);
}
XSLTemplate template = new XSLTemplate(stylesheetURL,
- listener);
+ listener);
} catch (WrappedTransformerException we) {
- if (transformUsesListener &&
- listener instanceof LoggingErrorListener &&
- !((LoggingErrorListener)listener).hasErrors()) {
+ if (transformUsesListener &&
+ listener instanceof LoggingErrorListener &&
+ !((LoggingErrorListener)listener).hasErrors()) {
transformUsesListener = false;
}
if (!transformUsesListener) {
- TransformerException transEx =
- (TransformerException)we.getRootCause();
+ TransformerException transEx =
+ (TransformerException)we.getRootCause();
try {
listener.error(transEx);
} catch (TransformerException transformerEx) {
- s_log.error("Error logging the exception " +
- transEx.getMessage(),
- transformerEx);
+ s_log.error("Error logging the exception " +
+ transEx.getMessage(),
+ transformerEx);
transEx.printStackTrace();
}
}
s_log.debug("Wrapper excpetion thrown");
- } catch (Exception exp) {
- s_log.warn("Error creating template that was not a " +
- " standard wrapper transformer exception.",
+ } catch (MalformedURLException exp) {
+ s_log.warn("Error creating template that was not a "
+ + "standard wrapper transformer exception.",
exp);
}
}
@@ -249,9 +267,10 @@ class ThemeValidationPanel extends GridPanel implements ThemeDirectorConstants {
/**
* This is simply used so that only directories and xsl files are
- * examined
+ * examined.
*/
private static class XSLFileFilter implements FileFilter {
+ @Override
public boolean accept(File pathname) {
return pathname.isDirectory() ||
pathname.getName().endsWith(".xsl");
@@ -260,8 +279,8 @@ class ThemeValidationPanel extends GridPanel implements ThemeDirectorConstants {
private class ValidationResults extends SimpleContainer {
- private Label m_noErrorsLabel;
- private Label m_errorsLabel;
+ private final Label m_noErrorsLabel;
+ private final Label m_errorsLabel;
ValidationResults() {
super();
@@ -299,8 +318,8 @@ class ThemeValidationPanel extends GridPanel implements ThemeDirectorConstants {
/**
- * if the collection size > 0 then it prints out the xml
- * to display the messages
+ * If the collection size > 0 then it prints out the xml
+ * to display the messages.
*/
private void printMessages(String name, Element parent,
Collection messages) {
diff --git a/ccm-themedirector/src/com/arsdigita/themedirector/ui/listeners/ApproveThemeActionListener.java b/ccm-themedirector/src/com/arsdigita/themedirector/ui/listeners/ApproveThemeActionListener.java
index b07b7cabb..8022575f8 100755
--- a/ccm-themedirector/src/com/arsdigita/themedirector/ui/listeners/ApproveThemeActionListener.java
+++ b/ccm-themedirector/src/com/arsdigita/themedirector/ui/listeners/ApproveThemeActionListener.java
@@ -44,23 +44,40 @@ import java.util.TreeSet;
import org.apache.log4j.Logger;
/**
- * This approves the theme and pushes it to the production file location
- * This action means that the user wants to approve the themes and
- * push them live. This is done by copying the files from
+ * This approves the theme and pushes it to the production file location
+ * This action means that the user wants to approve the themes and
+ * push them live. This is done by copying the files from the devel directory
+ * into the published directory.
*
* @author Randy Graebner <randyg@redhat.com>
*/
-public class ApproveThemeActionListener implements ThemeDirectorConstants, ActionListener {
+public class ApproveThemeActionListener implements ThemeDirectorConstants,
+ ActionListener {
- private static final Logger s_log =
- Logger.getLogger(ApproveThemeActionListener.class);
+ /** Internal logger instance to faciliate debugging. Enable logging output
+ * by editing /WEB-INF/conf/log4j.properties int the runtime environment
+ * and set
+ * com.arsdigita.themedirector.ui.listeners.ApproveThemeActionListener=DEBUG
+ * by uncommenting or adding the line. */
+ private static final Logger s_log = Logger.getLogger(
+ ApproveThemeActionListener.class);
- private ThemeSelectionModel m_model;
+ private final ThemeSelectionModel m_model;
+ /**
+ * Constructor, just stores the ThemeSelectionModel.
+ *
+ * @param model the ThemeSelectionModel
+ */
public ApproveThemeActionListener(ThemeSelectionModel model) {
m_model = model;
}
+ /**
+ *
+ * @param e
+ */
+ @Override
public void actionPerformed(ActionEvent e) {
// First, we rename the current production directory
// so that if there is an exception, we can try to move it
diff --git a/ccm-themedirector/src/com/arsdigita/themedirector/util/ManifestReader.java b/ccm-themedirector/src/com/arsdigita/themedirector/util/ManifestReader.java
index b356dccf4..5813dc905 100755
--- a/ccm-themedirector/src/com/arsdigita/themedirector/util/ManifestReader.java
+++ b/ccm-themedirector/src/com/arsdigita/themedirector/util/ManifestReader.java
@@ -19,32 +19,37 @@
package com.arsdigita.themedirector.util;
+import com.arsdigita.themedirector.ThemeDirector;
+import com.arsdigita.themedirector.ThemeDirectorConstants;
+import com.arsdigita.util.UncheckedWrapperException;
+import com.arsdigita.web.Web;
+
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.LineNumberReader;
-import java.util.HashMap;
-import com.arsdigita.web.Web;
-import com.arsdigita.util.UncheckedWrapperException;
import java.util.Collection;
-import com.arsdigita.themedirector.ThemeDirector;
-import com.arsdigita.themedirector.ThemeDirectorConstants;
+import java.util.HashMap;
import javax.servlet.ServletContext;
+
import org.apache.log4j.Logger;
/**
- * This is a utility class that will take in a manifest file and
- * read it and then make calls to methods for each file that is found.
- * In a typical usage, code will subclass this so that certain methods
- * will write to different places. For instance, some code may
- * override the "processManifestFileLine" to write the contents to
- * the file system while another may write it to a zip file.
+ * This is a utility class that will take in a manifest file, read it, and
+ * then make calls to methods for each file that is found.
+ * In a typical usage, code will subclass this so that certain methods will
+ * write to different places. For instance, some code may override the
+ * "processManifestFileLine" to write the contents to the file system
+ * while another may write it to a zip file.
*/
public abstract class ManifestReader implements ThemeDirectorConstants {
- private static final Logger s_log =
- Logger.getLogger(ManifestReader.class);
+ /** Internal logger instance to faciliate debugging. Enable logging output
+ * by editing /WEB-INF/conf/log4j.properties int hte runtime environment
+ * and set com.arsdigita.themedirector.util.ManifestReader=DEBUG by
+ * uncommenting or adding the line. */
+ private static final Logger s_log = Logger.getLogger(ManifestReader.class);
private InputStream m_stream;
private String m_fileName;
@@ -52,8 +57,10 @@ public abstract class ManifestReader implements ThemeDirectorConstants {
private HashMap m_actualContextList;
/**
- * This takes in the actual input stream that is the Manifest File
- * so that the input stream can be correctly read
+ * This takes in the actual input stream that is the Manifest File
+ * so that the input stream can be correctly read.
+ *
+ * @param stream the input stream to read
*/
public ManifestReader(InputStream stream) {
this(stream, null);
@@ -64,6 +71,8 @@ public abstract class ManifestReader implements ThemeDirectorConstants {
* so that the input stream can be correctly read. It also
* takes in the fileName so that it can be used in error messages
* if there is an error.
+ * @param stream the input stream to read
+ * @param fileName
*/
public ManifestReader(InputStream stream, String fileName) {
this(stream, fileName, null);
@@ -77,11 +86,11 @@ public abstract class ManifestReader implements ThemeDirectorConstants {
* @param stream The input stream to read
* @param fileName The name of the file we are reading that will
* be displayed in the case of an error.
- * @param possibleServletContext The servlet context to try to use
- * when looking for files listed in the Manifest. This should be
- * set when it is know that the manifest file specifies files
- * that are located under a different webapps. If the
- * file is not found under this context or this context is null
+ * @param possibleServletContext The servlet context to try to use when
+ * looking for files listed in the Manifest. This should be set
+ * when it is known that the manifest file specifies files that
+ * are located under a different webapps. If the file ist not
+ * found under this context or this context is null
* then the file tries to use the default ServletContext
*/
public ManifestReader(InputStream stream, String fileName,
@@ -94,13 +103,20 @@ public abstract class ManifestReader implements ThemeDirectorConstants {
/**
- * this is the name of the file that is being parsed. This will
- * return null if the name has not been set
+ * Retrieves the name of the file that is being parsed. Will return null
+ * if the name has not been set.
+ *
+ * @return file name if set, otherwise null
*/
public String getFileName() {
return m_fileName;
}
+ /**
+ * Set the name of the file that is being parsed.
+ *
+ * @param fileName
+ */
public void setFileName(String fileName) {
m_fileName = fileName;
}
@@ -112,17 +128,18 @@ public abstract class ManifestReader implements ThemeDirectorConstants {
* this method will only really do anything once.
*/
public void processFile() {
- LineNumberReader lines =
- new LineNumberReader(new InputStreamReader(m_stream));
- Collection extensions = ThemeDirector.getConfig()
- .getDownloadFileExtensions();
- try {
- String line = lines.readLine();
- while (line != null) {
- line = line.trim();
+ LineNumberReader lines = new LineNumberReader(
+ new InputStreamReader(m_stream));
+ Collection extensions = ThemeDirector.getConfig()
+ .getDownloadFileExtensions();
- int fileExtensionIndex = line.lastIndexOf(".");
+ try {
+ String line = lines.readLine();
+ while (line != null) {
+ line = line.trim();
+
+ int fileExtensionIndex = line.lastIndexOf(".");
// We check the following things to set the boolean
// indicating if it is a file that should
@@ -134,70 +151,77 @@ public abstract class ManifestReader implements ThemeDirectorConstants {
// extensions as specified in the config file
// 4. the file starts with the default directory and is
// not just the directory itself
- boolean fileForDownload = fileExtensionIndex > -1 &&
- line.length() > (fileExtensionIndex+1) &&
- extensions.contains(line.substring(fileExtensionIndex+1)
- .toLowerCase());
+ boolean fileForDownload = fileExtensionIndex > -1
+ && line.length() > (fileExtensionIndex+1)
+ && extensions.contains(line.substring(fileExtensionIndex+1)
+ .toLowerCase());
- // get the stream from the WAR or file system
- InputStream stream =
- getResourceAsStream(line, m_possibleServletContext);
+ // get the stream from the WAR or file system
+ InputStream stream = getResourceAsStream(line,
+ m_possibleServletContext);
- if (stream == null) {
- s_log.debug
- (m_fileName + ": " +
- lines.getLineNumber() +
- ": no such resource '" + line + "'");
- } else {
- processManifestFileLine(stream, line, fileForDownload);
-
- stream.close();
- }
- line = lines.readLine();
- }
- } catch (IOException e) {
- throw new UncheckedWrapperException
- ("Error with " + m_fileName + ": " +
- lines.getLineNumber(), e);
- } finally {
- try {
- m_stream.close();
- }
- catch (IOException e) {
- throw new UncheckedWrapperException(e);
+ if (stream == null) {
+ s_log.debug(m_fileName + ": " + lines.getLineNumber()
+ + ": no such resource '" + line + "'");
+ } else {
+ processManifestFileLine(stream, line, fileForDownload);
+ stream.close();
}
+ line = lines.readLine();
}
+ } catch (IOException e) {
+ throw new UncheckedWrapperException("Error with " + m_fileName
+ + ": "
+ + lines.getLineNumber(), e);
+ } finally {
+ try {
+ m_stream.close();
+ }
+ catch (IOException e) {
+ throw new UncheckedWrapperException(e);
+ }
+ }
}
/**
- * This provides a way for child classes to look for the resource
- * in multiple places. By default, it only looks in the ServletContext
+ * This provides a way for child classes to look for the resource in
+ * multiple places. By default, it only looks in the ServletContext.
+ *
+ * @param line
+ * @param possibleServletContext
+ * @return stream, may be null
*/
protected InputStream getResourceAsStream(String line,
String possibleServletContext) {
InputStream stream = null;
+
if (possibleServletContext != null) {
- stream = Web.getServletContext().getContext(possibleServletContext)
- .getResourceAsStream(line);
+ stream = Web.getServletContext() // gets the servlet context of
+ // the current thread
+ .getContext(possibleServletContext)
+ .getResourceAsStream(line);
}
if (stream != null) {
- setActualContext
- (line,
- Web.getServletContext().getContext(possibleServletContext));
+ setActualContext(line,
+ Web.getServletContext()
+ .getContext(possibleServletContext));
} else {
- stream = Web.getServletContext().getResourceAsStream(line);
+ stream = Web.getServletContext() // servlet ctx of actual thread
+ .getResourceAsStream(line);
if (stream == null) {
// this means that the file is not under the passed in
- // context or the default context so let's check the "ROOT"
+ // context nor the default context so let's check the "ROOT"
// context
- stream = Web.getServletContext().getContext(ROOT_WEBAPP_PATH)
- .getResourceAsStream(line);
- if (stream != null) {
- setActualContext(line, Web.getServletContext()
- .getContext(ROOT_WEBAPP_PATH));
- }
+ // DEPRECATED. CCM may be installed at any context, in many
+ // cases dedicatedly no longer in ROOT
+ // stream = Web.getServletContext().getContext(ROOT_WEBAPP_PATH)
+ // .getResourceAsStream(line);
+ // if (stream != null) {
+ // setActualContext(line, Web.getServletContext()
+ // .getContext(ROOT_WEBAPP_PATH));
+ // }
} else {
setActualContext(line, Web.getServletContext());
}
@@ -207,14 +231,22 @@ public abstract class ManifestReader implements ThemeDirectorConstants {
/**
- * This provides subclasses with access to the actual ServletContext
- * where the line is found. The info for the line should be available
- * when processManifestFileLine is called for a given line
+ * This provides subclasses with access to the actual ServletContext
+ * where the line is found. The info for the line should be available
+ * when processManifestFileLine is called for a given line.
+ *
+ * @param line
+ * @return
*/
protected ServletContext getActualContext(String line) {
return (ServletContext)m_actualContextList.get(line);
}
+ /**
+ *
+ * @param line
+ * @param context
+ */
protected void setActualContext(String line, ServletContext context) {
m_actualContextList.put(line, context);
}
diff --git a/ccm-themedirector/src/com/arsdigita/themedirector/util/ThemeDevelopmentFileManager.java b/ccm-themedirector/src/com/arsdigita/themedirector/util/ThemeDevelopmentFileManager.java
index 312887d47..15fe09e62 100755
--- a/ccm-themedirector/src/com/arsdigita/themedirector/util/ThemeDevelopmentFileManager.java
+++ b/ccm-themedirector/src/com/arsdigita/themedirector/util/ThemeDevelopmentFileManager.java
@@ -40,8 +40,12 @@ import org.apache.log4j.Logger;
*/
public class ThemeDevelopmentFileManager extends ThemeFileManager {
- private static Logger s_log =
- Logger.getLogger(ThemeDevelopmentFileManager.class);
+ /** Internal logger instance to faciliate debugging. Enable logging output
+ * by editing /WEB-INF/conf/log4j.properties int hte runtime environment
+ * and set com.arsdigita.themedirector.util.ThemeDevelopmentFileManager=DEBUG
+ * by uncommenting or adding the line. */
+ private static Logger s_log = Logger
+ .getLogger(ThemeDevelopmentFileManager.class);
// The code in this class borrows heavily from
// com.arsdigita.cms.publishToFile.FileManager
@@ -51,13 +55,16 @@ public class ThemeDevelopmentFileManager extends ThemeFileManager {
/**
* Constructor just delegates to super class.
+ *
* @param startupDelay
* @param pollDelay
* @param baseDirectory
*/
protected ThemeDevelopmentFileManager(int startupDelay, int pollDelay,
String baseDirectory) {
- super(s_log, startupDelay, pollDelay, baseDirectory);
+
+ super(s_log, // Injects it's own logger
+ startupDelay, pollDelay, baseDirectory); // to the parent class methods!
}
diff --git a/ccm-themedirector/src/com/arsdigita/themedirector/util/ThemeFileManager.java b/ccm-themedirector/src/com/arsdigita/themedirector/util/ThemeFileManager.java
index 8bfe3e676..4510f9e35 100755
--- a/ccm-themedirector/src/com/arsdigita/themedirector/util/ThemeFileManager.java
+++ b/ccm-themedirector/src/com/arsdigita/themedirector/util/ThemeFileManager.java
@@ -16,16 +16,12 @@
package com.arsdigita.themedirector.util;
import com.arsdigita.themedirector.Theme;
-import com.arsdigita.themedirector.ThemeDirector;
import com.arsdigita.themedirector.ThemeCollection;
import com.arsdigita.themedirector.ThemeDirectorConstants;
import com.arsdigita.themedirector.ThemeFileCollection;
import com.arsdigita.persistence.SessionManager;
import com.arsdigita.persistence.TransactionContext;
import com.arsdigita.themedirector.dispatcher.InternalThemePrefixerServlet;
-import com.arsdigita.web.Application;
-import com.arsdigita.web.ApplicationCollection;
-import com.arsdigita.web.Web;
import java.io.File;
import java.io.FileOutputStream;
@@ -38,8 +34,9 @@ import org.apache.log4j.Logger;
/**
- * Class for polling the database to look for new/updated files in
- * the ThemeFile table.
+ * Class providing client classes (as FileManager for development and published
+ * themes) with base methods for polling the database to look for new/updated
+ * files in the ThemeFile table.
*
* For "published" files, It goes through each Theme and looks at the
* last time it was published. If the last time published > last
@@ -52,15 +49,14 @@ import org.apache.log4j.Logger;
* then it writes out the new file. If the timestamp on the file system
* is newer, it ignores the file.
*
- *
* @author Randy Graebner
- *
* @version $Revision: #2 $ $DateTime: 2004/01/30 17:24:49 $
*/
public abstract class ThemeFileManager extends Thread
implements ThemeDirectorConstants {
- /** Internal logger instance to faciliate debugging */
+ /** Internal logger instance to faciliate debugging. Carries over the
+ * logger instance from the client child which actually does the work. */
private final Logger m_log;
// The code in this class borrows heavily from
@@ -89,8 +85,10 @@ public abstract class ThemeFileManager extends Thread
* @param pollDelay
* @param baseDirectory
*/
- protected ThemeFileManager(Logger log, int startupDelay, int pollDelay,
- String baseDirectory) {
+ protected ThemeFileManager(Logger log,
+ int startupDelay,
+ int pollDelay,
+ String baseDirectory) {
m_log = log;
m_startupDelay = startupDelay;
m_pollDelay = pollDelay;
@@ -122,6 +120,7 @@ public abstract class ThemeFileManager extends Thread
* Watch file for entries to process. The main routine that starts
* file processing.
*/
+ @Override
public void run() {
m_log.info("Start polling file in " + m_startupDelay + "s.");
if (m_lastRunDate == null) {
@@ -129,7 +128,7 @@ public abstract class ThemeFileManager extends Thread
sleepSeconds(m_startupDelay);
}
m_log.info("Polling file every " + m_pollDelay + "s.");
- while ( (sleepSeconds(m_pollDelay) || m_ignoreInterrupt)
+ while ( (sleepSeconds(m_pollDelay) || m_ignoreInterrupt)
&& m_keepWatchingFiles ) {
// Get the last run date before we do anything,
// so we can be sure that we do not miss any themes
@@ -186,6 +185,8 @@ public abstract class ThemeFileManager extends Thread
* This allows an outside piece of code to force an automatic update
* on a single theme instead of making it wait for the thread to wake
* up.
+ *
+ * @param theme
*/
public void updateThemeNow(Theme theme) {
updateTheme(theme);
@@ -194,13 +195,15 @@ public abstract class ThemeFileManager extends Thread
/**
- * This returns the base directory to use when writing out files
- * THIS IS A HACK BECAUSE IT REQUIRES A SERVER TO BE RUNNING
+ * This returns the base directory to use when writing out files.
+ * THIS IS A HACK BECAUSE IT REQUIRES A SERVER TO BE RUNNING.
+ *
+ * @return
*/
protected String getBaseDirectory() {
if (m_baseDirectory == null) {
- // Because the constructor sets the base deirectory this should
+ // Because the constructor sets the base directory this should
// never happen, but just in case ....
// ThemeDirector may execute in a different web application context
// as core oder CMS. To determine the actual context we may ask
@@ -231,13 +234,18 @@ public abstract class ThemeFileManager extends Thread
}
/**
- * this typically returns something like "getBaseDirectory() + PUB_DIR"
+ * This typically returns something like "getBaseDirectory() + PUB_DIR".
+ *
+ * @return
*/
protected abstract String getManagerSpecificDirectory();
/**
- * This allows subclasses to filter the collection as appropriate
- * (e.g. only return "live" files or only "draft" files).
+ * This allows subclasses to filter the collection as appropriate.
+ * (e.g. only return "live" files or only "draft" files).
+ *
+ * @param theme
+ * @return
*/
protected abstract ThemeFileCollection getThemeFilesCollection(Theme theme);
@@ -268,9 +276,11 @@ public abstract class ThemeFileManager extends Thread
*/
/**
- * This looks at all of the files in the db for the passed in theme
- * and makes sure that this servers file system has all of the
- * updated files.
+ * This looks at all of the files in the db for the passed in theme
+ * and makes sure that this servers file system has all of the
+ * updated files.
+ *
+ * @param theme
*/
protected void updateTheme(Theme theme) {
String stub = getManagerSpecificDirectory();
@@ -329,7 +339,10 @@ public abstract class ThemeFileManager extends Thread
/***
- * Sleep for n seconds
+ * Sleep for n seconds.
+ *
+ * @param n
+ * @return
***/
protected boolean sleepSeconds(long n) {
try {