diff --git a/productMods/WEB-INF/visualization/visualizations-beans-injection-fm.xml b/productMods/WEB-INF/visualization/visualizations-beans-injection-fm.xml new file mode 100644 index 00000000..22a3d0a9 --- /dev/null +++ b/productMods/WEB-INF/visualization/visualizations-beans-injection-fm.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/productMods/WEB-INF/web.xml b/productMods/WEB-INF/web.xml index f2467807..262e5927 100644 --- a/productMods/WEB-INF/web.xml +++ b/productMods/WEB-INF/web.xml @@ -1251,7 +1251,7 @@ DummyVisClient - edu.cornell.mannlib.vitro.webapp.controller.visualization.DummyVisClientController + edu.cornell.mannlib.vitro.webapp.controller.visualization.freemarker.DummyVisClientController @@ -1271,6 +1271,17 @@ /visualization + + VisualizationControllerFM + edu.cornell.mannlib.vitro.webapp.controller.visualization.freemarker.VisualizationController + + + + VisualizationControllerFM + /visualizationfm + + + authtest edu.cornell.mannlib.vitro.webapp.auth.AuthTestController diff --git a/productMods/js/visualization/sparkline.js b/productMods/js/visualization/sparkline.js index 9439f949..bb717eb1 100644 --- a/productMods/js/visualization/sparkline.js +++ b/productMods/js/visualization/sparkline.js @@ -26,5 +26,6 @@ var visualization = { }; $(document).ready(function() { + visualizationUrl = visualizationUrl.replace("/visualization", "/visualizationfm"); visualization.render(visualizationUrl); }); diff --git a/productMods/templates/freemarker/body/partials/individual/individual-sparklineVisualization.ftl b/productMods/templates/freemarker/body/partials/individual/individual-sparklineVisualization.ftl index 4a2a9bbe..30f58b7a 100644 --- a/productMods/templates/freemarker/body/partials/individual/individual-sparklineVisualization.ftl +++ b/productMods/templates/freemarker/body/partials/individual/individual-sparklineVisualization.ftl @@ -3,9 +3,13 @@ <#-- Template for sparkline visualization on individual profile page --> <#if individual.visualizationUrl??> + +<#assign googleJSAPI = 'http://www.google.com/jsapi?autoload=%7B%22modules%22%3A%5B%7B%22name%22%3A%22visualization%22%2C%22version%22%3A%221%22%2C%22packages%22%3A%5B%22areachart%22%2C%22imagesparkline%22%5D%7D%5D%7D'> +
 
${stylesheets.addFromTheme("/visualization/visualization.css")} + ${scripts.add(googleJSAPI)} ${scripts.add("/js/visualization/sparkline.js")} + +
+ + + +

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

+ + + + +

Hello World!

+ + + + + + + + +vis query for person -> "Crane, Brian" + + +
iioio
\ No newline at end of file diff --git a/productMods/templates/freemarker/visualization/publicationCount.ftl b/productMods/templates/freemarker/visualization/publicationCount.ftl new file mode 100644 index 00000000..ab78c65a --- /dev/null +++ b/productMods/templates/freemarker/visualization/publicationCount.ftl @@ -0,0 +1,7 @@ +<#-- $This file is distributed under the terms of the license in /doc/license.txt$ --> + +<#assign googleJSAPI = 'http://www.google.com/jsapi?autoload=%7B%22modules%22%3A%5B%7B%22name%22%3A%22visualization%22%2C%22version%22%3A%221%22%2C%22packages%22%3A%5B%22areachart%22%2C%22imagesparkline%22%5D%7D%5D%7D'> + +${headScripts.add(googleJSAPI)} + +<#include "/visualization/publicationSparklineContent.ftl"> \ No newline at end of file diff --git a/productMods/templates/freemarker/visualization/publicationSparklineContent.ftl b/productMods/templates/freemarker/visualization/publicationSparklineContent.ftl new file mode 100644 index 00000000..1285bfd0 --- /dev/null +++ b/productMods/templates/freemarker/visualization/publicationSparklineContent.ftl @@ -0,0 +1,247 @@ +<#assign visContainerID = '${sparklineVO.visContainerDivID}'> + +<#if sparklineVO.shortVisMode> + <#assign sparklineContainerID = 'pub_count_short_sparkline_vis'> +<#else> + <#assign sparklineContainerID = 'pub_count_full_sparkline_vis'> + + +<#-- This is used to prevent collision between sparkline & visualization conatiner div ids. --> +<#if visContainerID?upper_case == sparklineContainerID?upper_case> + <#assign sparklineContainerID = visContainerID + "_spark"> + + +
+ +
+ + + + + +
+ +<#if sparklineVO.shortVisMode> + + + View all VIVO publications and corresponding co-author network. + + + +<#else> + + +

+ + + + + + + + + + + <#list sparklineVO.yearToActivityCount?keys as year> + + + + + + + +
+ Publications per year (.CSV File) +
+ Year + + Publications +
+ ${year} + + ${sparklineVO.yearToActivityCount[year]} +
+ Download data as .csv file. +
+

+ + + +
\ No newline at end of file diff --git a/productMods/templates/freemarker/visualization/sparklineAjaxVisContent.ftl b/productMods/templates/freemarker/visualization/sparklineAjaxVisContent.ftl new file mode 100644 index 00000000..d7bbedb4 --- /dev/null +++ b/productMods/templates/freemarker/visualization/sparklineAjaxVisContent.ftl @@ -0,0 +1,5 @@ +<#-- $This file is distributed under the terms of the license in /doc/license.txt$ --> + +<#if shouldVIVOrenderVis> + <#include "/visualization/publicationSparklineContent.ftl"> + diff --git a/productMods/templates/freemarker/visualization/vistest.ftl b/productMods/templates/freemarker/visualization/vistest.ftl new file mode 100644 index 00000000..e69de29b diff --git a/productMods/templates/freemarker/visualization/visualizationError.ftl b/productMods/templates/freemarker/visualization/visualizationError.ftl new file mode 100644 index 00000000..00bd865f --- /dev/null +++ b/productMods/templates/freemarker/visualization/visualizationError.ftl @@ -0,0 +1,8 @@ +<%-- $This file is distributed under the terms of the license in /doc/license.txt$ --%> + +
+ +${error} + +
+ diff --git a/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/VisualizationFrameworkConstants.java b/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/VisualizationFrameworkConstants.java index b58af3ea..ef40004a 100644 --- a/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/VisualizationFrameworkConstants.java +++ b/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/VisualizationFrameworkConstants.java @@ -11,6 +11,14 @@ public class VisualizationFrameworkConstants { */ public static final String RELATIVE_LOCATION_OF_VISUALIZATIONS_BEAN = "/WEB-INF/visualization/visualizations-beans-injection.xml"; + + /* + * Freemarker Version + * */ + public static final String RELATIVE_LOCATION_OF_FM_VISUALIZATIONS_BEAN = + "/WEB-INF/visualization/visualizations-beans-injection-fm.xml"; + + public static final String ERROR_TEMPLATE = "/visualization/visualizationError.ftl"; /* * Vis URL prefix that is seen by all the users diff --git a/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/freemarker/DummyVisClientController.java b/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/freemarker/DummyVisClientController.java new file mode 100644 index 00000000..e9c47da1 --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/freemarker/DummyVisClientController.java @@ -0,0 +1,82 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.controller.visualization.freemarker; + +/* +Copyright (c) 2010, Cornell University +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of Cornell University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import edu.cornell.mannlib.vedit.beans.LoginStatusBean; +import edu.cornell.mannlib.vitro.webapp.beans.Portal; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerHttpServlet; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues; + +/** + * Services a sparql query. This will return a simple error message and a 501 if + * there is no jena Model. + * + * @author bdc34 + * + */ +public class DummyVisClientController extends FreemarkerHttpServlet { + + private static final long serialVersionUID = 1L; + + private static final Log log = LogFactory.getLog(DummyVisClientController.class.getName()); + private static final String TEMPLATE_DEFAULT = "/visualization/dummyVisClient.ftl"; + + @Override + protected int requiredLoginLevel() { + // User must be logged in to view this page. + return LoginStatusBean.EDITOR; + } + + @Override + protected ResponseValues processRequest(VitroRequest vreq) { + Portal portal = vreq.getPortal(); + + Map body = new HashMap(); + body.put("portalBean", portal); + //body.put("scripts", "/templates/visualization/visualization_scripts.jsp"); + + return new TemplateResponseValues(TEMPLATE_DEFAULT, body); + } + + @Override + protected String getTitle(String siteName) { + return "Dummy Visualization Controller"; + } + +} \ No newline at end of file diff --git a/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/freemarker/VisualizationController.java b/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/freemarker/VisualizationController.java new file mode 100644 index 00000000..88c1bf5e --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/freemarker/VisualizationController.java @@ -0,0 +1,215 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.controller.visualization.freemarker; + +import java.io.IOException; +import java.util.Map; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +import com.hp.hpl.jena.query.DataSource; +import com.hp.hpl.jena.query.DatasetFactory; +import com.hp.hpl.jena.query.Syntax; +import com.hp.hpl.jena.rdf.model.Model; +import com.hp.hpl.jena.rdf.model.ModelMaker; + +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerHttpServlet; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues; +import edu.cornell.mannlib.vitro.webapp.controller.visualization.VisualizationFrameworkConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.constants.VisConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.UtilityFunctions; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.VisualizationRequestHandler; +import freemarker.template.Configuration; + +/** + * Services a visualization request. This will return a simple error message and a 501 if + * there is no jena Model. + * + * @author cdtank + */ +@SuppressWarnings("serial") +public class VisualizationController extends FreemarkerHttpServlet { + + private Map visualizationIDsToClass; + + public static final String URL_ENCODING_SCHEME = "UTF-8"; + + private static final Log log = LogFactory.getLog(VisualizationController.class.getName()); + + protected static final Syntax SYNTAX = Syntax.syntaxARQ; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException { + + VitroRequest vreq = new VitroRequest(request); + + String renderMode = vreq.getParameter(VisualizationFrameworkConstants + .RENDER_MODE_KEY); + + if (StringUtils.equalsIgnoreCase(renderMode, VisualizationFrameworkConstants.DYNAMIC_RENDER_MODE)) { + + System.out.println("inside doing ajax request that is dynamic response"); + + Configuration config = getConfig(vreq); + TemplateResponseValues trv = (TemplateResponseValues) processRequest(vreq); + writeTemplate(trv.getTemplateName(), trv.getMap(), config, request, response); + + } else { + System.out.println("inside doing super.doGet that is normal response"); + super.doGet(request, response); + } + + + } + + + + /* This method is overridden to inject vis dependencies i.e. the vis algorithms that are + * being implemented into the vis controller. Modified Dependency Injection pattern is + * used here. XML file containing the location of all the vis is saved in accessible folder. + * @see javax.servlet.GenericServlet#init() + */ + @Override + public void init() throws ServletException { + super.init(); + try { + + String resourcePath = + getServletContext() + .getRealPath(VisualizationFrameworkConstants + .RELATIVE_LOCATION_OF_FM_VISUALIZATIONS_BEAN); + + ApplicationContext context = new ClassPathXmlApplicationContext( + "file:" + resourcePath); + + BeanFactory factory = context; + + VisualizationInjector visualizationInjector = + (VisualizationInjector) factory.getBean("visualizationInjector"); + + visualizationIDsToClass = visualizationInjector.getVisualizationIDToClass(); + + } catch (Exception e) { + log.error(e); + } + } + + + + @Override + protected ResponseValues processRequest(VitroRequest vreq) { + + /* + * Based on the query parameters passed via URI get the appropriate visualization + * request handler. + * */ + VisualizationRequestHandler visRequestHandler = + getVisualizationRequestHandler(vreq); + + if (visRequestHandler != null) { + + /* + * Pass the query to the selected visualization request handler & render the visualization. + * Since the visualization content is directly added to the response object we are side- + * effecting this method. + * */ + return renderVisualization(vreq, visRequestHandler); + + } else { + + return UtilityFunctions.handleMalformedParameters("Visualization Query Error", + "Inappropriate query parameters were submitted.", + vreq); + + } + + + } + + + private ResponseValues renderVisualization(VitroRequest vitroRequest, + VisualizationRequestHandler visRequestHandler) { + + Model model = vitroRequest.getJenaOntModel(); // getModel() + if (model == null) { + + String errorMessage = "This service is not supporeted by the current " + + "webapp configuration. A jena model is required in the " + + "servlet context."; + + log.error(errorMessage); + + return UtilityFunctions.handleMalformedParameters("Visualization Query Error", + errorMessage, + vitroRequest); + + } + + DataSource dataSource = setupJENADataSource(model, vitroRequest); + + if (dataSource != null && visRequestHandler != null) { + + return visRequestHandler.generateVisualization(vitroRequest, + log, + dataSource); + + } else { + + String errorMessage = "Data Model Empty &/or Inappropriate " + + "query parameters were submitted. "; + + log.error(errorMessage); + + return UtilityFunctions.handleMalformedParameters("Visualization Query Error", + errorMessage, + vitroRequest); + + + } + } + + private VisualizationRequestHandler getVisualizationRequestHandler( + VitroRequest vitroRequest) { + + String visType = vitroRequest.getParameter(VisualizationFrameworkConstants + .VIS_TYPE_KEY); + VisualizationRequestHandler visRequestHandler = null; + + System.out.println(visType + " --> " + visualizationIDsToClass); + + try { + visRequestHandler = visualizationIDsToClass.get(visType); + } catch (NullPointerException nullKeyException) { + + return null; + } + + return visRequestHandler; + } + + private DataSource setupJENADataSource(Model model, VitroRequest vreq) { + + log.debug("rdfResultFormat was: " + VisConstants.RDF_RESULT_FORMAT_PARAM); + + DataSource dataSource = DatasetFactory.create(); + ModelMaker maker = (ModelMaker) getServletContext().getAttribute("vitroJenaModelMaker"); + + dataSource.setDefaultModel(model); + + return dataSource; + } + +} + diff --git a/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/freemarker/VisualizationInjector.java b/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/freemarker/VisualizationInjector.java new file mode 100644 index 00000000..03a60bf6 --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/freemarker/VisualizationInjector.java @@ -0,0 +1,22 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ +package edu.cornell.mannlib.vitro.webapp.controller.visualization.freemarker; + +import java.util.Map; + +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.VisualizationRequestHandler; + +public class VisualizationInjector { + private Map visualizationIDToClass; + + public Map getVisualizationIDToClass() { + + System.out.println("giving the vis id class " + visualizationIDToClass); + return visualizationIDToClass; + } + + public void setVisualizations(Map visualizationIDToClass) { + this.visualizationIDToClass = visualizationIDToClass; + System.out.println("setting the vis id class " + visualizationIDToClass); + } + +} diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/personpubcount/PersonPublicationCountQueryRunner.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/personpubcount/PersonPublicationCountQueryRunner.java new file mode 100644 index 00000000..ca25837f --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/personpubcount/PersonPublicationCountQueryRunner.java @@ -0,0 +1,220 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.personpubcount; + +import java.util.HashSet; +import java.util.Set; + +import org.apache.commons.lang.StringUtils; +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.freemarker.valueobjects.BiboDocument; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.Individual; +import edu.cornell.mannlib.vitro.webapp.visualization.visutils.QueryRunner; + + + +/** + * This query runner is used to execute a sparql query that will fetch all the publications + * defined by bibo:Document property for a particular individual. + * + * @author cdtank + */ +public class PersonPublicationCountQueryRunner implements QueryRunner> { + + protected static final Syntax SYNTAX = Syntax.syntaxARQ; + + private String personURI; + private DataSource dataSource; + + private Individual author; + + public Individual getAuthor() { + return author; + } + + private Log log; + + private static final String SPARQL_QUERY_COMMON_SELECT_CLAUSE = "" + + "SELECT (str(?authorLabel) as ?authorLabelLit) " + + " (str(?document) as ?documentLit) " + + " (str(?documentMoniker) as ?documentMonikerLit) " + + " (str(?documentLabel) as ?documentLabelLit) " + + " (str(?documentBlurb) as ?documentBlurbLit) " + + " (str(?publicationYear) as ?publicationYearLit) " + + " (str(?publicationYearMonth) as ?publicationYearMonthLit) " + + " (str(?publicationDate) as ?publicationDateLit) " + + " (str(?documentDescription) as ?documentDescriptionLit) "; + + private static final String SPARQL_QUERY_COMMON_WHERE_CLAUSE = "" + + "?document rdfs:label ?documentLabel ." + + "OPTIONAL { ?document core:year ?publicationYear } ." + + "OPTIONAL { ?document core:yearMonth ?publicationYearMonth } ." + + "OPTIONAL { ?document core:date ?publicationDate } ." + + "OPTIONAL { ?document vitro:moniker ?documentMoniker } ." + + "OPTIONAL { ?document vitro:blurb ?documentBlurb } ." + + "OPTIONAL { ?document vitro:description ?documentDescription }"; + + public PersonPublicationCountQueryRunner(String personURI, + DataSource dataSource, Log log) { + + this.personURI = personURI; + this.dataSource = dataSource; + this.log = log; + + } + + private Set createJavaValueObjects(ResultSet resultSet) { + Set authorDocuments = new HashSet(); + + while (resultSet.hasNext()) { + QuerySolution solution = resultSet.nextSolution(); + + BiboDocument biboDocument = new BiboDocument( + solution.get(QueryFieldLabels.DOCUMENT_URL) + .toString()); + + 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 documentDescriptionNode = solution.get(QueryFieldLabels.DOCUMENT_DESCRIPTION); + if (documentDescriptionNode != null) { + biboDocument.setDocumentDescription(documentDescriptionNode.toString()); + } + + RDFNode publicationYearNode = solution.get(QueryFieldLabels.DOCUMENT_PUBLICATION_YEAR); + if (publicationYearNode != null) { + biboDocument.setPublicationYear(publicationYearNode.toString()); + } + + RDFNode publicationYearMonthNode = solution.get( + QueryFieldLabels + .DOCUMENT_PUBLICATION_YEAR_MONTH); + if (publicationYearMonthNode != null) { + biboDocument.setPublicationYearMonth(publicationYearMonthNode.toString()); + } + + RDFNode publicationDateNode = solution.get(QueryFieldLabels.DOCUMENT_PUBLICATION_DATE); + if (publicationDateNode != null) { + biboDocument.setPublicationDate(publicationDateNode.toString()); + } + + /* + * Since we are getting publication count for just one author at a time we need + * to create only one "Individual" instance. We test against the null for "author" to + * make sure that it has not already been instantiated. + * */ + RDFNode authorURLNode = solution.get(QueryFieldLabels.AUTHOR_URL); + if (authorURLNode != null && author == null) { + author = new Individual(authorURLNode.toString()); + RDFNode authorLabelNode = solution.get(QueryFieldLabels.AUTHOR_LABEL); + if (authorLabelNode != null) { + author.setIndividualLabel(authorLabelNode.toString()); + } + } + + authorDocuments.add(biboDocument); + } + return authorDocuments; + } + + private ResultSet executeQuery(String queryURI, + DataSource dataSource) { + + QueryExecution queryExecution = null; +// try { + Query query = QueryFactory.create(getSparqlQuery(queryURI), SYNTAX); + +// QuerySolutionMap qs = new QuerySolutionMap(); +// qs.add("authPerson", queryParam); // bind resource to s + + queryExecution = QueryExecutionFactory.create(query, dataSource); + + +// if (query.isSelectType()) { + return queryExecution.execSelect(); +// } +// } finally { +// if (queryExecution != null) { +// queryExecution.close(); +// } +// } +// return null; + } + + private String getSparqlQuery(String queryURI) { +// Resource uri1 = ResourceFactory.createResource(queryURI); + + String sparqlQuery = QueryConstants.getSparqlPrefixQuery() + + SPARQL_QUERY_COMMON_SELECT_CLAUSE + + "(str(<" + queryURI + ">) as ?authPersonLit) " + + "WHERE { " + + "<" + queryURI + "> rdf:type foaf:Person ;" + + " rdfs:label ?authorLabel ;" + + " core:authorInAuthorship ?authorshipNode . " + + " ?authorshipNode rdf:type core:Authorship ;" + + " core:linkedInformationResource ?document . " + + SPARQL_QUERY_COMMON_WHERE_CLAUSE + + "}"; + +// System.out.println("SPARQL query for person pub count -> \n" + sparqlQuery); + return sparqlQuery; + } + + public Set getQueryResult() + throws MalformedQueryParametersException { + + if (StringUtils.isNotBlank(this.personURI)) { + + /* + * To test for the validity of the URI submitted. + * */ + IRIFactory iRIFactory = IRIFactory.jenaImplementation(); + IRI iri = iRIFactory.create(this.personURI); + if (iri.hasViolation(false)) { + String errorMsg = ((Violation) iri.violations(false).next()).getShortMessage(); + log.error("Pub Count vis Query " + errorMsg); + throw new MalformedQueryParametersException( + "URI provided for an individual is malformed."); + } + + } else { + throw new MalformedQueryParametersException("URL parameter is either null or empty."); + } + + ResultSet resultSet = executeQuery(this.personURI, + this.dataSource); + + return createJavaValueObjects(resultSet); + } + +} diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/personpubcount/PersonPublicationCountRequestHandler.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/personpubcount/PersonPublicationCountRequestHandler.java new file mode 100644 index 00000000..cd381d58 --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/personpubcount/PersonPublicationCountRequestHandler.java @@ -0,0 +1,342 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.personpubcount; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.Map.Entry; + +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang.StringEscapeUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; + +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.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.FileResponseValues; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues; +import edu.cornell.mannlib.vitro.webapp.controller.visualization.VisualizationFrameworkConstants; + +import edu.cornell.mannlib.vitro.webapp.visualization.exceptions.MalformedQueryParametersException; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.UtilityFunctions; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.VisualizationRequestHandler; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.BiboDocument; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.Individual; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.SparklineData; +import edu.cornell.mannlib.vitro.webapp.visualization.visutils.PDFDocument; +import edu.cornell.mannlib.vitro.webapp.visualization.visutils.QueryRunner; +import edu.cornell.mannlib.vitro.webapp.web.ContentType; + +/** + * + * This request handler is used to serve the content related to an individual's + * publications over the years like, + * 1. Sprakline representing this + * 2. An entire page dedicated to the sparkline vis which will also have links to + * download the data using which the sparkline was rendered & its tabular representation etc. + * 3. Downloadable CSV file containing number of publications over the years. + * 4. Downloadable PDf file containing the publications content, among other things. + * Currently this is disabled because the feature is half-baked. We plan to activate this in + * the next major release. + * + * @author cdtank + */ +public class PersonPublicationCountRequestHandler implements VisualizationRequestHandler { + + public ResponseValues generateVisualization(VitroRequest vitroRequest, + Log log, + DataSource dataSource) { + + String peronURI = vitroRequest.getParameter( + VisualizationFrameworkConstants + .INDIVIDUAL_URI_KEY); + + String renderMode = vitroRequest.getParameter( + VisualizationFrameworkConstants + .RENDER_MODE_KEY); + + String visMode = vitroRequest.getParameter( + VisualizationFrameworkConstants + .VIS_MODE_KEY); + + String visContainer = vitroRequest.getParameter( + VisualizationFrameworkConstants + .VIS_CONTAINER_KEY); + + QueryRunner> queryManager = + new PersonPublicationCountQueryRunner(peronURI, dataSource, log); + + try { + Set authorDocuments = queryManager.getQueryResult(); + + /* + * Create a map from the year to number of publications. Use the BiboDocument's + * parsedPublicationYear to populate the data. + * */ + Map yearToPublicationCount = + UtilityFunctions.getYearToPublicationCount(authorDocuments); + + Individual author = ((PersonPublicationCountQueryRunner) queryManager).getAuthor(); + + if (VisualizationFrameworkConstants.DATA_RENDER_MODE + .equalsIgnoreCase(renderMode)) { + + return prepareDataResponse(author, + authorDocuments, + yearToPublicationCount); + } + + + /* + * For now we are disabling the capability to render pdf file. + * */ + /* + if (VisualizationFrameworkConstants.PDF_RENDER_MODE + .equalsIgnoreCase(renderMode)) { + + preparePDFResponse(author, + authorDocuments, + yearToPublicationCount, + response); + return; + } + */ + + /* + * Computations required to generate HTML for the sparkline & related context. + * */ + PersonPublicationCountVisCodeGenerator visualizationCodeGenerator = + new PersonPublicationCountVisCodeGenerator(vitroRequest.getContextPath(), + peronURI, + visMode, + visContainer, + authorDocuments, + yearToPublicationCount, + log); + + SparklineData sparklineData = visualizationCodeGenerator + .getValueObjectContainer(); + + /* + * 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 (VisualizationFrameworkConstants.DYNAMIC_RENDER_MODE + .equalsIgnoreCase(renderMode)) { + + return prepareDynamicResponse(vitroRequest, + sparklineData, + yearToPublicationCount); + +// requestDispatcher = request.getRequestDispatcher("/templates/page/blankPage.jsp"); + + } else { + return prepareStandaloneResponse(vitroRequest, + sparklineData); + } + + } catch (MalformedQueryParametersException e) { + return UtilityFunctions.handleMalformedParameters( + "Visualization Query Error - Individual Publication Count", + e.getMessage(), + vitroRequest); + } + } + + private String getPublicationsOverTimeCSVContent(Map yearToPublicationCount) { + + StringBuilder csvFileContent = new StringBuilder(); + + csvFileContent.append("Year, Publications\n"); + + for (Entry currentEntry : yearToPublicationCount.entrySet()) { + csvFileContent.append(StringEscapeUtils.escapeCsv(currentEntry.getKey())); + csvFileContent.append(","); + csvFileContent.append(currentEntry.getValue()); + csvFileContent.append("\n"); + } + + return csvFileContent.toString(); + } + + /** + * Provides response when csv file containing the publication count over the years + * is requested. + * @param author + * @param authorDocuments + * @param yearToPublicationCount + * @return + */ + private FileResponseValues prepareDataResponse( + Individual author, + Set 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 = author.getIndividualLabel(); + } + + /* + * To make sure that null/empty records for author names do not cause any mischief. + * */ + if (StringUtils.isBlank(authorName)) { + authorName = "no-author"; + } + + String outputFileName = UtilityFunctions.slugify(authorName) + + "_publications-per-year" + ".csv"; + + + Map fileContents = new HashMap(); + fileContents.put("fileContent", getPublicationsOverTimeCSVContent(yearToPublicationCount)); + + return new FileResponseValues(new ContentType(), outputFileName, fileContents); + } + + /** + * Provides response when an entire page dedicated to publication sparkline is requested. + * @param vreq + * @param valueObjectContainer + * @return + */ + private TemplateResponseValues prepareStandaloneResponse(VitroRequest vreq, + SparklineData valueObjectContainer) { + + Portal portal = vreq.getPortal(); + + String standaloneTemplate = "/visualization/publicationCount.ftl"; + + Map body = new HashMap(); + body.put("portalBean", portal); + body.put("title", "Individual Publication Count visualization"); + body.put("sparklineVO", valueObjectContainer); + + /* + * DO NOT DO THIS HERE. Set stylesheets/scripts in the *.ftl instead using $(scripts.add) + * */ +// body.put("scripts", "/templates/visualization/visualization_scripts.jsp"); + + return new TemplateResponseValues(standaloneTemplate, body); + + } + + /** + * Provides response when the publication sparkline has to be rendered in already existing + * page, e.g. profile page. + * @param vreq + * @param valueObjectContainer + * @param yearToPublicationCount + * @return + */ + private TemplateResponseValues prepareDynamicResponse( + VitroRequest vreq, + SparklineData valueObjectContainer, + Map yearToPublicationCount) { + + Portal portal = vreq.getPortal(); + + + String dynamicTemplate = "/visualization/sparklineAjaxVisContent.ftl"; + + Map body = new HashMap(); + body.put("portalBean", portal); + body.put("sparklineVO", valueObjectContainer); + + /* + * DO NOT DO THIS HERE. Set stylesheets/scripts in the *.ftl instead using $(scripts.add) + * */ +// body.put("scripts", "/templates/visualization/visualization_scripts.jsp"); + + if (yearToPublicationCount.size() > 0) { + body.put("shouldVIVOrenderVis", true); + } else { + body.put("shouldVIVOrenderVis", false); + } + + return new TemplateResponseValues(dynamicTemplate, body); + + } + + private void preparePDFResponse( + Individual author, + Set authorDocuments, + Map yearToPublicationCount, + HttpServletResponse response) { + + String authorName = null; + + // To protect against cases where there are no author documents associated with the +// / individual. + if (authorDocuments.size() > 0) { + authorName = author.getIndividualLabel(); + } + + //To make sure that null/empty records for author names do not cause any mischief. + if (StringUtils.isBlank(authorName)) { + authorName = "no-author"; + } + + String outputFileName = UtilityFunctions.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(); + + // setting some response headers & content type + response.setHeader("Expires", "0"); + response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0"); + response.setHeader("Pragma", "public"); + response.setContentLength(baos.size()); + // write ByteArrayOutputStream to the ServletOutputStream + baos.writeTo(responseOutputStream); + responseOutputStream.flush(); + responseOutputStream.close(); + + } catch (IOException e) { + e.printStackTrace(); + } catch (DocumentException e) { + e.printStackTrace(); + } + } + + + + +} diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/personpubcount/PersonPublicationCountVisCodeGenerator.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/personpubcount/PersonPublicationCountVisCodeGenerator.java new file mode 100644 index 00000000..4abd587d --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/personpubcount/PersonPublicationCountVisCodeGenerator.java @@ -0,0 +1,676 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.personpubcount; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.Map.Entry; + +import org.apache.commons.logging.Log; + +import edu.cornell.mannlib.vitro.webapp.controller.visualization.freemarker.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.constants.VisConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.BiboDocument; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.SparklineData; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.YearPublicationCountDataElement; + + +@SuppressWarnings("serial") +public class PersonPublicationCountVisCodeGenerator { + + /* + * There are 2 modes of sparkline that are available via this visualization. + * 1. Short Sparkline - This sparkline will render all the data points (or sparks), + * which in this case are the publications over the years, from the last 10 years. + * + * 2. Full Sparkline - This sparkline will render all the data points (or sparks) + * spanning the career of the person & last 10 years at the minimum, in case if + * the person started his career in the last 10 yeras. + * */ + private static final Map VIS_DIV_NAMES = new HashMap() { { + + put("SHORT_SPARK", "pub_count_short_sparkline_vis"); + put("FULL_SPARK", "pub_count_full_sparkline_vis"); + + } }; + + private static final String VISUALIZATION_STYLE_CLASS = "sparkline_style"; + + private static final String DEFAULT_VIS_CONTAINER_DIV_ID = "pub_count_vis_container"; + + private Map yearToPublicationCount; + + private Log log; + + private SparklineData sparklineData; + + private String contextPath; + + private String individualURI; + + public PersonPublicationCountVisCodeGenerator(String contextPath, + String individualURIParam, + String visMode, + String visContainer, + Set authorDocuments, + Map yearToPublicationCount, + Log log) { + + this.contextPath = contextPath; + this.individualURI = individualURIParam; + + this.yearToPublicationCount = yearToPublicationCount; + this.sparklineData = new SparklineData(); + + sparklineData.setYearToActivityCount(yearToPublicationCount); + + + this.log = log; + + generateVisualizationCode(visMode, visContainer, authorDocuments); + } + + /** + * This method is used to generate the visualization code (HMTL, CSS & JavaScript). + * There 2 parts to it - 1. Actual Content Code & 2. Context Code. + * 1. Actual Content code in this case is the sparkline image, text related to + * data and the wrapping tables. This is generated via call to google vis API through + * JavaScript. + * 2. Context code is generally optional but contains code pertaining to tabulated + * data & links to download files etc. + * @param visMode + * @param visContainer + * @param authorDocuments + */ + private void generateVisualizationCode(String visMode, + String visContainer, + Set authorDocuments) { + + sparklineData.setSparklineContent(getMainVisualizationCode(authorDocuments, + visMode, + visContainer)); + + + sparklineData.setSparklineContext(getVisualizationContextCode(visMode)); + + } + + private String getMainVisualizationCode(Set authorDocuments, + String visMode, + String providedVisContainerID) { + + int numOfYearsToBeRendered = 0; + int currentYear = Calendar.getInstance().get(Calendar.YEAR); + int shortSparkMinYear = currentYear + - VisConstants.MINIMUM_YEARS_CONSIDERED_FOR_SPARKLINE + + 1; + + /* + * 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". + * */ + Set publishedYears = new HashSet(yearToPublicationCount.keySet()); + publishedYears.remove(VOConstants.DEFAULT_PUBLICATION_YEAR); + + /* + * We are setting the default value of minPublishedYear to be 10 years before + * the current year (which is suitably represented by the shortSparkMinYear), + * this in case we run into invalid set of published years. + * */ + int minPublishedYear = shortSparkMinYear; + + String visContainerID = null; + + StringBuilder visualizationCode = new StringBuilder(); + + if (yearToPublicationCount.size() > 0) { + try { + minPublishedYear = Integer.parseInt(Collections.min(publishedYears)); + } catch (NoSuchElementException e1) { + log.debug("vis: " + e1.getMessage() + " error occurred for " + + yearToPublicationCount.toString()); + } catch (NumberFormatException e2) { + log.debug("vis: " + e2.getMessage() + " error occurred for " + + yearToPublicationCount.toString()); + } + } + + int minPubYearConsidered = 0; + + /* + * There might be a case that the author has made his first publication within the + * last 10 years but we want to make sure that the sparkline is representative of + * at least the last 10 years, so we will set the minPubYearConsidered to + * "currentYear - 10" which is also given by "shortSparkMinYear". + * */ + if (minPublishedYear > shortSparkMinYear) { + minPubYearConsidered = shortSparkMinYear; + } else { + minPubYearConsidered = minPublishedYear; + } + + numOfYearsToBeRendered = currentYear - minPubYearConsidered + 1; + + sparklineData.setNumOfYearsToBeRendered(numOfYearsToBeRendered); + + visualizationCode.append("\n"); + + visualizationCode.append("\n"; + } + + private String getVisualizationContextCode(String visMode) { + + String visualizationContextCode = ""; + if (VisualizationFrameworkConstants.SHORT_SPARKLINE_VIS_MODE.equalsIgnoreCase(visMode)) { + visualizationContextCode = generateShortVisContext(); + } else { + visualizationContextCode = generateFullVisContext(); + } + + log.debug(visualizationContextCode); + + return visualizationContextCode; + } + + private String generateFullVisContext() { + + StringBuilder divContextCode = new StringBuilder(); + + String csvDownloadURLHref = ""; + + if (yearToPublicationCount.size() > 0) { + + try { + if (getCSVDownloadURL() != null) { + + csvDownloadURLHref = "Download data as .csv file.
"; + sparklineData.setDownloadDataLink(getCSVDownloadURL()); + + } else { + csvDownloadURLHref = ""; + } + + } catch (UnsupportedEncodingException e) { + csvDownloadURLHref = ""; + } + } else { + csvDownloadURLHref = "No data available to export.
"; + } + + String tableCode = generateDataTable(); + + divContextCode.append("

" + tableCode + csvDownloadURLHref + "

"); + + sparklineData.setTable(tableCode); + + return divContextCode.toString(); + } + + private String getCSVDownloadURL() + throws UnsupportedEncodingException { + + if (yearToPublicationCount.size() > 0) { + + String secondaryContextPath = ""; + if (!contextPath.contains(VisualizationFrameworkConstants.VISUALIZATION_URL_PREFIX)) { + secondaryContextPath = VisualizationFrameworkConstants.VISUALIZATION_URL_PREFIX; + } + + String downloadURL = contextPath + + secondaryContextPath + + "?" + VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY + + "=" + URLEncoder.encode(individualURI, + VisualizationController.URL_ENCODING_SCHEME) + .toString() + + "&" + VisualizationFrameworkConstants.VIS_TYPE_KEY + + "=" + URLEncoder.encode( + VisualizationFrameworkConstants + .PERSON_PUBLICATION_COUNT_VIS, + VisualizationController.URL_ENCODING_SCHEME) + .toString() + + "&" + VisualizationFrameworkConstants.RENDER_MODE_KEY + + "=" + URLEncoder.encode(VisualizationFrameworkConstants + .DATA_RENDER_MODE, + VisualizationController.URL_ENCODING_SCHEME) + .toString(); + return downloadURL; + } else { + return null; + } + } + + private String generateShortVisContext() { + + StringBuilder divContextCode = new StringBuilder(); + + try { + + String fullTimelineLink; + if (yearToPublicationCount.size() > 0) { + + String secondaryContextPath = ""; + if (!contextPath.contains(VisualizationFrameworkConstants.VISUALIZATION_URL_PREFIX)) { + secondaryContextPath = VisualizationFrameworkConstants.VISUALIZATION_URL_PREFIX; + } + + String fullTimelineNetworkURL = contextPath + + secondaryContextPath + + "?" + + VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY + + "=" + URLEncoder.encode(individualURI, + VisualizationController.URL_ENCODING_SCHEME).toString() + + "&" + + VisualizationFrameworkConstants.VIS_TYPE_KEY + + "=" + URLEncoder.encode("person_level", + VisualizationController.URL_ENCODING_SCHEME).toString() + + "&" + + VisualizationFrameworkConstants.RENDER_MODE_KEY + + "=" + URLEncoder.encode(VisualizationFrameworkConstants + .STANDALONE_RENDER_MODE, + VisualizationController.URL_ENCODING_SCHEME).toString(); + + fullTimelineLink = "View all VIVO " + + "publications and corresponding co-author network."; + + sparklineData.setFullTimelineNetworkLink(fullTimelineNetworkURL); + + } else { + fullTimelineLink = "No data available to render full timeline.
"; + } + + divContextCode.append("" + fullTimelineLink + ""); + + } catch (UnsupportedEncodingException e) { + log.error(e); + } + return divContextCode.toString(); + } + + private String generateDataTable() { + + String csvDownloadURLHref = ""; + + try { + if (getCSVDownloadURL() != null) { + csvDownloadURLHref = "(.CSV File)"; + } else { + csvDownloadURLHref = ""; + } + } catch (UnsupportedEncodingException e) { + csvDownloadURLHref = ""; + } + + StringBuilder dataTable = new StringBuilder(); + + dataTable.append("" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + ""); + + for (Entry currentEntry : yearToPublicationCount.entrySet()) { + dataTable.append("" + + "" + + "" + + ""); + } + + dataTable.append("\n
Publications per year " + csvDownloadURLHref + "
YearPublications
" + currentEntry.getKey() + "" + currentEntry.getValue() + "
\n"); + + return dataTable.toString(); + } + + public SparklineData getValueObjectContainer() { + return sparklineData; + } +} diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/BiboDocument.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/BiboDocument.java new file mode 100644 index 00000000..24cf27b8 --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/BiboDocument.java @@ -0,0 +1,183 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import edu.cornell.mannlib.vitro.webapp.visualization.constants.VOConstants; + +/** + * @author cdtank + * + */ +public class BiboDocument extends Individual { + + private String documentMoniker; + private String documentBlurb; + private String documentDescription; + private String publicationYear; + private String publicationYearMonth; + private String publicationDate; + private String parsedPublicationYear = VOConstants.DEFAULT_PUBLICATION_YEAR; + + public BiboDocument(String documentURL) { + super(documentURL); + } + + public String getDocumentURL() { + return this.getIndividualURI(); + } + + public String getDocumentMoniker() { + return documentMoniker; + } + + public void setDocumentMoniker(String documentMoniker) { + this.documentMoniker = documentMoniker; + } + + public String getDocumentLabel() { + return this.getIndividualLabel(); + } + + public void setDocumentLabel(String documentLabel) { + this.setIndividualLabel(documentLabel); + } + + public String getDocumentBlurb() { + return documentBlurb; + } + + public void setDocumentBlurb(String documentBlurb) { + this.documentBlurb = documentBlurb; + +// if (documentBlurb != null) { +// this.setParsedPublicationYear(parsePublicationYear(documentBlurb)); +// } + } + + private String parsePublicationYear(String documentBlurb) { + + /* + * This pattern will match all group of numbers which have only 4 digits + * delimited by the word boundary. + * */ + String pattern = "(?= VOConstants.MINIMUM_PUBLICATION_YEAR) { + publishedYear = candidateYearInteger.toString(); + } + + } + + return publishedYear; + } + + public String getDocumentDescription() { + return documentDescription; + } + public void setDocumentDescription(String documentDescription) { + this.documentDescription = documentDescription; + } + + /** + * This method will be called when there is no usable core:year value found + * for the bibo:Document. It will first check & parse core:yearMonth failing + * which it will try core:date + * @return + */ + public String getParsedPublicationYear() { + + /* + * We are assuming that core:yearMonth has "YYYY-MM" format. This is based + * off of http://www.w3.org/TR/xmlschema-2/#gYearMonth , which is what + * core:yearMonth points to internally. + * */ + if (publicationYearMonth != null + && publicationYearMonth.length() >= VOConstants.NUM_CHARS_IN_YEAR_FORMAT + && isValidPublicationYear(publicationYearMonth.substring( + 0, + VOConstants.NUM_CHARS_IN_YEAR_FORMAT))) { + + return publicationYearMonth.substring(0, VOConstants.NUM_CHARS_IN_YEAR_FORMAT); + + } + + if (publicationDate != null + && publicationDate.length() >= VOConstants.NUM_CHARS_IN_YEAR_FORMAT + && isValidPublicationYear(publicationDate + .substring(0, + VOConstants.NUM_CHARS_IN_YEAR_FORMAT))) { + + return publicationDate.substring(0, VOConstants.NUM_CHARS_IN_YEAR_FORMAT); + } + + /* + * If all else fails return default unknown year identifier + * */ + return VOConstants.DEFAULT_PUBLICATION_YEAR; + } + + /* + * This publicationYear value is directly from the data supported by the ontology. + * If this is empty only then use the parsedPublicationYear. + * */ + public String getPublicationYear() { + if (publicationYear != null && isValidPublicationYear(publicationYear)) { + return publicationYear; + } else { + return null; + } + + } + + public void setPublicationYear(String publicationYear) { + this.publicationYear = publicationYear; + } + + public String getPublicationYearMonth() { + return publicationYearMonth; + } + + public void setPublicationYearMonth(String publicationYearMonth) { + this.publicationYearMonth = publicationYearMonth; + } + + public String getPublicationDate() { + return publicationDate; + } + + public void setPublicationDate(String publicationDate) { + this.publicationDate = publicationDate; + } + + private boolean isValidPublicationYear(String testPublicationYear) { + + if (testPublicationYear.length() != 0 + && testPublicationYear.trim().length() == VOConstants.NUM_CHARS_IN_YEAR_FORMAT + && testPublicationYear.matches("\\d+") + && Integer.parseInt(testPublicationYear) >= VOConstants.MINIMUM_PUBLICATION_YEAR) { + return true; + } + + return false; + } + +} diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/Child.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/Child.java new file mode 100644 index 00000000..3cce4c43 --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/Child.java @@ -0,0 +1,42 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ +package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects; + +import java.util.Set; +import java.util.HashSet; +/** + * @author bkoniden + * Deepak Konidena + * + */ +public class Child extends Individual { + + Set documents = new HashSet(); + + public Child(String individualURI) { + super(individualURI); + } + + public Set getDocuments() { + return documents; + } + + public Child(String individualURI, String individualLabel) { + super(individualURI, individualLabel); + } + + @Override + public boolean equals(Object other){ + boolean result = false; + if (other instanceof Child){ + Child person = (Child) other; + result = (this.getIndividualLabel().equals(person.getIndividualLabel()) + && this.getIndividualURI().equals(person.getIndividualURI())); + } + return result; + } + + @Override + public int hashCode(){ + return(41*(getIndividualLabel().hashCode() + 41*(getIndividualURI().hashCode()))); + } +} diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/CoAuthorshipData.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/CoAuthorshipData.java new file mode 100644 index 00000000..720856ed --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/CoAuthorshipData.java @@ -0,0 +1,229 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects; + +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +public class CoAuthorshipData { + + private Set nodes; + private Set edges; + private Node egoNode; + private Set> NODE_SCHEMA; + private Set> EDGE_SCHEMA; + + public CoAuthorshipData(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; + } + + /* + * Node Schema for graphML + * */ + public Set> getNodeSchema() { + + if (NODE_SCHEMA == null) { + NODE_SCHEMA = initializeNodeSchema(); + } + + return NODE_SCHEMA; + } + + /* + * Edge Schema for graphML + * */ + public Set> getEdgeSchema() { + + if (EDGE_SCHEMA == null) { + EDGE_SCHEMA = initializeEdgeSchema(); + } + + return EDGE_SCHEMA; + } + + private Set> initializeEdgeSchema() { + + Set> edgeSchema = new HashSet>(); + + Map schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "collaborator1"); + schemaAttributes.put("for", "edge"); + schemaAttributes.put("attr.name", "collaborator1"); + schemaAttributes.put("attr.type", "string"); + + edgeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "collaborator2"); + schemaAttributes.put("for", "edge"); + schemaAttributes.put("attr.name", "collaborator2"); + schemaAttributes.put("attr.type", "string"); + + edgeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "number_of_coauthored_works"); + schemaAttributes.put("for", "edge"); + schemaAttributes.put("attr.name", "number_of_coauthored_works"); + schemaAttributes.put("attr.type", "int"); + + edgeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "earliest_collaboration"); + schemaAttributes.put("for", "edge"); + schemaAttributes.put("attr.name", "earliest_collaboration"); + schemaAttributes.put("attr.type", "int"); + + edgeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "num_earliest_collaboration"); + schemaAttributes.put("for", "edge"); + schemaAttributes.put("attr.name", "num_earliest_collaboration"); + schemaAttributes.put("attr.type", "int"); + + edgeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "latest_collaboration"); + schemaAttributes.put("for", "edge"); + schemaAttributes.put("attr.name", "latest_collaboration"); + schemaAttributes.put("attr.type", "int"); + + edgeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "num_latest_collaboration"); + schemaAttributes.put("for", "edge"); + schemaAttributes.put("attr.name", "num_latest_collaboration"); + schemaAttributes.put("attr.type", "int"); + + edgeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "num_unknown_collaboration"); + schemaAttributes.put("for", "edge"); + schemaAttributes.put("attr.name", "num_unknown_collaboration"); + schemaAttributes.put("attr.type", "int"); + + edgeSchema.add(schemaAttributes); + + return edgeSchema; + } + + + private Set> initializeNodeSchema() { + + Set> nodeSchema = new HashSet>(); + + Map schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "url"); + schemaAttributes.put("for", "node"); + schemaAttributes.put("attr.name", "url"); + schemaAttributes.put("attr.type", "string"); + + nodeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "label"); + schemaAttributes.put("for", "node"); + schemaAttributes.put("attr.name", "label"); + schemaAttributes.put("attr.type", "string"); + + nodeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "profile_url"); + schemaAttributes.put("for", "node"); + schemaAttributes.put("attr.name", "profile_url"); + schemaAttributes.put("attr.type", "string"); + + nodeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "number_of_authored_works"); + schemaAttributes.put("for", "node"); + schemaAttributes.put("attr.name", "number_of_authored_works"); + schemaAttributes.put("attr.type", "int"); + + nodeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "earliest_publication"); + schemaAttributes.put("for", "node"); + schemaAttributes.put("attr.name", "earliest_publication"); + schemaAttributes.put("attr.type", "int"); + + nodeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "num_earliest_publication"); + schemaAttributes.put("for", "node"); + schemaAttributes.put("attr.name", "num_earliest_publication"); + schemaAttributes.put("attr.type", "int"); + + nodeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "latest_publication"); + schemaAttributes.put("for", "node"); + schemaAttributes.put("attr.name", "latest_publication"); + schemaAttributes.put("attr.type", "int"); + + nodeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "num_latest_publication"); + schemaAttributes.put("for", "node"); + schemaAttributes.put("attr.name", "num_latest_publication"); + schemaAttributes.put("attr.type", "int"); + + nodeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "num_unknown_publication"); + schemaAttributes.put("for", "node"); + schemaAttributes.put("attr.name", "num_unknown_publication"); + schemaAttributes.put("attr.type", "int"); + + nodeSchema.add(schemaAttributes); + + + return nodeSchema; + } + +} diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/CoPIData.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/CoPIData.java new file mode 100644 index 00000000..6ad3299f --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/CoPIData.java @@ -0,0 +1,251 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects; + +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +public class CoPIData { + + private Set nodes; + private Set edges; + private CoPINode egoNode; + private Set> NODE_SCHEMA; + private Set> EDGE_SCHEMA; + + public CoPIData(CoPINode 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 CoPINode getEgoNode() { + return egoNode; + } + + /* + * Node Schema for graphML + * */ + public Set> getNodeSchema() { + + if (NODE_SCHEMA == null) { + NODE_SCHEMA = initializeNodeSchema(); + } + + return NODE_SCHEMA; + } + + /* + * Edge Schema for graphML + * */ + public Set> getEdgeSchema() { + + if (EDGE_SCHEMA == null) { + EDGE_SCHEMA = initializeEdgeSchema(); + } + + return EDGE_SCHEMA; + } + + public void print(){ + + System.out.println("\n-----------------------------"); + + System.out.println("Ego node is "+ this.getEgoNode().getNodeName()); + + System.out.println("\nNodes are: "); + + for(CoPINode node : this.getNodes()){ + System.out.println(node.getNodeName()); + } + + System.out.println("\nEdges are: "); + + for(CoPIEdge edge : this.getEdges()){ + System.out.println(edge.getSourceNode() + "-->" + edge.getTargetNode()); + } + + System.out.println("\n-----------------------------"); + + } + + private Set> initializeEdgeSchema() { + + Set> edgeSchema = new HashSet>(); + + Map schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "collaborator1"); + schemaAttributes.put("for", "edge"); + schemaAttributes.put("attr.name", "collaborator1"); + schemaAttributes.put("attr.type", "string"); + + edgeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "collaborator2"); + schemaAttributes.put("for", "edge"); + schemaAttributes.put("attr.name", "collaborator2"); + schemaAttributes.put("attr.type", "string"); + + edgeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "number_of_coinvestigated_grants"); + schemaAttributes.put("for", "edge"); + schemaAttributes.put("attr.name", "number_of_coinvestigated_grants"); + schemaAttributes.put("attr.type", "int"); + + edgeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "earliest_collaboration"); + schemaAttributes.put("for", "edge"); + schemaAttributes.put("attr.name", "earliest_collaboration"); + schemaAttributes.put("attr.type", "int"); + + edgeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "num_earliest_collaboration"); + schemaAttributes.put("for", "edge"); + schemaAttributes.put("attr.name", "num_earliest_collaboration"); + schemaAttributes.put("attr.type", "int"); + + edgeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "latest_collaboration"); + schemaAttributes.put("for", "edge"); + schemaAttributes.put("attr.name", "latest_collaboration"); + schemaAttributes.put("attr.type", "int"); + + edgeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "num_latest_collaboration"); + schemaAttributes.put("for", "edge"); + schemaAttributes.put("attr.name", "num_latest_collaboration"); + schemaAttributes.put("attr.type", "int"); + + edgeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "num_unknown_collaboration"); + schemaAttributes.put("for", "edge"); + schemaAttributes.put("attr.name", "num_unknown_collaboration"); + schemaAttributes.put("attr.type", "int"); + + edgeSchema.add(schemaAttributes); + + return edgeSchema; + } + + + private Set> initializeNodeSchema() { + + Set> nodeSchema = new HashSet>(); + + Map schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "url"); + schemaAttributes.put("for", "node"); + schemaAttributes.put("attr.name", "url"); + schemaAttributes.put("attr.type", "string"); + + nodeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "label"); + schemaAttributes.put("for", "node"); + schemaAttributes.put("attr.name", "label"); + schemaAttributes.put("attr.type", "string"); + + nodeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "profile_url"); + schemaAttributes.put("for", "node"); + schemaAttributes.put("attr.name", "profile_url"); + schemaAttributes.put("attr.type", "string"); + + nodeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "number_of_investigated_grants"); + schemaAttributes.put("for", "node"); + schemaAttributes.put("attr.name", "number_of_investigated_grants"); + schemaAttributes.put("attr.type", "int"); + + nodeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "earliest_grant"); + schemaAttributes.put("for", "node"); + schemaAttributes.put("attr.name", "earliest_grant"); + schemaAttributes.put("attr.type", "int"); + + nodeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "num_earliest_grant"); + schemaAttributes.put("for", "node"); + schemaAttributes.put("attr.name", "num_earliest_grant"); + schemaAttributes.put("attr.type", "int"); + + nodeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "latest_grant"); + schemaAttributes.put("for", "node"); + schemaAttributes.put("attr.name", "latest_grant"); + schemaAttributes.put("attr.type", "int"); + + nodeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "num_latest_grant"); + schemaAttributes.put("for", "node"); + schemaAttributes.put("attr.name", "num_latest_grant"); + schemaAttributes.put("attr.type", "int"); + + nodeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "num_unknown_grant"); + schemaAttributes.put("for", "node"); + schemaAttributes.put("attr.name", "num_unknown_grant"); + schemaAttributes.put("attr.type", "int"); + + nodeSchema.add(schemaAttributes); + + + return nodeSchema; + } + +} diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/CoPIEdge.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/CoPIEdge.java new file mode 100644 index 00000000..cc43356f --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/CoPIEdge.java @@ -0,0 +1,144 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ +package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.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.freemarker.visutils.UniqueIDGenerator; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.UtilityFunctions; + +/** + * This stores edge information for Co-PI vis. + * @author bkoniden + * Deepak Konidena + */ +public class CoPIEdge { + + private int edgeID; + private Map yearToGrantCount; + private Set collaboratorGrants = new HashSet(); + private CoPINode sourceNode; + private CoPINode targetNode; + + public CoPIEdge(CoPINode sourceNode, CoPINode targetNode, Grant seedCoPIedGrant, UniqueIDGenerator uniqueIDGenerator){ + edgeID = uniqueIDGenerator.getNextNumericID(); + this.sourceNode = sourceNode; + this.targetNode = targetNode; + this.collaboratorGrants.add(seedCoPIedGrant); + } + + public int getEdgeID() { + return edgeID; + } + public Set getCollaboratorGrants() { + return collaboratorGrants; + } + public CoPINode getSourceNode() { + return sourceNode; + } + public CoPINode getTargetNode() { + return targetNode; + } + + public int getNumberOfCoInvestigatedGrants(){ + return collaboratorGrants.size(); + } + + public void addCollaboratorGrant(Grant grant){ + this.collaboratorGrants.add(grant); + } + + /* + * getEarliest, Latest & Unknown Grant 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 (yearToGrantCount == null) { + yearToGrantCount = UtilityFunctions.getYearToGrantCount(collaboratorGrants); + } + + /* + * We do not want to consider the default grant year when we are checking + * for the min or max grant year. + * */ + Set yearsToBeConsidered = new HashSet(yearToGrantCount.keySet()); + yearsToBeConsidered.remove(VOConstants.DEFAULT_PUBLICATION_YEAR); + + /* + * There can be a case when the only publication the author has no attached year to it + * so essentially an "Unknown". In that case Collections.max or min will throw an + * NoSuchElementException. + * + * If there is no maximum year available then we should imply so by returning a "null". + * */ + if (yearsToBeConsidered.size() > 0) { + final String earliestYear = Collections.min(yearsToBeConsidered); + final Integer earliestYearGrantCount = yearToGrantCount.get(earliestYear); + + return new HashMap() { { + put(earliestYear, earliestYearGrantCount); + } }; + } else { + return null; + } + } + + + @SuppressWarnings("serial") + public Map getLatestCollaborationYearCount() { + if (yearToGrantCount == null) { + yearToGrantCount = UtilityFunctions.getYearToGrantCount(collaboratorGrants); + } + + /* + * We do not want to consider the default grant year when we are checking + * for the min or max grant year. + * */ + Set yearsToBeConsidered = new HashSet(yearToGrantCount.keySet()); + yearsToBeConsidered.remove(VOConstants.DEFAULT_PUBLICATION_YEAR); + + /* + * There can be a case when the only grant the PI has no attached year to it + * so essentially an "Unknown". In that case Collections.max or min will throw an + * NoSuchElementException. + * + * If there is no maximum year available then we should imply so by returning a "null". + * */ + if (yearsToBeConsidered.size() > 0) { + final String latestYear = Collections.max(yearsToBeConsidered); + final Integer latestYearGrantCount = yearToGrantCount.get(latestYear); + + return new HashMap() { { + put(latestYear, latestYearGrantCount); + } }; + } else { + return null; + } + + } + + public Integer getUnknownCollaborationYearCount() { + if (yearToGrantCount == null) { + yearToGrantCount = UtilityFunctions.getYearToGrantCount(collaboratorGrants); + } + + Integer unknownYearGrantCount = yearToGrantCount + .get(VOConstants.DEFAULT_PUBLICATION_YEAR); + + /* + * If there is no unknown year available then we should imply so by returning a "null". + * */ + if (unknownYearGrantCount != null) { + return unknownYearGrantCount; + } else { + return null; + } + } + +} diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/CoPINode.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/CoPINode.java new file mode 100644 index 00000000..3aedffbf --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/CoPINode.java @@ -0,0 +1,154 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ +package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.HashSet; + +import edu.cornell.mannlib.vitro.webapp.visualization.constants.VOConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.visutils.UniqueIDGenerator; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.UtilityFunctions; + +/** + * CoPINode is the node in a CoPI vis. + * @author bkoniden + * Deepak Konidena + */ +public class CoPINode extends Individual { + + private int nodeID; + private Map yearToGrantCount; + + private Set pIGrants = new HashSet(); + + public CoPINode(String nodeURI, UniqueIDGenerator uniqueIDGenerator){ + super(nodeURI); + nodeID = uniqueIDGenerator.getNextNumericID(); + } + + public int getNodeID(){ + return nodeID; + } + + public String getNodeURI(){ + return this.getIndividualURI(); + } + + public String getNodeName(){ + return this.getIndividualLabel(); + } + + public void setNodeName(String nodeName) { + this.setIndividualLabel(nodeName); + } + + public Set getInvestigatedGrants(){ + return pIGrants; + } + + public int getNumberOfInvestigatedGrants(){ + return pIGrants.size(); + } + + public void addGrant(Grant grant){ + this.pIGrants.add(grant); + } + + public Map getYearToGrantCount(){ + if(yearToGrantCount == null){ + yearToGrantCount = UtilityFunctions.getYearToGrantCount(pIGrants); + } + return yearToGrantCount; + } + + /* + * getEarliest, Latest & Unknown Grant 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 getEarliestGrantYearCount() { + if (yearToGrantCount == null) { + yearToGrantCount = UtilityFunctions.getYearToGrantCount(pIGrants); + } + + /* + * We do not want to consider the default grant year when we are checking + * for the min or max grant year. + * */ + Set yearsToBeConsidered = new HashSet(yearToGrantCount.keySet()); + yearsToBeConsidered.remove(VOConstants.DEFAULT_PUBLICATION_YEAR); + + /* + * There can be a case when the only publication the author has no attached year to it + * so essentially an "Unknown". In that case Collections.max or min will throw an + * NoSuchElementException. + * + * If there is no maximum year available then we should imply so by returning a "null". + * */ + if (yearsToBeConsidered.size() > 0) { + final String earliestYear = Collections.min(yearsToBeConsidered); + final Integer earliestYearGrantCount = yearToGrantCount.get(earliestYear); + + return new HashMap() { { + put(earliestYear, earliestYearGrantCount); + } }; + } else { + return null; + } + } + + + @SuppressWarnings("serial") + public Map getLatestGrantYearCount() { + if (yearToGrantCount == null) { + yearToGrantCount = UtilityFunctions.getYearToGrantCount(pIGrants); + } + + /* + * We do not want to consider the default grant year when we are checking + * for the min or max grant year. + * */ + Set yearsToBeConsidered = new HashSet(yearToGrantCount.keySet()); + yearsToBeConsidered.remove(VOConstants.DEFAULT_PUBLICATION_YEAR); + + /* + * There can be a case when the only grant the PI has no attached year to it + * so essentially an "Unknown". In that case Collections.max or min will throw an + * NoSuchElementException. + * + * If there is no maximum year available then we should imply so by returning a "null". + * */ + if (yearsToBeConsidered.size() > 0) { + final String latestYear = Collections.max(yearsToBeConsidered); + final Integer latestYearGrantCount = yearToGrantCount.get(latestYear); + + return new HashMap() { { + put(latestYear, latestYearGrantCount); + } }; + } else { + return null; + } + + } + + public Integer getUnknownGrantYearCount() { + if (yearToGrantCount == null) { + yearToGrantCount = UtilityFunctions.getYearToGrantCount(pIGrants); + } + + Integer unknownYearGrantCount = yearToGrantCount + .get(VOConstants.DEFAULT_PUBLICATION_YEAR); + + /* + * If there is no unknown year available then we should imply so by returning a "null". + * */ + if (unknownYearGrantCount != null) { + return unknownYearGrantCount; + } else { + return null; + } + } +} diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/Department.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/Department.java new file mode 100644 index 00000000..51da237d --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/Department.java @@ -0,0 +1,54 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ +package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects; + +import java.util.Set; + +/** + * @author bkoniden + * Deepak Konidena + * + */ +public class Department extends Individual{ + + Set publication; + Set person; + + public Department(String departmentURI, String departmentLabel){ + super(departmentURI, departmentLabel); + } + + public void setDepartmentLabel(String departmentURI){ + this.setIndividualLabel(departmentURI); + } + + public String getDepartmentURI(){ + return this.getIndividualURI(); + } + + public Set getPublication() { + return publication; + } + + public String getDepartmentLabel(){ + return this.getIndividualLabel(); + } + + public Set getPerson() { + return person; + } + + public void addPublication(BiboDocument biboDocument) { + this.publication.add(biboDocument); + } + + public void addPersons(Person person) { + this.person.add(person); + + } + + public void addPerson(Person person) { + this.person.add(person); + + } + +} diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/Edge.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/Edge.java new file mode 100644 index 00000000..200edb38 --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/Edge.java @@ -0,0 +1,153 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.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.visutils.UniqueIDGenerator; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.UtilityFunctions; + +/** + * + * This is stores edge information mainly for co-author vis. + * + * @author cdtank + * + */ +public class Edge { + + private int edgeID; + private Map 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 = UtilityFunctions + .getYearToPublicationCount(collaboratorDocuments); + } + + /* + * We do not want to consider the default publication year when we are checking + * for the min or max publication year. + * */ + Set yearsToBeConsidered = new HashSet(yearToPublicationCount.keySet()); + yearsToBeConsidered.remove(VOConstants.DEFAULT_PUBLICATION_YEAR); + + /* + * There can be a case when the only publication the author has no attached year to it + * so essentially an "Unknown". In that case Collections.max or min will throw an + * NoSuchElementException. + * + * If there is no maximum year available then we should imply so by returning a "null". + * */ + if (yearsToBeConsidered.size() > 0) { + final String earliestYear = Collections.min(yearsToBeConsidered); + final Integer earliestYearPubCount = yearToPublicationCount.get(earliestYear); + + return new HashMap() { { + put(earliestYear, earliestYearPubCount); + } }; + } else { + return null; + } + } + + @SuppressWarnings("serial") + public Map getLatestCollaborationYearCount() { + if (yearToPublicationCount == null) { + yearToPublicationCount = UtilityFunctions + .getYearToPublicationCount(collaboratorDocuments); + } + + /* + * We do not want to consider the default publication year when we are checking + * for the min or max publication year. + * */ + Set yearsToBeConsidered = new HashSet(yearToPublicationCount.keySet()); + yearsToBeConsidered.remove(VOConstants.DEFAULT_PUBLICATION_YEAR); + + /* + * There can be a case when the only publication the author has no attached year to it + * so essentially an "Unknown". In that case Collections.max or min will throw an + * NoSuchElementException. + * + * If there is no maximum year available then we should imply so by returning a "null". + * */ + if (yearsToBeConsidered.size() > 0) { + final String latestYear = Collections.max(yearsToBeConsidered); + final Integer latestYearPubCount = yearToPublicationCount.get(latestYear); + + return new HashMap() { { + put(latestYear, latestYearPubCount); + } }; + } else { + return null; + } + } + + public Integer getUnknownCollaborationYearCount() { + if (yearToPublicationCount == null) { + yearToPublicationCount = UtilityFunctions + .getYearToPublicationCount(collaboratorDocuments); + } + + 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 unknownYearPubCount; + } else { + return null; + } + } + + +} diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/Entity.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/Entity.java new file mode 100644 index 00000000..8d32bc18 --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/Entity.java @@ -0,0 +1,51 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ +package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects; + +import java.util.HashSet; +import java.util.Set; +import java.util.LinkedHashSet; + +/** + * @author bkoniden + * Deepak Konidena + * + */ +public class Entity extends Individual{ + + Set publications = new HashSet(); + Set children = new LinkedHashSet(); + + public Entity(String departmentURI, String departmentLabel){ + super(departmentURI, departmentLabel); + } + + public void setDepartmentLabel(String departmentURI){ + this.setIndividualLabel(departmentURI); + } + + public String getEntityURI(){ + return this.getIndividualURI(); + } + + public Set getPublications() { + return publications; + } + + public String getEntityLabel(){ + return this.getIndividualLabel(); + } + + public Set getSubEntities() { + return children; + } + + public void addPublications(BiboDocument biboDocument) { + this.publications.add(biboDocument); + } + + public void addSubEntity(SubEntity subEntity) { + this.children.add(subEntity); + + } + +} diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/GenericQueryMap.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/GenericQueryMap.java new file mode 100644 index 00000000..f9b13d5f --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/GenericQueryMap.java @@ -0,0 +1,41 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; + +/** + * Right now this is just acting as a hashmap but in future we would want to provide + * more detailed info other than just what properties had what values. E.g. we + * could parse properties (& its values) to look for what namespaces are used. + * + * @author cdtank + */ +@SuppressWarnings("serial") +public class GenericQueryMap extends HashMap> { + + public GenericQueryMap() { + super(); + } + + public void addEntry(String property, String value) { + + Set values; + + if (this.containsKey(property)) { + + values = this.get(property); + values.add(value); + + } else { + + values = new HashSet(); + values.add(value); + this.put(property, values); + + } + } + +} diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/Grant.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/Grant.java new file mode 100644 index 00000000..eddcb8d3 --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/Grant.java @@ -0,0 +1,134 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ +package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects; + +import edu.cornell.mannlib.vitro.webapp.visualization.constants.VOConstants; + +/** + * @author bkoniden + * Deepak Konidena + * + */ + +public class Grant extends Individual { + + private String grantStartYear; + private String grantStartYearMonth; + private String grantStartDate; + private String grantEndYear; + private String grantEndYearMonth; + private String grantEndDate; + + public Grant(String grantURL, String grantLabel){ + super(grantURL, grantLabel); + } + + public Grant(String grantURL){ + super(grantURL); + } + + public String getGrantURL() { + return this.getIndividualURI(); + } + + public String getGrantLabel(){ + return this.getIndividualLabel(); + } + /** + * This method will be called when there is no usable core:year value found + * for the bibo:Document. It will first check & parse core:yearMonth failing + * which it will try core:date + * @return + */ + public String getParsedGrantStartYear() { + + /* + * We are assuming that core:yearMonth has "YYYY-MM-DD" format. This is based + * off of http://www.w3.org/TR/xmlschema-2/#gYearMonth , which is what + * core:yearMonth points to internally. + * */ + if (grantStartYearMonth != null + && grantStartYearMonth.length() >= VOConstants.NUM_CHARS_IN_YEAR_FORMAT + && isValidPublicationYear(grantStartYearMonth.substring( + 0, + VOConstants.NUM_CHARS_IN_YEAR_FORMAT))) { + + return grantStartYearMonth.substring(0, VOConstants.NUM_CHARS_IN_YEAR_FORMAT); + + } + + if (grantStartDate != null + && grantStartDate.length() >= VOConstants.NUM_CHARS_IN_YEAR_FORMAT + && isValidPublicationYear(grantStartDate + .substring(0, + VOConstants.NUM_CHARS_IN_YEAR_FORMAT))) { + + return grantStartDate.substring(0, VOConstants.NUM_CHARS_IN_YEAR_FORMAT); + } + + /* + * If all else fails return default unknown year identifier + * */ + return VOConstants.DEFAULT_GRANT_YEAR; + } + + public String getGrantStartYear() { + return grantStartYear; + } + + public void setGrantStartYear(String grantStartYear) { + this.grantStartYear = grantStartYear; + } + + public String getGrantStartYearMonth() { + return grantStartYearMonth; + } + + public void setGrantStartYearMonth(String grantStartYearMonth) { + this.grantStartYearMonth = grantStartYearMonth; + } + + public String getGrantStartDate() { + return grantStartDate; + } + + public void setGrantStartDate(String grantStartDate) { + this.grantStartDate = grantStartDate; + } + + public String getGrantEndYear() { + return grantEndYear; + } + + public void setGrantEndYear(String grantEndYear) { + this.grantEndYear = grantEndYear; + } + + public String getGrantEndYearMonth() { + return grantEndYearMonth; + } + + public void setGrantEndYearMonth(String grantEndYearMonth) { + this.grantEndYearMonth = grantEndYearMonth; + } + + public String getGrantEndDate() { + return grantEndDate; + } + + public void setGrantEndDate(String grantEndDate) { + this.grantEndDate = grantEndDate; + } + + private boolean isValidPublicationYear(String testGrantYear) { + + if (testGrantYear.length() != 0 + && testGrantYear.trim().length() == VOConstants.NUM_CHARS_IN_YEAR_FORMAT + && testGrantYear.matches("\\d+") + && Integer.parseInt(testGrantYear) >= VOConstants.MINIMUM_PUBLICATION_YEAR) { + return true; + } + + return false; + } + +} diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/Individual.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/Individual.java new file mode 100644 index 00000000..e3d3872f --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/Individual.java @@ -0,0 +1,32 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects; + +public class Individual { + + private String individualLabel; + private String individualURI; + + public Individual(String individualURI, String individualLabel) { + this.individualURI = individualURI; + this.individualLabel = individualLabel; + } + + public Individual(String individualURI) { + this(individualURI, ""); + } + + public String getIndividualLabel() { + return individualLabel; + } + + public void setIndividualLabel(String individualLabel) { + this.individualLabel = individualLabel; + } + + public String getIndividualURI() { + return individualURI; + } + + +} diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/JsonObject.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/JsonObject.java new file mode 100644 index 00000000..4fbae0ad --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/JsonObject.java @@ -0,0 +1,76 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ +package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects; + +import java.util.ArrayList; +import java.util.List; + +/** + * JsonObject is used for creating data in JSON format, + * by just using the fields that are required to be included. + * @author bkoniden + * Deepak Konidena + */ +public class JsonObject { + + private String label; + private List> data = new ArrayList>(); + private String entityURI; + private String visMode; + private List organizationType = new ArrayList(); + private List stopWords = new ArrayList(); + + public List getStopWords() { + return stopWords; + } + + public void setStopWords(List stopWords) { + this.stopWords = stopWords; + } + + public List getOrganizationType() { + return organizationType; + } + + public void setOrganizationType(List organizationType) { + this.organizationType = organizationType; + } + + public String getEntityURI() { + return entityURI; + } + + public void setEntityURI(String entityURI) { + this.entityURI = entityURI; + } + + public String getVisMode() { + return visMode; + } + + public void setVisMode(String visMode) { + this.visMode = visMode; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public List> getYearToPublicationCount() { + return data; + } + + + + public JsonObject(String label){ + this.label = label; + } + + public void setYearToPublicationCount(List> yearToPublicationCount){ + this.data = yearToPublicationCount; + } + +} diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/Node.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/Node.java new file mode 100644 index 00000000..04fddaff --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/Node.java @@ -0,0 +1,156 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.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.visutils.UniqueIDGenerator; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.UtilityFunctions; + +/** + * + * This stores 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 nodeURI, + UniqueIDGenerator uniqueIDGenerator) { + super(nodeURI); + nodeID = uniqueIDGenerator.getNextNumericID(); + } + + public int getNodeID() { + return nodeID; + } + + public String getNodeURI() { + return this.getIndividualURI(); + } + + 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); + } + + public Map getYearToPublicationCount() { + if (yearToPublicationCount == null) { + yearToPublicationCount = UtilityFunctions.getYearToPublicationCount(authorDocuments); + } + return yearToPublicationCount; + } + + /* + * 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 = UtilityFunctions.getYearToPublicationCount(authorDocuments); + } + + /* + * We do not want to consider the default publication year when we are checking + * for the min or max publication year. + * */ + Set yearsToBeConsidered = new HashSet(yearToPublicationCount.keySet()); + yearsToBeConsidered.remove(VOConstants.DEFAULT_PUBLICATION_YEAR); + + /* + * There can be a case when the only publication the author has no attached year to it + * so essentially an "Unknown". In that case Collections.max or min will throw an + * NoSuchElementException. + * + * If there is no maximum year available then we should imply so by returning a "null". + * */ + if (yearsToBeConsidered.size() > 0) { + final String earliestYear = Collections.min(yearsToBeConsidered); + final Integer earliestYearPubCount = yearToPublicationCount.get(earliestYear); + + return new HashMap() { { + put(earliestYear, earliestYearPubCount); + } }; + } else { + return null; + } + } + + @SuppressWarnings("serial") + public Map getLatestPublicationYearCount() { + if (yearToPublicationCount == null) { + yearToPublicationCount = UtilityFunctions.getYearToPublicationCount(authorDocuments); + } + + /* + * We do not want to consider the default publication year when we are checking + * for the min or max publication year. + * */ + Set yearsToBeConsidered = new HashSet(yearToPublicationCount.keySet()); + yearsToBeConsidered.remove(VOConstants.DEFAULT_PUBLICATION_YEAR); + + /* + * There can be a case when the only publication the author has no attached year to it + * so essentially an "Unknown". In that case Collections.max or min will throw an + * NoSuchElementException. + * + * If there is no maximum year available then we should imply so by returning a "null". + * */ + if (yearsToBeConsidered.size() > 0) { + final String latestYear = Collections.max(yearsToBeConsidered); + final Integer latestYearPubCount = yearToPublicationCount.get(latestYear); + + return new HashMap() { { + put(latestYear, latestYearPubCount); + } }; + } else { + return null; + } + + } + + public Integer getUnknownPublicationYearCount() { + if (yearToPublicationCount == null) { + yearToPublicationCount = UtilityFunctions.getYearToPublicationCount(authorDocuments); + } + + 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 unknownYearPubCount; + } else { + return null; + } + } +} diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/Person.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/Person.java new file mode 100644 index 00000000..abafa30b --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/Person.java @@ -0,0 +1,27 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ +package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects; + +import java.util.Set; +import java.util.HashSet; + +/** + * @author bkoniden + * Deepak Konidena + */ +public class Person extends Individual { + + Set documents = new HashSet(); + + public Person(String individualURI) { + super(individualURI); + } + + public Set getDocuments() { + return documents; + } + + public Person(String individualURI, String individualLabel) { + super(individualURI, individualLabel); + } + +} diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/SparklineData.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/SparklineData.java new file mode 100644 index 00000000..f30037c3 --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/SparklineData.java @@ -0,0 +1,181 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects; + +import java.util.List; +import java.util.Map; + +public class SparklineData { + + /* + * For now sparklineNumPublicationsText & sparklinePublicationRangeText is left + * as empty but later on we would want to leverage the granularity that this + * provides. + * */ + private String sparklineNumPublicationsText = ""; + private String sparklinePublicationRangeText = ""; + + private Integer earliestYearConsidered; + private Integer earliestRenderedPublicationYear; + private Integer latestRenderedPublicationYear; + + private Integer renderedSparks; + private Integer unknownYearPublications; + + private Map yearToActivityCount; + + private String table = ""; + + private String downloadDataLink = ""; + private String fullTimelineNetworkLink = ""; + + private String visContainerDivID = "pub_count_vis_container"; + private String sparklineContent; + private String sparklineContext; + + private boolean isShortVisMode = true; + + private List yearToPublicationCountDataTable; + + private int numOfYearsToBeRendered; + + public String getSparklineNumPublicationsText() { + return sparklineNumPublicationsText; + } + + public void setSparklineNumPublicationsText(String sparklineNumPublicationsText) { + this.sparklineNumPublicationsText = sparklineNumPublicationsText; + } + + public String getSparklinePublicationRangeText() { + return sparklinePublicationRangeText; + } + + public void setSparklinePublicationRangeText( + String sparklinePublicationRangeText) { + this.sparklinePublicationRangeText = sparklinePublicationRangeText; + } + + public void setNumOfYearsToBeRendered(int numOfYearsToBeRendered) { + this.numOfYearsToBeRendered = numOfYearsToBeRendered; + } + + public int getNumOfYearsToBeRendered() { + return numOfYearsToBeRendered; + } + + public void setYearToPublicationCountDataTable( + List yearToPublicationCountDataTable) { + this.yearToPublicationCountDataTable = yearToPublicationCountDataTable; + } + + public List getYearToPublicationCountDataTable() { + return yearToPublicationCountDataTable; + } + + public void setYearToActivityCount(Map yearToActivityCount) { + this.yearToActivityCount = yearToActivityCount; + } + + public Map getYearToActivityCount() { + return yearToActivityCount; + } + + public void setEarliestYearConsidered(Integer earliestYearConsidered) { + this.earliestYearConsidered = earliestYearConsidered; + } + + public Integer getEarliestYearConsidered() { + return earliestYearConsidered; + } + + public Integer getEarliestRenderedPublicationYear() { + return earliestRenderedPublicationYear; + } + + public void setEarliestRenderedPublicationYear( + Integer earliestRenderedPublicationYear) { + this.earliestRenderedPublicationYear = earliestRenderedPublicationYear; + } + + public Integer getLatestRenderedPublicationYear() { + return latestRenderedPublicationYear; + } + + public void setLatestRenderedPublicationYear( + Integer latestRenderedPublicationYear) { + this.latestRenderedPublicationYear = latestRenderedPublicationYear; + } + + public void setUnknownYearPublications(Integer unknownYearPublications) { + this.unknownYearPublications = unknownYearPublications; + } + + public Integer getUnknownYearPublications() { + return unknownYearPublications; + } + + public void setRenderedSparks(Integer renderedSparks) { + this.renderedSparks = renderedSparks; + } + + public Integer getRenderedSparks() { + return renderedSparks; + } + + public String getTable() { + return table; + } + + public void setTable(String table) { + this.table = table; + } + + public String getDownloadDataLink() { + return downloadDataLink; + } + + public void setDownloadDataLink(String downloadDataLink) { + this.downloadDataLink = downloadDataLink; + } + + public String getFullTimelineNetworkLink() { + return fullTimelineNetworkLink; + } + + public void setFullTimelineNetworkLink(String fullTimelineNetworkLink) { + this.fullTimelineNetworkLink = fullTimelineNetworkLink; + } + + public void setVisContainerDivID(String visContainerDivID) { + this.visContainerDivID = visContainerDivID; + } + + public String getVisContainerDivID() { + return visContainerDivID; + } + + public String getSparklineContent() { + return sparklineContent; + } + + public void setSparklineContent(String shortSparklineContent) { + this.sparklineContent = shortSparklineContent; + } + + public void setShortVisMode(boolean isShortVisMode) { + this.isShortVisMode = isShortVisMode; + } + + public boolean isShortVisMode() { + return isShortVisMode; + } + + public String getSparklineContext() { + return sparklineContext; + } + + public void setSparklineContext(String shortSparklineContext) { + this.sparklineContext = shortSparklineContext; + } +} diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/SubEntity.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/SubEntity.java new file mode 100644 index 00000000..5f6aaa8e --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/SubEntity.java @@ -0,0 +1,59 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ +package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.HashSet; + +/** + * @author bkoniden + * Deepak Konidena + */ +public class SubEntity extends Individual { + + Set publications = new HashSet(); + Map> personToPositionAndStartYear = new HashMap>(); + + public SubEntity(String individualURI) { + super(individualURI); + } + + + public Map> getPersonToPositionAndStartYear() { + return personToPositionAndStartYear; + } + + public void setPersonToPositionAndStartYear( + Map> personToPositionAndStartYear) { + this.personToPositionAndStartYear = personToPositionAndStartYear; + } + + public Set getDocuments() { + return publications; + } + + public SubEntity(String individualURI, String individualLabel) { + super(individualURI, individualLabel); + } + + @Override + public boolean equals(Object other){ + boolean result = false; + if (other instanceof SubEntity){ + SubEntity person = (SubEntity) other; + result = (this.getIndividualLabel().equals(person.getIndividualLabel()) + && this.getIndividualURI().equals(person.getIndividualURI())); + } + return result; + } + + @Override + public int hashCode(){ + return(41*(getIndividualLabel().hashCode() + 41*(getIndividualURI().hashCode()))); + } + + public void addPublications(BiboDocument biboDocument) { + this.publications.add(biboDocument); + } +} diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/YearPublicationCountDataElement.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/YearPublicationCountDataElement.java new file mode 100644 index 00000000..e9bd9e4c --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/YearPublicationCountDataElement.java @@ -0,0 +1,34 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects; + +/** + * This object is used to store information about the yearToPublicationCount Map in the format + * easily expressed to Google Visualization's DataTableAPI. + * @author cdtank + * + */ +public class YearPublicationCountDataElement { + + private int publicationCounter; + private String publishedYear; + private int currentPublications; + + public YearPublicationCountDataElement(int publicationCounter, + String publishedYear, int currentPublications) { + this.publicationCounter = publicationCounter; + this.publishedYear = publishedYear; + this.currentPublications = currentPublications; + } + + public int getPublicationCounter() { + return publicationCounter; + } + + public String getPublishedYear() { + return publishedYear; + } + + public int getCurrentPublications() { + return currentPublications; + } + +} diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/visutils/UniqueIDGenerator.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/visutils/UniqueIDGenerator.java new file mode 100644 index 00000000..b41995b6 --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/visutils/UniqueIDGenerator.java @@ -0,0 +1,16 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils; + +public class UniqueIDGenerator { + + private int nextNumericID = 1; + + public int getNextNumericID() { + int nextNumericID = this.nextNumericID; + this.nextNumericID++; + + return nextNumericID; + } + +} diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/visutils/UtilityFunctions.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/visutils/UtilityFunctions.java new file mode 100644 index 00000000..87465af7 --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/visutils/UtilityFunctions.java @@ -0,0 +1,250 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +import org.apache.commons.lang.StringUtils; + +import edu.cornell.mannlib.vitro.webapp.beans.Portal; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues; +import edu.cornell.mannlib.vitro.webapp.controller.visualization.VisualizationFrameworkConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.constants.VisConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.BiboDocument; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.CoAuthorshipData; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.CoPIData; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.Grant; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.CoPINode; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.Node; + +public class UtilityFunctions { + + public static 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. + * + * I am pushing the logic to check for validity of year in "getPublicationYear" itself + * because, + * 1. We will be using getPub... multiple times & this will save us duplication of code + * 2. If we change the logic of validity of a pub year we would not have to make + * changes all throughout the codebase. + * 3. We are asking for a publication year & we should get a proper one or NOT at all. + * */ + String publicationYear; + if (curr.getPublicationYear() != null) { + publicationYear = curr.getPublicationYear(); + } else { + publicationYear = curr.getParsedPublicationYear(); + } + + if (yearToPublicationCount.containsKey(publicationYear)) { + yearToPublicationCount.put(publicationYear, + yearToPublicationCount + .get(publicationYear) + 1); + + } else { + yearToPublicationCount.put(publicationYear, 1); + } + + } + + return yearToPublicationCount; + } + + /** + * This method is used to return a mapping between publication year & all the co-authors + * that published with ego in that year. + * @param authorNodesAndEdges + * @return + */ + public static Map> getPublicationYearToCoAuthors( + CoAuthorshipData authorNodesAndEdges) { + + Map> yearToCoAuthors = new TreeMap>(); + + Node egoNode = authorNodesAndEdges.getEgoNode(); + + for (Node currNode : authorNodesAndEdges.getNodes()) { + + /* + * We have already printed the Ego Node info. + * */ + if (currNode != egoNode) { + + for (String year : currNode.getYearToPublicationCount().keySet()) { + + Set coAuthorNodes; + + if (yearToCoAuthors.containsKey(year)) { + + coAuthorNodes = yearToCoAuthors.get(year); + coAuthorNodes.add(currNode); + + } else { + + coAuthorNodes = new HashSet(); + coAuthorNodes.add(currNode); + yearToCoAuthors.put(year, coAuthorNodes); + } + + } + + } + } + return yearToCoAuthors; + } + + /** + * Currently the approach for slugifying filenames is naive. In future if there is need, + * we can write more sophisticated method. + * @param textToBeSlugified + * @return + */ + public static String slugify(String textToBeSlugified) { + String textBlockSeparator = "-"; + return StringUtils.removeEnd(StringUtils.substring(textToBeSlugified.toLowerCase().trim() + .replaceAll("[^a-zA-Z0-9-]+", textBlockSeparator), + 0, + VisConstants.MAX_NAME_TEXT_LENGTH), + textBlockSeparator); + } + + + public static ResponseValues handleMalformedParameters(String errorPageTitle, String errorMessage, VitroRequest vitroRequest) { + + Portal portal = vitroRequest.getPortal(); + + Map body = new HashMap(); + body.put("portalBean", portal); + body.put("error", errorMessage); + body.put("title", errorPageTitle); + + return new TemplateResponseValues(VisualizationFrameworkConstants.ERROR_TEMPLATE, body); + } + +/* public static void handleMalformedParameters(String errorMessage, + String errorPageTitle, + VitroRequest vitroRequest, + HttpServletRequest request, + HttpServletResponse response, + Log log) + 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", errorPageTitle); + + try { + requestDispatcher.forward(request, response); + } catch (Exception e) { + log.error("EntityEditController could not forward to view."); + log.error(e.getMessage()); + log.error(e.getStackTrace()); + } + }*/ + + public static Map> getGrantYearToCoPI( + CoPIData pINodesAndEdges) { + + + Map> yearToCoPIs = new TreeMap>(); + + CoPINode egoNode = pINodesAndEdges.getEgoNode(); + + for (CoPINode currNode : pINodesAndEdges.getNodes()) { + + /* + * We have already printed the Ego Node info. + * */ + if (currNode != egoNode) { + + for (String year : currNode.getYearToGrantCount().keySet()) { + + Set coPINodes; + + if (yearToCoPIs.containsKey(year)) { + + coPINodes = yearToCoPIs.get(year); + coPINodes.add(currNode); + + } else { + + coPINodes = new HashSet(); + coPINodes.add(currNode); + yearToCoPIs.put(year, coPINodes); + } + + } + + } + } + return yearToCoPIs; + + } + + public static Map getYearToGrantCount(Set pIGrants) { + + /* + * Create a map from the year to number of grants. Use the Grant's + * parsedGrantStartYear to populate the data. + * */ + Map yearToGrantCount = new TreeMap(); + + for (Grant curr : pIGrants) { + + /* + * Increment the count because there is an entry already available for + * that particular year. + * + * I am pushing the logic to check for validity of year in "getGrantYear" itself + * because, + * 1. We will be using getGra... multiple times & this will save us duplication of code + * 2. If we change the logic of validity of a grant year we would not have to make + * changes all throughout the codebase. + * 3. We are asking for a grant year & we should get a proper one or NOT at all. + * */ + String grantYear; + if (curr.getGrantStartYear() != null) { + grantYear = curr.getGrantStartYear(); + } else { + grantYear = curr.getParsedGrantStartYear(); + } + + if (yearToGrantCount.containsKey(grantYear)) { + yearToGrantCount.put(grantYear, + yearToGrantCount + .get(grantYear) + 1); + + } else { + yearToGrantCount.put(grantYear, 1); + } + + } + + return yearToGrantCount; + + } + +} diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/visutils/VisualizationRequestHandler.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/visutils/VisualizationRequestHandler.java new file mode 100644 index 00000000..fd18905d --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/visutils/VisualizationRequestHandler.java @@ -0,0 +1,27 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ +package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils; + +import org.apache.commons.logging.Log; + +import com.hp.hpl.jena.query.DataSource; + +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues; + +/** + * This interface is being implemented by all the visualization request handlers like + * PersonLevelRequestHandler, PersonPublicationCountRequestHandler, UtilitiesRequestHandler + * etc. All the future visualizations must implement this because the ability of + * a visualization to be served to the users is dependent on it. We have implemented + * dependency injection mechanism & one of the conditions that is used to enable a visualization + * handler is its implementation of VisualizationRequestHandler. + * + * @author cdtank + */ +public interface VisualizationRequestHandler{ + + ResponseValues generateVisualization(VitroRequest vitroRequest, + Log log, + DataSource dataSource); + +}