1. Changed vis architecture to serve 3 type of responses from 3 corresponding url patterns (standard, ajax, data).

2. Removed debug statements from publication sparkline ftl.
3. Reworked publication sparkline & utilities visualziation to ahere to new architecture.
4. Started work on co-authorship freemarkerization.
5. Removed FileResponseValues type per talks with Rebecca Y. & Nick C.
6. Temporarily disabled person grant count visualization (freemarker version).
This commit is contained in:
cdtank 2010-12-16 01:18:39 +00:00
parent b8e8a81171
commit 06523d402e
26 changed files with 2565 additions and 558 deletions

View file

@ -12,13 +12,15 @@
<bean id="person_pub_count" <bean id="person_pub_count"
class="edu.cornell.mannlib.vitro.webapp.visualization.freemarker.personpubcount.PersonPublicationCountRequestHandler" /> class="edu.cornell.mannlib.vitro.webapp.visualization.freemarker.personpubcount.PersonPublicationCountRequestHandler" />
<bean id="utilities"
class="edu.cornell.mannlib.vitro.webapp.visualization.freemarker.utilities.UtilitiesRequestHandler" />
<!-- <!--
<bean id="coauthorship" <bean id="coauthorship"
class="edu.cornell.mannlib.vitro.webapp.visualization.coauthorship.CoAuthorshipRequestHandler" /> class="edu.cornell.mannlib.vitro.webapp.visualization.coauthorship.CoAuthorshipRequestHandler" />
<bean id="person_level" <bean id="person_level"
class="edu.cornell.mannlib.vitro.webapp.visualization.personlevel.PersonLevelRequestHandler" /> class="edu.cornell.mannlib.vitro.webapp.visualization.personlevel.PersonLevelRequestHandler" />
<bean id="utilities"
class="edu.cornell.mannlib.vitro.webapp.visualization.utilities.UtilitiesRequestHandler" />
<bean id="entity_comparison" <bean id="entity_comparison"
class="edu.cornell.mannlib.vitro.webapp.visualization.entitycomparison.EntityPublicationCountRequestHandler" /> class="edu.cornell.mannlib.vitro.webapp.visualization.entitycomparison.EntityPublicationCountRequestHandler" />
<bean id="coprincipalinvestigator" <bean id="coprincipalinvestigator"
@ -33,6 +35,9 @@
<ref bean="person_pub_count"></ref> <ref bean="person_pub_count"></ref>
</entry> </entry>
<entry key="utilities">
<ref bean="utilities"></ref>
</entry>
<!-- <!--
<entry key="coauthorship"> <entry key="coauthorship">
<ref bean="coauthorship"></ref> <ref bean="coauthorship"></ref>
@ -40,9 +45,6 @@
<entry key="person_level"> <entry key="person_level">
<ref bean="person_level"></ref> <ref bean="person_level"></ref>
</entry> </entry>
<entry key="utilities">
<ref bean="utilities"></ref>
</entry>
<entry key="entity_comparison"> <entry key="entity_comparison">
<ref bean="entity_comparison"></ref> <ref bean="entity_comparison"></ref>
</entry> </entry>

View file

@ -495,6 +495,7 @@
<url-pattern>/csv2rdf</url-pattern> <url-pattern>/csv2rdf</url-pattern>
</servlet-mapping> </servlet-mapping>
<servlet> <servlet>
<servlet-name>JenaExportController</servlet-name> <servlet-name>JenaExportController</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.jena.JenaExportController</servlet-class> <servlet-class>edu.cornell.mannlib.vitro.webapp.controller.jena.JenaExportController</servlet-class>
@ -1248,16 +1249,6 @@
<url-pattern>/admin/sparqlquery</url-pattern> <url-pattern>/admin/sparqlquery</url-pattern>
</servlet-mapping> </servlet-mapping>
<servlet>
<servlet-name>DummyVisClientFM</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.visualization.freemarker.DummyVisClientController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DummyVisClientFM</servlet-name>
<url-pattern>/admin/dummyVisClientfm</url-pattern>
</servlet-mapping>
<servlet> <servlet>
<servlet-name>DummyVisClient</servlet-name> <servlet-name>DummyVisClient</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.visualization.DummyVisClientController</servlet-class> <servlet-class>edu.cornell.mannlib.vitro.webapp.controller.visualization.DummyVisClientController</servlet-class>
@ -1267,6 +1258,16 @@
<servlet-name>DummyVisClient</servlet-name> <servlet-name>DummyVisClient</servlet-name>
<url-pattern>/admin/dummyVisClient</url-pattern> <url-pattern>/admin/dummyVisClient</url-pattern>
</servlet-mapping> </servlet-mapping>
<servlet>
<servlet-name>DummyVisClientFM</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.visualization.freemarker.DummyVisClientController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DummyVisClientFM</servlet-name>
<url-pattern>/admin/dummyVisClientfm</url-pattern>
</servlet-mapping>
<servlet> <servlet>
<servlet-name>VisualizationController</servlet-name> <servlet-name>VisualizationController</servlet-name>
@ -1279,15 +1280,34 @@
</servlet-mapping> </servlet-mapping>
<servlet> <servlet>
<servlet-name>VisualizationControllerFM</servlet-name> <servlet-name>StandardVisualizationController</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.visualization.freemarker.VisualizationController</servlet-class> <servlet-class>edu.cornell.mannlib.vitro.webapp.controller.visualization.freemarker.StandardVisualizationController</servlet-class>
</servlet> </servlet>
<servlet-mapping> <servlet-mapping>
<servlet-name>VisualizationControllerFM</servlet-name> <servlet-name>StandardVisualizationController</servlet-name>
<url-pattern>/visualizationfm</url-pattern> <url-pattern>/visualizationfm</url-pattern>
</servlet-mapping> </servlet-mapping>
<servlet>
<servlet-name>AjaxVisualizationController</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.visualization.freemarker.AjaxVisualizationController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AjaxVisualizationController</servlet-name>
<url-pattern>/visualizationAjax</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>DataVisualizationController</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.visualization.freemarker.DataVisualizationController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DataVisualizationController</servlet-name>
<url-pattern>/visualizationData</url-pattern>
</servlet-mapping>
<servlet> <servlet>
<servlet-name>authtest</servlet-name> <servlet-name>authtest</servlet-name>

View file

@ -26,6 +26,6 @@ var visualization = {
}; };
$(document).ready(function() { $(document).ready(function() {
visualizationUrl = visualizationUrl.replace("/visualization", "/visualizationfm"); visualizationUrl = visualizationUrl.replace("/visualization", "/visualizationAjax");
visualization.render(visualizationUrl); visualization.render(visualizationUrl);
}); });

View file

@ -0,0 +1,2 @@
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->

View file

@ -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'>
<c:url var="adobeFlashDetector" value="/js/visualization/coauthorship/AC_OETags.js" />
<c:url var="googleVisualizationAPI" value="http://www.google.com/jsapi?autoload=%7B%22modules%22%3A%5B%7B%22name%22%3A%22visualization%22%2C%22version%22%3A%221%22%2C%22packages%22%3A%5B%22areachart%22%2C%22imagesparkline%22%5D%7D%5D%7D"/>
<c:url var="coAuthorShipJavaScript" value="/js/visualization/personlevel/person_level.js" />

View file

@ -69,8 +69,6 @@
<#if sparklineVO.shortVisMode> <#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 <#-- 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. --> the data we actually want to use for render. -->
@ -85,8 +83,6 @@
<#else> <#else>
console.log("Yay! Full Vis Mode!");
</#if> </#if>
@ -175,8 +171,6 @@
row.append(sparklineImgTD); row.append(sparklineImgTD);
console.log(sparklineImgTD);
var sparklineNumberTD = $('<td>'); var sparklineNumberTD = $('<td>');
sparklineNumberTD.attr('width', '30'); sparklineNumberTD.attr('width', '30');
sparklineNumberTD.attr('align', 'right'); sparklineNumberTD.attr('align', 'right');
@ -191,8 +185,6 @@
} }
console.log(sparklineImgTD);
drawPubCountVisualization(sparklineImgTD); drawPubCountVisualization(sparklineImgTD);
}); });
</script> </script>

View file

@ -25,6 +25,8 @@ public class VisualizationFrameworkConstants {
*/ */
public static final String VISUALIZATION_URL_PREFIX = "/visualization"; public static final String VISUALIZATION_URL_PREFIX = "/visualization";
public static final String FREEMARKERIZED_VISUALIZATION_URL_PREFIX = "/visualizationfm"; 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"; 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 ENTITY_COMPARISON_VIS = "entity_comparison";
public static final String CO_PI_VIS = "coprincipalinvestigator"; public static final String CO_PI_VIS = "coprincipalinvestigator";
} }

View file

@ -9,12 +9,8 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; 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.DataSource;
import com.hp.hpl.jena.query.DatasetFactory; 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.freemarker.responsevalues.TemplateResponseValues;
import edu.cornell.mannlib.vitro.webapp.controller.visualization.VisualizationFrameworkConstants; 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.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.UtilityFunctions;
import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.VisualizationRequestHandler; import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.VisualizationRequestHandler;
import freemarker.template.Configuration; import freemarker.template.Configuration;
@ -39,75 +36,34 @@ import freemarker.template.Configuration;
* @author cdtank * @author cdtank
*/ */
@SuppressWarnings("serial") @SuppressWarnings("serial")
public class VisualizationController extends FreemarkerHttpServlet { public class AjaxVisualizationController extends FreemarkerHttpServlet {
private Map<String, VisualizationRequestHandler> visualizationIDsToClass;
public static final String URL_ENCODING_SCHEME = "UTF-8"; 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; protected static final Syntax SYNTAX = Syntax.syntaxARQ;
@Override @Override
public void doGet(HttpServletRequest request, HttpServletResponse response) public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException { throws IOException, ServletException {
VitroRequest vreq = new VitroRequest(request); VitroRequest vreq = new VitroRequest(request);
String renderMode = vreq.getParameter(VisualizationFrameworkConstants Object ajaxResponse = processAjaxRequest(vreq);
.RENDER_MODE_KEY);
if (ajaxResponse instanceof TemplateResponseValues) {
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 {
String resourcePath = Configuration config = getConfig(vreq);
getServletContext() TemplateResponseValues trv = (TemplateResponseValues) ajaxResponse;
.getRealPath(VisualizationFrameworkConstants writeTemplate(trv.getTemplateName(), trv.getMap(), config, request, response);
.RELATIVE_LOCATION_OF_FM_VISUALIZATIONS_BEAN);
ApplicationContext context = new ClassPathXmlApplicationContext( } else {
"file:" + resourcePath); response.getWriter().write(ajaxResponse.toString());
BeanFactory factory = context;
VisualizationInjector visualizationInjector =
(VisualizationInjector) factory.getBean("visualizationInjector");
visualizationIDsToClass = visualizationInjector.getVisualizationIDToClass();
} catch (Exception e) {
log.error(e);
} }
} }
private Object processAjaxRequest(VitroRequest vreq) {
@Override
protected ResponseValues processRequest(VitroRequest vreq) {
/* /*
* Based on the query parameters passed via URI get the appropriate visualization * Based on the query parameters passed via URI get the appropriate visualization
* request handler. * request handler.
@ -131,12 +87,10 @@ public class VisualizationController extends FreemarkerHttpServlet {
vreq); vreq);
} }
} }
private ResponseValues renderVisualization(VitroRequest vitroRequest, private Object renderVisualization(VitroRequest vitroRequest,
VisualizationRequestHandler visRequestHandler) { VisualizationRequestHandler visRequestHandler) {
Model model = vitroRequest.getJenaOntModel(); // getModel() Model model = vitroRequest.getJenaOntModel(); // getModel()
@ -158,9 +112,17 @@ public class VisualizationController extends FreemarkerHttpServlet {
if (dataSource != null && visRequestHandler != null) { if (dataSource != null && visRequestHandler != null) {
return visRequestHandler.generateVisualization(vitroRequest, try {
log, return visRequestHandler.generateAjaxVisualization(vitroRequest,
dataSource); log,
dataSource);
} catch (MalformedQueryParametersException e) {
return UtilityFunctions.handleMalformedParameters(
"Ajax Visualization Query Error - Individual Publication Count",
e.getMessage(),
vitroRequest);
}
} else { } else {
@ -184,10 +146,10 @@ public class VisualizationController extends FreemarkerHttpServlet {
.VIS_TYPE_KEY); .VIS_TYPE_KEY);
VisualizationRequestHandler visRequestHandler = null; VisualizationRequestHandler visRequestHandler = null;
System.out.println(visType + " --> " + visualizationIDsToClass);
try { try {
visRequestHandler = visualizationIDsToClass.get(visType); visRequestHandler = VisualizationsDependencyInjector
.getVisualizationIDsToClassMap(getServletContext()).get(visType);
} catch (NullPointerException nullKeyException) { } catch (NullPointerException nullKeyException) {
return null; return null;

View file

@ -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<String, String> 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<String, String> 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;
}
}

View file

@ -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;
}
}

View file

@ -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<String, VisualizationRequestHandler> 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<String, VisualizationRequestHandler> 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<String, VisualizationRequestHandler> getVisualizationIDsToClassMap(
ServletContext servletContext) {
if (visualizationIDsToClass != null) {
return visualizationIDsToClass;
} else {
return initVisualizations(servletContext);
}
}
}

View file

@ -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 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ " <graphml xmlns=\"http://graphml.graphdrawing.org/xmlns\"\n"
+ " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
+ " xsi:schemaLocation=\"http://graphml.graphdrawing.org/xmlns\n"
+ " http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd\">\n\n";
private final String GRAPHML_FOOTER = "</graphml>";
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<graph edgedefault=\"undirected\">\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("</graph>\n");
}
private void generateEdgeSectionContent(CoAuthorshipData coAuthorshipData,
StringBuilder graphMLContent) {
graphMLContent.append("<!-- edges -->\n");
Set<Edge> edges = coAuthorshipData.getEdges();
List<Edge> orderedEdges = new ArrayList<Edge>(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("<edge "
+ "id=\"" + currentEdge.getEdgeID() + "\" "
+ "source=\"" + currentEdge.getSourceNode().getNodeID() + "\" "
+ "target=\"" + currentEdge.getTargetNode().getNodeID() + "\" "
+ ">\n");
graphMLContent.append("\t<data key=\"collaborator1\">"
+ currentEdge.getSourceNode().getNodeName()
+ "</data>\n");
graphMLContent.append("\t<data key=\"collaborator2\">"
+ currentEdge.getTargetNode().getNodeName()
+ "</data>\n");
graphMLContent.append("\t<data key=\"number_of_coauthored_works\">"
+ currentEdge.getNumOfCoAuthoredWorks()
+ "</data>\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<String, Integer> publicationInfo
: currentEdge.getEarliestCollaborationYearCount().entrySet()) {
graphMLContent.append("\t<data key=\"earliest_collaboration\">"
+ publicationInfo.getKey()
+ "</data>\n");
graphMLContent.append("\t<data key=\"num_earliest_collaboration\">"
+ publicationInfo.getValue()
+ "</data>\n");
}
}
if (currentEdge.getLatestCollaborationYearCount() != null) {
for (Map.Entry<String, Integer> publicationInfo
: currentEdge.getLatestCollaborationYearCount().entrySet()) {
graphMLContent.append("\t<data key=\"latest_collaboration\">"
+ publicationInfo.getKey()
+ "</data>\n");
graphMLContent.append("\t<data key=\"num_latest_collaboration\">"
+ publicationInfo.getValue()
+ "</data>\n");
}
}
if (currentEdge.getUnknownCollaborationYearCount() != null) {
graphMLContent.append("\t<data key=\"num_unknown_collaboration\">"
+ currentEdge.getUnknownCollaborationYearCount()
+ "</data>\n");
}
graphMLContent.append("</edge>\n");
}
private void generateNodeSectionContent(CoAuthorshipData coAuthorshipData,
StringBuilder graphMLContent) {
graphMLContent.append("<!-- nodes -->\n");
Node egoNode = coAuthorshipData.getEgoNode();
Set<Node> 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<Node> orderedAuthorNodes = new ArrayList<Node>(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("<node id=\"" + node.getNodeID() + "\">\n");
graphMLContent.append("\t<data key=\"url\">" + node.getNodeURI() + "</data>\n");
graphMLContent.append("\t<data key=\"label\">" + node.getNodeName() + "</data>\n");
if (profileURL != null) {
graphMLContent.append("\t<data key=\"profile_url\">" + profileURL + "</data>\n");
}
graphMLContent.append("\t<data key=\"number_of_authored_works\">"
+ node.getNumOfAuthoredWorks()
+ "</data>\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<String, Integer> publicationInfo
: node.getEarliestPublicationYearCount().entrySet()) {
graphMLContent.append("\t<data key=\"earliest_publication\">"
+ publicationInfo.getKey()
+ "</data>\n");
graphMLContent.append("\t<data key=\"num_earliest_publication\">"
+ publicationInfo.getValue()
+ "</data>\n");
}
}
if (node.getLatestPublicationYearCount() != null) {
for (Map.Entry<String, Integer> publicationInfo
: node.getLatestPublicationYearCount().entrySet()) {
graphMLContent.append("\t<data key=\"latest_publication\">"
+ publicationInfo.getKey()
+ "</data>\n");
graphMLContent.append("\t<data key=\"num_latest_publication\">"
+ publicationInfo.getValue()
+ "</data>\n");
}
}
if (node.getUnknownPublicationYearCount() != null) {
graphMLContent.append("\t<data key=\"num_unknown_publication\">"
+ node.getUnknownPublicationYearCount()
+ "</data>\n");
}
graphMLContent.append("</node>\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<Map<String, String>> schema,
StringBuilder graphMLContent) {
for (Map<String, String> currentNodeSchemaAttribute : schema) {
graphMLContent.append("\n<key ");
for (Map.Entry<String, String> currentAttributeKey
: currentNodeSchemaAttribute.entrySet()) {
graphMLContent.append(currentAttributeKey.getKey()
+ "=\"" + currentAttributeKey.getValue()
+ "\" ");
}
if (currentNodeSchemaAttribute.containsKey("default")) {
graphMLContent.append(">\n");
graphMLContent.append("<default>");
graphMLContent.append(currentNodeSchemaAttribute.get("default"));
graphMLContent.append("</default>\n");
graphMLContent.append("</key>\n");
} else {
graphMLContent.append("/>\n");
}
}
}
}

View file

@ -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<CoAuthorshipData> {
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<Node> nodes = new HashSet<Node>();
Map<String, BiboDocument> biboDocumentURLToVO = new HashMap<String, BiboDocument>();
Map<String, Set<Node>> biboDocumentURLToCoAuthors = new HashMap<String, Set<Node>>();
Map<String, Node> nodeURLToVO = new HashMap<String, Node>();
Map<String, Edge> edgeUniqueIdentifierToVO = new HashMap<String, Edge>();
Node egoNode = null;
Set<Edge> edges = new HashSet<Edge>();
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<Node> coAuthorsForCurrentBiboDocument;
if (biboDocumentURLToCoAuthors.containsKey(biboDocument.getDocumentURL())) {
coAuthorsForCurrentBiboDocument = biboDocumentURLToCoAuthors
.get(biboDocument.getDocumentURL());
} else {
coAuthorsForCurrentBiboDocument = new HashSet<Node>();
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<Node> nodes,
Map<String, BiboDocument> biboDocumentURLToVO,
Map<String, Set<Node>> biboDocumentURLToCoAuthors,
Set<Edge> edges) {
Set<Node> nodesToBeRemoved = new HashSet<Node>();
for (Map.Entry<String, Set<Node>> currentBiboDocumentEntry
: biboDocumentURLToCoAuthors.entrySet()) {
if (currentBiboDocumentEntry.getValue().size() > MAX_AUTHORS_PER_PAPER_ALLOWED) {
BiboDocument currentBiboDocument = biboDocumentURLToVO
.get(currentBiboDocumentEntry.getKey());
Set<Edge> edgesToBeRemoved = new HashSet<Edge>();
for (Edge currentEdge : edges) {
Set<BiboDocument> 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<String, BiboDocument> biboDocumentURLToVO,
Map<String, Set<Node>> biboDocumentURLToCoAuthors, Set<Edge> edges,
Map<String, Edge> edgeUniqueIdentifierToVO) {
for (Map.Entry<String, Set<Node>> 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<Edge> newlyAddedEdges = new HashSet<Edge>();
/*
* 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<Node> coAuthorNodes = new ArrayList<Node>(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<String, Edge> 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<String, VivoCollegeOrSchool> 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);
}
}

View file

@ -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<String, String> 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<CoAuthorshipData> 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<CoAuthorshipData> queryManager =
new CoAuthorshipQueryRunner(egoURI, dataSource, log);
CoAuthorshipData authorNodesAndEdges =
queryManager.getQueryResult();
return prepareStandaloneResponse(egoURI,
authorNodesAndEdges,
vitroRequest);
}
private String getCoauthorsPerYearCSVContent(Map<String, Set<Node>> yearToCoauthors) {
StringBuilder csvFileContent = new StringBuilder();
csvFileContent.append("Year, Count, Co-Author(s)\n");
for (Entry<String, Set<Node>> 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<Node> 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<String, String> prepareSparklineDataResponse(CoAuthorshipData authorNodesAndEdges) {
String outputFileName;
Map<String, Set<Node>> yearToCoauthors = new TreeMap<String, Set<Node>>();
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<String, String> fileData = new HashMap<String, String>();
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<String, String> 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<String, String> fileData = new HashMap<String, String>();
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<String, Object> body = new HashMap<String, Object>();
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);
}
}

View file

@ -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<String, String> VIS_DIV_NAMES = new HashMap<String, String>() { {
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<String, Set<Node>> yearToUniqueCoauthors;
private Log log;
private SparklineData sparklineData;
private String individualURI;
public CoAuthorshipVisCodeGenerator(String individualURI,
String visMode,
String visContainer,
Map<String, Set<Node>> 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<String> publishedYears = new HashSet<String>(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("<style type='text/css'>"
+ "." + VISUALIZATION_STYLE_CLASS + " table{"
+ " margin: 0;"
+ " padding: 0;"
+ " width: auto;"
+ " border-collapse: collapse;"
+ " border-spacing: 0;"
+ " vertical-align: inherit;"
+ "}"
+ ".incomplete-data-holder {"
+ ""
+ "}"
+ "td.sparkline_number { text-align:right; "
+ "padding-right:5px; }"
+ "td.sparkline_text {text-align:left;}"
+ "</style>\n");
visualizationCode.append("<script type=\"text/javascript\">\n"
+ "function drawUniqueCoauthorCountVisualization(providedSparklineImgTD) {\n"
+ "var data = new google.visualization.DataTable();\n"
+ "data.addColumn('string', 'Year');\n"
+ "data.addColumn('number', 'Unique co-authors');\n"
+ "data.addRows(" + numOfYearsToBeRendered + ");\n");
int uniqueCoAuthorCounter = 0;
int renderedFullSparks = 0;
Set<Node> allCoAuthorsWithKnownAuthorshipYears = new HashSet<Node>();
for (int publicationYear = minPubYearConsidered;
publicationYear <= currentYear;
publicationYear++) {
String publicationYearAsString = String.valueOf(publicationYear);
Set<Node> currentCoAuthors = yearToUniqueCoauthors.get(publicationYearAsString);
Integer currentUniqueCoAuthors = null;
if (currentCoAuthors != null) {
currentUniqueCoAuthors = currentCoAuthors.size();
allCoAuthorsWithKnownAuthorshipYears.addAll(currentCoAuthors);
} else {
currentUniqueCoAuthors = 0;
}
visualizationCode.append("data.setValue("
+ uniqueCoAuthorCounter
+ ", 0, '"
+ publicationYearAsString
+ "');\n");
visualizationCode.append("data.setValue("
+ uniqueCoAuthorCounter
+ ", 1, "
+ currentUniqueCoAuthors
+ ");\n");
uniqueCoAuthorCounter++;
}
/*
* For the purpose of this visualization I have come up with a term "Sparks" which
* essentially means data points.
* Sparks that will be rendered in full mode will always be the one's which have any year
* associated with it. Hence.
* */
renderedFullSparks = allCoAuthorsWithKnownAuthorshipYears.size();
/*
* Total publications will also consider publications that have no year associated with
* them. Hence.
* */
Integer unknownYearCoauthors = 0;
if (yearToUniqueCoauthors.get(VOConstants.DEFAULT_PUBLICATION_YEAR) != null) {
unknownYearCoauthors = yearToUniqueCoauthors
.get(VOConstants.DEFAULT_PUBLICATION_YEAR).size();
}
String sparklineDisplayOptions = "{width: 65, height: 30, showAxisLines: false, "
+ "showValueLabels: false, labelPosition: 'none'}";
if (providedVisContainerID != null) {
visContainerID = providedVisContainerID;
} else {
visContainerID = DEFAULT_VISCONTAINER_DIV_ID;
}
/*
* By default these represents the range of the rendered sparks. Only in case of
* "short" sparkline mode we will set the Earliest RenderedPublication year to
* "currentYear - 10".
* */
sparklineData.setEarliestRenderedPublicationYear(minPublishedYear);
sparklineData.setLatestRenderedPublicationYear(currentYear);
/*
* The Full Sparkline will be rendered by default. Only if the url has specific mention of
* SHORT_SPARKLINE_MODE_KEY then we render the short sparkline and not otherwise.
* */
/*
* Since building StringBuilder objects (which is being used to store the vis code) is
* essentially a side-effecting process, we have both the activators method as
* side-effecting. They both side-effect "visualizationCode"
* */
if (VisualizationFrameworkConstants.SHORT_SPARKLINE_VIS_MODE.equalsIgnoreCase(visMode)) {
sparklineData.setEarliestRenderedPublicationYear(shortSparkMinYear);
generateShortSparklineVisualizationContent(currentYear,
shortSparkMinYear,
visContainerID,
visualizationCode,
unknownYearCoauthors,
sparklineDisplayOptions);
} else {
generateFullSparklineVisualizationContent(currentYear,
minPubYearConsidered,
visContainerID,
visualizationCode,
unknownYearCoauthors,
renderedFullSparks,
sparklineDisplayOptions);
}
log.debug(visualizationCode);
return visualizationCode.toString();
}
private void generateShortSparklineVisualizationContent(int currentYear,
int shortSparkMinYear,
String visContainerID,
StringBuilder visualizationCode,
int unknownYearCoauthors,
String sparklineDisplayOptions) {
/*
* Create a view of the data containing only the column pertaining to publication count.
* */
visualizationCode.append("var shortSparklineView = "
+ "new google.visualization.DataView(data);\n"
+ "shortSparklineView.setColumns([1]);\n");
/*
* 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.
* */
visualizationCode.append("shortSparklineView.setRows("
+ "data.getFilteredRows([{column: 0, "
+ "minValue: '" + shortSparkMinYear + "', "
+ "maxValue: '" + currentYear + "'}])"
+ ");\n");
/*
* Create the vis object and draw it in the div pertaining to short-sparkline.
* */
visualizationCode.append("var short_spark = new google.visualization.ImageSparkLine("
+ "providedSparklineImgTD[0]"
+ ");\n"
+ "short_spark.draw(shortSparklineView, "
+ sparklineDisplayOptions + ");\n");
/*
* We want to display how many publication counts were considered, so this is used
* to calculate this.
* */
visualizationCode.append("var shortSparkRows = shortSparklineView.getViewRows();\n"
+ "var renderedShortSparks = 0;\n"
+ "$.each(shortSparkRows, function(index, value) {"
+ "renderedShortSparks += data.getValue(value, 1);"
+ "});\n");
/*
* Generate the text introducing the vis.
* */
String imcompleteDataText = "This information is based solely on publications which "
+ "have been loaded into the VIVO system. "
+ "This may only be a small sample of the person\\'s "
+ "total work.";
visualizationCode.append("$('#" + VIS_DIV_NAMES.get("SHORT_SPARK")
+ " td.sparkline_number')" + ".text("
+ "parseInt(renderedShortSparks) + "
+ "parseInt(" + unknownYearCoauthors + "));");
visualizationCode.append("var shortSparksText = ''"
+ "+ ' co-author(s) within the last 10 years '"
+ "<span class=\"incomplete-data-holder\" title=\""
+ imcompleteDataText + "\">incomplete data</span>'"
+ "+ '';"
+ "$('#" + VIS_DIV_NAMES.get("SHORT_SPARK")
+ " td.sparkline_text').html(shortSparksText);");
visualizationCode.append("}\n ");
/*
* Generate the code that will activate the visualization. It takes care of creating div
* elements to hold the actual sparkline image and then calling the
* drawUniqueCoauthorCountVisualization function.
* */
visualizationCode.append(generateVisualizationActivator(VIS_DIV_NAMES.get("SHORT_SPARK"),
visContainerID));
}
private void generateFullSparklineVisualizationContent(int currentYear,
int minPubYearConsidered,
String visContainerID,
StringBuilder visualizationCode,
int unknownYearCoauthors,
int renderedFullSparks,
String sparklineDisplayOptions) {
String csvDownloadURLHref = "";
if (getCSVDownloadURL() != null) {
csvDownloadURLHref = "<a href=\"" + getCSVDownloadURL()
+ "\" class=\"inline_href\">(.CSV File)</a>";
} else {
csvDownloadURLHref = "";
}
visualizationCode.append("var fullSparklineView = "
+ "new google.visualization.DataView(data);\n"
+ "fullSparklineView.setColumns([1]);\n");
visualizationCode.append("var full_spark = new google.visualization.ImageSparkLine("
+ "providedSparklineImgTD[0]"
+ ");\n"
+ "full_spark.draw(fullSparklineView, "
+ sparklineDisplayOptions + ");\n");
visualizationCode.append("$('#" + VIS_DIV_NAMES.get("FULL_SPARK")
+ " td.sparkline_number')"
+ ".text('" + (renderedFullSparks
+ unknownYearCoauthors) + "');");
visualizationCode.append("var allSparksText = ''"
+ "+ ' co-author(s) from '"
+ "+ ' <span class=\"sparkline_range\">"
+ "" + minPubYearConsidered + " to " + currentYear + ""
+ "</span> '"
+ "+ ' " + csvDownloadURLHref + " ';"
+ "$('#" + VIS_DIV_NAMES.get("FULL_SPARK")
+ " td.sparkline_text').html(allSparksText);");
visualizationCode.append("}\n ");
visualizationCode.append(generateVisualizationActivator(VIS_DIV_NAMES.get("FULL_SPARK"),
visContainerID));
}
private String generateVisualizationActivator(String sparklineID, String visContainerID) {
String sparklineTableWrapper = "\n"
+ "var table = $('<table>');"
+ "table.attr('class', 'sparkline_wrapper_table');"
+ "var row = $('<tr>');"
+ "sparklineImgTD = $('<td>');"
+ "sparklineImgTD.attr('id', '" + sparklineID + "_img');"
+ "sparklineImgTD.attr('width', '65');"
+ "sparklineImgTD.attr('align', 'right');"
+ "sparklineImgTD.attr('class', '" + VISUALIZATION_STYLE_CLASS + "');"
+ "row.append(sparklineImgTD);"
+ "var sparklineNumberTD = $('<td>');"
+ "sparklineNumberTD.attr('width', '30');"
+ "sparklineNumberTD.attr('align', 'right');"
+ "sparklineNumberTD.attr('class', 'sparkline_number');"
+ "row.append(sparklineNumberTD);"
+ "var sparklineTextTD = $('<td>');"
+ "sparklineTextTD.attr('width', '350');"
+ "sparklineTextTD.attr('class', 'sparkline_text');"
+ "row.append(sparklineTextTD);"
+ "table.append(row);"
+ "table.prependTo('#" + sparklineID + "');\n";
return "$(document).ready(function() {"
+ "var sparklineImgTD; "
/*
* This is a nuclear option (creating the container in which everything goes)
* the only reason this will be ever used is the API user never submitted a
* container ID in which everything goes. The alternative was to let the
* vis not appear in the calling page at all. So now atleast vis appears but
* appended at the bottom of the body.
* */
+ "if ($('#" + visContainerID + "').length === 0) {"
+ " $('<div/>', {'id': '" + visContainerID + "'"
+ " }).appendTo('body');"
+ "}"
+ "if ($('#" + sparklineID + "').length === 0) {"
+ "$('<div/>', {'id': '" + sparklineID + "',"
+ "'class': '" + VISUALIZATION_STYLE_CLASS + "'"
+ "}).prependTo('#" + visContainerID + "');"
+ sparklineTableWrapper
+ "}"
+ "drawUniqueCoauthorCountVisualization(sparklineImgTD);"
+ "});"
+ "</script>\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 <a href='"
+ getCSVDownloadURL() + "'>.csv</a> file.<br />";
sparklineData.setDownloadDataLink(getCSVDownloadURL());
} else {
csvDownloadURLHref = "";
}
} else {
csvDownloadURLHref = "No data available to export.<br />";
}
String tableCode = generateDataTable();
divContextCode.append("<p>" + tableCode + csvDownloadURLHref + "</p>");
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 = "<a href='" + fullTimelineNetworkURL
+ "'>View full timeline and co-author network.</a>";
sparklineData.setFullTimelineNetworkLink(fullTimelineNetworkURL);
} else {
fullTimelineLink = "No data available to render full timeline.<br />";
}
divContextCode.append("<p>" + fullTimelineLink + "</p>");
return divContextCode.toString();
}
private String generateDataTable() {
StringBuilder dataTable = new StringBuilder();
dataTable.append("<table id='sparkline_data_table'>"
+ "<caption>Unique Co-Authors per year</caption>"
+ "<thead>"
+ "<tr>"
+ "<th>Year</th>"
+ "<th>Count</th>"
+ "</tr>"
+ "</thead>"
+ "<tbody>");
for (Entry<String, Set<Node>> currentEntry : yearToUniqueCoauthors.entrySet()) {
dataTable.append("<tr>"
+ "<td>" + currentEntry.getKey() + "</td>"
+ "<td>" + currentEntry.getValue().size() + "</td>"
+ "</tr>");
}
dataTable.append("</tbody>\n </table>\n");
return dataTable.toString();
}
public SparklineData getValueObjectContainer() {
return sparklineData;
}
}

View file

@ -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<Edge> {
@Override
public int compare(Edge arg0, Edge arg1) {
return arg0.getEdgeID() - arg1.getEdgeID();
}
}

View file

@ -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<Node> {
@Override
public int compare(Node arg0, Node arg1) {
return arg0.getNodeID() - arg1.getNodeID();
}
}

View file

@ -24,20 +24,17 @@ import com.itextpdf.text.pdf.PdfWriter;
import edu.cornell.mannlib.vitro.webapp.beans.Portal; import edu.cornell.mannlib.vitro.webapp.beans.Portal;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; 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.ResponseValues;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues; 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.VisualizationFrameworkConstants;
import edu.cornell.mannlib.vitro.webapp.visualization.exceptions.MalformedQueryParametersException; 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.Grant;
import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.Individual; 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.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.PDFDocument;
import edu.cornell.mannlib.vitro.webapp.visualization.visutils.QueryRunner; 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 if (VisualizationFrameworkConstants.DATA_RENDER_MODE
.equalsIgnoreCase(renderMode)) { .equalsIgnoreCase(renderMode)) {
/*
return prepareDataResponse(investigator, return prepareDataResponse(investigator,
piGrants, piGrants,
yearToGrantCount); yearToGrantCount);
*/
} }
/* /*
@ -173,7 +173,7 @@ public class PersonGrantCountRequestHandler implements VisualizationRequestHandl
* @param yearToGrantCount * @param yearToGrantCount
* @return * @return
*/ */
private FileResponseValues prepareDataResponse( private Map<String, String> prepareDataResponse(
Individual investigator, Individual investigator,
Set<Grant> piGrants, Set<Grant> piGrants,
Map<String, Integer> yearToGrantCount) { Map<String, Integer> yearToGrantCount) {
@ -203,7 +203,9 @@ public class PersonGrantCountRequestHandler implements VisualizationRequestHandl
Map<String, Object> fileContents = new HashMap<String, Object>(); Map<String, Object> fileContents = new HashMap<String, Object>();
fileContents.put("fileContent", getGrantsOverTimeCSVContent(yearToGrantCount)); fileContents.put("fileContent", getGrantsOverTimeCSVContent(yearToGrantCount));
return new FileResponseValues(new ContentType(), outputFileName, fileContents); // return new FileResponseValues(new ContentType(), outputFileName, fileContents);
return new HashMap<String, String>();
} }
/** /**
@ -329,47 +331,27 @@ public class PersonGrantCountRequestHandler implements VisualizationRequestHandl
e.printStackTrace(); e.printStackTrace();
} }
} }
}
@Override
public Object generateAjaxVisualization(VitroRequest vitroRequest, Log log,
DataSource dataSource) throws MalformedQueryParametersException {
// TODO Auto-generated method stub
return null;
}
@Override
public Map<String, String> 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;
}
}

View file

@ -17,7 +17,7 @@ import java.util.Map.Entry;
import org.apache.commons.logging.Log; 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.controller.visualization.VisualizationFrameworkConstants;
import edu.cornell.mannlib.vitro.webapp.visualization.constants.VOConstants; 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.constants.VisConstants;
@ -547,18 +547,18 @@ public class PersonGrantCountVisCodeGenerator {
+ secondaryContextPath + secondaryContextPath
+ "?" + VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY + "?" + VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY
+ "=" + URLEncoder.encode(individualURI, + "=" + URLEncoder.encode(individualURI,
VisualizationController.URL_ENCODING_SCHEME) StandardVisualizationController.URL_ENCODING_SCHEME)
.toString() .toString()
+ "&" + VisualizationFrameworkConstants.VIS_TYPE_KEY + "&" + VisualizationFrameworkConstants.VIS_TYPE_KEY
+ "=" + URLEncoder.encode( + "=" + URLEncoder.encode(
VisualizationFrameworkConstants VisualizationFrameworkConstants
.PERSON_GRANT_COUNT_VIS, .PERSON_GRANT_COUNT_VIS,
VisualizationController.URL_ENCODING_SCHEME) StandardVisualizationController.URL_ENCODING_SCHEME)
.toString() .toString()
+ "&" + VisualizationFrameworkConstants.RENDER_MODE_KEY + "&" + VisualizationFrameworkConstants.RENDER_MODE_KEY
+ "=" + URLEncoder.encode(VisualizationFrameworkConstants + "=" + URLEncoder.encode(VisualizationFrameworkConstants
.DATA_RENDER_MODE, .DATA_RENDER_MODE,
VisualizationController.URL_ENCODING_SCHEME) StandardVisualizationController.URL_ENCODING_SCHEME)
.toString(); .toString();
return downloadURL; return downloadURL;
} else { } else {
@ -586,16 +586,16 @@ public class PersonGrantCountVisCodeGenerator {
+ "?" + "?"
+ VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY + VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY
+ "=" + URLEncoder.encode(individualURI, + "=" + URLEncoder.encode(individualURI,
VisualizationController.URL_ENCODING_SCHEME).toString() StandardVisualizationController.URL_ENCODING_SCHEME).toString()
+ "&" + "&"
+ VisualizationFrameworkConstants.VIS_TYPE_KEY + VisualizationFrameworkConstants.VIS_TYPE_KEY
+ "=" + URLEncoder.encode("person_level", + "=" + URLEncoder.encode("person_level",
VisualizationController.URL_ENCODING_SCHEME).toString() StandardVisualizationController.URL_ENCODING_SCHEME).toString()
+ "&" + "&"
+ VisualizationFrameworkConstants.RENDER_MODE_KEY + VisualizationFrameworkConstants.RENDER_MODE_KEY
+ "=" + URLEncoder.encode(VisualizationFrameworkConstants + "=" + URLEncoder.encode(VisualizationFrameworkConstants
.STANDALONE_RENDER_MODE, .STANDALONE_RENDER_MODE,
VisualizationController.URL_ENCODING_SCHEME).toString(); StandardVisualizationController.URL_ENCODING_SCHEME).toString();
fullTimelineLink = "<a href='" + fullTimelineNetworkURL + "'>View all VIVO " fullTimelineLink = "<a href='" + fullTimelineNetworkURL + "'>View all VIVO "
+ "grants and corresponding co-pi network.</a>"; + "grants and corresponding co-pi network.</a>";

View file

@ -9,7 +9,6 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.Map.Entry; import java.util.Map.Entry;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletOutputStream; import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse; 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.beans.Portal;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; 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.ResponseValues;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues; 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.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.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.BiboDocument;
import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.Individual; 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.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.PDFDocument;
import edu.cornell.mannlib.vitro.webapp.visualization.visutils.QueryRunner; 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 * This request handler is used to serve the content related to an individual's
* publications over the years like, * publications over the years like, 1. Sprakline representing this 2. An entire
* 1. Sprakline representing this * page dedicated to the sparkline vis which will also have links to download
* 2. An entire page dedicated to the sparkline vis which will also have links to * the data using which the sparkline was rendered & its tabular representation
* download the data using which the sparkline was rendered & its tabular representation etc. * etc. 3. Downloadable CSV file containing number of publications over the
* 3. Downloadable CSV file containing number of publications over the years. * years. 4. Downloadable PDf file containing the publications content, among
* 4. Downloadable PDf file containing the publications content, among other things. * other things. Currently this is disabled because the feature is half-baked.
* Currently this is disabled because the feature is half-baked. We plan to activate this in * We plan to activate this in the next major release.
* the next major release.
* *
* @author cdtank * @author cdtank
*/ */
public class PersonPublicationCountRequestHandler implements VisualizationRequestHandler { public class PersonPublicationCountRequestHandler implements
VisualizationRequestHandler {
public ResponseValues generateVisualization(VitroRequest vitroRequest,
Log log,
DataSource dataSource) {
String peronURI = vitroRequest.getParameter(
VisualizationFrameworkConstants
.INDIVIDUAL_URI_KEY);
String renderMode = vitroRequest.getParameter( @Override
VisualizationFrameworkConstants public Object generateAjaxVisualization(VitroRequest vitroRequest, Log log,
.RENDER_MODE_KEY); DataSource dataSource) throws MalformedQueryParametersException {
String visMode = vitroRequest.getParameter(
VisualizationFrameworkConstants
.VIS_MODE_KEY);
String visContainer = vitroRequest.getParameter( String personURI = vitroRequest
VisualizationFrameworkConstants .getParameter(
.VIS_CONTAINER_KEY); VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY);
QueryRunner<Set<BiboDocument>> queryManager = String visMode = vitroRequest
new PersonPublicationCountQueryRunner(peronURI, dataSource, log); .getParameter(
VisualizationFrameworkConstants.VIS_MODE_KEY);
try { String visContainer = vitroRequest
Set<BiboDocument> authorDocuments = queryManager.getQueryResult(); .getParameter(
VisualizationFrameworkConstants.VIS_CONTAINER_KEY);
/* QueryRunner<Set<BiboDocument>> queryManager = new PersonPublicationCountQueryRunner(
* Create a map from the year to number of publications. Use the BiboDocument's personURI,
* parsedPublicationYear to populate the data. dataSource,
* */ log);
Map<String, Integer> yearToPublicationCount =
UtilityFunctions.getYearToPublicationCount(authorDocuments);
Individual author = ((PersonPublicationCountQueryRunner) queryManager).getAuthor();
if (VisualizationFrameworkConstants.DATA_RENDER_MODE Set<BiboDocument> authorDocuments = queryManager.getQueryResult();
.equalsIgnoreCase(renderMode)) {
return prepareDataResponse(author,
authorDocuments,
yearToPublicationCount);
}
/*
* For now we are disabling the capability to render pdf file.
* */
/*
if (VisualizationFrameworkConstants.PDF_RENDER_MODE
.equalsIgnoreCase(renderMode)) {
preparePDFResponse(author,
authorDocuments,
yearToPublicationCount,
response);
return;
}
*/
/*
* Computations required to generate HTML for the sparkline & related context.
* */
PersonPublicationCountVisCodeGenerator visualizationCodeGenerator =
new PersonPublicationCountVisCodeGenerator(vitroRequest.getContextPath(),
peronURI,
visMode,
visContainer,
authorDocuments,
yearToPublicationCount,
log);
SparklineData sparklineData = visualizationCodeGenerator
.getValueObjectContainer();
/*
* This is side-effecting because the response of this method is just to redirect to
* a page with visualization on it.
* */
RequestDispatcher requestDispatcher = null;
if (VisualizationFrameworkConstants.DYNAMIC_RENDER_MODE
.equalsIgnoreCase(renderMode)) {
return prepareDynamicResponse(vitroRequest, /*
sparklineData, * Create a map from the year to number of publications. Use the
yearToPublicationCount); * BiboDocument's parsedPublicationYear to populate the data.
*/
} else { Map<String, Integer> yearToPublicationCount =
return prepareStandaloneResponse(vitroRequest, UtilityFunctions.getYearToPublicationCount(authorDocuments);
sparklineData);
} 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<String, Integer> yearToPublicationCount) { @Override
public Map<String, String> generateDataVisualization(VitroRequest vitroRequest, Log log,
DataSource dataSource) throws MalformedQueryParametersException {
String personURI = vitroRequest
.getParameter(VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY);
QueryRunner<Set<BiboDocument>> queryManager = new PersonPublicationCountQueryRunner(
personURI,
dataSource,
log);
Set<BiboDocument> authorDocuments = queryManager.getQueryResult();
/*
* Create a map from the year to number of publications. Use the
* BiboDocument's parsedPublicationYear to populate the data.
*/
Map<String, Integer> 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<Set<BiboDocument>> queryManager = new PersonPublicationCountQueryRunner(
personURI,
dataSource,
log);
Set<BiboDocument> authorDocuments = queryManager.getQueryResult();
/*
* Create a map from the year to number of publications. Use the
* BiboDocument's parsedPublicationYear to populate the data.
*/
Map<String, Integer> 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<String, Integer> yearToPublicationCount) {
StringBuilder csvFileContent = new StringBuilder(); StringBuilder csvFileContent = new StringBuilder();
csvFileContent.append("Year, Publications\n"); csvFileContent.append("Year, Publications\n");
for (Entry<String, Integer> currentEntry : yearToPublicationCount.entrySet()) { for (Entry<String, Integer> currentEntry : yearToPublicationCount
csvFileContent.append(StringEscapeUtils.escapeCsv(currentEntry.getKey())); .entrySet()) {
csvFileContent.append(StringEscapeUtils.escapeCsv(currentEntry
.getKey()));
csvFileContent.append(","); csvFileContent.append(",");
csvFileContent.append(currentEntry.getValue()); csvFileContent.append(currentEntry.getValue());
csvFileContent.append("\n"); csvFileContent.append("\n");
@ -172,169 +202,156 @@ public class PersonPublicationCountRequestHandler implements VisualizationReques
} }
/** /**
* Provides response when csv file containing the publication count over the years * Provides response when csv file containing the publication count over the
* is requested. * years is requested.
*
* @param author * @param author
* @param authorDocuments * @param authorDocuments
* @param yearToPublicationCount * @param yearToPublicationCount
* @return * @return
*/ */
private FileResponseValues prepareDataResponse( private Map<String, String> prepareDataResponse(Individual author,
Individual author, Set<BiboDocument> authorDocuments,
Set<BiboDocument> authorDocuments, Map<String, Integer> yearToPublicationCount) {
Map<String, Integer> 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";
String authorName = null;
Map<String, Object> fileContents = new HashMap<String, Object>();
fileContents.put("fileContent", getPublicationsOverTimeCSVContent(yearToPublicationCount)); /*
* To protect against cases where there are no author documents
return new FileResponseValues(new ContentType(), outputFileName, fileContents); * 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<String, String> fileData = new HashMap<String, String>();
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 vreq
* @param valueObjectContainer * @param valueObjectContainer
* @return * @return
*/ */
private TemplateResponseValues prepareStandaloneResponse(VitroRequest vreq, private TemplateResponseValues prepareStandaloneResponse(VitroRequest vreq,
SparklineData valueObjectContainer) { SparklineData valueObjectContainer) {
Portal portal = vreq.getPortal(); Portal portal = vreq.getPortal();
String standaloneTemplate = "/visualization/publicationCount.ftl";
Map<String, Object> body = new HashMap<String, Object>(); String standaloneTemplate = "/visualization/publicationCount.ftl";
body.put("portalBean", portal);
body.put("title", "Individual Publication Count visualization"); Map<String, Object> body = new HashMap<String, Object>();
body.put("sparklineVO", valueObjectContainer); 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 * Provides response when the publication sparkline has to be rendered in
* page, e.g. profile page. * already existing page, e.g. profile page.
*
* @param vreq * @param vreq
* @param valueObjectContainer * @param valueObjectContainer
* @param yearToPublicationCount * @param yearToPublicationCount
* @return * @return
*/ */
private TemplateResponseValues prepareDynamicResponse( private TemplateResponseValues prepareDynamicResponse(VitroRequest vreq,
VitroRequest vreq, SparklineData valueObjectContainer, boolean shouldVIVOrenderVis) {
SparklineData valueObjectContainer,
Map<String, Integer> yearToPublicationCount) {
Portal portal = vreq.getPortal(); Portal portal = vreq.getPortal();
String dynamicTemplate = "/visualization/sparklineAjaxVisContent.ftl";
String dynamicTemplate = "/visualization/sparklineAjaxVisContent.ftl"; Map<String, Object> body = new HashMap<String, Object>();
body.put("portalBean", portal);
body.put("sparklineVO", valueObjectContainer);
body.put("shouldVIVOrenderVis", shouldVIVOrenderVis);
Map<String, Object> body = new HashMap<String, Object>(); return new TemplateResponseValues(dynamicTemplate, body);
body.put("portalBean", portal);
body.put("sparklineVO", valueObjectContainer);
/*
* DO NOT DO THIS HERE. Set stylesheets/scripts in the *.ftl instead using $(scripts.add)
* */
// body.put("scripts", "/templates/visualization/visualization_scripts.jsp");
if (yearToPublicationCount.size() > 0) {
body.put("shouldVIVOrenderVis", true);
} else {
body.put("shouldVIVOrenderVis", false);
}
return new TemplateResponseValues(dynamicTemplate, body);
} }
private void preparePDFResponse( private void preparePDFResponse(Individual author,
Individual author, Set<BiboDocument> authorDocuments,
Set<BiboDocument> authorDocuments, Map<String, Integer> yearToPublicationCount,
Map<String, Integer> yearToPublicationCount, HttpServletResponse response) {
HttpServletResponse response) {
String authorName = null;
String authorName = null;
// To protect against cases where there are no author documents
// To protect against cases where there are no author documents associated with the // associated with the
// / individual. // / individual.
if (authorDocuments.size() > 0) { if (authorDocuments.size() > 0) {
authorName = author.getIndividualLabel(); 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)) { if (StringUtils.isBlank(authorName)) {
authorName = "no-author"; authorName = "no-author";
} }
String outputFileName = UtilityFunctions.slugify(authorName) + "_report" + ".pdf"; String outputFileName = UtilityFunctions.slugify(authorName)
+ "_report" + ".pdf";
response.setContentType("application/pdf"); response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment;filename=" + outputFileName); response.setHeader("Content-Disposition", "attachment;filename="
+ outputFileName);
ServletOutputStream responseOutputStream;
try { ServletOutputStream responseOutputStream;
responseOutputStream = response.getOutputStream(); try {
responseOutputStream = response.getOutputStream();
Document document = new Document(); Document document = new Document();
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfWriter pdfWriter = PdfWriter.getInstance(document, baos); PdfWriter pdfWriter = PdfWriter.getInstance(document, baos);
document.open(); document.open();
PDFDocument pdfDocument = new PDFDocument(authorName, PDFDocument pdfDocument = new PDFDocument(authorName,
yearToPublicationCount, yearToPublicationCount, document, pdfWriter);
document,
pdfWriter); document.close();
document.close(); // setting some response headers & content type
response.setHeader("Expires", "0");
// setting some response headers & content type response.setHeader("Cache-Control",
response.setHeader("Expires", "0"); "must-revalidate, post-check=0, pre-check=0");
response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0"); response.setHeader("Pragma", "public");
response.setHeader("Pragma", "public"); response.setContentLength(baos.size());
response.setContentLength(baos.size()); // write ByteArrayOutputStream to the ServletOutputStream
// write ByteArrayOutputStream to the ServletOutputStream baos.writeTo(responseOutputStream);
baos.writeTo(responseOutputStream); responseOutputStream.flush();
responseOutputStream.flush(); responseOutputStream.close();
responseOutputStream.close();
} catch (IOException e) {
} catch (IOException e) { e.printStackTrace();
e.printStackTrace(); } catch (DocumentException e) {
} catch (DocumentException e) { e.printStackTrace();
e.printStackTrace(); }
}
} }
} }

View file

@ -2,8 +2,6 @@
package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.personpubcount; package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.personpubcount;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.Collections; import java.util.Collections;
@ -17,7 +15,8 @@ import java.util.Map.Entry;
import org.apache.commons.logging.Log; 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.controller.visualization.VisualizationFrameworkConstants;
import edu.cornell.mannlib.vitro.webapp.visualization.constants.VOConstants; 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.constants.VisConstants;
@ -55,19 +54,15 @@ public class PersonPublicationCountVisCodeGenerator {
private SparklineData sparklineData; private SparklineData sparklineData;
private String contextPath;
private String individualURI; private String individualURI;
public PersonPublicationCountVisCodeGenerator(String contextPath, public PersonPublicationCountVisCodeGenerator(String individualURIParam,
String individualURIParam,
String visMode, String visMode,
String visContainer, String visContainer,
Set<BiboDocument> authorDocuments, Set<BiboDocument> authorDocuments,
Map<String, Integer> yearToPublicationCount, Map<String, Integer> yearToPublicationCount,
Log log) { Log log) {
this.contextPath = contextPath;
this.individualURI = individualURIParam; this.individualURI = individualURIParam;
this.yearToPublicationCount = yearToPublicationCount; this.yearToPublicationCount = yearToPublicationCount;
@ -407,17 +402,12 @@ public class PersonPublicationCountVisCodeGenerator {
String csvDownloadURLHref = ""; String csvDownloadURLHref = "";
try { if (getCSVDownloadURL() != null) {
if (getCSVDownloadURL() != null) {
csvDownloadURLHref = "<a href=\"" + getCSVDownloadURL()
csvDownloadURLHref = "<a href=\"" + getCSVDownloadURL() + "\" class=\"inline_href\">(.CSV File)</a>";
+ "\" class=\"inline_href\">(.CSV File)</a>";
} else {
} else {
csvDownloadURLHref = "";
}
} catch (UnsupportedEncodingException e) {
csvDownloadURLHref = ""; csvDownloadURLHref = "";
} }
@ -525,18 +515,13 @@ public class PersonPublicationCountVisCodeGenerator {
if (yearToPublicationCount.size() > 0) { if (yearToPublicationCount.size() > 0) {
try { if (getCSVDownloadURL() != null) {
if (getCSVDownloadURL() != null) {
csvDownloadURLHref = "Download data as <a href='"
csvDownloadURLHref = "Download data as <a href='" + getCSVDownloadURL() + "'>.csv</a> file.<br />";
+ getCSVDownloadURL() + "'>.csv</a> file.<br />"; sparklineData.setDownloadDataLink(getCSVDownloadURL());
sparklineData.setDownloadDataLink(getCSVDownloadURL());
} else {
} else {
csvDownloadURLHref = "";
}
} catch (UnsupportedEncodingException e) {
csvDownloadURLHref = ""; csvDownloadURLHref = "";
} }
} else { } else {
@ -552,34 +537,18 @@ public class PersonPublicationCountVisCodeGenerator {
return divContextCode.toString(); return divContextCode.toString();
} }
private String getCSVDownloadURL() private String getCSVDownloadURL() {
throws UnsupportedEncodingException {
if (yearToPublicationCount.size() > 0) { if (yearToPublicationCount.size() > 0) {
String secondaryContextPath = ""; ParamMap CSVDownloadURLParams = new ParamMap(VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY,
if (!contextPath.contains(VisualizationFrameworkConstants.VISUALIZATION_URL_PREFIX)) { individualURI,
secondaryContextPath = VisualizationFrameworkConstants.VISUALIZATION_URL_PREFIX; VisualizationFrameworkConstants.VIS_TYPE_KEY,
} VisualizationFrameworkConstants.PERSON_PUBLICATION_COUNT_VIS);
String downloadURL = contextPath return UrlBuilder.getUrl(VisualizationFrameworkConstants.DATA_VISUALIZATION_SERVICE_URL_PREFIX,
+ secondaryContextPath CSVDownloadURLParams);
+ "?" + VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY
+ "=" + URLEncoder.encode(individualURI,
VisualizationController.URL_ENCODING_SCHEME)
.toString()
+ "&" + VisualizationFrameworkConstants.VIS_TYPE_KEY
+ "=" + URLEncoder.encode(
VisualizationFrameworkConstants
.PERSON_PUBLICATION_COUNT_VIS,
VisualizationController.URL_ENCODING_SCHEME)
.toString()
+ "&" + VisualizationFrameworkConstants.RENDER_MODE_KEY
+ "=" + URLEncoder.encode(VisualizationFrameworkConstants
.DATA_RENDER_MODE,
VisualizationController.URL_ENCODING_SCHEME)
.toString();
return downloadURL;
} else { } else {
return null; return null;
} }
@ -589,31 +558,18 @@ public class PersonPublicationCountVisCodeGenerator {
StringBuilder divContextCode = new StringBuilder(); StringBuilder divContextCode = new StringBuilder();
try {
String fullTimelineLink; String fullTimelineLink;
if (yearToPublicationCount.size() > 0) { if (yearToPublicationCount.size() > 0) {
String secondaryContextPath = ""; ParamMap fullTimelineNetworkURLParams = new ParamMap(VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY,
if (!contextPath.contains(VisualizationFrameworkConstants.VISUALIZATION_URL_PREFIX)) { individualURI,
secondaryContextPath = VisualizationFrameworkConstants.VISUALIZATION_URL_PREFIX; VisualizationFrameworkConstants.VIS_TYPE_KEY,
} VisualizationFrameworkConstants.PERSON_LEVEL_VIS);
String fullTimelineNetworkURL = contextPath String fullTimelineNetworkURL = UrlBuilder.getUrl(
+ secondaryContextPath VisualizationFrameworkConstants.FREEMARKERIZED_VISUALIZATION_URL_PREFIX,
+ "?" fullTimelineNetworkURLParams);
+ VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY
+ "=" + URLEncoder.encode(individualURI,
VisualizationController.URL_ENCODING_SCHEME).toString()
+ "&"
+ VisualizationFrameworkConstants.VIS_TYPE_KEY
+ "=" + URLEncoder.encode("person_level",
VisualizationController.URL_ENCODING_SCHEME).toString()
+ "&"
+ VisualizationFrameworkConstants.RENDER_MODE_KEY
+ "=" + URLEncoder.encode(VisualizationFrameworkConstants
.STANDALONE_RENDER_MODE,
VisualizationController.URL_ENCODING_SCHEME).toString();
fullTimelineLink = "<a href='" + fullTimelineNetworkURL + "'>View all VIVO " fullTimelineLink = "<a href='" + fullTimelineNetworkURL + "'>View all VIVO "
+ "publications and corresponding co-author network.</a>"; + "publications and corresponding co-author network.</a>";
@ -625,10 +581,6 @@ public class PersonPublicationCountVisCodeGenerator {
} }
divContextCode.append("<span class=\"vis_link\">" + fullTimelineLink + "</span>"); divContextCode.append("<span class=\"vis_link\">" + fullTimelineLink + "</span>");
} catch (UnsupportedEncodingException e) {
log.error(e);
}
return divContextCode.toString(); return divContextCode.toString();
} }
@ -636,13 +588,9 @@ public class PersonPublicationCountVisCodeGenerator {
String csvDownloadURLHref = ""; String csvDownloadURLHref = "";
try { if (getCSVDownloadURL() != null) {
if (getCSVDownloadURL() != null) { csvDownloadURLHref = "<a href=\"" + getCSVDownloadURL() + "\">(.CSV File)</a>";
csvDownloadURLHref = "<a href=\"" + getCSVDownloadURL() + "\">(.CSV File)</a>"; } else {
} else {
csvDownloadURLHref = "";
}
} catch (UnsupportedEncodingException e) {
csvDownloadURLHref = ""; csvDownloadURLHref = "";
} }

View file

@ -2,17 +2,9 @@
package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.utilities; 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.HashMap;
import java.util.Map; 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.Log;
import com.google.gson.Gson; 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.query.ResultSet;
import com.hp.hpl.jena.rdf.model.RDFNode; 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.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; 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.UrlBuilder.ParamMap;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues; 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.controller.visualization.VisualizationFrameworkConstants;
import edu.cornell.mannlib.vitro.webapp.filestorage.FileServingHelper; import edu.cornell.mannlib.vitro.webapp.filestorage.FileServingHelper;
import edu.cornell.mannlib.vitro.webapp.visualization.constants.QueryFieldLabels; 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.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.AllPropertiesQueryRunner;
import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.GenericQueryRunner; 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.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.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 * 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 class UtilitiesRequestHandler implements VisualizationRequestHandler {
public ResponseValues generateVisualization(VitroRequest vitroRequest, public Object generateAjaxVisualization(VitroRequest vitroRequest,
Log log, Log log,
DataSource dataSource) { DataSource dataSource)
throws MalformedQueryParametersException {
String individualURI = vitroRequest.getParameter( String individualURI = vitroRequest.getParameter(
VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY); VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY);
@ -61,10 +50,6 @@ public class UtilitiesRequestHandler implements VisualizationRequestHandler {
String visMode = vitroRequest.getParameter( String visMode = vitroRequest.getParameter(
VisualizationFrameworkConstants.VIS_MODE_KEY); 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 * If the info being requested is about a profile which includes the name, moniker
* & image url. * & image url.
@ -83,28 +68,14 @@ public class UtilitiesRequestHandler implements VisualizationRequestHandler {
dataSource, dataSource,
log); log);
try { GenericQueryMap profilePropertiesToValues =
profileQueryHandler.getQueryResult();
GenericQueryMap profilePropertiesToValues =
profileQueryHandler.getQueryResult(); Gson profileInformation = new Gson();
profilePropertiesToValues.addEntry("imageContextPath", return profileInformation.toJson(profilePropertiesToValues);
urlBuilder.getBaseUrl());
Gson profileInformation = new Gson();
return prepareUtilitiesResponse(
profileInformation.toJson(profilePropertiesToValues),
vitroRequest);
} catch (MalformedQueryParametersException e) {
return UtilityFunctions.handleMalformedParameters(
"Visualization Query Error - Utilities Profile Info",
e.getMessage(),
vitroRequest);
}
} else if (VisualizationFrameworkConstants.IMAGE_UTILS_VIS_MODE } else if (VisualizationFrameworkConstants.IMAGE_UTILS_VIS_MODE
.equalsIgnoreCase(visMode)) { .equalsIgnoreCase(visMode)) {
/* /*
@ -131,21 +102,9 @@ public class UtilitiesRequestHandler implements VisualizationRequestHandler {
dataSource, dataSource,
log); log);
try { return getThumbnailInformation(imageQueryHandler.getQueryResult(),
fieldLabelToOutputFieldLabel);
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);
}
} else if (VisualizationFrameworkConstants.COAUTHOR_UTILS_VIS_MODE } else if (VisualizationFrameworkConstants.COAUTHOR_UTILS_VIS_MODE
.equalsIgnoreCase(visMode)) { .equalsIgnoreCase(visMode)) {
@ -160,12 +119,9 @@ public class UtilitiesRequestHandler implements VisualizationRequestHandler {
VisualizationFrameworkConstants.RENDER_MODE_KEY, VisualizationFrameworkConstants.RENDER_MODE_KEY,
VisualizationFrameworkConstants.STANDALONE_RENDER_MODE); VisualizationFrameworkConstants.STANDALONE_RENDER_MODE);
preparedURL = UrlBuilder.getUrl(VisualizationFrameworkConstants.FREEMARKERIZED_VISUALIZATION_URL_PREFIX, return UrlBuilder.getUrl(VisualizationFrameworkConstants.FREEMARKERIZED_VISUALIZATION_URL_PREFIX,
coAuthorProfileURLParams); coAuthorProfileURLParams);
return prepareUtilitiesResponse(preparedURL, vitroRequest);
} else if (VisualizationFrameworkConstants.PERSON_LEVEL_UTILS_VIS_MODE } else if (VisualizationFrameworkConstants.PERSON_LEVEL_UTILS_VIS_MODE
.equalsIgnoreCase(visMode)) { .equalsIgnoreCase(visMode)) {
/* /*
@ -179,19 +135,16 @@ public class UtilitiesRequestHandler implements VisualizationRequestHandler {
VisualizationFrameworkConstants.RENDER_MODE_KEY, VisualizationFrameworkConstants.RENDER_MODE_KEY,
VisualizationFrameworkConstants.STANDALONE_RENDER_MODE); VisualizationFrameworkConstants.STANDALONE_RENDER_MODE);
preparedURL = UrlBuilder.getUrl(VisualizationFrameworkConstants.FREEMARKERIZED_VISUALIZATION_URL_PREFIX, return UrlBuilder.getUrl(VisualizationFrameworkConstants.FREEMARKERIZED_VISUALIZATION_URL_PREFIX,
personLevelURLParams); personLevelURLParams);
return prepareUtilitiesResponse(preparedURL, vitroRequest);
} else { } else {
ParamMap individualProfileURLParams = new ParamMap(VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY, ParamMap individualProfileURLParams = new ParamMap(VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY,
individualURI); individualURI);
preparedURL = UrlBuilder.getUrl(VisualizationFrameworkConstants.INDIVIDUAL_URL_PREFIX, return UrlBuilder.getUrl(VisualizationFrameworkConstants.INDIVIDUAL_URL_PREFIX,
individualProfileURLParams); individualProfileURLParams);
return prepareUtilitiesResponse(preparedURL, vitroRequest);
} }
} }
@ -219,6 +172,7 @@ public class UtilitiesRequestHandler implements VisualizationRequestHandler {
} }
return finalThumbNailLocation; return finalThumbNailLocation;
} }
/*
private TemplateResponseValues prepareUtilitiesResponse(String preparedContent, VitroRequest vreq) { private TemplateResponseValues prepareUtilitiesResponse(String preparedContent, VitroRequest vreq) {
@ -231,6 +185,20 @@ public class UtilitiesRequestHandler implements VisualizationRequestHandler {
return new TemplateResponseValues(utilitiesTemplate, body); return new TemplateResponseValues(utilitiesTemplate, body);
}*/
@Override
public Map<String, String> 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.");
} }
} }

View file

@ -9,7 +9,7 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import edu.cornell.mannlib.vitro.webapp.visualization.constants.VOConstants; 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; import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.UtilityFunctions;
/** /**

View file

@ -9,7 +9,7 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import edu.cornell.mannlib.vitro.webapp.visualization.constants.VOConstants; 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; import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.UtilityFunctions;
/** /**

View file

@ -2,15 +2,23 @@
package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils; package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils;
import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.TreeMap; 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.lang.StringUtils;
import org.apache.commons.logging.Log;
import edu.cornell.mannlib.vitro.webapp.beans.Portal; 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.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues; 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.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(); Portal portal = vitroRequest.getPortal();
@ -139,23 +149,23 @@ public class UtilityFunctions {
return new TemplateResponseValues(VisualizationFrameworkConstants.ERROR_TEMPLATE, body); return new TemplateResponseValues(VisualizationFrameworkConstants.ERROR_TEMPLATE, body);
} }
/* public static void handleMalformedParameters(String errorMessage, public static void handleMalformedParameters(String errorPageTitle,
String errorPageTitle, String errorMessage,
VitroRequest vitroRequest, VitroRequest vitroRequest,
HttpServletRequest request, HttpServletRequest request,
HttpServletResponse response, HttpServletResponse response,
Log log) Log log)
throws ServletException, IOException { throws ServletException, IOException {
Portal portal = vitroRequest.getPortal(); Portal portal = vitroRequest.getPortal();
request.setAttribute("error", errorMessage); request.setAttribute("error", errorMessage);
RequestDispatcher requestDispatcher = request.getRequestDispatcher(Controllers.BASIC_JSP); RequestDispatcher requestDispatcher = request.getRequestDispatcher(Controllers.BASIC_JSP);
request.setAttribute("bodyJsp", "/templates/visualization/visualization_error.jsp"); request.setAttribute("bodyJsp", "/templates/visualization/visualization_error.jsp");
request.setAttribute("portalBean", portal); request.setAttribute("portalBean", portal);
request.setAttribute("title", errorPageTitle); request.setAttribute("title", errorPageTitle);
try { try {
requestDispatcher.forward(request, response); requestDispatcher.forward(request, response);
} catch (Exception e) { } catch (Exception e) {
@ -163,8 +173,8 @@ public class UtilityFunctions {
log.error(e.getMessage()); log.error(e.getMessage());
log.error(e.getStackTrace()); log.error(e.getStackTrace());
} }
}*/ }
public static Map<String, Set<CoPINode>> getGrantYearToCoPI( public static Map<String, Set<CoPINode>> getGrantYearToCoPI(
CoPIData pINodesAndEdges) { CoPIData pINodesAndEdges) {

View file

@ -1,12 +1,15 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */ /* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils; package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils;
import java.util.Map;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import com.hp.hpl.jena.query.DataSource; import com.hp.hpl.jena.query.DataSource;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; 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.ResponseValues;
import edu.cornell.mannlib.vitro.webapp.visualization.exceptions.MalformedQueryParametersException;
/** /**
* This interface is being implemented by all the visualization request handlers like * 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{ public interface VisualizationRequestHandler{
ResponseValues generateVisualization(VitroRequest vitroRequest, ResponseValues generateStandardVisualization(VitroRequest vitroRequest,
Log log, Log log,
DataSource dataSource); DataSource dataSource) throws MalformedQueryParametersException;
Object generateAjaxVisualization(VitroRequest vitroRequest,
Log log,
DataSource dataSource) throws MalformedQueryParametersException;
Map<String, String> generateDataVisualization(VitroRequest vitroRequest,
Log log,
DataSource dataSource) throws MalformedQueryParametersException;
} }