From 9442468b75a67c218c110a97e20246a7ec7f973b Mon Sep 17 00:00:00 2001 From: j2blake Date: Thu, 22 Mar 2012 20:10:18 +0000 Subject: [PATCH] NIHVIVO-3300 Placeholder images are configured by a properties file, which is loaded at startup. --- .../manageproxies/ManageProxiesListPage.java | 10 +- .../ajax/BasicProxiesGetter.java | 7 +- .../manageproxies/ajax/MoreProfileInfo.java | 4 +- .../user/UserAccountsMyAccountPage.java | 7 +- .../freemarker/ImageUploadController.java | 7 +- .../mannlib/vitro/webapp/utils/ImageUtil.java | 61 ----- .../webapp/web/images/PlaceholderUtil.java | 238 ++++++++++++++++++ .../IndividualPlaceholderImageUrlMethod.java | 4 +- .../WEB-INF/resources/startup_listeners.txt | 2 + .../placeholders/placeholders.properties | 17 ++ 10 files changed, 278 insertions(+), 79 deletions(-) delete mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/utils/ImageUtil.java create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/web/images/PlaceholderUtil.java create mode 100644 webapp/web/images/placeholders/placeholders.properties diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/manageproxies/ManageProxiesListPage.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/manageproxies/ManageProxiesListPage.java index 8783f02a7..6847fb236 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/manageproxies/ManageProxiesListPage.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/manageproxies/ManageProxiesListPage.java @@ -24,7 +24,7 @@ import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; -import edu.cornell.mannlib.vitro.webapp.utils.ImageUtil; +import edu.cornell.mannlib.vitro.webapp.web.images.PlaceholderUtil; /** * TODO @@ -134,8 +134,8 @@ public class ManageProxiesListPage extends AbstractPageHandler { private ProxyItemInfo wrapProxyItem(ProxyItemInfo item) { String imagePath = item.getImageUrl(); if (imagePath.isEmpty()) { - imagePath = ImageUtil - .getPlaceholderImagePathForType(VitroVocabulary.USERACCOUNT); + imagePath = PlaceholderUtil.getPlaceholderImagePathForType(vreq, + VitroVocabulary.USERACCOUNT); } UserAccount ua = userAccountsDao.getUserAccountByUri(item.getUri()); @@ -151,8 +151,8 @@ public class ManageProxiesListPage extends AbstractPageHandler { private ProxyItemInfo wrapProfileItem(ProxyItemInfo item) { String imagePath = item.getImageUrl(); if (imagePath.isEmpty()) { - imagePath = ImageUtil.getPlaceholderImagePathForIndividual(vreq, - item.getUri()); + imagePath = PlaceholderUtil.getPlaceholderImagePathForIndividual( + vreq, item.getUri()); } return new ProfileItemWrapper(item.getUri(), item.getLabel(), diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/manageproxies/ajax/BasicProxiesGetter.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/manageproxies/ajax/BasicProxiesGetter.java index 23c239e82..674acf9cb 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/manageproxies/ajax/BasicProxiesGetter.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/manageproxies/ajax/BasicProxiesGetter.java @@ -24,9 +24,9 @@ import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; import edu.cornell.mannlib.vitro.webapp.dao.jena.ModelContext; import edu.cornell.mannlib.vitro.webapp.dao.jena.OntModelSelector; -import edu.cornell.mannlib.vitro.webapp.utils.ImageUtil; import edu.cornell.mannlib.vitro.webapp.utils.SparqlQueryRunner; import edu.cornell.mannlib.vitro.webapp.utils.SparqlQueryUtils; +import edu.cornell.mannlib.vitro.webapp.web.images.PlaceholderUtil; /** * Get the basic auto-complete info for the proxy selection. @@ -64,8 +64,9 @@ public class BasicProxiesGetter extends AbstractAjaxResponder { OntModelSelector oms = ModelContext.getUnionOntModelSelector(ctx); userAccountsModel = oms.getUserAccountsModel(); - placeholderImageUrl = UrlBuilder.getUrl(ImageUtil - .getPlaceholderImagePathForType(VitroVocabulary.USERACCOUNT)); + placeholderImageUrl = UrlBuilder.getUrl(PlaceholderUtil + .getPlaceholderImagePathForType(vreq, + VitroVocabulary.USERACCOUNT)); } @Override diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/manageproxies/ajax/MoreProfileInfo.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/manageproxies/ajax/MoreProfileInfo.java index 77eaee0ad..9b62a1c7a 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/manageproxies/ajax/MoreProfileInfo.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/manageproxies/ajax/MoreProfileInfo.java @@ -19,7 +19,7 @@ import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.controller.ajax.AbstractAjaxResponder; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; import edu.cornell.mannlib.vitro.webapp.dao.ObjectPropertyStatementDao; -import edu.cornell.mannlib.vitro.webapp.utils.ImageUtil; +import edu.cornell.mannlib.vitro.webapp.web.images.PlaceholderUtil; /** * Get more information (class label and image URL) about a selected proxy. @@ -79,7 +79,7 @@ public class MoreProfileInfo extends AbstractAjaxResponder { private String getFullImageUrl(Individual ind) { String path = ind.getThumbUrl(); if ((path == null) || path.isEmpty()) { - path = ImageUtil.getPlaceholderImagePathForIndividual(vreq, + path = PlaceholderUtil.getPlaceholderImagePathForIndividual(vreq, ind.getURI()); } return UrlBuilder.getUrl(path); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsMyAccountPage.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsMyAccountPage.java index fa98177d5..791b3d277 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsMyAccountPage.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsMyAccountPage.java @@ -27,7 +27,7 @@ import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; -import edu.cornell.mannlib.vitro.webapp.utils.ImageUtil; +import edu.cornell.mannlib.vitro.webapp.web.images.PlaceholderUtil; /** * Handle the "My Account" form display and submission. @@ -270,8 +270,9 @@ public class UserAccountsMyAccountPage extends UserAccountsPage { String userUri = proxyUser.getUri(); String label = assembleUserAccountLabel(proxyUser); String classLabel = ""; - String imageUrl = UrlBuilder.getUrl(ImageUtil - .getPlaceholderImagePathForType(VitroVocabulary.USERACCOUNT)); + String imageUrl = UrlBuilder.getUrl(PlaceholderUtil + .getPlaceholderImagePathForType(vreq, + VitroVocabulary.USERACCOUNT)); // Does this user have a profile? Can we get better info? Individual proxyProfilePage = getProfilePage(proxyUser); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ImageUploadController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ImageUploadController.java index e28b4c942..bbcce862f 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ImageUploadController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ImageUploadController.java @@ -36,7 +36,7 @@ import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorageSetup; import edu.cornell.mannlib.vitro.webapp.filestorage.model.FileInfo; import edu.cornell.mannlib.vitro.webapp.filestorage.model.ImageInfo; import edu.cornell.mannlib.vitro.webapp.filestorage.uploadrequest.FileUploadServletRequest; -import edu.cornell.mannlib.vitro.webapp.utils.ImageUtil; +import edu.cornell.mannlib.vitro.webapp.web.images.PlaceholderUtil; /** * Handle adding, replacing or deleting the main image on an Individual. @@ -405,8 +405,9 @@ public class ImageUploadController extends FreemarkerHttpServlet { ACTION_UPLOAD); String cancelUrl = (entity == null) ? "" : exitPageUrl(vreq, entity.getURI()); - String placeholderUrl = (entity == null) ? "" : UrlBuilder.getUrl(ImageUtil - .getPlaceholderImagePathForIndividual(vreq, entity.getURI())); + String placeholderUrl = (entity == null) ? "" : UrlBuilder + .getUrl(PlaceholderUtil.getPlaceholderImagePathForIndividual( + vreq, entity.getURI())); TemplateResponseValues rv = new TemplateResponseValues(TEMPLATE_NEW); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/ImageUtil.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/ImageUtil.java deleted file mode 100644 index 54ee2d4da..000000000 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/ImageUtil.java +++ /dev/null @@ -1,61 +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.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; - -import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; -import edu.cornell.mannlib.vitro.webapp.dao.IndividualDao; - -/** - * Some static methods that help in dealing with image files. - */ -public class ImageUtil { - private static final String DEFAULT_IMAGE_PATH = "/images/placeholders/thumbnail.jpg"; - - private static final Map DEFAULT_IMAGE_PATHS_BY_TYPE = initImagePaths(); - - private static Map initImagePaths() { - Map map = new HashMap(); - // No images other than the default. - return Collections.unmodifiableMap(map); - } - - /** - * If we have a placeholder image for this exact type, return it. Otherwise, - * return the default. - */ - public static String getPlaceholderImagePathForType(String typeUri) { - for (Entry entry : DEFAULT_IMAGE_PATHS_BY_TYPE - .entrySet()) { - if (typeUri.equals(entry.getKey())) { - return entry.getValue(); - } - } - return DEFAULT_IMAGE_PATH; - } - - /** - * If there is a placeholder image for any type that this Individual - * instantiates, return that image. Otherwise, return the default. - */ - public static String getPlaceholderImagePathForIndividual( - VitroRequest vreq, String individualUri) { - IndividualDao indDao = vreq.getWebappDaoFactory().getIndividualDao(); - for (Entry entry : DEFAULT_IMAGE_PATHS_BY_TYPE - .entrySet()) { - if (indDao.isIndividualOfClass(entry.getKey(), individualUri)) { - return entry.getValue(); - } - } - return DEFAULT_IMAGE_PATH; - } - - /** Never need to instantiate this -- all methods are static. */ - private ImageUtil() { - // Nothing to do - } -} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/images/PlaceholderUtil.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/images/PlaceholderUtil.java new file mode 100644 index 000000000..d0c03dad3 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/images/PlaceholderUtil.java @@ -0,0 +1,238 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.web.images; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.Map.Entry; + +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 edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.dao.IndividualDao; +import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus; + +/** + * A utility for finding the URL of the correct Placeholder image. + * + * The mapping of image URLs to classes is created at startup, and stored in the + * ServletContext. + */ +public class PlaceholderUtil { + private static final Log log = LogFactory.getLog(PlaceholderUtil.class); + + private static final String ATTRIBUTE_NAME = PlaceholderUtil.class + .getName(); + private static final String PROPERTIES_FILE_PATH = "/images/placeholders/placeholders.properties"; + private static final String DEFAULT_IMAGE_PATH = "/images/placeholders/thumbnail.jpg"; + + // ---------------------------------------------------------------------- + // Static methods + // ---------------------------------------------------------------------- + + /** + * If we have a placeholder image for this exact type, return it. Otherwise, + * return the default. + */ + public static String getPlaceholderImagePathForType(VitroRequest vreq, + String typeUri) { + PlaceholderUtil pu = getPlaceholderUtil(vreq); + if (pu == null) { + return DEFAULT_IMAGE_PATH; + } else { + return pu.getPlaceholderImagePathForType(typeUri); + } + } + + /** + * If there is a placeholder image for any type that this Individual + * instantiates, return that image. Otherwise, return the default. + */ + public static String getPlaceholderImagePathForIndividual( + VitroRequest vreq, String individualUri) { + PlaceholderUtil pu = getPlaceholderUtil(vreq); + if (pu == null) { + return DEFAULT_IMAGE_PATH; + } else { + IndividualDao iDao = vreq.getWebappDaoFactory().getIndividualDao(); + return pu.getPlaceholderImagePathForIndividual(iDao, individualUri); + } + } + + /** Get the PlaceholderUtil instance from the context, or null if none. */ + private static PlaceholderUtil getPlaceholderUtil(VitroRequest vreq) { + if (vreq == null) { + return null; + } + ServletContext ctx = vreq.getSession().getServletContext(); + Object attrib = ctx.getAttribute(ATTRIBUTE_NAME); + if (attrib instanceof PlaceholderUtil) { + return (PlaceholderUtil) attrib; + } else { + log.warn("Looked for a PlaceholerUtil, but found " + attrib); + return null; + } + } + + // ---------------------------------------------------------------------- + // The object + // ---------------------------------------------------------------------- + + private final Map mapUrlsByClass; + + private PlaceholderUtil(Map map) { + this.mapUrlsByClass = Collections + .unmodifiableMap(new HashMap(map)); + } + + /** + * If we have a placeholder image for this exact type, return it. Otherwise, + * return the default. + */ + private String getPlaceholderImagePathForType(String typeUri) { + if (typeUri == null) { + log.debug("getPlaceholderImagePathForType: typeUri is null"); + return DEFAULT_IMAGE_PATH; + } + String url = mapUrlsByClass.get(typeUri); + if (url == null) { + log.debug("getPlaceholderImagePathForType: no value for '" + + typeUri + "'"); + return DEFAULT_IMAGE_PATH; + } + log.debug("getPlaceholderImagePathForType: value for '" + typeUri + + "' is '" + url + "'"); + return url; + } + + /** + * If there is a placeholder image for any type that this Individual + * instantiates, return that image. Otherwise, return the default. + */ + private String getPlaceholderImagePathForIndividual(IndividualDao iDao, + String individualUri) { + if (individualUri == null) { + log.debug("getPlaceholderImagePathForIndividual: " + + "individualUri is null"); + return DEFAULT_IMAGE_PATH; + } + for (String classUri : mapUrlsByClass.keySet()) { + String imageUrl = mapUrlsByClass.get(classUri); + if (iDao.isIndividualOfClass(classUri, individualUri)) { + log.debug("getPlaceholderImagePathForIndividual: individual '" + + individualUri + "' is of class '" + classUri + + "', value is '" + imageUrl + "'"); + return imageUrl; + } + } + log.debug("getPlaceholderImagePathForIndividual: individual '" + + individualUri + "' is not of any recognized class"); + return DEFAULT_IMAGE_PATH; + } + + // ---------------------------------------------------------------------- + // Classes used for setup + // ---------------------------------------------------------------------- + + public static class Setup implements ServletContextListener { + @Override + public void contextInitialized(ServletContextEvent sce) { + ServletContext ctx = sce.getServletContext(); + StartupStatus ss = StartupStatus.getBean(ctx); + + try { + File propertiesFile = confirmRealPath(ctx, PROPERTIES_FILE_PATH); + Map map = loadPropertiesToMap(propertiesFile); + confirmImagesArePresent(ctx, map); + ctx.setAttribute(ATTRIBUTE_NAME, new PlaceholderUtil(map)); + } catch (SetupException e) { + if (e.getCause() == null) { + ss.warning(this, e.getMessage()); + } else { + ss.warning(this, e.getMessage(), e.getCause()); + } + } + } + + private Map loadPropertiesToMap(File propertiesFile) + throws SetupException { + Properties props = new Properties(); + try { + props.load(new FileReader(propertiesFile)); + } catch (IOException e) { + throw new SetupException( + "Can't load properties from the file at '" + + PROPERTIES_FILE_PATH + + "'. Is it in a valid format?", e); + } + + Map map = new HashMap(); + for (Enumeration keys = props.keys(); keys + .hasMoreElements();) { + String key = (String) keys.nextElement(); + String value = props.getProperty(key); + map.put(key, value); + } + + return map; + } + + private void confirmImagesArePresent(ServletContext ctx, + Map map) throws SetupException { + Set imageUrls = new HashSet(); + imageUrls.add(DEFAULT_IMAGE_PATH); + imageUrls.addAll(map.values()); + for (String imageUrl : imageUrls) { + confirmRealPath(ctx, imageUrl); + } + + } + + private File confirmRealPath(ServletContext ctx, String url) + throws SetupException { + String path = ctx.getRealPath(url); + if (path == null) { + throw new SetupException("Can't translate to real path: '" + + url + "'"); + } + File file = new File(path); + if (!file.exists()) { + throw new SetupException("No file found at '" + url + "'."); + } + if (!file.canRead()) { + throw new SetupException("Can't read the file at '" + url + + "'."); + } + return file; + } + + @Override + public void contextDestroyed(ServletContextEvent sce) { + sce.getServletContext().removeAttribute(ATTRIBUTE_NAME); + } + + } + + private static class SetupException extends Exception { + public SetupException(String message) { + super(message); + } + + public SetupException(String message, Throwable cause) { + super(message, cause); + } + } +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/methods/IndividualPlaceholderImageUrlMethod.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/methods/IndividualPlaceholderImageUrlMethod.java index 1be234797..39692fd11 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/methods/IndividualPlaceholderImageUrlMethod.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/methods/IndividualPlaceholderImageUrlMethod.java @@ -11,7 +11,7 @@ import javax.servlet.http.HttpServletRequest; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; -import edu.cornell.mannlib.vitro.webapp.utils.ImageUtil; +import edu.cornell.mannlib.vitro.webapp.web.images.PlaceholderUtil; import freemarker.core.Environment; import freemarker.template.TemplateModelException; @@ -32,7 +32,7 @@ public class IndividualPlaceholderImageUrlMethod extends BaseTemplateMethodModel Environment env = Environment.getCurrentEnvironment(); HttpServletRequest request = (HttpServletRequest) env.getCustomAttribute("request"); VitroRequest vreq = new VitroRequest(request); - String imageUrl = ImageUtil.getPlaceholderImagePathForIndividual(vreq, uri); + String imageUrl = PlaceholderUtil.getPlaceholderImagePathForIndividual(vreq, uri); return UrlBuilder.getUrl(imageUrl); } diff --git a/webapp/web/WEB-INF/resources/startup_listeners.txt b/webapp/web/WEB-INF/resources/startup_listeners.txt index 034242f09..eb004d336 100644 --- a/webapp/web/WEB-INF/resources/startup_listeners.txt +++ b/webapp/web/WEB-INF/resources/startup_listeners.txt @@ -24,6 +24,8 @@ edu.cornell.mannlib.vitro.webapp.servlet.setup.UpdateKnowledgeBase edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorageSetup +edu.cornell.mannlib.vitro.webapp.web.images.PlaceholderUtil$Setup + # Update the URIs on Permission Sets on UserAccounts from model (1.4) to 1.5. edu.cornell.mannlib.vitro.webapp.servlet.setup.UpdatePermissionSetUris diff --git a/webapp/web/images/placeholders/placeholders.properties b/webapp/web/images/placeholders/placeholders.properties new file mode 100644 index 000000000..7ebaffd73 --- /dev/null +++ b/webapp/web/images/placeholders/placeholders.properties @@ -0,0 +1,17 @@ +# +# Assign placeholder images to classes of individuals. +# +# If showing an individual that has no image, a placeholder image may be shown. +# By default, the placeholder is /images/placeholders/thumbnail.jpg. However, +# this file allows you to associate classes with special placeholder images, and +# if the individual belongs to such a class, the special placeholder is shown +# instead of the default. +# +# EXAMPLE: +# http\://xmlns.com/foaf/0.1/Person = /images/placeholders/person.thumbnail.jpg +# means that any individual of type foaf:Person will be represented by +# person.thumbnail.jpg +# +# NOTE: a colon is a special character in a properties file, and must be escaped +# by a backslash. +