NIHVIVO-3628 convert PropertyListConfig and InvalidConfigurationException from inner classes on ObjectPropertyTemplateModel to top-level classes. Combine InvalidConfigurationException with InvalidConfigFileException. Adjust tests accordingly.

This commit is contained in:
j2blake 2012-02-22 21:40:48 +00:00
parent 6a4228f099
commit 11d32685cf
8 changed files with 313 additions and 269 deletions

View file

@ -71,7 +71,7 @@ public class CustomListViewConfigFile {
// Might be empty but will not be null. // Might be empty but will not be null.
private final String postprocessorName; private final String postprocessorName;
public CustomListViewConfigFile(Reader reader) throws InvalidConfigFileException { public CustomListViewConfigFile(Reader reader) throws InvalidConfigurationException {
Document doc = parseDocument(reader); Document doc = parseDocument(reader);
selectQueryElement = parseSelectQuery(doc); selectQueryElement = parseSelectQuery(doc);
constructQueries = parseConstructQueries(doc); constructQueries = parseConstructQueries(doc);
@ -80,9 +80,9 @@ public class CustomListViewConfigFile {
} }
private Document parseDocument(Reader reader) private Document parseDocument(Reader reader)
throws InvalidConfigFileException { throws InvalidConfigurationException {
if (reader == null) { if (reader == null) {
throw new InvalidConfigFileException("Config file reader is null."); throw new InvalidConfigurationException("Config file reader is null.");
} }
try { try {
@ -91,18 +91,18 @@ public class CustomListViewConfigFile {
Document doc = db.parse(new InputSource(reader)); Document doc = db.parse(new InputSource(reader));
return doc; return doc;
} catch (ParserConfigurationException e) { } catch (ParserConfigurationException e) {
throw new InvalidConfigFileException("Problem with XML parser.", e); throw new InvalidConfigurationException("Problem with XML parser.", e);
} catch (SAXException e) { } catch (SAXException e) {
throw new InvalidConfigFileException( throw new InvalidConfigurationException(
"Config file is not valid XML: " + e.getMessage(), e); "Config file is not valid XML: " + e.getMessage(), e);
} catch (IOException e) { } catch (IOException e) {
throw new InvalidConfigFileException("Unable to read config file.", throw new InvalidConfigurationException("Unable to read config file.",
e); e);
} }
} }
private Element parseSelectQuery(Document doc) private Element parseSelectQuery(Document doc)
throws InvalidConfigFileException { throws InvalidConfigurationException {
Element element = getExactlyOneElement(doc, TAG_SELECT); Element element = getExactlyOneElement(doc, TAG_SELECT);
elementMustNotBeEmpty(element); elementMustNotBeEmpty(element);
return element; return element;
@ -120,14 +120,14 @@ public class CustomListViewConfigFile {
} }
private String parseTemplateName(Document doc) private String parseTemplateName(Document doc)
throws InvalidConfigFileException { throws InvalidConfigurationException {
Element element = getExactlyOneElement(doc, TAG_TEMPLATE); Element element = getExactlyOneElement(doc, TAG_TEMPLATE);
elementMustNotBeEmpty(element); elementMustNotBeEmpty(element);
return element.getTextContent(); return element.getTextContent();
} }
private String parsePostprocessorName(Document doc) private String parsePostprocessorName(Document doc)
throws InvalidConfigFileException { throws InvalidConfigurationException {
Element element = getZeroOrOneElement(doc, TAG_POSTPROCESSOR); Element element = getZeroOrOneElement(doc, TAG_POSTPROCESSOR);
if (element == null) { if (element == null) {
return ""; return "";
@ -148,40 +148,40 @@ public class CustomListViewConfigFile {
} }
private Element getExactlyOneElement(Document doc, String tagName) private Element getExactlyOneElement(Document doc, String tagName)
throws InvalidConfigFileException { throws InvalidConfigurationException {
List<Element> elements = getElements(doc, tagName); List<Element> elements = getElements(doc, tagName);
if (elements.size() == 1) { if (elements.size() == 1) {
return elements.get(0); return elements.get(0);
} else if (elements.isEmpty()) { } else if (elements.isEmpty()) {
throw new InvalidConfigFileException("Config file must contain a " throw new InvalidConfigurationException("Config file must contain a "
+ tagName + " element"); + tagName + " element");
} else { } else {
throw new InvalidConfigFileException( throw new InvalidConfigurationException(
"Config file may not contain more than one " + tagName "Config file may not contain more than one " + tagName
+ " element"); + " element");
} }
} }
private Element getZeroOrOneElement(Document doc, String tagName) private Element getZeroOrOneElement(Document doc, String tagName)
throws InvalidConfigFileException { throws InvalidConfigurationException {
List<Element> elements = getElements(doc, tagName); List<Element> elements = getElements(doc, tagName);
if (elements.size() == 1) { if (elements.size() == 1) {
return elements.get(0); return elements.get(0);
} else if (elements.isEmpty()) { } else if (elements.isEmpty()) {
return null; return null;
} else { } else {
throw new InvalidConfigFileException( throw new InvalidConfigurationException(
"Config file may not contain more than one " + tagName "Config file may not contain more than one " + tagName
+ " element"); + " element");
} }
} }
private void elementMustNotBeEmpty(Element element) private void elementMustNotBeEmpty(Element element)
throws InvalidConfigFileException { throws InvalidConfigurationException {
String contents = element.getTextContent(); String contents = element.getTextContent();
if (contents.trim().isEmpty()) { if (contents.trim().isEmpty()) {
throw new InvalidConfigFileException("In a config file, the <" throw new InvalidConfigurationException("In a config file, the <"
+ element.getTagName() + "> element must not be empty."); + element.getTagName() + "> element must not be empty.");
} }
} }
@ -249,13 +249,4 @@ public class CustomListViewConfigFile {
} }
} }
public static class InvalidConfigFileException extends Exception {
public InvalidConfigFileException(String message) {
super(message);
}
public InvalidConfigFileException(String message, Throwable cause) {
super(message, cause);
}
}
} }

View file

@ -0,0 +1,28 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.web.templatemodels.customlistview;
/**
* Indicates that there is a problem with the custom configuration. Perhaps the
* file can't be found, can't be parsed, or the information it contains is
* erroneous.
*/
public class InvalidConfigurationException extends Exception {
public InvalidConfigurationException() {
super();
}
public InvalidConfigurationException(String message, Throwable cause) {
super(message, cause);
}
public InvalidConfigurationException(String message) {
super(message);
}
public InvalidConfigurationException(Throwable cause) {
super(cause);
}
}

View file

@ -0,0 +1,213 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.web.templatemodels.customlistview;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.CollatedObjectPropertyTemplateModel;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.DefaultObjectPropertyDataPostProcessor;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.ObjectPropertyDataPostProcessor;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.ObjectPropertyTemplateModel;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.ObjectPropertyTemplateModel.ConfigError;
import freemarker.cache.TemplateLoader;
import freemarker.template.Configuration;
public class PropertyListConfig {
private static final Log log = LogFactory.getLog(PropertyListConfig.class);
private static final String CONFIG_FILE_PATH = "/config/";
private static final String DEFAULT_CONFIG_FILE_NAME = "listViewConfig-default.xml";
/* NB The default post-processor is not the same as the post-processor for the default view. The latter
* actually defines its own post-processor, whereas the default post-processor is used for custom views
* that don't define a post-processor, to ensure that the standard post-processing applies.
*
* edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.DefaultObjectPropertyDataPostProcessor
*/
// TODO Lump these together into the PropertyListConfigContext
private final ObjectPropertyTemplateModel optm;
private final VitroRequest vreq;
private boolean isDefaultConfig;
private Set<String> constructQueries;
private String selectQuery;
private String templateName;
private ObjectPropertyDataPostProcessor postprocessor; // never null
public PropertyListConfig(ObjectPropertyTemplateModel optm, VitroRequest vreq, ObjectProperty op, boolean editing)
throws InvalidConfigurationException {
this.optm = optm;
this.vreq = vreq;
WebappDaoFactory wadf = vreq.getWebappDaoFactory();
// Get the custom config filename
String configFileName = wadf.getObjectPropertyDao().getCustomListViewConfigFileName(op);
if (configFileName == null) { // no custom config; use default config
configFileName = DEFAULT_CONFIG_FILE_NAME;
}
log.debug("Using list view config file " + configFileName + " for object property " + op.getURI());
String configFilePath = getConfigFilePath(configFileName);
try {
File config = new File(configFilePath);
if ( ! isDefaultConfig(configFileName) && ! config.exists() ) {
log.warn("Can't find config file " + configFilePath + " for object property " + op.getURI() + "\n" +
". Using default config file instead.");
configFilePath = getConfigFilePath(DEFAULT_CONFIG_FILE_NAME);
// Should we test for the existence of the default, and throw an error if it doesn't exist?
}
setValuesFromConfigFile(configFilePath, wadf, editing);
} catch (Exception e) {
log.error("Error processing config file " + configFilePath + " for object property " + op.getURI(), e);
// What should we do here?
}
if ( ! isDefaultConfig(configFileName) ) {
ConfigError configError = checkConfiguration();
if ( configError != null ) { // the configuration contains an error
// If this is a collated property, throw an error: this results in creating an
// UncollatedPropertyTemplateModel instead.
if (optm instanceof CollatedObjectPropertyTemplateModel) {
throw new InvalidConfigurationException(configError.getMessage());
}
// Otherwise, switch to the default config
log.warn("Invalid list view config for object property " + op.getURI() +
" in " + configFilePath + ":\n" +
configError + " Using default config instead.");
configFilePath = getConfigFilePath(DEFAULT_CONFIG_FILE_NAME);
setValuesFromConfigFile(configFilePath, wadf, editing);
}
}
isDefaultConfig = isDefaultConfig(configFileName);
}
private boolean isDefaultConfig(String configFileName) {
return configFileName.equals(DEFAULT_CONFIG_FILE_NAME);
}
private ConfigError checkConfiguration() {
ConfigError error = optm.checkQuery(selectQuery);
if (error != null) {
return error;
}
if (StringUtils.isBlank(selectQuery)) {
return ConfigError.NO_SELECT_QUERY;
}
if ( StringUtils.isBlank(templateName)) {
return ConfigError.NO_TEMPLATE;
}
Configuration fmConfig = (Configuration) vreq.getAttribute("freemarkerConfig");
TemplateLoader tl = fmConfig.getTemplateLoader();
try {
if ( tl.findTemplateSource(templateName) == null ) {
return ConfigError.TEMPLATE_NOT_FOUND;
}
} catch (IOException e) {
log.error("Error finding template " + templateName, e);
}
return null;
}
private void setValuesFromConfigFile(String configFilePath, WebappDaoFactory wdf,
boolean editing) {
try {
FileReader reader = new FileReader(configFilePath);
CustomListViewConfigFile configFileContents = new CustomListViewConfigFile(reader);
boolean collated = optm instanceof CollatedObjectPropertyTemplateModel;
selectQuery = configFileContents.getSelectQuery(collated, editing);
templateName = configFileContents.getTemplateName();
constructQueries = configFileContents.getConstructQueries();
String postprocessorName = configFileContents.getPostprocessorName();
postprocessor = getPostProcessor(postprocessorName, optm, wdf, configFilePath);
} catch (Exception e) {
log.error("Error processing config file " + configFilePath, e);
}
}
private ObjectPropertyDataPostProcessor getPostProcessor(
String className,
ObjectPropertyTemplateModel optm,
WebappDaoFactory wdf, String configFilePath) {
try {
if (StringUtils.isBlank(className)) {
return new DefaultObjectPropertyDataPostProcessor(optm, wdf);
}
Class<?> clazz = Class.forName(className);
Constructor<?> constructor = clazz.getConstructor(ObjectPropertyTemplateModel.class, WebappDaoFactory.class);
return (ObjectPropertyDataPostProcessor) constructor.newInstance(optm, wdf);
} catch (ClassNotFoundException e) {
log.warn("Error processing config file '" + configFilePath
+ "': can't load postprocessor class '" + className
+ "'. " + "Using default postprocessor.", e);
return new DefaultObjectPropertyDataPostProcessor(optm, wdf);
} catch (NoSuchMethodException e) {
log.warn("Error processing config file '" + configFilePath
+ "': postprocessor class '" + className
+ "' does not have a constructor that takes "
+ "ObjectPropertyTemplateModel and WebappDaoFactory. "
+ "Using default postprocessor.", e);
return new DefaultObjectPropertyDataPostProcessor(optm, wdf);
} catch (ClassCastException e) {
log.warn("Error processing config file '" + configFilePath
+ "': postprocessor class '" + className + "' does "
+ "not implement ObjectPropertyDataPostProcessor. "
+ "Using default postprocessor.", e);
return new DefaultObjectPropertyDataPostProcessor(optm, wdf);
} catch (Exception e) {
log.warn("Error processing config file '" + configFilePath
+ "': can't create postprocessor instance of class '"
+ className + "'. " + "Using default postprocessor.", e);
return new DefaultObjectPropertyDataPostProcessor(optm, wdf);
}
}
private String getConfigFilePath(String filename) {
return vreq.getSession().getServletContext().getRealPath(CONFIG_FILE_PATH + filename);
}
public String getSelectQuery() {
return this.selectQuery;
}
public Set<String> getConstructQueries() {
return this.constructQueries;
}
public String getTemplateName() {
return this.templateName;
}
public boolean isDefaultListView() {
return this.isDefaultConfig;
}
public ObjectPropertyDataPostProcessor getPostprocessor() {
return this.postprocessor;
}
}

View file

@ -21,6 +21,7 @@ import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty;
import edu.cornell.mannlib.vitro.webapp.beans.VClass; import edu.cornell.mannlib.vitro.webapp.beans.VClass;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.dao.VClassDao; import edu.cornell.mannlib.vitro.webapp.dao.VClassDao;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.customlistview.InvalidConfigurationException;
public class CollatedObjectPropertyTemplateModel extends ObjectPropertyTemplateModel { public class CollatedObjectPropertyTemplateModel extends ObjectPropertyTemplateModel {
@ -77,7 +78,7 @@ public class CollatedObjectPropertyTemplateModel extends ObjectPropertyTemplateM
return subclasses.isEmpty(); return subclasses.isEmpty();
} }
protected ConfigError checkQuery(String queryString) { public ConfigError checkQuery(String queryString) {
if (StringUtils.isBlank(queryString)) { if (StringUtils.isBlank(queryString)) {
return ConfigError.NO_SELECT_QUERY; return ConfigError.NO_SELECT_QUERY;

View file

@ -2,10 +2,6 @@
package edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual; package edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@ -31,10 +27,8 @@ import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.ParamMa
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Route; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Route;
import edu.cornell.mannlib.vitro.webapp.dao.ObjectPropertyStatementDao; import edu.cornell.mannlib.vitro.webapp.dao.ObjectPropertyStatementDao;
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; import edu.cornell.mannlib.vitro.webapp.web.templatemodels.customlistview.InvalidConfigurationException;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.customlistview.CustomListViewConfigFile; import edu.cornell.mannlib.vitro.webapp.web.templatemodels.customlistview.PropertyListConfig;
import freemarker.cache.TemplateLoader;
import freemarker.template.Configuration;
public abstract class ObjectPropertyTemplateModel extends PropertyTemplateModel { public abstract class ObjectPropertyTemplateModel extends PropertyTemplateModel {
@ -59,7 +53,7 @@ public abstract class ObjectPropertyTemplateModel extends PropertyTemplateModel
// ?subject ?property ?\w+ // ?subject ?property ?\w+
Pattern.compile("\\?" + KEY_SUBJECT + "\\s+\\?" + KEY_PROPERTY + "\\s+\\?(\\w+)"); Pattern.compile("\\?" + KEY_SUBJECT + "\\s+\\?" + KEY_PROPERTY + "\\s+\\?(\\w+)");
protected static enum ConfigError { public static enum ConfigError {
NO_SELECT_QUERY("Missing select query specification"), NO_SELECT_QUERY("Missing select query specification"),
NO_SUBCLASS_SELECT("Query does not select a subclass variable"), NO_SUBCLASS_SELECT("Query does not select a subclass variable"),
NO_SUBCLASS_ORDER_BY("Query does not sort first by subclass variable"), NO_SUBCLASS_ORDER_BY("Query does not sort first by subclass variable"),
@ -93,7 +87,7 @@ public abstract class ObjectPropertyTemplateModel extends PropertyTemplateModel
// Get the config for this object property // Get the config for this object property
try { try {
config = new PropertyListConfig(op, editing); config = new PropertyListConfig(this, vreq, op, editing);
} catch (InvalidConfigurationException e) { } catch (InvalidConfigurationException e) {
throw e; throw e;
} catch (Exception e) { } catch (Exception e) {
@ -146,7 +140,7 @@ public abstract class ObjectPropertyTemplateModel extends PropertyTemplateModel
return Route.OBJECT_PROPERTY_EDIT; return Route.OBJECT_PROPERTY_EDIT;
} }
protected ConfigError checkQuery(String queryString) { public ConfigError checkQuery(String queryString) {
if (StringUtils.isBlank(queryString)) { if (StringUtils.isBlank(queryString)) {
return ConfigError.NO_SELECT_QUERY; return ConfigError.NO_SELECT_QUERY;
} }
@ -154,19 +148,19 @@ public abstract class ObjectPropertyTemplateModel extends PropertyTemplateModel
} }
private String getSelectQuery() { private String getSelectQuery() {
return config.selectQuery; return config.getSelectQuery();
} }
private Set<String> getConstructQueries() { private Set<String> getConstructQueries() {
return config.constructQueries; return config.getConstructQueries();
} }
protected String getTemplateName() { protected String getTemplateName() {
return config.templateName; return config.getTemplateName();
} }
protected boolean hasDefaultListView() { protected boolean hasDefaultListView() {
return config.isDefaultConfig; return config.isDefaultListView();
} }
protected static String getImageUploadUrl(String subjectUri, String action) { protected static String getImageUploadUrl(String subjectUri, String action) {
@ -227,14 +221,8 @@ public abstract class ObjectPropertyTemplateModel extends PropertyTemplateModel
logData(data); logData(data);
} }
ObjectPropertyDataPostProcessor postprocessor = config.postprocessor; ObjectPropertyDataPostProcessor postprocessor = config.getPostprocessor();
if (postprocessor == null) {
log.debug("No postprocessor for property " + getUri());
return;
} else {
log.debug("Using postprocessor " + postprocessor.getClass().getName() + " for property " + getUri()); log.debug("Using postprocessor " + postprocessor.getClass().getName() + " for property " + getUri());
}
postprocessor.process(data); postprocessor.process(data);
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
@ -331,174 +319,6 @@ public abstract class ObjectPropertyTemplateModel extends PropertyTemplateModel
return objectKey; return objectKey;
} }
private class PropertyListConfig {
private static final String CONFIG_FILE_PATH = "/config/";
private static final String DEFAULT_CONFIG_FILE_NAME = "listViewConfig-default.xml";
/* NB The default post-processor is not the same as the post-processor for the default view. The latter
* actually defines its own post-processor, whereas the default post-processor is used for custom views
* that don't define a post-processor, to ensure that the standard post-processing applies.
*
* edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.DefaultObjectPropertyDataPostProcessor
*/
private boolean isDefaultConfig;
private Set<String> constructQueries;
private String selectQuery;
private String templateName;
private ObjectPropertyDataPostProcessor postprocessor = null;
PropertyListConfig(ObjectProperty op, boolean editing)
throws InvalidConfigurationException {
// Get the custom config filename
String configFileName = vreq.getWebappDaoFactory().getObjectPropertyDao().getCustomListViewConfigFileName(op);
if (configFileName == null) { // no custom config; use default config
configFileName = DEFAULT_CONFIG_FILE_NAME;
}
log.debug("Using list view config file " + configFileName + " for object property " + op.getURI());
String configFilePath = getConfigFilePath(configFileName);
try {
File config = new File(configFilePath);
if ( ! isDefaultConfig(configFileName) && ! config.exists() ) {
log.warn("Can't find config file " + configFilePath + " for object property " + op.getURI() + "\n" +
". Using default config file instead.");
configFilePath = getConfigFilePath(DEFAULT_CONFIG_FILE_NAME);
// Should we test for the existence of the default, and throw an error if it doesn't exist?
}
setValuesFromConfigFile(configFilePath, vreq.getWebappDaoFactory(), editing);
} catch (Exception e) {
log.error("Error processing config file " + configFilePath + " for object property " + op.getURI(), e);
// What should we do here?
}
if ( ! isDefaultConfig(configFileName) ) {
ConfigError configError = checkConfiguration();
if ( configError != null ) { // the configuration contains an error
// If this is a collated property, throw an error: this results in creating an
// UncollatedPropertyTemplateModel instead.
if (ObjectPropertyTemplateModel.this instanceof CollatedObjectPropertyTemplateModel) {
throw new InvalidConfigurationException(configError.getMessage());
}
// Otherwise, switch to the default config
log.warn("Invalid list view config for object property " + op.getURI() +
" in " + configFilePath + ":\n" +
configError + " Using default config instead.");
configFilePath = getConfigFilePath(DEFAULT_CONFIG_FILE_NAME);
setValuesFromConfigFile(configFilePath, vreq.getWebappDaoFactory(), editing);
}
}
isDefaultConfig = isDefaultConfig(configFileName);
}
private boolean isDefaultConfig(String configFileName) {
return configFileName.equals(DEFAULT_CONFIG_FILE_NAME);
}
private ConfigError checkConfiguration() {
ConfigError error = ObjectPropertyTemplateModel.this.checkQuery(selectQuery);
if (error != null) {
return error;
}
if (StringUtils.isBlank(selectQuery)) {
return ConfigError.NO_SELECT_QUERY;
}
if ( StringUtils.isBlank(templateName)) {
return ConfigError.NO_TEMPLATE;
}
Configuration fmConfig = (Configuration) vreq.getAttribute("freemarkerConfig");
TemplateLoader tl = fmConfig.getTemplateLoader();
try {
if ( tl.findTemplateSource(templateName) == null ) {
return ConfigError.TEMPLATE_NOT_FOUND;
}
} catch (IOException e) {
log.error("Error finding template " + templateName, e);
}
return null;
}
private void setValuesFromConfigFile(String configFilePath, WebappDaoFactory wdf,
boolean editing) {
try {
FileReader reader = new FileReader(configFilePath);
CustomListViewConfigFile configFileContents = new CustomListViewConfigFile(reader);
boolean collated = ObjectPropertyTemplateModel.this instanceof CollatedObjectPropertyTemplateModel;
selectQuery = configFileContents.getSelectQuery(collated, editing);
templateName = configFileContents.getTemplateName();
constructQueries = configFileContents.getConstructQueries();
String postprocessorName = configFileContents.getPostprocessorName();
postprocessor = getPostProcessor(postprocessorName, ObjectPropertyTemplateModel.this, wdf, configFilePath);
} catch (Exception e) {
log.error("Error processing config file " + configFilePath, e);
}
}
private ObjectPropertyDataPostProcessor getPostProcessor(
String className,
ObjectPropertyTemplateModel optm,
WebappDaoFactory wdf, String configFilePath) {
try {
if (StringUtils.isBlank(className)) {
return new DefaultObjectPropertyDataPostProcessor(optm, wdf);
}
Class<?> clazz = Class.forName(className);
Constructor<?> constructor = clazz.getConstructor(ObjectPropertyTemplateModel.class, WebappDaoFactory.class);
return (ObjectPropertyDataPostProcessor) constructor.newInstance(optm, wdf);
} catch (ClassNotFoundException e) {
log.warn("Error processing config file '" + configFilePath
+ "': can't load postprocessor class '" + className
+ "'. " + "Using default postprocessor.", e);
return new DefaultObjectPropertyDataPostProcessor(optm, wdf);
} catch (NoSuchMethodException e) {
log.warn("Error processing config file '" + configFilePath
+ "': postprocessor class '" + className
+ "' does not have a constructor that takes "
+ "ObjectPropertyTemplateModel and WebappDaoFactory. "
+ "Using default postprocessor.", e);
return new DefaultObjectPropertyDataPostProcessor(optm, wdf);
} catch (ClassCastException e) {
log.warn("Error processing config file '" + configFilePath
+ "': postprocessor class '" + className + "' does "
+ "not implement ObjectPropertyDataPostProcessor. "
+ "Using default postprocessor.", e);
return new DefaultObjectPropertyDataPostProcessor(optm, wdf);
} catch (Exception e) {
log.warn("Error processing config file '" + configFilePath
+ "': can't create postprocessor instance of class '"
+ className + "'. " + "Using default postprocessor.", e);
return new DefaultObjectPropertyDataPostProcessor(optm, wdf);
}
}
private String getConfigFilePath(String filename) {
return servletContext.getRealPath(CONFIG_FILE_PATH + filename);
}
}
protected class InvalidConfigurationException extends Exception {
private static final long serialVersionUID = 1L;
protected InvalidConfigurationException(String s) {
super(s);
}
}
/* Template properties */ /* Template properties */
public String getType() { public String getType() {
@ -506,7 +326,7 @@ public abstract class ObjectPropertyTemplateModel extends PropertyTemplateModel
} }
public String getTemplate() { public String getTemplate() {
return config.templateName; return getTemplateName();
} }
public abstract boolean isCollatedBySubclass(); public abstract boolean isCollatedBySubclass();

View file

@ -12,6 +12,7 @@ import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.beans.Individual; import edu.cornell.mannlib.vitro.webapp.beans.Individual;
import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty; import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.customlistview.InvalidConfigurationException;
public class UncollatedObjectPropertyTemplateModel extends ObjectPropertyTemplateModel { public class UncollatedObjectPropertyTemplateModel extends ObjectPropertyTemplateModel {

View file

@ -17,8 +17,6 @@ import org.junit.matchers.JUnitMatchers;
import org.junit.rules.ExpectedException; import org.junit.rules.ExpectedException;
import edu.cornell.mannlib.vitro.testing.AbstractTestClass; import edu.cornell.mannlib.vitro.testing.AbstractTestClass;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.customlistview.CustomListViewConfigFile;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.customlistview.CustomListViewConfigFile.InvalidConfigFileException;
/** /**
* Note: when testing, an "empty" element may be self-closing, or with * Note: when testing, an "empty" element may be self-closing, or with
@ -59,19 +57,19 @@ public class CustomListViewConfigFileTest extends AbstractTestClass {
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
@Test @Test
public void readerIsNull() throws InvalidConfigFileException { public void readerIsNull() throws InvalidConfigurationException {
expectException("Config file reader is null."); expectException("Config file reader is null.");
configFile = new CustomListViewConfigFile(null); configFile = new CustomListViewConfigFile(null);
} }
@Test @Test
public void readerThrowsIOException() throws InvalidConfigFileException { public void readerThrowsIOException() throws InvalidConfigurationException {
expectException("Unable to read config file."); expectException("Unable to read config file.");
configFile = new CustomListViewConfigFile(new ExplodingReader()); configFile = new CustomListViewConfigFile(new ExplodingReader());
} }
@Test @Test
public void invalidXml() throws InvalidConfigFileException { public void invalidXml() throws InvalidConfigurationException {
suppressSyserr(); // catch the error report from the XML parser suppressSyserr(); // catch the error report from the XML parser
expectException(JUnitMatchers expectException(JUnitMatchers
.containsString("Config file is not valid XML:")); .containsString("Config file is not valid XML:"));
@ -79,14 +77,14 @@ public class CustomListViewConfigFileTest extends AbstractTestClass {
} }
@Test @Test
public void selectQueryMissing() throws InvalidConfigFileException { public void selectQueryMissing() throws InvalidConfigurationException {
expectException("Config file must contain a query-select element"); expectException("Config file must contain a query-select element");
readConfigFile("<list-view-config>" readConfigFile("<list-view-config>"
+ "<template>template.ftl</template>" + "</list-view-config>"); + "<template>template.ftl</template>" + "</list-view-config>");
} }
@Test @Test
public void selectQueryMultiple() throws InvalidConfigFileException { public void selectQueryMultiple() throws InvalidConfigurationException {
expectException("Config file may not contain more than one query-select element"); expectException("Config file may not contain more than one query-select element");
readConfigFile("<list-view-config>" readConfigFile("<list-view-config>"
+ "<query-select>SELECT</query-select>" + "<query-select>SELECT</query-select>"
@ -95,21 +93,21 @@ public class CustomListViewConfigFileTest extends AbstractTestClass {
} }
@Test @Test
public void selectQueryEmpty() throws InvalidConfigFileException { public void selectQueryEmpty() throws InvalidConfigurationException {
expectException("In a config file, the <query-select> element must not be empty."); expectException("In a config file, the <query-select> element must not be empty.");
readConfigFile("<list-view-config>" + "<query-select/>" readConfigFile("<list-view-config>" + "<query-select/>"
+ "<template>template.ftl</template>" + "</list-view-config>"); + "<template>template.ftl</template>" + "</list-view-config>");
} }
@Test @Test
public void templateNameMissing() throws InvalidConfigFileException { public void templateNameMissing() throws InvalidConfigurationException {
expectException("Config file must contain a template element"); expectException("Config file must contain a template element");
readConfigFile("<list-view-config>" readConfigFile("<list-view-config>"
+ "<query-select>SELECT</query-select>" + "</list-view-config>"); + "<query-select>SELECT</query-select>" + "</list-view-config>");
} }
@Test @Test
public void templateNameMultiple() throws InvalidConfigFileException { public void templateNameMultiple() throws InvalidConfigurationException {
expectException("Config file may not contain more than one template element"); expectException("Config file may not contain more than one template element");
readConfigFile("<list-view-config>" readConfigFile("<list-view-config>"
+ "<query-select>SELECT</query-select>" + "<query-select>SELECT</query-select>"
@ -118,7 +116,7 @@ public class CustomListViewConfigFileTest extends AbstractTestClass {
} }
@Test @Test
public void templateNameEmpty() throws InvalidConfigFileException { public void templateNameEmpty() throws InvalidConfigurationException {
expectException("In a config file, the <template> element must not be empty."); expectException("In a config file, the <template> element must not be empty.");
readConfigFile("<list-view-config>" readConfigFile("<list-view-config>"
+ "<query-select>SELECT</query-select>" + "<query-select>SELECT</query-select>"
@ -126,7 +124,7 @@ public class CustomListViewConfigFileTest extends AbstractTestClass {
} }
@Test @Test
public void postprocessorNameMultiple() throws InvalidConfigFileException { public void postprocessorNameMultiple() throws InvalidConfigurationException {
expectException("Config file may not contain more than one postprocessor element"); expectException("Config file may not contain more than one postprocessor element");
readConfigFile("<list-view-config>" readConfigFile("<list-view-config>"
+ "<query-select>SELECT</query-select>" + "<query-select>SELECT</query-select>"
@ -140,7 +138,7 @@ public class CustomListViewConfigFileTest extends AbstractTestClass {
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
@Test @Test
public void minimalSuccess() throws InvalidConfigFileException { public void minimalSuccess() throws InvalidConfigurationException {
readConfigFile("<list-view-config>" readConfigFile("<list-view-config>"
+ "<query-select>SELECT</query-select>" + "<query-select>SELECT</query-select>"
+ "<template>template.ftl</template>" + "</list-view-config>"); + "<template>template.ftl</template>" + "</list-view-config>");
@ -149,7 +147,7 @@ public class CustomListViewConfigFileTest extends AbstractTestClass {
} }
@Test @Test
public void maximalSuccess() throws InvalidConfigFileException { public void maximalSuccess() throws InvalidConfigurationException {
readConfigFile("<list-view-config>" readConfigFile("<list-view-config>"
+ "<query-select>SELECT</query-select>" + "<query-select>SELECT</query-select>"
+ "<query-construct>CONSTRUCT ONE</query-construct>" + "<query-construct>CONSTRUCT ONE</query-construct>"
@ -163,7 +161,7 @@ public class CustomListViewConfigFileTest extends AbstractTestClass {
} }
@Test @Test
public void postprocessorEmptyIsOK() throws InvalidConfigFileException { public void postprocessorEmptyIsOK() throws InvalidConfigurationException {
readConfigFile("<list-view-config>" readConfigFile("<list-view-config>"
+ "<query-select>SELECT</query-select>" + "<query-select>SELECT</query-select>"
+ "<query-construct>CONSTRUCT</query-construct>" + "<query-construct>CONSTRUCT</query-construct>"
@ -174,28 +172,28 @@ public class CustomListViewConfigFileTest extends AbstractTestClass {
} }
@Test @Test
public void selectCollatedEditing() throws InvalidConfigFileException { public void selectCollatedEditing() throws InvalidConfigurationException {
readConfigFile(XML_WITH_RICH_SELECT_CLAUSE); readConfigFile(XML_WITH_RICH_SELECT_CLAUSE);
assertConfigFile(true, true, "SELECT collated1 collated2 ", constructs(), assertConfigFile(true, true, "SELECT collated1 collated2 ", constructs(),
"template.ftl", ""); "template.ftl", "");
} }
@Test @Test
public void selectCollatedNotEditing() throws InvalidConfigFileException { public void selectCollatedNotEditing() throws InvalidConfigurationException {
readConfigFile(XML_WITH_RICH_SELECT_CLAUSE); readConfigFile(XML_WITH_RICH_SELECT_CLAUSE);
assertConfigFile(true, false, "SELECT collated1 collated2 critical", assertConfigFile(true, false, "SELECT collated1 collated2 critical",
constructs(), "template.ftl", ""); constructs(), "template.ftl", "");
} }
@Test @Test
public void selectNotCollatedEditing() throws InvalidConfigFileException { public void selectNotCollatedEditing() throws InvalidConfigurationException {
readConfigFile(XML_WITH_RICH_SELECT_CLAUSE); readConfigFile(XML_WITH_RICH_SELECT_CLAUSE);
assertConfigFile(false, true, "SELECT ", constructs(), assertConfigFile(false, true, "SELECT ", constructs(),
"template.ftl", ""); "template.ftl", "");
} }
@Test @Test
public void selectNotCollatedNotEditing() throws InvalidConfigFileException { public void selectNotCollatedNotEditing() throws InvalidConfigurationException {
readConfigFile(XML_WITH_RICH_SELECT_CLAUSE); readConfigFile(XML_WITH_RICH_SELECT_CLAUSE);
assertConfigFile(false, false, "SELECT critical", constructs(), assertConfigFile(false, false, "SELECT critical", constructs(),
"template.ftl", ""); "template.ftl", "");
@ -215,17 +213,17 @@ public class CustomListViewConfigFileTest extends AbstractTestClass {
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
private void expectException(String message) { private void expectException(String message) {
thrown.expect(InvalidConfigFileException.class); thrown.expect(InvalidConfigurationException.class);
thrown.expectMessage(message); thrown.expectMessage(message);
} }
private void expectException(Matcher<String> matcher) { private void expectException(Matcher<String> matcher) {
thrown.expect(InvalidConfigFileException.class); thrown.expect(InvalidConfigurationException.class);
thrown.expectMessage(matcher); thrown.expectMessage(matcher);
} }
private void readConfigFile(String xmlString) private void readConfigFile(String xmlString)
throws InvalidConfigFileException { throws InvalidConfigurationException {
StringReader reader = new StringReader(xmlString); StringReader reader = new StringReader(xmlString);
configFile = new CustomListViewConfigFile(reader); configFile = new CustomListViewConfigFile(reader);
} }

View file

@ -18,7 +18,6 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.apache.log4j.Level;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.Before; import org.junit.Before;
import org.junit.BeforeClass; import org.junit.BeforeClass;
@ -39,7 +38,8 @@ import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.BaseTemplateModel; import edu.cornell.mannlib.vitro.webapp.web.templatemodels.BaseTemplateModel;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.ObjectPropertyTemplateModel.InvalidConfigurationException; import edu.cornell.mannlib.vitro.webapp.web.templatemodels.customlistview.InvalidConfigurationException;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.customlistview.PropertyListConfig;
import freemarker.template.Configuration; import freemarker.template.Configuration;
public class ObjectPropertyTemplateModel_PropertyListConfigTest extends public class ObjectPropertyTemplateModel_PropertyListConfigTest extends
@ -204,7 +204,7 @@ public class ObjectPropertyTemplateModel_PropertyListConfigTest extends
throws InvalidConfigurationException { throws InvalidConfigurationException {
// TODO if we can't translate the path, log the error and use the // TODO if we can't translate the path, log the error and use the
// default. // default.
captureLogsFromOPTM(); captureLogsFromPropertyListConfig();
op = buildOperation("fileHasNoRealPath"); op = buildOperation("fileHasNoRealPath");
optm = new NonCollatingOPTM(op, subject, vreq, false); optm = new NonCollatingOPTM(op, subject, vreq, false);
@ -215,7 +215,7 @@ public class ObjectPropertyTemplateModel_PropertyListConfigTest extends
@Test @Test
public void configFileNotFound() throws InvalidConfigurationException { public void configFileNotFound() throws InvalidConfigurationException {
captureLogsFromOPTM(); captureLogsFromPropertyListConfig();
op = buildOperation("configFileDoesNotExist"); op = buildOperation("configFileDoesNotExist");
@ -233,7 +233,7 @@ public class ObjectPropertyTemplateModel_PropertyListConfigTest extends
@Test @Test
public void configFileNotValidXml() throws InvalidConfigurationException { public void configFileNotValidXml() throws InvalidConfigurationException {
suppressSyserr(); suppressSyserr();
captureLogsFromOPTM(); captureLogsFromPropertyListConfig();
op = buildOperation("notValidXml"); op = buildOperation("notValidXml");
optm = new NonCollatingOPTM(op, subject, vreq, false); optm = new NonCollatingOPTM(op, subject, vreq, false);
@ -248,7 +248,7 @@ public class ObjectPropertyTemplateModel_PropertyListConfigTest extends
@Test @Test
public void selectQueryNodeIsNotFound() public void selectQueryNodeIsNotFound()
throws InvalidConfigurationException { throws InvalidConfigurationException {
captureLogsFromOPTM(); captureLogsFromPropertyListConfig();
op = buildOperation("selectQueryNodeNotFound"); op = buildOperation("selectQueryNodeNotFound");
optm = new NonCollatingOPTM(op, subject, vreq, false); optm = new NonCollatingOPTM(op, subject, vreq, false);
@ -259,7 +259,7 @@ public class ObjectPropertyTemplateModel_PropertyListConfigTest extends
@Test @Test
public void selectQueryNodeIsBlank() throws InvalidConfigurationException { public void selectQueryNodeIsBlank() throws InvalidConfigurationException {
captureLogsFromOPTM(); captureLogsFromPropertyListConfig();
op = buildOperation("selectQueryNodeBlank"); op = buildOperation("selectQueryNodeBlank");
optm = new NonCollatingOPTM(op, subject, vreq, false); optm = new NonCollatingOPTM(op, subject, vreq, false);
@ -273,7 +273,7 @@ public class ObjectPropertyTemplateModel_PropertyListConfigTest extends
// //
@Test @Test
public void templateNodeNotFound() throws InvalidConfigurationException { public void templateNodeNotFound() throws InvalidConfigurationException {
captureLogsFromOPTM(); captureLogsFromPropertyListConfig();
op = buildOperation("templateNodeNotFound"); op = buildOperation("templateNodeNotFound");
optm = new NonCollatingOPTM(op, subject, vreq, false); optm = new NonCollatingOPTM(op, subject, vreq, false);
@ -284,7 +284,7 @@ public class ObjectPropertyTemplateModel_PropertyListConfigTest extends
@Test @Test
public void templateNodeIsEmpty() throws InvalidConfigurationException { public void templateNodeIsEmpty() throws InvalidConfigurationException {
captureLogsFromOPTM(); captureLogsFromPropertyListConfig();
op = buildOperation("templateNodeIsEmpty"); op = buildOperation("templateNodeIsEmpty");
optm = new NonCollatingOPTM(op, subject, vreq, false); optm = new NonCollatingOPTM(op, subject, vreq, false);
@ -295,7 +295,7 @@ public class ObjectPropertyTemplateModel_PropertyListConfigTest extends
@Test @Test
public void templateDoesNotExist() throws InvalidConfigurationException { public void templateDoesNotExist() throws InvalidConfigurationException {
captureLogsFromOPTM(); captureLogsFromPropertyListConfig();
op = buildOperation("templateDoesNotExist"); op = buildOperation("templateDoesNotExist");
optm = new NonCollatingOPTM(op, subject, vreq, false); optm = new NonCollatingOPTM(op, subject, vreq, false);
@ -414,7 +414,7 @@ public class ObjectPropertyTemplateModel_PropertyListConfigTest extends
@Test @Test
public void postProcessorClassNotFound() public void postProcessorClassNotFound()
throws InvalidConfigurationException { throws InvalidConfigurationException {
captureLogsFromOPTM(); captureLogsFromPropertyListConfig();
op = buildOperation("postProcessorClassNotFound"); op = buildOperation("postProcessorClassNotFound");
optm = new NonCollatingOPTM(op, subject, vreq, false); optm = new NonCollatingOPTM(op, subject, vreq, false);
@ -428,7 +428,7 @@ public class ObjectPropertyTemplateModel_PropertyListConfigTest extends
@Test @Test
public void postProcessorClassIsNotSuitable() public void postProcessorClassIsNotSuitable()
throws InvalidConfigurationException { throws InvalidConfigurationException {
captureLogsFromOPTM(); captureLogsFromPropertyListConfig();
op = buildOperation("postProcessorClassNotSuitable"); op = buildOperation("postProcessorClassNotSuitable");
optm = new NonCollatingOPTM(op, subject, vreq, false); optm = new NonCollatingOPTM(op, subject, vreq, false);
@ -442,7 +442,7 @@ public class ObjectPropertyTemplateModel_PropertyListConfigTest extends
@Test @Test
public void postProcessorClassHasWrongConstructor() public void postProcessorClassHasWrongConstructor()
throws InvalidConfigurationException { throws InvalidConfigurationException {
captureLogsFromOPTM(); captureLogsFromPropertyListConfig();
op = buildOperation("postProcessorWrongConstructor"); op = buildOperation("postProcessorWrongConstructor");
optm = new NonCollatingOPTM(op, subject, vreq, false); optm = new NonCollatingOPTM(op, subject, vreq, false);
@ -456,7 +456,7 @@ public class ObjectPropertyTemplateModel_PropertyListConfigTest extends
@Test @Test
public void postProcessorConstructorThrowsAnException() public void postProcessorConstructorThrowsAnException()
throws InvalidConfigurationException { throws InvalidConfigurationException {
captureLogsFromOPTM(); captureLogsFromPropertyListConfig();
op = buildOperation("postProcessorConstructorThrowsException"); op = buildOperation("postProcessorConstructorThrowsException");
optm = new NonCollatingOPTM(op, subject, vreq, false); optm = new NonCollatingOPTM(op, subject, vreq, false);
@ -498,11 +498,10 @@ public class ObjectPropertyTemplateModel_PropertyListConfigTest extends
} }
/** /**
* Capture the log for ObjectPropertyTemplateModel and suppress it from the * Capture the log for PropertyListConfig and suppress it from the console.
* console.
*/ */
private void captureLogsFromOPTM() { private void captureLogsFromPropertyListConfig() {
captureLogOutput(ObjectPropertyTemplateModel.class, logMessages, true); captureLogOutput(PropertyListConfig.class, logMessages, true);
} }
private void assertLogMessagesContains(String message, String expected) { private void assertLogMessagesContains(String message, String expected) {
@ -548,17 +547,10 @@ public class ObjectPropertyTemplateModel_PropertyListConfigTest extends
Field configField = ObjectPropertyTemplateModel.class Field configField = ObjectPropertyTemplateModel.class
.getDeclaredField("config"); .getDeclaredField("config");
configField.setAccessible(true); configField.setAccessible(true);
Object config = configField.get(optm); PropertyListConfig config = (PropertyListConfig) configField
.get(optm);
Class<?> configClass = Class
.forName("edu.cornell.mannlib.vitro.webapp.web."
+ "templatemodels.individual."
+ "ObjectPropertyTemplateModel$PropertyListConfig");
Field ppField = configClass.getDeclaredField("postprocessor");
ppField.setAccessible(true);
Object pp = ppField.get(config);
ObjectPropertyDataPostProcessor pp = config.getPostprocessor();
if (pp == null) { if (pp == null) {
assertNull(message + " - postprocessor is null", expected); assertNull(message + " - postprocessor is null", expected);
} else { } else {
@ -607,7 +599,7 @@ public class ObjectPropertyTemplateModel_PropertyListConfigTest extends
} }
@Override @Override
protected ConfigError checkQuery(String queryString) { public ConfigError checkQuery(String queryString) {
return null; return null;
} }