merging 8813 8810 8803 8802 8741 8731
This commit is contained in:
parent
ee42cad576
commit
199a5f6c2f
12 changed files with 585 additions and 344 deletions
|
@ -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:
|
||||
|
||||
<rdf:Description rdf:about="http://vivoweb.org/ontology/core#authorInAuthorship">
|
||||
<display:listViewConfigFile rdf:datatype="http://www.w3.org/2001/XMLSchema#string">listViewConfig-authorInAuthorship.xml</display:listViewConfigFile>
|
||||
</rdf:Description>
|
||||
<http://vivoweb.org/ontology/core#authorInAuthorship>
|
||||
<http://vitro.mannlib.cornell.edu/ontologies/display/1.1#listViewConfigFile>
|
||||
"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
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE rdf:RDF [
|
||||
<!ENTITY display "http://vitro.mannlib.cornell.edu/ontologies/display/1.1#">
|
||||
<!ENTITY owl "http://www.w3.org/2002/07/owl#">
|
||||
<!ENTITY rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
||||
<!ENTITY rdfs "http://www.w3.org/2000/01/rdf-schema#">
|
||||
<!ENTITY xsd "http://www.w3.org/2001/XMLSchema#">
|
||||
<!ENTITY vitro "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#">
|
||||
]>
|
||||
|
||||
<rdf:RDF xml:base="http://vitro.mannlib.cornell.edu/ontologies/display/1.1/"
|
||||
xmlns:display="&display;"
|
||||
xmlns:owl="&owl;"
|
||||
xmlns:rdf="&rdf;"
|
||||
xmlns:rdfs="&rdfs;"
|
||||
xmlns:vitro="&vitro;">
|
||||
|
||||
|
||||
<rdf:Description rdf:about="http://vitro.mannlib.cornell.edu/ontologies/display/1.1#hasElement">
|
||||
<display:listViewConfigFile rdf:datatype="http://www.w3.org/2001/XMLSchema#string">listViewConfig-hasElement.xml</display:listViewConfigFile>
|
||||
</rdf:Description>
|
||||
|
||||
</rdf:RDF>
|
|
@ -1,23 +1,27 @@
|
|||
# $This file is distributed under the terms of the license in /doc/license.txt$
|
||||
|
||||
@prefix owl: <http://www.w3.org/2002/07/owl#> .
|
||||
@prefix vitroDisplay: <http://vitro.mannlib.cornell.edu/ontologies/display/1.1#> .
|
||||
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
|
||||
@prefix core: <http://vivoweb.org/ontology/core#> .
|
||||
@prefix example: <http://example/ns/> .
|
||||
|
||||
# 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: <http://www.w3.org/2002/07/owl#> .
|
||||
# @prefix vitroDisplay: <http://vitro.mannlib.cornell.edu/ontologies/display/1.1#> .
|
||||
# @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
|
||||
# @prefix example: <http://example/ns/> .
|
||||
#
|
||||
# vitroDisplay:SearchIndex
|
||||
# rdf:type owl:Thing ;
|
||||
# vitroDisplay:excludeClass example:classToExclude ;
|
|
@ -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<Literal> 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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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<String,Object> getResultsForVClasses(List<String> vclassURIs, int page, String alpha, IndividualDao indDao, ServletContext context)
|
||||
throws IOException, ServletException{
|
||||
Map<String,Object> rvMap = new HashMap<String,Object>();
|
||||
try{
|
||||
SolrQuery query = getQuery(vclassURIs, alpha);
|
||||
rvMap = getResultsForVClassQuery(query, page, alpha, indDao, context);
|
||||
List<Individual> individuals = (List<Individual>) 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<String,Object> getResultsForVClasses(List<String> vclassURIs, int page, String alpha, IndividualDao indDao, ServletContext context)
|
||||
// throws IOException, ServletException{
|
||||
// Map<String,Object> rvMap = new HashMap<String,Object>();
|
||||
// try{
|
||||
// SolrQuery query = getQuery(vclassURIs, alpha, page, INDIVIDUALS_PER_PAGE);
|
||||
// rvMap = getResultsForVClassQuery(query, page, alpha, indDao, context);
|
||||
// List<Individual> individuals = (List<Individual>) 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<String,Object> getResultsForVClass(String vclassURI, int page, String alpha, IndividualDao indDao, ServletContext context)
|
||||
throws IOException, SearchException{
|
||||
Map<String,Object> rvMap = new HashMap<String,Object>();
|
||||
|
@ -188,8 +189,8 @@ public class IndividualListController extends FreemarkerHttpServlet {
|
|||
//make query for this rdf:type
|
||||
List<String> classUris = new ArrayList<String>();
|
||||
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<Individual> individuals = (List<Individual>) 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<String,Object> getResultsForVClassIntersections(List<String> vclassURIs, int page, String alpha, IndividualDao indDao, ServletContext context)
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Map<String,Object> getResultsForVClassIntersections(List<String> vclassURIs, int page, int pageSize, String alpha, IndividualDao indDao, ServletContext context)
|
||||
throws IOException, ServletException{
|
||||
Map<String,Object> rvMap = new HashMap<String,Object>();
|
||||
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<Individual> individuals = (List<Individual>) 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<String,Object> getResultsForVClassQuery(SolrQuery query, int page, String alpha, IndividualDao indDao, ServletContext context)
|
||||
protected static Map<String,Object> getResultsForVClassQuery(SolrQuery query, int page, int pageSize, String alpha, IndividualDao indDao, ServletContext context)
|
||||
throws IOException, ServletException {
|
||||
Map<String,Object> rvMap = new HashMap<String,Object>();
|
||||
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<Individual> individuals = new ArrayList<Individual>(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<SolrDocument> docIter = docs.iterator();
|
||||
List<Individual> individuals = new ArrayList<Individual>(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<PageRecord> pageRecords = makePagesList(hitCount, INDIVIDUALS_PER_PAGE, page);
|
||||
List<PageRecord> 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<String> vclassUris, IndividualDao indDao, ServletContext context) {
|
||||
SolrQuery query = getQuery(vclassUris, null, 0);
|
||||
try {
|
||||
Map<String,Object> rvMap = getResultsForVClassQuery(query, 1, null, indDao, context);
|
||||
Long count = (Long) rvMap.get("totalCount");
|
||||
return count.longValue();
|
||||
public static long getIndividualCount(List<String> 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<String> vclassUris, String alpha) {
|
||||
return getQuery(vclassUris, alpha, INDIVIDUAL_LIST_CONTROLLER_MAX_RESULTS);
|
||||
}
|
||||
|
||||
private static SolrQuery getQuery(List<String> 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<String> vclassUris, String alpha, int page, int pageSize){
|
||||
String queryText = "";
|
||||
|
||||
List<String> queryTypes = new ArrayList<String>();
|
||||
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<String> vclassUris){
|
||||
String queryText = "";
|
||||
List<String> queryTypes = new ArrayList<String>();
|
||||
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<PageRecord> makePagesList( long size, int pageSize, int selectedPage ) {
|
||||
|
||||
List<PageRecord> records = new ArrayList<PageRecord>( MAX_PAGES + 1 );
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<Individual> individuals = new LinkedList<Individual>();
|
||||
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<Individual> individuals = new ArrayList<Individual>(docs.size());
|
||||
Iterator<SolrDocument> 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<VClassGroup> classgroups = getClassGroups(grpDao, docs, maxHitCount);
|
||||
List<VClassGroupSearchLink> classGroupLinks = new ArrayList<VClassGroupSearchLink>(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<VClass> vClasses = getVClasses(vclassDao, docs);
|
||||
List<VClassSearchLink> vClassLinks = new ArrayList<VClassSearchLink>(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<VClassGroup> getClassGroups(VClassGroupDao grpDao, SolrDocumentList docs, int maxHitCount) {
|
||||
LinkedHashMap<String,VClassGroup> grpMap = grpDao.getClassGroupMap();
|
||||
int n = grpMap.size();
|
||||
private List<VClassGroupSearchLink> getClassGroupsLinks(VClassGroupDao grpDao, SolrDocumentList docs, QueryResponse rsp, String qtxt) {
|
||||
Map<String,Long> cgURItoCount = new HashMap<String,Long>();
|
||||
|
||||
HashSet<String> classGroupsInHits = new HashSet<String>(n);
|
||||
int grpsFound = 0;
|
||||
List<VClassGroup> classgroups = new ArrayList<VClassGroup>( );
|
||||
List<FacetField> ffs = rsp.getFacetFields();
|
||||
for(FacetField ff : ffs){
|
||||
if(VitroSearchTermNames.CLASSGROUP_URI.equals(ff.getName())){
|
||||
List<Count> 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<Object> 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<String> classgroupURIs= Collections.list(Collections.enumeration(classGroupsInHits));
|
||||
List<VClassGroup> classgroups = new ArrayList<VClassGroup>( 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<VClassGroupSearchLink> classGroupLinks = new ArrayList<VClassGroupSearchLink>(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<VClass> getVClasses(VClassDao vclassDao, SolrDocumentList docs){
|
||||
private List<VClassSearchLink> getVClassLinks(VClassDao vclassDao, SolrDocumentList docs, QueryResponse rsp, String qtxt){
|
||||
HashSet<String> typesInHits = getVClassUrisForHits(docs);
|
||||
List<VClass> classes = new ArrayList<VClass>(typesInHits.size());
|
||||
Map<String,Long> typeURItoCount = new HashMap<String,Long>();
|
||||
|
||||
Iterator<String> 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<String> 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<FacetField> ffs = rsp.getFacetFields();
|
||||
for(FacetField ff : ffs){
|
||||
if(VitroSearchTermNames.RDFTYPE.equals(ff.getName())){
|
||||
List<Count> 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<VClass>(){
|
||||
public int compare(VClass o1, VClass o2) {
|
||||
return o1.compareTo(o2);
|
||||
}});
|
||||
return classes;
|
||||
|
||||
List<VClassSearchLink> vClassLinks = new ArrayList<VClassSearchLink>(classes.size());
|
||||
for (VClass vc : classes) {
|
||||
long count = typeURItoCount.get(vc.getURI());
|
||||
vClassLinks.add(new VClassSearchLink(qtxt, vc, count ));
|
||||
}
|
||||
|
||||
return vClassLinks;
|
||||
}
|
||||
|
||||
private HashSet<String> 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<PagingLink> 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<PagingLink> getPagingLinks(int startIndex, int hitsPerPage, long hitCount, String baseUrl, ParamMap params) {
|
||||
|
||||
List<PagingLink> pagingLinks = new ArrayList<PagingLink>();
|
||||
|
||||
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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: <http://vitro.mannlib.cornell.edu/ontologies/display/1.1#>\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 )));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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<PagingLink> 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<PagingLink> 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());
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue