Move FreeMarker templates, controllers, setup, and library upgrades into trunk. Not used to generate any pages or templates yet (except a couple of hidden pages that are only available through the url).
This commit is contained in:
parent
72ee86f0a7
commit
a0c93fda6d
44 changed files with 2256 additions and 7 deletions
|
@ -138,6 +138,12 @@
|
||||||
</listener-class>
|
</listener-class>
|
||||||
</listener>
|
</listener>
|
||||||
|
|
||||||
|
<listener>
|
||||||
|
<listener-class>
|
||||||
|
edu.cornell.mannlib.vitro.webapp.servlet.setup.FreeMarkerSetup
|
||||||
|
</listener-class>
|
||||||
|
</listener>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
<listener>
|
<listener>
|
||||||
<listener-class>
|
<listener-class>
|
||||||
|
@ -267,6 +273,15 @@
|
||||||
<url-pattern>/about</url-pattern>
|
<url-pattern>/about</url-pattern>
|
||||||
</servlet-mapping>
|
</servlet-mapping>
|
||||||
|
|
||||||
|
<servlet>
|
||||||
|
<servlet-name>AboutControllerFM</servlet-name>
|
||||||
|
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.AboutControllerFM</servlet-class>
|
||||||
|
</servlet>
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>AboutControllerFM</servlet-name>
|
||||||
|
<url-pattern>/about-fm</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
|
||||||
<servlet>
|
<servlet>
|
||||||
<servlet-name>FakeSelfEditController</servlet-name>
|
<servlet-name>FakeSelfEditController</servlet-name>
|
||||||
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.FakeSelfEditController</servlet-class>
|
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.FakeSelfEditController</servlet-class>
|
||||||
|
@ -781,6 +796,15 @@
|
||||||
<url-pattern>/entitylist</url-pattern>
|
<url-pattern>/entitylist</url-pattern>
|
||||||
</servlet-mapping>
|
</servlet-mapping>
|
||||||
|
|
||||||
|
<servlet>
|
||||||
|
<servlet-name>IndividualListControllerFM</servlet-name>
|
||||||
|
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.IndividualListControllerFM</servlet-class>
|
||||||
|
</servlet>
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>IndividualListControllerFM</servlet-name>
|
||||||
|
<url-pattern>/individuallistFM</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
|
||||||
<servlet>
|
<servlet>
|
||||||
<servlet-name>SearchController</servlet-name>
|
<servlet-name>SearchController</servlet-name>
|
||||||
<servlet-class>edu.cornell.mannlib.vitro.webapp.search.controller.PagedSearchController</servlet-class>
|
<servlet-class>edu.cornell.mannlib.vitro.webapp.search.controller.PagedSearchController</servlet-class>
|
||||||
|
@ -947,6 +971,12 @@
|
||||||
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.BrowseController</servlet-class>
|
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.BrowseController</servlet-class>
|
||||||
<load-on-startup>5</load-on-startup>
|
<load-on-startup>5</load-on-startup>
|
||||||
</servlet>
|
</servlet>
|
||||||
|
|
||||||
|
<servlet>
|
||||||
|
<servlet-name>browsecontrollerFM</servlet-name>
|
||||||
|
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.BrowseControllerFM</servlet-class>
|
||||||
|
<load-on-startup>5</load-on-startup>
|
||||||
|
</servlet>
|
||||||
|
|
||||||
<servlet>
|
<servlet>
|
||||||
<servlet-name>pubsbyorg</servlet-name>
|
<servlet-name>pubsbyorg</servlet-name>
|
||||||
|
@ -1064,6 +1094,10 @@
|
||||||
<servlet-name>browsecontroller</servlet-name>
|
<servlet-name>browsecontroller</servlet-name>
|
||||||
<url-pattern>/browsecontroller</url-pattern>
|
<url-pattern>/browsecontroller</url-pattern>
|
||||||
</servlet-mapping>
|
</servlet-mapping>
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>browsecontrollerFM</servlet-name>
|
||||||
|
<url-pattern>/browse</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
<servlet-mapping>
|
<servlet-mapping>
|
||||||
<servlet-name>pubsbyorg</servlet-name>
|
<servlet-name>pubsbyorg</servlet-name>
|
||||||
<url-pattern>/pubsbyorg</url-pattern>
|
<url-pattern>/pubsbyorg</url-pattern>
|
||||||
|
|
Binary file not shown.
Binary file not shown.
BIN
webapp/lib/commons-collections-3.2.1.jar
Normal file
BIN
webapp/lib/commons-collections-3.2.1.jar
Normal file
Binary file not shown.
Binary file not shown.
BIN
webapp/lib/commons-lang-2.4.jar
Normal file
BIN
webapp/lib/commons-lang-2.4.jar
Normal file
Binary file not shown.
BIN
webapp/lib/freemarker.jar
Normal file
BIN
webapp/lib/freemarker.jar
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -45,7 +45,8 @@ public class VClass extends BaseResourceBean implements Comparable<VClass>
|
||||||
// [bjl23 2007-08-12] Yep. A count of individuals in the class.
|
// [bjl23 2007-08-12] Yep. A count of individuals in the class.
|
||||||
private int myEntityCount = -1;
|
private int myEntityCount = -1;
|
||||||
|
|
||||||
@Deprecated
|
// rjy7 Removing deprecation since currently we have no other means to get this value.
|
||||||
|
// @Deprecated
|
||||||
public int getEntityCount() { return myEntityCount; }
|
public int getEntityCount() { return myEntityCount; }
|
||||||
|
|
||||||
public void setEntityCount( int ec ) { myEntityCount = ec; }
|
public void setEntityCount( int ec ) { myEntityCount = ec; }
|
||||||
|
@ -107,8 +108,8 @@ public class VClass extends BaseResourceBean implements Comparable<VClass>
|
||||||
public VClass( String namespace, String localName, String vclassName )
|
public VClass( String namespace, String localName, String vclassName )
|
||||||
{
|
{
|
||||||
myName = vclassName;
|
myName = vclassName;
|
||||||
namespace = namespace;
|
this.namespace = namespace;
|
||||||
localName = localName;
|
this.localName = localName;
|
||||||
URI = namespace + localName;
|
URI = namespace + localName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.controller;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.FreeMarkerHttpServlet;
|
||||||
|
|
||||||
|
import freemarker.template.SimpleDate;
|
||||||
|
import freemarker.template.TemplateDateModel;
|
||||||
|
import freemarker.template.TemplateModelException;
|
||||||
|
|
||||||
|
public class AboutControllerFM extends FreeMarkerHttpServlet {
|
||||||
|
|
||||||
|
private static final Log log = LogFactory.getLog(AboutControllerFM.class.getName());
|
||||||
|
|
||||||
|
protected String getTitle() {
|
||||||
|
return "About " + portal.getAppName();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getBody() {
|
||||||
|
|
||||||
|
Map<String, Object> body = new HashMap<String, Object>();
|
||||||
|
|
||||||
|
body.put("aboutText", portal.getAboutText());
|
||||||
|
body.put("acknowledgeText", portal.getAcknowledgeText());
|
||||||
|
|
||||||
|
String templateName = "body/about.ftl";
|
||||||
|
return mergeBodyToTemplate(templateName, body);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,322 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.controller;
|
||||||
|
|
||||||
|
import com.hp.hpl.jena.ontology.OntModel;
|
||||||
|
import com.hp.hpl.jena.rdf.listeners.StatementListener;
|
||||||
|
import com.hp.hpl.jena.rdf.model.Statement;
|
||||||
|
import com.hp.hpl.jena.vocabulary.RDF;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.beans.ApplicationBean;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.beans.Portal;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.beans.VClassGroup;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.dao.VClassGroupDao;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.dao.filtering.WebappDaoFactoryFiltering;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.dao.filtering.filters.VitroFilterUtils;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.dao.filtering.filters.VitroFilters;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.flags.PortalFlag;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.FreeMarkerHttpServlet;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.view.VClassGroupView;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import freemarker.template.*;
|
||||||
|
|
||||||
|
import javax.servlet.ServletContext;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
|
|
||||||
|
public class BrowseControllerFM extends FreeMarkerHttpServlet {
|
||||||
|
static final long serialVersionUID=2006030721126L;
|
||||||
|
|
||||||
|
private transient ConcurrentHashMap<Integer, List> _groupListMap
|
||||||
|
= new ConcurrentHashMap<Integer, List>();
|
||||||
|
private transient ConcurrentLinkedQueue<String> _rebuildQueue
|
||||||
|
= new ConcurrentLinkedQueue<String>();
|
||||||
|
private RebuildGroupCacheThread _cacheRebuildThread;
|
||||||
|
|
||||||
|
private static final Log log = LogFactory.getLog(BrowseControllerFM.class.getName());
|
||||||
|
|
||||||
|
public void init(javax.servlet.ServletConfig servletConfig)
|
||||||
|
throws javax.servlet.ServletException {
|
||||||
|
super.init(servletConfig);
|
||||||
|
ServletContext sContext = servletConfig.getServletContext();
|
||||||
|
|
||||||
|
//BJL23: I'll work on a strategy for avoiding all this craziness.
|
||||||
|
OntModel model = (OntModel)sContext.getAttribute("jenaOntModel");
|
||||||
|
OntModel baseModel = (OntModel)sContext.getAttribute("baseOntModel");
|
||||||
|
OntModel infModel = (OntModel)sContext.getAttribute("inferenceOntModel");
|
||||||
|
|
||||||
|
BrowseControllerChangeListener bccl = new BrowseControllerChangeListener(this);
|
||||||
|
model.register(bccl);
|
||||||
|
baseModel.register(bccl);
|
||||||
|
infModel.register(bccl);
|
||||||
|
|
||||||
|
_rebuildQueue.add(REBUILD_EVERY_PORTAL);
|
||||||
|
_cacheRebuildThread = new RebuildGroupCacheThread(this);
|
||||||
|
_cacheRebuildThread.setDaemon(true);
|
||||||
|
_cacheRebuildThread.start();
|
||||||
|
_cacheRebuildThread.informOfQueueChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getTitle() {
|
||||||
|
return "Index to " + portal.getAppName() + " Contents";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getBody() {
|
||||||
|
|
||||||
|
Map body = new HashMap();
|
||||||
|
|
||||||
|
// Set main page template attributes specific to this page
|
||||||
|
root.put("contentClass", "siteMap");
|
||||||
|
|
||||||
|
if( vreq.getParameter("clearcache") != null ) //mainly for debugging
|
||||||
|
clearGroupCache();
|
||||||
|
|
||||||
|
//PortalFlag portalState= vreq.getPortalFlag();
|
||||||
|
|
||||||
|
String message = "";
|
||||||
|
List<VClassGroup> groups = getGroups(vreq.getWebappDaoFactory().getVClassGroupDao(), vreq.getPortal().getPortalId());
|
||||||
|
|
||||||
|
if (groups == null || groups.isEmpty()) {
|
||||||
|
message = "There are not yet any items in the system.";
|
||||||
|
body.put("message", message);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
List<VClassGroupView> vcgroups = new ArrayList<VClassGroupView>();
|
||||||
|
Iterator<VClassGroup> i = groups.iterator();
|
||||||
|
VClassGroup group;
|
||||||
|
VClassGroupView displayGroup;
|
||||||
|
while (i.hasNext()) {
|
||||||
|
group = (VClassGroup) i.next();
|
||||||
|
displayGroup = new VClassGroupView(group);
|
||||||
|
vcgroups.add(displayGroup);
|
||||||
|
}
|
||||||
|
body.put("classGroups", vcgroups);
|
||||||
|
}
|
||||||
|
|
||||||
|
String templateName = "body/browseGroups.ftl";
|
||||||
|
return mergeBodyToTemplate(templateName, body);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void destroy(){
|
||||||
|
_cacheRebuildThread.kill();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List getGroups( VClassGroupDao vcgDao, int portalId ){
|
||||||
|
List grp = _groupListMap.get(portalId);
|
||||||
|
if( grp == null ){
|
||||||
|
log.debug("needed to build vclassGroups for portal " + portalId);
|
||||||
|
// Get all classgroups, each populated with a list of their member vclasses
|
||||||
|
List groups = vcgDao.getPublicGroupsWithVClasses(ORDER_BY_DISPLAYRANK, !INCLUDE_UNINSTANTIATED);
|
||||||
|
|
||||||
|
// now cull out the groups with no populated classes
|
||||||
|
//removeUnpopulatedClasses( groups);
|
||||||
|
vcgDao.removeUnpopulatedGroups(groups);
|
||||||
|
|
||||||
|
_groupListMap.put(portalId, groups);
|
||||||
|
return groups;
|
||||||
|
} else {
|
||||||
|
return grp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean ORDER_BY_DISPLAYRANK = true;
|
||||||
|
private static boolean INCLUDE_UNINSTANTIATED = true;
|
||||||
|
|
||||||
|
// private void removeUnpopulatedClasses( List<VClassGroup> groups){
|
||||||
|
// if( groups == null || groups.size() == 0 ) return;
|
||||||
|
// for( VClassGroup grp : groups ){
|
||||||
|
// ListIterator it = grp.listIterator();
|
||||||
|
// while(it.hasNext()){
|
||||||
|
// VClass claz = (VClass)it.next();
|
||||||
|
// if( claz.getEntityCount() < 1 )
|
||||||
|
// it.remove();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
void requestCacheUpdate(String portalUri){
|
||||||
|
log.debug("requesting update for portal " + portalUri);
|
||||||
|
_rebuildQueue.add(portalUri);
|
||||||
|
_cacheRebuildThread.informOfQueueChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected synchronized void refreshGroupCache() {
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
try{
|
||||||
|
boolean rebuildAll = false;
|
||||||
|
HashSet<String> portalURIsToRebuild = new HashSet<String>();
|
||||||
|
String portalUri;
|
||||||
|
while ( null != (portalUri = _rebuildQueue.poll()) ){
|
||||||
|
if( portalUri.equals(REBUILD_EVERY_PORTAL)){
|
||||||
|
rebuildAll = true;
|
||||||
|
_rebuildQueue.clear();
|
||||||
|
break;
|
||||||
|
}else{
|
||||||
|
portalURIsToRebuild.add(portalUri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ServletContext sContext = getServletConfig().getServletContext();
|
||||||
|
ApplicationBean appBean = new ApplicationBean();
|
||||||
|
WebappDaoFactory wdFactory = (WebappDaoFactory)sContext.getAttribute("webappDaoFactory");
|
||||||
|
if( wdFactory == null ){
|
||||||
|
log.error("Unable to rebuild cache: could not get 'webappDaoFactory' from Servletcontext");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Collection<Portal> portals;
|
||||||
|
if( rebuildAll ){
|
||||||
|
portals = wdFactory.getPortalDao().getAllPortals();
|
||||||
|
} else {
|
||||||
|
portals = new LinkedList<Portal>();
|
||||||
|
for( String uri : portalURIsToRebuild){
|
||||||
|
Portal p =wdFactory.getPortalDao().getPortalByURI(uri);
|
||||||
|
if( p!= null)
|
||||||
|
portals.add(wdFactory.getPortalDao().getPortalByURI(uri));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(Portal portal : portals){
|
||||||
|
rebuildCacheForPortal(portal,appBean,wdFactory);
|
||||||
|
}
|
||||||
|
log.info("rebuilt ClassGroup cache in " + (System.currentTimeMillis() - start) + " msec");
|
||||||
|
}catch (Exception ex){
|
||||||
|
log.error("could not rebuild cache", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected synchronized void rebuildCacheForPortalUri(String uri){
|
||||||
|
ServletContext sContext = getServletConfig().getServletContext();
|
||||||
|
WebappDaoFactory wdFactory = (WebappDaoFactory)sContext.getAttribute("webappDaoFactory");
|
||||||
|
if( wdFactory == null ){
|
||||||
|
log.error("Unable to rebuild cache: could not get 'webappDaoFactory' from Servletcontext");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ApplicationBean appBean = new ApplicationBean();
|
||||||
|
Portal portal = wdFactory.getPortalDao().getPortalByURI(uri);
|
||||||
|
rebuildCacheForPortal(portal,appBean,wdFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected synchronized void rebuildCacheForPortal(Portal portal, ApplicationBean appBean, WebappDaoFactory wdFactory){
|
||||||
|
VitroFilters vFilters = null;
|
||||||
|
|
||||||
|
if( portal.isFlag1Filtering() ){
|
||||||
|
PortalFlag pflag = new PortalFlag(portal.getPortalId());
|
||||||
|
if( vFilters == null)
|
||||||
|
vFilters = VitroFilterUtils.getFilterFromPortalFlag(pflag);
|
||||||
|
else
|
||||||
|
vFilters = vFilters.and( VitroFilterUtils.getFilterFromPortalFlag(pflag));
|
||||||
|
}
|
||||||
|
WebappDaoFactory filteringDaoFactory ;
|
||||||
|
if( vFilters !=null ){
|
||||||
|
filteringDaoFactory = new WebappDaoFactoryFiltering(wdFactory,vFilters);
|
||||||
|
}else{
|
||||||
|
filteringDaoFactory = wdFactory;
|
||||||
|
}
|
||||||
|
_groupListMap.remove(portal.getPortalId());
|
||||||
|
getGroups(filteringDaoFactory.getVClassGroupDao(),portal.getPortalId());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearGroupCache(){
|
||||||
|
_groupListMap = new ConcurrentHashMap<Integer, List>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ****************** Jena Model Change Listener***************************** */
|
||||||
|
private class BrowseControllerChangeListener extends StatementListener {
|
||||||
|
private BrowseControllerFM controller = null;
|
||||||
|
public BrowseControllerChangeListener(BrowseControllerFM controller){
|
||||||
|
this.controller=controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addedStatement(Statement stmt) {
|
||||||
|
checkAndDoUpdate(stmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removedStatement(Statement stmt) {
|
||||||
|
checkAndDoUpdate(stmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkAndDoUpdate(Statement stmt){
|
||||||
|
if( stmt==null ) return;
|
||||||
|
if( log.isDebugEnabled()){
|
||||||
|
log.debug("subject: " + stmt.getSubject().getURI());
|
||||||
|
log.debug("predicate: " + stmt.getPredicate().getURI());
|
||||||
|
}
|
||||||
|
if( RDF.type.getURI().equals( stmt.getPredicate().getURI()) ){
|
||||||
|
requestCacheUpdate(REBUILD_EVERY_PORTAL);
|
||||||
|
} else if( VitroVocabulary.PORTAL_FLAG1FILTERING.equals( stmt.getPredicate().getURI())){
|
||||||
|
requestCacheUpdate(stmt.getSubject().getURI());
|
||||||
|
} else if( VitroVocabulary.IN_CLASSGROUP.equals( stmt.getPredicate().getURI() )){
|
||||||
|
requestCacheUpdate(REBUILD_EVERY_PORTAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* ******************** RebuildGroupCacheThread **************** */
|
||||||
|
protected class RebuildGroupCacheThread extends Thread {
|
||||||
|
BrowseControllerFM controller;
|
||||||
|
boolean die = false;
|
||||||
|
boolean queueChange = false;
|
||||||
|
long queueChangeMills = 0;
|
||||||
|
private boolean awareOfQueueChange = false;
|
||||||
|
|
||||||
|
RebuildGroupCacheThread(BrowseControllerFM controller) {
|
||||||
|
this.controller = controller;
|
||||||
|
}
|
||||||
|
public void run() {
|
||||||
|
while(true){
|
||||||
|
try{
|
||||||
|
synchronized (this){
|
||||||
|
if( _rebuildQueue.isEmpty() ){
|
||||||
|
log.debug("rebuildGroupCacheThread.run() -- queye empty, sleep");
|
||||||
|
wait(1000 * 60 );
|
||||||
|
}
|
||||||
|
if( die ) {
|
||||||
|
log.debug("doing rebuildGroupCacheThread.run() -- die()");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if( queueChange && !awareOfQueueChange){
|
||||||
|
log.debug("rebuildGroupCacheThread.run() -- awareOfQueueChange, delay start of rebuild");
|
||||||
|
awareOfQueueChange = true;
|
||||||
|
wait(200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( awareOfQueueChange && System.currentTimeMillis() - queueChangeMills > 200){
|
||||||
|
log.debug("rebuildGroupCacheThread.run() -- refreshGroupCache()");
|
||||||
|
controller.refreshGroupCache();
|
||||||
|
synchronized( this){
|
||||||
|
queueChange = false;
|
||||||
|
}
|
||||||
|
awareOfQueueChange = false;
|
||||||
|
}else {
|
||||||
|
synchronized( this ){
|
||||||
|
wait(200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch(InterruptedException e){}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized void informOfQueueChange(){
|
||||||
|
queueChange = true;
|
||||||
|
queueChangeMills = System.currentTimeMillis();
|
||||||
|
this.notifyAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized void kill(){
|
||||||
|
die = true;
|
||||||
|
notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static String REBUILD_EVERY_PORTAL ="Rebuild every portal.";
|
||||||
|
}
|
|
@ -66,7 +66,8 @@ public class Controllers {
|
||||||
public static final String TAB_PRIMARY_JSP = "/templates/tabs/tabprimary.jsp";
|
public static final String TAB_PRIMARY_JSP = "/templates/tabs/tabprimary.jsp";
|
||||||
|
|
||||||
public static final String ALPHA_INDEX_JSP = "/templates/alpha/alphaIndex.jsp";
|
public static final String ALPHA_INDEX_JSP = "/templates/alpha/alphaIndex.jsp";
|
||||||
|
|
||||||
|
public static final String SEARCH_URL = "/search";
|
||||||
public static final String SEARCH_BASIC_JSP = "/templates/search/searchBasic.jsp";
|
public static final String SEARCH_BASIC_JSP = "/templates/search/searchBasic.jsp";
|
||||||
public static final String SEARCH_PAGED_JSP = "/templates/search/searchPaged.jsp";
|
public static final String SEARCH_PAGED_JSP = "/templates/search/searchPaged.jsp";
|
||||||
public static final String SEARCH_FAILED_JSP = "/templates/search/searchFailed.jsp";
|
public static final String SEARCH_FAILED_JSP = "/templates/search/searchFailed.jsp";
|
||||||
|
@ -86,7 +87,9 @@ public class Controllers {
|
||||||
public static final String TOGGLE_SCRIPT_ELEMENT = "<script language='JavaScript' type='text/javascript' src='js/toggle.js'></script>";
|
public static final String TOGGLE_SCRIPT_ELEMENT = "<script language='JavaScript' type='text/javascript' src='js/toggle.js'></script>";
|
||||||
|
|
||||||
public static final Object SEARCH_ERROR_JSP = "/search_error.jsp";
|
public static final Object SEARCH_ERROR_JSP = "/search_error.jsp";
|
||||||
|
|
||||||
|
public static final String CONTACT_URL = "/comments";
|
||||||
|
|
||||||
//public static final String TAB_ENTITIES_LIST_JSP = "templates/tab/tabEntities.jsp";
|
//public static final String TAB_ENTITIES_LIST_JSP = "templates/tab/tabEntities.jsp";
|
||||||
|
|
||||||
private static List letters = null;
|
private static List letters = null;
|
||||||
|
|
|
@ -0,0 +1,292 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.controller;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import javax.servlet.http.HttpSession;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vedit.beans.LoginFormBean;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.beans.ApplicationBean;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.beans.Portal;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.utils.StringUtils;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.view.menu.TabMenu;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.web.PortalWebUtil;
|
||||||
|
import freemarker.template.Configuration;
|
||||||
|
import freemarker.template.Template;
|
||||||
|
import freemarker.template.TemplateException;
|
||||||
|
import freemarker.template.TemplateModelException;
|
||||||
|
|
||||||
|
public class FreeMarkerHttpServlet extends VitroHttpServlet {
|
||||||
|
|
||||||
|
private static final Log log = LogFactory.getLog(FreeMarkerHttpServlet.class.getName());
|
||||||
|
private static final int FILTER_SECURITY_LEVEL = LoginFormBean.EDITOR;
|
||||||
|
|
||||||
|
public static Configuration config = null;
|
||||||
|
public static String contextPath = null; // RY or do we need to store the entire ServletContext?
|
||||||
|
|
||||||
|
protected VitroRequest vreq;
|
||||||
|
protected HttpServletResponse response;
|
||||||
|
protected Portal portal;
|
||||||
|
protected Map<String, Object> root = new HashMap<String, Object>();
|
||||||
|
|
||||||
|
// Some servlets have their own doGet() method, in which case they need to call
|
||||||
|
// doSetup(), setTitle(), setBody(), and write() themselves. Other servlets define only
|
||||||
|
// a getBody() and getTitle() method and use the parent doGet() method.
|
||||||
|
public void doGet( HttpServletRequest request, HttpServletResponse response )
|
||||||
|
throws IOException, ServletException {
|
||||||
|
try {
|
||||||
|
doSetup(request, response);
|
||||||
|
setTitle();
|
||||||
|
setBody();
|
||||||
|
write(response);
|
||||||
|
|
||||||
|
} catch (Throwable e) {
|
||||||
|
log.error("FreeMarkerHttpServlet could not forward to view.");
|
||||||
|
log.error(e.getMessage());
|
||||||
|
log.error(e.getStackTrace());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doPost(HttpServletRequest request, HttpServletResponse response)
|
||||||
|
throws ServletException, IOException {
|
||||||
|
doGet(request, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setBody() {
|
||||||
|
root.put("body", getBody());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setSharedVariable(String key, String value) {
|
||||||
|
try {
|
||||||
|
config.setSharedVariable(key, value);
|
||||||
|
} catch (TemplateModelException e) {
|
||||||
|
log.error("Can't set shared variable '" + key + "'.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setTitle() {
|
||||||
|
setSharedVariable("title", getTitle());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getTitle() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getBody() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected StringWriter mergeToTemplate(String templateName, Map<String, Object> map) {
|
||||||
|
|
||||||
|
Template template = null;
|
||||||
|
try {
|
||||||
|
template = config.getTemplate(templateName);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Cannot get template " + templateName);
|
||||||
|
}
|
||||||
|
StringWriter sw = new StringWriter();
|
||||||
|
if (template != null) {
|
||||||
|
try {
|
||||||
|
template.process(map, sw);
|
||||||
|
} catch (TemplateException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sw;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String mergeBodyToTemplate(String templateName, Map<String, Object> map) {
|
||||||
|
String body = mergeToTemplate(templateName, map).toString();
|
||||||
|
extractLinkTagsFromBody(body);
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is the only way to do this in FreeMarker. We cannot: (1) put a sequence of stylesheets in the template
|
||||||
|
// context which the template can add to, because the template cannot call methods on the container. The template
|
||||||
|
// can create a container but not add to one.
|
||||||
|
// (2) create a sequence of stylesheets or a scalar to hold the name of a stylesheet in the template, because
|
||||||
|
// it does not get passed back to the controller. The template can create only local variables.
|
||||||
|
|
||||||
|
// *** RY But we can create a view object with an add method, that the templates could use to add to the
|
||||||
|
// list. ***
|
||||||
|
private String extractLinkTagsFromBody(String body) {
|
||||||
|
List<String> links = new ArrayList<String>();
|
||||||
|
|
||||||
|
String re = "<link[^>]*>";
|
||||||
|
Pattern pattern = Pattern.compile(re);
|
||||||
|
Matcher matcher = pattern.matcher(body);
|
||||||
|
while (matcher.find()) {
|
||||||
|
links.add(matcher.group());
|
||||||
|
}
|
||||||
|
|
||||||
|
root.put("stylesheets", links); // SIDE-EFFECT
|
||||||
|
|
||||||
|
body = matcher.replaceAll("");
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void write(HttpServletResponse response) {
|
||||||
|
|
||||||
|
String templateName = "page/default.ftl";
|
||||||
|
StringWriter sw = mergeToTemplate(templateName, root);
|
||||||
|
try {
|
||||||
|
PrintWriter out = response.getWriter();
|
||||||
|
out.print(sw);
|
||||||
|
} catch (IOException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void doSetup(HttpServletRequest request, HttpServletResponse response) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
super.doGet(request,response);
|
||||||
|
} catch (ServletException e1) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e1.printStackTrace();
|
||||||
|
} catch (IOException e1) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e1.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
vreq = new VitroRequest(request);
|
||||||
|
this.response = response;
|
||||||
|
portal = vreq.getPortal();
|
||||||
|
|
||||||
|
// RY Can this be removed? Do templates need it? Ideally, they should not.
|
||||||
|
// Only needed for some weird stuff in search box that I think is only used in old default theme.
|
||||||
|
int portalId = portal.getPortalId();
|
||||||
|
try {
|
||||||
|
config.setSharedVariable("portalId", portalId);
|
||||||
|
} catch (TemplateModelException e) {
|
||||||
|
log.error("Can't set shared variable 'portalId'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
TabMenu menu = getTabMenu(portalId);
|
||||||
|
root.put("tabMenu", menu);
|
||||||
|
|
||||||
|
ApplicationBean appBean = vreq.getAppBean();
|
||||||
|
PortalWebUtil.populateSearchOptions(portal, appBean, vreq.getWebappDaoFactory().getPortalDao());
|
||||||
|
PortalWebUtil.populateNavigationChoices(portal, vreq, appBean, vreq.getWebappDaoFactory().getPortalDao());
|
||||||
|
|
||||||
|
// We'll need to separate theme-general and theme-specific stylesheet
|
||||||
|
// dirs, so we need either two attributes or a list.
|
||||||
|
String themeDir = portal.getThemeDir();
|
||||||
|
String stylesheetDir = getUrl(themeDir + "css/");
|
||||||
|
try {
|
||||||
|
config.setSharedVariable("stylesheetDir", stylesheetDir);
|
||||||
|
} catch (TemplateModelException e) {
|
||||||
|
log.error("Can't set shared variable 'stylesheetDir'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
root.put("siteName", portal.getAppName());
|
||||||
|
root.put("tagline", portal.getShortHand());
|
||||||
|
|
||||||
|
setUrls(portalId, themeDir);
|
||||||
|
setLoginInfo();
|
||||||
|
setCopyrightInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define the URLs that are accessible to the templates. Note that we do not create menus here,
|
||||||
|
// because we want the templates to be free to define the link text and where the links are displayed.
|
||||||
|
private final void setUrls(int portalId, String themeDir) {
|
||||||
|
// The urls that are accessible to the templates.
|
||||||
|
// NB We are not using our menu object mechanism to build menus here, because we want the
|
||||||
|
// view to control which links go where, and the link text and title.
|
||||||
|
Map<String, String> urls = new HashMap<String, String>();
|
||||||
|
|
||||||
|
String homeUrl = (portal.getRootBreadCrumbURL()!=null && portal.getRootBreadCrumbURL().length()>0) ?
|
||||||
|
portal.getRootBreadCrumbURL() : vreq.getContextPath()+"/";
|
||||||
|
urls.put("home", homeUrl);
|
||||||
|
|
||||||
|
String bannerImage = portal.getBannerImage();
|
||||||
|
if ( ! StringUtils.isEmpty(bannerImage)) {
|
||||||
|
root.put("bannerImage", getUrl(themeDir + "site_icons/" + bannerImage));
|
||||||
|
}
|
||||||
|
|
||||||
|
urls.put("about", getUrl(Controllers.ABOUT + "?home=" + portalId));
|
||||||
|
urls.put("aboutFM", getUrl(Controllers.ABOUT + "-fm?home=" + portalId)); // TEMPORARY
|
||||||
|
if (ContactMailServlet.getSmtpHostFromProperties() != null) {
|
||||||
|
urls.put("contact", getUrl(Controllers.CONTACT_URL + "?home=" + portalId));
|
||||||
|
}
|
||||||
|
urls.put("search", getUrl(Controllers.SEARCH_URL));
|
||||||
|
urls.put("termsOfUse", getUrl("/termsOfUse?home=" + portalId));
|
||||||
|
urls.put("login", getUrl(Controllers.LOGIN));
|
||||||
|
urls.put("logout", getUrl(Controllers.LOGOUT));
|
||||||
|
urls.put("siteAdmin", getUrl(Controllers.SITE_ADMIN));
|
||||||
|
|
||||||
|
root.put("urls", urls);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final void setLoginInfo() {
|
||||||
|
|
||||||
|
String loginName = null;
|
||||||
|
int securityLevel;
|
||||||
|
|
||||||
|
HttpSession session = vreq.getSession();
|
||||||
|
LoginFormBean loginBean = (LoginFormBean) session.getAttribute("loginHandler");
|
||||||
|
if (loginBean != null && loginBean.testSessionLevel(vreq) > -1) {
|
||||||
|
loginName = loginBean.getLoginName();
|
||||||
|
securityLevel = Integer.parseInt(loginBean.getLoginRole());
|
||||||
|
}
|
||||||
|
if (loginName != null) {
|
||||||
|
root.put("loginName", loginName);
|
||||||
|
|
||||||
|
securityLevel = Integer.parseInt(loginBean.getLoginRole());
|
||||||
|
if (securityLevel >= FILTER_SECURITY_LEVEL) {
|
||||||
|
ApplicationBean appBean = vreq.getAppBean();
|
||||||
|
if (appBean.isFlag1Active()) {
|
||||||
|
root.put("showFlag1SearchField", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final void setCopyrightInfo() {
|
||||||
|
|
||||||
|
String copyrightText = portal.getCopyrightAnchor();
|
||||||
|
if ( ! StringUtils.isEmpty(copyrightText) ) {
|
||||||
|
Map<String, Object> copyright = new HashMap<String, Object>();
|
||||||
|
copyright.put("text", copyrightText);
|
||||||
|
int thisYear = Calendar.getInstance().get(Calendar.YEAR); // use ${copyrightYear?c} in template
|
||||||
|
//String thisYear = ((Integer)Calendar.getInstance().get(Calendar.YEAR)).toString(); // use ${copyrightYear} in template
|
||||||
|
//SimpleDate thisYear = new SimpleDate(Calendar.getInstance().getTime(), TemplateDateModel.DATE); // use ${copyrightYear?string("yyyy")} in template
|
||||||
|
copyright.put("year", thisYear);
|
||||||
|
copyright.put("url", portal.getCopyrightURL());
|
||||||
|
root.put("copyright", copyright);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getUrl(String path) {
|
||||||
|
if ( ! path.startsWith("/") ) {
|
||||||
|
path = "/" + path;
|
||||||
|
}
|
||||||
|
return contextPath + path;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TabMenu getTabMenu(int portalId) {
|
||||||
|
return new TabMenu(vreq, portalId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,681 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.controller;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import javax.servlet.RequestDispatcher;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.ServletOutputStream;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import javax.servlet.http.HttpSession;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import com.hp.hpl.jena.datatypes.TypeMapper;
|
||||||
|
import com.hp.hpl.jena.ontology.OntModel;
|
||||||
|
import com.hp.hpl.jena.rdf.model.Literal;
|
||||||
|
import com.hp.hpl.jena.rdf.model.Model;
|
||||||
|
import com.hp.hpl.jena.rdf.model.ModelFactory;
|
||||||
|
import com.hp.hpl.jena.rdf.model.Property;
|
||||||
|
import com.hp.hpl.jena.rdf.model.RDFNode;
|
||||||
|
import com.hp.hpl.jena.rdf.model.Resource;
|
||||||
|
import com.hp.hpl.jena.shared.Lock;
|
||||||
|
import com.hp.hpl.jena.vocabulary.RDF;
|
||||||
|
import com.hp.hpl.jena.vocabulary.RDFS;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.beans.ApplicationBean;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.beans.DataPropertyStatement;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatement;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.beans.Portal;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.beans.VClass;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.dao.IndividualDao;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.dao.ObjectPropertyDao;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.search.beans.VitroQuery;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.search.beans.VitroQueryWrapper;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.utils.NamespaceMapper;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.utils.NamespaceMapperFactory;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.web.ContentType;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.web.jsptags.StringProcessorTag;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles requests for entity information.
|
||||||
|
* Calls EntityPropertyListController to draw property list.
|
||||||
|
*
|
||||||
|
* @author bdc34
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class IndividualControllerFM extends VitroHttpServlet {
|
||||||
|
private static final Log log = LogFactory.getLog(IndividualControllerFM.class.getName());
|
||||||
|
|
||||||
|
private String default_jsp = Controllers.BASIC_JSP;
|
||||||
|
private String default_body_jsp = Controllers.ENTITY_JSP;
|
||||||
|
private ApplicationBean appBean;
|
||||||
|
|
||||||
|
public void doGet( HttpServletRequest req, HttpServletResponse res )
|
||||||
|
throws IOException, ServletException {
|
||||||
|
try {
|
||||||
|
super.doGet(req, res);
|
||||||
|
|
||||||
|
VitroRequest vreq = new VitroRequest(req);
|
||||||
|
//get URL without hostname or servlet context
|
||||||
|
String url = req.getRequestURI().substring(req.getContextPath().length());
|
||||||
|
|
||||||
|
//Check to see if the request is for a non-information resource, redirect if it is.
|
||||||
|
String redirectURL = checkForRedirect ( url, req.getHeader("accept") );
|
||||||
|
if( redirectURL != null ){
|
||||||
|
doRedirect( req, res, redirectURL );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentType rdfFormat = checkForLinkedDataRequest(url,req.getHeader("accept"));
|
||||||
|
if( rdfFormat != null ){
|
||||||
|
doRdf( vreq, res, rdfFormat );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Individual indiv = null;
|
||||||
|
try{
|
||||||
|
indiv = getEntityFromRequest( vreq);
|
||||||
|
}catch(Throwable th){
|
||||||
|
doHelp(res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( indiv == null || checkForHidden(vreq, indiv) || checkForSunset(vreq, indiv)){
|
||||||
|
doNotFound(vreq, res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
doHtml( vreq, res , indiv);
|
||||||
|
return;
|
||||||
|
|
||||||
|
} catch (Throwable e) {
|
||||||
|
log.error(e);
|
||||||
|
req.setAttribute("javax.servlet.jsp.jspException",e);
|
||||||
|
RequestDispatcher rd = req.getRequestDispatcher("/error.jsp");
|
||||||
|
rd.forward(req, res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doHtml(VitroRequest vreq, HttpServletResponse res, Individual indiv) throws ServletException, IOException {
|
||||||
|
IndividualDao iwDao = vreq.getWebappDaoFactory().getIndividualDao();
|
||||||
|
ObjectPropertyDao opDao = vreq.getWebappDaoFactory().getObjectPropertyDao();
|
||||||
|
|
||||||
|
//Check if a "relatedSubjectUri" parameter has been supplied, and,
|
||||||
|
//if so, retrieve the related individual.t
|
||||||
|
//Some individuals make little sense standing alone and should
|
||||||
|
//be displayed in the context of their relationship to another.
|
||||||
|
String relatedSubjectUri = vreq.getParameter("relatedSubjectUri");
|
||||||
|
if (relatedSubjectUri != null) {
|
||||||
|
Individual relatedSubjectInd = iwDao.getIndividualByURI(relatedSubjectUri);
|
||||||
|
if (relatedSubjectInd != null) {
|
||||||
|
vreq.setAttribute("relatedSubject", relatedSubjectInd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String relatingPredicateUri = vreq.getParameter("relatingPredicateUri");
|
||||||
|
if (relatingPredicateUri != null) {
|
||||||
|
ObjectProperty relatingPredicateProp = opDao.getObjectPropertyByURI(relatingPredicateUri);
|
||||||
|
if (relatingPredicateProp != null) {
|
||||||
|
vreq.setAttribute("relatingPredicate", relatingPredicateProp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
indiv.setKeywords(iwDao.getKeywordsForIndividualByMode(indiv.getURI(),"visible"));
|
||||||
|
indiv.sortForDisplay();
|
||||||
|
|
||||||
|
String vclassName = "unknown";
|
||||||
|
String customView = null;
|
||||||
|
String customCss = null;
|
||||||
|
if( indiv.getVClass() != null ){
|
||||||
|
vclassName = indiv.getVClass().getName();
|
||||||
|
List<VClass> clasList = indiv.getVClasses(true);
|
||||||
|
for (VClass clas : clasList) {
|
||||||
|
customView = clas.getCustomDisplayView();
|
||||||
|
if (customView != null) {
|
||||||
|
if (customView.length()>0) {
|
||||||
|
vclassName = clas.getName(); // reset entity vclassname to name of class where a custom view
|
||||||
|
log.debug("Found direct class ["+clas.getName()+"] with custom view "+customView+"; resetting entity vclassName to this class");
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
customView = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (customView == null) { //still
|
||||||
|
clasList = indiv.getVClasses(false);
|
||||||
|
for (VClass clas : clasList) {
|
||||||
|
customView = clas.getCustomDisplayView();
|
||||||
|
if (customView != null) {
|
||||||
|
if (customView.length()>0) {
|
||||||
|
// note that NOT changing entity vclassName here yet
|
||||||
|
log.debug("Found inferred class ["+clas.getName()+"] with custom view "+customView);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
customView = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.error("Entity " + indiv.getURI() + " with vclass URI " +
|
||||||
|
indiv.getVClassURI() + ", no vclass with that URI exists");
|
||||||
|
}
|
||||||
|
if (customView!=null) {
|
||||||
|
// insert test for whether a css files of the same name exists, and populate the customCss string for use when construction the header
|
||||||
|
}
|
||||||
|
String netid = iwDao.getNetId(indiv.getURI());
|
||||||
|
|
||||||
|
vreq.setAttribute("netid", netid);
|
||||||
|
vreq.setAttribute("vclassName", vclassName);
|
||||||
|
vreq.setAttribute("entity",indiv);
|
||||||
|
Portal portal = vreq.getPortal();
|
||||||
|
vreq.setAttribute("portal",String.valueOf(portal));
|
||||||
|
String view= getViewFromRequest(vreq);
|
||||||
|
if( view == null){
|
||||||
|
if (customView == null) {
|
||||||
|
view = default_jsp;
|
||||||
|
vreq.setAttribute("bodyJsp","/"+Controllers.ENTITY_JSP);
|
||||||
|
log.debug("no custom view and no view parameter in request for rendering "+indiv.getName());
|
||||||
|
} else {
|
||||||
|
view = default_jsp;
|
||||||
|
log.debug("setting custom view templates/entity/"+ customView + " for rendering "+indiv.getName());
|
||||||
|
vreq.setAttribute("bodyJsp", "/templates/entity/"+customView);
|
||||||
|
}
|
||||||
|
vreq.setAttribute("entityPropsListJsp",Controllers.ENTITY_PROP_LIST_JSP);
|
||||||
|
vreq.setAttribute("entityDatapropsListJsp",Controllers.ENTITY_DATAPROP_LIST_JSP);
|
||||||
|
vreq.setAttribute("entityMergedPropsListJsp",Controllers.ENTITY_MERGED_PROP_LIST_GROUPED_JSP);
|
||||||
|
vreq.setAttribute("entityKeywordsListJsp",Controllers.ENTITY_KEYWORDS_LIST_JSP);
|
||||||
|
} else {
|
||||||
|
log.debug("Found view parameter "+view+" in request for rendering "+indiv.getName());
|
||||||
|
}
|
||||||
|
//set title before we do the highlighting so we don't get markup in it.
|
||||||
|
vreq.setAttribute("title",indiv.getName());
|
||||||
|
//setup highlighter for search terms
|
||||||
|
checkForSearch(vreq, indiv);
|
||||||
|
|
||||||
|
// set CSS and script elements
|
||||||
|
String contextPath = "";
|
||||||
|
if (vreq.getContextPath().length()>1) {
|
||||||
|
contextPath = vreq.getContextPath();
|
||||||
|
}
|
||||||
|
String css = "<link rel=\"stylesheet\" type=\"text/css\" media=\"screen\" href=\""
|
||||||
|
+ contextPath + "/" + portal.getThemeDir() + "css/entity.css\"/>\n"
|
||||||
|
+ "<script language='JavaScript' type='text/javascript' src='"+contextPath+"/js/toggle.js'></script> \n";
|
||||||
|
if (customCss!=null) {
|
||||||
|
css += customCss;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( indiv.getURI().startsWith( vreq.getWebappDaoFactory().getDefaultNamespace() )){
|
||||||
|
vreq.setAttribute("entityLinkedDataURL", indiv.getURI() + "/" + indiv.getLocalName() + ".rdf");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// generate link to RDF representation for semantic web clients like Piggy Bank
|
||||||
|
// BJL 2008-07-16: I'm temporarily commenting this out because I forgot we need to make sure it filters out the hidden properties
|
||||||
|
// generate url for this entity
|
||||||
|
// String individualToRDF = "http://"+vreq.getServerName()+":"+vreq.getServerPort()+vreq.getContextPath()+"/entity?home=1&uri="+forURL(entity.getURI())+"&view=rdf.rdf";
|
||||||
|
//css += "<link rel='alternate' type='application/rdf+xml' title='"+entity.getName()+"' href='"+individualToRDF+"' />";
|
||||||
|
|
||||||
|
vreq.setAttribute("css",css);
|
||||||
|
vreq.setAttribute("scripts", "/templates/entity/entity_inject_head.jsp");
|
||||||
|
|
||||||
|
RequestDispatcher rd = vreq.getRequestDispatcher( view );
|
||||||
|
rd.forward(vreq,res);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doRdf(VitroRequest vreq, HttpServletResponse res,
|
||||||
|
ContentType rdfFormat) throws IOException, ServletException {
|
||||||
|
|
||||||
|
Individual indiv = getEntityFromRequest(vreq);
|
||||||
|
if( indiv == null ){
|
||||||
|
doNotFound(vreq, res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OntModel ontModel = null;
|
||||||
|
HttpSession session = vreq.getSession(false);
|
||||||
|
if( session != null )
|
||||||
|
ontModel =(OntModel)session.getAttribute("jenaOntModel");
|
||||||
|
if( ontModel == null)
|
||||||
|
ontModel = (OntModel)getServletContext().getAttribute("jenaOntModel");
|
||||||
|
|
||||||
|
Model newModel;
|
||||||
|
newModel = getRDF(indiv, ontModel, ModelFactory.createDefaultModel(), 0);
|
||||||
|
|
||||||
|
res.setContentType(rdfFormat.getMediaType());
|
||||||
|
String format = "";
|
||||||
|
if ( RDFXML_MIMETYPE.equals(rdfFormat.getMediaType()))
|
||||||
|
format = "RDF/XML";
|
||||||
|
else if( N3_MIMETYPE.equals(rdfFormat.getMediaType()))
|
||||||
|
format = "N3";
|
||||||
|
else if ( TTL_MIMETYPE.equals(rdfFormat.getMediaType()))
|
||||||
|
format ="TTL";
|
||||||
|
|
||||||
|
newModel.write( res.getOutputStream(), format );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doRedirect(HttpServletRequest req, HttpServletResponse res,
|
||||||
|
String redirectURL) {
|
||||||
|
// It seems like there must be a better way to do this
|
||||||
|
String hn = req.getHeader("Host");
|
||||||
|
res.setHeader("Location", res.encodeURL( "http://" + hn + req.getContextPath() + redirectURL ));
|
||||||
|
res.setStatus(res.SC_SEE_OTHER);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static Pattern LINKED_DATA_URL = Pattern.compile("^/individual/([^/]*)$");
|
||||||
|
private static Pattern NS_PREFIX_URL = Pattern.compile("^/individual/([^/]*)/([^/]*)$");
|
||||||
|
|
||||||
|
/**
|
||||||
|
Gets the entity id from the request.
|
||||||
|
Works for the following styles of URLs:
|
||||||
|
|
||||||
|
/individual?id=individualLocalName
|
||||||
|
/individual?entityId=individualLocalName
|
||||||
|
/individual?uri=urlencodedURI
|
||||||
|
/individual?nedit=bdc34
|
||||||
|
/individual?nedIt=bdc34
|
||||||
|
/individual/nsprefix/localname
|
||||||
|
/individual/localname
|
||||||
|
/individual/localname/localname.rdf
|
||||||
|
/individual/localname/localname.n3
|
||||||
|
/individual/localname/localname.ttl
|
||||||
|
/individual/localname/localname.html
|
||||||
|
|
||||||
|
@return null on failure.
|
||||||
|
*/
|
||||||
|
public static Individual getEntityFromRequest(VitroRequest vreq) {
|
||||||
|
String netIdStr = null;
|
||||||
|
Individual entity = null;
|
||||||
|
IndividualDao iwDao = vreq.getWebappDaoFactory().getIndividualDao();
|
||||||
|
|
||||||
|
String entityIdStr = vreq.getParameter("id");
|
||||||
|
if (entityIdStr == null || entityIdStr.equals(""))
|
||||||
|
entityIdStr = vreq.getParameter("entityId");
|
||||||
|
|
||||||
|
if( entityIdStr != null){
|
||||||
|
try {
|
||||||
|
String entityURI = vreq.getWebappDaoFactory().getDefaultNamespace()+"individual"+entityIdStr;
|
||||||
|
entity = iwDao.getIndividualByURI(entityURI);
|
||||||
|
} catch ( Exception e ) {
|
||||||
|
log.warn("Could not parse entity id: " + entityIdStr);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
String entityURIStr = vreq.getParameter("uri");
|
||||||
|
if (entityURIStr != null) {
|
||||||
|
try {
|
||||||
|
entity = iwDao.getIndividualByURI(entityURIStr);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("Could not retrieve entity "+entityURIStr);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
//get URL without hostname or servlet context
|
||||||
|
String url = vreq.getRequestURI().substring(vreq.getContextPath().length());
|
||||||
|
|
||||||
|
/* check for parts of URL that indicate request for RDF
|
||||||
|
http://vivo.cornell.edu/individual/n23/n23.rdf
|
||||||
|
http://vivo.cornell.edu/individual/n23/n23.n3
|
||||||
|
http://vivo.cornell.edu/individual/n23/n23.ttl */
|
||||||
|
String uri = null;
|
||||||
|
Matcher m = RDF_REQUEST.matcher(url);
|
||||||
|
if( m.matches() && m.groupCount() == 1)
|
||||||
|
uri = m.group(1);
|
||||||
|
m = N3_REQUEST.matcher(url);
|
||||||
|
if( m.matches() && m.groupCount() == 1)
|
||||||
|
uri = m.group(1);
|
||||||
|
m = TTL_REQUEST.matcher(url);
|
||||||
|
if( m.matches() && m.groupCount() == 1)
|
||||||
|
uri= m.group(1);
|
||||||
|
m = HTML_REQUEST.matcher(url);
|
||||||
|
if( m.matches() && m.groupCount() == 1)
|
||||||
|
uri= m.group(1);
|
||||||
|
if( uri != null )
|
||||||
|
return iwDao.getIndividualByURI(vreq.getWebappDaoFactory().getDefaultNamespace() + uri);
|
||||||
|
|
||||||
|
// see if we can get the URI from a name space prefix and a local name
|
||||||
|
Matcher prefix_match = NS_PREFIX_URL.matcher(url);
|
||||||
|
if( prefix_match.matches() && prefix_match.groupCount() == 2){
|
||||||
|
String prefix = prefix_match.group(1);
|
||||||
|
String localName = prefix_match.group(2);
|
||||||
|
|
||||||
|
//String[] requestParts = requestURI.split("/individual/");
|
||||||
|
//String[] URIParts = requestParts[1].split("/");
|
||||||
|
//String localName = URIParts[1];
|
||||||
|
|
||||||
|
String namespace = "";
|
||||||
|
NamespaceMapper namespaceMapper = NamespaceMapperFactory.getNamespaceMapper(vreq.getSession().getServletContext());
|
||||||
|
String t;
|
||||||
|
namespace = ( (t = namespaceMapper.getNamespaceForPrefix(prefix)) != null) ? t : "";
|
||||||
|
|
||||||
|
return iwDao.getIndividualByURI(namespace+localName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// see if we can get a local name
|
||||||
|
Matcher linkedDataMatch = LINKED_DATA_URL.matcher(url);
|
||||||
|
if( linkedDataMatch.matches() && linkedDataMatch.groupCount() == 1){
|
||||||
|
String localName = linkedDataMatch.group(1);
|
||||||
|
String ns = vreq.getWebappDaoFactory().getDefaultNamespace();
|
||||||
|
return iwDao.getIndividualByURI( ns + localName );
|
||||||
|
}
|
||||||
|
|
||||||
|
//so we try to get the netid
|
||||||
|
netIdStr = vreq.getParameter("netId");
|
||||||
|
if (netIdStr==null || netIdStr.equals(""))
|
||||||
|
netIdStr = vreq.getParameter("netid");
|
||||||
|
if ( netIdStr != null ){
|
||||||
|
uri = iwDao.getIndividualURIFromNetId(netIdStr);
|
||||||
|
return iwDao.getIndividualByURI(uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static Pattern URI_PATTERN = Pattern.compile("^/individual/([^/]*)$");
|
||||||
|
//Redirect if the request is for http://hostname/individual/localname
|
||||||
|
// if accept is nothing or text/html redirect to ???
|
||||||
|
// if accept is some RDF thing redirect to the URL for RDF
|
||||||
|
private String checkForRedirect(String url, String acceptHeader) {
|
||||||
|
Matcher m = URI_PATTERN.matcher(url);
|
||||||
|
if( m.matches() && m.groupCount() == 1 ){
|
||||||
|
ContentType c = checkForLinkedDataRequest(url, acceptHeader);
|
||||||
|
if( c != null ){
|
||||||
|
String redirectUrl = "/individual/" + m.group(1) + "/" + m.group(1) ;
|
||||||
|
if( RDFXML_MIMETYPE.equals( c.getMediaType()) ){
|
||||||
|
return redirectUrl + ".rdf";
|
||||||
|
}else if( N3_MIMETYPE.equals( c.getMediaType() )){
|
||||||
|
return redirectUrl + ".n3";
|
||||||
|
}else if( TTL_MIMETYPE.equals( c.getMediaType() )){
|
||||||
|
return redirectUrl + ".ttl";
|
||||||
|
}//else send them to html
|
||||||
|
}
|
||||||
|
//else redirect to HTML representation
|
||||||
|
return "/display/" + m.group(1) ;
|
||||||
|
}else{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Pattern RDF_REQUEST = Pattern.compile("^/individual/([^/]*)/\\1.rdf$");
|
||||||
|
private static Pattern N3_REQUEST = Pattern.compile("^/individual/([^/]*)/\\1.n3$");
|
||||||
|
private static Pattern TTL_REQUEST = Pattern.compile("^/individual/([^/]*)/\\1.ttl$");
|
||||||
|
private static Pattern HTML_REQUEST = Pattern.compile("^/display/([^/]*)$");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return null if this is not a linked data request, returns content type if it is a
|
||||||
|
* linked data request.
|
||||||
|
*/
|
||||||
|
private ContentType checkForLinkedDataRequest(String url, String acceptHeader) {
|
||||||
|
try {
|
||||||
|
//check the accept header
|
||||||
|
if (acceptHeader != null) {
|
||||||
|
List<ContentType> actualContentTypes = new ArrayList<ContentType>();
|
||||||
|
actualContentTypes.add(new ContentType( XHTML_MIMETYPE ));
|
||||||
|
actualContentTypes.add(new ContentType( HTML_MIMETYPE ));
|
||||||
|
|
||||||
|
actualContentTypes.add(new ContentType( RDFXML_MIMETYPE ));
|
||||||
|
actualContentTypes.add(new ContentType( N3_MIMETYPE ));
|
||||||
|
actualContentTypes.add(new ContentType( TTL_MIMETYPE ));
|
||||||
|
|
||||||
|
|
||||||
|
ContentType best = ContentType.getBestContentType(acceptHeader,actualContentTypes);
|
||||||
|
if (best!=null && (
|
||||||
|
RDFXML_MIMETYPE.equals(best.getMediaType()) ||
|
||||||
|
N3_MIMETYPE.equals(best.getMediaType()) ||
|
||||||
|
TTL_MIMETYPE.equals(best.getMediaType()) ))
|
||||||
|
return best;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* check for parts of URL that indicate request for RDF
|
||||||
|
http://vivo.cornell.edu/individual/n23/n23.rdf
|
||||||
|
http://vivo.cornell.edu/individual/n23/n23.n3
|
||||||
|
http://vivo.cornell.edu/individual/n23/n23.ttl
|
||||||
|
*/
|
||||||
|
|
||||||
|
Matcher m = RDF_REQUEST.matcher(url);
|
||||||
|
if( m.matches() )
|
||||||
|
return new ContentType(RDFXML_MIMETYPE);
|
||||||
|
m = N3_REQUEST.matcher(url);
|
||||||
|
if( m.matches() )
|
||||||
|
return new ContentType(N3_MIMETYPE);
|
||||||
|
m = TTL_REQUEST.matcher(url);
|
||||||
|
if( m.matches() )
|
||||||
|
return new ContentType(TTL_MIMETYPE);
|
||||||
|
|
||||||
|
} catch (Throwable th) {
|
||||||
|
log.error("problem while checking accept header " , th);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkForSunset(VitroRequest vreq, Individual entity) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkForHidden(VitroRequest vreq, Individual entity){
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Model getRDF(Individual entity, OntModel contextModel, Model newModel, int recurseDepth ) {
|
||||||
|
Resource subj = newModel.getResource(entity.getURI());
|
||||||
|
|
||||||
|
List<DataPropertyStatement> dstates = entity.getDataPropertyStatements();
|
||||||
|
//System.out.println("data: "+dstates.size());
|
||||||
|
TypeMapper typeMapper = TypeMapper.getInstance();
|
||||||
|
for (DataPropertyStatement ds: dstates) {
|
||||||
|
Property dp = newModel.getProperty(ds.getDatapropURI());
|
||||||
|
Literal lit = null;
|
||||||
|
if ((ds.getLanguage()) != null && (ds.getLanguage().length()>0)) {
|
||||||
|
lit = newModel.createLiteral(ds.getData(),ds.getLanguage());
|
||||||
|
} else if ((ds.getDatatypeURI() != null) && (ds.getDatatypeURI().length()>0)) {
|
||||||
|
lit = newModel.createTypedLiteral(ds.getData(),typeMapper.getSafeTypeByName(ds.getDatatypeURI()));
|
||||||
|
} else {
|
||||||
|
lit = newModel.createLiteral(ds.getData());
|
||||||
|
}
|
||||||
|
newModel.add(newModel.createStatement(subj, dp, lit));
|
||||||
|
}
|
||||||
|
|
||||||
|
if( recurseDepth < 5 ){
|
||||||
|
List<ObjectPropertyStatement> ostates = entity.getObjectPropertyStatements();
|
||||||
|
for (ObjectPropertyStatement os: ostates) {
|
||||||
|
ObjectProperty objProp = os.getProperty();
|
||||||
|
Property op = newModel.getProperty(os.getPropertyURI());
|
||||||
|
Resource obj = newModel.getResource(os.getObjectURI());
|
||||||
|
newModel.add(newModel.createStatement(subj, op, obj));
|
||||||
|
if( objProp.getStubObjectRelation() )
|
||||||
|
newModel.add(getRDF(os.getObject(), contextModel, newModel, recurseDepth + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newModel = getLabelAndTypes(entity, contextModel, newModel );
|
||||||
|
return newModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the properties that are difficult to get via a filtered WebappDaoFactory. */
|
||||||
|
private Model getLabelAndTypes(Individual entity, Model ontModel, Model newModel){
|
||||||
|
for( VClass vclass : entity.getVClasses()){
|
||||||
|
newModel.add(newModel.getResource(entity.getURI()), RDF.type, newModel.getResource(vclass.getURI()));
|
||||||
|
}
|
||||||
|
|
||||||
|
ontModel.enterCriticalSection(Lock.READ);
|
||||||
|
try {
|
||||||
|
newModel.add(ontModel.listStatements(ontModel.getResource(entity.getURI()), RDFS.label, (RDFNode)null));
|
||||||
|
} finally {
|
||||||
|
ontModel.leaveCriticalSection();
|
||||||
|
}
|
||||||
|
|
||||||
|
return newModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void checkForSearch(HttpServletRequest req, Individual ent) {
|
||||||
|
if (req.getSession().getAttribute("LastQuery") != null) {
|
||||||
|
VitroQueryWrapper qWrap = (VitroQueryWrapper) req.getSession()
|
||||||
|
.getAttribute("LastQuery");
|
||||||
|
if (qWrap.getRequestCount() > 0 && qWrap.getQuery() != null) {
|
||||||
|
VitroQuery query = qWrap.getQuery();
|
||||||
|
|
||||||
|
//set query text so we can get it in JSP
|
||||||
|
req.setAttribute("querytext", query.getTerms());
|
||||||
|
|
||||||
|
//setup highlighting for output
|
||||||
|
StringProcessorTag.putStringProcessorInRequest(req, qWrap.getHighlighter());
|
||||||
|
|
||||||
|
qWrap.setRequestCount(qWrap.getRequestCount() - 1);
|
||||||
|
} else {
|
||||||
|
req.getSession().removeAttribute("LastQuery");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Pattern badrequest= Pattern.compile(".*([&\\?=]|\\.\\.).*");
|
||||||
|
|
||||||
|
public String getViewFromRequest(HttpServletRequest request){
|
||||||
|
String viewParam = request.getParameter("view");
|
||||||
|
if( viewParam != null ){
|
||||||
|
if( badrequest.matcher(viewParam).matches() ){
|
||||||
|
log.debug("request for a non-default view was bad: " + viewParam);
|
||||||
|
return null;
|
||||||
|
}else{
|
||||||
|
log.debug("view request : " + viewParam);
|
||||||
|
return viewParam;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doPost(HttpServletRequest request, HttpServletResponse response)
|
||||||
|
throws ServletException,IOException {
|
||||||
|
doGet(request, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doHelp(HttpServletResponse res)
|
||||||
|
throws IOException, ServletException {
|
||||||
|
ServletOutputStream out = res.getOutputStream();
|
||||||
|
res.setContentType("text/html; charset=UTF-8");
|
||||||
|
out.println("<html><body><h2>Quick Notes on using entity:</h2>");
|
||||||
|
out.println("<p>id is the id of the entity to query for. netid also works.</p>");
|
||||||
|
out.println("</body></html>");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doNotFound(HttpServletRequest req, HttpServletResponse res)
|
||||||
|
throws IOException, ServletException {
|
||||||
|
VitroRequest vreq = new VitroRequest(req);
|
||||||
|
Portal portal = vreq.getPortal();
|
||||||
|
ApplicationBean appBean = ApplicationBean.getAppBean(getServletContext());
|
||||||
|
int allPortalId = appBean.getAllPortalFlagNumeric();
|
||||||
|
|
||||||
|
//If an Individual is not found, there is possibility that it
|
||||||
|
//was requested from a portal where it was not visible.
|
||||||
|
//In this case redirect to the all portal.
|
||||||
|
try{
|
||||||
|
Portal allPortal =
|
||||||
|
vreq.getWebappDaoFactory().getPortalDao().getPortal(allPortalId);
|
||||||
|
// there must be a portal defined with the ID of the all portal
|
||||||
|
// for this to work
|
||||||
|
if( portal.getPortalId() != allPortalId && allPortal != null ) {
|
||||||
|
|
||||||
|
//bdc34:
|
||||||
|
// this is hard coded to get the all portal
|
||||||
|
// I didn't find a way to get the id of the all portal
|
||||||
|
// it is likely that redirecting will not work in non VIVO clones
|
||||||
|
String portalPrefix = null;
|
||||||
|
String portalParam = null;
|
||||||
|
if( allPortal != null && allPortal.getUrlprefix() != null )
|
||||||
|
portalPrefix = allPortal.getUrlprefix();
|
||||||
|
else
|
||||||
|
portalParam = "home=" + allPortalId;
|
||||||
|
|
||||||
|
String queryStr = req.getQueryString();
|
||||||
|
if( queryStr == null && portalParam != null && !"".equals(portalParam)){
|
||||||
|
queryStr = portalParam;
|
||||||
|
} else {
|
||||||
|
if( portalParam != null && !"".equals(portalParam))
|
||||||
|
queryStr = queryStr + "&" + portalParam;
|
||||||
|
}
|
||||||
|
if( queryStr != null && !queryStr.startsWith("?") )
|
||||||
|
queryStr = "?" + queryStr;
|
||||||
|
|
||||||
|
StringBuilder url = new StringBuilder();
|
||||||
|
url.append( req.getContextPath() );
|
||||||
|
if( req.getContextPath() != null && !req.getContextPath().endsWith("/"))
|
||||||
|
url.append('/');
|
||||||
|
|
||||||
|
if( portalPrefix != null && !"".equals(portalPrefix))
|
||||||
|
url.append( portalPrefix ).append('/');
|
||||||
|
|
||||||
|
String servletPath = req.getServletPath();
|
||||||
|
String spath = "";
|
||||||
|
if( servletPath != null ){
|
||||||
|
if( servletPath.startsWith("/") )
|
||||||
|
spath = servletPath.substring(1);
|
||||||
|
else
|
||||||
|
spath = servletPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( spath != null && !"".equals(spath))
|
||||||
|
url.append( spath );
|
||||||
|
|
||||||
|
if( req.getPathInfo() != null )
|
||||||
|
url.append( req.getPathInfo() );
|
||||||
|
|
||||||
|
if( queryStr != null && !"".equals(queryStr ))
|
||||||
|
url.append( queryStr );
|
||||||
|
|
||||||
|
res.sendRedirect(url.toString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}catch(Throwable th){
|
||||||
|
log.error("could not do a redirect", th);
|
||||||
|
}
|
||||||
|
|
||||||
|
//set title before we do the highlighting so we don't get markup in it.
|
||||||
|
req.setAttribute("title","not found");
|
||||||
|
res.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
||||||
|
|
||||||
|
String css = "<link rel=\"stylesheet\" type=\"text/css\" media=\"screen\" href=\""
|
||||||
|
+ portal.getThemeDir() + "css/entity.css\"/>"
|
||||||
|
+ "<script language='JavaScript' type='text/javascript' src='js/toggle.js'></script>";
|
||||||
|
req.setAttribute("css",css);
|
||||||
|
|
||||||
|
req.setAttribute("bodyJsp","/"+Controllers.ENTITY_NOT_FOUND_JSP);
|
||||||
|
|
||||||
|
RequestDispatcher rd = req.getRequestDispatcher(Controllers.BASIC_JSP);
|
||||||
|
rd.forward(req,res);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String forURL(String frag)
|
||||||
|
{
|
||||||
|
String result = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = URLEncoder.encode(frag, "UTF-8");
|
||||||
|
} catch (UnsupportedEncodingException ex) {
|
||||||
|
throw new RuntimeException("UTF-8 not supported", ex);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class HelpException extends Throwable{}
|
||||||
|
private class EntityNotFoundException extends Throwable{}
|
||||||
|
}
|
|
@ -0,0 +1,141 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.controller;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.servlet.RequestDispatcher;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.ServletOutputStream;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.beans.VClass;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.beans.VClassGroup;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.view.IndividualView;
|
||||||
|
|
||||||
|
public class IndividualListControllerFM extends FreeMarkerHttpServlet {
|
||||||
|
|
||||||
|
long startTime = -1;
|
||||||
|
|
||||||
|
private static final Log log = LogFactory.getLog(IndividualListControllerFM.class.getName());
|
||||||
|
private VClass vclass = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This generates a list of entities and then sends that
|
||||||
|
* off to a jsp to be displayed.
|
||||||
|
*
|
||||||
|
* Expected parameters:
|
||||||
|
*
|
||||||
|
* Expected Attributes:
|
||||||
|
* entity - set to entity to display properties for.
|
||||||
|
*
|
||||||
|
* @author bdc34
|
||||||
|
*/
|
||||||
|
|
||||||
|
// TODO Rewrite error cases to use FreeMarker templates. Restructure so we're always doing the body
|
||||||
|
// and then calling writeOutput().
|
||||||
|
public void doGet( HttpServletRequest req, HttpServletResponse res )
|
||||||
|
throws IOException, ServletException {
|
||||||
|
startTime = System.currentTimeMillis(); // TODO: remove
|
||||||
|
try {
|
||||||
|
super.doSetup(req, res);
|
||||||
|
Object obj = vreq.getAttribute("vclass");
|
||||||
|
vclass=null;
|
||||||
|
if( obj == null ) { // look for vitroclass id parameter
|
||||||
|
String vitroClassIdStr=req.getParameter("vclassId");
|
||||||
|
if (vitroClassIdStr!=null && !vitroClassIdStr.equals("")) {
|
||||||
|
try {
|
||||||
|
//TODO have to change this so vclass's group and entity count are populated
|
||||||
|
vclass = vreq.getWebappDaoFactory().getVClassDao().getVClassByURI(vitroClassIdStr);
|
||||||
|
if (vclass == null) {
|
||||||
|
log.error("Couldn't retrieve vclass "+vitroClassIdStr);
|
||||||
|
response.sendRedirect(Controllers.BROWSE_CONTROLLER+"-freemarker?"+vreq.getQueryString());
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new HelpException("EntityListControllerFM: request parameter 'vclassId' must be a URI string");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (obj instanceof VClass) {
|
||||||
|
vclass = (VClass)obj;
|
||||||
|
} else {
|
||||||
|
throw new HelpException("EntityListControllerFM: attribute 'vclass' must be of type "
|
||||||
|
+ VClass.class.getName() );
|
||||||
|
}
|
||||||
|
if (vclass!=null){
|
||||||
|
setBody();
|
||||||
|
write(response);
|
||||||
|
}
|
||||||
|
// RY Rewrite error cases for FreeMarker, not JSP
|
||||||
|
} catch (HelpException help){
|
||||||
|
doHelp(response);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
vreq.setAttribute("javax.servlet.jsp.jspException",e);
|
||||||
|
RequestDispatcher rd = req.getRequestDispatcher("/error.jsp");
|
||||||
|
rd.forward(vreq, response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doPost(HttpServletRequest request, HttpServletResponse response)
|
||||||
|
throws ServletException,IOException {
|
||||||
|
doGet(request, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getBody() {
|
||||||
|
|
||||||
|
Map<String, Object> body = new HashMap<String, Object>();
|
||||||
|
|
||||||
|
// Create list of individuals
|
||||||
|
List<Individual> individualList = vreq.getWebappDaoFactory().getIndividualDao().getIndividualsByVClass(vclass);
|
||||||
|
List<IndividualView> individuals = new ArrayList<IndividualView>();
|
||||||
|
|
||||||
|
body.put("individuals", individuals);
|
||||||
|
|
||||||
|
// But the JSP version includes url rewriting via URLRewritingHttpServletResponse
|
||||||
|
body.put("individualUrl", config.getSharedVariable("contextPath") + "/entity?home=" + config.getSharedVariable("portalId") + "&uri=");
|
||||||
|
|
||||||
|
if (individuals == null) {
|
||||||
|
log.error("individuals list is null");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use instead of getTitle(), because we have a subtitle too
|
||||||
|
String title = "";
|
||||||
|
VClassGroup classGroup=vclass.getGroup();
|
||||||
|
if (classGroup==null) {
|
||||||
|
title = vclass.getName();
|
||||||
|
} else {
|
||||||
|
title = classGroup.getPublicName();
|
||||||
|
setSharedVariable("subTitle", vclass.getName());
|
||||||
|
}
|
||||||
|
setSharedVariable("title", title);
|
||||||
|
|
||||||
|
String templateName = "entityList.ftl";
|
||||||
|
return mergeBodyToTemplate(templateName, body);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// RY Rewrite as a template
|
||||||
|
private void doHelp(HttpServletResponse res)
|
||||||
|
throws IOException, ServletException {
|
||||||
|
ServletOutputStream out = res.getOutputStream();
|
||||||
|
res.setContentType("text/html; charset=UTF-8");
|
||||||
|
out.println("<html><body><h2>Quick Notes on using EntityList:</h2>");
|
||||||
|
out.println("<p>request.attributes 'entities' must be set by servlet before calling."
|
||||||
|
+" It must be a List of Entity objects </p>");
|
||||||
|
out.println("</body></html>");
|
||||||
|
}
|
||||||
|
|
||||||
|
private class HelpException extends Throwable{
|
||||||
|
public HelpException(String string) {
|
||||||
|
super(string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
/* $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.io.IOException;
|
||||||
|
|
||||||
|
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.ConfigurationProperties;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.FreeMarkerHttpServlet;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.view.ViewObject;
|
||||||
|
import freemarker.template.Configuration;
|
||||||
|
import freemarker.template.DefaultObjectWrapper;
|
||||||
|
import freemarker.template.TemplateException;
|
||||||
|
|
||||||
|
public class FreeMarkerSetup implements ServletContextListener {
|
||||||
|
|
||||||
|
private static final Log log = LogFactory.getLog(FreeMarkerSetup.class);
|
||||||
|
|
||||||
|
public void contextInitialized(ServletContextEvent event) {
|
||||||
|
|
||||||
|
ServletContext sc = event.getServletContext();
|
||||||
|
|
||||||
|
// RY Change this to multi-location template scheme
|
||||||
|
String templatePath = sc.getRealPath("/templates/freemarker");
|
||||||
|
|
||||||
|
Configuration cfg = new Configuration();
|
||||||
|
|
||||||
|
/* **** RY
|
||||||
|
Here's what I want to do to avoid having to pass in the contextPath to every view object created (in order for them to create their URLs):
|
||||||
|
Subclass Configuration. Add a static variable CONTEXT_PATH to it. Set that value here, and define a getter also. Then when creating
|
||||||
|
urls in view object methods like getUrl(), we can reference that configuration value. None of this is possible unless we can use
|
||||||
|
the method ServletContext.getContextPath(), new to Servlet API 2.5 andn therefore requiring tomcat 6 rather than 5.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Specify the data source where the template files come from.
|
||||||
|
try {
|
||||||
|
cfg.setDirectoryForTemplateLoading(new File(templatePath));
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Error specifying template directory.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// RY This setting won't take effect until we use Configuration.getTemplate() to
|
||||||
|
// create templates.
|
||||||
|
String buildEnv = ConfigurationProperties.getProperty("Environment.build");
|
||||||
|
if (buildEnv != null && buildEnv.equals("development")) {
|
||||||
|
cfg.setTemplateUpdateDelay(0); // no template caching in development
|
||||||
|
}
|
||||||
|
|
||||||
|
// Specify how templates will see the data-model. This is an advanced topic...
|
||||||
|
// but just use this:
|
||||||
|
cfg.setObjectWrapper(new DefaultObjectWrapper());
|
||||||
|
|
||||||
|
try {
|
||||||
|
cfg.setSetting("url_escaping_charset", "ISO-8859-1");
|
||||||
|
} catch (TemplateException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
log.error("Error setting value for url_escaping_charset.");
|
||||||
|
}
|
||||||
|
|
||||||
|
FreeMarkerHttpServlet.config = cfg;
|
||||||
|
|
||||||
|
String contextPath = sc.getContextPath();
|
||||||
|
FreeMarkerHttpServlet.contextPath = contextPath;
|
||||||
|
ViewObject.contextPath = contextPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void contextDestroyed(ServletContextEvent event) {
|
||||||
|
// nothing to do here
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -4,7 +4,6 @@ package edu.cornell.mannlib.vitro.webapp.utils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class StringUtils {
|
public class StringUtils {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
package edu.cornell.mannlib.vitro.webapp.utils.display;
|
package edu.cornell.mannlib.vitro.webapp.utils.view;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
|
@ -0,0 +1,54 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.view;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.beans.Portal;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.beans.VClassGroup;
|
||||||
|
|
||||||
|
public class IndividualView extends ViewObject {
|
||||||
|
|
||||||
|
private static final Log log = LogFactory.getLog(IndividualView.class.getName());
|
||||||
|
|
||||||
|
private static final String URL = "/individual";
|
||||||
|
|
||||||
|
private Individual individual;
|
||||||
|
|
||||||
|
public IndividualView(Individual individual) {
|
||||||
|
this.individual = individual;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return individual.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMoniker() {
|
||||||
|
return individual.getMoniker();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUri() {
|
||||||
|
return individual.getURI();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Or maybe getProfileUrl - there might be other kinds of urls
|
||||||
|
// e.g., getEditUrl, getDeleteUrl - these would return the computations of PropertyEditLinks
|
||||||
|
public String getProfileUrl() {
|
||||||
|
return contextPath + URL + ""; // ADD IN the label from the individual's uri
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCustomView() {
|
||||||
|
// see code currently in entityList.ftl
|
||||||
|
String customView = null;
|
||||||
|
|
||||||
|
return customView;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getProperty(String propertyName) {
|
||||||
|
return new Object();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.view;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.beans.VClass;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.beans.VClassGroup;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A VClassGroupDisplay object is associated with a VClassGroup for display.
|
||||||
|
* It is an object that contains a linked list, rather than a type of linked list,
|
||||||
|
* so that JSP EL can access properties such as publicName.
|
||||||
|
*
|
||||||
|
* RY We may want an abstract display class as a superclass.
|
||||||
|
* RY We may want an interface that the superclass would implement.
|
||||||
|
* RY We may want to nest this class in the VClassGroup class.
|
||||||
|
*/
|
||||||
|
public class VClassGroupView extends ViewObject {
|
||||||
|
|
||||||
|
private static final Log log = LogFactory.getLog(VClassGroupView.class.getName());
|
||||||
|
|
||||||
|
private VClassGroup vClassGroup = null;
|
||||||
|
private List<VClassView> classes = null;
|
||||||
|
|
||||||
|
public VClassGroupView(VClassGroup vClassGroup) {
|
||||||
|
this.vClassGroup = vClassGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDisplayRank() {
|
||||||
|
return vClassGroup.getDisplayRank();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUri() {
|
||||||
|
return vClassGroup.getURI();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNamespace() {
|
||||||
|
return vClassGroup.getNamespace();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLocalName() {
|
||||||
|
return vClassGroup.getLocalName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPublicName() {
|
||||||
|
return vClassGroup.getPublicName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<VClassView> getClasses() {
|
||||||
|
// Do we need to store the classes as an instance member? Would we ever access this method more than once per template?
|
||||||
|
if (classes == null) {
|
||||||
|
List<VClass> classList = vClassGroup.getVitroClassList();
|
||||||
|
classes = new ArrayList<VClassView>();
|
||||||
|
Iterator<VClass> i = classList.iterator();
|
||||||
|
while (i.hasNext()) {
|
||||||
|
classes.add(new VClassView((VClass) i.next()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return classes;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.view;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.beans.VClass;
|
||||||
|
|
||||||
|
public class VClassView extends ViewObject {
|
||||||
|
|
||||||
|
private static final Log log = LogFactory.getLog(VClassView.class.getName());
|
||||||
|
private static final String URL = "/individuallistFM?vclassId=";
|
||||||
|
|
||||||
|
private VClass vclass;
|
||||||
|
|
||||||
|
public VClassView(VClass vclass) {
|
||||||
|
this.vclass = vclass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return vclass.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrl() {
|
||||||
|
return contextPath + URL + encodeUrl(vclass.getURI());
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getEntityCount() {
|
||||||
|
return vclass.getEntityCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.view;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.FreeMarkerHttpServlet;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.utils.StringUtils;
|
||||||
|
|
||||||
|
public abstract class ViewObject {
|
||||||
|
|
||||||
|
private static final Log log = LogFactory.getLog(ViewObject.class.getName());
|
||||||
|
|
||||||
|
public static String contextPath;
|
||||||
|
|
||||||
|
protected static String getUrl(String path) {
|
||||||
|
return FreeMarkerHttpServlet.getUrl(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String encodeUrl(String url) {
|
||||||
|
String encoding = "ISO-8859-1";
|
||||||
|
String encodedUrl = null;
|
||||||
|
try {
|
||||||
|
encodedUrl = URLEncoder.encode(url, encoding);
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
log.error("Error encoding url " + url + " with encoding " + encoding + ": Unsupported encoding.");
|
||||||
|
}
|
||||||
|
return encodedUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.view.menu;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||||
|
|
||||||
|
/** A menu that can indicate the active item.
|
||||||
|
*
|
||||||
|
* @author rjy7
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class MainMenu extends Menu {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
private static final Log log = LogFactory.getLog(MainMenu.class.getName());
|
||||||
|
|
||||||
|
public MainMenu(VitroRequest vreq, int portalId) {
|
||||||
|
super(vreq, portalId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addItem(String text, String path) {
|
||||||
|
boolean active = vreq.getServletPath().equals(path);
|
||||||
|
MainMenuItem i = new MainMenuItem(text, path, active);
|
||||||
|
items.add(i);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.view.menu;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||||
|
|
||||||
|
/** A menu item that indicates whether it is the active item or not.
|
||||||
|
*
|
||||||
|
* @author rjy7
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class MainMenuItem extends MenuItem {
|
||||||
|
|
||||||
|
private static final Log log = LogFactory.getLog(MainMenuItem.class.getName());
|
||||||
|
|
||||||
|
private boolean active;
|
||||||
|
|
||||||
|
public MainMenuItem(String linkText, String path, boolean active) {
|
||||||
|
super(linkText, path);
|
||||||
|
this.active = active;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isActive() {
|
||||||
|
return active;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.view.menu;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
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.view.ViewObject;
|
||||||
|
|
||||||
|
public class Menu extends ViewObject {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
private static final Log log = LogFactory.getLog(Menu.class.getName());
|
||||||
|
|
||||||
|
protected VitroRequest vreq;
|
||||||
|
protected int portalId;
|
||||||
|
protected List<MenuItem> items;
|
||||||
|
|
||||||
|
public Menu(VitroRequest vreq, int portalId) {
|
||||||
|
this.vreq = vreq;
|
||||||
|
this.portalId = portalId;
|
||||||
|
items = new ArrayList<MenuItem>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addItem(String text, String path) {
|
||||||
|
items.add(new MenuItem(text, path));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<MenuItem> getItems() {
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.view.menu;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.view.ViewObject;
|
||||||
|
|
||||||
|
public class MenuItem extends ViewObject {
|
||||||
|
|
||||||
|
private static final Log log = LogFactory.getLog(MenuItem.class.getName());
|
||||||
|
|
||||||
|
private String text;
|
||||||
|
private String url;
|
||||||
|
|
||||||
|
public MenuItem(String linkText, String path) {
|
||||||
|
text = linkText;
|
||||||
|
url = getUrl(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLinkText() {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.view.menu;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.beans.Tab;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.web.TabWebUtil;
|
||||||
|
|
||||||
|
/** A main menu constructed from persisted tab data
|
||||||
|
*
|
||||||
|
* @author rjy7
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class TabMenu extends MainMenu {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
private static final Log log = LogFactory.getLog(TabMenu.class.getName());
|
||||||
|
|
||||||
|
public TabMenu(VitroRequest vreq, int portalId) {
|
||||||
|
super(vreq, portalId);
|
||||||
|
|
||||||
|
//Tabs stored in database
|
||||||
|
List<Tab> primaryTabs = vreq.getWebappDaoFactory().getTabDao().getPrimaryTabs(portalId);
|
||||||
|
int tabId = TabWebUtil.getTabIdFromRequest(vreq);
|
||||||
|
int rootId = TabWebUtil.getRootTabId(vreq);
|
||||||
|
List tabLevels = vreq.getWebappDaoFactory().getTabDao().getTabHierarcy(tabId,rootId);
|
||||||
|
vreq.setAttribute("tabLevels", tabLevels);
|
||||||
|
Iterator<Tab> primaryTabIterator = primaryTabs.iterator();
|
||||||
|
Iterator tabLevelIterator = tabLevels.iterator();
|
||||||
|
Tab tab;
|
||||||
|
while (primaryTabIterator.hasNext()) {
|
||||||
|
tab = (Tab) primaryTabIterator.next();
|
||||||
|
addItem(tab.getTitle(), "/index.jsp?primary=" + tab.getTabId());
|
||||||
|
// RY Also need to loop through nested tab levels, but not doing that now.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hard-coded tabs. It's not really a good idea to have these here, since any menu item that doesn't
|
||||||
|
// come from the db should be accessible to the template to change the text. But we need them here
|
||||||
|
// to apply the "active" mechanism.
|
||||||
|
addItem("Index", "/browsecontroller");
|
||||||
|
addItem("Index - FM", "/browse");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
12
webapp/web/templates/freemarker/body/about.ftl
Normal file
12
webapp/web/templates/freemarker/body/about.ftl
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<#-- $This file is distributed under the terms of the license in /doc/license.txt -->
|
||||||
|
|
||||||
|
<h2>${title}</h2>
|
||||||
|
|
||||||
|
<#if aboutText??>
|
||||||
|
<div class="pageGroupBody" id="aboutText">${aboutText}</div>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#if acknowledgeText??>
|
||||||
|
<div class="pageGroupBody" id="acknowledgementText">${acknowledgeText}</div>
|
||||||
|
</#if>
|
||||||
|
|
14
webapp/web/templates/freemarker/body/browseGroups.ftl
Normal file
14
webapp/web/templates/freemarker/body/browseGroups.ftl
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
|
||||||
|
|
||||||
|
<#if message??>
|
||||||
|
<p>${message}</p>
|
||||||
|
<#else>
|
||||||
|
<#list classGroups as classGroup>
|
||||||
|
<h2>${classGroup.publicName}</h2>
|
||||||
|
<ul>
|
||||||
|
<#list classGroup.classes as class>
|
||||||
|
<li><a href="${class.url}">${class.name}</a> (${class.entityCount})</li>
|
||||||
|
</#list>
|
||||||
|
</ul>
|
||||||
|
</#list>
|
||||||
|
</#if>
|
0
webapp/web/templates/freemarker/body/individual.ftl
Normal file
0
webapp/web/templates/freemarker/body/individual.ftl
Normal file
35
webapp/web/templates/freemarker/body/individualList.ftl
Normal file
35
webapp/web/templates/freemarker/body/individualList.ftl
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
|
||||||
|
|
||||||
|
<div class="contents">
|
||||||
|
|
||||||
|
<div class="entityList">
|
||||||
|
<h2>${title}</h2>
|
||||||
|
<#if subtitle??>
|
||||||
|
<h4>${subTitle}"</h4>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<#list entities as entity>
|
||||||
|
<#-- Iterate through the object's class hierarchy, looking for a custom view -->
|
||||||
|
<#-- RY This should be done in a view method -->
|
||||||
|
<#list entity.VClasses as type>
|
||||||
|
<#if type.customSearchView?has_content>
|
||||||
|
<#assign altRender = type.customSearchView>
|
||||||
|
<#-- What order are these returned in? If from specific to general, we should break if we find one -->
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
<li>
|
||||||
|
<#-- RY Create a directive to work like c:url with c:param -->
|
||||||
|
<#-- RY The JSP version includes URL rewriting in a filter - see URLRewritingHttpServletResponse -->
|
||||||
|
<a href="${entityUrl}${entity.URI?url}">${entity.name}</a> | <#-- add p:process to name -->
|
||||||
|
<#if entity.moniker?has_content>
|
||||||
|
${entity.moniker} <#-- add p:process -->
|
||||||
|
<#else>
|
||||||
|
${entity.VClass.name}
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
</li>
|
||||||
|
</#list>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
12
webapp/web/templates/freemarker/components/copyright.ftl
Normal file
12
webapp/web/templates/freemarker/components/copyright.ftl
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
|
||||||
|
|
||||||
|
<#if copyright??>
|
||||||
|
<div class="copyright">
|
||||||
|
©${copyright.year?c}
|
||||||
|
<#if copyright.url??>
|
||||||
|
<a href="${copyright.url}">${copyright.text}</a>
|
||||||
|
<#else>
|
||||||
|
${copyright.text}
|
||||||
|
</#if>
|
||||||
|
</div>
|
||||||
|
</#if>
|
5
webapp/web/templates/freemarker/components/doctype.html
Normal file
5
webapp/web/templates/freemarker/components/doctype.html
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<!-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
|
||||||
|
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||||
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
28
webapp/web/templates/freemarker/components/footer.ftl
Normal file
28
webapp/web/templates/freemarker/components/footer.ftl
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
|
||||||
|
|
||||||
|
<#import "/macros/list.ftl" as l>
|
||||||
|
|
||||||
|
<div id="footer">
|
||||||
|
|
||||||
|
<#if bannerImageUrl??>
|
||||||
|
<img class="footerLogo" src="${urls.bannerImage}" alt="${tagline!}" />
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<div class="footerLinks">
|
||||||
|
<ul class="otherNav">
|
||||||
|
<@l.makeList>
|
||||||
|
<li><a href="${urls.about}" title="more about this web site">About</a></li>,
|
||||||
|
<#if urls.contact??>
|
||||||
|
<li><a href="${urls.contact}" title="feedback form">Contact Us</a></li>
|
||||||
|
</#if>
|
||||||
|
</@l.makeList>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<#include "copyright.ftl">
|
||||||
|
|
||||||
|
All Rights Reserved. <a href="${urls.termsOfUse}">Terms of Use</a>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<#-- SCRIPT TAGS SHOULD GO HERE -->
|
6
webapp/web/templates/freemarker/components/head.ftl
Normal file
6
webapp/web/templates/freemarker/components/head.ftl
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<#include "title.ftl">
|
||||||
|
<#include "stylesheets.ftl">
|
||||||
|
</head>
|
33
webapp/web/templates/freemarker/components/identity.ftl
Normal file
33
webapp/web/templates/freemarker/components/identity.ftl
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
|
||||||
|
|
||||||
|
<#import "/macros/list.ftl" as l>
|
||||||
|
|
||||||
|
<div id="identity">
|
||||||
|
|
||||||
|
<h1><a title="Home" href="${urls.home}">${siteName}</a></h1>
|
||||||
|
|
||||||
|
<#-- RY We will need this in non-NIHVIVO versions
|
||||||
|
<#if tagline.has_content>
|
||||||
|
<em>${tagline}</em>
|
||||||
|
</#if>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<ul id="otherMenu">
|
||||||
|
<@l.makeList>
|
||||||
|
<#if loginName??>
|
||||||
|
<li>
|
||||||
|
Logged in as <strong>${loginName}</strong> (<a href="${urls.logout}">Log out</a>)
|
||||||
|
</li>,
|
||||||
|
<li><a href="${urls.siteAdmin}">Site Admin</a></li>,
|
||||||
|
<#else>
|
||||||
|
<li><a title="log in to manage this site" href="${urls.login}">Log in</a></li>,
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<li><a href="${urls.about}$">About</a></li>,
|
||||||
|
<li><a href="${urls.aboutFM}">About - FM</a></li>,
|
||||||
|
<#if urls.contact??>
|
||||||
|
<li><a href="${urls.contact}">Contact Us</a></li>
|
||||||
|
</#if>
|
||||||
|
</@l.makeList>
|
||||||
|
</ul>
|
||||||
|
</div>
|
13
webapp/web/templates/freemarker/components/menu.ftl
Normal file
13
webapp/web/templates/freemarker/components/menu.ftl
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
|
||||||
|
|
||||||
|
<div id="primaryAndOther">
|
||||||
|
<ul id="primary">
|
||||||
|
<#list tabMenu.items as item>
|
||||||
|
<li>
|
||||||
|
<a href="${item.url}" <#if item.active> class="activeTab" </#if>>
|
||||||
|
${item.linkText}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</#list>
|
||||||
|
</ul>
|
||||||
|
</div>
|
1
webapp/web/templates/freemarker/components/scripts.ftl
Normal file
1
webapp/web/templates/freemarker/components/scripts.ftl
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
|
19
webapp/web/templates/freemarker/components/search.ftl
Normal file
19
webapp/web/templates/freemarker/components/search.ftl
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
|
||||||
|
|
||||||
|
<div id="searchBlock">
|
||||||
|
<form id="searchForm" action="${urls.search}" >
|
||||||
|
<label for="search">Search </label>
|
||||||
|
|
||||||
|
<#if showFlag1SearchField??>
|
||||||
|
<select id="search-form-modifier" name="flag1" class="form-item" >
|
||||||
|
<option value="nofiltering" selected="selected">entire database (${loginName})</option>
|
||||||
|
<option value="${portalId}">${tagline!}</option>
|
||||||
|
</select>
|
||||||
|
<#else>
|
||||||
|
<input type="hidden" name="flag1" value="${portalId}" />
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<input type="text" name="querytext" id="search" class="search-form-item" value="${querytext!}" size="20" />
|
||||||
|
<input class="search-form-submit" name="submit" type="submit" value="Search" />
|
||||||
|
</form>
|
||||||
|
</div>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
|
||||||
|
|
||||||
|
<link rel="stylesheet" type="text/css" href="${stylesheetDir}screen.css" media="screen"/>
|
||||||
|
<link rel="stylesheet" type="text/css" href="${stylesheetDir}print.css" media="print"/>
|
||||||
|
|
||||||
|
<#list stylesheets as stylesheet>
|
||||||
|
${stylesheet}
|
||||||
|
</#list>
|
3
webapp/web/templates/freemarker/components/title.ftl
Normal file
3
webapp/web/templates/freemarker/components/title.ftl
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
|
||||||
|
|
||||||
|
<title>${title}</title>
|
68
webapp/web/templates/freemarker/macros/list.ftl
Normal file
68
webapp/web/templates/freemarker/macros/list.ftl
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
<#--
|
||||||
|
Output a sequence of <li> elements, adding classes "first" and "last" to first and last list elements, respectively.
|
||||||
|
It is helpful when the list elements are generated conditionally, to avoid complex tests for the presence/absence
|
||||||
|
of other list elements in order to assign these classes.
|
||||||
|
|
||||||
|
Input should be a series of <li> elements separated by some delimiter. Default delimiter value is ",".
|
||||||
|
|
||||||
|
Tolerates a delimiter following the last <li> element.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
<@makeList>
|
||||||
|
<li>apples</li>,
|
||||||
|
<li>bananas</li>,
|
||||||
|
<li>oranges</li>
|
||||||
|
<@makeList>
|
||||||
|
|
||||||
|
<@makeList delim="??">
|
||||||
|
<li>apples, oranges</li>??
|
||||||
|
<li>bananas, lemons</li>??
|
||||||
|
<li>grapefruit, limes</li>
|
||||||
|
<@makeList>
|
||||||
|
|
||||||
|
RY Consider rewriting in Java. Probably designers won't want to modify this.
|
||||||
|
-->
|
||||||
|
<#macro makeList delim=",">
|
||||||
|
<#assign text>
|
||||||
|
<#nested>
|
||||||
|
</#assign>
|
||||||
|
|
||||||
|
<#-- Strip out a list-final delimiter, else (unlike most languages) it results in an empty final array item. -->
|
||||||
|
<#assign text = text?replace("${delim}$", "", "r")>
|
||||||
|
|
||||||
|
<#assign items = text?split(delim)>
|
||||||
|
|
||||||
|
<#list items as item>
|
||||||
|
<#-- A FreeMarker loop variable cannot have its value modified, so we use a new variable. -->
|
||||||
|
<#assign newItem = item?trim>
|
||||||
|
|
||||||
|
<#assign classVal = "">
|
||||||
|
|
||||||
|
<#-- Keep any class value already assigned -->
|
||||||
|
<#assign currentClass = newItem?matches("^<li [^>]*(class=[\'\"](.*?)[\'\"])")>
|
||||||
|
<#list currentClass as m>
|
||||||
|
<#assign classVal = m?groups[2]>
|
||||||
|
<#assign newItem = newItem?replace(m?groups[1], "")>
|
||||||
|
</#list>
|
||||||
|
|
||||||
|
<#-- Test indices, rather than comparing content, on the remote chance
|
||||||
|
that there are two list items with the same content. -->
|
||||||
|
<#-- <#if item == arr?first> -->
|
||||||
|
<#if item_index == 0>
|
||||||
|
<#assign classVal = "${classVal} first">
|
||||||
|
</#if>
|
||||||
|
<#-- <#if item == arr?last> -->
|
||||||
|
<#if !item_has_next>
|
||||||
|
<#assign classVal = "${classVal} last">
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#if classVal != "">
|
||||||
|
<#assign classVal = classVal?replace("^ ", "", "r")>
|
||||||
|
<#-- Replace first instance only, in case the item contains nested li tags. -->
|
||||||
|
<#assign newItem = newItem?replace("<li", "<li class=\"${classVal}\"", "f")>
|
||||||
|
</#if>
|
||||||
|
${newItem}
|
||||||
|
</#list>
|
||||||
|
</#macro>
|
||||||
|
|
||||||
|
<#----------------------------------------------------------------------------->
|
32
webapp/web/templates/freemarker/page/default.ftl
Normal file
32
webapp/web/templates/freemarker/page/default.ftl
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
|
||||||
|
|
||||||
|
<#include "/components/doctype.html">
|
||||||
|
|
||||||
|
<#include "/components/head.ftl">
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="wrap" class="container">
|
||||||
|
<div id="header">
|
||||||
|
|
||||||
|
<#include "/components/identity.ftl">
|
||||||
|
|
||||||
|
<div id="navAndSearch" class="block">
|
||||||
|
<#include "/components/menu.ftl">
|
||||||
|
<#include "/components/search.ftl">
|
||||||
|
</div> <!-- navAndSearch -->
|
||||||
|
|
||||||
|
</div> <!-- header -->
|
||||||
|
|
||||||
|
<hr class="hidden" />
|
||||||
|
|
||||||
|
<div id="contentwrap">
|
||||||
|
<div id="content" <#if contentClass??> class="${contentClass}" </#if>>
|
||||||
|
${body}
|
||||||
|
</div> <!-- content -->
|
||||||
|
</div> <!-- contentwrap -->
|
||||||
|
|
||||||
|
<#include "/components/footer.ftl">
|
||||||
|
|
||||||
|
</div> <!-- wrap -->
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Add table
Reference in a new issue