diff --git a/productMods/templates/freemarker/visualization/grantCount.ftl b/productMods/templates/freemarker/visualization/grantCount.ftl new file mode 100644 index 00000000..83c58c93 --- /dev/null +++ b/productMods/templates/freemarker/visualization/grantCount.ftl @@ -0,0 +1,7 @@ +<#-- $This file is distributed under the terms of the license in /doc/license.txt$ --> + +<#assign googleJSAPI = 'http://www.google.com/jsapi?autoload=%7B%22modules%22%3A%5B%7B%22name%22%3A%22visualization%22%2C%22version%22%3A%221%22%2C%22packages%22%3A%5B%22areachart%22%2C%22imagesparkline%22%5D%7D%5D%7D'> + +${headScripts.add(googleJSAPI)} + +<#include "/visualization/grantSparklineContent.ftl"> \ No newline at end of file diff --git a/productMods/templates/freemarker/visualization/grantSparklineContent.ftl b/productMods/templates/freemarker/visualization/grantSparklineContent.ftl new file mode 100644 index 00000000..3bcbfc04 --- /dev/null +++ b/productMods/templates/freemarker/visualization/grantSparklineContent.ftl @@ -0,0 +1,243 @@ +<#-- $This file is distributed under the terms of the license in /doc/license.txt$ --> +<#assign visContainerID = '${sparklineVO.visContainerDivID}'> + +<#if sparklineVO.shortVisMode> + <#assign sparklineContainerID = 'grant_count_short_sparkline_vis'> +<#else> + <#assign sparklineContainerID = 'grant_count_full_sparkline_vis'> + + +<#-- This is used to prevent collision between sparkline & visualization container div ids. --> +<#if visContainerID?upper_case == sparklineContainerID?upper_case> + <#assign sparklineContainerID = visContainerID + "_spark"> + + +
+ +
+ + + + +
+ +<#if sparklineVO.shortVisMode> + + + View all grants and corresponding co-pi network. + + + +<#else> + + +

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

+ + + +
\ No newline at end of file diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/persongrantcount/PersonGrantCountQueryRunner.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/persongrantcount/PersonGrantCountQueryRunner.java new file mode 100644 index 00000000..448f14eb --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/persongrantcount/PersonGrantCountQueryRunner.java @@ -0,0 +1,161 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.persongrantcount; + +import java.util.HashSet; +import java.util.Set; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; + +import com.hp.hpl.jena.iri.IRI; +import com.hp.hpl.jena.iri.IRIFactory; +import com.hp.hpl.jena.iri.Violation; +import com.hp.hpl.jena.query.DataSource; +import com.hp.hpl.jena.query.Query; +import com.hp.hpl.jena.query.QueryExecution; +import com.hp.hpl.jena.query.QueryExecutionFactory; +import com.hp.hpl.jena.query.QueryFactory; +import com.hp.hpl.jena.query.QuerySolution; +import com.hp.hpl.jena.query.ResultSet; +import com.hp.hpl.jena.query.Syntax; +import com.hp.hpl.jena.rdf.model.RDFNode; + +import edu.cornell.mannlib.vitro.webapp.visualization.constants.QueryConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.constants.QueryFieldLabels; +import edu.cornell.mannlib.vitro.webapp.visualization.exceptions.MalformedQueryParametersException; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.Grant; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.Individual; +import edu.cornell.mannlib.vitro.webapp.visualization.visutils.QueryRunner; + + +/** + * This query runner is used to execute Sparql query that will fetch all the grants for an individual + * @author bkoniden + * Deepak Konidena + * + */ +public class PersonGrantCountQueryRunner implements QueryRunner>{ + + protected static final Syntax SYNTAX = Syntax.syntaxARQ; + + private String personURI; + private DataSource dataSource; + private Individual principalInvestigator; + + public Individual getPrincipalInvestigator(){ + return principalInvestigator; + } + + private Log log; + + private static final String SPARQL_QUERY_COMMON_SELECT_CLAUSE = "" + + "SELECT (str(?PILabel) as ?PILabelLit) " + + "(str(?Grant) as ?grantLit)" + + "(str(?GrantLabel) as ?grantLabelLit)" + + "(str(?GrantStartDate) as ?grantStartDateLit)" + + "(str(?GrantEndDate) as ?grantEndDateLit)" ; + + public PersonGrantCountQueryRunner(String personURI, DataSource dataSource, Log log){ + + this.personURI = personURI; + this.dataSource = dataSource; + this.log = log; + } + + private Set createJavaValueObjects(ResultSet resultSet){ + Set PIGrant = new HashSet(); + + while(resultSet.hasNext()){ + QuerySolution solution = resultSet.nextSolution(); + + Grant grant = new Grant(solution.get(QueryFieldLabels.GRANT_URL).toString()); + + RDFNode grantLabelNode = solution.get(QueryFieldLabels.GRANT_LABEL); + if(grantLabelNode != null){ + grant.setIndividualLabel(grantLabelNode.toString()); + } + + RDFNode grantStartDateNode = solution.get(QueryFieldLabels.GRANT_START_DATE); + if(grantStartDateNode != null){ + grant.setGrantStartDate(grantStartDateNode.toString()); + } + + RDFNode grantEndDateNode = solution.get(QueryFieldLabels.GRANT_END_DATE); + if(grantEndDateNode != null){ + grant.setGrantEndDate(grantEndDateNode.toString()); + } + + /* + * Since we are getting grant count for just one PI at a time we need + * to create only one "Individual" instance. We test against the null for "PI" to + * make sure that it has not already been instantiated. + * */ + RDFNode PIURLNode = solution.get(QueryFieldLabels.PI_URL); + if (PIURLNode != null && principalInvestigator == null) { + principalInvestigator = new Individual(PIURLNode.toString()); + RDFNode PILabelNode = solution.get(QueryFieldLabels.PI_LABEL); + if (PILabelNode != null) { + principalInvestigator.setIndividualLabel(PILabelNode.toString()); + } + } + + PIGrant.add(grant); + } + return PIGrant; + } + + private ResultSet executeQuery(String queryURI, DataSource dataSource){ + + QueryExecution queryExecution = null; + + Query query = QueryFactory.create(getSparqlQuery(queryURI), SYNTAX); + queryExecution = QueryExecutionFactory.create(query,dataSource); + + return queryExecution.execSelect(); + } + + + + private String getSparqlQuery(String queryURI){ + + String sparqlQuery = QueryConstants.getSparqlPrefixQuery() + + SPARQL_QUERY_COMMON_SELECT_CLAUSE + + "(str(<" + queryURI + ">) as ?PILit) " + + "WHERE {" + + "<" + queryURI + "> rdfs:label ?PILabel;" + + "core:hasCo-PrincipalInvestigatorRole ?Role ." + + "?Role core:roleIn ?Grant ." + + "?Grant rdfs:label ?GrantLabel ; core:startDate ?GrantStartDate ; core:endDate ?GrantEndDate ." + + "}"; + + System.out.println("SPARQL query for person grant count -> \n"+ sparqlQuery); + return sparqlQuery; + } + + public Set getQueryResult() throws MalformedQueryParametersException{ + + if(StringUtils.isNotBlank(this.personURI)){ + + /* + * To test the validity of the URI submitted + */ + IRIFactory iriFactory = IRIFactory.jenaImplementation(); + IRI iri = iriFactory.create(this.personURI); + + if(iri.hasViolation(false)){ + String errorMsg = ((Violation) iri.violations(false).next()).getShortMessage(); + log.error("Grant Count vis Query " + errorMsg); + throw new MalformedQueryParametersException( + "URI provided for an individual is malformed."); + } + } else { + throw new MalformedQueryParametersException("URL parameter is either null or empty."); + } + + ResultSet resultSet = executeQuery(this.personURI, this.dataSource); + + return createJavaValueObjects(resultSet); + } + +} diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/persongrantcount/PersonGrantCountRequestHandler.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/persongrantcount/PersonGrantCountRequestHandler.java new file mode 100644 index 00000000..bd6a1ad0 --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/persongrantcount/PersonGrantCountRequestHandler.java @@ -0,0 +1,375 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.persongrantcount; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.Map.Entry; + +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang.StringEscapeUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; + +import com.hp.hpl.jena.query.DataSource; +import com.itextpdf.text.Document; +import com.itextpdf.text.DocumentException; +import com.itextpdf.text.pdf.PdfWriter; + +import edu.cornell.mannlib.vitro.webapp.beans.Portal; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.FileResponseValues; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues; +import edu.cornell.mannlib.vitro.webapp.controller.visualization.VisualizationFrameworkConstants; + +import edu.cornell.mannlib.vitro.webapp.visualization.exceptions.MalformedQueryParametersException; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.UtilityFunctions; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.visutils.VisualizationRequestHandler; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.Grant; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.Individual; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.SparklineData; +import edu.cornell.mannlib.vitro.webapp.visualization.visutils.PDFDocument; +import edu.cornell.mannlib.vitro.webapp.visualization.visutils.QueryRunner; +import edu.cornell.mannlib.vitro.webapp.web.ContentType; + + +/** + * + * This request handler is used to serve the content related to an individual's + * grants over the years like, + * 1. Sparkline representing this + * 2. An entire page dedicated to the sparkline vis which will also have links to + * download the data using which the sparkline was rendered & its tabular representation etc. + * 3. Downloadable CSV file containing number of grants over the years. + * 4. Downloadable PDf file containing the grant content, among other things. + * Currently this is disabled because the feature is half-baked. We plan to activate this in + * the next major release. + * + * @author bkoniden + * Deepak Konidena + */ +public class PersonGrantCountRequestHandler implements VisualizationRequestHandler { + + public ResponseValues generateVisualization(VitroRequest vitroRequest, + Log log, DataSource dataSource) { + + String personURI = vitroRequest + .getParameter(VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY); + + String renderMode = vitroRequest + .getParameter(VisualizationFrameworkConstants.RENDER_MODE_KEY); + + String visMode = vitroRequest + .getParameter(VisualizationFrameworkConstants.VIS_MODE_KEY); + + String visContainer = vitroRequest + .getParameter(VisualizationFrameworkConstants.VIS_CONTAINER_KEY); + + QueryRunner> queryManager = new PersonGrantCountQueryRunner(personURI, dataSource, log ); + + try{ + Set piGrants = queryManager.getQueryResult(); + + /* + * Create a map from the year to number of grants. Use the Grant's + * parsedGrantYear to populate the data. + * */ + Map yearToGrantCount = + UtilityFunctions.getYearToGrantCount(piGrants); + + Individual investigator = ((PersonGrantCountQueryRunner) queryManager).getPrincipalInvestigator(); + + if (VisualizationFrameworkConstants.DATA_RENDER_MODE + .equalsIgnoreCase(renderMode)) { + + return prepareDataResponse(investigator, + piGrants, + yearToGrantCount); + } + + /* + * For now we are disabling the capability to render pdf file. + * */ + /* + if (VisualizationFrameworkConstants.PDF_RENDER_MODE + .equalsIgnoreCase(renderMode)) { + + preparePDFResponse(investigator, + piGrants, + yearToGrantCount, + response); + return; + } + */ + + /* + * Computations required to generate HTML for the sparkline & related context. + * */ + PersonGrantCountVisCodeGenerator visualizationCodeGenerator = + new PersonGrantCountVisCodeGenerator(vitroRequest.getContextPath(), + personURI, + visMode, + visContainer, + piGrants, + yearToGrantCount, + 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, + yearToGrantCount); + + } else { + return prepareStandaloneResponse(vitroRequest, + sparklineData); + } + } catch (MalformedQueryParametersException e) { + return UtilityFunctions.handleMalformedParameters( + "Visualization Query Error - Individual Grant Count", + e.getMessage(), + vitroRequest); + } + } + + private String getGrantsOverTimeCSVContent(Map yearToGrantCount) { + + StringBuilder csvFileContent = new StringBuilder(); + + csvFileContent.append("Year, Grants\n"); + + for (Entry currentEntry : yearToGrantCount.entrySet()) { + csvFileContent.append(StringEscapeUtils.escapeCsv(currentEntry.getKey())); + csvFileContent.append(","); + csvFileContent.append(currentEntry.getValue()); + csvFileContent.append("\n"); + } + + return csvFileContent.toString(); + } + + /** + * Provides response when csv file containing the grant count over the years + * is requested. + * @param investigator + * @param piGrants + * @param yearToGrantCount + * @return + */ + private FileResponseValues prepareDataResponse( + Individual investigator, + Set piGrants, + Map yearToGrantCount) { + + + String piName = null; + + /* + * To protect against cases where there are no PI grants associated with the + * individual. + * */ + if (piGrants.size() > 0) { + piName = investigator.getIndividualLabel(); + } + + /* + * To make sure that null/empty records for PI names do not cause any mischief. + * */ + if (StringUtils.isBlank(piName)) { + piName = "no-principal-investigator"; + } + + String outputFileName = UtilityFunctions.slugify(piName) + + "_grants-per-year" + ".csv"; + + + Map fileContents = new HashMap(); + fileContents.put("fileContent", getGrantsOverTimeCSVContent(yearToGrantCount)); + + return new FileResponseValues(new ContentType(), outputFileName, fileContents); + } + + /** + * Provides response when an entire page dedicated to grant sparkline is requested. + * @param vreq + * @param valueObjectContainer + * @return + */ + private TemplateResponseValues prepareStandaloneResponse(VitroRequest vreq, + SparklineData valueObjectContainer) { + + Portal portal = vreq.getPortal(); + + String standaloneTemplate = "/visualization/grantCount.ftl"; + + Map body = new HashMap(); + body.put("portalBean", portal); + body.put("title", "Individual Grant Count visualization"); + body.put("sparklineVO", valueObjectContainer); + + /* + * DO NOT DO THIS HERE. Set stylesheets/scripts in the *.ftl instead using $(scripts.add) + * */ +// body.put("scripts", "/templates/visualization/visualization_scripts.jsp"); + + return new TemplateResponseValues(standaloneTemplate, body); + + } + + /** + * Provides response when the grant sparkline has to be rendered in already existing + * page, e.g. profile page. + * @param vreq + * @param valueObjectContainer + * @param yearToGrantCount + * @return + */ + private TemplateResponseValues prepareDynamicResponse( + VitroRequest vreq, + SparklineData valueObjectContainer, + Map yearToGrantCount) { + + Portal portal = vreq.getPortal(); + + + String dynamicTemplate = "/visualization/sparklineAjaxVisContent.ftl"; + + Map body = new HashMap(); + body.put("portalBean", portal); + body.put("sparklineVO", valueObjectContainer); + + /* + * DO NOT DO THIS HERE. Set stylesheets/scripts in the *.ftl instead using $(scripts.add) + * */ +// body.put("scripts", "/templates/visualization/visualization_scripts.jsp"); + + if (yearToGrantCount.size() > 0) { + body.put("shouldVIVOrenderVis", true); + } else { + body.put("shouldVIVOrenderVis", false); + } + + return new TemplateResponseValues(dynamicTemplate, body); + + } + + + private void preparePDFResponse(Individual investigator, + Set piGrants, + Map yearToGrantCount, + HttpServletResponse response) { + + String piName = null; + + // To protect against cases where there are no PI grants + // associated with the + // / individual. + if (piGrants.size() > 0) { + piName = investigator.getIndividualLabel(); + } + + // To make sure that null/empty records for PI names do not cause + // any mischief. + if (StringUtils.isBlank(piName)) { + piName = "no-principal-investigator"; + } + + String outputFileName = UtilityFunctions.slugify(piName) + + "_report" + ".pdf"; + + response.setContentType("application/pdf"); + response.setHeader("Content-Disposition", "attachment;filename=" + + outputFileName); + + ServletOutputStream responseOutputStream; + try { + responseOutputStream = response.getOutputStream(); + + Document document = new Document(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PdfWriter pdfWriter = PdfWriter.getInstance(document, baos); + document.open(); + + PDFDocument pdfDocument = new PDFDocument(piName, + yearToGrantCount, document, pdfWriter); + + document.close(); + + // setting some response headers & content type + response.setHeader("Expires", "0"); + response.setHeader("Cache-Control", + "must-revalidate, post-check=0, pre-check=0"); + response.setHeader("Pragma", "public"); + response.setContentLength(baos.size()); + // write ByteArrayOutputStream to the ServletOutputStream + baos.writeTo(responseOutputStream); + responseOutputStream.flush(); + responseOutputStream.close(); + + } catch (IOException e) { + e.printStackTrace(); + } catch (DocumentException e) { + e.printStackTrace(); + } + } +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/persongrantcount/PersonGrantCountVisCodeGenerator.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/persongrantcount/PersonGrantCountVisCodeGenerator.java new file mode 100644 index 00000000..64e5b799 --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/persongrantcount/PersonGrantCountVisCodeGenerator.java @@ -0,0 +1,658 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.persongrantcount; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.Map.Entry; + +import org.apache.commons.logging.Log; + +import edu.cornell.mannlib.vitro.webapp.controller.visualization.freemarker.VisualizationController; +import edu.cornell.mannlib.vitro.webapp.controller.visualization.VisualizationFrameworkConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.constants.VOConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.constants.VisConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.Grant; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.SparklineData; +import edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects.YearGrantCountDataElement; + + + +public class PersonGrantCountVisCodeGenerator { + + /* + * 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 grants over the years, from the last 10 years. + * + * 2. Full Sparkline - This sparkline will render all the data points (or sparks) + * spanning the career of the person & last 10 years at the minimum, in case if + * the person started his career in the last 10 yeras. + * */ + private static final Map VIS_DIV_NAMES = new HashMap() { { + + put("SHORT_SPARK", "grant_count_short_sparkline_vis"); + put("FULL_SPARK", "grant_count_full_sparkline_vis"); + + } }; + + private static final String VISUALIZATION_STYLE_CLASS = "sparkline_style"; + + private static final String DEFAULT_VIS_CONTAINER_DIV_ID = "grant_count_vis_container"; + + private Map yearToGrantCount; + + private Log log; + + private SparklineData sparklineData; + + private String contextPath; + + private String individualURI; + + public PersonGrantCountVisCodeGenerator(String contextPath, + String individualURIParam, String visMode, String visContainer, + Set piGrants, + Map yearToGrantCount, Log log) { + + this.contextPath = contextPath; + this.individualURI = individualURIParam; + + this.yearToGrantCount = yearToGrantCount; + this.sparklineData = new SparklineData(); + + sparklineData.setYearToActivityCount(yearToGrantCount); + + this.log = log; + + generateVisualizationCode(visMode, visContainer, piGrants); + } + + /** + * This method is used to generate the visualization code (HMTL, CSS & JavaScript). + * There 2 parts to it - 1. Actual Content Code & 2. Context Code. + * 1. Actual Content code in this case is the sparkline image, text related to + * data and the wrapping tables. This is generated via call to google vis API through + * JavaScript. + * 2. Context code is generally optional but contains code pertaining to tabulated + * data & links to download files etc. + * @param visMode + * @param visContainer + * @param piGrants + */ + private void generateVisualizationCode(String visMode, + String visContainer, + Set piGrants) { + + sparklineData.setSparklineContent(getMainVisualizationCode(piGrants, + visMode, + visContainer)); + + + sparklineData.setSparklineContext(getVisualizationContextCode(visMode)); + + } + + private String getMainVisualizationCode(Set piGrants, + 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_GRANT_YEAR". + */ + Set grantYears = new HashSet(yearToGrantCount + .keySet()); + grantYears.remove(VOConstants.DEFAULT_GRANT_YEAR); + + /* + * We are setting the default value of minGrantYear to be 10 years + * before the current year (which is suitably represented by the + * shortSparkMinYear), this in case we run into invalid set of grant + * years. + */ + int minGrantYear = shortSparkMinYear; + + String visContainerID = null; + + StringBuilder visualizationCode = new StringBuilder(); + + if (yearToGrantCount.size() > 0) { + try { + minGrantYear = Integer.parseInt(Collections + .min(grantYears)); + } catch (NoSuchElementException e1) { + log.debug("vis: " + e1.getMessage() + " error occurred for " + + yearToGrantCount.toString()); + } catch (NumberFormatException e2) { + log.debug("vis: " + e2.getMessage() + " error occurred for " + + yearToGrantCount.toString()); + } + } + + int minGrantYearConsidered = 0; + + /* + * There might be a case that the author investigated his first grant + * 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 + * minGrantYearConsidered to "currentYear - 10" which is also given by + * "shortSparkMinYear". + */ + if (minGrantYear > shortSparkMinYear) { + minGrantYearConsidered = shortSparkMinYear; + } else { + minGrantYearConsidered = minGrantYear; + } + + numOfYearsToBeRendered = currentYear - minGrantYearConsidered + 1; + + sparklineData.setNumOfYearsToBeRendered(numOfYearsToBeRendered); + + visualizationCode.append("\n"); + + visualizationCode.append("\n"; + } + + + private String getVisualizationContextCode(String visMode) { + + String visualizationContextCode = ""; + if (VisualizationFrameworkConstants.SHORT_SPARKLINE_VIS_MODE.equalsIgnoreCase(visMode)) { + visualizationContextCode = generateShortVisContext(); + } else { + visualizationContextCode = generateFullVisContext(); + } + + log.debug(visualizationContextCode); + + return visualizationContextCode; + } + + private String generateFullVisContext() { + + StringBuilder divContextCode = new StringBuilder(); + + String csvDownloadURLHref = ""; + + if (yearToGrantCount.size() > 0) { + + try { + if (getCSVDownloadURL() != null) { + + csvDownloadURLHref = "Download data as .csv file.
"; + sparklineData.setDownloadDataLink(getCSVDownloadURL()); + + } else { + csvDownloadURLHref = ""; + } + + } catch (UnsupportedEncodingException e) { + csvDownloadURLHref = ""; + } + } else { + csvDownloadURLHref = "No data available to export.
"; + } + + String tableCode = generateDataTable(); + + divContextCode.append("

" + tableCode + csvDownloadURLHref + "

"); + + sparklineData.setTable(tableCode); + + return divContextCode.toString(); + } + + + private String getCSVDownloadURL() + throws UnsupportedEncodingException { + + if (yearToGrantCount.size() > 0) { + + String secondaryContextPath = ""; + if (!contextPath.contains(VisualizationFrameworkConstants.VISUALIZATION_URL_PREFIX)) { + secondaryContextPath = VisualizationFrameworkConstants.VISUALIZATION_URL_PREFIX; + } + + String downloadURL = contextPath + + secondaryContextPath + + "?" + VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY + + "=" + URLEncoder.encode(individualURI, + VisualizationController.URL_ENCODING_SCHEME) + .toString() + + "&" + VisualizationFrameworkConstants.VIS_TYPE_KEY + + "=" + URLEncoder.encode( + VisualizationFrameworkConstants + .PERSON_GRANT_COUNT_VIS, + VisualizationController.URL_ENCODING_SCHEME) + .toString() + + "&" + VisualizationFrameworkConstants.RENDER_MODE_KEY + + "=" + URLEncoder.encode(VisualizationFrameworkConstants + .DATA_RENDER_MODE, + VisualizationController.URL_ENCODING_SCHEME) + .toString(); + return downloadURL; + } else { + return null; + } + } + + + private String generateShortVisContext() { + + StringBuilder divContextCode = new StringBuilder(); + + try { + + String fullTimelineLink; + if (yearToGrantCount.size() > 0) { + + String secondaryContextPath = ""; + if (!contextPath.contains(VisualizationFrameworkConstants.VISUALIZATION_URL_PREFIX)) { + secondaryContextPath = VisualizationFrameworkConstants.VISUALIZATION_URL_PREFIX; + } + + String fullTimelineNetworkURL = contextPath + + secondaryContextPath + + "?" + + VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY + + "=" + URLEncoder.encode(individualURI, + VisualizationController.URL_ENCODING_SCHEME).toString() + + "&" + + VisualizationFrameworkConstants.VIS_TYPE_KEY + + "=" + URLEncoder.encode("person_level", + VisualizationController.URL_ENCODING_SCHEME).toString() + + "&" + + VisualizationFrameworkConstants.RENDER_MODE_KEY + + "=" + URLEncoder.encode(VisualizationFrameworkConstants + .STANDALONE_RENDER_MODE, + VisualizationController.URL_ENCODING_SCHEME).toString(); + + fullTimelineLink = "View all VIVO " + + "grants and corresponding co-pi network."; + + sparklineData.setFullTimelineNetworkLink(fullTimelineNetworkURL); + + } else { + fullTimelineLink = "No data available to render full timeline.
"; + } + + divContextCode.append("" + fullTimelineLink + ""); + + } catch (UnsupportedEncodingException e) { + log.error(e); + } + return divContextCode.toString(); + } + + private String generateDataTable() { + + String csvDownloadURLHref = ""; + + try { + if (getCSVDownloadURL() != null) { + csvDownloadURLHref = "(.CSV File)"; + } else { + csvDownloadURLHref = ""; + } + } catch (UnsupportedEncodingException e) { + csvDownloadURLHref = ""; + } + + StringBuilder dataTable = new StringBuilder(); + + dataTable.append("" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + ""); + + for (Entry currentEntry : yearToGrantCount.entrySet()) { + dataTable.append("" + + "" + + "" + + ""); + } + + dataTable.append("\n
Grants per year " + csvDownloadURLHref + "
YearGrants
" + currentEntry.getKey() + "" + currentEntry.getValue() + "
\n"); + + return dataTable.toString(); + } + + public SparklineData getValueObjectContainer() { + return sparklineData; + } +} diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/SparklineData.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/SparklineData.java index f30037c3..b5fd445b 100644 --- a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/SparklineData.java +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/SparklineData.java @@ -18,9 +18,13 @@ public class SparklineData { private Integer earliestYearConsidered; private Integer earliestRenderedPublicationYear; private Integer latestRenderedPublicationYear; + private Integer earliestRenderedGrantYear; + private Integer latestRenderedGrantYear; private Integer renderedSparks; private Integer unknownYearPublications; + private Integer unknownYearGrants; + private Map yearToActivityCount; @@ -36,6 +40,7 @@ public class SparklineData { private boolean isShortVisMode = true; private List yearToPublicationCountDataTable; + private List yearToGrantCountDataTable; private int numOfYearsToBeRendered; @@ -56,6 +61,39 @@ public class SparklineData { this.sparklinePublicationRangeText = sparklinePublicationRangeText; } + public Integer getEarliestRenderedGrantYear() { + return earliestRenderedGrantYear; + } + + public void setEarliestRenderedGrantYear(Integer earliestRenderedGrantYear) { + this.earliestRenderedGrantYear = earliestRenderedGrantYear; + } + + public Integer getLatestRenderedGrantYear() { + return latestRenderedGrantYear; + } + + public void setLatestRenderedGrantYear(Integer latestRenderedGrantYear) { + this.latestRenderedGrantYear = latestRenderedGrantYear; + } + + public Integer getUnknownYearGrants() { + return unknownYearGrants; + } + + public void setUnknownYearGrants(Integer unknownYearGrants) { + this.unknownYearGrants = unknownYearGrants; + } + + public List getYearToGrantCountDataTable() { + return yearToGrantCountDataTable; + } + + public void setYearToGrantCountDataTable( + List yearToGrantCountDataTable) { + this.yearToGrantCountDataTable = yearToGrantCountDataTable; + } + public void setNumOfYearsToBeRendered(int numOfYearsToBeRendered) { this.numOfYearsToBeRendered = numOfYearsToBeRendered; } diff --git a/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/YearGrantCountDataElement.java b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/YearGrantCountDataElement.java new file mode 100644 index 00000000..44afc617 --- /dev/null +++ b/src/edu/cornell/mannlib/vitro/webapp/visualization/freemarker/valueobjects/YearGrantCountDataElement.java @@ -0,0 +1,35 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.freemarker.valueobjects; + +/** + * This object is used to store information about the yearToGrantCount Map in the format + * easily expressed to Google Visualization's DataTableAPI. + * @author bkoniden + * Deepak Konidena + */ + +public class YearGrantCountDataElement { + + private int grantCounter; + private String investigatedYear; + private int currentGrants; + + public YearGrantCountDataElement(int grantCounter, + String investigatedYear, int currentGrants) { + this.grantCounter = grantCounter; + this.investigatedYear = investigatedYear; + this.currentGrants = currentGrants; + } + + public int getGrantCounter() { + return grantCounter; + } + + public String getInvestigatedYear() { + return investigatedYear; + } + + public int getCurrentGrants() { + return currentGrants; + } + +}