diff --git a/productMods/WEB-INF/visualization/visualizations-beans-injection-fm.xml b/productMods/WEB-INF/visualization/visualizations-beans-injection-fm.xml index 22a3d0a9..0700f430 100644 --- a/productMods/WEB-INF/visualization/visualizations-beans-injection-fm.xml +++ b/productMods/WEB-INF/visualization/visualizations-beans-injection-fm.xml @@ -12,13 +12,15 @@ + + + diff --git a/productMods/templates/freemarker/visualization/personlevel/personLevelInjectHead.ftl b/productMods/templates/freemarker/visualization/personlevel/personLevelInjectHead.ftl new file mode 100644 index 00000000..d3f9e354 --- /dev/null +++ b/productMods/templates/freemarker/visualization/personlevel/personLevelInjectHead.ftl @@ -0,0 +1,17 @@ +<#-- $This file is distributed under the terms of the license in /doc/license.txt$ --> + +<#assign visualizationURLRoot ="/visualization"> + +<#assign egoURI ="${egoURIParam?url}"> + +<#assign egoCoAuthorshipDataFeederURL = '${urls.base}${visualizationURLRoot}?vis=coauthorship&uri=${egoURI}&render_mode=data&labelField=label'> + +<#assign egoCoPIDataFeederURL = '${urls.base}${visualizationURLRoot}?vis=coprincipalinvestigator&uri=${egoURI}&render_mode=data&labelField=label'> + +<#assign egoCoAuthorsListDataFileURL = '${urls.base}${visualizationURLRoot}?vis=person_level&uri=${egoURI}&render_mode=data&vis_mode=coauthors'> + +<#assign swfLink = '${urls.images}/visualization/coauthorship/EgoCentric.swf'> + + + + diff --git a/productMods/templates/freemarker/visualization/publicationSparklineContent.ftl b/productMods/templates/freemarker/visualization/publicationSparklineContent.ftl index c94c8fc8..f5406915 100644 --- a/productMods/templates/freemarker/visualization/publicationSparklineContent.ftl +++ b/productMods/templates/freemarker/visualization/publicationSparklineContent.ftl @@ -69,8 +69,6 @@ <#if sparklineVO.shortVisMode> - console.log("Yay! Short Vis Mode!"); - <#-- For the short view we only want the last 10 year's view of publication count, hence we filter the data we actually want to use for render. --> @@ -85,8 +83,6 @@ <#else> - console.log("Yay! Full Vis Mode!"); - @@ -175,8 +171,6 @@ row.append(sparklineImgTD); - console.log(sparklineImgTD); - var sparklineNumberTD = $(''); sparklineNumberTD.attr('width', '30'); sparklineNumberTD.attr('align', 'right'); @@ -191,8 +185,6 @@ } - console.log(sparklineImgTD); - drawPubCountVisualization(sparklineImgTD); }); 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 4d065348..22418b1d 100644 --- a/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/VisualizationFrameworkConstants.java +++ b/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/VisualizationFrameworkConstants.java @@ -25,6 +25,8 @@ public class VisualizationFrameworkConstants { */ public static final String VISUALIZATION_URL_PREFIX = "/visualization"; public static final String FREEMARKERIZED_VISUALIZATION_URL_PREFIX = "/visualizationfm"; + public static final String AJAX_VISUALIZATION_SERVICE_URL_PREFIX = "/visualizationAjax"; + public static final String DATA_VISUALIZATION_SERVICE_URL_PREFIX = "/visualizationData"; public static final String INDIVIDUAL_URL_PREFIX = "/individual"; @@ -85,6 +87,5 @@ public class VisualizationFrameworkConstants { public static final String ENTITY_COMPARISON_VIS = "entity_comparison"; public static final String CO_PI_VIS = "coprincipalinvestigator"; - } diff --git a/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/freemarker/VisualizationController.java b/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/freemarker/AjaxVisualizationController.java similarity index 65% rename from src/edu/cornell/mannlib/vitro/webapp/controller/visualization/freemarker/VisualizationController.java rename to src/edu/cornell/mannlib/vitro/webapp/controller/visualization/freemarker/AjaxVisualizationController.java index f57526b7..07f748d5 100644 --- a/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/freemarker/VisualizationController.java +++ b/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/freemarker/AjaxVisualizationController.java @@ -9,12 +9,8 @@ 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; @@ -28,6 +24,7 @@ import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.Res 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.exceptions.MalformedQueryParametersException; import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.UtilityFunctions; import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.VisualizationRequestHandler; import freemarker.template.Configuration; @@ -39,75 +36,34 @@ import freemarker.template.Configuration; * @author cdtank */ @SuppressWarnings("serial") -public class VisualizationController extends FreemarkerHttpServlet { - - private Map visualizationIDsToClass; +public class AjaxVisualizationController extends FreemarkerHttpServlet { public static final String URL_ENCODING_SCHEME = "UTF-8"; - private static final Log log = LogFactory.getLog(VisualizationController.class.getName()); + private static final Log log = LogFactory.getLog(AjaxVisualizationController.class.getName()); protected static final Syntax SYNTAX = Syntax.syntaxARQ; @Override public void doGet(HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException { + throws IOException, ServletException { VitroRequest vreq = new VitroRequest(request); - - String renderMode = vreq.getParameter(VisualizationFrameworkConstants - .RENDER_MODE_KEY); - - if (StringUtils.equalsIgnoreCase(renderMode, VisualizationFrameworkConstants.DYNAMIC_RENDER_MODE)) { - - Configuration config = getConfig(vreq); - TemplateResponseValues trv = (TemplateResponseValues) processRequest(vreq); - writeTemplate(trv.getTemplateName(), trv.getMap(), config, request, response); - - } else { - 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 { + + Object ajaxResponse = processAjaxRequest(vreq); + + if (ajaxResponse instanceof TemplateResponseValues) { - String resourcePath = - getServletContext() - .getRealPath(VisualizationFrameworkConstants - .RELATIVE_LOCATION_OF_FM_VISUALIZATIONS_BEAN); + Configuration config = getConfig(vreq); + TemplateResponseValues trv = (TemplateResponseValues) ajaxResponse; + writeTemplate(trv.getTemplateName(), trv.getMap(), config, request, response); - ApplicationContext context = new ClassPathXmlApplicationContext( - "file:" + resourcePath); - - BeanFactory factory = context; - - VisualizationInjector visualizationInjector = - (VisualizationInjector) factory.getBean("visualizationInjector"); - - visualizationIDsToClass = visualizationInjector.getVisualizationIDToClass(); - - } catch (Exception e) { - log.error(e); + } else { + response.getWriter().write(ajaxResponse.toString()); } - } + } - - - @Override - protected ResponseValues processRequest(VitroRequest vreq) { - + private Object processAjaxRequest(VitroRequest vreq) { /* * Based on the query parameters passed via URI get the appropriate visualization * request handler. @@ -131,12 +87,10 @@ public class VisualizationController extends FreemarkerHttpServlet { vreq); } - - } - private ResponseValues renderVisualization(VitroRequest vitroRequest, + private Object renderVisualization(VitroRequest vitroRequest, VisualizationRequestHandler visRequestHandler) { Model model = vitroRequest.getJenaOntModel(); // getModel() @@ -158,9 +112,17 @@ public class VisualizationController extends FreemarkerHttpServlet { if (dataSource != null && visRequestHandler != null) { - return visRequestHandler.generateVisualization(vitroRequest, - log, - dataSource); + try { + return visRequestHandler.generateAjaxVisualization(vitroRequest, + log, + dataSource); + } catch (MalformedQueryParametersException e) { + return UtilityFunctions.handleMalformedParameters( + "Ajax Visualization Query Error - Individual Publication Count", + e.getMessage(), + vitroRequest); + + } } else { @@ -184,10 +146,10 @@ public class VisualizationController extends FreemarkerHttpServlet { .VIS_TYPE_KEY); VisualizationRequestHandler visRequestHandler = null; - System.out.println(visType + " --> " + visualizationIDsToClass); - try { - visRequestHandler = visualizationIDsToClass.get(visType); + visRequestHandler = VisualizationsDependencyInjector + .getVisualizationIDsToClassMap(getServletContext()).get(visType); + } catch (NullPointerException nullKeyException) { return null; diff --git a/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/freemarker/DataVisualizationController.java b/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/freemarker/DataVisualizationController.java new file mode 100644 index 00000000..a02bb4b2 --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/freemarker/DataVisualizationController.java @@ -0,0 +1,178 @@ +/* $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.logging.Log; +import org.apache.commons.logging.LogFactory; + +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.VitroHttpServlet; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +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.exceptions.MalformedQueryParametersException; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.UtilityFunctions; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.VisualizationRequestHandler; + +/** + * 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 DataVisualizationController extends VitroHttpServlet { + + public static final String URL_ENCODING_SCHEME = "UTF-8"; + + private static final Log log = LogFactory.getLog(DataVisualizationController.class.getName()); + + protected static final Syntax SYNTAX = Syntax.syntaxARQ; + + public static final String FILE_CONTENT_TYPE_KEY = "fileContentType"; + public static final String FILE_CONTENT_KEY = "fileContent"; + public static final String FILE_NAME_KEY = "fileName"; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException { + + VitroRequest vreq = new VitroRequest(request); + + /* + * 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. + * */ + try { + + Map dataResponse = renderVisualization(vreq, visRequestHandler); + + response.setContentType(dataResponse.get(FILE_CONTENT_TYPE_KEY)); + + if (dataResponse.containsKey(FILE_NAME_KEY)) { + response.setHeader("Content-Disposition", + "attachment;filename=" + dataResponse.get(FILE_NAME_KEY)); + } + + response.getWriter().write(dataResponse.get(FILE_CONTENT_KEY)); + + return; + + } catch (MalformedQueryParametersException e) { + + UtilityFunctions.handleMalformedParameters("Visualization Query Error", + e.getMessage(), + vreq, + request, + response, + log); + + } + + return; + + } else { + + UtilityFunctions.handleMalformedParameters("Visualization Query Error", + "Inappropriate query parameters were submitted.", + vreq, + request, + response, + log); + + } + + + } + + + private Map renderVisualization( + VitroRequest vitroRequest, + VisualizationRequestHandler visRequestHandler) + throws MalformedQueryParametersException { + + 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); + + throw new MalformedQueryParametersException(errorMessage); + } + + DataSource dataSource = setupJENADataSource(model, vitroRequest); + + if (dataSource != null && visRequestHandler != null) { + return visRequestHandler.generateDataVisualization(vitroRequest, + log, + dataSource); + + } else { + + String errorMessage = "Data Model Empty &/or Inappropriate " + + "query parameters were submitted. "; + + throw new MalformedQueryParametersException(errorMessage); + + } + } + + private VisualizationRequestHandler getVisualizationRequestHandler( + VitroRequest vitroRequest) { + + String visType = vitroRequest.getParameter(VisualizationFrameworkConstants + .VIS_TYPE_KEY); + VisualizationRequestHandler visRequestHandler = null; + + + try { + visRequestHandler = VisualizationsDependencyInjector + .getVisualizationIDsToClassMap(getServletContext()) + .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/StandardVisualizationController.java b/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/freemarker/StandardVisualizationController.java new file mode 100644 index 00000000..efdbaf3a --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/freemarker/StandardVisualizationController.java @@ -0,0 +1,147 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.controller.visualization.freemarker; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +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.visualization.VisualizationFrameworkConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.constants.VisConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.exceptions.MalformedQueryParametersException; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.UtilityFunctions; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.VisualizationRequestHandler; + +/** + * Services a standard visualization request, which involves templates. This will return a simple error message and a 501 if + * there is no jena Model. + * + * @author cdtank + */ +@SuppressWarnings("serial") +public class StandardVisualizationController extends FreemarkerHttpServlet { + + public static final String URL_ENCODING_SCHEME = "UTF-8"; + + private static final Log log = LogFactory.getLog(StandardVisualizationController.class.getName()); + + protected static final Syntax SYNTAX = Syntax.syntaxARQ; + + @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) { + + try { + return visRequestHandler.generateStandardVisualization(vitroRequest, + log, + dataSource); + } catch (MalformedQueryParametersException e) { + return UtilityFunctions.handleMalformedParameters( + "Standard Visualization Query Error - Individual Publication Count", + e.getMessage(), + vitroRequest); + } + + } 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; + + try { + visRequestHandler = VisualizationsDependencyInjector + .getVisualizationIDsToClassMap(getServletContext()) + .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/VisualizationsDependencyInjector.java b/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/freemarker/VisualizationsDependencyInjector.java new file mode 100644 index 00000000..26147e8d --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/freemarker/VisualizationsDependencyInjector.java @@ -0,0 +1,64 @@ +package edu.cornell.mannlib.vitro.webapp.controller.visualization.freemarker; + +import java.util.Map; + +import javax.servlet.ServletContext; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +import edu.cornell.mannlib.vitro.webapp.controller.visualization.VisualizationFrameworkConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.VisualizationRequestHandler; + +public class VisualizationsDependencyInjector { + + private static Map visualizationIDsToClass; + + /** + * This method is used 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. + * @param servletContext + * @return + */ + private synchronized static Map initVisualizations( + ServletContext servletContext) { + + /* + * A visualization request has already been made causing the visualizationIDsToClass to be + * initiated & populated with visualization ids to its request handlers. + * */ + if (visualizationIDsToClass != null) { + return visualizationIDsToClass; + } + + String resourcePath = + servletContext + .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(); + + + return visualizationIDsToClass; + } + + public static Map getVisualizationIDsToClassMap( + ServletContext servletContext) { + if (visualizationIDsToClass != null) { + return visualizationIDsToClass; + } else { + return initVisualizations(servletContext); + } + } + +} diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/coauthorship/CoAuthorshipGraphMLWriter.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/coauthorship/CoAuthorshipGraphMLWriter.java new file mode 100644 index 00000000..0828f12e --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/coauthorship/CoAuthorshipGraphMLWriter.java @@ -0,0 +1,332 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.coauthorship; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import edu.cornell.mannlib.vitro.webapp.controller.visualization.freemarker.StandardVisualizationController; +import edu.cornell.mannlib.vitro.webapp.controller.visualization.VisualizationFrameworkConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.CoAuthorshipData; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.Edge; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.Node; + +public class CoAuthorshipGraphMLWriter { + + private StringBuilder coAuthorshipGraphMLContent; + + private final String GRAPHML_HEADER = "\n" + + " \n\n"; + + private final String GRAPHML_FOOTER = ""; + + public CoAuthorshipGraphMLWriter(CoAuthorshipData visVOContainer) { + + coAuthorshipGraphMLContent = createCoAuthorshipGraphMLContent(visVOContainer); + + } + + public StringBuilder getCoAuthorshipGraphMLContent() { + return coAuthorshipGraphMLContent; + } + + private StringBuilder createCoAuthorshipGraphMLContent( + CoAuthorshipData coAuthorshipData) { + + StringBuilder graphMLContent = new StringBuilder(); + + graphMLContent.append(GRAPHML_HEADER); + + /* + * We are side-effecting "graphMLContent" object in this method since creating + * another String object to hold key definition data will be redundant & will + * not serve the purpose. + * */ + generateKeyDefinitionContent(coAuthorshipData, graphMLContent); + + /* + * Used to generate graph content. It will contain both the nodes & edge information. + * We are side-effecting "graphMLContent". + * */ + generateGraphContent(coAuthorshipData, graphMLContent); + + graphMLContent.append(GRAPHML_FOOTER); + + return graphMLContent; + } + + private void generateGraphContent(CoAuthorshipData coAuthorshipData, + StringBuilder graphMLContent) { + + graphMLContent.append("\n\n"); + + if (coAuthorshipData.getNodes() != null & coAuthorshipData.getNodes().size() > 0) { + generateNodeSectionContent(coAuthorshipData, graphMLContent); + } + + if (coAuthorshipData.getEdges() != null & coAuthorshipData.getEdges().size() > 0) { + generateEdgeSectionContent(coAuthorshipData, graphMLContent); + } + + graphMLContent.append("\n"); + + + + + } + + private void generateEdgeSectionContent(CoAuthorshipData coAuthorshipData, + StringBuilder graphMLContent) { + + graphMLContent.append("\n"); + + Set edges = coAuthorshipData.getEdges(); + + List orderedEdges = new ArrayList(edges); + + Collections.sort(orderedEdges, new EdgeComparator()); + + for (Edge currentEdge : orderedEdges) { + + /* + * This method actually creates the XML code for a single edge. "graphMLContent" + * is being side-effected. + * */ + getEdgeContent(graphMLContent, currentEdge); + + } + + } + + private void getEdgeContent(StringBuilder graphMLContent, Edge currentEdge) { + + graphMLContent.append("\n"); + + graphMLContent.append("\t" + + currentEdge.getSourceNode().getNodeName() + + "\n"); + + graphMLContent.append("\t" + + currentEdge.getTargetNode().getNodeName() + + "\n"); + + graphMLContent.append("\t" + + currentEdge.getNumOfCoAuthoredWorks() + + "\n"); + + if (currentEdge.getEarliestCollaborationYearCount() != null) { + + /* + * There is no clean way of getting the map contents in java even though + * we are sure to have only one entry on the map. So using the for loop. + * */ + for (Map.Entry publicationInfo + : currentEdge.getEarliestCollaborationYearCount().entrySet()) { + + graphMLContent.append("\t" + + publicationInfo.getKey() + + "\n"); + + graphMLContent.append("\t" + + publicationInfo.getValue() + + "\n"); + } + + } + + if (currentEdge.getLatestCollaborationYearCount() != null) { + + for (Map.Entry publicationInfo + : currentEdge.getLatestCollaborationYearCount().entrySet()) { + + graphMLContent.append("\t" + + publicationInfo.getKey() + + "\n"); + + graphMLContent.append("\t" + + publicationInfo.getValue() + + "\n"); + } + + } + + if (currentEdge.getUnknownCollaborationYearCount() != null) { + + graphMLContent.append("\t" + + currentEdge.getUnknownCollaborationYearCount() + + "\n"); + + } + + graphMLContent.append("\n"); + } + + private void generateNodeSectionContent(CoAuthorshipData coAuthorshipData, + StringBuilder graphMLContent) { + + graphMLContent.append("\n"); + + Node egoNode = coAuthorshipData.getEgoNode(); + Set authorNodes = coAuthorshipData.getNodes(); + + /* + * This method actually creates the XML code for a single node. "graphMLContent" + * is being side-effected. The egoNode is added first because this is the "requirement" + * of the co-author vis. Ego should always come first. + * + * */ + getNodeContent(graphMLContent, egoNode); + + List orderedAuthorNodes = new ArrayList(authorNodes); + orderedAuthorNodes.remove(egoNode); + + Collections.sort(orderedAuthorNodes, new NodeComparator()); + + + for (Node currNode : orderedAuthorNodes) { + + /* + * We have already printed the Ego Node info. + * */ + if (currNode != egoNode) { + + getNodeContent(graphMLContent, currNode); + + } + + } + + } + + private void getNodeContent(StringBuilder graphMLContent, Node node) { + + String profileURL = null; + try { + profileURL = VisualizationFrameworkConstants.INDIVIDUAL_URL_PREFIX + "?" + + VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY + + "=" + URLEncoder.encode(node.getNodeURI(), + StandardVisualizationController + .URL_ENCODING_SCHEME).toString(); + } catch (UnsupportedEncodingException e) { + System.err.println("URL Encoding ERRor. Move this to use log.error ASAP"); + } + + graphMLContent.append("\n"); + graphMLContent.append("\t" + node.getNodeURI() + "\n"); + graphMLContent.append("\t" + node.getNodeName() + "\n"); + + if (profileURL != null) { + graphMLContent.append("\t" + profileURL + "\n"); + } + + + graphMLContent.append("\t" + + node.getNumOfAuthoredWorks() + + "\n"); + + if (node.getEarliestPublicationYearCount() != null) { + + /* + * There is no clean way of getting the map contents in java even though + * we are sure to have only one entry on the map. So using the for loop. + * I am feeling dirty just about now. + * */ + for (Map.Entry publicationInfo + : node.getEarliestPublicationYearCount().entrySet()) { + + graphMLContent.append("\t" + + publicationInfo.getKey() + + "\n"); + + graphMLContent.append("\t" + + publicationInfo.getValue() + + "\n"); + } + + } + + if (node.getLatestPublicationYearCount() != null) { + + for (Map.Entry publicationInfo + : node.getLatestPublicationYearCount().entrySet()) { + + graphMLContent.append("\t" + + publicationInfo.getKey() + + "\n"); + + graphMLContent.append("\t" + + publicationInfo.getValue() + + "\n"); + } + + } + + if (node.getUnknownPublicationYearCount() != null) { + + graphMLContent.append("\t" + + node.getUnknownPublicationYearCount() + + "\n"); + + } + + graphMLContent.append("\n"); + } + + private void generateKeyDefinitionContent(CoAuthorshipData visVOContainer, + StringBuilder graphMLContent) { + + /* + * Generate the key definition content for node. + * */ + getKeyDefinitionFromSchema(visVOContainer.getNodeSchema(), graphMLContent); + + /* + * Generate the key definition content for edge. + * */ + getKeyDefinitionFromSchema(visVOContainer.getEdgeSchema(), graphMLContent); + + + } + + private void getKeyDefinitionFromSchema(Set> schema, + StringBuilder graphMLContent) { + + for (Map currentNodeSchemaAttribute : schema) { + + graphMLContent.append("\n currentAttributeKey + : currentNodeSchemaAttribute.entrySet()) { + + graphMLContent.append(currentAttributeKey.getKey() + + "=\"" + currentAttributeKey.getValue() + + "\" "); + + } + + if (currentNodeSchemaAttribute.containsKey("default")) { + + graphMLContent.append(">\n"); + graphMLContent.append(""); + graphMLContent.append(currentNodeSchemaAttribute.get("default")); + graphMLContent.append("\n"); + graphMLContent.append("\n"); + + } else { + graphMLContent.append("/>\n"); + } + } + } +} diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/coauthorship/CoAuthorshipQueryRunner.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/coauthorship/CoAuthorshipQueryRunner.java new file mode 100644 index 00000000..0644a497 --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/coauthorship/CoAuthorshipQueryRunner.java @@ -0,0 +1,488 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.coauthorship; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +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.CoAuthorshipData; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.Edge; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.Node; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.QueryRunner; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.UniqueIDGenerator; + +/** + * This query runner is used to execute a sparql query to get all the publications + * for a particular individual. It will also fetch all the authors that worked + * on that particular publication. + * + * @author cdtank + */ +public class CoAuthorshipQueryRunner implements QueryRunner { + + private static final int MAX_AUTHORS_PER_PAPER_ALLOWED = 100; + + protected static final Syntax SYNTAX = Syntax.syntaxARQ; + + private String egoURI; + + private DataSource dataSource; + + private Log log; + + private UniqueIDGenerator nodeIDGenerator; + + private UniqueIDGenerator edgeIDGenerator; + + public CoAuthorshipQueryRunner(String egoURI, + DataSource dataSource, Log log) { + + this.egoURI = egoURI; + this.dataSource = dataSource; + this.log = log; + + this.nodeIDGenerator = new UniqueIDGenerator(); + this.edgeIDGenerator = new UniqueIDGenerator(); + + } + + private CoAuthorshipData createQueryResult(ResultSet resultSet) { + + Set nodes = new HashSet(); + + Map biboDocumentURLToVO = new HashMap(); + Map> biboDocumentURLToCoAuthors = new HashMap>(); + Map nodeURLToVO = new HashMap(); + Map edgeUniqueIdentifierToVO = new HashMap(); + + Node egoNode = null; + + Set edges = new HashSet(); + + while (resultSet.hasNext()) { + QuerySolution solution = resultSet.nextSolution(); + + /* + * We only want to create only ONE ego node. + * */ + RDFNode egoAuthorURLNode = solution.get(QueryFieldLabels.AUTHOR_URL); + if (nodeURLToVO.containsKey(egoAuthorURLNode.toString())) { + + egoNode = nodeURLToVO.get(egoAuthorURLNode.toString()); + + } else { + + egoNode = new Node(egoAuthorURLNode.toString(), nodeIDGenerator); + nodes.add(egoNode); + nodeURLToVO.put(egoAuthorURLNode.toString(), egoNode); + + RDFNode authorLabelNode = solution.get(QueryFieldLabels.AUTHOR_LABEL); + if (authorLabelNode != null) { + egoNode.setNodeName(authorLabelNode.toString()); + } + } + + RDFNode documentNode = solution.get(QueryFieldLabels.DOCUMENT_URL); + BiboDocument biboDocument; + + if (biboDocumentURLToVO.containsKey(documentNode.toString())) { + biboDocument = biboDocumentURLToVO.get(documentNode.toString()); + } else { + biboDocument = createDocumentVO(solution, documentNode.toString()); + biboDocumentURLToVO.put(documentNode.toString(), biboDocument); + } + + egoNode.addAuthorDocument(biboDocument); + + /* + * After some discussion we concluded that for the purpose of this visualization + * we do not want a co-author node or edge if the publication has only one + * author and that happens to be the ego. + * */ + if (solution.get(QueryFieldLabels.AUTHOR_URL).toString().equalsIgnoreCase( + solution.get(QueryFieldLabels.CO_AUTHOR_URL).toString())) { + continue; + } + + Node coAuthorNode; + + RDFNode coAuthorURLNode = solution.get(QueryFieldLabels.CO_AUTHOR_URL); + if (nodeURLToVO.containsKey(coAuthorURLNode.toString())) { + + coAuthorNode = nodeURLToVO.get(coAuthorURLNode.toString()); + + } else { + + coAuthorNode = new Node(coAuthorURLNode.toString(), nodeIDGenerator); + nodes.add(coAuthorNode); + nodeURLToVO.put(coAuthorURLNode.toString(), coAuthorNode); + + RDFNode coAuthorLabelNode = solution.get(QueryFieldLabels.CO_AUTHOR_LABEL); + if (coAuthorLabelNode != null) { + coAuthorNode.setNodeName(coAuthorLabelNode.toString()); + } + } + + coAuthorNode.addAuthorDocument(biboDocument); + + Set coAuthorsForCurrentBiboDocument; + + if (biboDocumentURLToCoAuthors.containsKey(biboDocument.getDocumentURL())) { + coAuthorsForCurrentBiboDocument = biboDocumentURLToCoAuthors + .get(biboDocument.getDocumentURL()); + } else { + coAuthorsForCurrentBiboDocument = new HashSet(); + biboDocumentURLToCoAuthors.put(biboDocument.getDocumentURL(), + coAuthorsForCurrentBiboDocument); + } + + coAuthorsForCurrentBiboDocument.add(coAuthorNode); + + Edge egoCoAuthorEdge = getExistingEdge(egoNode, coAuthorNode, edgeUniqueIdentifierToVO); + + /* + * If "egoCoAuthorEdge" is null it means that no edge exists in between the egoNode + * & current coAuthorNode. Else create a new edge, add it to the edges set & add + * the collaborator document to it. + * */ + if (egoCoAuthorEdge != null) { + egoCoAuthorEdge.addCollaboratorDocument(biboDocument); + } else { + egoCoAuthorEdge = new Edge(egoNode, coAuthorNode, biboDocument, edgeIDGenerator); + edges.add(egoCoAuthorEdge); + edgeUniqueIdentifierToVO.put( + getEdgeUniqueIdentifier(egoNode.getNodeID(), + coAuthorNode.getNodeID()), + egoCoAuthorEdge); + } + + + } + + + + /* + * This method takes out all the authors & edges between authors that belong to documents + * that have more than 100 authors. We conjecture that these papers do not provide much + * insight. However, we have left the documents be. + * + * This method side-effects "nodes" & "edges". + * */ + removeLowQualityNodesAndEdges(nodes, + biboDocumentURLToVO, + biboDocumentURLToCoAuthors, + edges); + + /* + * We need to create edges between 2 co-authors. E.g. On a paper there were 3 authors + * ego, A & B then we have already created edges like, + * ego - A + * ego - B + * The below sub-routine will take care of, + * A - B + * + * We are side-effecting "edges" here. The only reason to do this is because we are adding + * edges en masse for all the co-authors on all the publications considered so far. The + * other reason being we dont want to compare against 2 sets of edges (edges created before + * & co-author edges created during the course of this method) when we are creating a new + * edge. + * */ + createCoAuthorEdges(biboDocumentURLToVO, + biboDocumentURLToCoAuthors, + edges, + edgeUniqueIdentifierToVO); + + + return new CoAuthorshipData(egoNode, nodes, edges); + } + + private void removeLowQualityNodesAndEdges(Set nodes, + Map biboDocumentURLToVO, + Map> biboDocumentURLToCoAuthors, + Set edges) { + + Set nodesToBeRemoved = new HashSet(); + for (Map.Entry> currentBiboDocumentEntry + : biboDocumentURLToCoAuthors.entrySet()) { + + if (currentBiboDocumentEntry.getValue().size() > MAX_AUTHORS_PER_PAPER_ALLOWED) { + + BiboDocument currentBiboDocument = biboDocumentURLToVO + .get(currentBiboDocumentEntry.getKey()); + + Set edgesToBeRemoved = new HashSet(); + + for (Edge currentEdge : edges) { + Set currentCollaboratorDocuments = + currentEdge.getCollaboratorDocuments(); + + if (currentCollaboratorDocuments.contains(currentBiboDocument)) { + currentCollaboratorDocuments.remove(currentBiboDocument); + if (currentCollaboratorDocuments.isEmpty()) { + edgesToBeRemoved.add(currentEdge); + } + } + } + + edges.removeAll(edgesToBeRemoved); + + for (Node currentCoAuthor : currentBiboDocumentEntry.getValue()) { + currentCoAuthor.getAuthorDocuments().remove(currentBiboDocument); + if (currentCoAuthor.getAuthorDocuments().isEmpty()) { + nodesToBeRemoved.add(currentCoAuthor); + } + } + } + } + nodes.removeAll(nodesToBeRemoved); + } + + private void createCoAuthorEdges( + Map biboDocumentURLToVO, + Map> biboDocumentURLToCoAuthors, Set edges, + Map edgeUniqueIdentifierToVO) { + + for (Map.Entry> currentBiboDocumentEntry + : biboDocumentURLToCoAuthors.entrySet()) { + + /* + * If there was only one co-author (other than ego) then we dont have to create any + * edges. so the below condition will take care of that. + * + * We are restricting edges between co-author if a particular document has more than + * 100 co-authors. Our conjecture is that such edges do not provide any good insight + * & causes unnecessary computations causing the server to time-out. + * */ + if (currentBiboDocumentEntry.getValue().size() > 1 + && currentBiboDocumentEntry.getValue().size() + <= MAX_AUTHORS_PER_PAPER_ALLOWED) { + + + Set newlyAddedEdges = new HashSet(); + + /* + * In order to leverage the nested "for loop" for making edges between all the + * co-authors we need to create a list out of the set first. + * */ + List coAuthorNodes = new ArrayList(currentBiboDocumentEntry.getValue()); + Collections.sort(coAuthorNodes, new NodeComparator()); + + int numOfCoAuthors = coAuthorNodes.size(); + + for (int ii = 0; ii < numOfCoAuthors - 1; ii++) { + for (int jj = ii + 1; jj < numOfCoAuthors; jj++) { + + Node coAuthor1 = coAuthorNodes.get(ii); + Node coAuthor2 = coAuthorNodes.get(jj); + + Edge coAuthor1_2Edge = getExistingEdge(coAuthor1, + coAuthor2, + edgeUniqueIdentifierToVO); + + BiboDocument currentBiboDocument = biboDocumentURLToVO + .get(currentBiboDocumentEntry + .getKey()); + + if (coAuthor1_2Edge != null) { + coAuthor1_2Edge.addCollaboratorDocument(currentBiboDocument); + } else { + coAuthor1_2Edge = new Edge(coAuthor1, + coAuthor2, + currentBiboDocument, + edgeIDGenerator); + newlyAddedEdges.add(coAuthor1_2Edge); + edgeUniqueIdentifierToVO.put( + getEdgeUniqueIdentifier(coAuthor1.getNodeID(), + coAuthor2.getNodeID()), + coAuthor1_2Edge); + } + } + } + edges.addAll(newlyAddedEdges); + } + + } + } + + private Edge getExistingEdge( + Node collaboratingNode1, + Node collaboratingNode2, + Map edgeUniqueIdentifierToVO) { + + String edgeUniqueIdentifier = getEdgeUniqueIdentifier(collaboratingNode1.getNodeID(), + collaboratingNode2.getNodeID()); + + return edgeUniqueIdentifierToVO.get(edgeUniqueIdentifier); + + } + + private String getEdgeUniqueIdentifier(int nodeID1, int nodeID2) { + + String separator = "*"; + + if (nodeID1 < nodeID2) { + return nodeID1 + separator + nodeID2; + } else { + return nodeID2 + separator + nodeID1; + } + + } + +// public Map getCollegeURLToVO() { +// return collegeURLToVO; +// } + + private BiboDocument createDocumentVO(QuerySolution solution, String documentURL) { + + BiboDocument biboDocument = new BiboDocument(documentURL); + + RDFNode documentLabelNode = solution.get(QueryFieldLabels.DOCUMENT_LABEL); + if (documentLabelNode != null) { + biboDocument.setDocumentLabel(documentLabelNode.toString()); + } + + RDFNode documentBlurbNode = solution.get(QueryFieldLabels.DOCUMENT_BLURB); + if (documentBlurbNode != null) { + biboDocument.setDocumentBlurb(documentBlurbNode.toString()); + } + + RDFNode documentMonikerNode = solution.get(QueryFieldLabels.DOCUMENT_MONIKER); + if (documentMonikerNode != null) { + biboDocument.setDocumentMoniker(documentMonikerNode.toString()); + } + + RDFNode publicationYearNode = solution.get(QueryFieldLabels.DOCUMENT_PUBLICATION_YEAR); + if (publicationYearNode != null) { + biboDocument.setPublicationYear(publicationYearNode.toString()); + } + + 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()); + } + + return biboDocument; + } + + private ResultSet executeQuery(String queryText, + DataSource dataSource) { + + QueryExecution queryExecution = null; + // try { + Query query = QueryFactory.create(queryText, SYNTAX); + +// QuerySolutionMap qs = new QuerySolutionMap(); +// qs.add("authPerson", queryParam); // bind resource to s + + queryExecution = QueryExecutionFactory.create(query, dataSource); + System.out.println("\n\nquery.isSelectType() is "+ query.isSelectType()+ " \n\n"); +// if (query.isSelectType()) { + return queryExecution.execSelect(); +// } +// } finally { +// if (queryExecution != null) { +// queryExecution.close(); +// } +// } +// return null; + } + + private String generateEgoCoAuthorshipSparqlQuery(String queryURI) { +// Resource uri1 = ResourceFactory.createResource(queryURI); + + String sparqlQuery = QueryConstants.getSparqlPrefixQuery() + + "SELECT " + + " (str(<" + queryURI + ">) as ?" + QueryFieldLabels.AUTHOR_URL + ") " + + " (str(?authorLabel) as ?" + QueryFieldLabels.AUTHOR_LABEL + ") " + + " (str(?coAuthorPerson) as ?" + QueryFieldLabels.CO_AUTHOR_URL + ") " + + " (str(?coAuthorPersonLabel) as ?" + QueryFieldLabels.CO_AUTHOR_LABEL + ") " + + " (str(?document) as ?" + QueryFieldLabels.DOCUMENT_URL + ") " + + " (str(?documentLabel) as ?" + QueryFieldLabels.DOCUMENT_LABEL + ") " + + " (str(?documentMoniker) as ?" + QueryFieldLabels.DOCUMENT_MONIKER + ") " + + " (str(?documentBlurb) as ?" + QueryFieldLabels.DOCUMENT_BLURB + ") " + + " (str(?publicationYear) as ?" + QueryFieldLabels.DOCUMENT_PUBLICATION_YEAR + ") " + + " (str(?publicationYearMonth) as ?" + + QueryFieldLabels.DOCUMENT_PUBLICATION_YEAR_MONTH + ") " + + " (str(?publicationDate) as ?" + + QueryFieldLabels.DOCUMENT_PUBLICATION_DATE + ") " + + "WHERE { " + + "<" + queryURI + "> rdf:type foaf:Person ;" + + " rdfs:label ?authorLabel ;" + + " core:authorInAuthorship ?authorshipNode . " + + "?authorshipNode rdf:type core:Authorship ;" + + " core:linkedInformationResource ?document . " + + "?document rdfs:label ?documentLabel . " + + "?document core:informationResourceInAuthorship ?coAuthorshipNode . " + + "?coAuthorshipNode core:linkedAuthor ?coAuthorPerson . " + + "?coAuthorPerson rdfs:label ?coAuthorPersonLabel . " + + "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 } " + + "} " + + "ORDER BY ?document ?coAuthorPerson"; + +// System.out.println("COAUTHORSHIP QUERY - " + sparqlQuery); + + return sparqlQuery; + } + + + public CoAuthorshipData getQueryResult() + throws MalformedQueryParametersException { + + if (StringUtils.isNotBlank(this.egoURI)) { + /* + * To test for the validity of the URI submitted. + * */ + IRIFactory iRIFactory = IRIFactory.jenaImplementation(); + IRI iri = iRIFactory.create(this.egoURI); + if (iri.hasViolation(false)) { + String errorMsg = ((Violation) iri.violations(false).next()).getShortMessage(); + log.error("Ego Co-Authorship Vis Query " + errorMsg); + throw new MalformedQueryParametersException( + "URI provided for an individual is malformed."); + } + } else { + throw new MalformedQueryParametersException("URI parameter is either null or empty."); + } + + ResultSet resultSet = executeQuery(generateEgoCoAuthorshipSparqlQuery(this.egoURI), + this.dataSource); + return createQueryResult(resultSet); + } + +} diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/coauthorship/CoAuthorshipRequestHandler.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/coauthorship/CoAuthorshipRequestHandler.java new file mode 100644 index 00000000..d9084a95 --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/coauthorship/CoAuthorshipRequestHandler.java @@ -0,0 +1,243 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.coauthorship; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.Map.Entry; + +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 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.controller.visualization.freemarker.DataVisualizationController; +import edu.cornell.mannlib.vitro.webapp.visualization.exceptions.MalformedQueryParametersException; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.CoAuthorshipData; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.Node; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.QueryRunner; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.UtilityFunctions; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.VisualizationRequestHandler; + +/** + * This request handler is used when information related to co-authorship network + * for an individual is requested. It currently provides 2 outputs, + * 1. Graphml content representing the individual's co-authorship network + * 1. CSV file containing the list(& count) of unique co-authors with which + * the individual has worked over the years. This data powers the related sparkline. + * + * @author cdtank + */ +public class CoAuthorshipRequestHandler implements VisualizationRequestHandler { + + @Override + public Object generateAjaxVisualization(VitroRequest vitroRequest, Log log, + DataSource dataSource) throws MalformedQueryParametersException { + throw new UnsupportedOperationException("CoAuthorship does not provide Ajax Response."); + } + + @Override + public Map generateDataVisualization( + VitroRequest vitroRequest, Log log, DataSource dataSource) + throws MalformedQueryParametersException { + + + String egoURI = vitroRequest.getParameter( + VisualizationFrameworkConstants + .INDIVIDUAL_URI_KEY); + + String visMode = vitroRequest.getParameter( + VisualizationFrameworkConstants + .VIS_MODE_KEY); + + QueryRunner queryManager = + new CoAuthorshipQueryRunner(egoURI, dataSource, log); + + CoAuthorshipData authorNodesAndEdges = + queryManager.getQueryResult(); + + /* + * We will be using the same visualization package for both sparkline & coauthorship + * flash vis. We will use "VIS_MODE_KEY" as a modifier to differentiate + * between these two. The default will be to render the coauthorship network vis. + * */ + if (VisualizationFrameworkConstants.SPARKLINE_VIS_MODE + .equalsIgnoreCase(visMode)) { + /* + * When the csv file is required - based on which sparkline visualization will + * be rendered. + * */ + return prepareSparklineDataResponse(authorNodesAndEdges); + } else { + /* + * When the graphML file is required - based on which coauthorship network + * visualization will be rendered. + * */ + return prepareNetworkDataResponse(authorNodesAndEdges); + } + + } + + public ResponseValues generateStandardVisualization(VitroRequest vitroRequest, + Log log, + DataSource dataSource) + throws MalformedQueryParametersException { + + String egoURI = vitroRequest.getParameter( + VisualizationFrameworkConstants + .INDIVIDUAL_URI_KEY); + + QueryRunner queryManager = + new CoAuthorshipQueryRunner(egoURI, dataSource, log); + + CoAuthorshipData authorNodesAndEdges = + queryManager.getQueryResult(); + + + return prepareStandaloneResponse(egoURI, + authorNodesAndEdges, + vitroRequest); + + + } + + private String getCoauthorsPerYearCSVContent(Map> yearToCoauthors) { + + StringBuilder csvFileContent = new StringBuilder(); + + csvFileContent.append("Year, Count, Co-Author(s)\n"); + + for (Entry> currentEntry : yearToCoauthors.entrySet()) { + csvFileContent.append(StringEscapeUtils.escapeCsv(currentEntry.getKey())); + csvFileContent.append(","); + csvFileContent.append(currentEntry.getValue().size()); + csvFileContent.append(","); + csvFileContent.append(StringEscapeUtils.escapeCsv(getCoauthorNamesAsString(currentEntry.getValue()))); + csvFileContent.append("\n"); + } + + return csvFileContent.toString(); + + } + + private String getCoauthorNamesAsString(Set coAuthors) { + + StringBuilder coAuthorsMerged = new StringBuilder(); + + String coAuthorSeparator = "; "; + for (Node currCoAuthor : coAuthors) { + coAuthorsMerged.append(currCoAuthor.getNodeName() + coAuthorSeparator); + } + + return StringUtils.removeEnd(coAuthorsMerged.toString(), coAuthorSeparator); + } + + /** + * Provides response when a csv file containing number & names of unique co-authors per + * year is requested. + * @param authorNodesAndEdges + * @param response + */ + private Map prepareSparklineDataResponse(CoAuthorshipData authorNodesAndEdges) { + + String outputFileName; + Map> yearToCoauthors = new TreeMap>(); + + if (authorNodesAndEdges.getNodes() != null && authorNodesAndEdges.getNodes().size() > 0) { + + outputFileName = UtilityFunctions.slugify(authorNodesAndEdges + .getEgoNode().getNodeName()) + + "_coauthors-per-year" + ".csv"; + + yearToCoauthors = UtilityFunctions.getPublicationYearToCoAuthors(authorNodesAndEdges); + + } else { + + outputFileName = "no_coauthors-per-year" + ".csv"; + } + + Map fileData = new HashMap(); + fileData.put(DataVisualizationController.FILE_NAME_KEY, + outputFileName); + fileData.put(DataVisualizationController.FILE_CONTENT_TYPE_KEY, + "application/octet-stream"); + fileData.put(DataVisualizationController.FILE_CONTENT_KEY, + getCoauthorsPerYearCSVContent(yearToCoauthors)); + + return fileData; + } + + /** + * Provides a response when graphml formatted co-authorship network is requested, typically by + * the flash vis. + * @param authorNodesAndEdges + * @param response + */ + private Map prepareNetworkDataResponse(CoAuthorshipData authorNodesAndEdges) { + + /* + * We are side-effecting responseWriter since we are directly manipulating the response + * object of the servlet. + * */ + CoAuthorshipGraphMLWriter coAuthorshipGraphMLWriter = + new CoAuthorshipGraphMLWriter(authorNodesAndEdges); + + Map fileData = new HashMap(); + fileData.put(DataVisualizationController.FILE_CONTENT_TYPE_KEY, + "text/xml"); + fileData.put(DataVisualizationController.FILE_CONTENT_KEY, + coAuthorshipGraphMLWriter.getCoAuthorshipGraphMLContent().toString()); + + return fileData; + + } + + /** + * When the page for person level visualization is requested. + * @param egoURI + * @param coAuthorshipVO + * @param vitroRequest + * @param request + * @return + */ + private TemplateResponseValues prepareStandaloneResponse( + String egoURI, + CoAuthorshipData coAuthorshipVO, + VitroRequest vitroRequest) { + + Portal portal = vitroRequest.getPortal(); + + String title = ""; + Map body = new HashMap(); + + if (coAuthorshipVO.getNodes() != null && coAuthorshipVO.getNodes().size() > 0) { + title = coAuthorshipVO.getEgoNode().getNodeName() + " - "; + body.put("numOfAuthors", coAuthorshipVO.getNodes().size()); + } + + if (coAuthorshipVO.getEdges() != null && coAuthorshipVO.getEdges().size() > 0) { + body.put("numOfCoAuthorShips", coAuthorshipVO.getEdges().size()); + } + + + //request.setAttribute("scripts", "/templates/visualization/person_level_inject_head.jsp"); + + String standaloneTemplate = "/visualization/coauthorship/coAuthorship.ftl"; + + + body.put("portalBean", portal); + body.put("egoURIParam", egoURI); + body.put("title", title + "Co-Authorship Visualization"); + + return new TemplateResponseValues(standaloneTemplate, body); + } + +} diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/coauthorship/CoAuthorshipVisCodeGenerator.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/coauthorship/CoAuthorshipVisCodeGenerator.java new file mode 100644 index 00000000..3452bf74 --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/coauthorship/CoAuthorshipVisCodeGenerator.java @@ -0,0 +1,580 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.coauthorship; + +import java.util.Calendar; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +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.freemarker.UrlBuilder; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.ParamMap; +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.valueobjects.Node; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.SparklineData; + + +@SuppressWarnings("serial") +public class CoAuthorshipVisCodeGenerator { + + /* + * 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 coauthors 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", "unique_coauthors_short_sparkline_vis"); + put("FULL_SPARK", "unique_coauthors_full_sparkline_vis"); + + } }; + + private static final String VISUALIZATION_STYLE_CLASS = "sparkline_style"; + + private static final String DEFAULT_VISCONTAINER_DIV_ID = "unique_coauthors_vis_container"; + + private Map> yearToUniqueCoauthors; + + private Log log; + + private SparklineData sparklineData; + + private String individualURI; + + public CoAuthorshipVisCodeGenerator(String individualURI, + String visMode, + String visContainer, + Map> yearToUniqueCoauthors, + Log log) { + + this.individualURI = individualURI; + + this.yearToUniqueCoauthors = yearToUniqueCoauthors; + this.sparklineData = new SparklineData(); + + this.log = log; + + generateVisualizationCode(visMode, visContainer); + } + + /** + * 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 + */ + private void generateVisualizationCode(String visMode, + String visContainer) { + + sparklineData.setSparklineContent(getMainVisualizationCode(visMode, + visContainer)); + + sparklineData.setSparklineContext(getVisualizationContextCode(visMode)); + + } + + private String getMainVisualizationCode(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(yearToUniqueCoauthors.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 (yearToUniqueCoauthors.size() > 0) { + try { + minPublishedYear = Integer.parseInt(Collections.min(publishedYears)); + } catch (NoSuchElementException e1) { + log.debug("vis: " + e1.getMessage() + " error occurred for " + + yearToUniqueCoauthors.toString()); + } catch (NumberFormatException e2) { + log.debug("vis: " + e2.getMessage() + " error occurred for " + + yearToUniqueCoauthors.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; + + 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 (yearToUniqueCoauthors.size() > 0) { + + if (getCSVDownloadURL() != null) { + + csvDownloadURLHref = "Download data as .csv file.
"; + sparklineData.setDownloadDataLink(getCSVDownloadURL()); + + } else { + csvDownloadURLHref = ""; + } + + } else { + csvDownloadURLHref = "No data available to export.
"; + } + + String tableCode = generateDataTable(); + + divContextCode.append("

" + tableCode + csvDownloadURLHref + "

"); + + sparklineData.setTable(tableCode); + + return divContextCode.toString(); + } + + private String getCSVDownloadURL(){ + + if (yearToUniqueCoauthors.size() > 0) { + + ParamMap CSVDownloadURLParams = new ParamMap(VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY, + individualURI, + VisualizationFrameworkConstants.VIS_TYPE_KEY, + VisualizationFrameworkConstants.COAUTHORSHIP_VIS, + VisualizationFrameworkConstants.VIS_MODE_KEY, + VisualizationFrameworkConstants.SPARKLINE_VIS_MODE); + + return UrlBuilder.getUrl(VisualizationFrameworkConstants.DATA_VISUALIZATION_SERVICE_URL_PREFIX, + CSVDownloadURLParams); + + } else { + return null; + } + } + + private String generateShortVisContext() { + + StringBuilder divContextCode = new StringBuilder(); + + String fullTimelineLink; + if (yearToUniqueCoauthors.size() > 0) { + + ParamMap fullTimelineNetworkURLParams = new ParamMap( + VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY, + individualURI, + VisualizationFrameworkConstants.VIS_TYPE_KEY, + VisualizationFrameworkConstants.PERSON_LEVEL_VIS, + VisualizationFrameworkConstants.VIS_CONTAINER_KEY, + "ego_sparkline"); + + String fullTimelineNetworkURL = UrlBuilder.getUrl( + VisualizationFrameworkConstants.FREEMARKERIZED_VISUALIZATION_URL_PREFIX, + fullTimelineNetworkURLParams); + + fullTimelineLink = "View full timeline and co-author network."; + + sparklineData.setFullTimelineNetworkLink(fullTimelineNetworkURL); + + } else { + fullTimelineLink = "No data available to render full timeline.
"; + } + + divContextCode.append("

" + fullTimelineLink + "

"); + + return divContextCode.toString(); + } + + + private String generateDataTable() { + + StringBuilder dataTable = new StringBuilder(); + + dataTable.append("" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + ""); + + for (Entry> currentEntry : yearToUniqueCoauthors.entrySet()) { + dataTable.append("" + + "" + + "" + + ""); + } + + dataTable.append("\n
Unique Co-Authors per year
YearCount
" + currentEntry.getKey() + "" + currentEntry.getValue().size() + "
\n"); + + return dataTable.toString(); + } + + public SparklineData getValueObjectContainer() { + return sparklineData; + } +} diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/coauthorship/EdgeComparator.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/coauthorship/EdgeComparator.java new file mode 100644 index 00000000..78f04fb1 --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/coauthorship/EdgeComparator.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.visualization.freemarker.coauthorship; + +import java.util.Comparator; + +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.Edge; + + +/** + * This Comparator is used to sort the edges based on their IDs in ascending order. + * @author cdtank + * + */ +public class EdgeComparator implements Comparator { + + @Override + public int compare(Edge arg0, Edge arg1) { + return arg0.getEdgeID() - arg1.getEdgeID(); + } + +} diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/coauthorship/NodeComparator.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/coauthorship/NodeComparator.java new file mode 100644 index 00000000..0f9c140b --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/coauthorship/NodeComparator.java @@ -0,0 +1,21 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.coauthorship; + +import java.util.Comparator; + +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.Node; + + +/** + * This Comparator is used to sort the nodes based on their IDs in ascending order. + * @author cdtank + */ +public class NodeComparator implements Comparator { + + @Override + public int compare(Node arg0, Node arg1) { + return arg0.getNodeID() - arg1.getNodeID(); + } + +} diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/persongrantcount/PersonGrantCountRequestHandler.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/persongrantcount/PersonGrantCountRequestHandler.java index bd6a1ad0..5a235cf5 100644 --- a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/persongrantcount/PersonGrantCountRequestHandler.java +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/persongrantcount/PersonGrantCountRequestHandler.java @@ -24,20 +24,17 @@ 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.Grant; 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.freemarker.visutils.UtilityFunctions; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.VisualizationRequestHandler; 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; /** @@ -89,9 +86,12 @@ public class PersonGrantCountRequestHandler implements VisualizationRequestHandl if (VisualizationFrameworkConstants.DATA_RENDER_MODE .equalsIgnoreCase(renderMode)) { + + /* return prepareDataResponse(investigator, piGrants, yearToGrantCount); + */ } /* @@ -173,7 +173,7 @@ public class PersonGrantCountRequestHandler implements VisualizationRequestHandl * @param yearToGrantCount * @return */ - private FileResponseValues prepareDataResponse( + private Map prepareDataResponse( Individual investigator, Set piGrants, Map yearToGrantCount) { @@ -203,7 +203,9 @@ public class PersonGrantCountRequestHandler implements VisualizationRequestHandl Map fileContents = new HashMap(); fileContents.put("fileContent", getGrantsOverTimeCSVContent(yearToGrantCount)); - return new FileResponseValues(new ContentType(), outputFileName, fileContents); +// return new FileResponseValues(new ContentType(), outputFileName, fileContents); + + return new HashMap(); } /** @@ -329,47 +331,27 @@ public class PersonGrantCountRequestHandler implements VisualizationRequestHandl e.printStackTrace(); } } -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @Override + public Object generateAjaxVisualization(VitroRequest vitroRequest, Log log, + DataSource dataSource) throws MalformedQueryParametersException { + // TODO Auto-generated method stub + return null; + } + @Override + public Map generateDataVisualization( + VitroRequest vitroRequest, Log log, DataSource dataSource) + throws MalformedQueryParametersException { + // TODO Auto-generated method stub + return null; + } + @Override + public ResponseValues generateStandardVisualization( + VitroRequest vitroRequest, Log log, DataSource dataSource) + throws MalformedQueryParametersException { + // TODO Auto-generated method stub + return null; + } +} \ No newline at end of file diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/persongrantcount/PersonGrantCountVisCodeGenerator.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/persongrantcount/PersonGrantCountVisCodeGenerator.java index 64e5b799..ae7c9f08 100644 --- a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/persongrantcount/PersonGrantCountVisCodeGenerator.java +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/persongrantcount/PersonGrantCountVisCodeGenerator.java @@ -17,7 +17,7 @@ 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.freemarker.StandardVisualizationController; 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; @@ -547,18 +547,18 @@ public class PersonGrantCountVisCodeGenerator { + secondaryContextPath + "?" + VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY + "=" + URLEncoder.encode(individualURI, - VisualizationController.URL_ENCODING_SCHEME) + StandardVisualizationController.URL_ENCODING_SCHEME) .toString() + "&" + VisualizationFrameworkConstants.VIS_TYPE_KEY + "=" + URLEncoder.encode( VisualizationFrameworkConstants .PERSON_GRANT_COUNT_VIS, - VisualizationController.URL_ENCODING_SCHEME) + StandardVisualizationController.URL_ENCODING_SCHEME) .toString() + "&" + VisualizationFrameworkConstants.RENDER_MODE_KEY + "=" + URLEncoder.encode(VisualizationFrameworkConstants .DATA_RENDER_MODE, - VisualizationController.URL_ENCODING_SCHEME) + StandardVisualizationController.URL_ENCODING_SCHEME) .toString(); return downloadURL; } else { @@ -586,16 +586,16 @@ public class PersonGrantCountVisCodeGenerator { + "?" + VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY + "=" + URLEncoder.encode(individualURI, - VisualizationController.URL_ENCODING_SCHEME).toString() + StandardVisualizationController.URL_ENCODING_SCHEME).toString() + "&" + VisualizationFrameworkConstants.VIS_TYPE_KEY + "=" + URLEncoder.encode("person_level", - VisualizationController.URL_ENCODING_SCHEME).toString() + StandardVisualizationController.URL_ENCODING_SCHEME).toString() + "&" + VisualizationFrameworkConstants.RENDER_MODE_KEY + "=" + URLEncoder.encode(VisualizationFrameworkConstants .STANDALONE_RENDER_MODE, - VisualizationController.URL_ENCODING_SCHEME).toString(); + StandardVisualizationController.URL_ENCODING_SCHEME).toString(); fullTimelineLink = "View all VIVO " + "grants and corresponding co-pi network."; 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 index c4fd228e..b39ba7bd 100644 --- a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/personpubcount/PersonPublicationCountRequestHandler.java +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/personpubcount/PersonPublicationCountRequestHandler.java @@ -9,7 +9,6 @@ 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; @@ -24,145 +23,176 @@ 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.controller.visualization.freemarker.DataVisualizationController; 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.freemarker.visutils.UtilityFunctions; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.VisualizationRequestHandler; 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. + * 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); +public class PersonPublicationCountRequestHandler implements +VisualizationRequestHandler { - String renderMode = vitroRequest.getParameter( - VisualizationFrameworkConstants - .RENDER_MODE_KEY); - - String visMode = vitroRequest.getParameter( - VisualizationFrameworkConstants - .VIS_MODE_KEY); + @Override + public Object generateAjaxVisualization(VitroRequest vitroRequest, Log log, + DataSource dataSource) throws MalformedQueryParametersException { - String visContainer = vitroRequest.getParameter( - VisualizationFrameworkConstants - .VIS_CONTAINER_KEY); + String personURI = vitroRequest + .getParameter( + VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY); - QueryRunner> queryManager = - new PersonPublicationCountQueryRunner(peronURI, dataSource, log); + String visMode = vitroRequest + .getParameter( + VisualizationFrameworkConstants.VIS_MODE_KEY); - try { - Set authorDocuments = queryManager.getQueryResult(); + String visContainer = vitroRequest + .getParameter( + VisualizationFrameworkConstants.VIS_CONTAINER_KEY); - /* - * 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(); + QueryRunner> queryManager = new PersonPublicationCountQueryRunner( + personURI, + dataSource, + log); - 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)) { + Set authorDocuments = queryManager.getQueryResult(); - return prepareDynamicResponse(vitroRequest, - sparklineData, - yearToPublicationCount); - - } else { - return prepareStandaloneResponse(vitroRequest, - sparklineData); - } + /* + * Create a map from the year to number of publications. Use the + * BiboDocument's parsedPublicationYear to populate the data. + */ + Map yearToPublicationCount = + UtilityFunctions.getYearToPublicationCount(authorDocuments); + + boolean shouldVIVOrenderVis = + yearToPublicationCount.size() > 0 ? true : false; + + /* + * Computations required to generate HTML for the sparkline & related + * context. + */ + PersonPublicationCountVisCodeGenerator visualizationCodeGenerator = + new PersonPublicationCountVisCodeGenerator( + personURI, + visMode, + visContainer, + authorDocuments, + yearToPublicationCount, + log); + + SparklineData sparklineData = visualizationCodeGenerator + .getValueObjectContainer(); + + return prepareDynamicResponse(vitroRequest, sparklineData, + shouldVIVOrenderVis); - } catch (MalformedQueryParametersException e) { - return UtilityFunctions.handleMalformedParameters( - "Visualization Query Error - Individual Publication Count", - e.getMessage(), - vitroRequest); - } } - private String getPublicationsOverTimeCSVContent(Map yearToPublicationCount) { - + @Override + public Map generateDataVisualization(VitroRequest vitroRequest, Log log, + DataSource dataSource) throws MalformedQueryParametersException { + + String personURI = vitroRequest + .getParameter(VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY); + + QueryRunner> queryManager = new PersonPublicationCountQueryRunner( + personURI, + dataSource, + log); + + 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(); + + return prepareDataResponse(author, + authorDocuments, + yearToPublicationCount); + + } + + @Override + public ResponseValues generateStandardVisualization( + VitroRequest vitroRequest, Log log, DataSource dataSource) + throws MalformedQueryParametersException { + + String personURI = vitroRequest.getParameter( + VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY); + + String visMode = vitroRequest.getParameter( + VisualizationFrameworkConstants.VIS_MODE_KEY); + + String visContainer = vitroRequest.getParameter( + VisualizationFrameworkConstants.VIS_CONTAINER_KEY); + + QueryRunner> queryManager = new PersonPublicationCountQueryRunner( + personURI, + dataSource, + log); + + 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); + + /* + * Computations required to generate HTML for the sparkline & related + * context. + */ + PersonPublicationCountVisCodeGenerator visualizationCodeGenerator = + new PersonPublicationCountVisCodeGenerator( + personURI, + visMode, + visContainer, + authorDocuments, + yearToPublicationCount, + log); + + SparklineData sparklineData = + visualizationCodeGenerator.getValueObjectContainer(); + + return prepareStandaloneResponse(vitroRequest, sparklineData); + } + + 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())); + for (Entry currentEntry : yearToPublicationCount + .entrySet()) { + csvFileContent.append(StringEscapeUtils.escapeCsv(currentEntry + .getKey())); csvFileContent.append(","); csvFileContent.append(currentEntry.getValue()); csvFileContent.append("\n"); @@ -172,169 +202,156 @@ public class PersonPublicationCountRequestHandler implements VisualizationReques } /** - * Provides response when csv file containing the publication count over the years - * is requested. + * Provides response when csv file containing the publication count over the + * years is requested. + * * @param author * @param authorDocuments * @param yearToPublicationCount - * @return + * @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"; + private Map prepareDataResponse(Individual author, + Set authorDocuments, + Map yearToPublicationCount) { - - Map fileContents = new HashMap(); - fileContents.put("fileContent", getPublicationsOverTimeCSVContent(yearToPublicationCount)); - - return new FileResponseValues(new ContentType(), outputFileName, fileContents); + 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 fileData = new HashMap(); + fileData.put(DataVisualizationController.FILE_NAME_KEY, + outputFileName); + fileData.put(DataVisualizationController.FILE_CONTENT_TYPE_KEY, + "application/octet-stream"); + fileData.put(DataVisualizationController.FILE_CONTENT_KEY, + getPublicationsOverTimeCSVContent(yearToPublicationCount)); + + return fileData; } - + /** - * Provides response when an entire page dedicated to publication sparkline is requested. + * Provides response when an entire page dedicated to publication sparkline + * is requested. + * * @param vreq * @param valueObjectContainer - * @return + * @return */ private TemplateResponseValues prepareStandaloneResponse(VitroRequest vreq, SparklineData valueObjectContainer) { - Portal portal = vreq.getPortal(); - - String standaloneTemplate = "/visualization/publicationCount.ftl"; + Portal portal = vreq.getPortal(); - Map body = new HashMap(); - body.put("portalBean", portal); - body.put("title", "Individual Publication Count visualization"); - body.put("sparklineVO", valueObjectContainer); + String standaloneTemplate = "/visualization/publicationCount.ftl"; + + Map body = new HashMap(); + body.put("portalBean", portal); + body.put("title", "Individual Publication Count visualization"); + body.put("sparklineVO", valueObjectContainer); + + return new TemplateResponseValues(standaloneTemplate, body); - /* - * 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. + * 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 + * @return */ - private TemplateResponseValues prepareDynamicResponse( - VitroRequest vreq, - SparklineData valueObjectContainer, - Map yearToPublicationCount) { + private TemplateResponseValues prepareDynamicResponse(VitroRequest vreq, + SparklineData valueObjectContainer, boolean shouldVIVOrenderVis) { - Portal portal = vreq.getPortal(); + Portal portal = vreq.getPortal(); + String dynamicTemplate = "/visualization/sparklineAjaxVisContent.ftl"; - String dynamicTemplate = "/visualization/sparklineAjaxVisContent.ftl"; + Map body = new HashMap(); + body.put("portalBean", portal); + body.put("sparklineVO", valueObjectContainer); + body.put("shouldVIVOrenderVis", shouldVIVOrenderVis); - Map body = new HashMap(); - body.put("portalBean", portal); - body.put("sparklineVO", valueObjectContainer); + return new TemplateResponseValues(dynamicTemplate, body); - /* - * 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. + 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. + + // 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"; - + + 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(); - } + 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 index 4abd587d..9b1a9109 100644 --- a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/personpubcount/PersonPublicationCountVisCodeGenerator.java +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/personpubcount/PersonPublicationCountVisCodeGenerator.java @@ -2,8 +2,6 @@ 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; @@ -17,7 +15,8 @@ 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.freemarker.UrlBuilder; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.ParamMap; 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; @@ -55,19 +54,15 @@ public class PersonPublicationCountVisCodeGenerator { private SparklineData sparklineData; - private String contextPath; - private String individualURI; - public PersonPublicationCountVisCodeGenerator(String contextPath, - String individualURIParam, + public PersonPublicationCountVisCodeGenerator(String individualURIParam, String visMode, String visContainer, Set authorDocuments, Map yearToPublicationCount, Log log) { - this.contextPath = contextPath; this.individualURI = individualURIParam; this.yearToPublicationCount = yearToPublicationCount; @@ -407,17 +402,12 @@ public class PersonPublicationCountVisCodeGenerator { String csvDownloadURLHref = ""; - try { - if (getCSVDownloadURL() != null) { - - csvDownloadURLHref = "(.CSV File)"; - - } else { - csvDownloadURLHref = ""; - } - - } catch (UnsupportedEncodingException e) { + if (getCSVDownloadURL() != null) { + + csvDownloadURLHref = "(.CSV File)"; + + } else { csvDownloadURLHref = ""; } @@ -525,18 +515,13 @@ public class PersonPublicationCountVisCodeGenerator { if (yearToPublicationCount.size() > 0) { - try { - if (getCSVDownloadURL() != null) { - - csvDownloadURLHref = "Download data as .csv file.
"; - sparklineData.setDownloadDataLink(getCSVDownloadURL()); - - } else { - csvDownloadURLHref = ""; - } - - } catch (UnsupportedEncodingException e) { + if (getCSVDownloadURL() != null) { + + csvDownloadURLHref = "Download data as .csv file.
"; + sparklineData.setDownloadDataLink(getCSVDownloadURL()); + + } else { csvDownloadURLHref = ""; } } else { @@ -552,34 +537,18 @@ public class PersonPublicationCountVisCodeGenerator { return divContextCode.toString(); } - private String getCSVDownloadURL() - throws UnsupportedEncodingException { + private String getCSVDownloadURL() { 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; + ParamMap CSVDownloadURLParams = new ParamMap(VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY, + individualURI, + VisualizationFrameworkConstants.VIS_TYPE_KEY, + VisualizationFrameworkConstants.PERSON_PUBLICATION_COUNT_VIS); + + return UrlBuilder.getUrl(VisualizationFrameworkConstants.DATA_VISUALIZATION_SERVICE_URL_PREFIX, + CSVDownloadURLParams); + } else { return null; } @@ -589,31 +558,18 @@ public class PersonPublicationCountVisCodeGenerator { 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(); + ParamMap fullTimelineNetworkURLParams = new ParamMap(VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY, + individualURI, + VisualizationFrameworkConstants.VIS_TYPE_KEY, + VisualizationFrameworkConstants.PERSON_LEVEL_VIS); + + String fullTimelineNetworkURL = UrlBuilder.getUrl( + VisualizationFrameworkConstants.FREEMARKERIZED_VISUALIZATION_URL_PREFIX, + fullTimelineNetworkURLParams); + fullTimelineLink = "View all VIVO " + "publications and corresponding co-author network."; @@ -625,10 +581,6 @@ public class PersonPublicationCountVisCodeGenerator { } divContextCode.append("" + fullTimelineLink + ""); - - } catch (UnsupportedEncodingException e) { - log.error(e); - } return divContextCode.toString(); } @@ -636,13 +588,9 @@ public class PersonPublicationCountVisCodeGenerator { String csvDownloadURLHref = ""; - try { - if (getCSVDownloadURL() != null) { - csvDownloadURLHref = "(.CSV File)"; - } else { - csvDownloadURLHref = ""; - } - } catch (UnsupportedEncodingException e) { + if (getCSVDownloadURL() != null) { + csvDownloadURLHref = "(.CSV File)"; + } else { csvDownloadURLHref = ""; } diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/utilities/UtilitiesRequestHandler.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/utilities/UtilitiesRequestHandler.java index 82cbfb13..1e106b7b 100644 --- a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/utilities/UtilitiesRequestHandler.java +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/utilities/UtilitiesRequestHandler.java @@ -2,17 +2,9 @@ package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.utilities; -import java.io.IOException; -import java.io.PrintWriter; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; import java.util.HashMap; import java.util.Map; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - import org.apache.commons.logging.Log; import com.google.gson.Gson; @@ -21,23 +13,19 @@ import com.hp.hpl.jena.query.QuerySolution; import com.hp.hpl.jena.query.ResultSet; import com.hp.hpl.jena.rdf.model.RDFNode; -import edu.cornell.mannlib.vitro.webapp.beans.Portal; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.ParamMap; 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.freemarker.VisualizationController; import edu.cornell.mannlib.vitro.webapp.controller.visualization.VisualizationFrameworkConstants; import edu.cornell.mannlib.vitro.webapp.filestorage.FileServingHelper; 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.valueobjects.GenericQueryMap; import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.AllPropertiesQueryRunner; import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.GenericQueryRunner; import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.QueryRunner; -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.valueobjects.GenericQueryMap; /** * This request handler is used when you need helpful information to add more context @@ -51,9 +39,10 @@ import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.Visual */ public class UtilitiesRequestHandler implements VisualizationRequestHandler { - public ResponseValues generateVisualization(VitroRequest vitroRequest, - Log log, - DataSource dataSource) { + public Object generateAjaxVisualization(VitroRequest vitroRequest, + Log log, + DataSource dataSource) + throws MalformedQueryParametersException { String individualURI = vitroRequest.getParameter( VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY); @@ -61,10 +50,6 @@ public class UtilitiesRequestHandler implements VisualizationRequestHandler { String visMode = vitroRequest.getParameter( VisualizationFrameworkConstants.VIS_MODE_KEY); - String preparedURL = ""; - - UrlBuilder urlBuilder = new UrlBuilder(vitroRequest.getPortal()); - /* * If the info being requested is about a profile which includes the name, moniker * & image url. @@ -83,28 +68,14 @@ public class UtilitiesRequestHandler implements VisualizationRequestHandler { dataSource, log); - try { - - GenericQueryMap profilePropertiesToValues = - profileQueryHandler.getQueryResult(); - - profilePropertiesToValues.addEntry("imageContextPath", - urlBuilder.getBaseUrl()); - - Gson profileInformation = new Gson(); - - return prepareUtilitiesResponse( - profileInformation.toJson(profilePropertiesToValues), - vitroRequest); + GenericQueryMap profilePropertiesToValues = + profileQueryHandler.getQueryResult(); + + Gson profileInformation = new Gson(); + + return profileInformation.toJson(profilePropertiesToValues); - - } catch (MalformedQueryParametersException e) { - return UtilityFunctions.handleMalformedParameters( - "Visualization Query Error - Utilities Profile Info", - e.getMessage(), - vitroRequest); - } } else if (VisualizationFrameworkConstants.IMAGE_UTILS_VIS_MODE .equalsIgnoreCase(visMode)) { /* @@ -131,21 +102,9 @@ public class UtilitiesRequestHandler implements VisualizationRequestHandler { dataSource, log); - try { - - String thumbnailAccessURL = - getThumbnailInformation( - imageQueryHandler.getQueryResult(), - fieldLabelToOutputFieldLabel); - - return prepareUtilitiesResponse(thumbnailAccessURL, vitroRequest); - - } catch (MalformedQueryParametersException e) { - return UtilityFunctions.handleMalformedParameters( - "Visualization Query Error - Utilities Image Info", - e.getMessage(), - vitroRequest); - } + return getThumbnailInformation(imageQueryHandler.getQueryResult(), + fieldLabelToOutputFieldLabel); + } else if (VisualizationFrameworkConstants.COAUTHOR_UTILS_VIS_MODE .equalsIgnoreCase(visMode)) { @@ -160,12 +119,9 @@ public class UtilitiesRequestHandler implements VisualizationRequestHandler { VisualizationFrameworkConstants.RENDER_MODE_KEY, VisualizationFrameworkConstants.STANDALONE_RENDER_MODE); - preparedURL = UrlBuilder.getUrl(VisualizationFrameworkConstants.FREEMARKERIZED_VISUALIZATION_URL_PREFIX, + return UrlBuilder.getUrl(VisualizationFrameworkConstants.FREEMARKERIZED_VISUALIZATION_URL_PREFIX, coAuthorProfileURLParams); - - return prepareUtilitiesResponse(preparedURL, vitroRequest); - } else if (VisualizationFrameworkConstants.PERSON_LEVEL_UTILS_VIS_MODE .equalsIgnoreCase(visMode)) { /* @@ -179,19 +135,16 @@ public class UtilitiesRequestHandler implements VisualizationRequestHandler { VisualizationFrameworkConstants.RENDER_MODE_KEY, VisualizationFrameworkConstants.STANDALONE_RENDER_MODE); - preparedURL = UrlBuilder.getUrl(VisualizationFrameworkConstants.FREEMARKERIZED_VISUALIZATION_URL_PREFIX, - personLevelURLParams); + return UrlBuilder.getUrl(VisualizationFrameworkConstants.FREEMARKERIZED_VISUALIZATION_URL_PREFIX, + personLevelURLParams); - return prepareUtilitiesResponse(preparedURL, vitroRequest); } else { ParamMap individualProfileURLParams = new ParamMap(VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY, individualURI); - preparedURL = UrlBuilder.getUrl(VisualizationFrameworkConstants.INDIVIDUAL_URL_PREFIX, + return UrlBuilder.getUrl(VisualizationFrameworkConstants.INDIVIDUAL_URL_PREFIX, individualProfileURLParams); - - return prepareUtilitiesResponse(preparedURL, vitroRequest); } } @@ -219,6 +172,7 @@ public class UtilitiesRequestHandler implements VisualizationRequestHandler { } return finalThumbNailLocation; } + /* private TemplateResponseValues prepareUtilitiesResponse(String preparedContent, VitroRequest vreq) { @@ -231,6 +185,20 @@ public class UtilitiesRequestHandler implements VisualizationRequestHandler { return new TemplateResponseValues(utilitiesTemplate, body); + }*/ + + @Override + public Map generateDataVisualization( + VitroRequest vitroRequest, Log log, DataSource dataSource) + throws MalformedQueryParametersException { + throw new UnsupportedOperationException("Utilities does not provide Data Response."); + } + + @Override + public ResponseValues generateStandardVisualization( + VitroRequest vitroRequest, Log log, DataSource dataSource) + throws MalformedQueryParametersException { + throw new UnsupportedOperationException("Utilities does not provide Standard Response."); } } 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 index 200edb38..8454f878 100644 --- a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/Edge.java +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/Edge.java @@ -9,7 +9,7 @@ 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.UniqueIDGenerator; import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.UtilityFunctions; /** 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 index 04fddaff..697e6b0e 100644 --- a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/Node.java +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/Node.java @@ -9,7 +9,7 @@ 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.UniqueIDGenerator; import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.UtilityFunctions; /** 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 index 87465af7..d5639967 100644 --- a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/visutils/UtilityFunctions.java +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/visutils/UtilityFunctions.java @@ -2,15 +2,23 @@ package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils; +import java.io.IOException; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.TreeMap; +import javax.servlet.RequestDispatcher; +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 edu.cornell.mannlib.vitro.webapp.beans.Portal; +import edu.cornell.mannlib.vitro.webapp.controller.Controllers; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues; @@ -127,7 +135,9 @@ public class UtilityFunctions { } - public static ResponseValues handleMalformedParameters(String errorPageTitle, String errorMessage, VitroRequest vitroRequest) { + public static ResponseValues handleMalformedParameters(String errorPageTitle, + String errorMessage, + VitroRequest vitroRequest) { Portal portal = vitroRequest.getPortal(); @@ -139,23 +149,23 @@ public class UtilityFunctions { return new TemplateResponseValues(VisualizationFrameworkConstants.ERROR_TEMPLATE, body); } -/* public static void handleMalformedParameters(String errorMessage, - String errorPageTitle, + public static void handleMalformedParameters(String errorPageTitle, + String errorMessage, VitroRequest vitroRequest, HttpServletRequest request, HttpServletResponse response, Log log) - throws ServletException, IOException { - + 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) { @@ -163,8 +173,8 @@ public class UtilityFunctions { log.error(e.getMessage()); log.error(e.getStackTrace()); } - }*/ - + } + public static Map> getGrantYearToCoPI( CoPIData pINodesAndEdges) { 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 index fd18905d..6cf42c03 100644 --- a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/visutils/VisualizationRequestHandler.java +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/visutils/VisualizationRequestHandler.java @@ -1,12 +1,15 @@ /* $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.Map; + 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; +import edu.cornell.mannlib.vitro.webapp.visualization.exceptions.MalformedQueryParametersException; /** * This interface is being implemented by all the visualization request handlers like @@ -20,8 +23,16 @@ import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.Res */ public interface VisualizationRequestHandler{ - ResponseValues generateVisualization(VitroRequest vitroRequest, + ResponseValues generateStandardVisualization(VitroRequest vitroRequest, Log log, - DataSource dataSource); + DataSource dataSource) throws MalformedQueryParametersException; + + Object generateAjaxVisualization(VitroRequest vitroRequest, + Log log, + DataSource dataSource) throws MalformedQueryParametersException; + + Map generateDataVisualization(VitroRequest vitroRequest, + Log log, + DataSource dataSource) throws MalformedQueryParametersException; }