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.

This commit is contained in:
j2blake 2011-09-30 22:10:39 +00:00
parent 0ed27c1d51
commit 3f6b6a7d28
6 changed files with 200 additions and 150 deletions

View file

@ -2,21 +2,10 @@
package edu.cornell.mannlib.vitro.webapp.beans; 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.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.servlet.ServletContext; 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. * This object is intended to represent the single row of data in the table application.
*
* @author jc55
*
*/ */
public class ApplicationBean { public class ApplicationBean {
private static final Log log = LogFactory.getLog(ApplicationBean.class); private static final Log log = LogFactory.getLog(ApplicationBean.class);
public final static int CALS_SEARCHBOX_SIZE = 25; public final static int CALS_SEARCHBOX_SIZE = 25;
@ -43,7 +28,7 @@ public class ApplicationBean {
private final static String DEFAULT_ROOT_LOGOTYPE_TITLE = ""; private final static String DEFAULT_ROOT_LOGOTYPE_TITLE = "";
// Value gets set in default theme setup context listener at application startup // 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<String>());
// Default initializations, which may be overwritten in the AppBeanMapper // Default initializations, which may be overwritten in the AppBeanMapper
// but are otherwise not changed there // but are otherwise not changed there
@ -136,17 +121,9 @@ public class ApplicationBean {
} }
public void setThemeDir(String 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)
|| "&nbsp;".equalsIgnoreCase(string_val) )
themeDir = DEFAULT_THEME_DIR_FROM_CONTEXT;
else
themeDir = string_val; themeDir = string_val;
} }
/*************************** GET functions ****************************/ /*************************** GET functions ****************************/
public String getSessionIdStr() { public String getSessionIdStr() {
@ -217,37 +194,71 @@ public class ApplicationBean {
* @return * @return
*/ */
public String getThemeDir(){ public String getThemeDir(){
return (themeDir != null && themeDir.length()>0) if (themeInfo.isValidThemeDir(themeDir)) {
? themeDir return themeDir;
: DEFAULT_THEME_DIR_FROM_CONTEXT; } else {
return themeInfo.getDefaultThemeDir();
}
} }
/**********************************************************************/ /**********************************************************************/
public boolean themeDirExists(){ /**
String themeDir = this.getThemeDir(); * Hold the names of the available themes, the name of the default theme,
if( themeDir == null || themeDir.length() < 1 ){ * and the base directory that contains the theme directories.
log.error("Application has no themeDir/stylesheet set in the db." ); *
return false; * 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<String> themeNames;
public ThemeInfo(File themesBaseDir, String defaultThemeName,
List<String> themeNames) {
this.themesBaseDir = themesBaseDir;
this.defaultThemeName = defaultThemeName;
this.themeNames = Collections
.unmodifiableList(new ArrayList<String>(themeNames));
} }
File dir = new File(themeDir); public static String themeNameFromDir(String themeDir) {
if( !dir.exists() ){ if (themeDir == null) {
log.error("Application: the themeDir/stylesheet " return themeDir;
+ dir.getAbsolutePath()+ " does not exist."); }
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 false;
} }
if( !dir.isDirectory() ){ return themeNames.contains(themeNameFromDir(themeDir));
log.error("Application: themeDir/stylesheet "
+ dir.getAbsolutePath() + " is not a directory.");
return false;
} }
if( !dir.canRead() ){
log.error("Application: themeDir/stylesheet " public String getDefaultThemeDir() {
+ dir.getAbsolutePath() + " is not readable."); return "themes/" + defaultThemeName + "/";
return false;
} }
return true;
public File getThemesBaseDir() {
return themesBaseDir;
}
public String getDefaultThemeName() {
return defaultThemeName;
}
public List<String> getThemeNames() {
return themeNames;
}
} }
} }

View file

@ -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.Controllers;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.dao.ApplicationDao; import edu.cornell.mannlib.vitro.webapp.dao.ApplicationDao;
import edu.cornell.mannlib.vitro.webapp.utils.ThemeUtils;
public class ApplicationBeanRetryController extends BaseEditController { public class ApplicationBeanRetryController extends BaseEditController {
@ -118,7 +117,7 @@ public class ApplicationBeanRetryController extends BaseEditController {
// Get the available themes // Get the available themes
ServletContext sc = getServletContext(); ServletContext sc = getServletContext();
boolean doSort = true; boolean doSort = true;
ArrayList<String> themeNames = ThemeUtils.getThemes(sc, doSort); List<String> themeNames = ApplicationBean.themeInfo.getThemeNames();
// Create the list of theme Options // Create the list of theme Options
String currentThemeDir = application.getThemeDir(); String currentThemeDir = application.getThemeDir();

View file

@ -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<String> 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
}
}

View file

@ -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<String> 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<String> getThemeNames(File themesBaseDir) {
ArrayList<String> themeNames = new ArrayList<String>();
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<RDFNode> 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
}
}

View file

@ -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<String> 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<String> themeNames = new ArrayList<String>(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;
}
}

View file

@ -11,9 +11,6 @@ edu.cornell.mannlib.vitro.webapp.config.RevisionInfoSetup
edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailFactory$Setup 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 # Comment out this listener to run Vitro without a database
# If used, this listener must be run before JenaDataSourceSetup # If used, this listener must be run before JenaDataSourceSetup
edu.cornell.mannlib.vitro.webapp.servlet.setup.JenaPersistentDataSourceSetup 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 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.permissions.PermissionSetsLoader
edu.cornell.mannlib.vitro.webapp.auth.policy.bean.PropertyRestrictionPolicyHelper$Setup edu.cornell.mannlib.vitro.webapp.auth.policy.bean.PropertyRestrictionPolicyHelper$Setup