diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/VisualizationController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/VisualizationController.java index dcb8a6564..e41dfab02 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/VisualizationController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/VisualizationController.java @@ -108,9 +108,11 @@ public class VisualizationController extends BaseEditController { public static final String PDF_REPORT_VIS_URL_VALUE = "pdf_report"; - public static final String COLLEGE_PUBLICATION_COUNT_VIS_URL_VALUE = "college_pub_count"; + + public static final String COAUTHORSHIP_VIS_URL_VALUE + = "coauthorship"; @Override @@ -180,6 +182,31 @@ public class VisualizationController extends BaseEditController { log.error("ERROR! data model empoty"); } + } else if (COAUTHORSHIP_VIS_URL_VALUE + .equalsIgnoreCase(vreq.getParameter(VIS_TYPE_URL_HANDLE))) { + + edu.cornell.mannlib.vitro.webapp.visualization.coauthorship.VisualizationRequestHandler visRequestHandler = + new edu.cornell.mannlib.vitro.webapp.visualization.coauthorship.VisualizationRequestHandler(vreq, request, response, log); + + String rdfResultFormatParam = "RDF/XML-ABBREV"; + + DataSource dataSource = setupJENADataSource(request, + response, + vreq, + rdfResultFormatParam); + + if (dataSource != null) { + + /* + * This is side-effecting because the visualization content is added + * to the request object. + * */ + visRequestHandler.generateVisualization(dataSource); + + } else { + log.error("ERROR! data model empoty"); + } + } else if (PDF_REPORT_VIS_URL_VALUE .equalsIgnoreCase(vreq.getParameter(VIS_TYPE_URL_HANDLE))) { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/VisualizationFrameworkConstants.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/VisualizationFrameworkConstants.java new file mode 100644 index 000000000..465648c9c --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/VisualizationFrameworkConstants.java @@ -0,0 +1,22 @@ +package edu.cornell.mannlib.vitro.webapp.controller.visualization; + +public class VisualizationFrameworkConstants { + + public static final String VIS_CONTAINER_URL_HANDLE = "container"; + + public static final String INDIVIDUAL_URI_URL_HANDLE = "uri"; + + public static final String VIS_MODE_URL_HANDLE = "vis_mode"; + + public static final String RENDER_MODE_URL_HANDLE = "render_mode"; + + public static final String STANDALONE_RENDER_MODE_URL_VALUE = "standalone"; + + public static final String DYNAMIC_RENDER_MODE_URL_VALUE = "dynamic"; + + public static final String DATA_RENDER_MODE_URL_VALUE = "data"; + + public static final String PDF_RENDER_MODE_URL_VALUE = "pdf"; + + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/TestJava.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/TestJava.java index d4c8ded46..803af7300 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/TestJava.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/TestJava.java @@ -1,10 +1,16 @@ package edu.cornell.mannlib.vitro.webapp.visualization; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import java.util.TreeMap; import com.hp.hpl.jena.iri.IRIFactory; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Node; + public class TestJava { /** @@ -44,8 +50,43 @@ public class TestJava { yearToPublicationCount.put("2001", 5); yearToPublicationCount.put("2002", 5); yearToPublicationCount.put("2090", 7); - yearToPublicationCount.put("2087", 6); + yearToPublicationCount.put("Unknown", 6); + Node egoNode; + + System.out.println(); + + Map> biboDocumentURLToCoAuthors = new HashMap>(); + + Set coAuthorsForCurrentBiboDocument; + + if (biboDocumentURLToCoAuthors.containsKey("a")) { + coAuthorsForCurrentBiboDocument = biboDocumentURLToCoAuthors.get("a"); + } else { + coAuthorsForCurrentBiboDocument = new HashSet(); + biboDocumentURLToCoAuthors.put("a", coAuthorsForCurrentBiboDocument); + } + + coAuthorsForCurrentBiboDocument.add(1); + + int actual_size = 4; +// int n = actual_size - 1; + + for (int ii = 0; ii < actual_size - 1; ii++) { + for (int jj = ii + 1; jj < actual_size; jj++) { + System.out.println(ii + " - " + jj ); + } + } + + System.out.println(biboDocumentURLToCoAuthors); + + + System.out.println( new HashMap(){{ + put("sdsd", 4); + }}); + + System.out.println(yearToPublicationCount.get("44454454")); + System.out.println(Collections.min(yearToPublicationCount.keySet())); String emptyString = ""; System.out.println(emptyString.isEmpty()); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/VisualizationCodeGenerator.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/VisualizationCodeGenerator.java index 90f4e4b2a..5b33d9459 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/VisualizationCodeGenerator.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/VisualizationCodeGenerator.java @@ -14,6 +14,8 @@ import java.util.Map.Entry; import org.apache.commons.logging.Log; import edu.cornell.mannlib.vitro.webapp.controller.visualization.VisualizationController; +import edu.cornell.mannlib.vitro.webapp.controller.visualization.VisualizationFrameworkConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.constants.VOConstants; import edu.cornell.mannlib.vitro.webapp.visualization.personpubcount.VisualizationRequestHandler; import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.BiboDocument; @@ -142,8 +144,8 @@ public class VisualizationCodeGenerator { * Total publications will also consider publications that have no year associated with * it. Hence. * */ - if (yearToPublicationCount.get(BiboDocument.DEFAULT_PUBLICATION_YEAR) != null) { - totalPublications += yearToPublicationCount.get(BiboDocument.DEFAULT_PUBLICATION_YEAR); + if (yearToPublicationCount.get(VOConstants.DEFAULT_PUBLICATION_YEAR) != null) { + totalPublications += yearToPublicationCount.get(VOConstants.DEFAULT_PUBLICATION_YEAR); } String sparklineDisplayOptions = "{width: 63, height: 21, showAxisLines: false, " + @@ -333,7 +335,7 @@ public class VisualizationCodeGenerator { String downloadFileCode; if (yearToPublicationCount.size() > 0) { downloadFileCode = "Download data as .csv file.
"; } else { @@ -374,7 +375,7 @@ public class VisualizationCodeGenerator { String fullTimelineLink; if (yearToPublicationCount.size() > 0) { fullTimelineLink = "View full timeline and network.
"; } else { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/coauthorship/QueryHandler.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/coauthorship/QueryHandler.java new file mode 100644 index 000000000..80ad31027 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/coauthorship/QueryHandler.java @@ -0,0 +1,429 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.coauthorship; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +import org.apache.commons.logging.Log; + +import com.hp.hpl.jena.iri.IRI; +import com.hp.hpl.jena.iri.IRIFactory; +import com.hp.hpl.jena.iri.Violation; +import com.hp.hpl.jena.query.DataSource; +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.query.QuerySolution; +import com.hp.hpl.jena.query.ResultSet; +import com.hp.hpl.jena.query.Syntax; +import com.hp.hpl.jena.rdf.model.RDFNode; + +import edu.cornell.mannlib.vitro.webapp.visualization.constants.QueryConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.constants.QueryFieldLabels; +import edu.cornell.mannlib.vitro.webapp.visualization.exceptions.MalformedQueryParametersException; +import edu.cornell.mannlib.vitro.webapp.visualization.utils.UniqueIDGenerator; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.BiboDocument; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Edge; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Node; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.VivoCollegeOrSchool; + + + +/** + * Very dumb name of the class. change it. + * @author cdtank + * + */ +public class QueryHandler { + + protected static final Syntax SYNTAX = Syntax.syntaxARQ; + + private String egoURLParam, resultFormatParam, rdfResultFormatParam; + private Map collegeURLToVO = new HashMap(); + private DataSource dataSource; + + private Log log; + + private UniqueIDGenerator nodeIDGenerator; + + private UniqueIDGenerator edgeIDGenerator; + + public QueryHandler(String egoURLParam, + String resultFormatParam, String rdfResultFormatParam, + DataSource dataSource, Log log) { + + this.egoURLParam = egoURLParam; + this.resultFormatParam = resultFormatParam; + this.rdfResultFormatParam = rdfResultFormatParam; + this.dataSource = dataSource; + this.log = log; + + this.nodeIDGenerator = new UniqueIDGenerator(); + this.edgeIDGenerator = new UniqueIDGenerator(); + + } + + private VisVOContainer createJavaValueObjects(ResultSet resultSet) { + + Set nodes = new HashSet(); + + Map biboDocumentURLToVO = new HashMap(); + Map> biboDocumentURLToCoAuthors = new HashMap>(); + Map nodeURLToVO = new HashMap(); + + Node egoNode = null; + + Set edges = new HashSet(); + + while (resultSet.hasNext()) { + QuerySolution solution = resultSet.nextSolution(); + + + /* + * We only want to create only ONE ego node. + * */ + RDFNode egoAuthorURLNode = solution.get(QueryFieldLabels.AUTHOR_URL); + if (nodeURLToVO.containsKey(egoAuthorURLNode.toString())) { + + egoNode = nodeURLToVO.get(egoAuthorURLNode.toString()); + + } else { + + egoNode = new Node(egoAuthorURLNode.toString(), nodeIDGenerator); + nodes.add(egoNode); + nodeURLToVO.put(egoAuthorURLNode.toString(), egoNode); + + RDFNode authorLabelNode = solution.get(QueryFieldLabels.AUTHOR_LABEL); + if (authorLabelNode != null) { + egoNode.setNodeName(authorLabelNode.toString()); + } + } + + RDFNode documentNode = solution.get(QueryFieldLabels.DOCUMENT_URL); + BiboDocument biboDocument; + + if (biboDocumentURLToVO.containsKey(documentNode.toString())) { + biboDocument = biboDocumentURLToVO.get(documentNode.toString()); + } else { + biboDocument = createDocumentVO(solution, documentNode.toString()); + biboDocumentURLToVO.put(documentNode.toString(), biboDocument); + } + + egoNode.addAuthorDocument(biboDocument); + + Node coAuthorNode; + + RDFNode coAuthorURLNode = solution.get(QueryFieldLabels.CO_AUTHOR_URL); + if (nodeURLToVO.containsKey(coAuthorURLNode.toString())) { + + coAuthorNode = nodeURLToVO.get(coAuthorURLNode.toString()); + + } else { + + coAuthorNode = new Node(coAuthorURLNode.toString(), nodeIDGenerator); + nodes.add(coAuthorNode); + nodeURLToVO.put(coAuthorURLNode.toString(), coAuthorNode); + + RDFNode coAuthorLabelNode = solution.get(QueryFieldLabels.CO_AUTHOR_LABEL); + if (coAuthorLabelNode != null) { + coAuthorNode.setNodeName(coAuthorLabelNode.toString()); + } + } + + coAuthorNode.addAuthorDocument(biboDocument); + + Set coAuthorsForCurrentBiboDocument; + + if (biboDocumentURLToCoAuthors.containsKey(biboDocument.getDocumentURL())) { + coAuthorsForCurrentBiboDocument = biboDocumentURLToCoAuthors.get(biboDocument.getDocumentURL()); + } else { + coAuthorsForCurrentBiboDocument = new HashSet(); + biboDocumentURLToCoAuthors.put(biboDocument.getDocumentURL(), coAuthorsForCurrentBiboDocument); + } + + coAuthorsForCurrentBiboDocument.add(coAuthorNode); + + Edge egoCoAuthorEdge = getExistingEdge(egoNode, coAuthorNode, edges); + + /* + * If "egoCoAuthorEdge" is null it means that no edge exists in between the egoNode & current + * coAuthorNode. Else create a new edge, add it to the edges set & add the collaborator document + * to it. + * */ + if (egoCoAuthorEdge != null) { + egoCoAuthorEdge.addCollaboratorDocument(biboDocument); + } else { + egoCoAuthorEdge = new Edge(egoNode, coAuthorNode, biboDocument, edgeIDGenerator); + edges.add(egoCoAuthorEdge); + } + } + + /* + * We need to create edges between 2 co-authors. E.g. On a paper there were 3 authors + * ego, A & B then we have already created edges like, + * ego - A + * ego - B + * The below sub-routine will take care of, + * A - B + * + * We are side-effecting "edges" here. The only reason to do this is because we are adding + * edges en masse for all the co-authors on all the publications considered so far. The other + * reason being we dont want to compare against 2 sets of edges (edges created before & co- + * author edges created during the course of this method) when we are creating a new edge. + * */ + createCoAuthorEdges(biboDocumentURLToVO, + biboDocumentURLToCoAuthors, + edges); + + +/* System.out.println(collegeURLToVO); + System.out.println("------------------------------------------------------------"); + System.out.println(departmentURLToVO); + System.out.println("------------------------------------------------------------"); + System.out.println(employeeURLToVO); + System.out.println("------------------------------------------------------------"); +*/ + return new VisVOContainer(egoNode, nodes, edges); + } + + private void createCoAuthorEdges( + Map biboDocumentURLToVO, + Map> biboDocumentURLToCoAuthors, Set edges) { + for (Map.Entry> currentBiboDocumentEntry : biboDocumentURLToCoAuthors.entrySet()) { + /* + * If there was only one co-author (other than ego) then we dont have to create any edges. so + * the below condition will take care of that. + * */ + if (currentBiboDocumentEntry.getValue().size() > 1) { + + /* + * In order to leverage the nested "for loop" for making edges between all the co=authors + * we need to create a list out of the set first. + * */ + List coAuthorNodes = new ArrayList(currentBiboDocumentEntry.getValue()); + + int numOfCoAuthors = coAuthorNodes.size(); + + for (int ii = 0; ii < numOfCoAuthors - 1; ii++) { + for (int jj = ii + 1; jj < numOfCoAuthors; jj++) { + + Node coAuthor1 = coAuthorNodes.get(ii); + Node coAuthor2 = coAuthorNodes.get(jj); + + Edge coAuthor1_2Edge = getExistingEdge(coAuthor1, coAuthor2, edges); + + BiboDocument currentBiboDocument = biboDocumentURLToVO + .get(currentBiboDocumentEntry.getKey()); + + if (coAuthor1_2Edge != null) { + coAuthor1_2Edge.addCollaboratorDocument(currentBiboDocument); + } else { + coAuthor1_2Edge = new Edge(coAuthor1, coAuthor2, currentBiboDocument, edgeIDGenerator); + edges.add(coAuthor1_2Edge); + } + } + } + + } + + } + } + + private Edge getExistingEdge( + Node collaboratingNode1, + Node collaboratingNode2, + Set edges) { + + Edge duplicateEdge = null; + + for (Edge currentEdge : edges) { + + /* + * We first check if either the source or target node of the current edge is + * the collaboratingNode1. If yes then we go on to check if the collaboratingNode2 + * matches either the source or the target node. We dont care about the directionality + * of the edge. + * */ + if (currentEdge.getSourceNode().getNodeID() == collaboratingNode1.getNodeID() + || currentEdge.getTargetNode().getNodeID() == collaboratingNode1.getNodeID()) { + + if (currentEdge.getSourceNode().getNodeID() == collaboratingNode2.getNodeID() + || currentEdge.getTargetNode().getNodeID() == collaboratingNode2.getNodeID()) { + + duplicateEdge = currentEdge; + break; + } + } + } + + return duplicateEdge; + } + + public Map getCollegeURLToVO() { + return collegeURLToVO; + } + + private BiboDocument createDocumentVO(QuerySolution solution, String documentURL) { + + BiboDocument biboDocument = new BiboDocument(documentURL); + + RDFNode documentLabelNode = solution.get(QueryFieldLabels.DOCUMENT_LABEL); + if (documentLabelNode != null) { + biboDocument.setDocumentLabel(documentLabelNode.toString()); + } + + RDFNode documentBlurbNode = solution.get(QueryFieldLabels.DOCUMENT_BLURB); + if (documentBlurbNode != null) { + biboDocument.setDocumentBlurb(documentBlurbNode.toString()); + } + + RDFNode documentMonikerNode = solution.get(QueryFieldLabels.DOCUMENT_MONIKER); + if (documentMonikerNode != null) { + biboDocument.setDocumentMoniker(documentMonikerNode.toString()); + } + + RDFNode publicationYearNode = solution.get(QueryFieldLabels.DOCUMENT_PUBLICATION_YEAR); + if (publicationYearNode != null) { + biboDocument.setPublicationYear(publicationYearNode.toString()); + } + + return biboDocument; + } + + private ResultSet executeQuery(String queryText, + String resultFormatParam, + String rdfResultFormatParam, + DataSource dataSource) { + + QueryExecution queryExecution = null; + try{ + Query query = QueryFactory.create(queryText, SYNTAX); + +// QuerySolutionMap qs = new QuerySolutionMap(); +// qs.add("authPerson", queryParam); // bind resource to s + + queryExecution = QueryExecutionFactory.create(query, dataSource); + + + //remocve this if loop after knowing what is describe & construct sparql stuff. + if (query.isSelectType()){ + return queryExecution.execSelect(); + } + } finally { + if(queryExecution != null) { + queryExecution.close(); + } + + } + return null; + } + + private String generateEgoCoAuthorshipSparqlQuery(String queryURI) { +// Resource uri1 = ResourceFactory.createResource(queryURI); + + String sparqlQuery = QueryConstants.SPARQL_QUERY_PREFIXES + + "SELECT " + + " (str(<" + queryURI + ">) as ?" + QueryFieldLabels.AUTHOR_URL + ") " + + " (str(?authorLabel) as ?" + QueryFieldLabels.AUTHOR_LABEL + ") " + + " (str(?coAuthorPerson) as ?" + QueryFieldLabels.CO_AUTHOR_URL + ") " + + " (str(?coAuthorLabel) as ?" + QueryFieldLabels.CO_AUTHOR_LABEL + ") " + + " (str(?document) as ?" + QueryFieldLabels.DOCUMENT_URL + ") " + + " (str(?documentLabel) as ?" + QueryFieldLabels.DOCUMENT_LABEL + ") " + + " (str(?documentMoniker) as ?" + QueryFieldLabels.DOCUMENT_MONIKER + ") " + + " (str(?documentBlurb) as ?" + QueryFieldLabels.DOCUMENT_BLURB + ") " + + " (str(?publicationYear) as ?" + QueryFieldLabels.DOCUMENT_PUBLICATION_YEAR + ") " + + "WHERE { " + + "<" + queryURI + "> rdf:type foaf:Person ; vivo:authorOf ?document ; rdfs:label ?authorLabel. " + + "?document rdf:type bibo:Document . " + + "?document rdfs:label ?documentLabel . " + + "?document vivo:hasAuthor ?coAuthorPerson . " + + "?coAuthorPerson rdfs:label ?coAuthorPersonLabel . " + + "OPTIONAL { ?document vivo:publicationYear ?publicationYear } . " + + "OPTIONAL { ?document vitro:moniker ?documentMoniker } . " + + "OPTIONAL { ?document vitro:blurb ?documentBlurb } . " + + "OPTIONAL { ?document vitro:description ?documentDescription } " + + "FILTER (<" + queryURI + "> != ?coAuthorPerson ) . " + + "}"; + + System.out.println(sparqlQuery); + + return sparqlQuery; + } + + + public VisVOContainer getVisualizationJavaValueObjects() + throws MalformedQueryParametersException { + + if (this.egoURLParam == null || "".equals(egoURLParam)) { + throw new MalformedQueryParametersException("URI parameter is either null or empty."); + } else { + + /* + * To test for the validity of the URI submitted. + * */ + IRIFactory iRIFactory = IRIFactory.jenaImplementation(); + IRI iri = iRIFactory.create(this.egoURLParam); + if (iri.hasViolation(false)) { + String errorMsg = ((Violation)iri.violations(false).next()).getShortMessage()+" "; + log.error("Ego Co Authorship Vis Query " + errorMsg); + throw new MalformedQueryParametersException("URI provided for an individual is malformed."); + } + } + + ResultSet resultSet = executeQuery(generateEgoCoAuthorshipSparqlQuery(this.egoURLParam), + this.resultFormatParam, + this.rdfResultFormatParam, + this.dataSource); + + return createJavaValueObjects(resultSet); + } + + public Map getYearToPublicationCount( + Set authorDocuments) { + + /* + * Create a map from the year to number of publications. Use the BiboDocument's + * parsedPublicationYear to populate the data. + * */ + Map yearToPublicationCount = new TreeMap(); + + for (BiboDocument curr : authorDocuments) { + + /* + * Increment the count because there is an entry already available for + * that particular year. + * */ + String publicationYear; + if (curr.getPublicationYear() != null + && curr.getPublicationYear().length() != 0 + && curr.getPublicationYear().trim().length() != 0) { + publicationYear = curr.getPublicationYear(); + } else { + publicationYear = curr.getParsedPublicationYear(); + } + + if (yearToPublicationCount.containsKey(publicationYear)) { + yearToPublicationCount.put(publicationYear, + yearToPublicationCount + .get(publicationYear) + 1); + + } else { + yearToPublicationCount.put(publicationYear, 1); + } + + } + +// System.out.println("****************************\n" + yearToPublicationCount); + return yearToPublicationCount; + } + + + + + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/coauthorship/VisVOContainer.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/coauthorship/VisVOContainer.java new file mode 100644 index 000000000..b86060bb9 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/coauthorship/VisVOContainer.java @@ -0,0 +1,32 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.coauthorship; + +import java.util.Set; + +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Edge; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Node; + +public class VisVOContainer { + + private Set nodes; + private Set edges; + private Node egoNode; + + public VisVOContainer(Node egoNode, Set nodes, Set edges) { + this.egoNode = egoNode; + this.nodes = nodes; + this.edges = edges; + } + + public Set getNodes() { + return nodes; + } + + public Set getEdges() { + return edges; + } + + public Node getEgoNode() { + return egoNode; + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/coauthorship/VisualizationRequestHandler.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/coauthorship/VisualizationRequestHandler.java new file mode 100644 index 000000000..f63c08e37 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/coauthorship/VisualizationRequestHandler.java @@ -0,0 +1,433 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.coauthorship; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.Map.Entry; + +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.logging.Log; +import org.skife.csv.CSVWriter; +import org.skife.csv.SimpleWriter; + +import com.hp.hpl.jena.query.DataSource; +import com.itextpdf.text.Document; +import com.itextpdf.text.DocumentException; +import com.itextpdf.text.pdf.PdfWriter; + +import edu.cornell.mannlib.vitro.webapp.beans.Portal; +import edu.cornell.mannlib.vitro.webapp.controller.Controllers; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.controller.visualization.VisualizationFrameworkConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.PDFDocument; +import edu.cornell.mannlib.vitro.webapp.visualization.constants.VOConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.constants.VisConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.exceptions.MalformedQueryParametersException; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.BiboDocument; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Edge; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Individual; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Node; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.VivoCollegeOrSchool; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.VivoDepartmentOrDivision; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.VivoEmployee; + +public class VisualizationRequestHandler { + + private VitroRequest vitroRequest; + private HttpServletRequest request; + private HttpServletResponse response; + private Log log; + + public VisualizationRequestHandler(VitroRequest vitroRequest, + HttpServletRequest request, HttpServletResponse response, Log log) { + + this.vitroRequest = vitroRequest; + this.request = request; + this.response = response; + this.log = log; + + } + + public void generateVisualization(DataSource dataSource) { + + String resultFormatParam = "RS_TEXT"; + String rdfResultFormatParam = "RDF/XML-ABBREV"; + + String egoURIParam = vitroRequest.getParameter(VisualizationFrameworkConstants.INDIVIDUAL_URI_URL_HANDLE); + + String renderMode = vitroRequest.getParameter(VisualizationFrameworkConstants.RENDER_MODE_URL_HANDLE); + + String visMode = vitroRequest.getParameter(VisualizationFrameworkConstants.VIS_MODE_URL_HANDLE); + + String visContainer = vitroRequest.getParameter(VisualizationFrameworkConstants.VIS_CONTAINER_URL_HANDLE); + + QueryHandler queryManager = + new QueryHandler(egoURIParam, + resultFormatParam, + rdfResultFormatParam, + dataSource, + + log); + + try { + + VisVOContainer authorNodesAndEdges = queryManager.getVisualizationJavaValueObjects(); + + /* + * In order to avoid unneeded computations we have pushed this "if" condition up. + * This case arises when the render mode is data. In that case we dont want to generate + * HTML code to render sparkline, tables etc. Ideally I would want to avoid this flow. + * It is ugly! + * */ + if (VisualizationFrameworkConstants.DATA_RENDER_MODE_URL_VALUE.equalsIgnoreCase(renderMode)) { + prepareVisualizationQueryDataResponse(authorNodesAndEdges); + + return; + } + + + + /* + if (PDF_RENDER_MODE_URL_VALUE.equalsIgnoreCase(renderMode)) { + prepareVisualizationQueryPDFResponse(authorDocuments, + yearToPublicationCount); + return; + } + */ + + /* + * Computations required to generate HTML for the sparklines & related context. + * */ + + /* + * This is required because when deciding the range of years over which the vis + * was rendered we dont want to be influenced by the "DEFAULT_PUBLICATION_YEAR". + * */ +// publishedYearsForCollege.remove(VOConstants.DEFAULT_PUBLICATION_YEAR); + + /* + VisualizationCodeGenerator visualizationCodeGenerator = + new VisualizationCodeGenerator(yearToPublicationCount, log); + + String visContentCode = visualizationCodeGenerator + .getMainVisualizationCode(authorDocuments, + publishedYears, + visMode, + visContainer); + + String visContextCode = visualizationCodeGenerator + .getVisualizationContextCode(vitroRequest.getRequestURI(), + collegeURIParam, + visMode); + */ + + /* + * This is side-effecting because the response of this method is just to redirect to + * a page with visualization on it. + * */ + + /* + RequestDispatcher requestDispatcher = null; + + if (DYNAMIC_RENDER_MODE_URL_VALUE.equalsIgnoreCase(renderMode)) { + + prepareVisualizationQueryDynamicResponse(request, response, vitroRequest, + visContentCode, visContextCode); + requestDispatcher = request.getRequestDispatcher("/templates/page/blankPage.jsp"); + + } else { + prepareVisualizationQueryStandaloneResponse(request, response, vitroRequest, + visContentCode, visContextCode); + + requestDispatcher = request.getRequestDispatcher(Controllers.BASIC_JSP); + } + + try { + requestDispatcher.forward(request, response); + } catch (Exception e) { + log.error("EntityEditController could not forward to view."); + log.error(e.getMessage()); + log.error(e.getStackTrace()); + } + +*/ + } catch (MalformedQueryParametersException e) { + try { + handleMalformedParameters(e.getMessage()); + } catch (ServletException e1) { + log.error(e1.getStackTrace()); + } catch (IOException e1) { + log.error(e1.getStackTrace()); + } + return; + } + + } + + private Map getUpdatedDepartmentPublicationsOverTime( + Map currentEmployeeYearToPublicationCount, + Map currentDepartmentYearToPublicationCount) { + + Map departmentYearToPublicationCount; + +// System.out.println("inside get updated dept pub obr time"); + + /* + * In case this is the first time we are consolidating publication counts over time for a department. + * */ + if (currentDepartmentYearToPublicationCount == null) { + departmentYearToPublicationCount = new TreeMap(); + +// System.out.println("new dept yr pub cnt"); + + } else { + departmentYearToPublicationCount = currentDepartmentYearToPublicationCount; + } + + + Iterator employeePubCountIterator = currentEmployeeYearToPublicationCount.entrySet().iterator(); + + while (employeePubCountIterator.hasNext()) { + Map.Entry employeePubCountEntry = (Map.Entry) employeePubCountIterator.next(); + + String employeePublicationYear = employeePubCountEntry.getKey(); + Integer employeePublicationCount = employeePubCountEntry.getValue(); + + try { + if (departmentYearToPublicationCount.containsKey(employeePublicationYear)) { + departmentYearToPublicationCount.put(employeePublicationYear, + departmentYearToPublicationCount + .get(employeePublicationYear) + + employeePublicationCount); + + } else { + departmentYearToPublicationCount.put(employeePublicationYear, employeePublicationCount); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + return departmentYearToPublicationCount; + } + + private void prepareVisualizationQueryPDFResponse(Individual college, + List authorDocuments, + Map yearToPublicationCount) { + + String authorName = null; + + /* + * To protect against cases where there are no author documents associated with the + * individual. + * */ + if (authorDocuments.size() > 0) { + authorName = college.getIndividualLabel(); + } + + /* + * To make sure that null/empty records for author names do not cause any mischief. + * */ + if (authorName == null) { + authorName = ""; + } + + String outputFileName = slugify(authorName + "-report") + + ".pdf"; + + response.setContentType("application/pdf"); + response.setHeader("Content-Disposition","attachment;filename=" + outputFileName); + + ServletOutputStream responseOutputStream; + try { + responseOutputStream = response.getOutputStream(); + + + Document document = new Document(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PdfWriter pdfWriter = PdfWriter.getInstance(document, baos); + document.open(); + + PDFDocument pdfDocument = new PDFDocument(authorName, + yearToPublicationCount, + document, + pdfWriter); + document.close(); + + response.setHeader("Expires", "0"); + response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0"); + response.setHeader("Pragma", "public"); + response.setContentLength(baos.size()); + + baos.writeTo(responseOutputStream); + responseOutputStream.flush(); + responseOutputStream.close(); + + } catch (IOException e) { + e.printStackTrace(); + } catch (DocumentException e) { + e.printStackTrace(); + } + } + + private void prepareVisualizationQueryDataResponse(VisVOContainer authorNodesAndEdges) { + + String egoName = null; + + Node egoNode = authorNodesAndEdges.getEgoNode(); + + + /* + * To protect against cases where there are no author documents associated with the + * individual. + * */ +// System.out.println(collegeURLToVO); + if (egoNode != null) { + egoName = egoNode.getNodeName(); + } + + /* + * To make sure that null/empty records for author names do not cause any mischief. + * */ + if (egoName == null) { + egoName = ""; + } + + String outputFileName = slugify(egoName) + "co-authorship" + ".txt"; + + response.setContentType("application/octet-stream"); + response.setHeader("Content-Disposition","attachment;filename=" + outputFileName); + + try { + + PrintWriter responseWriter = response.getWriter(); + + /* + * We are side-effecting responseWriter since we are directly manipulating the response + * object of the servlet. + * */ + generateCsvFileBuffer(authorNodesAndEdges, + responseWriter); + + responseWriter.close(); + + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * Currently the approach for slugifying filenames is naive. In future if there is need, + * we can write more sophisticated method. + * @param textToBeSlugified + * @return + */ + private String slugify(String textToBeSlugified) { + return textToBeSlugified.toLowerCase().replaceAll("[^a-zA-Z0-9-]", "-") + .substring(0, VisConstants.MAX_NAME_TEXT_LENGTH); + } + + private void generateCsvFileBuffer(VisVOContainer authorNodesAndEdges, + PrintWriter printWriter) { + + Node egoNode = authorNodesAndEdges.getEgoNode(); + Set authorNodes = authorNodesAndEdges.getNodes(); + Set edges = authorNodesAndEdges.getEdges(); + + printWriter.append("\nEGO => "); + printWriter.append(egoNode.getNodeID() + " - " + egoNode.getNodeName() + " -> " + egoNode.getNodeURL() + "\n"); + printWriter.append("\tEarliest Publication - " + egoNode.getEarliestPublicationYearCount() + + "\n\tLatest Publication - " + egoNode.getLatestPublicationYearCount() + + "\n\tUnknown Publication - " + egoNode.getUnknownPublicationYearCount()); + + authorNodes.remove(egoNode); + + for (Node currNode : authorNodes) { + + printWriter.append("\nCO-AUTHOR => "); + printWriter.append(currNode.getNodeID() + " - " + currNode.getNodeName() + " -> " + currNode.getNodeURL() + "\n"); + printWriter.append("\tEarliest Publication - " + currNode.getEarliestPublicationYearCount() + + "\n\tLatest Publication - " + currNode.getLatestPublicationYearCount() + + "\n\tUnknown Publication - " + currNode.getUnknownPublicationYearCount()); + + } + + for (Edge currentEdge : edges) { + + printWriter.append("\nEdge => "); + printWriter.append(currentEdge.getEdgeID() + " => " + currentEdge.getSourceNode().getNodeName() + " - " + + currentEdge.getTargetNode().getNodeName() + "\n"); + printWriter.append("\tEarliest Collaboration - " + currentEdge.getEarliestCollaborationYearCount() + + "\n\tLatest Collaboration - " + currentEdge.getLatestCollaborationYearCount() + + "\n\tUnknown Collaboration - " + currentEdge.getUnknownCollaborationYearCount()); + + } + + printWriter.flush(); + + } + + private void prepareVisualizationQueryStandaloneResponse(HttpServletRequest request, + HttpServletResponse response, VitroRequest vreq, + String visContentCode, String visContextCode) { + + Portal portal = vreq.getPortal(); + + request.setAttribute("visContentCode", visContentCode); + request.setAttribute("visContextCode", visContextCode); + + request.setAttribute("bodyJsp", "/templates/visualization/publication_count.jsp"); + request.setAttribute("portalBean", portal); + request.setAttribute("title", "Individual Publication Count Visualization"); + request.setAttribute("scripts", "/templates/visualization/visualization_scripts.jsp"); + + } + + private void prepareVisualizationQueryDynamicResponse(HttpServletRequest request, + HttpServletResponse response, VitroRequest vreq, + String visContentCode, String visContextCode) { + + Portal portal = vreq.getPortal(); + + request.setAttribute("visContentCode", visContentCode); + request.setAttribute("visContextCode", visContextCode); + + request.setAttribute("portalBean", portal); + request.setAttribute("bodyJsp", "/templates/visualization/ajax_vis_content.jsp"); + + } + + private void handleMalformedParameters(String errorMessage) + throws ServletException, IOException { + + Portal portal = vitroRequest.getPortal(); + + request.setAttribute("error", errorMessage); + + RequestDispatcher requestDispatcher = request.getRequestDispatcher(Controllers.BASIC_JSP); + request.setAttribute("bodyJsp", "/templates/visualization/visualization_error.jsp"); + request.setAttribute("portalBean", portal); + request.setAttribute("title", "Visualization Query Error - Individual Publication Count"); + + try { + requestDispatcher.forward(request, response); + } catch (Exception e) { + log.error("EntityEditController could not forward to view."); + log.error(e.getMessage()); + log.error(e.getStackTrace()); + } + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/collegepubcount/QueryHandler.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/collegepubcount/QueryHandler.java index 3712a3c0e..346f21dff 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/collegepubcount/QueryHandler.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/collegepubcount/QueryHandler.java @@ -21,14 +21,14 @@ import com.hp.hpl.jena.query.ResultSet; import com.hp.hpl.jena.query.Syntax; import com.hp.hpl.jena.rdf.model.RDFNode; +import edu.cornell.mannlib.vitro.webapp.visualization.constants.QueryConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.constants.QueryFieldLabels; +import edu.cornell.mannlib.vitro.webapp.visualization.constants.VOConstants.EmployeeType; import edu.cornell.mannlib.vitro.webapp.visualization.exceptions.MalformedQueryParametersException; -import edu.cornell.mannlib.vitro.webapp.visualization.sparqlutils.QueryConstants; -import edu.cornell.mannlib.vitro.webapp.visualization.sparqlutils.QueryFieldLabels; import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.BiboDocument; import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.VivoCollegeOrSchool; import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.VivoDepartmentOrDivision; import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.VivoEmployee; -import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.VOConstants.EmployeeType; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/collegepubcount/VisualizationRequestHandler.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/collegepubcount/VisualizationRequestHandler.java index 1d361212c..c15023aac 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/collegepubcount/VisualizationRequestHandler.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/collegepubcount/VisualizationRequestHandler.java @@ -30,7 +30,10 @@ import com.itextpdf.text.pdf.PdfWriter; import edu.cornell.mannlib.vitro.webapp.beans.Portal; import edu.cornell.mannlib.vitro.webapp.controller.Controllers; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.controller.visualization.VisualizationFrameworkConstants; import edu.cornell.mannlib.vitro.webapp.visualization.PDFDocument; +import edu.cornell.mannlib.vitro.webapp.visualization.constants.VOConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.constants.VisConstants; import edu.cornell.mannlib.vitro.webapp.visualization.exceptions.MalformedQueryParametersException; import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.BiboDocument; import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Individual; @@ -40,24 +43,6 @@ import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.VivoEmployee; public class VisualizationRequestHandler { - private static final int MAX_NAME_TEXT_LENGTH = 10; - - public static final String VIS_CONTAINER_URL_HANDLE = "container"; - - public static final String COLLEGE_URI_URL_HANDLE = "uri"; - - public static final String VIS_MODE_URL_HANDLE = "vis_mode"; - - public static final String RENDER_MODE_URL_HANDLE = "render_mode"; - - public static final String STANDALONE_RENDER_MODE_URL_VALUE = "standalone"; - - public static final String DYNAMIC_RENDER_MODE_URL_VALUE = "dynamic"; - - public static final String DATA_RENDER_MODE_URL_VALUE = "data"; - - public static final String PDF_RENDER_MODE_URL_VALUE = "pdf"; - private VitroRequest vitroRequest; private HttpServletRequest request; private HttpServletResponse response; @@ -80,13 +65,13 @@ public class VisualizationRequestHandler { String resultFormatParam = "RS_TEXT"; String rdfResultFormatParam = "RDF/XML-ABBREV"; - String collegeURIParam = vitroRequest.getParameter(COLLEGE_URI_URL_HANDLE); + String collegeURIParam = vitroRequest.getParameter(VisualizationFrameworkConstants.INDIVIDUAL_URI_URL_HANDLE); - String renderMode = vitroRequest.getParameter(RENDER_MODE_URL_HANDLE); + String renderMode = vitroRequest.getParameter(VisualizationFrameworkConstants.RENDER_MODE_URL_HANDLE); - String visMode = vitroRequest.getParameter(VIS_MODE_URL_HANDLE); + String visMode = vitroRequest.getParameter(VisualizationFrameworkConstants.VIS_MODE_URL_HANDLE); - String visContainer = vitroRequest.getParameter(VIS_CONTAINER_URL_HANDLE); + String visContainer = vitroRequest.getParameter(VisualizationFrameworkConstants.VIS_CONTAINER_URL_HANDLE); QueryHandler queryManager = new QueryHandler(collegeURIParam, @@ -134,7 +119,7 @@ public class VisualizationRequestHandler { * HTML code to render sparkline, tables etc. Ideally I would want to avoid this flow. * It is ugly! * */ - if (DATA_RENDER_MODE_URL_VALUE.equalsIgnoreCase(renderMode)) { + if (VisualizationFrameworkConstants.DATA_RENDER_MODE_URL_VALUE.equalsIgnoreCase(renderMode)) { prepareVisualizationQueryDataResponse( departmentToPublicationsOverTime, queryManager.getCollegeURLToVO()); @@ -161,7 +146,7 @@ public class VisualizationRequestHandler { * This is required because when deciding the range of years over which the vis * was rendered we dont want to be influenced by the "DEFAULT_PUBLICATION_YEAR". * */ - publishedYearsForCollege.remove(BiboDocument.DEFAULT_PUBLICATION_YEAR); + publishedYearsForCollege.remove(VOConstants.DEFAULT_PUBLICATION_YEAR); /* VisualizationCodeGenerator visualizationCodeGenerator = @@ -381,7 +366,8 @@ public class VisualizationRequestHandler { * @return */ private String slugify(String textToBeSlugified) { - return textToBeSlugified.toLowerCase().replaceAll("[^a-zA-Z0-9-]", "-").substring(0, MAX_NAME_TEXT_LENGTH); + return textToBeSlugified.toLowerCase().replaceAll("[^a-zA-Z0-9-]", "-") + .substring(0, VisConstants.MAX_NAME_TEXT_LENGTH); } private void generateCsvFileBuffer( diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/sparqlutils/QueryConstants.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/constants/QueryConstants.java similarity index 87% rename from webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/sparqlutils/QueryConstants.java rename to webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/constants/QueryConstants.java index c046cc054..d01ffd0a5 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/sparqlutils/QueryConstants.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/constants/QueryConstants.java @@ -1,4 +1,4 @@ -package edu.cornell.mannlib.vitro.webapp.visualization.sparqlutils; +package edu.cornell.mannlib.vitro.webapp.visualization.constants; public class QueryConstants { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/sparqlutils/QueryFieldLabels.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/constants/QueryFieldLabels.java similarity index 81% rename from webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/sparqlutils/QueryFieldLabels.java rename to webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/constants/QueryFieldLabels.java index 83d964037..80107578e 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/sparqlutils/QueryFieldLabels.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/constants/QueryFieldLabels.java @@ -1,4 +1,4 @@ -package edu.cornell.mannlib.vitro.webapp.visualization.sparqlutils; +package edu.cornell.mannlib.vitro.webapp.visualization.constants; public class QueryFieldLabels { @@ -19,6 +19,12 @@ public class QueryFieldLabels { public static final String AUTHOR_URL = "authPersonLit"; public static final String AUTHOR_LABEL = "authorLabelLit"; + /* + * Co-Author related field labels + * */ + public static final String CO_AUTHOR_URL = "coAuthPersonLit"; + public static final String CO_AUTHOR_LABEL = "coAuthorLabelLit"; + /* * College related field labels * */ diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/VOConstants.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/constants/VOConstants.java similarity index 52% rename from webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/VOConstants.java rename to webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/constants/VOConstants.java index f1b24a7e1..5652c3ce0 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/VOConstants.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/constants/VOConstants.java @@ -1,7 +1,9 @@ -package edu.cornell.mannlib.vitro.webapp.visualization.valueobjects; +package edu.cornell.mannlib.vitro.webapp.visualization.constants; public class VOConstants { + public static final String DEFAULT_PUBLICATION_YEAR = "Unknown"; + /* * Employee related constants * */ @@ -9,4 +11,6 @@ public class VOConstants { ACADEMIC_FACULTY_EMPLOYEE, ACADEMIC_STAFF_EMPLOYEE } + + } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/constants/VisConstants.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/constants/VisConstants.java new file mode 100644 index 000000000..6d36b1e9b --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/constants/VisConstants.java @@ -0,0 +1,8 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.constants; + +public class VisConstants { + + public static final int MAX_NAME_TEXT_LENGTH = 10; + + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/personpubcount/QueryHandler.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/personpubcount/QueryHandler.java index afc267be2..6782f11ce 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/personpubcount/QueryHandler.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/personpubcount/QueryHandler.java @@ -20,9 +20,9 @@ import com.hp.hpl.jena.query.ResultSet; import com.hp.hpl.jena.query.Syntax; import com.hp.hpl.jena.rdf.model.RDFNode; +import edu.cornell.mannlib.vitro.webapp.visualization.constants.QueryConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.constants.QueryFieldLabels; import edu.cornell.mannlib.vitro.webapp.visualization.exceptions.MalformedQueryParametersException; -import edu.cornell.mannlib.vitro.webapp.visualization.sparqlutils.QueryConstants; -import edu.cornell.mannlib.vitro.webapp.visualization.sparqlutils.QueryFieldLabels; import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.BiboDocument; import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Individual; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/personpubcount/VisualizationRequestHandler.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/personpubcount/VisualizationRequestHandler.java index 8d8d35e15..cf1d2e1d1 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/personpubcount/VisualizationRequestHandler.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/personpubcount/VisualizationRequestHandler.java @@ -27,32 +27,17 @@ import com.itextpdf.text.pdf.PdfWriter; import edu.cornell.mannlib.vitro.webapp.beans.Portal; import edu.cornell.mannlib.vitro.webapp.controller.Controllers; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.controller.visualization.VisualizationFrameworkConstants; import edu.cornell.mannlib.vitro.webapp.visualization.PDFDocument; import edu.cornell.mannlib.vitro.webapp.visualization.VisualizationCodeGenerator; +import edu.cornell.mannlib.vitro.webapp.visualization.constants.VOConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.constants.VisConstants; import edu.cornell.mannlib.vitro.webapp.visualization.exceptions.MalformedQueryParametersException; import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.BiboDocument; import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Individual; public class VisualizationRequestHandler { - private static final int MAX_NAME_TEXT_LENGTH = 10; - - public static final String VIS_CONTAINER_URL_HANDLE = "container"; - - public static final String INDIVIDUAL_URI_URL_HANDLE = "uri"; - - public static final String VIS_MODE_URL_HANDLE = "vis_mode"; - - public static final String RENDER_MODE_URL_HANDLE = "render_mode"; - - public static final String STANDALONE_RENDER_MODE_URL_VALUE = "standalone"; - - public static final String DYNAMIC_RENDER_MODE_URL_VALUE = "dynamic"; - - public static final String DATA_RENDER_MODE_URL_VALUE = "data"; - - public static final String PDF_RENDER_MODE_URL_VALUE = "pdf"; - private VitroRequest vitroRequest; private HttpServletRequest request; private HttpServletResponse response; @@ -75,13 +60,13 @@ public class VisualizationRequestHandler { String resultFormatParam = "RS_TEXT"; String rdfResultFormatParam = "RDF/XML-ABBREV"; - String individualURIParam = vitroRequest.getParameter(INDIVIDUAL_URI_URL_HANDLE); + String individualURIParam = vitroRequest.getParameter(VisualizationFrameworkConstants.INDIVIDUAL_URI_URL_HANDLE); - String renderMode = vitroRequest.getParameter(RENDER_MODE_URL_HANDLE); + String renderMode = vitroRequest.getParameter(VisualizationFrameworkConstants.RENDER_MODE_URL_HANDLE); - String visMode = vitroRequest.getParameter(VIS_MODE_URL_HANDLE); + String visMode = vitroRequest.getParameter(VisualizationFrameworkConstants.VIS_MODE_URL_HANDLE); - String visContainer = vitroRequest.getParameter(VIS_CONTAINER_URL_HANDLE); + String visContainer = vitroRequest.getParameter(VisualizationFrameworkConstants.VIS_CONTAINER_URL_HANDLE); QueryHandler queryManager = new QueryHandler(individualURIParam, @@ -106,7 +91,7 @@ public class VisualizationRequestHandler { * HTML code to render sparkline, tables etc. Ideally I would want to avoid this flow. * It is ugly! * */ - if (DATA_RENDER_MODE_URL_VALUE.equalsIgnoreCase(renderMode)) { + if (VisualizationFrameworkConstants.DATA_RENDER_MODE_URL_VALUE.equalsIgnoreCase(renderMode)) { prepareVisualizationQueryDataResponse(queryManager.getAuthor(), authorDocuments, yearToPublicationCount); @@ -114,7 +99,7 @@ public class VisualizationRequestHandler { } - if (PDF_RENDER_MODE_URL_VALUE.equalsIgnoreCase(renderMode)) { + if (VisualizationFrameworkConstants.PDF_RENDER_MODE_URL_VALUE.equalsIgnoreCase(renderMode)) { prepareVisualizationQueryPDFResponse(queryManager.getAuthor(), authorDocuments, yearToPublicationCount); @@ -130,7 +115,7 @@ public class VisualizationRequestHandler { * was rendered we dont want to be influenced by the "DEFAULT_PUBLICATION_YEAR". * */ Set publishedYears = new HashSet(yearToPublicationCount.keySet()); - publishedYears.remove(BiboDocument.DEFAULT_PUBLICATION_YEAR); + publishedYears.remove(VOConstants.DEFAULT_PUBLICATION_YEAR); VisualizationCodeGenerator visualizationCodeGenerator = new VisualizationCodeGenerator(yearToPublicationCount, log); @@ -153,7 +138,7 @@ public class VisualizationRequestHandler { * */ RequestDispatcher requestDispatcher = null; - if (DYNAMIC_RENDER_MODE_URL_VALUE.equalsIgnoreCase(renderMode)) { + if (VisualizationFrameworkConstants.DYNAMIC_RENDER_MODE_URL_VALUE.equalsIgnoreCase(renderMode)) { prepareVisualizationQueryDynamicResponse(request, response, vitroRequest, visContentCode, visContextCode); @@ -293,7 +278,8 @@ public class VisualizationRequestHandler { * @return */ private String slugify(String textToBeSlugified) { - return textToBeSlugified.toLowerCase().replaceAll("[^a-zA-Z0-9-]", "-").substring(0, MAX_NAME_TEXT_LENGTH); + return textToBeSlugified.toLowerCase().replaceAll("[^a-zA-Z0-9-]", "-") + .substring(0, VisConstants.MAX_NAME_TEXT_LENGTH); } private void generateCsvFileBuffer(Map yearToPublicationCount, diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/utils/UniqueIDGenerator.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/utils/UniqueIDGenerator.java new file mode 100644 index 000000000..d85c8a300 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/utils/UniqueIDGenerator.java @@ -0,0 +1,14 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.utils; + +public class UniqueIDGenerator { + + private int nextNumericID = 1; + + public int getNextNumericID() { + int nextNumericID = this.nextNumericID; + this.nextNumericID++; + + return nextNumericID; + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/utils/VOUtils.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/utils/VOUtils.java new file mode 100644 index 000000000..cbe2163e3 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/utils/VOUtils.java @@ -0,0 +1,55 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.utils; + +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.BiboDocument; + +public class VOUtils { + + public static Map getYearToPublicationCount( + Set authorDocuments) { + + //List publishedYears = new ArrayList(); + + /* + * Create a map from the year to number of publications. Use the BiboDocument's + * parsedPublicationYear to populate the data. + * */ + Map yearToPublicationCount = new TreeMap(); + + for (BiboDocument curr : authorDocuments) { + + /* + * Increment the count because there is an entry already available for + * that particular year. + * */ + String publicationYear; + if (curr.getPublicationYear() != null + && curr.getPublicationYear().length() != 0 + && curr.getPublicationYear().trim().length() != 0) { + publicationYear = curr.getPublicationYear(); + } else { + publicationYear = curr.getParsedPublicationYear(); + } + + if (yearToPublicationCount.containsKey(publicationYear)) { + yearToPublicationCount.put(publicationYear, + yearToPublicationCount + .get(publicationYear) + 1); + + } else { + yearToPublicationCount.put(publicationYear, 1); + } + +// if (!parsedPublicationYear.equalsIgnoreCase(BiboDocument.DEFAULT_PUBLICATION_YEAR)) { +// publishedYears.add(Integer.parseInt(parsedPublicationYear)); +// } + + } + + return yearToPublicationCount; + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/BiboDocument.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/BiboDocument.java index 96ff3a082..6c8fad61b 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/BiboDocument.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/BiboDocument.java @@ -4,9 +4,10 @@ import java.util.Calendar; import java.util.regex.Matcher; import java.util.regex.Pattern; +import edu.cornell.mannlib.vitro.webapp.visualization.constants.VOConstants; + public class BiboDocument extends Individual{ - public static final String DEFAULT_PUBLICATION_YEAR = "Unknown"; public static final int MINIMUM_PUBLICATION_YEAR = 1800; private static final int CURRENT_YEAR = Calendar.getInstance().get(Calendar.YEAR); @@ -14,7 +15,7 @@ public class BiboDocument extends Individual{ private String documentBlurb; private String documentDescription; private String publicationYear; - private String parsedPublicationYear = DEFAULT_PUBLICATION_YEAR; + private String parsedPublicationYear = VOConstants.DEFAULT_PUBLICATION_YEAR; public BiboDocument(String documentURL) { super(documentURL); @@ -62,7 +63,7 @@ public class BiboDocument extends Individual{ String pattern = "(? yearToPublicationCount; + private Set collaboratorDocuments = new HashSet(); + private Node sourceNode; + private Node targetNode; + + public Edge(Node sourceNode, Node targetNode, BiboDocument seedCoAuthoredDocument, + UniqueIDGenerator uniqueIDGenerator) { + edgeID = uniqueIDGenerator.getNextNumericID(); + this.sourceNode = sourceNode; + this.targetNode = targetNode; + this.collaboratorDocuments.add(seedCoAuthoredDocument); + } + + public int getEdgeID() { + return edgeID; + } + + public Node getSourceNode() { + return sourceNode; + } + + public Node getTargetNode() { + return targetNode; + } + + public Set getCollaboratorDocuments() { + return collaboratorDocuments; + } + + public int getNumOfCoAuthoredWorks() { + return collaboratorDocuments.size(); + } + + public void addCollaboratorDocument(BiboDocument authorDocument) { + this.collaboratorDocuments.add(authorDocument); + } + + /* + * getEarliest, Latest & Unknown Publication YearCount should only be used after + * the parsing of the entire sparql is done. Else it will give results based on + * incomplete dataset. + * */ + @SuppressWarnings("serial") + public Map getEarliestCollaborationYearCount() { + if (yearToPublicationCount == null) { + yearToPublicationCount = VOUtils.getYearToPublicationCount(collaboratorDocuments); + } + + final String earliestYear = Collections.min(yearToPublicationCount.keySet()); + final Integer earliestYearPubCount = yearToPublicationCount.get(earliestYear); + + /* + * If there is no minimum year available then we should imply so by returning a "null". + * */ + if (!earliestYear.equalsIgnoreCase(VOConstants.DEFAULT_PUBLICATION_YEAR)) { + return new HashMap(){{ + put(earliestYear, earliestYearPubCount); + }}; + } else { + return null; + } + } + + @SuppressWarnings("serial") + public Map getLatestCollaborationYearCount() { + if (yearToPublicationCount == null) { + yearToPublicationCount = VOUtils.getYearToPublicationCount(collaboratorDocuments); + } + + final String latestYear = Collections.max(yearToPublicationCount.keySet()); + final Integer latestYearPubCount = yearToPublicationCount.get(latestYear); + + /* + * If there is no maximum year available then we should imply so by returning a "null". + * */ + if (!latestYear.equalsIgnoreCase(VOConstants.DEFAULT_PUBLICATION_YEAR)) { + return new HashMap(){{ + put(latestYear, latestYearPubCount); + }}; + } else { + return null; + } + } + + @SuppressWarnings("serial") + public Map getUnknownCollaborationYearCount() { + if (yearToPublicationCount == null) { + yearToPublicationCount = VOUtils.getYearToPublicationCount(collaboratorDocuments); + } + + final Integer unknownYearPubCount = yearToPublicationCount.get(VOConstants.DEFAULT_PUBLICATION_YEAR); + + /* + * If there is no unknown year available then we should imply so by returning a "null". + * */ + if (unknownYearPubCount != null) { + return new HashMap(){{ + put(VOConstants.DEFAULT_PUBLICATION_YEAR, unknownYearPubCount); + }}; + } else { + return null; + } + } + + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/Node.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/Node.java new file mode 100644 index 000000000..5330325c6 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/Node.java @@ -0,0 +1,128 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.valueobjects; + +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import edu.cornell.mannlib.vitro.webapp.visualization.constants.VOConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.utils.UniqueIDGenerator; +import edu.cornell.mannlib.vitro.webapp.visualization.utils.VOUtils; + +/** + * + * This is the Value Object for storing node information mainly for co-author vis. + * @author cdtank + * + */ +public class Node extends Individual { + + private int nodeID; + private Map yearToPublicationCount; + private Set authorDocuments = new HashSet(); + + public Node(String nodeURL, + UniqueIDGenerator uniqueIDGenerator) { + super(nodeURL); + nodeID = uniqueIDGenerator.getNextNumericID(); + } + + public int getNodeID() { + return nodeID; + } + + public String getNodeURL() { + return this.getIndividualURL(); + } + + public String getNodeName() { + return this.getIndividualLabel(); + } + + public void setNodeName(String nodeName) { + this.setIndividualLabel(nodeName); + } + + public Set getAuthorDocuments() { + return authorDocuments; + } + + public int getNumOfAuthoredWorks() { + return authorDocuments.size(); + } + + public void addAuthorDocument(BiboDocument authorDocument) { + this.authorDocuments.add(authorDocument); + } + + + /* + * getEarliest, Latest & Unknown Publication YearCount should only be used after + * the parsing of the entire sparql is done. Else it will give results based on + * incomplete dataset. + * */ + @SuppressWarnings("serial") + public Map getEarliestPublicationYearCount() { + if (yearToPublicationCount == null) { + yearToPublicationCount = VOUtils.getYearToPublicationCount(authorDocuments); + } + + final String earliestYear = Collections.min(yearToPublicationCount.keySet()); + final Integer earliestYearPubCount = yearToPublicationCount.get(earliestYear); + + /* + * If there is no minimum year available then we should imply so by returning a "null". + * */ + if (!earliestYear.equalsIgnoreCase(VOConstants.DEFAULT_PUBLICATION_YEAR)) { + return new HashMap(){{ + put(earliestYear, earliestYearPubCount); + }}; + } else { + return null; + } + } + + @SuppressWarnings("serial") + public Map getLatestPublicationYearCount() { + if (yearToPublicationCount == null) { + yearToPublicationCount = VOUtils.getYearToPublicationCount(authorDocuments); + } + + final String latestYear = Collections.max(yearToPublicationCount.keySet()); + final Integer latestYearPubCount = yearToPublicationCount.get(latestYear); + + /* + * If there is no maximum year available then we should imply so by returning a "null". + * */ + if (!latestYear.equalsIgnoreCase(VOConstants.DEFAULT_PUBLICATION_YEAR)) { + return new HashMap(){{ + put(latestYear, latestYearPubCount); + }}; + } else { + return null; + } + } + + @SuppressWarnings("serial") + public Map getUnknownPublicationYearCount() { + if (yearToPublicationCount == null) { + yearToPublicationCount = VOUtils.getYearToPublicationCount(authorDocuments); + } + + final Integer unknownYearPubCount = yearToPublicationCount.get(VOConstants.DEFAULT_PUBLICATION_YEAR); + + /* + * If there is no unknown year available then we should imply so by returning a "null". + * */ + if (unknownYearPubCount != null) { + return new HashMap(){{ + put(VOConstants.DEFAULT_PUBLICATION_YEAR, unknownYearPubCount); + }}; + } else { + return null; + } + } + + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/VivoEmployee.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/VivoEmployee.java index 9903233b4..6863289d2 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/VivoEmployee.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/VivoEmployee.java @@ -3,7 +3,7 @@ package edu.cornell.mannlib.vitro.webapp.visualization.valueobjects; import java.util.HashSet; import java.util.Set; -import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.VOConstants.EmployeeType; +import edu.cornell.mannlib.vitro.webapp.visualization.constants.VOConstants.EmployeeType; /** * diff --git a/webapp/web/templates/visualization/dummy_vis_client.jsp b/webapp/web/templates/visualization/dummy_vis_client.jsp index 82d7879dc..6dc72c6c9 100644 --- a/webapp/web/templates/visualization/dummy_vis_client.jsp +++ b/webapp/web/templates/visualization/dummy_vis_client.jsp @@ -87,6 +87,12 @@ + + + + + + + +

Visualization Testbed (Not to be seen by eventual end users)

+ +vis data query for coauthorship -> "Erb, Hollis Nancy"
vis data query for college -> "School of Industrial and Labor Relations (ILR)"
vis data query for college -> "College of Agriculture and Life Sciences (CALS)"
vis data query for college -> "College of Arts and Sciences"