diff --git a/doc/list_view_configuration_guidelines.txt b/doc/list_view_configuration_guidelines.txt index 20ac1ce99..97daab064 100644 --- a/doc/list_view_configuration_guidelines.txt +++ b/doc/list_view_configuration_guidelines.txt @@ -5,13 +5,16 @@ List view configuration guidelines REGISTERING THE LIST VIEW ------------------------- -A custom list view is associated with an object property in the file /vivo/productMods/WEB-INF/ontologies/app/listViewConfig.owl. -Example: +A custom list view is associated with an object property in the RDF files in the directory /vivo/productMods/WEB-INF/ontologies/app/loadedAtStartup +To register a list view, create a new .rdf or .n3 file in that directory. The file must be well formed RDF/XML or N3. + +Example of registering a new association in a file named newListViews.n3: - - listViewConfig-authorInAuthorship.xml - + + + "listViewConfig-authorInAuthorship.xml" . +Place this file in /vivo/productMods/WEB-INF/ontologies/app/loadedAtStartup, redeploy and restart tomcat to put the new custom list view in effect. ----------------- REQUIRED ELEMENTS diff --git a/webapp/ontologies/app/loadedAtStartup/displayModelListViews.rdf b/webapp/ontologies/app/loadedAtStartup/displayModelListViews.rdf new file mode 100644 index 000000000..4a17524f5 --- /dev/null +++ b/webapp/ontologies/app/loadedAtStartup/displayModelListViews.rdf @@ -0,0 +1,23 @@ + + + + + + + +]> + + + + + + listViewConfig-hasElement.xml + + + \ No newline at end of file diff --git a/webapp/ontologies/search/vitroSearchProhibited.n3 b/webapp/ontologies/search/vitroSearchProhibited.n3 index 4b79892ac..ba3ed6838 100644 --- a/webapp/ontologies/search/vitroSearchProhibited.n3 +++ b/webapp/ontologies/search/vitroSearchProhibited.n3 @@ -1,23 +1,27 @@ # $This file is distributed under the terms of the license in /doc/license.txt$ -@prefix owl: . -@prefix vitroDisplay: . -@prefix rdf: . -@prefix core: . -@prefix example: . - # All instances of a class can be excluded from the search index # by adding a vitroDisplay:excludeClass property between # vitroDisplay:SearchIndex and the URI of the class # that you would like to exclude. -# All .n3 files in this directory will be used to configure -# the search exclusions. Only .n3 files will be loaded. -# +# All .n3 or .rdf files in this directory will be used to configure +# the search exclusions. Each file must be a valid file in the format +# specified by its extension. Each file will be loaded individually and +# must be a complete stand alone example of its format. Each file must contain all +# the necessary prefixes, namespaces and preambles required by the format +# specified by its extension. + # If you would like to add classes to the # exclusions, add a file to this directory ending in .n3 with # N3 statements similar to this example. +# +# @prefix owl: . +# @prefix vitroDisplay: . +# @prefix rdf: . +# @prefix example: . +# # vitroDisplay:SearchIndex # rdf:type owl:Thing ; # vitroDisplay:excludeClass example:classToExclude ; \ No newline at end of file diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/JsonServlet.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/JsonServlet.java index e0ce72697..8a648f2d6 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/JsonServlet.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/JsonServlet.java @@ -54,6 +54,7 @@ public class JsonServlet extends VitroHttpServlet { private static final long serialVersionUID = 1L; private static final Log log = LogFactory.getLog(JsonServlet.class); private static final int REPLY_SIZE = 256; + private static final int INDIVIDUALS_PER_PAGE = 30; @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { @@ -267,7 +268,7 @@ public class JsonServlet extends VitroHttpServlet { try { map = IndividualListController.getResultsForVClassIntersections( vclassURIs, - page, + page, INDIVIDUALS_PER_PAGE, alpha, vreq.getWebappDaoFactory().getIndividualDao(), context); @@ -292,17 +293,11 @@ public class JsonServlet extends VitroHttpServlet { } public static String getDataPropertyValue(Individual ind, DataProperty dp, WebappDaoFactory wdf){ - List values = wdf.getDataPropertyStatementDao() - .getDataPropertyValuesForIndividualByProperty(ind, dp); - if( values == null || values.isEmpty() ) + String value = ind.getDataValue(dp.getURI()); + if( value == null || value.isEmpty() ) return ""; - else{ - if( values.get(0) != null ) - return values.get(0).getLexicalForm(); - else - return ""; - } - + else + return value; } /** diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/IndividualListController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/IndividualListController.java index 9f11d4b87..12bcaafbf 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/IndividualListController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/IndividualListController.java @@ -6,6 +6,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; @@ -40,8 +41,7 @@ public class IndividualListController extends FreemarkerHttpServlet { private static final long serialVersionUID = 1L; private static final Log log = LogFactory.getLog(IndividualListController.class.getName()); - - private static final int INDIVIDUAL_LIST_CONTROLLER_MAX_RESULTS = 30000; + private static final int INDIVIDUALS_PER_PAGE = 30; private static final int MAX_PAGES = 40; // must be even @@ -165,22 +165,23 @@ public class IndividualListController extends FreemarkerHttpServlet { } } - //Pulling out common code that is used for both single (regular) vclass query and multiple (intersection) query - public static Map getResultsForVClasses(List vclassURIs, int page, String alpha, IndividualDao indDao, ServletContext context) - throws IOException, ServletException{ - Map rvMap = new HashMap(); - try{ - SolrQuery query = getQuery(vclassURIs, alpha); - rvMap = getResultsForVClassQuery(query, page, alpha, indDao, context); - List individuals = (List) rvMap.get("entities"); - if (individuals == null) - log.debug("entities list is null for vclasses " + vclassURIs.toString() ); - } catch(Throwable th) { - log.error("An error occurred retrieving results for vclass query", th); - } - return rvMap; - } +// //Pulling out common code that is used for both single (regular) vclass query and multiple (intersection) query +// public static Map getResultsForVClasses(List vclassURIs, int page, String alpha, IndividualDao indDao, ServletContext context) +// throws IOException, ServletException{ +// Map rvMap = new HashMap(); +// try{ +// SolrQuery query = getQuery(vclassURIs, alpha, page, INDIVIDUALS_PER_PAGE); +// rvMap = getResultsForVClassQuery(query, page, alpha, indDao, context); +// List individuals = (List) rvMap.get("entities"); +// if (individuals == null) +// log.debug("entities list is null for vclasses " + vclassURIs.toString() ); +// } catch(Throwable th) { +// log.error("An error occurred retrieving results for vclass query", th); +// } +// return rvMap; +// } + @SuppressWarnings("unchecked") public static Map getResultsForVClass(String vclassURI, int page, String alpha, IndividualDao indDao, ServletContext context) throws IOException, SearchException{ Map rvMap = new HashMap(); @@ -188,8 +189,8 @@ public class IndividualListController extends FreemarkerHttpServlet { //make query for this rdf:type List classUris = new ArrayList(); classUris.add(vclassURI); - SolrQuery query = getQuery(classUris, alpha); - rvMap = getResultsForVClassQuery(query, page, alpha, indDao, context); + SolrQuery query = getQuery(classUris, alpha, page, INDIVIDUALS_PER_PAGE); + rvMap = getResultsForVClassQuery(query, page, INDIVIDUALS_PER_PAGE, alpha, indDao, context); List individuals = (List) rvMap.get("entities"); if (individuals == null) log.debug("entities list is null for vclass " + vclassURI ); @@ -204,14 +205,15 @@ public class IndividualListController extends FreemarkerHttpServlet { return rvMap; } - public static Map getResultsForVClassIntersections(List vclassURIs, int page, String alpha, IndividualDao indDao, ServletContext context) + @SuppressWarnings("unchecked") + public static Map getResultsForVClassIntersections(List vclassURIs, int page, int pageSize, String alpha, IndividualDao indDao, ServletContext context) throws IOException, ServletException{ Map rvMap = new HashMap(); try{ // make query for multiple rdf types - SolrQuery query = getQuery(vclassURIs, alpha); + SolrQuery query = getQuery(vclassURIs, alpha, page, pageSize); log.debug("Executed solr query for " + vclassURIs.toString()); - rvMap = getResultsForVClassQuery(query, page, alpha, indDao, context); + rvMap = getResultsForVClassQuery(query, page, pageSize, alpha, indDao, context); List individuals = (List) rvMap.get("entities"); if (individuals == null) log.debug("entities list is null for vclass " + vclassURIs.toString() ); @@ -225,7 +227,7 @@ public class IndividualListController extends FreemarkerHttpServlet { * This method is now called in a couple of places. It should be refactored * into a DAO or similar object. */ - public static Map getResultsForVClassQuery(SolrQuery query, int page, String alpha, IndividualDao indDao, ServletContext context) + protected static Map getResultsForVClassQuery(SolrQuery query, int page, int pageSize, String alpha, IndividualDao indDao, ServletContext context) throws IOException, ServletException { Map rvMap = new HashMap(); SolrServer solr = SolrSetup.getSolrServer(context); @@ -252,31 +254,26 @@ public class IndividualListController extends FreemarkerHttpServlet { long hitCount = docs.getNumFound(); log.debug("Number of search results: " + hitCount); - List individuals = new ArrayList(INDIVIDUALS_PER_PAGE); - int individualsAdded = 0; - int index = (page-1) * INDIVIDUALS_PER_PAGE; - if(docs.size() > 0) { - while (individualsAdded < INDIVIDUALS_PER_PAGE && index < hitCount) { - SolrDocument doc = docs.get(index); + Iterator docIter = docs.iterator(); + List individuals = new ArrayList(docs.size()); + + while ( docIter.hasNext() ){ + SolrDocument doc = docIter.next(); if (doc != null) { String uri = doc.get(VitroSearchTermNames.URI).toString(); Individual individual = indDao.getIndividualByURI( uri ); - if (individual != null) { - individualsAdded++; - individuals.add(individual); + if (individual != null) { + individuals.add( individual ); log.debug("Adding individual " + uri + " to individual list display"); } else { log.debug("No existing individual for search document with uri = " + uri); } - } - index++; - } - } else { - log.debug("Docs size is 0"); - } - if ( hitCount > INDIVIDUALS_PER_PAGE ){ + } + } + + if ( hitCount > pageSize ){ rvMap.put("showPages", Boolean.TRUE); - List pageRecords = makePagesList(hitCount, INDIVIDUALS_PER_PAGE, page); + List pageRecords = makePagesList(hitCount, pageSize, page); rvMap.put("pages", pageRecords); }else{ rvMap.put("showPages", Boolean.FALSE); @@ -292,63 +289,71 @@ public class IndividualListController extends FreemarkerHttpServlet { } //Get count of individuals without actually getting the results - public static long getIndividualCount(List vclassUris, IndividualDao indDao, ServletContext context) { - SolrQuery query = getQuery(vclassUris, null, 0); - try { - Map rvMap = getResultsForVClassQuery(query, 1, null, indDao, context); - Long count = (Long) rvMap.get("totalCount"); - return count.longValue(); + public static long getIndividualCount(List vclassUris, IndividualDao indDao, ServletContext context) { + SolrQuery query = new SolrQuery(makeMultiClassQuery(vclassUris)); + query.setRows(0); + try { + SolrServer solr = SolrSetup.getSolrServer(context); + QueryResponse response = null; + response = solr.query(query); + return response.getResults().getNumFound(); } catch(Exception ex) { log.error("An error occured in retrieving individual count", ex); } return 0; } - private static SolrQuery getQuery(List vclassUris, String alpha) { - return getQuery(vclassUris, alpha, INDIVIDUAL_LIST_CONTROLLER_MAX_RESULTS); - } - - private static SolrQuery getQuery(List vclassUris, String alpha, int numberRows){ - + /** + * builds a query with a type clause for each type in vclassUris, NAME_LOWERCASE filetred by + * alpha, and just the hits for the page for pageSize. + */ + private static SolrQuery getQuery(List vclassUris, String alpha, int page, int pageSize){ String queryText = ""; - - List queryTypes = new ArrayList(); - try { + + try { + queryText = makeMultiClassQuery(vclassUris); - // query term for rdf:type - multiple types possible - for(String vclassUri: vclassUris) { - queryTypes.add(VitroSearchTermNames.RDFTYPE + ":\"" + vclassUri + "\" "); - } - - if (queryTypes.size() > 0) { - queryText = StringUtils.join(queryTypes, " AND "); - } - // Add alpha filter if applicable if ( alpha != null && !"".equals(alpha) && alpha.length() == 1) { queryText += VitroSearchTermNames.NAME_LOWERCASE + ":" + alpha.toLowerCase() + "*"; } SolrQuery query = new SolrQuery(queryText); - log.debug("Query text is " + queryText); - - // Get all available results from index rather than just those for the current page. - // Otherwise, if there are a large number of non-existent individuals in the search - // index, the current page of results might not retrieve any existing individuals, - // and nothing gets returned. - query.setStart(0) - .setRows(numberRows) - // Need a single-valued field for sorting - .setSortField(VitroSearchTermNames.NAME_LOWERCASE_SINGLE_VALUED, SolrQuery.ORDER.asc); + query.setStart( page > 0 ? pageSize * page + 1 : 0 ) + .setRows( pageSize ); + + // Need a single-valued field for sorting + query.setSortField(VitroSearchTermNames.NAME_LOWERCASE_SINGLE_VALUED, SolrQuery.ORDER.asc); + + log.debug("Query text is " + queryText); return query; } catch (Exception ex){ - log.error(ex,ex); + log.error("Could not make Solr query",ex); return new SolrQuery(); } } + private static String makeMultiClassQuery( List vclassUris){ + String queryText = ""; + List queryTypes = new ArrayList(); + try { + // query term for rdf:type - multiple types possible + for(String vclassUri: vclassUris) { + queryTypes.add(VitroSearchTermNames.RDFTYPE + ":\"" + vclassUri + "\" "); + } + if (queryTypes.size() > 0) { + queryText = StringUtils.join(queryTypes, " AND "); + } + return queryText; + } catch (Exception ex){ + log.error("Could not make Solr query",ex); + return ""; + } + } + + public static List makePagesList( long size, int pageSize, int selectedPage ) { List records = new ArrayList( MAX_PAGES + 1 ); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/search/beans/FileBasedProhibitedFromSearch.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/search/beans/FileBasedProhibitedFromSearch.java index b72838bc8..45549f9f7 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/search/beans/FileBasedProhibitedFromSearch.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/search/beans/FileBasedProhibitedFromSearch.java @@ -8,6 +8,8 @@ import java.io.FileInputStream; import com.hp.hpl.jena.ontology.OntModel; import com.hp.hpl.jena.rdf.model.ModelFactory; +import edu.cornell.mannlib.vitro.webapp.servlet.setup.JenaDataSourceSetupBase; + public class FileBasedProhibitedFromSearch extends ProhibitedFromSearch { /** @@ -17,42 +19,12 @@ public class FileBasedProhibitedFromSearch extends ProhibitedFromSearch { * @param dir to find N3 files in. */ public FileBasedProhibitedFromSearch(String uri, File dir){ - super( uri, getModelFromDir(dir)); + super( uri, JenaDataSourceSetupBase.getModelFromDir(dir)); } public FileBasedProhibitedFromSearch(String URI, OntModel model) { super(URI, model); } - protected static OntModel getModelFromDir( File dir){ - if( dir == null ) - throw new IllegalStateException("Must pass a File to FileBasedProhibitedFromSearch"); - if( !dir.isDirectory() ) - throw new IllegalStateException("Parameter dir to FileBasedProhibitedFromSearch " + - "must be a File object for a directory"); - if( !dir.canRead() ) - throw new IllegalStateException("Parameter dir to FileBasedProhibitedFromSearch must " + - "be a directory that is readable, check premissions on " + dir.getAbsolutePath()); - - OntModel modelOnlyForPFS = ModelFactory.createOntologyModel(); - for( File file : dir.listFiles()){ - if( file.isFile() - && file.canRead() - && file.getName() != null - && file.getName().endsWith(".n3")){ - try{ - modelOnlyForPFS.read( new FileInputStream(file), null, "N3"); - }catch( Throwable th){ - log.warn("could not load file " + - file.getAbsolutePath() + file.separator + file.getName(), th); - } - } - } - - if( modelOnlyForPFS.size() == 0 ){ - log.warn("No class exclusion statements found."); - } - - return modelOnlyForPFS; - } + } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/search/controller/PagedSearchController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/search/controller/PagedSearchController.java index 46826d1ff..f8bb688b1 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/search/controller/PagedSearchController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/search/controller/PagedSearchController.java @@ -11,7 +11,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; -import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -24,13 +23,14 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.SolrServer; +import org.apache.solr.client.solrj.response.FacetField; import org.apache.solr.client.solrj.response.QueryResponse; +import org.apache.solr.client.solrj.response.FacetField.Count; import org.apache.solr.common.SolrDocument; import org.apache.solr.common.SolrDocumentList; import edu.cornell.mannlib.vitro.webapp.beans.ApplicationBean; import edu.cornell.mannlib.vitro.webapp.beans.Individual; -import edu.cornell.mannlib.vitro.webapp.beans.IndividualImpl; import edu.cornell.mannlib.vitro.webapp.beans.VClass; import edu.cornell.mannlib.vitro.webapp.beans.VClassGroup; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; @@ -51,7 +51,6 @@ import edu.cornell.mannlib.vitro.webapp.search.beans.VitroQuery; import edu.cornell.mannlib.vitro.webapp.search.beans.VitroQueryFactory; import edu.cornell.mannlib.vitro.webapp.search.solr.SolrSetup; import edu.cornell.mannlib.vitro.webapp.web.templatemodels.LinkTemplateModel; -import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individuallist.BaseListedIndividual; import edu.cornell.mannlib.vitro.webapp.web.templatemodels.searchresult.IndividualSearchResult; import freemarker.template.Configuration; @@ -67,8 +66,8 @@ public class PagedSearchController extends FreemarkerHttpServlet { private static final long serialVersionUID = 1L; private static final Log log = LogFactory.getLog(PagedSearchController.class); - private static final int DEFAULT_HITS_PER_PAGE = 25; - private static final int DEFAULT_MAX_HIT_COUNT = 1000; + protected static final int DEFAULT_HITS_PER_PAGE = 25; + protected static final int DEFAULT_MAX_HIT_COUNT = 1000; private static final String PARAM_XML_REQUEST = "xml"; private static final String PARAM_START_INDEX = "startIndex"; @@ -146,26 +145,8 @@ public class PagedSearchController extends FreemarkerHttpServlet { log.debug("IndividualDao is " + iDao.toString() + " Public classes in the classgroup are " + grpDao.getPublicGroupsWithVClasses().toString()); log.debug("VClassDao is "+ vclassDao.toString() ); - int startIndex = 0; - try{ - startIndex = Integer.parseInt(vreq.getParameter(PARAM_START_INDEX)); - }catch (Throwable e) { - startIndex = 0; - } - log.debug("startIndex is " + startIndex); - - int hitsPerPage = DEFAULT_HITS_PER_PAGE; - try{ - hitsPerPage = Integer.parseInt(vreq.getParameter(PARAM_HITS_PER_PAGE)); - } catch (Throwable e) { - hitsPerPage = DEFAULT_HITS_PER_PAGE; - } - log.debug("hitsPerPage is " + hitsPerPage); - - int maxHitCount = DEFAULT_MAX_HIT_COUNT ; - if( startIndex >= DEFAULT_MAX_HIT_COUNT - hitsPerPage ) - maxHitCount = startIndex + DEFAULT_MAX_HIT_COUNT ; - log.debug("maxHitCount is " + maxHitCount); + int startIndex = getStartIndex(vreq); + int hitsPerPage = getHitsPerPage( vreq ); String qtxt = vreq.getParameter(VitroQuery.QUERY_PARAMETER_NAME); log.debug("Query text is \""+ qtxt + "\""); @@ -175,42 +156,27 @@ public class PagedSearchController extends FreemarkerHttpServlet { return doFailedSearch(badQueryMsg, qtxt, format); } - SolrQuery query = getQuery(qtxt, maxHitCount, vreq); + SolrQuery query = getQuery(qtxt, hitsPerPage, startIndex, vreq); SolrServer solr = SolrSetup.getSolrServer(getServletContext()); - QueryResponse response = null; - + QueryResponse response = null; try { response = solr.query(query); - - } catch (Throwable t) { - log.error("in first pass at search: " + t); - // this is a hack to deal with odd cases where search and index threads interact - try{ - wait(150); - response = solr.query(query); - } catch (Exception ex) { - log.error(ex); - String msg = makeBadSearchMessage(qtxt, ex.getMessage()); - if (msg == null) { - msg = "The search request contained errors."; - } - return doFailedSearch(msg, qtxt, format); - } + } catch (Exception ex) { + String msg = makeBadSearchMessage(qtxt, ex.getMessage()); + log.error("could not run Solr query",ex); + return doFailedSearch(msg, qtxt, format); } if (response == null) { - log.error("Search response was null"); - String msg = "The search request contained errors."; - return doFailedSearch(msg, qtxt, format); + log.error("Search response was null"); + return doFailedSearch("The search request contained errors.", qtxt, format); } SolrDocumentList docs = response.getResults(); - if (docs == null) { log.error("Document list for a search was null"); - String msg = "The search request contained errors."; - return doFailedSearch(msg, qtxt,format); + return doFailedSearch("The search request contained errors.", qtxt,format); } long hitCount = docs.getNumFound(); @@ -218,30 +184,20 @@ public class PagedSearchController extends FreemarkerHttpServlet { if ( hitCount < 1 ) { return doNoHits(qtxt,format); } - - long lastHitToShow = 0; - if ((startIndex + hitsPerPage) > hitCount ) { - lastHitToShow = hitCount; - } else { - lastHitToShow = startIndex + hitsPerPage; - } - List individuals = new LinkedList(); - for(int i = startIndex; i < lastHitToShow; i++){ - try { - SolrDocument doc = docs.get(i); - String uri = doc.get(VitroSearchTermNames.URI).toString(); - log.debug("Retrieving individual with uri "+ uri); - Individual ent = new IndividualImpl(); - ent.setURI(uri); - ent = iDao.getIndividualByURI(uri); - if(ent!=null) { - ent.setSearchSnippet(getSnippet(doc, response)); - individuals.add(ent); + List individuals = new ArrayList(docs.size()); + Iterator docIter = docs.iterator(); + while( docIter.hasNext() ){ + try { + SolrDocument doc = docIter.next(); + String uri = doc.get(VitroSearchTermNames.URI).toString(); + Individual ind = iDao.getIndividualByURI(uri); + if(ind != null) { + ind.setSearchSnippet( getSnippet(doc, response) ); + individuals.add(ind); } } catch(Exception e) { - log.error("Problem getting usable individuals from search hits. " + - e.getMessage()); + log.error("Problem getting usable individuals from search hits. ",e); } } @@ -275,31 +231,19 @@ public class PagedSearchController extends FreemarkerHttpServlet { body.put("typeName", type.getName()); } - /* Add classgroup and type refinement links to body */ + /* Add ClassGroup and type refinement links to body */ if( wasHtmlRequested ){ - // Search request includes no classgroup and no type, so add classgroup search refinement links. - if ( !classGroupFilterRequested && !typeFilterRequested ) { - List classgroups = getClassGroups(grpDao, docs, maxHitCount); - List classGroupLinks = new ArrayList(classgroups.size()); - for (VClassGroup vcg : classgroups) { - if (vcg.getPublicName() != null) { - classGroupLinks.add(new VClassGroupSearchLink(qtxt, vcg)); - } - } - body.put("classGroupLinks", classGroupLinks); - - // Search request is for a classgroup, so add rdf:type search refinement links - // but try to filter out classes that are subclasses - } else if ( classGroupFilterRequested && !typeFilterRequested ) { - List vClasses = getVClasses(vclassDao, docs); - List vClassLinks = new ArrayList(vClasses.size()); - for (VClass vc : vClasses) { - vClassLinks.add(new VClassSearchLink(qtxt, vc)); - } - body.put("classLinks", vClassLinks); + if ( !classGroupFilterRequested && !typeFilterRequested ) { + // Search request includes no ClassGroup and no type, so add ClassGroup search refinement links. + body.put("classGroupLinks", getClassGroupsLinks(grpDao, docs, response, qtxt)); + } else if ( classGroupFilterRequested && !typeFilterRequested ) { + // Search request is for a ClassGroup, so add rdf:type search refinement links + // but try to filter out classes that are subclasses + body.put("classLinks", getVClassLinks(vclassDao, docs, response, qtxt)); pagingLinkParams.put(PARAM_CLASSGROUP, classGroupParam); } else { + //search request is for a class so there are no more refinements pagingLinkParams.put(PARAM_RDFTYPE, typeParam); } } @@ -314,9 +258,10 @@ public class PagedSearchController extends FreemarkerHttpServlet { body.put("hitCount", hitCount); body.put("startIndex", startIndex); - body.put("pagingLinks", getPagingLinks(startIndex, hitsPerPage, - hitCount, maxHitCount, vreq.getServletPath(), - pagingLinkParams)); + body.put("pagingLinks", + getPagingLinks(startIndex, hitsPerPage, hitCount, + vreq.getServletPath(), + pagingLinkParams)); if (startIndex != 0) { body.put("prevPage", getPreviousPageLink(startIndex, @@ -336,6 +281,28 @@ public class PagedSearchController extends FreemarkerHttpServlet { } + private int getHitsPerPage(VitroRequest vreq) { + int hitsPerPage = DEFAULT_HITS_PER_PAGE; + try{ + hitsPerPage = Integer.parseInt(vreq.getParameter(PARAM_HITS_PER_PAGE)); + } catch (Throwable e) { + hitsPerPage = DEFAULT_HITS_PER_PAGE; + } + log.debug("hitsPerPage is " + hitsPerPage); + return hitsPerPage; + } + + private int getStartIndex(VitroRequest vreq) { + int startIndex = 0; + try{ + startIndex = Integer.parseInt(vreq.getParameter(PARAM_START_INDEX)); + }catch (Throwable e) { + startIndex = 0; + } + log.debug("startIndex is " + startIndex); + return startIndex; + } + private String badQueryText(String qtxt) { if( qtxt == null || "".equals( qtxt.trim() ) ) return "Please enter a search term."; @@ -348,80 +315,103 @@ public class PagedSearchController extends FreemarkerHttpServlet { /** * Get the class groups represented for the individuals in the documents. + * @param qtxt */ - private List getClassGroups(VClassGroupDao grpDao, SolrDocumentList docs, int maxHitCount) { - LinkedHashMap grpMap = grpDao.getClassGroupMap(); - int n = grpMap.size(); + private List getClassGroupsLinks(VClassGroupDao grpDao, SolrDocumentList docs, QueryResponse rsp, String qtxt) { + Map cgURItoCount = new HashMap(); - HashSet classGroupsInHits = new HashSet(n); - int grpsFound = 0; + List classgroups = new ArrayList( ); + List ffs = rsp.getFacetFields(); + for(FacetField ff : ffs){ + if(VitroSearchTermNames.CLASSGROUP_URI.equals(ff.getName())){ + List counts = ff.getValues(); + for( Count ct: counts){ + VClassGroup vcg = grpDao.getGroupByURI( ct.getName() ); + if( vcg == null ){ + log.debug("could not get classgroup for URI " + ct.getName()); + }else{ + classgroups.add(vcg); + cgURItoCount.put(vcg.getURI(), ct.getCount()); + } + } + } + } - long maxHits = Math.min(docs.getNumFound(), maxHitCount); - for(int i = 0; i < maxHits && n > grpsFound ;i++){ - try{ - SolrDocument doc = docs.get(i); - Collection grps = doc.getFieldValues(VitroSearchTermNames.CLASSGROUP_URI); - if (grps != null) { - for (Object o : grps) { - String groupUri = o.toString(); - if( groupUri != null && !classGroupsInHits.contains(groupUri)){ - classGroupsInHits.add(groupUri); - grpsFound++; - if( grpsFound >= n ) - break; - } - } - } - } catch(Exception e) { - log.error("problem getting VClassGroups from search hits " - + e.getMessage() ); - e.printStackTrace(); - } - } - - List classgroupURIs= Collections.list(Collections.enumeration(classGroupsInHits)); - List classgroups = new ArrayList( classgroupURIs.size() ); - for(String cgUri: classgroupURIs){ - if( cgUri != null && ! "".equals(cgUri) ){ - VClassGroup vcg = grpDao.getGroupByURI( cgUri ); - if( vcg == null ){ - log.debug("could not get classgroup for URI " + cgUri); - }else{ - classgroups.add(vcg); - } - } - } grpDao.sortGroupList(classgroups); - - return classgroups; + + List classGroupLinks = new ArrayList(classgroups.size()); + for (VClassGroup vcg : classgroups) { + long count = cgURItoCount.get( vcg.getURI() ); + if (vcg.getPublicName() != null && count > 0 ) { + classGroupLinks.add(new VClassGroupSearchLink(qtxt, vcg, count)); + } + } + return classGroupLinks; } - private List getVClasses(VClassDao vclassDao, SolrDocumentList docs){ + private List getVClassLinks(VClassDao vclassDao, SolrDocumentList docs, QueryResponse rsp, String qtxt){ HashSet typesInHits = getVClassUrisForHits(docs); List classes = new ArrayList(typesInHits.size()); + Map typeURItoCount = new HashMap(); - Iterator it = typesInHits.iterator(); - while(it.hasNext()){ - String typeUri = it.next(); - try{ - if( VitroVocabulary.OWL_THING.equals(typeUri)) - continue; - VClass type = vclassDao.getVClassByURI(typeUri); - if( type != null && - ! type.isAnonymous() && - type.getName() != null && !"".equals(type.getName()) && - type.getGroupURI() != null ) //don't display classes that aren't in classgroups - classes.add(type); - }catch(Exception ex){ - if( log.isDebugEnabled() ) - log.debug("could not add type " + typeUri, ex); - } +// Iterator it = typesInHits.iterator(); +// while(it.hasNext()){ +// String typeUri = it.next(); +// try{ +// if( VitroVocabulary.OWL_THING.equals(typeUri)) +// continue; +// VClass type = vclassDao.getVClassByURI(typeUri); +// if( type != null && +// ! type.isAnonymous() && +// type.getName() != null && !"".equals(type.getName()) && +// type.getGroupURI() != null ) //don't display classes that aren't in classgroups +// classes.add(type); +// }catch(Exception ex){ +// if( log.isDebugEnabled() ) +// log.debug("could not add type " + typeUri, ex); +// } +// } + + List ffs = rsp.getFacetFields(); + for(FacetField ff : ffs){ + if(VitroSearchTermNames.RDFTYPE.equals(ff.getName())){ + List counts = ff.getValues(); + for( Count ct: counts){ + String typeUri = ct.getName(); + long count = ct.getCount(); + try{ + if( VitroVocabulary.OWL_THING.equals(typeUri) || + count == 0 ) + continue; + VClass type = vclassDao.getVClassByURI(typeUri); + if( type != null && + ! type.isAnonymous() && + type.getName() != null && !"".equals(type.getName()) && + type.getGroupURI() != null ){ //don't display classes that aren't in classgroups + typeURItoCount.put(typeUri,count); + classes.add(type); + } + }catch(Exception ex){ + if( log.isDebugEnabled() ) + log.debug("could not add type " + typeUri, ex); + } + } + } } + + Collections.sort(classes, new Comparator(){ public int compare(VClass o1, VClass o2) { return o1.compareTo(o2); }}); - return classes; + + List vClassLinks = new ArrayList(classes.size()); + for (VClass vc : classes) { + long count = typeURItoCount.get(vc.getURI()); + vClassLinks.add(new VClassSearchLink(qtxt, vc, count )); + } + + return vClassLinks; } private HashSet getVClassUrisForHits(SolrDocumentList docs){ @@ -455,51 +445,68 @@ public class PagedSearchController extends FreemarkerHttpServlet { return text.toString(); } - private SolrQuery getQuery(String queryText, int maxHitCount, VitroRequest vreq) { + private SolrQuery getQuery(String queryText, int hitsPerPage, int startIndex, VitroRequest vreq) { SolrQuery query = new SolrQuery(queryText); - // Solr requires these values, but we don't want them to be the real values for this page - // of results, else the refinement links won't work correctly: each page of results needs to - // show refinement links generated for all results, not just for the results on the current page. - query.setStart(0) - .setRows(maxHitCount); + query.setStart( startIndex ) + .setRows(hitsPerPage); - // Classgroup filtering + // ClassGroup filtering param String classgroupParam = (String) vreq.getParameter(PARAM_CLASSGROUP); - if ( ! StringUtils.isBlank(classgroupParam) ) { + + // rdf:type filtering param + String typeParam = (String) vreq.getParameter(PARAM_RDFTYPE); + + if ( ! StringUtils.isBlank(classgroupParam) ) { + // ClassGroup filtering log.debug("Firing classgroup query "); log.debug("request.getParameter(classgroup) is "+ classgroupParam); query.addFilterQuery(VitroSearchTermNames.CLASSGROUP_URI + ":\"" + classgroupParam + "\""); - } - - // rdf:type filtering - String typeParam = (String) vreq.getParameter(PARAM_RDFTYPE); - if ( ! StringUtils.isBlank(typeParam) ) { + + //with ClassGroup filtering we want type facets + query.add("facet","true"); + query.add("facet.limit","-1"); + query.add("facet.field",VitroSearchTermNames.RDFTYPE); + + }else if ( ! StringUtils.isBlank(typeParam) ) { + // rdf:type filtering log.debug("Firing type query "); log.debug("request.getParameter(type) is "+ typeParam); query.addFilterQuery(VitroSearchTermNames.RDFTYPE + ":\"" + typeParam + "\""); - } - - //query.setQuery(queryText); + + //with type filtering we don't have facets. + }else{ + //When no filtering is set, we want ClassGroup facets + query.add("facet","true"); + query.add("facet.limit","-1"); + query.add("facet.field",VitroSearchTermNames.CLASSGROUP_URI); + } + log.debug("Query = " + query.toString()); return query; - } - - private class VClassGroupSearchLink extends LinkTemplateModel { - - VClassGroupSearchLink(String querytext, VClassGroup classgroup) { + } + + protected class VClassGroupSearchLink extends LinkTemplateModel { + long count = 0; + VClassGroupSearchLink(String querytext, VClassGroup classgroup, long count) { super(classgroup.getPublicName(), "/search", PARAM_QUERY_TEXT, querytext, PARAM_CLASSGROUP, classgroup.getURI()); + this.count = count; } - } - - private class VClassSearchLink extends LinkTemplateModel { - VClassSearchLink(String querytext, VClass type) { - super(type.getName(), "/search", PARAM_QUERY_TEXT, querytext, PARAM_RDFTYPE, type.getURI()); - } + public String getCount() { return Long.toString(count); } } - private List getPagingLinks(int startIndex, int hitsPerPage, long hitCount, int maxHitCount, String baseUrl, ParamMap params) { + protected class VClassSearchLink extends LinkTemplateModel { + long count = 0; + VClassSearchLink(String querytext, VClass type, long count) { + super(type.getName(), "/search", PARAM_QUERY_TEXT, querytext, PARAM_RDFTYPE, type.getURI()); + this.count = count; + } + + public String getCount() { return Long.toString(count); } + } + + protected static List getPagingLinks(int startIndex, int hitsPerPage, long hitCount, String baseUrl, ParamMap params) { List pagingLinks = new ArrayList(); @@ -508,17 +515,23 @@ public class PagedSearchController extends FreemarkerHttpServlet { return pagingLinks; } + int maxHitCount = DEFAULT_MAX_HIT_COUNT ; + if( startIndex >= DEFAULT_MAX_HIT_COUNT - hitsPerPage ) + maxHitCount = startIndex + DEFAULT_MAX_HIT_COUNT ; + for (int i = 0; i < hitCount; i += hitsPerPage) { params.put(PARAM_START_INDEX, String.valueOf(i)); if ( i < maxHitCount - hitsPerPage) { int pageNumber = i/hitsPerPage + 1; - if (i >= startIndex && i < (startIndex + hitsPerPage)) { + boolean iIsCurrentPage = (i >= startIndex && i < (startIndex + hitsPerPage)); + if ( iIsCurrentPage ) { pagingLinks.add(new PagingLink(pageNumber)); } else { pagingLinks.add(new PagingLink(pageNumber, baseUrl, params)); } } else { pagingLinks.add(new PagingLink("more...", baseUrl, params)); + break; } } @@ -535,7 +548,7 @@ public class PagedSearchController extends FreemarkerHttpServlet { return UrlBuilder.getUrl(baseUrl, params); } - private class PagingLink extends LinkTemplateModel { + protected static class PagingLink extends LinkTemplateModel { PagingLink(int pageNumber, String baseUrl, ParamMap params) { super(String.valueOf(pageNumber), baseUrl, params); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/search/indexing/IndexBuilder.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/search/indexing/IndexBuilder.java index b99fbe564..0511e6d5d 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/search/indexing/IndexBuilder.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/search/indexing/IndexBuilder.java @@ -195,8 +195,8 @@ public class IndexBuilder extends Thread { if(! stopRequested && log != null )//may be null on shutdown log.info("Stopping IndexBuilder thread"); } - - + + public static void checkIndexOnRootLogin(HttpServletRequest req){ HttpSession session = req.getSession(); ServletContext context = session.getServletContext(); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/JenaDataSourceSetupBase.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/JenaDataSourceSetupBase.java index 714a6da1f..03b63a2fd 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/JenaDataSourceSetupBase.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/JenaDataSourceSetupBase.java @@ -2,6 +2,7 @@ package edu.cornell.mannlib.vitro.webapp.servlet.setup; +import java.io.FileInputStream; import java.io.InputStream; import java.io.File; import java.sql.SQLException; @@ -15,6 +16,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.hp.hpl.jena.graph.Graph; +import com.hp.hpl.jena.ontology.OntModel; import com.hp.hpl.jena.ontology.OntModelSpec; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.ModelFactory; @@ -57,6 +59,12 @@ public class JenaDataSourceSetupBase extends JenaBaseDaoCon { //these files are loaded everytime the system starts up public static String APPPATH_LOAD = APPPATH + "menuload/"; protected static String SUBMODELS = "/WEB-INF/submodels/"; + + //All files in this directory will be reloaded every startup + //and attached as sub-models to the displayOntModel. + static final String DISPLAY_MODEL_LOAD_AT_STARTUP_DIR = + APPPATH + "loadedAtStartup"; + protected static boolean firstStartup = false; String DB_USER = "jenatest"; // database user id @@ -406,6 +414,39 @@ public class JenaDataSourceSetupBase extends JenaBaseDaoCon { } + /** + * Read all the files in the directory as RDF files + * and return a model build from all RDF data found in those files. + * This will attempt to load formats supported by getRdfFormat(). + */ + public static OntModel getModelFromDir( File dir){ + if( dir == null ) + throw new IllegalStateException("Must pass a File to getModelFromDir()"); + if( !dir.isDirectory() ) + throw new IllegalStateException("Directory must be a File object for a directory"); + if( !dir.canRead() ) + throw new IllegalStateException("getModelFromDir(): Directory " + + " must be readable, check premissions on " + dir.getAbsolutePath()); + + OntModel model = ModelFactory.createOntologyModel(); + for( File file : dir.listFiles()){ + if( file.isFile() + && file.canRead() + && file.getName() != null ){ + String format = getRdfFormat( file.getName() ); + try{ + model.read( new FileInputStream(file), null, format); + }catch( Throwable th){ + log.warn("Could not load file " + + file.getAbsolutePath() + file.separator + file.getName() + + " check that it contains valid " + format + " data.", + th); + } + } + } + return model; + } + public static void setVitroJenaModelMaker(VitroJenaModelMaker vjmm, ServletContext ctx){ ctx.setAttribute(rdbModelMaker, vjmm); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/JenaPersistentDataSourceSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/JenaPersistentDataSourceSetup.java index 4d9f944b6..bcffb1617 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/JenaPersistentDataSourceSetup.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/JenaPersistentDataSourceSetup.java @@ -2,14 +2,23 @@ package edu.cornell.mannlib.vitro.webapp.servlet.setup; +import java.io.File; +import java.io.FileOutputStream; + 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 org.joda.time.DateTime; +import org.joda.time.format.ISODateTimeFormat; import com.hp.hpl.jena.ontology.OntModel; +import com.hp.hpl.jena.query.Query; +import com.hp.hpl.jena.query.QueryExecution; +import com.hp.hpl.jena.query.QueryExecutionFactory; +import com.hp.hpl.jena.query.QueryFactory; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.ModelFactory; @@ -21,8 +30,8 @@ public class JenaPersistentDataSourceSetup extends JenaDataSourceSetupBase private static final Log log = LogFactory.getLog( JenaPersistentDataSourceSetup.class.getName()); - @Override - public void contextInitialized(ServletContextEvent sce) { + @Override + public void contextInitialized(ServletContextEvent sce) { ServletContext ctx = sce.getServletContext(); if (AbortStartup.isStartupAborted(ctx)) { @@ -35,7 +44,7 @@ public class JenaPersistentDataSourceSetup extends JenaDataSourceSetupBase JENA_USER_ACCOUNTS_MODEL, DB_ONT_MODEL_SPEC, ctx); if (userAccountsDbModel.size() == 0) { firstStartup = true; - readOntologyFilesInPathSet(AUTHPATH, sce.getServletContext(), + readOntologyFilesInPathSet(AUTHPATH, ctx, userAccountsDbModel); } OntModel userAccountsModel = ModelFactory.createOntologyModel( @@ -43,8 +52,8 @@ public class JenaPersistentDataSourceSetup extends JenaDataSourceSetupBase userAccountsModel.add(userAccountsDbModel); userAccountsModel.getBaseModel().register( new ModelSynchronizer(userAccountsDbModel)); - sce.getServletContext().setAttribute( - "userAccountsOntModel", userAccountsModel); + ctx.setAttribute("userAccountsOntModel", userAccountsModel); + if (userAccountsModel.isEmpty()) { initializeUserAccounts(ctx, userAccountsModel); } @@ -54,22 +63,20 @@ public class JenaPersistentDataSourceSetup extends JenaDataSourceSetupBase // display, editing and navigation Model try { - Model appDbModel = makeDBModelFromConfigurationProperties( + Model displayDbModel = makeDBModelFromConfigurationProperties( JENA_DISPLAY_METADATA_MODEL, DB_ONT_MODEL_SPEC, ctx); - log.debug("Display model size is " + appDbModel.size()); - if (appDbModel.size() == 0) { - readOntologyFilesInPathSet( - APPPATH, sce.getServletContext(),appDbModel); - log.debug("Loaded ontology files from " + APPPATH + " into display model"); + if (displayDbModel.size() == 0) { + readOntologyFilesInPathSet(APPPATH, ctx,displayDbModel); } - OntModel appModel = ModelFactory.createOntologyModel( - MEM_ONT_MODEL_SPEC); - appModel.add(appDbModel); - appModel.getBaseModel().register(new ModelSynchronizer(appDbModel)); - ctx.setAttribute("displayOntModel", appModel); + OntModel displayModel = ModelFactory.createOntologyModel(MEM_ONT_MODEL_SPEC); + displayModel.add(displayDbModel); + displayModel.getBaseModel().register(new ModelSynchronizer(displayDbModel)); + ctx.setAttribute("displayOntModel", displayModel); + //at each startup load all RDF files from directory to sub-models of display model + initializeDisplayLoadedAtStartup(ctx, displayModel); } catch (Throwable t) { - log.error("Unable to load user application configuration model from DB", t); + log.error("Unable to load user application configuration model", t); } //display tbox - currently reading in every time @@ -78,7 +85,7 @@ public class JenaPersistentDataSourceSetup extends JenaDataSourceSetupBase JENA_DISPLAY_TBOX_MODEL, DB_ONT_MODEL_SPEC, ctx); //Reading in single file every time //TODO: Check if original needs to be cleared/removed every time? - readOntologyFileFromPath(APPPATH_LOAD + "displayTBOX.n3", displayTboxModel, sce.getServletContext()); + readOntologyFileFromPath(APPPATH_LOAD + "displayTBOX.n3", displayTboxModel, ctx); OntModel appTBOXModel = ModelFactory.createOntologyModel( MEM_ONT_MODEL_SPEC); appTBOXModel.add(displayTboxModel); @@ -86,15 +93,16 @@ public class JenaPersistentDataSourceSetup extends JenaDataSourceSetupBase ctx.setAttribute("displayOntModelTBOX", appTBOXModel); log.debug("Loaded file " + APPPATH_LOAD + "displayTBOX.n3 into display tbox model"); } catch (Throwable t) { - log.error("Unable to load user application configuration model TBOX from DB", t); + log.error("Unable to load user application configuration model TBOX", t); } + //Display Display model, currently empty, create if doesn't exist but no files to load try { Model displayDisplayModel = makeDBModelFromConfigurationProperties( JENA_DISPLAY_DISPLAY_MODEL, DB_ONT_MODEL_SPEC, ctx); //Reading in single file every time //TODO: Check if original needs to be cleared/removed every time? - readOntologyFileFromPath(APPPATH_LOAD + "displayDisplay.n3", displayDisplayModel, sce.getServletContext()); + readOntologyFileFromPath(APPPATH_LOAD + "displayDisplay.n3", displayDisplayModel, ctx); OntModel appDisplayDisplayModel = ModelFactory.createOntologyModel( MEM_ONT_MODEL_SPEC); @@ -103,7 +111,7 @@ public class JenaPersistentDataSourceSetup extends JenaDataSourceSetupBase ctx.setAttribute("displayOntModelDisplayModel", appDisplayDisplayModel); log.debug("Loaded file " + APPPATH_LOAD + "displayDisplay.n3 into display display model"); } catch (Throwable t) { - log.error("Unable to load user application configuration model Display Model from DB", t); + log.error("Unable to load user application configuration model Display Model", t); } } @@ -117,4 +125,123 @@ public class JenaPersistentDataSourceSetup extends JenaDataSourceSetupBase readOntologyFilesInPathSet(AUTHPATH, ctx, userAccountsModel); } + /** + * Load the RDF found in the directory DISPLAY_MODEL_LOAD_AT_STARTUP_DIR + * a sub-models of displayModel. The RDF from thes files will not be saved + * in the database and it will be reloaded each time the system starts up. + */ + private void initializeDisplayLoadedAtStartup(ServletContext ctx, OntModel displayModel){ + Model displayLoadAtStartup = readInDisplayModelLoadAtStartup(ctx); + + if( log.isDebugEnabled() ){ + log.debug("loaded display model from files in " + ctx.getRealPath(DISPLAY_MODEL_LOAD_AT_STARTUP_DIR) ); + displayLoadAtStartup.write(System.out, "N3-PP"); + } + + checkForOldListViews(ctx,displayModel,displayLoadAtStartup); + displayModel.addSubModel( displayLoadAtStartup ); + } + + /** + * All of the list views should now reside in files in DISPLAY_MODEL_LOAD_AT_STARTUP_DIR. + * This will check for custom list view annotation statements in the displayModel, check + * if they exist in the files in DISPLAY_MODEL_LOAD_AT_STARTUP_DIR, and write any that don't + * exist there to a file in DISPLAY_MODEL_LOAD_AT_STARTUP_DIR. After that the statements + * will be removed from the displayDBModel. + * + * returns true if there were old list view statements in the DB, returns false + * if there were none. displayLoadAlways should be reloaded from the file system + * if this returns true as this method may have changed the files. + * + * displayLoadAtStartup and displayModel may be modified. + */ + private void checkForOldListViews( ServletContext ctx, OntModel displayModel, Model displayLoadAtStartup){ + // run construct for old custom list view statements from displayModel + Model oldListViewModel = getOldListViewStatements( displayModel ); + if( log.isDebugEnabled() ){ + log.debug("Printing the old list view statements from the display model to System.out."); + oldListViewModel.write(System.out,"N3-PP"); + } + + // find statements in old stmts that are not in loadedAtStartup and + // save them in a new file in DISPLAY_MODEL_LOAD_AT_STARTUP_DIR + // so that in the future they will be in loadedAtStartup + Model stmtsInOldAndFiles = displayLoadAtStartup.intersection( displayModel ); + Model unhandledOldListViewStmts = oldListViewModel.difference( stmtsInOldAndFiles ); + + boolean saved = false; + boolean neededSave = false; + + if( unhandledOldListViewStmts != null && !unhandledOldListViewStmts.isEmpty() ){ + log.debug("need to deal with old list view statements from the display model"); + neededSave = true; + try{ + //create a file for the old statements in the loadAtStartup directory + String newFileName = ctx.getRealPath( + DISPLAY_MODEL_LOAD_AT_STARTUP_DIR + File.separator + + new DateTime().toString(ISODateTimeFormat.basicDateTime()) + ".n3" ); + File file = new File( newFileName ); + file.createNewFile(); + + log.info("Relocating " + unhandledOldListViewStmts.size() + " custom list view statements from DB and saving to " + + file.getAbsolutePath()+ File.separator + file.getName() + + ". These will be loaded from this file when the system starts up."); + + FileOutputStream fileOut = new FileOutputStream(file); + unhandledOldListViewStmts.write(fileOut, "N3-PP"); + fileOut.close(); + saved = true; + }catch(Throwable th){ + log.warn("Could not save old list view statements. Leaving them in the DB",th); + } + + //need to reload displayLoadAlways because DISPLAY_MODEL_LOAD_AT_STARTUP_DIR may have changed + displayLoadAtStartup.removeAll().add(readInDisplayModelLoadAtStartup(ctx)); + } + + + if( oldListViewModel != null && ! oldListViewModel.isEmpty() ){ + //At this point, there are old list view statements in the DB but they + //should are all redundant with ones in DISPLAY_MODEL_LOAD_AT_STARTUP_DIR + if( (neededSave && saved) || (!neededSave) ){ + //if there was nothing to save, just remove the old stuff + //if there was stuff to save, only remove if it was saved. + log.debug("removing old statements from displayModel"); + displayModel.remove(oldListViewModel); + } + } + + } + + private Model getOldListViewStatements(OntModel displayModel) { + //run a construct on displayModel to get all list view statements + Query query = QueryFactory.create ( listViewQuery ); + QueryExecution qexec = QueryExecutionFactory.create(query, displayModel) ; + Model oldModel = null; + + try { + oldModel = qexec.execConstruct(); + } catch( Throwable th ){ + log.error("could not check for old custom list views, query exception",th); + }finally { + qexec.close() ; + } + + if( oldModel != null) + return oldModel; + else + return ModelFactory.createDefaultModel(); + } + + private static final String listViewQuery = "" + + "PREFIX d: \n" + + "CONSTRUCT { \n" + + " ?a d:listViewConfigFile ?b . \n" + + "} WHERE {\n" + + " ?a d:listViewConfigFile ?b . \n" + + "} "; + + protected Model readInDisplayModelLoadAtStartup( ServletContext ctx ){ + return getModelFromDir( new File( ctx.getRealPath( DISPLAY_MODEL_LOAD_AT_STARTUP_DIR ))); + } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/pageDataGetter/DataGetterUtils.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/pageDataGetter/DataGetterUtils.java index c09e82253..aa0ba5687 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/pageDataGetter/DataGetterUtils.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/pageDataGetter/DataGetterUtils.java @@ -246,11 +246,8 @@ public class DataGetterUtils { jo.put("imageUrl", ind.getImageUrl()); jo.put("profileUrl", UrlBuilder.getIndividualProfileUrl(ind, vreq)); - jo.put("mostSpecificTypes", JsonServlet.getMostSpecificTypes(ind,fullWdf)); - - jo.put("preferredTitle", JsonServlet.getDataPropertyValue(ind, preferredTitleDp, fullWdf)); - jo.put("firstName", JsonServlet.getDataPropertyValue(ind, fNameDp, fullWdf)); - jo.put("lastName", JsonServlet.getDataPropertyValue(ind, lNameDp, fullWdf)); + jo.put("mostSpecificTypes", JsonServlet.getMostSpecificTypes(ind,fullWdf)); + jo.put("preferredTitle", JsonServlet.getDataPropertyValue(ind, preferredTitleDp, fullWdf)); jInds.put(jo); } diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/search/controller/PagedSearchControllerTest.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/search/controller/PagedSearchControllerTest.java new file mode 100644 index 000000000..0060ed1d2 --- /dev/null +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/search/controller/PagedSearchControllerTest.java @@ -0,0 +1,61 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ +/** + * + */ +package edu.cornell.mannlib.vitro.webapp.search.controller; + +import java.util.List; + +import junit.framework.Assert; + +import org.junit.Before; +import org.junit.Test; + +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.ParamMap; +import edu.cornell.mannlib.vitro.webapp.search.controller.PagedSearchController.PagingLink; + +public class PagedSearchControllerTest { + + @Test + public void testGetPagingLinks() { + ParamMap pm = new ParamMap(); + int hitsPerPage = 25; + int totalHits = 500; + int currentStartIndex = 0; + List pageLinks = PagedSearchController.getPagingLinks(currentStartIndex, hitsPerPage, totalHits, "baseURL", pm); + Assert.assertNotNull(pageLinks); + Assert.assertEquals(500 / 25, pageLinks.size()); + + //test for no page links on a very short result + hitsPerPage = 25; + totalHits = 10; + currentStartIndex = 0; + pageLinks = PagedSearchController.getPagingLinks(currentStartIndex, hitsPerPage, totalHits, "baseURL", pm); + Assert.assertNotNull(pageLinks); + Assert.assertEquals(0, pageLinks.size()); + } + + @Test + public void testGetPagingLinksForLargeResults() { + ParamMap pm = new ParamMap(); + int hitsPerPage = 25; + int totalHits = 349909; + int currentStartIndex = 0; + List pageLinks = PagedSearchController.getPagingLinks(currentStartIndex, hitsPerPage, totalHits, "baseURL", pm); + Assert.assertNotNull(pageLinks); + Assert.assertEquals( PagedSearchController.DEFAULT_MAX_HIT_COUNT / hitsPerPage, pageLinks.size()); + + //test for large sets of results with high start index + hitsPerPage = 25; + totalHits = PagedSearchController.DEFAULT_MAX_HIT_COUNT + 20329; + currentStartIndex = PagedSearchController.DEFAULT_MAX_HIT_COUNT + 5432; + pageLinks = PagedSearchController.getPagingLinks(currentStartIndex, hitsPerPage, totalHits, "baseURL", pm); + Assert.assertNotNull(pageLinks); + Assert.assertEquals( + (currentStartIndex / hitsPerPage) + //all the pages that are before the current page + (PagedSearchController.DEFAULT_MAX_HIT_COUNT / hitsPerPage) + //some pages after the current apge + 1, //for the more... page + pageLinks.size()); + } + +}