diff --git a/webapp/config/web.xml b/webapp/config/web.xml index 260e3f111..bc0f7d4d1 100644 --- a/webapp/config/web.xml +++ b/webapp/config/web.xml @@ -82,7 +82,7 @@ edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorageSetup - + @@ -91,7 +91,7 @@ edu.cornell.mannlib.vitro.webapp.servlet.setup.UpdateUploadedFiles - + @@ -99,7 +99,7 @@ - + @@ -295,6 +295,15 @@ /SearchIndex + + NavigationController + edu.cornell.mannlib.vitro.webapp.controller.freemarker.NavigationController + + + NavigationController + /nav/* + + TestController edu.cornell.mannlib.vitro.webapp.controller.TestController diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/NavigationController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/NavigationController.java new file mode 100644 index 000000000..06d1e2b1b --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/NavigationController.java @@ -0,0 +1,215 @@ +package edu.cornell.mannlib.vitro.webapp.controller.freemarker; + +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import com.hp.hpl.jena.ontology.Individual; +import com.hp.hpl.jena.ontology.OntModel; +import com.hp.hpl.jena.rdf.listeners.StatementListener; +import com.hp.hpl.jena.rdf.model.Literal; +import com.hp.hpl.jena.rdf.model.Model; +import com.hp.hpl.jena.rdf.model.NodeIterator; +import com.hp.hpl.jena.rdf.model.RDFNode; +import com.hp.hpl.jena.rdf.model.Resource; +import com.hp.hpl.jena.rdf.model.Statement; +import com.hp.hpl.jena.rdf.model.StmtIterator; + +import edu.cornell.mannlib.vitro.webapp.web.DisplayVocabulary; + +public class NavigationController extends FreeMarkerHttpServlet { + private static final long serialVersionUID = 1L; + private static final Log log = LogFactory.getLog(NavigationController.class.getName()); + + //private Map urlPatternToURI; + private NavigationURLPatternListener urlPatterns; + + @Override + public void init(ServletConfig config) throws ServletException { + super.init(config); + OntModel displayOntModel = (OntModel)config.getServletContext().getAttribute("displayOntModel"); + this.urlPatterns = new NavigationURLPatternListener( ); + displayOntModel.getBaseModel().register( urlPatterns ); + } + + @Override + protected String getBody() { + OntModel displayOntModel = (OntModel)getServletContext().getAttribute("displayOntModel"); + OntModel jenaOntModel = (OntModel)getServletContext().getAttribute("jenaOntModel"); + + //figure out what is being requested + Individual ind = urlPatterns.getDisplayIndividual(vreq.getPathInfo(),displayOntModel); + Map values = getValues(ind, displayOntModel,jenaOntModel, getValuesFromRequest(/*?*/) ); + String template = getTemplate(ind, displayOntModel); + + return mergeBodyToTemplate(template, values); + } + + private MapgetValuesFromRequest(){ + // TODO: figure out how to get request for FreeMarkerHttpServlet. + return Collections.emptyMap(); + } + + private String getTemplate(Individual ind, OntModel displayOntModel) { + if( ind == null ) return "defaultBody"; + + // check vitroDisplay:requiresBodyTemplate + displayOntModel.enterCriticalSection(Model.READ); + StmtIterator it = displayOntModel.listStatements(ind, DisplayVocabulary.REQUIRES_BODY_TEMPLATE, (RDFNode) null); + //NodeIterator it = ind.listPropertyValues(DisplayVocabulary.REQUIRES_BODY_TEMPLATE); + try{ + while(it.hasNext()){ + Statement stmt = it.nextStatement(); + if( stmt.getObject().isLiteral() ){ + String template = ((Literal)stmt.getObject().as(Literal.class)).getLexicalForm(); + if( template != null && template.length() > 0 ){ + return template; + } + } + } + }finally{ + it.close(); + displayOntModel.leaveCriticalSection(); + } + return "defaultBody"; + } + + Map getValues(Individual ind, OntModel displayOntModel, OntModel assertionModel, Map baseValues){ + if( ind == null ) return Collections.emptyMap(); + + /* Figure out what ValueFactories are specified in the display ontology for this individual. */ + Set valueFactories = new HashSet(); + displayOntModel.enterCriticalSection(Model.READ); + StmtIterator stmts = ind.listProperties(DisplayVocabulary.REQUIRES_VALUES); + try{ + while(stmts.hasNext()){ + Statement stmt = stmts.nextStatement(); + RDFNode obj = stmt.getObject(); + valueFactories.addAll(getValueFactory(obj,displayOntModel)); + } + }finally{ + stmts.close(); + displayOntModel.leaveCriticalSection(); + } + + /* Get values from the ValueFactories. */ + HashMap values = new HashMap(); + values.putAll(baseValues); + for(ValueFactory vf : valueFactories){ + values.putAll( vf.getValues(assertionModel, values)); + } + return values; + } + + protected Set getValueFactory( RDFNode valueNode, OntModel displayOntModel) { + //maybe use jenabean or owl2java for this? + if( valueNode.isResource() ){ + Resource res = (Resource)valueNode.as(Resource.class); + Statement stmt = res.getProperty(DisplayVocabulary.JAVA_CLASS_NAME); + if( stmt == null || !stmt.getObject().isLiteral() ){ + log.debug("Cannot build value factory: java class was " + stmt.getObject()); + return Collections.emptySet(); + } + String javaClassName = ((Literal)stmt.getObject().as(Literal.class)).getLexicalForm(); + if( javaClassName == null || javaClassName.length() == 0 ){ + log.debug("Cannot build value factory: no java class was set."); + return Collections.emptySet(); + } + Class clazz; + Object newObj; + try { + clazz = Class.forName(javaClassName); + } catch (ClassNotFoundException e) { + log.debug("Cannot build value factory: no class found for " + javaClassName); + return Collections.emptySet(); + } + try { + newObj = clazz.newInstance(); + } catch (Exception e) { + log.debug("Cannot build value factory: exception while creating object of java class " + javaClassName + " " + e.getMessage()); + return Collections.emptySet(); + } + if( newObj instanceof ValueFactory){ + ValueFactory valueFactory = (ValueFactory)newObj; + return Collections.singleton( valueFactory ); + }else{ + log.debug("Cannot build value factory: " + javaClassName + " does not implement " + ValueFactory.class.getName() ); + return Collections.emptySet(); + } + }else{ + log.debug("Cannot build value factory for " + valueNode); + return Collections.emptySet(); + } + } + + interface ValueFactory { + void configure( Map config); + Map getValues(OntModel model, Map values); + } + + @Override + protected String getTitle() { + // TODO Auto-generated method stub + return super.getTitle(); + } + + private class NavigationURLPatternListener extends StatementListener { + private Map urlPatternToURI; + + public synchronized Map getUrlPatternToURIMap(){ + if( urlPatternToURI == null || urlPatternToURI.isEmpty() ){ + this.urlPatternToURI = buildUrlPatternToURI(); + } + return urlPatternToURI; + } + + protected synchronized void invalidateURLPatternMap(){ + this.urlPatternToURI = null; + } + + public Individual getDisplayIndividual( String pathInfo , OntModel displayModel){ + Map map = getUrlPatternToURIMap(); + for( Pattern regex : map.keySet()){ + Matcher m = regex.matcher(pathInfo); + if(m.matches() ){ + return displayModel.getIndividual(map.get(regex)); + } + } + return null; + } + + protected synchronized Map buildUrlPatternToURI(){ + OntModel displayModel = (OntModel)getServletContext().getAttribute("displayOntModel"); + Map map = new HashMap(); + StmtIterator stmts = displayModel.listStatements(null, DisplayVocabulary.URL_MAPPING,(Literal)null); + while(stmts.hasNext()){ + Statement stmt = stmts.nextStatement(); + if( stmt.getSubject().isURIResource() && stmt.getObject().isLiteral()){ + Resource r = (Resource)stmt.getSubject().as( Resource.class); + Pattern regex = Pattern.compile(stmt.getLiteral().getLexicalForm()); + map.put(regex,r.getURI()); + } + } + return map; + } + + @Override + public void addedStatement(Statement s) { + invalidateURLPatternMap(); + } + @Override + public void removedStatement(Statement s) { + invalidateURLPatternMap(); + } + } +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/SimpleOntModelSelector.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/SimpleOntModelSelector.java index 5966478ca..73c356a38 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/SimpleOntModelSelector.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/SimpleOntModelSelector.java @@ -21,6 +21,7 @@ public class SimpleOntModelSelector implements OntModelSelector { private OntModel userAccountsModel; private OntModelSpec DEFAULT_ONT_MODEL_SPEC = OntModelSpec.OWL_MEM; + private OntModel displayModel; /** * Construct an OntModelSelector with a bunch of empty models @@ -116,4 +117,10 @@ public class SimpleOntModelSelector implements OntModelSelector { this.userAccountsModel = userAccountsModel; } + public void setDisplayModel(OntModel displayModel) { + this.displayModel = displayModel; + } + public OntModel getDisplayModel(){ + return this.displayModel; + } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/JenaDataSourceSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/JenaDataSourceSetup.java index ac652e23c..71abec213 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/JenaDataSourceSetup.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/JenaDataSourceSetup.java @@ -8,7 +8,6 @@ import javax.servlet.ServletContextEvent; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import com.hp.hpl.jena.datatypes.xsd.XSDDatatype; import com.hp.hpl.jena.ontology.Individual; import com.hp.hpl.jena.ontology.OntModel; import com.hp.hpl.jena.rdf.model.Literal; @@ -17,7 +16,6 @@ import com.hp.hpl.jena.rdf.model.ModelFactory; import com.hp.hpl.jena.rdf.model.ResourceFactory; import com.hp.hpl.jena.shared.Lock; import com.hp.hpl.jena.util.iterator.ClosableIterator; -import com.hp.hpl.jena.vocabulary.OWL; import edu.cornell.mannlib.vitro.webapp.beans.ApplicationBean; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; @@ -61,6 +59,13 @@ public class JenaDataSourceSetup extends JenaDataSourceSetupBase implements java inferenceOms.setUserAccountsModel(userAccountsModel); unionOms.setUserAccountsModel(userAccountsModel); + OntModel displayModel = ontModelFromContextAttribute(sce.getServletContext(),"displayOntModel"); + OntModel displayUnionModel = ModelFactory.createOntologyModel(MEM_ONT_MODEL_SPEC,ModelFactory.createUnion(displayModel, unionModel)); + sce.getServletContext().setAttribute("displayOntModel", displayUnionModel); + baseOms.setDisplayModel(displayModel); + inferenceOms.setDisplayModel(displayModel); + unionOms.setDisplayModel(displayModel); + sce.getServletContext().setAttribute("baseOntModel", memModel); WebappDaoFactory baseWadf = new WebappDaoFactoryJena(baseOms, defaultNamespace, null, null); sce.getServletContext().setAttribute("assertionsWebappDaoFactory",baseWadf); @@ -87,7 +92,7 @@ public class JenaDataSourceSetup extends JenaDataSourceSetupBase implements java if (userAccountsModel.size() == 0) { createInitialAdminUser(userAccountsModel); } - } + } ensureEssentialInterfaceData(memModel, sce, wadf); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/JenaDataSourceSetupBase.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/JenaDataSourceSetupBase.java index 27edaebae..0df8c6419 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/JenaDataSourceSetupBase.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/JenaDataSourceSetupBase.java @@ -39,6 +39,7 @@ public class JenaDataSourceSetupBase { protected static String USERPATH = BASE+"user/"; protected static String SYSTEMPATH = BASE+"system/"; protected static String AUTHPATH = BASE+"auth/"; + protected static String APPPATH = BASE+"app/"; String DB_USER = "jenatest"; // database user id String DB_PASSWD = "jenatest"; // database password @@ -49,6 +50,7 @@ public class JenaDataSourceSetupBase { static final String JENA_INF_MODEL = "http://vitro.mannlib.cornell.edu/default/vitro-kb-inf"; static final String JENA_USER_ACCOUNTS_MODEL = "http://vitro.mannlib.cornell.edu/default/vitro-kb-userAccounts"; static final String JENA_APPLICATION_METADATA_MODEL = "http://vitro.mannlib.cornell.edu/default/vitro-kb-applicationMetadata"; + static final String JENA_DISPLAY_METADATA_MODEL = "http://vitro.mannlib.cornell.edu/default/vitro-kb-displayMetadata"; static final String DEFAULT_DEFAULT_NAMESPACE = "http://vitro.mannlib.cornell.edu/ns/default#"; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/JenaPersistentDataSourceSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/JenaPersistentDataSourceSetup.java index b5b68ada6..6cd0cdae5 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/JenaPersistentDataSourceSetup.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/JenaPersistentDataSourceSetup.java @@ -104,6 +104,19 @@ public class JenaPersistentDataSourceSetup extends JenaDataSourceSetupBase imple log.error("Unable to load user accounts model from DB", t); } + // display, editing and navigation Model + try { + Model appDbModel = makeDBModelFromConfigurationProperties(JENA_DISPLAY_METADATA_MODEL, DB_ONT_MODEL_SPEC); + if (appDbModel.size() == 0) + readOntologyFilesInPathSet(APPPATH, sce.getServletContext(),appDbModel); + OntModel appModel = ModelFactory.createOntologyModel(MEM_ONT_MODEL_SPEC); + appModel.add(appDbModel); + appModel.getBaseModel().register(new ModelSynchronizer(appDbModel)); + sce.getServletContext().setAttribute("displayOntModel", appModel); + } catch (Throwable t) { + log.error("Unable to load user application configuration model from DB", t); + } + sce.getServletContext().setAttribute("jenaOntModel", memModel); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/DisplayVocabulary.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/DisplayVocabulary.java new file mode 100644 index 000000000..cd733efe7 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/DisplayVocabulary.java @@ -0,0 +1,74 @@ +package edu.cornell.mannlib.vitro.webapp.web; + +import com.hp.hpl.jena.ontology.DatatypeProperty; +import com.hp.hpl.jena.ontology.Individual; +import com.hp.hpl.jena.ontology.ObjectProperty; +import com.hp.hpl.jena.ontology.OntClass; +import com.hp.hpl.jena.ontology.OntModel; +import com.hp.hpl.jena.ontology.OntModelSpec; +import com.hp.hpl.jena.rdf.model.ModelFactory; +import com.hp.hpl.jena.rdf.model.Resource; + +/** + * Vocabulary definitions from /home/bdc34/swoop/display.rdf + * @author Auto-generated by schemagen on 18 Jun 2010 16:57 + */ +public class DisplayVocabulary { + /**

The ontology model that holds the vocabulary terms

*/ + private static OntModel m_model = ModelFactory.createOntologyModel( OntModelSpec.OWL_MEM, null ); + + /**

The namespace of the vocabulary as a string

*/ + public static final String NS = "http://vitro.mannlib.cornell.edu/ontologies/display/1.1#"; + + /**

The namespace of the vocabulary as a string

+ * @see #NS */ + public static String getURI() {return NS;} + + /**

The namespace of the vocabulary as a resource

*/ + public static final Resource NAMESPACE = m_model.createResource( NS ); + + public static final ObjectProperty REQUIRES_VALUES = m_model.createObjectProperty( "http://vitro.mannlib.cornell.edu/ontologies/display/1.1#requiresValues" ); + + public static final ObjectProperty TO_PAGE = m_model.createObjectProperty( "http://vitro.mannlib.cornell.edu/ontologies/display/1.1#toPage" ); + + /**

Java package and class name. ex edu.cornell.mannlib.vitro.webapps.functions.ExampleFunction

*/ + public static final DatatypeProperty JAVA_CLASS_NAME = m_model.createDatatypeProperty( "http://vitro.mannlib.cornell.edu/ontologies/display/1.1#javaClassName" ); + + public static final DatatypeProperty MENU_POSITION = m_model.createDatatypeProperty( "http://vitro.mannlib.cornell.edu/ontologies/display/1.1#menuPosition" ); + + public static final DatatypeProperty PARAMETER_NAME = m_model.createDatatypeProperty( "http://vitro.mannlib.cornell.edu/ontologies/display/1.1#parameterName" ); + + public static final DatatypeProperty PARAMETER_VALUE = m_model.createDatatypeProperty( "http://vitro.mannlib.cornell.edu/ontologies/display/1.1#parameterValue" ); + + public static final DatatypeProperty REQUIRES_BODY_TEMPLATE = m_model.createDatatypeProperty( "http://vitro.mannlib.cornell.edu/ontologies/display/1.1#requiresBodyTemplate" ); + + /**

Values from HttpRequest.getPathInfo() will be mapped to values from urlMapping.

*/ + public static final DatatypeProperty URL_MAPPING = m_model.createDatatypeProperty( "http://vitro.mannlib.cornell.edu/ontologies/display/1.1#urlMapping" ); + + /**

This represents a menu item or other general navigation item.

*/ + public static final OntClass NAVIGATION_ELEMENT = m_model.createClass( "http://vitro.mannlib.cornell.edu/ontologies/display/1.1#NavigationElement" ); + + /**

Class of pages.

*/ + public static final OntClass PAGE = m_model.createClass( "http://vitro.mannlib.cornell.edu/ontologies/display/1.1#Page" ); + + //public static final Individual EVENTS = m_model.createIndividual( "http://vitro.mannlib.cornell.edu/ontologies/display/1.1#Events", PAGE ); + + //public static final Individual EVENTS_MENU_ITEM = m_model.createIndividual( "http://vitro.mannlib.cornell.edu/ontologies/display/1.1#EventsMenuItem", NAVIGATION_ELEMENT ); + + //public static final Individual HOME = m_model.createIndividual( "http://vitro.mannlib.cornell.edu/ontologies/display/1.1#Home", PAGE ); + + //public static final Individual HOME_MENU_ITEM = m_model.createIndividual( "http://vitro.mannlib.cornell.edu/ontologies/display/1.1#HomeMenuItem", NAVIGATION_ELEMENT ); + + //public static final Individual ORGANIZATIONS = m_model.createIndividual( "http://vitro.mannlib.cornell.edu/ontologies/display/1.1#Organizations", PAGE ); + + //public static final Individual ORGANIZATIONS_MENU_ITEM = m_model.createIndividual( "http://vitro.mannlib.cornell.edu/ontologies/display/1.1#OrganizationsMenuItem", NAVIGATION_ELEMENT ); + + //public static final Individual PEOPLE = m_model.createIndividual( "http://vitro.mannlib.cornell.edu/ontologies/display/1.1#People", PAGE ); + + //public static final Individual PEOPLE_MENU_ITEM = m_model.createIndividual( "http://vitro.mannlib.cornell.edu/ontologies/display/1.1#PeopleMenuItem", NAVIGATION_ELEMENT ); + + //public static final Individual PUBLICATIONS = m_model.createIndividual( "http://vitro.mannlib.cornell.edu/ontologies/display/1.1#Publications", PAGE ); + + //public static final Individual PUBLICATIONS_MENU_ITEM = m_model.createIndividual( "http://vitro.mannlib.cornell.edu/ontologies/display/1.1#PublicationsMenuItem", NAVIGATION_ELEMENT ); + +} diff --git a/webapp/web/templates/freemarker/body/home.ftl b/webapp/web/templates/freemarker/body/home.ftl new file mode 100644 index 000000000..54ea7f313 --- /dev/null +++ b/webapp/web/templates/freemarker/body/home.ftl @@ -0,0 +1 @@ +

Welcome to VIVO

\ No newline at end of file