From 3f6b6a7d2868a7acd24ef34e19da1e3fe99fc33a Mon Sep 17 00:00:00 2001 From: j2blake Date: Fri, 30 Sep 2011 22:10:39 +0000 Subject: [PATCH] NIHVIVO-1810 Change the way that the default theme and the list of available themes are handled. If the application is configured to use a theme that is not found, it will throw a warning on the StartupStatus and use the default theme instead. --- .../vitro/webapp/beans/ApplicationBean.java | 129 ++++++++++-------- .../edit/ApplicationBeanRetryController.java | 3 +- .../servlet/setup/DefaultThemeSetup.java | 41 ------ .../webapp/servlet/setup/ThemeInfoSetup.java | 126 +++++++++++++++++ .../vitro/webapp/utils/ThemeUtils.java | 45 ------ .../WEB-INF/resources/startup_listeners.txt | 6 +- 6 files changed, 200 insertions(+), 150 deletions(-) delete mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/DefaultThemeSetup.java create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/ThemeInfoSetup.java delete mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/utils/ThemeUtils.java diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/beans/ApplicationBean.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/beans/ApplicationBean.java index 004b9d4f8..bcf83a979 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/beans/ApplicationBean.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/beans/ApplicationBean.java @@ -2,21 +2,10 @@ package edu.cornell.mannlib.vitro.webapp.beans; -/** - * @version 2 2005-09-14 - * @author Brian Caruso, Jon Corson-Rikert - * - * UPDATES: - * 2006-03-13 jcr minor changes having to do with browse functionality; removing old commented out code and comments - * 2005-10-19 jcr added variables and methods to retrieve MAX PORTAL ID from database and use that and minSharedPortalId/maxSharedPortalId - * to get rid of need for ALL CALS RESEARCH - * 2005-09-14 bdc34 modified to initialize itself from database and store static instance in class - * 2005-07-05 JCR added onlyCurrent and onlyPublic to get rid of constants stuck here and there in the code - * 2005-06-14 JCR added boolean initialized value to help detect when settings come from current site database - * - */ - import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import javax.servlet.ServletContext; @@ -25,12 +14,8 @@ import org.apache.commons.logging.LogFactory; /** * This object is intended to represent the single row of data in the table application. - * - * @author jc55 - * */ public class ApplicationBean { - private static final Log log = LogFactory.getLog(ApplicationBean.class); public final static int CALS_SEARCHBOX_SIZE = 25; @@ -43,7 +28,7 @@ public class ApplicationBean { private final static String DEFAULT_ROOT_LOGOTYPE_TITLE = ""; // Value gets set in default theme setup context listener at application startup - public static String DEFAULT_THEME_DIR_FROM_CONTEXT = null; + public static ThemeInfo themeInfo = new ThemeInfo(null, "no_default_theme", new ArrayList()); // Default initializations, which may be overwritten in the AppBeanMapper // but are otherwise not changed there @@ -135,17 +120,9 @@ public class ApplicationBean { copyrightAnchor = string_val; } - public void setThemeDir(String string_val) { - if( string_val == null || string_val.length() == 0 - || "default".equalsIgnoreCase(string_val) - || "portal".equalsIgnoreCase(string_val) - || "null".equalsIgnoreCase(string_val) - || " ".equalsIgnoreCase(string_val) ) - themeDir = DEFAULT_THEME_DIR_FROM_CONTEXT; - else - themeDir = string_val; - } - + public void setThemeDir(String string_val) { + themeDir = string_val; + } /*************************** GET functions ****************************/ @@ -217,38 +194,72 @@ public class ApplicationBean { * @return */ public String getThemeDir(){ - return (themeDir != null && themeDir.length()>0) - ? themeDir - : DEFAULT_THEME_DIR_FROM_CONTEXT; + if (themeInfo.isValidThemeDir(themeDir)) { + return themeDir; + } else { + return themeInfo.getDefaultThemeDir(); + } } /**********************************************************************/ - - public boolean themeDirExists(){ - String themeDir = this.getThemeDir(); - if( themeDir == null || themeDir.length() < 1 ){ - log.error("Application has no themeDir/stylesheet set in the db." ); - return false; - } - File dir = new File(themeDir); - if( !dir.exists() ){ - log.error("Application: the themeDir/stylesheet " - + dir.getAbsolutePath()+ " does not exist."); - return false; - } - if( !dir.isDirectory() ){ - log.error("Application: themeDir/stylesheet " - + dir.getAbsolutePath() + " is not a directory."); - return false; - } - if( !dir.canRead() ){ - log.error("Application: themeDir/stylesheet " - + dir.getAbsolutePath() + " is not readable."); - return false; - } - return true; - } - + /** + * Hold the names of the available themes, the name of the default theme, + * and the base directory that contains the theme directories. + * + * The theme names are stored as simple strings, like "wilma". + * + * To be backwards compatible, we need to be able to test a string like + * "themes/wilma/ to see whether it is available, or to return the default + * directory in that form. + */ + public static class ThemeInfo { + private final File themesBaseDir; + private final String defaultThemeName; + private final List themeNames; + + public ThemeInfo(File themesBaseDir, String defaultThemeName, + List themeNames) { + this.themesBaseDir = themesBaseDir; + this.defaultThemeName = defaultThemeName; + this.themeNames = Collections + .unmodifiableList(new ArrayList(themeNames)); + } + + public static String themeNameFromDir(String themeDir) { + if (themeDir == null) { + return themeDir; + } + if (!themeDir.startsWith("themes/") || !themeDir.endsWith("/")) { + return themeDir; + } + return themeDir.substring(7, themeDir.length() - 1); + } + + public boolean isValidThemeDir(String themeDir) { + if (themeDir == null) { + return false; + } + return themeNames.contains(themeNameFromDir(themeDir)); + } + + public String getDefaultThemeDir() { + return "themes/" + defaultThemeName + "/"; + } + + public File getThemesBaseDir() { + return themesBaseDir; + } + + public String getDefaultThemeName() { + return defaultThemeName; + } + + public List getThemeNames() { + return themeNames; + } + + } + } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/ApplicationBeanRetryController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/ApplicationBeanRetryController.java index 2ef05fee1..727ec894a 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/ApplicationBeanRetryController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/ApplicationBeanRetryController.java @@ -26,7 +26,6 @@ import edu.cornell.mannlib.vitro.webapp.beans.ApplicationBean; import edu.cornell.mannlib.vitro.webapp.controller.Controllers; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.dao.ApplicationDao; -import edu.cornell.mannlib.vitro.webapp.utils.ThemeUtils; public class ApplicationBeanRetryController extends BaseEditController { @@ -118,7 +117,7 @@ public class ApplicationBeanRetryController extends BaseEditController { // Get the available themes ServletContext sc = getServletContext(); boolean doSort = true; - ArrayList themeNames = ThemeUtils.getThemes(sc, doSort); + List themeNames = ApplicationBean.themeInfo.getThemeNames(); // Create the list of theme Options String currentThemeDir = application.getThemeDir(); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/DefaultThemeSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/DefaultThemeSetup.java deleted file mode 100644 index adaad7662..000000000 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/DefaultThemeSetup.java +++ /dev/null @@ -1,41 +0,0 @@ -/* $This file is distributed under the terms of the license in /doc/license.txt$ */ - -package edu.cornell.mannlib.vitro.webapp.servlet.setup; - -import java.util.ArrayList; - -import javax.servlet.ServletContext; -import javax.servlet.ServletContextEvent; -import javax.servlet.ServletContextListener; - -import edu.cornell.mannlib.vitro.webapp.beans.ApplicationBean; -import edu.cornell.mannlib.vitro.webapp.utils.ThemeUtils; - -public class DefaultThemeSetup implements ServletContextListener { - - // Set default theme based on themes present on the file system - @Override - public void contextInitialized(ServletContextEvent event) { - // Find the themes directory in the file system - ServletContext sc = event.getServletContext(); - boolean doSort = true; - ArrayList themeNames = ThemeUtils.getThemes(sc, doSort); - - String defaultTheme; - if (themeNames.contains("vitro")) { - defaultTheme = "vitro"; - } - else { - defaultTheme = themeNames.get(0); - } - - String defaultThemeDir = "themes/" + defaultTheme + "/"; - // Define as a static variable of Portal so getThemeDir() method of portal can access it. - ApplicationBean.DEFAULT_THEME_DIR_FROM_CONTEXT = defaultThemeDir; - } - - @Override - public void contextDestroyed(ServletContextEvent event) { - // nothing to do here - } -} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/ThemeInfoSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/ThemeInfoSetup.java new file mode 100644 index 000000000..92547ce2a --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/ThemeInfoSetup.java @@ -0,0 +1,126 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.servlet.setup; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.servlet.ServletContext; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import com.hp.hpl.jena.ontology.OntModel; +import com.hp.hpl.jena.rdf.model.Literal; +import com.hp.hpl.jena.rdf.model.Property; +import com.hp.hpl.jena.rdf.model.RDFNode; +import com.hp.hpl.jena.shared.Lock; +import com.hp.hpl.jena.util.iterator.ClosableIterator; + +import edu.cornell.mannlib.vitro.webapp.beans.ApplicationBean; +import edu.cornell.mannlib.vitro.webapp.beans.ApplicationBean.ThemeInfo; +import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; +import edu.cornell.mannlib.vitro.webapp.dao.jena.ModelContext; +import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus; + +public class ThemeInfoSetup implements ServletContextListener { + private static final Log log = LogFactory.getLog(ThemeInfoSetup.class); + + // Set default theme based on themes present on the file system + @Override + public void contextInitialized(ServletContextEvent sce) { + ServletContext ctx = sce.getServletContext(); + StartupStatus ss = StartupStatus.getBean(ctx); + + String themeDirPath = ctx.getRealPath("/themes"); + if (themeDirPath == null) { + throw new IllegalStateException( + "Application does not have a /themes directory."); + } + File themesBaseDir = new File(themeDirPath); + + List themeNames = getThemeNames(themesBaseDir); + log.debug("themeNames: " + themeNames); + if (themeNames.isEmpty()) { + ss.fatal(this, "The application contains no themes. '" + + themesBaseDir.getAbsolutePath() + + "' has no child directories."); + } + + String defaultThemeName = "vitro"; + if (!themeNames.contains(defaultThemeName)) { + defaultThemeName = themeNames.get(0); + } + log.debug("defaultThemeName: " + defaultThemeName); + + String currentThemeName = getCurrentThemeName(ctx); + log.debug("currentThemeName: " + currentThemeName); + if ((currentThemeName != null) && (!currentThemeName.isEmpty()) + && (!themeNames.contains(currentThemeName))) { + ss.warning(this, "The current theme selection is '" + + currentThemeName + + "', but that theme is not available. The '" + + defaultThemeName + "' theme will be used instead. " + + "Go to the Site Admin page and choose " + + "\"Site Information\" to select a theme."); + } + + ApplicationBean.themeInfo = new ThemeInfo(themesBaseDir, + defaultThemeName, themeNames); + ss.info(this, ", current theme: " + currentThemeName + + "default theme: " + defaultThemeName + ", available themes: " + + themeNames); + } + + /** Get a list of the names of available themes, sorted alphabetically. */ + private List getThemeNames(File themesBaseDir) { + ArrayList themeNames = new ArrayList(); + + for (File child : themesBaseDir.listFiles()) { + if (child.isDirectory()) { + themeNames.add(child.getName()); + } + } + + Collections.sort(themeNames, String.CASE_INSENSITIVE_ORDER); + return themeNames; + } + + private String getCurrentThemeName(ServletContext ctx) { + OntModel ontModel = ModelContext.getBaseOntModelSelector(ctx) + .getApplicationMetadataModel(); + + ontModel.enterCriticalSection(Lock.READ); + try { + Property property = ontModel + .getProperty(VitroVocabulary.PORTAL_THEMEDIR); + ClosableIterator nodes = ontModel + .listObjectsOfProperty(property); + try { + if (nodes.hasNext()) { + String themeDir = ((Literal) nodes.next()).getString(); + return ThemeInfo.themeNameFromDir(themeDir); + } else { + return null; + } + } finally { + nodes.close(); + } + } catch (Exception e) { + log.error(e, e); + return null; + } finally { + ontModel.leaveCriticalSection(); + } + } + + @Override + public void contextDestroyed(ServletContextEvent event) { + // nothing to do here + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/ThemeUtils.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/ThemeUtils.java deleted file mode 100644 index 9675cf7fe..000000000 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/ThemeUtils.java +++ /dev/null @@ -1,45 +0,0 @@ -/* $This file is distributed under the terms of the license in /doc/license.txt$ */ - -package edu.cornell.mannlib.vitro.webapp.utils; - -import java.io.File; -import java.util.ArrayList; -import java.util.Collections; - -import javax.servlet.ServletContext; - -public class ThemeUtils { - - private ThemeUtils() { - throw new AssertionError(); - } - - public static ArrayList getThemes(ServletContext sc, boolean doSort) { - - // Find the themes directory on the file system - String themesDirName = sc.getRealPath("/themes"); - File themesDir = new File(themesDirName); - - // Get the children of the themes directory and their names - File[] children = themesDir.listFiles(); - String[] childNames = themesDir.list(); - - // Create a list of valid themes - ArrayList themeNames = new ArrayList(childNames.length); - for (int i = 0; i < children.length; i++) { - // Get only directories, not files - if (children[i].isDirectory()) { - themeNames.add(childNames[i]); - } - } - - // File.list() does not guarantee a specific order, so sort alphabetically - if (doSort) { - Collections.sort(themeNames); - } - - return themeNames; - - } - -} diff --git a/webapp/web/WEB-INF/resources/startup_listeners.txt b/webapp/web/WEB-INF/resources/startup_listeners.txt index 1a6bc2ad0..a2bbc32d4 100644 --- a/webapp/web/WEB-INF/resources/startup_listeners.txt +++ b/webapp/web/WEB-INF/resources/startup_listeners.txt @@ -11,9 +11,6 @@ edu.cornell.mannlib.vitro.webapp.config.RevisionInfoSetup edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailFactory$Setup -# DefaultThemeSetup needs to run before the JenaDataSourceSetup to allow creation of default portal and tab -edu.cornell.mannlib.vitro.webapp.servlet.setup.DefaultThemeSetup - # Comment out this listener to run Vitro without a database # If used, this listener must be run before JenaDataSourceSetup edu.cornell.mannlib.vitro.webapp.servlet.setup.JenaPersistentDataSourceSetup @@ -37,6 +34,9 @@ edu.cornell.mannlib.vitro.webapp.servlet.setup.FileGraphSetup edu.cornell.mannlib.vitro.webapp.servlet.setup.SimpleReasonerSetup +# Must run after JenaDataSourceSetup +edu.cornell.mannlib.vitro.webapp.servlet.setup.ThemeInfoSetup + edu.cornell.mannlib.vitro.webapp.auth.permissions.PermissionSetsLoader edu.cornell.mannlib.vitro.webapp.auth.policy.bean.PropertyRestrictionPolicyHelper$Setup