diff --git a/webapp/config/web.xml b/webapp/config/web.xml index fce712432..1c7dddd9b 100644 --- a/webapp/config/web.xml +++ b/webapp/config/web.xml @@ -1119,6 +1119,26 @@ SparqlQuery /admin/sparqlquery + + + DummyVisClient + edu.cornell.mannlib.vitro.webapp.controller.visualization.DummyVisClientController + + + + DummyVisClient + /admin/dummyVisClient + + + + VisualizationController + edu.cornell.mannlib.vitro.webapp.controller.visualization.VisualizationController + + + + VisualizationController + /admin/visQuery + authtest diff --git a/webapp/lib/gson-1.4.jar b/webapp/lib/gson-1.4.jar new file mode 100644 index 000000000..b9c33d039 Binary files /dev/null and b/webapp/lib/gson-1.4.jar differ diff --git a/webapp/lib/iText-5.0.2.jar b/webapp/lib/iText-5.0.2.jar new file mode 100644 index 000000000..ed9565316 Binary files /dev/null and b/webapp/lib/iText-5.0.2.jar differ diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/SparqlQueryServlet.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/SparqlQueryServlet.java index 1e3acc0c5..5868d70d2 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/SparqlQueryServlet.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/SparqlQueryServlet.java @@ -417,7 +417,11 @@ public class SparqlQueryServlet extends BaseEditController { "PREFIX swrl: \n" + "PREFIX swrlb: \n" + "PREFIX vitro: \n"+ - "PREFIX vivo: \n"+ + "PREFIX vivo: \n" + + "PREFIX bibo: \n" + + "PREFIX foaf: \n" + + "PREFIX core: \n" + + "PREFIX aktp: \n"+ "#\n" + "# This query gets all range entities labels and types of a person\n"+ "# A query like this could be used to get enough info to create a display\n"+ diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/DummyVisClientController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/DummyVisClientController.java new file mode 100644 index 000000000..413b80e7e --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/DummyVisClientController.java @@ -0,0 +1,136 @@ +package edu.cornell.mannlib.vitro.webapp.controller.visualization; + +/* +Copyright (c) 2010, Cornell University +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of Cornell University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +import java.io.IOException; + +import javax.servlet.RequestDispatcher; +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 edu.cornell.mannlib.vedit.beans.LoginFormBean; +import edu.cornell.mannlib.vedit.controller.BaseEditController; +import edu.cornell.mannlib.vitro.webapp.beans.Portal; +import edu.cornell.mannlib.vitro.webapp.controller.Controllers; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; + +/** + * Services a sparql query. This will return a simple error message and a 501 if + * there is no jena Model. + * + * @author bdc34 + * + */ +public class DummyVisClientController extends BaseEditController { + + private static final long serialVersionUID = 1L; + + private static final Log log = LogFactory.getLog(DummyVisClientController.class.getName()); + + @Override + protected void doPost(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException + { + this.doGet(request,response); + } + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException + { + super.doGet(request, response); + + VitroRequest vreq = handleLoginAuthentication(request, response); + prepareVisualizationQueryResponse(request, response, vreq); + + return; + } + + private void prepareVisualizationQueryResponse(HttpServletRequest request, + HttpServletResponse response, VitroRequest vreq) { + + Portal portal = vreq.getPortal(); + + RequestDispatcher requestDispatcher = request.getRequestDispatcher(Controllers.BASIC_JSP); + request.setAttribute("bodyJsp", "/templates/visualization/dummy_vis_client.jsp"); + request.setAttribute("portalBean", portal); + request.setAttribute("title", "Dummy Visualization Client"); + request.setAttribute("scripts", "/templates/visualization/visualization_scripts.jsp"); + + try { + requestDispatcher.forward(request, response); + } catch (Exception e) { + log.error("EntityEditController could not forward to view."); + log.error(e.getMessage()); + log.error(e.getStackTrace()); + } + + } + + private VitroRequest handleLoginAuthentication(HttpServletRequest request, + HttpServletResponse response) throws IOException { + // This might not be required + /* + * why are there multiple places where the login is checked? shud be abtracted into + * new methoid? + * */ +// if( !checkLoginStatus(request, response) ) +// return null; + + VitroRequest vreq = new VitroRequest(request); + + Object obj = vreq.getSession().getAttribute("loginHandler"); + LoginFormBean loginHandler = null; + + if( obj != null && obj instanceof LoginFormBean ) + loginHandler = ((LoginFormBean)obj); + + + /* + * what is the speciality of 5 in the conditions? + * + if( loginHandler == null || + ! "authenticated".equalsIgnoreCase(loginHandler.getLoginStatus()) || + Integer.parseInt(loginHandler.getLoginRole()) <= 5 ){ + HttpSession session = request.getSession(true); + + session.setAttribute("postLoginRequest", + vreq.getRequestURI()+( vreq.getQueryString()!=null?('?' + vreq.getQueryString()):"" )); + String redirectURL = request.getContextPath() + Controllers.SITE_ADMIN + "?login=block"; + response.sendRedirect(redirectURL); + return null; + }*/ + return vreq; + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/VisualizationController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/VisualizationController.java new file mode 100644 index 000000000..e3340ea95 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/VisualizationController.java @@ -0,0 +1,379 @@ +package edu.cornell.mannlib.vitro.webapp.controller.visualization; + +/* +Copyright (c) 2010, Cornell University +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of Cornell University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +import java.io.IOException; +import java.util.HashMap; + +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.logging.Log; +import org.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 com.hp.hpl.jena.sparql.resultset.ResultSetFormat; + +import edu.cornell.mannlib.vedit.beans.LoginFormBean; +import edu.cornell.mannlib.vedit.controller.BaseEditController; +import edu.cornell.mannlib.vitro.webapp.beans.Portal; +import edu.cornell.mannlib.vitro.webapp.controller.Controllers; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; + +/** + * Services a sparql query. This will return a simple error message and a 501 if + * there is no jena Model. + * + * @author bdc34 + * + */ +public class VisualizationController extends BaseEditController { + + private static final String VIS_TYPE_URL_HANDLE = "vis"; + + public static final String URL_ENCODING_SCHEME = "UTF-8"; + + private static final long serialVersionUID = 1L; + + private static final Log log = LogFactory.getLog(VisualizationController.class.getName()); + + protected static final Syntax SYNTAX = Syntax.syntaxARQ; + + protected static HashMap formatSymbols = new HashMap(); + static{ + formatSymbols.put( ResultSetFormat.syntaxXML.getSymbol(), ResultSetFormat.syntaxXML); + formatSymbols.put( ResultSetFormat.syntaxRDF_XML.getSymbol(), ResultSetFormat.syntaxRDF_XML); + formatSymbols.put( ResultSetFormat.syntaxRDF_N3.getSymbol(), ResultSetFormat.syntaxRDF_N3); + formatSymbols.put( ResultSetFormat.syntaxText.getSymbol() , ResultSetFormat.syntaxText); + formatSymbols.put( ResultSetFormat.syntaxJSON.getSymbol() , ResultSetFormat.syntaxJSON); + formatSymbols.put( "vitro:csv", null); + } + + protected static HashMap rdfFormatSymbols = new HashMap(); + static { + rdfFormatSymbols.put( "RDF/XML", "application/rdf+xml" ); + rdfFormatSymbols.put( "RDF/XML-ABBREV", "application/rdf+xml" ); + rdfFormatSymbols.put( "N3", "text/n3" ); + rdfFormatSymbols.put( "N-TRIPLE", "text/plain" ); + rdfFormatSymbols.put( "TTL", "application/x-turtle" ); + } + + protected static HashMap mimeTypes = new HashMap(); + static{ + mimeTypes.put( ResultSetFormat.syntaxXML.getSymbol() , "text/xml" ); + mimeTypes.put( ResultSetFormat.syntaxRDF_XML.getSymbol(), "application/rdf+xml" ); + mimeTypes.put( ResultSetFormat.syntaxRDF_N3.getSymbol(), "text/plain" ); + mimeTypes.put( ResultSetFormat.syntaxText.getSymbol() , "text/plain"); + mimeTypes.put( ResultSetFormat.syntaxJSON.getSymbol(), "application/javascript" ); + mimeTypes.put( "vitro:csv", "text/csv"); + } + + public static final String PERSON_PUBLICATION_COUNT_VIS_URL_VALUE + = "person_pub_count"; + + public static final String PDF_REPORT_VIS_URL_VALUE + = "pdf_report"; + + public static final String COLLEGE_PUBLICATION_COUNT_VIS_URL_VALUE + = "college_pub_count"; + + public static final String COAUTHORSHIP_VIS_URL_VALUE + = "coauthorship"; + + public static final String PERSON_LEVEL_VIS_URL_VALUE + = "person_level"; + + public static final String UTILITIES_URL_VALUE + = "utilities"; + + + + @Override + protected void doPost(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException + { + this.doGet(request,response); + } + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException + { + super.doGet(request, response); + + VitroRequest vreq = handleLoginAuthentication(request, response); + + + if (PERSON_PUBLICATION_COUNT_VIS_URL_VALUE + .equalsIgnoreCase(vreq.getParameter(VIS_TYPE_URL_HANDLE))) { + + edu.cornell.mannlib.vitro.webapp.visualization.personpubcount.VisualizationRequestHandler visRequestHandler = + new edu.cornell.mannlib.vitro.webapp.visualization.personpubcount.VisualizationRequestHandler(vreq, request, response, log); + + String rdfResultFormatParam = "RDF/XML-ABBREV"; + + DataSource dataSource = setupJENADataSource(request, + response, + vreq, + rdfResultFormatParam); + + if (dataSource != null) { + + /* + * This is side-effecting because the visualization content is added + * to the request object. + * */ + visRequestHandler.generateVisualization(dataSource); + + } else { + + log.error("ERROR! Data Model Empty"); + } + + } else if (COLLEGE_PUBLICATION_COUNT_VIS_URL_VALUE + .equalsIgnoreCase(vreq.getParameter(VIS_TYPE_URL_HANDLE))) { + + edu.cornell.mannlib.vitro.webapp.visualization.collegepubcount.VisualizationRequestHandler visRequestHandler = + new edu.cornell.mannlib.vitro.webapp.visualization.collegepubcount.VisualizationRequestHandler(vreq, request, response, log); + + String rdfResultFormatParam = "RDF/XML-ABBREV"; + + DataSource dataSource = setupJENADataSource(request, + response, + vreq, + rdfResultFormatParam); + + if (dataSource != null) { + + /* + * This is side-effecting because the visualization content is added + * to the request object. + * */ + visRequestHandler.generateVisualization(dataSource); + + } else { + log.error("ERROR! data model empoty"); + } + + } else if (COAUTHORSHIP_VIS_URL_VALUE + .equalsIgnoreCase(vreq.getParameter(VIS_TYPE_URL_HANDLE))) { + + edu.cornell.mannlib.vitro.webapp.visualization.coauthorship.VisualizationRequestHandler visRequestHandler = + new edu.cornell.mannlib.vitro.webapp.visualization.coauthorship.VisualizationRequestHandler(vreq, request, response, log); + + String rdfResultFormatParam = "RDF/XML-ABBREV"; + + DataSource dataSource = setupJENADataSource(request, + response, + vreq, + rdfResultFormatParam); + + if (dataSource != null) { + + /* + * This is side-effecting because the visualization content is added + * to the request object. + * */ + visRequestHandler.generateVisualization(dataSource); + + } else { + log.error("ERROR! data model empoty"); + } + + } else if (PERSON_LEVEL_VIS_URL_VALUE + .equalsIgnoreCase(vreq.getParameter(VIS_TYPE_URL_HANDLE))) { + + edu.cornell.mannlib.vitro.webapp.visualization.personlevel.VisualizationRequestHandler visRequestHandler = + new edu.cornell.mannlib.vitro.webapp.visualization.personlevel.VisualizationRequestHandler(vreq, request, response, log); + + String rdfResultFormatParam = "RDF/XML-ABBREV"; + + DataSource dataSource = setupJENADataSource(request, + response, + vreq, + rdfResultFormatParam); + + if (dataSource != null) { + + /* + * This is side-effecting because the visualization content is added + * to the request object. + * */ + visRequestHandler.generateVisualization(dataSource); + + } else { + log.error("ERROR! data model empoty"); + } + + } else if (PDF_REPORT_VIS_URL_VALUE + .equalsIgnoreCase(vreq.getParameter(VIS_TYPE_URL_HANDLE))) { + + } else if (UTILITIES_URL_VALUE + .equalsIgnoreCase(vreq.getParameter(VIS_TYPE_URL_HANDLE))) { + + edu.cornell.mannlib.vitro.webapp.visualization.utilities.VisualizationRequestHandler visRequestHandler = + new edu.cornell.mannlib.vitro.webapp.visualization.utilities.VisualizationRequestHandler(vreq, request, response, log); + + String rdfResultFormatParam = "RDF/XML-ABBREV"; + + DataSource dataSource = setupJENADataSource(request, + response, + vreq, + rdfResultFormatParam); + + if (dataSource != null) { + + /* + * This is side-effecting because the visualization content is added + * to the request object. + * */ + visRequestHandler.generateVisualization(dataSource); + + } else { + log.error("ERROR! data model empoty"); + } + + } else { + + log.debug("vis uqery parameter value -> " + vreq.getParameter("vis")); + log.debug("uri uqery parameter value -> " + vreq.getParameter("uri")); + log.debug("render_mode query parameter value -> " + vreq.getParameter("render_mode")); + + /* + * This is side-effecting because the error content is directly + * added to the request object. From where it is redirected to + * the error page. + * */ + handleMalformedParameters("Inappropriate query parameters were submitted. ", request, response); + } + + return; + } + + private VitroRequest handleLoginAuthentication(HttpServletRequest request, + HttpServletResponse response) throws IOException { + // This might not be required + /* + * why are there multiple places where the login is checked? shud be abtracted into + * new methoid? + * */ +// if( !checkLoginStatus(request, response) ) +// return null; + + VitroRequest vreq = new VitroRequest(request); + + Object obj = vreq.getSession().getAttribute("loginHandler"); + LoginFormBean loginHandler = null; + + + if( obj != null && obj instanceof LoginFormBean ) + loginHandler = ((LoginFormBean)obj); + + /* + * what is the speciality of 5 in the conditions? + * + if( loginHandler == null || + ! "authenticated".equalsIgnoreCase(loginHandler.getLoginStatus()) || + Integer.parseInt(loginHandler.getLoginRole()) <= 5 ){ + HttpSession session = request.getSession(true); + + session.setAttribute("postLoginRequest", + vreq.getRequestURI()+( vreq.getQueryString()!=null?('?' + vreq.getQueryString()):"" )); + String redirectURL = request.getContextPath() + Controllers.SITE_ADMIN + "?login=block"; + response.sendRedirect(redirectURL); + return null; + } + */ + return vreq; + } + + private DataSource setupJENADataSource(HttpServletRequest request, + HttpServletResponse response, VitroRequest vreq, + String rdfResultFormatParam) { + + Model model = vreq.getJenaOntModel(); // getModel() + if( model == null ){ + doNoModelInContext(request,response); + return null; + } + + log.debug("rdfResultFormat was: " + rdfResultFormatParam); + + DataSource dataSource = DatasetFactory.create() ; + ModelMaker maker = (ModelMaker) getServletContext().getAttribute("vitroJenaModelMaker"); + + dataSource.setDefaultModel(model) ; + + return dataSource; + } + + private void doNoModelInContext(HttpServletRequest request, HttpServletResponse res){ + try { + res.setStatus(HttpServletResponse.SC_NOT_IMPLEMENTED); + ServletOutputStream sos = res.getOutputStream(); + sos.println("this service is not supporeted by the current " + + "webapp configuration. A jena model is required in the servlet context." ); + } catch (IOException e) { + log.error("Could not write to ServletOutputStream"); + } + } + + + private void handleMalformedParameters(String errorMessage, HttpServletRequest request, + HttpServletResponse response) + throws ServletException, IOException { + + VitroRequest vreq = new VitroRequest(request); + Portal portal = vreq.getPortal(); + + request.setAttribute("error", errorMessage); + + RequestDispatcher requestDispatcher = request.getRequestDispatcher(Controllers.BASIC_JSP); + request.setAttribute("bodyJsp", "/templates/visualization/visualization_error.jsp"); + request.setAttribute("portalBean", portal); + request.setAttribute("title", "Visualization Query Error"); + + try { + requestDispatcher.forward(request, response); + } catch (Exception e) { + log.error("EntityEditController could not forward to view."); + log.error(e.getMessage()); + log.error(e.getStackTrace()); + } + } + +} + diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/VisualizationFrameworkConstants.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/VisualizationFrameworkConstants.java new file mode 100644 index 000000000..6b83e03a9 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/visualization/VisualizationFrameworkConstants.java @@ -0,0 +1,20 @@ +package edu.cornell.mannlib.vitro.webapp.controller.visualization; + +public class VisualizationFrameworkConstants { + + public static final String VIS_TYPE_URL_HANDLE = "vis"; + public static final String VIS_CONTAINER_URL_HANDLE = "container"; + public static final String INDIVIDUAL_URI_URL_HANDLE = "uri"; + public static final String VIS_MODE_URL_HANDLE = "vis_mode"; + public static final String RENDER_MODE_URL_HANDLE = "render_mode"; + + + + public static final String STANDALONE_RENDER_MODE_URL_VALUE = "standalone"; + public static final String DYNAMIC_RENDER_MODE_URL_VALUE = "dynamic"; + public static final String DATA_RENDER_MODE_URL_VALUE = "data"; + public static final String PDF_RENDER_MODE_URL_VALUE = "pdf"; + public static final String IMAGE_VIS_MODE_URL_VALUE = "image"; + + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/PDFDocument.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/PDFDocument.java new file mode 100644 index 000000000..1fca6b138 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/PDFDocument.java @@ -0,0 +1,295 @@ +package edu.cornell.mannlib.vitro.webapp.visualization; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Stroke; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Map; +import java.util.Map.Entry; + +import com.itextpdf.text.BadElementException; +import com.itextpdf.text.BaseColor; +import com.itextpdf.text.Chunk; +import com.itextpdf.text.Document; +import com.itextpdf.text.DocumentException; +import com.itextpdf.text.Element; +import com.itextpdf.text.Font; +import com.itextpdf.text.FontFactory; +import com.itextpdf.text.Image; +import com.itextpdf.text.Paragraph; +import com.itextpdf.text.Phrase; +import com.itextpdf.text.pdf.ColumnText; +import com.itextpdf.text.pdf.PdfContentByte; +import com.itextpdf.text.pdf.PdfGState; +import com.itextpdf.text.pdf.PdfPCell; +import com.itextpdf.text.pdf.PdfPTable; +import com.itextpdf.text.pdf.PdfWriter; + +public class PDFDocument{ + + + static Stroke stroke = new BasicStroke(5.f, BasicStroke.CAP_ROUND, + BasicStroke.JOIN_ROUND); + + final static Color bg = Color.green; + + final static Color fg = Color.black; + + public PDFDocument(String authorName, + Map yearToPublicationCount, + Document document, + PdfWriter pdfWriter) { + +// setPreferredSize(new Dimension(600,400)); + + try { + + document.addTitle("PDF Pipeline iText Prototype"); + document.addAuthor(authorName); + document.addSubject("This example tests text, color, image, transparency & table functionality."); + document.addKeywords("text, color, image, transparency, table"); + document.addCreator("Standalone PDF Renderer using iText"); + + Paragraph header = new Paragraph(); + + Font pageHeaderStyle = FontFactory.getFont(FontFactory.TIMES_ROMAN, 15, Font.BOLDITALIC | Font.UNDERLINE); + Font featureHeaderStyle = FontFactory.getFont(FontFactory.TIMES_ROMAN, 10, new BaseColor(Color.red)); + + header.add(new Chunk("PDF Pipeline Prototype v2 using iText\n", + pageHeaderStyle)); + + header.setSpacingAfter(15f); + + + document.add(header); + + + Paragraph content = new Paragraph(); + + content.add(new Chunk("Publication Count - Author Name - " + authorName, + featureHeaderStyle)); + + content.setSpacingAfter(15f); + + document.add(content); + // step4 + + PdfPTable publicationCount = createTable(yearToPublicationCount); + + document.add(publicationCount); + + content = new Paragraph(); + + content.add(new Chunk("Transparency of Shapes", + featureHeaderStyle)); + + content.setSpacingAfter(15f); + + document.add(content); + + createTransparencyShapes(document, pdfWriter); + + + createImage(document, pdfWriter, featureHeaderStyle); + + } catch (DocumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + + + private void createImage(Document document, PdfWriter writer, + Font featureHeaderStyle) throws BadElementException, + MalformedURLException, IOException, DocumentException { + Image imageSprite = Image.getInstance(new URL("http://lh3.ggpht.com/_4msVPAgKJv8/SCRYD-pPVKI/AAAAAAAAAYU/zUN963EPoZc/s1024/102_0609.JPG")); + imageSprite.setAbsolutePosition(400, 500); + imageSprite.scaleAbsolute(171.0f, 250.0f); + float imageSpriteY = document.getPageSize().getHeight() * 0.60f; + float imageSpriteX = document.getPageSize().getWidth() * 0.65f; + imageSprite.setAlignment(Image.UNDERLYING); + + document.add(imageSprite); + + PdfContentByte cb = writer.getDirectContent(); + ColumnText ct = new ColumnText(cb); + Chunk imageHeader = new Chunk("Images", + featureHeaderStyle); + ct.addText(imageHeader); + ct.setAlignment(Element.ALIGN_LEFT); + ct.setSimpleColumn(imageSpriteX, imageSpriteY - imageSprite.getScaledHeight(), + imageSpriteX + imageSprite.getScaledWidth(), imageSpriteY + imageSprite.getScaledHeight() + 20); + ct.go(); + + ct = new ColumnText(cb); + Chunk imageFooter = new Chunk("Footer to be set for a figure. Similar to 'image cpation'.", + FontFactory.getFont(FontFactory.TIMES_ROMAN, 8)); + ct.addText(imageFooter); + ct.setAlignment(Element.ALIGN_CENTER); + ct.setSimpleColumn(imageSpriteX, imageSpriteY - 150, imageSpriteX + imageSprite.getScaledWidth(), imageSpriteY); + ct.go(); + } + + private void createTransparencyShapes(Document document, + PdfWriter writer) throws Exception { + PdfContentByte cb = writer.getDirectContent(); + + pictureBackdrop(document.leftMargin(), 350, cb); + cb.saveState(); + PdfGState gs1 = new PdfGState(); + gs1.setFillOpacity(0.5f); + cb.setGState(gs1); + pictureCircles(document.leftMargin(), 350, cb); + cb.restoreState(); + + cb.resetRGBColorFill(); + } + + /** + * Prints a square and fills half of it with a gray rectangle. + * @param x + * @param y + * @param cb + * @throws Exception + */ + public void pictureBackdrop(float x, float y, PdfContentByte cb) throws Exception { + cb.setColorStroke(new BaseColor(Color.black)); + cb.setColorFill(new BaseColor(Color.gray)); + cb.rectangle(x, y, 100, 200); + cb.fill(); + cb.setLineWidth(2); + cb.rectangle(x, y, 200, 200); + cb.stroke(); + } + + /** + * Prints 3 circles in different colors that intersect with eachother. + * @param x + * @param y + * @param cb + * @throws Exception + */ + public void pictureCircles(float x, float y, PdfContentByte cb) throws Exception { + + cb.saveState(); + PdfGState gs1 = new PdfGState(); + gs1.setFillOpacity(1.0f); + cb.setGState(gs1); + cb.setColorFill(new BaseColor(Color.red)); + cb.circle(x + 70, y + 70, 50); + cb.fill(); + cb.restoreState(); + + cb.setColorFill(new BaseColor(Color.yellow)); + cb.circle(x + 100, y + 130, 50); + cb.fill(); + cb.setColorFill(new BaseColor(Color.blue)); + cb.circle(x + 130, y + 70, 50); + cb.fill(); + } + + private PdfPTable createTable(Map yearToPublicationCount) { + + Font normalContentStyle = FontFactory.getFont(FontFactory.TIMES_ROMAN, 11); + Font summaryContentStyle = FontFactory.getFont(FontFactory.TIMES_ROMAN, 11, Font.BOLDITALIC); + BaseColor summaryBackgroundColor = new BaseColor(0xEE, 0xEE, 0xEE); + BaseColor headerBackgroundColor = new BaseColor(0xC3, 0xD9, 0xFF); + BaseColor bodyBackgroundColor = new BaseColor(Color.white); + + PdfPTable table = new PdfPTable(2); + table.setWidthPercentage(36.0f); + + table.setHorizontalAlignment(Element.ALIGN_LEFT); + table.getDefaultCell().setBorderWidth(0.0f); + table.setHeaderRows(2); + + PdfPCell cell; + cell = new PdfPCell(new Phrase("Publications per year", normalContentStyle)); + setTableCaptionStyle(summaryBackgroundColor, cell); + table.addCell(cell); + + cell = new PdfPCell(new Phrase("Year", normalContentStyle)); + setTableHeaderStyle(headerBackgroundColor, cell); + table.addCell(cell); + + cell.setPhrase(new Phrase("Publications", normalContentStyle)); + table.addCell(cell); + + + + setTableBodyStyle(bodyBackgroundColor, cell); + int totalPublications = 0; + + for (Entry currentEntry : yearToPublicationCount.entrySet()) { + + cell.setPhrase(new Phrase(currentEntry.getKey(), normalContentStyle)); + table.addCell(cell); + + cell.setPhrase(new Phrase(currentEntry.getValue().toString(), normalContentStyle)); + table.addCell(cell); + + totalPublications += currentEntry.getValue(); + } + + setTableFooterStyle(summaryBackgroundColor, cell); + cell.setPhrase(new Phrase("Total", summaryContentStyle)); + table.addCell(cell); + + cell.setPhrase(new Phrase(String.valueOf(totalPublications), summaryContentStyle)); + table.addCell(cell); + + return table; + } + + private void setTableFooterStyle(BaseColor footerBackgroundColor, + PdfPCell cell) { + cell.setBorderWidth(0.0f); + cell.setBackgroundColor(footerBackgroundColor); + cell.setHorizontalAlignment(Element.ALIGN_CENTER); + cell.setPaddingTop(5f); + cell.setPaddingRight(10f); + cell.setPaddingBottom(5f); + cell.setPaddingLeft(10f); + } + + private void setTableBodyStyle(BaseColor bodyBackgroundColor, + PdfPCell cell) { + cell.setBorderWidth(0.0f); + cell.setBackgroundColor(bodyBackgroundColor); + cell.setHorizontalAlignment(Element.ALIGN_CENTER); + cell.setPaddingTop(5f); + cell.setPaddingRight(10f); + cell.setPaddingBottom(5f); + cell.setPaddingLeft(10f); + } + + private void setTableHeaderStyle(BaseColor headerBackgroundColor, + PdfPCell cell) { + cell.setBorderWidth(0.0f); + cell.setBackgroundColor(headerBackgroundColor); + cell.setHorizontalAlignment(Element.ALIGN_CENTER); + cell.setPaddingTop(5f); + cell.setPaddingRight(10f); + cell.setPaddingBottom(5f); + cell.setPaddingLeft(10f); + } + + private void setTableCaptionStyle(BaseColor summaryBackgroundColor, + PdfPCell cell) { + cell.setBorderWidth(0.0f); + cell.setBackgroundColor(summaryBackgroundColor); + cell.setHorizontalAlignment(Element.ALIGN_CENTER); + cell.setPaddingTop(5.0f); + cell.setPaddingRight(10.0f); + cell.setPaddingBottom(5.0f); + cell.setPaddingLeft(10.0f); + cell.setColspan(2); + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/TestJava.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/TestJava.java new file mode 100644 index 000000000..6dade7988 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/TestJava.java @@ -0,0 +1,192 @@ +package edu.cornell.mannlib.vitro.webapp.visualization; + +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.Map.Entry; + +import org.apache.commons.collections.BidiMap; +import org.apache.commons.collections.MapIterator; +import org.apache.commons.collections.bidimap.TreeBidiMap; + +import com.google.gson.Gson; +import com.hp.hpl.jena.iri.IRIFactory; + +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.GenericQueryMap; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Node; + +public class TestJava { + + /** + * @param args + */ + public static void main(String[] args) { + String uriStr = "http%3A%2F%2Fvivo.library.cornell.edu%2Fns%2F0.1%23individual8588"; + IRIFactory factory = IRIFactory.jenaImplementation(); + + String[] sampleBlurns = {"Gold, J R [Reprint Author, Author]; Perkins, G A; Erb, H N; Ainsworth, D M | Journal of Veterinary Internal Medicine, 2006; 20(3): 720", + "Goldstein, Richard E; Lin, Rebecca C; Langston, Catherine E; Scrivani, Peter V; Erb, Hollis N; Barr, Stephen C | Journal of Veterinary Internal Medicine, 2006; 20(3): 489-494", + "McClellan, Jennifer M; Goldstein, Richard E; Erb, Hollis N; Dykes, Ned L; Cowgill, Larry D | American Journal of Veterinary Research, 2006; 67(4): 715-722", + "Cook, Christopher P; Scott, Danny W; Erb, Hollis N; Miller, William H | Vet Dermatol. 2005; 16(1): 47-51", + "Estrada, Amara; Moise, N Sydney; Erb, Hollis N; McDonough, Sean P; Renaud, Farrell, Shari | Journal of Veterinary Internal Medicine, 2006; 20(4): 862-872", + "Aguirre, A L [Reprint Author, Author]; Center, S A; Yeager, A E; Randolph, J F; Erb, H N | Journal of Veterinary Internal Medicine, 2006; 20(3): 787-788", + "MacLeod, K D; Scott, D W; Erb, H N | Journal of Veterinary Medicine Series A, 2004; 51(9-10): 400-404", + "Bailey, Dennis B; Rassnick, Kenneth M; Erb, Hollis N; Dykes, Nathan L; Hoopes, P Jack; Page, Rodney L | American Journal of Veterinary Research, 2004; 65(11): 1502-1507", + "Ainsworth, Dorothy M; Wagner, Bettina; Franchini, Marco; Grunig, Gabriele; Erb, Hollis N; Tan, Jean Yin | American Journal of Veterinary Research, 2006; 67(4): 669-677", + "Page, Richard B; Scrivani, Peter V; Dykes, Nathan L; Erb, Hollis N; Hobbs, Jeff M | Veterinary Radiology and Ultrasound, 2006; 47(2): 206-211", + "Scrivani, Peter V; Dykes, Nathan L; Erb, Hollis N | Veterinary Radiology and Ultrasound, 2004; 45(5): 419-423", + "Sepesy, Lisa M; Center, Sharon A; Randolph, John F; Warner, Karen L; Erb, Hollis N | Journal of the American Veterinary Medical Association, 2006; 229(2): 246-252", + "Dereszynski, D [Reprint Author, Author]; Center, S; Hadden, A; Randolph, J; Brooks, M; Palyada, K; McDonough, S; Messick, J; Bischoff, K; Erb, H; Gluckman, S; Sanders, S | Journal of Veterinary Internal Medicine, 2006; 20(3): 751-752", + "Kroll, Tracy L; Houpt, Katherine A; Erb, Hollis N | Journal of the American Animal Hospital Association, 2004; 40(1): 13-19", + "Fortier, Lisa A; Gregg, Abigail J; Erb, Hollis N; Fubini, Susan L | Vet Surg. 33(6): 661-7", + "Wagner, Bettina; Flaminio, Julia B F; Hillegas, Julie; Leibold, Wolfgang; Erb, Hollis N; Antczak, Douglas F | Veterinary Immunology and Immunopathology, 2006; 110(3-4): 269-278", + "Chalmers, H J; Scrivani, Peter V; Dykes, Nathan L; Erb, Hollis N; Hobbs, J M; Hubble, Lorna J | Veterinary Radiology and Ultrasound, 2006; 47(5): 507-509", + "Center, Sharon A; Warner, Karen L; McCabe, Jennifer; Foureman, Polly; Hoffmann, Walter E; Erb, Hollis N | Am J Vet Res. 2005; 66(2): 330-41"}; + + System.out.println(sampleBlurns); + for (String blurb : sampleBlurns) { + + System.out.println(blurb.contains("author")); + } + Map yearToPublicationCount = new TreeMap(); + + yearToPublicationCount.put("2003", 5); + yearToPublicationCount.put("2005", 3); + yearToPublicationCount.put("2002", 1); + yearToPublicationCount.put("2090", 5); + yearToPublicationCount.put("Unknown", 6); + + BidiMap map1 = new TreeBidiMap(yearToPublicationCount); + + + System.out.println(map1 + " --- " + map1.inverseBidiMap()); + + Node egoNode; + + + MapIterator mapIterator = map1.inverseBidiMap().mapIterator(); + + + while(mapIterator.hasNext()) { + + Object next = mapIterator.next(); + + System.out.println(next + " %%% " + next); + + + } + + + + + System.out.println(); + + Map> biboDocumentURLToCoAuthors = new HashMap>(); + + Set coAuthorsForCurrentBiboDocument; + + if (biboDocumentURLToCoAuthors.containsKey("a")) { + coAuthorsForCurrentBiboDocument = biboDocumentURLToCoAuthors.get("a"); + } else { + coAuthorsForCurrentBiboDocument = new HashSet(); + biboDocumentURLToCoAuthors.put("a", coAuthorsForCurrentBiboDocument); + } + + coAuthorsForCurrentBiboDocument.add(1); + + int actual_size = 4; +// int n = actual_size - 1; + + for (int ii = 0; ii < actual_size - 1; ii++) { + for (int jj = ii + 1; jj < actual_size; jj++) { + System.out.println(ii + " - " + jj ); + } + } + + System.out.println(yearToPublicationCount); + + + Map saHashMap = new HashMap(){{ + put("sdsd", 4); + + }}; + System.out.println(saHashMap.keySet()); + + + Set keySet = new HashSet(yearToPublicationCount.keySet()); + keySet.remove("Unknown"); + + try { + System.out.println(Collections.min(keySet)); + } catch (Exception e) { + } + + + GenericQueryMap stringToSetOfStrings = new GenericQueryMap(); + + stringToSetOfStrings.put("A", yearToPublicationCount.keySet()); + stringToSetOfStrings.put("B", yearToPublicationCount.keySet()); + stringToSetOfStrings.put("C", yearToPublicationCount.keySet()); + stringToSetOfStrings.put("imageOffset", keySet); + + Set what = new HashSet(); + + what.add("sup"); + + stringToSetOfStrings.put("imageOffset2", what); + + + String emptyString = ""; + System.out.println(emptyString.isEmpty()); + + System.out.println(stringToSetOfStrings); + + Gson gson = new Gson(); + String json = gson.toJson(stringToSetOfStrings); + + + System.out.println(json); + + + +// System.out.println(Collections.max(yearToPublicationCount.keySet())); +// System.out.println(Collections.min(yearToPublicationCount.keySet())); + +// yearToPublicationCount.put("2087", testIt(5, yearToPublicationCount.get("2087"))); + +// try { +// factory.setEncoding("HEX"); +// } catch (UnsupportedEncodingException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } + + + /* + IRI iri = factory.create(uriStr); + + + + if (iri.hasViolation(false) ) { + boolean validURI = false; + String errorMsg = ((Violation)iri.violations(false).next()).getShortMessage()+" "; + System.out.println("MURDER!!!!!" + errorMsg); + + } else { + System.out.println(iri.hasViolation(true)); + + }*/ + + + } + + private static Integer testIt(int i, Integer integer) { +// System.out.println("testit - " + i + " --- " + integer); + + return 10; + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/coauthorship/CoAuthorshipGraphMLWriter.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/coauthorship/CoAuthorshipGraphMLWriter.java new file mode 100644 index 000000000..bb1ff8b44 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/coauthorship/CoAuthorshipGraphMLWriter.java @@ -0,0 +1,334 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.coauthorship; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.Map; +import java.util.Set; + +import edu.cornell.mannlib.vitro.webapp.controller.visualization.VisualizationController; +import edu.cornell.mannlib.vitro.webapp.controller.visualization.VisualizationFrameworkConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Edge; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Node; + +public class CoAuthorshipGraphMLWriter { + + private StringBuilder coAuthorshipGraphMLContent; + + private final String GRAPHML_HEADER = "\n" + + " \n\n"; + + private final String GRAPHML_FOOTER = ""; + + public CoAuthorshipGraphMLWriter(VisVOContainer visVOContainer) { + + coAuthorshipGraphMLContent = createCoAuthorshipGraphMLContent(visVOContainer); + + } + + public StringBuilder getCoAuthorshipGraphMLContent() { + return coAuthorshipGraphMLContent; + } + + private StringBuilder createCoAuthorshipGraphMLContent( + VisVOContainer visVOContainer) { + + 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(visVOContainer, graphMLContent); + + /* + * Used to generate graph content. It will contain both the nodes & edge information. + * We are side-effecting "graphMLContent". + * */ + generateGraphContent(visVOContainer, graphMLContent); + + graphMLContent.append(GRAPHML_FOOTER); + + return graphMLContent; + } + + private void generateGraphContent(VisVOContainer visVOContainer, + StringBuilder graphMLContent) { + + graphMLContent.append("\n\n"); + + if (visVOContainer.getNodes() != null & visVOContainer.getNodes().size() > 0) { + generateNodeSectionContent(visVOContainer, graphMLContent); + } + + if (visVOContainer.getEdges() != null & visVOContainer.getEdges().size() > 0) { + generateEdgeSectionContent(visVOContainer, graphMLContent); + } + + graphMLContent.append("\n"); + + + + + } + + private void generateEdgeSectionContent(VisVOContainer visVOContainer, + StringBuilder graphMLContent) { + + graphMLContent.append("\n"); + + Set edges = visVOContainer.getEdges(); + + + for (Edge currentEdge : edges) { + + /* + * This method actually creates the XML code for a single edge. "graphMLContent" + * is being side-effected. + * */ + getEdgeContent(graphMLContent, currentEdge); + + } + + } + + private void getEdgeContent(StringBuilder graphMLContent, Edge currentEdge) { + + graphMLContent.append("\n"); + + graphMLContent.append("\t" + currentEdge.getSourceNode().getNodeName() + "\n"); + graphMLContent.append("\t" + currentEdge.getTargetNode().getNodeName() + "\n"); + + graphMLContent.append("\t" + + currentEdge.getNumOfCoAuthoredWorks() + + "\n"); + + if (currentEdge.getEarliestCollaborationYearCount() != null) { + + /* + * There is no clean way of getting the map contents in java even though + * we are sure to have only one entry on the map. So using the for loop. + * I am feeling dirty just about now. + * */ + for (Map.Entry publicationInfo : + currentEdge.getEarliestCollaborationYearCount().entrySet()) { + + graphMLContent.append("\t" + + publicationInfo.getKey() + + "\n"); + + graphMLContent.append("\t" + + publicationInfo.getValue() + + "\n"); + + + } + + } + + if (currentEdge.getLatestCollaborationYearCount() != null) { + + for (Map.Entry publicationInfo : + currentEdge.getLatestCollaborationYearCount().entrySet()) { + + graphMLContent.append("\t" + + publicationInfo.getKey() + + "\n"); + + graphMLContent.append("\t" + + publicationInfo.getValue() + + "\n"); + } + + } + + if (currentEdge.getUnknownCollaborationYearCount() != null) { + + graphMLContent.append("\t" + + currentEdge.getUnknownCollaborationYearCount() + + "\n"); + + } + + graphMLContent.append("\n"); + + + } + + private void generateNodeSectionContent(VisVOContainer visVOContainer, + StringBuilder graphMLContent) { + + graphMLContent.append("\n"); + + Node egoNode = visVOContainer.getEgoNode(); + Set authorNodes = visVOContainer.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); + + + for (Node currNode : authorNodes) { + + /* + * 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 = "/individual?" + + VisualizationFrameworkConstants.INDIVIDUAL_URI_URL_HANDLE + + "=" + URLEncoder.encode(node.getNodeURL(), + VisualizationController + .URL_ENCODING_SCHEME).toString(); + } catch (UnsupportedEncodingException e) { + System.err.println("URL Encoding ERRor. Move this to use log.error ASAP"); + } + + + + graphMLContent.append("\n"); + graphMLContent.append("\t" + node.getNodeURL() + "\n"); + graphMLContent.append("\t" + node.getNodeName() + "\n"); + + if (profileURL != null) { + graphMLContent.append("\t" + profileURL + "\n"); + } + + + graphMLContent.append("\t" + + node.getNumOfAuthoredWorks() + + "\n"); + + if (node.getEarliestPublicationYearCount() != null) { + + /* + * There is no clean way of getting the map contents in java even though + * we are sure to have only one entry on the map. So using the for loop. + * I am feeling dirty just about now. + * */ + for (Map.Entry publicationInfo : + node.getEarliestPublicationYearCount().entrySet()) { + + graphMLContent.append("\t" + + publicationInfo.getKey() + + "\n"); + + graphMLContent.append("\t" + + publicationInfo.getValue() + + "\n"); + + + } + + } + + if (node.getLatestPublicationYearCount() != null) { + + for (Map.Entry publicationInfo : + node.getLatestPublicationYearCount().entrySet()) { + + graphMLContent.append("\t" + + publicationInfo.getKey() + + "\n"); + + graphMLContent.append("\t" + + publicationInfo.getValue() + + "\n"); + + + } + + } + + if (node.getUnknownPublicationYearCount() != null) { + + graphMLContent.append("\t" + + node.getUnknownPublicationYearCount() + + "\n"); + + } + + graphMLContent.append("\n"); + } + + private void generateKeyDefinitionContent(VisVOContainer visVOContainer, + StringBuilder graphMLContent) { + + /* + * Generate the key definition content for node. + * */ + getKeyDefinitionFromSchema(visVOContainer.getNodeSchema(), graphMLContent); + + /* + * Generate the key definition content for edge. + * */ + getKeyDefinitionFromSchema(visVOContainer.getEdgeSchema(), graphMLContent); + + + } + + private void getKeyDefinitionFromSchema(Set> schema, + StringBuilder graphMLContent) { + + for (Map currentNodeSchemaAttribute : schema) { + + graphMLContent.append("\n currentAttributeKey : currentNodeSchemaAttribute.entrySet()) { + + graphMLContent.append(currentAttributeKey.getKey() + + "=\"" + currentAttributeKey.getValue() + + "\" "); + + } + + if (currentNodeSchemaAttribute.containsKey("default")) { + + graphMLContent.append(">\n"); + graphMLContent.append(""); + graphMLContent.append(currentNodeSchemaAttribute.get("default")); + graphMLContent.append("\n"); + graphMLContent.append("\n"); + + } else { + graphMLContent.append("/>\n"); + } + + } + } + + + + + + + + + + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/coauthorship/QueryHandler.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/coauthorship/QueryHandler.java new file mode 100644 index 000000000..489487cdf --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/coauthorship/QueryHandler.java @@ -0,0 +1,441 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.coauthorship; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +import org.apache.commons.logging.Log; + +import com.hp.hpl.jena.iri.IRI; +import com.hp.hpl.jena.iri.IRIFactory; +import com.hp.hpl.jena.iri.Violation; +import com.hp.hpl.jena.query.DataSource; +import com.hp.hpl.jena.query.Query; +import com.hp.hpl.jena.query.QueryExecution; +import com.hp.hpl.jena.query.QueryExecutionFactory; +import com.hp.hpl.jena.query.QueryFactory; +import com.hp.hpl.jena.query.QuerySolution; +import com.hp.hpl.jena.query.ResultSet; +import com.hp.hpl.jena.query.Syntax; +import com.hp.hpl.jena.rdf.model.RDFNode; + +import edu.cornell.mannlib.vitro.webapp.visualization.constants.QueryConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.constants.QueryFieldLabels; +import edu.cornell.mannlib.vitro.webapp.visualization.exceptions.MalformedQueryParametersException; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.BiboDocument; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Edge; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Node; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.VivoCollegeOrSchool; +import edu.cornell.mannlib.vitro.webapp.visualization.visutils.UniqueIDGenerator; + + + +/** + * Very dumb name of the class. change it. + * @author cdtank + * + */ +public class QueryHandler { + + protected static final Syntax SYNTAX = Syntax.syntaxARQ; + + private String egoURLParam, resultFormatParam, rdfResultFormatParam; + private Map collegeURLToVO = new HashMap(); + private DataSource dataSource; + + private Log log; + + private UniqueIDGenerator nodeIDGenerator; + + private UniqueIDGenerator edgeIDGenerator; + + public QueryHandler(String egoURLParam, + String resultFormatParam, String rdfResultFormatParam, + DataSource dataSource, Log log) { + + this.egoURLParam = egoURLParam; + this.resultFormatParam = resultFormatParam; + this.rdfResultFormatParam = rdfResultFormatParam; + this.dataSource = dataSource; + this.log = log; + + this.nodeIDGenerator = new UniqueIDGenerator(); + this.edgeIDGenerator = new UniqueIDGenerator(); + + } + + private VisVOContainer createJavaValueObjects(ResultSet resultSet) { + + Set nodes = new HashSet(); + + Map biboDocumentURLToVO = new HashMap(); + Map> biboDocumentURLToCoAuthors = new HashMap>(); + Map nodeURLToVO = new HashMap(); + + Node egoNode = null; + + Set edges = new HashSet(); + + while (resultSet.hasNext()) { + QuerySolution solution = resultSet.nextSolution(); + + + /* + * We only want to create only ONE ego node. + * */ + RDFNode egoAuthorURLNode = solution.get(QueryFieldLabels.AUTHOR_URL); + if (nodeURLToVO.containsKey(egoAuthorURLNode.toString())) { + + egoNode = nodeURLToVO.get(egoAuthorURLNode.toString()); + + } else { + + egoNode = new Node(egoAuthorURLNode.toString(), nodeIDGenerator); + nodes.add(egoNode); + nodeURLToVO.put(egoAuthorURLNode.toString(), egoNode); + + RDFNode authorLabelNode = solution.get(QueryFieldLabels.AUTHOR_LABEL); + if (authorLabelNode != null) { + egoNode.setNodeName(authorLabelNode.toString()); + } + } + + RDFNode documentNode = solution.get(QueryFieldLabels.DOCUMENT_URL); + BiboDocument biboDocument; + + if (biboDocumentURLToVO.containsKey(documentNode.toString())) { + biboDocument = biboDocumentURLToVO.get(documentNode.toString()); + } else { + biboDocument = createDocumentVO(solution, documentNode.toString()); + biboDocumentURLToVO.put(documentNode.toString(), biboDocument); + } + + egoNode.addAuthorDocument(biboDocument); + + /* + * After some discussion we concluded that for the purpose of this visualization + * we do not want a co-author node or edge if the publication has only one + * author and that happens to be the ego. + * */ + if (solution.get(QueryFieldLabels.AUTHOR_URL).toString().equalsIgnoreCase( + solution.get(QueryFieldLabels.CO_AUTHOR_URL).toString())) { + continue; + } + + Node coAuthorNode; + + RDFNode coAuthorURLNode = solution.get(QueryFieldLabels.CO_AUTHOR_URL); + if (nodeURLToVO.containsKey(coAuthorURLNode.toString())) { + + coAuthorNode = nodeURLToVO.get(coAuthorURLNode.toString()); + + } else { + + coAuthorNode = new Node(coAuthorURLNode.toString(), nodeIDGenerator); + nodes.add(coAuthorNode); + nodeURLToVO.put(coAuthorURLNode.toString(), coAuthorNode); + + RDFNode coAuthorLabelNode = solution.get(QueryFieldLabels.CO_AUTHOR_LABEL); + if (coAuthorLabelNode != null) { + coAuthorNode.setNodeName(coAuthorLabelNode.toString()); + } + } + + coAuthorNode.addAuthorDocument(biboDocument); + + Set coAuthorsForCurrentBiboDocument; + + if (biboDocumentURLToCoAuthors.containsKey(biboDocument.getDocumentURL())) { + coAuthorsForCurrentBiboDocument = biboDocumentURLToCoAuthors.get(biboDocument.getDocumentURL()); + } else { + coAuthorsForCurrentBiboDocument = new HashSet(); + biboDocumentURLToCoAuthors.put(biboDocument.getDocumentURL(), coAuthorsForCurrentBiboDocument); + } + + coAuthorsForCurrentBiboDocument.add(coAuthorNode); + + Edge egoCoAuthorEdge = getExistingEdge(egoNode, coAuthorNode, edges); + + /* + * If "egoCoAuthorEdge" is null it means that no edge exists in between the egoNode & current + * coAuthorNode. Else create a new edge, add it to the edges set & add the collaborator document + * to it. + * */ + if (egoCoAuthorEdge != null) { + egoCoAuthorEdge.addCollaboratorDocument(biboDocument); + } else { + egoCoAuthorEdge = new Edge(egoNode, coAuthorNode, biboDocument, edgeIDGenerator); + edges.add(egoCoAuthorEdge); + } + + + } + + /* + * We need to create edges between 2 co-authors. E.g. On a paper there were 3 authors + * ego, A & B then we have already created edges like, + * ego - A + * ego - B + * The below sub-routine will take care of, + * A - B + * + * We are side-effecting "edges" here. The only reason to do this is because we are adding + * edges en masse for all the co-authors on all the publications considered so far. The other + * reason being we dont want to compare against 2 sets of edges (edges created before & co- + * author edges created during the course of this method) when we are creating a new edge. + * */ + createCoAuthorEdges(biboDocumentURLToVO, + biboDocumentURLToCoAuthors, + edges); + + +/* System.out.println(collegeURLToVO); + System.out.println("------------------------------------------------------------"); + System.out.println(departmentURLToVO); + System.out.println("------------------------------------------------------------"); + System.out.println(employeeURLToVO); + System.out.println("------------------------------------------------------------"); +*/ + return new VisVOContainer(egoNode, nodes, edges); + } + + private void createCoAuthorEdges( + Map biboDocumentURLToVO, + Map> biboDocumentURLToCoAuthors, Set edges) { + for (Map.Entry> currentBiboDocumentEntry : biboDocumentURLToCoAuthors.entrySet()) { + /* + * If there was only one co-author (other than ego) then we dont have to create any edges. so + * the below condition will take care of that. + * */ + if (currentBiboDocumentEntry.getValue().size() > 1) { + + /* + * In order to leverage the nested "for loop" for making edges between all the co=authors + * we need to create a list out of the set first. + * */ + List coAuthorNodes = new ArrayList(currentBiboDocumentEntry.getValue()); + + int numOfCoAuthors = coAuthorNodes.size(); + + for (int ii = 0; ii < numOfCoAuthors - 1; ii++) { + for (int jj = ii + 1; jj < numOfCoAuthors; jj++) { + + Node coAuthor1 = coAuthorNodes.get(ii); + Node coAuthor2 = coAuthorNodes.get(jj); + + Edge coAuthor1_2Edge = getExistingEdge(coAuthor1, coAuthor2, edges); + + BiboDocument currentBiboDocument = biboDocumentURLToVO + .get(currentBiboDocumentEntry.getKey()); + + if (coAuthor1_2Edge != null) { + coAuthor1_2Edge.addCollaboratorDocument(currentBiboDocument); + } else { + coAuthor1_2Edge = new Edge(coAuthor1, coAuthor2, currentBiboDocument, edgeIDGenerator); + edges.add(coAuthor1_2Edge); + } + } + } + + } + + } + } + + private Edge getExistingEdge( + Node collaboratingNode1, + Node collaboratingNode2, + Set edges) { + + Edge duplicateEdge = null; + + for (Edge currentEdge : edges) { + + /* + * We first check if either the source or target node of the current edge is + * the collaboratingNode1. If yes then we go on to check if the collaboratingNode2 + * matches either the source or the target node. We dont care about the directionality + * of the edge. + * */ + if (currentEdge.getSourceNode().getNodeID() == collaboratingNode1.getNodeID() + || currentEdge.getTargetNode().getNodeID() == collaboratingNode1.getNodeID()) { + + if (currentEdge.getSourceNode().getNodeID() == collaboratingNode2.getNodeID() + || currentEdge.getTargetNode().getNodeID() == collaboratingNode2.getNodeID()) { + + duplicateEdge = currentEdge; + break; + } + } + } + + return duplicateEdge; + } + + public Map getCollegeURLToVO() { + return collegeURLToVO; + } + + private BiboDocument createDocumentVO(QuerySolution solution, String documentURL) { + + BiboDocument biboDocument = new BiboDocument(documentURL); + + RDFNode documentLabelNode = solution.get(QueryFieldLabels.DOCUMENT_LABEL); + if (documentLabelNode != null) { + biboDocument.setDocumentLabel(documentLabelNode.toString()); + } + + RDFNode documentBlurbNode = solution.get(QueryFieldLabels.DOCUMENT_BLURB); + if (documentBlurbNode != null) { + biboDocument.setDocumentBlurb(documentBlurbNode.toString()); + } + + RDFNode documentMonikerNode = solution.get(QueryFieldLabels.DOCUMENT_MONIKER); + if (documentMonikerNode != null) { + biboDocument.setDocumentMoniker(documentMonikerNode.toString()); + } + + RDFNode publicationYearNode = solution.get(QueryFieldLabels.DOCUMENT_PUBLICATION_YEAR); + if (publicationYearNode != null) { + biboDocument.setPublicationYear(publicationYearNode.toString()); + } + + return biboDocument; + } + + private ResultSet executeQuery(String queryText, + String resultFormatParam, + String rdfResultFormatParam, + DataSource dataSource) { + + QueryExecution queryExecution = null; + try{ + Query query = QueryFactory.create(queryText, SYNTAX); + +// QuerySolutionMap qs = new QuerySolutionMap(); +// qs.add("authPerson", queryParam); // bind resource to s + + queryExecution = QueryExecutionFactory.create(query, dataSource); + + + //remocve this if loop after knowing what is describe & construct sparql stuff. + if (query.isSelectType()){ + return queryExecution.execSelect(); + } + } finally { + if(queryExecution != null) { + queryExecution.close(); + } + + } + return null; + } + + private String generateEgoCoAuthorshipSparqlQuery(String queryURI) { +// Resource uri1 = ResourceFactory.createResource(queryURI); + + String sparqlQuery = QueryConstants.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 + ") " + + "WHERE { " + + "<" + queryURI + "> rdf:type foaf:Person ; vivo:authorOf ?document ; rdfs:label ?authorLabel. " + + "?document rdf:type bibo:Document . " + + "?document rdfs:label ?documentLabel . " + + "?document vivo:hasAuthor ?coAuthorPerson . " + + "?coAuthorPerson rdfs:label ?coAuthorPersonLabel . " + + "OPTIONAL { ?document vivo:publicationYear ?publicationYear } . " + + "OPTIONAL { ?document vitro:moniker ?documentMoniker } . " + + "OPTIONAL { ?document vitro:blurb ?documentBlurb } . " + + "OPTIONAL { ?document vitro:description ?documentDescription } " +// + "FILTER (<" + queryURI + "> != ?coAuthorPerson ) . " + + "}"; + + System.out.println(sparqlQuery); + + return sparqlQuery; + } + + + public VisVOContainer getVisualizationJavaValueObjects() + throws MalformedQueryParametersException { + + if (this.egoURLParam == null || "".equals(egoURLParam)) { + throw new MalformedQueryParametersException("URI parameter is either null or empty."); + } else { + + /* + * To test for the validity of the URI submitted. + * */ + IRIFactory iRIFactory = IRIFactory.jenaImplementation(); + IRI iri = iRIFactory.create(this.egoURLParam); + if (iri.hasViolation(false)) { + String errorMsg = ((Violation)iri.violations(false).next()).getShortMessage()+" "; + log.error("Ego Co Authorship Vis Query " + errorMsg); + throw new MalformedQueryParametersException("URI provided for an individual is malformed."); + } + } + + ResultSet resultSet = executeQuery(generateEgoCoAuthorshipSparqlQuery(this.egoURLParam), + this.resultFormatParam, + this.rdfResultFormatParam, + this.dataSource); + + return createJavaValueObjects(resultSet); + } + + public Map getYearToPublicationCount( + Set authorDocuments) { + + /* + * Create a map from the year to number of publications. Use the BiboDocument's + * parsedPublicationYear to populate the data. + * */ + Map yearToPublicationCount = new TreeMap(); + + for (BiboDocument curr : authorDocuments) { + + /* + * Increment the count because there is an entry already available for + * that particular year. + * */ + String publicationYear; + if (curr.getPublicationYear() != null + && curr.getPublicationYear().length() != 0 + && curr.getPublicationYear().trim().length() != 0) { + publicationYear = curr.getPublicationYear(); + } else { + publicationYear = curr.getParsedPublicationYear(); + } + + if (yearToPublicationCount.containsKey(publicationYear)) { + yearToPublicationCount.put(publicationYear, + yearToPublicationCount + .get(publicationYear) + 1); + + } else { + yearToPublicationCount.put(publicationYear, 1); + } + + } + +// System.out.println("****************************\n" + yearToPublicationCount); + return yearToPublicationCount; + } + + + + + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/coauthorship/VisVOContainer.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/coauthorship/VisVOContainer.java new file mode 100644 index 000000000..7cfb31030 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/coauthorship/VisVOContainer.java @@ -0,0 +1,232 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.coauthorship; + +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Edge; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Node; + +public class VisVOContainer { + + private Set nodes; + private Set edges; + private Node egoNode; + private Set> NODE_SCHEMA; + private Set> EDGE_SCHEMA; + + public VisVOContainer(Node egoNode, Set nodes, Set edges) { + this.egoNode = egoNode; + this.nodes = nodes; + this.edges = edges; + } + + public Set getNodes() { + return nodes; + } + + public Set getEdges() { + return edges; + } + + public Node getEgoNode() { + return egoNode; + } + + /* + * Node Schema for graphML + * */ + public Set> getNodeSchema() { + + if (NODE_SCHEMA == null) { + NODE_SCHEMA = initializeNodeSchema(); + } + + return NODE_SCHEMA; + } + + /* + * Edge Schema for graphML + * */ + public Set> getEdgeSchema() { + + if (EDGE_SCHEMA == null) { + EDGE_SCHEMA = initializeEdgeSchema(); + } + + return EDGE_SCHEMA; + } + + private Set> initializeEdgeSchema() { + + Set> edgeSchema = new HashSet>(); + + Map schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "collaborator1"); + schemaAttributes.put("for", "edge"); + schemaAttributes.put("attr.name", "collaborator1"); + schemaAttributes.put("attr.type", "string"); + + edgeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "collaborator2"); + schemaAttributes.put("for", "edge"); + schemaAttributes.put("attr.name", "collaborator2"); + schemaAttributes.put("attr.type", "string"); + + edgeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "number_of_coauthored_works"); + schemaAttributes.put("for", "edge"); + schemaAttributes.put("attr.name", "number_of_coauthored_works"); + schemaAttributes.put("attr.type", "int"); + + edgeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "earliest_collaboration"); + schemaAttributes.put("for", "edge"); + schemaAttributes.put("attr.name", "earliest_collaboration"); + schemaAttributes.put("attr.type", "int"); + + edgeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "num_earliest_collaboration"); + schemaAttributes.put("for", "edge"); + schemaAttributes.put("attr.name", "num_earliest_collaboration"); + schemaAttributes.put("attr.type", "int"); + + edgeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "latest_collaboration"); + schemaAttributes.put("for", "edge"); + schemaAttributes.put("attr.name", "latest_collaboration"); + schemaAttributes.put("attr.type", "int"); + + edgeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "num_latest_collaboration"); + schemaAttributes.put("for", "edge"); + schemaAttributes.put("attr.name", "num_latest_collaboration"); + schemaAttributes.put("attr.type", "int"); + + edgeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "num_unknown_collaboration"); + schemaAttributes.put("for", "edge"); + schemaAttributes.put("attr.name", "num_unknown_collaboration"); + schemaAttributes.put("attr.type", "int"); + + edgeSchema.add(schemaAttributes); + + return edgeSchema; + } + + + private Set> initializeNodeSchema() { + + Set> nodeSchema = new HashSet>(); + + Map schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "url"); + schemaAttributes.put("for", "node"); + schemaAttributes.put("attr.name", "url"); + schemaAttributes.put("attr.type", "string"); + + nodeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "name"); + schemaAttributes.put("for", "node"); + schemaAttributes.put("attr.name", "name"); + schemaAttributes.put("attr.type", "string"); + + nodeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "profile_url"); + schemaAttributes.put("for", "node"); + schemaAttributes.put("attr.name", "profile_url"); + schemaAttributes.put("attr.type", "string"); + + nodeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "number_of_authored_works"); + schemaAttributes.put("for", "node"); + schemaAttributes.put("attr.name", "number_of_authored_works"); + schemaAttributes.put("attr.type", "int"); + + nodeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "earliest_publication"); + schemaAttributes.put("for", "node"); + schemaAttributes.put("attr.name", "earliest_publication"); + schemaAttributes.put("attr.type", "int"); + + nodeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "num_earliest_publication"); + schemaAttributes.put("for", "node"); + schemaAttributes.put("attr.name", "num_earliest_publication"); + schemaAttributes.put("attr.type", "int"); + + nodeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "latest_publication"); + schemaAttributes.put("for", "node"); + schemaAttributes.put("attr.name", "latest_publication"); + schemaAttributes.put("attr.type", "int"); + + nodeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "num_latest_publication"); + schemaAttributes.put("for", "node"); + schemaAttributes.put("attr.name", "num_latest_publication"); + schemaAttributes.put("attr.type", "int"); + + nodeSchema.add(schemaAttributes); + + schemaAttributes = new LinkedHashMap(); + + schemaAttributes.put("id", "num_unknown_publication"); + schemaAttributes.put("for", "node"); + schemaAttributes.put("attr.name", "num_unknown_publication"); + schemaAttributes.put("attr.type", "int"); + + nodeSchema.add(schemaAttributes); + + + return nodeSchema; + } + + + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/coauthorship/VisualizationCodeGenerator.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/coauthorship/VisualizationCodeGenerator.java new file mode 100644 index 000000000..442401d7b --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/coauthorship/VisualizationCodeGenerator.java @@ -0,0 +1,643 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.coauthorship; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +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.visualization.VisualizationController; +import edu.cornell.mannlib.vitro.webapp.controller.visualization.VisualizationFrameworkConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.constants.VOConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.SparklineVOContainer; + + +public class VisualizationCodeGenerator { + + private final static Map visDivNames = new HashMap() {{ + + put("SHORT_SPARK", "unique_coauthors_short_sparkline_vis"); + put("FULL_SPARK", "unique_coauthors_full_sparkline_vis"); + + }}; + + private static final String visualizationStyleClass = "sparkline_style"; + + private static final String defaultVisContainerDivID = "unique_coauthors_vis_container"; + + public static final String SHORT_SPARKLINE_MODE_URL_HANDLE = "short"; + + public static final String FULL_SPARKLINE_MODE_URL_HANDLE = "full"; + + private Map yearToUniqueCoauthorsCount; + + private Log log; + + private SparklineVOContainer valueObjectContainer; + + private String contextPath; + + private String individualURIParam; + + public VisualizationCodeGenerator(String contextPath, + String individualURIParam, + String visMode, + String visContainer, + Map yearToUniqueCoauthorsCount, + SparklineVOContainer valueObjectContainer, + Log log) { + + this.contextPath = contextPath; + this.individualURIParam = individualURIParam; + + this.yearToUniqueCoauthorsCount = yearToUniqueCoauthorsCount; + this.valueObjectContainer = valueObjectContainer; + + this.log = log; + + + generateVisualizationCode(visMode, + visContainer); + + + } + + private void generateVisualizationCode(String visMode, + String visContainer) { + + valueObjectContainer.setSparklineContent(getMainVisualizationCode(visMode, + visContainer)); + + + valueObjectContainer.setSparklineContext(getVisualizationContextCode(visMode)); + + } + + private String getMainVisualizationCode(String visMode, + String providedVisContainerID) { + + int numOfYearsToBeRendered = 0; + int currentYear = Calendar.getInstance().get(Calendar.YEAR); + int shortSparkMinYear = currentYear - 10 + 1; + + /* + * This is required because when deciding the range of years over which the vis + * was rendered we dont want to be influenced by the "DEFAULT_PUBLICATION_YEAR". + * */ + Set publishedYears = new HashSet(yearToUniqueCoauthorsCount.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(); + +// System.out.println(yearToPublicationCount); + if (yearToUniqueCoauthorsCount.size() > 0) { + try { + minPublishedYear = Integer.parseInt(Collections.min(publishedYears)); + System.out.println("min pub year - " + minPublishedYear); + } catch (NoSuchElementException e1) { + log.debug("vis: " + e1.getMessage() + " error occurred for " + yearToUniqueCoauthorsCount.toString()); + } catch (NumberFormatException e2) { + log.debug("vis: " + e2.getMessage() + " error occurred for " + yearToUniqueCoauthorsCount.toString()); + } + } + + int minPubYearConsidered = 0; + + /* + * There might be a case that the author has made his first publication within the + * last 10 years but we want to make sure that the sparkline is representative of + * at least the last 10 years, so we will set the minPubYearConsidered to + * "currentYear - 10" which is also given by "shortSparkMinYear". + * */ + if (minPublishedYear > shortSparkMinYear) { + minPubYearConsidered = shortSparkMinYear; + } else { + minPubYearConsidered = minPublishedYear; + } + + numOfYearsToBeRendered = currentYear - minPubYearConsidered + 1; + + visualizationCode.append("\n"); + +// .sparkline {display:inline; margin:0; padding:0; width:600px } + + + +// td.sparkline-img {margin:0; padding:0; } + + + visualizationCode.append("\n"; + } + + private String getVisualizationContextCode(String visMode) { + + String visualizationContextCode = ""; + if (SHORT_SPARKLINE_MODE_URL_HANDLE.equalsIgnoreCase(visMode)) { + visualizationContextCode = generateShortVisContext(); + } else { + visualizationContextCode = generateFullVisContext(); + } + + + + + + +// System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); + log.debug(visualizationContextCode); +// System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); + + return visualizationContextCode; + } + + private String generateFullVisContext() { + + StringBuilder divContextCode = new StringBuilder(); + + String csvDownloadURLHref = ""; + + if (yearToUniqueCoauthorsCount.size() > 0) { + + try { + if (getCSVDownloadURL() != null) { + + csvDownloadURLHref = "Download data as .csv file.
"; + valueObjectContainer.setDownloadDataLink(getCSVDownloadURL()); + + } else { + + csvDownloadURLHref = ""; + + } + + } catch (UnsupportedEncodingException e) { + csvDownloadURLHref = ""; + } + + + } else { + csvDownloadURLHref = "No data available to export.
"; + } + + String tableCode = generateDataTable(); + + divContextCode.append("

" + tableCode + + csvDownloadURLHref + "

"); + + valueObjectContainer.setTable(tableCode); + + return divContextCode.toString(); + + } + + private String getCSVDownloadURL() + throws UnsupportedEncodingException { + + if (yearToUniqueCoauthorsCount.size() > 0) { + + String secondaryContextPath = ""; + if (!contextPath.contains("/admin/visQuery")) { + secondaryContextPath = "/admin/visQuery"; + } + + + String downloadURL = contextPath + + secondaryContextPath + + "?" + VisualizationFrameworkConstants.INDIVIDUAL_URI_URL_HANDLE + + "=" + URLEncoder.encode(individualURIParam, + VisualizationController.URL_ENCODING_SCHEME).toString() + + "&" + VisualizationFrameworkConstants.VIS_TYPE_URL_HANDLE + + "=" + URLEncoder.encode(VisualizationController + .COAUTHORSHIP_VIS_URL_VALUE, + VisualizationController.URL_ENCODING_SCHEME).toString() + + "&" + VisualizationFrameworkConstants.VIS_MODE_URL_HANDLE + + "=" + URLEncoder.encode("sparkline", + VisualizationController.URL_ENCODING_SCHEME).toString() + + "&" + VisualizationFrameworkConstants.RENDER_MODE_URL_HANDLE + + "=" + URLEncoder.encode(VisualizationFrameworkConstants.DATA_RENDER_MODE_URL_VALUE, + VisualizationController.URL_ENCODING_SCHEME).toString(); + + System.out.println(" ----- >>>> " + contextPath + " XX " + individualURIParam + " XX " + downloadURL); + + return downloadURL; + } else { + return null; + } + + } + + + private String generateShortVisContext() { + + StringBuilder divContextCode = new StringBuilder(); + + try { + + String fullTimelineLink; + if (yearToUniqueCoauthorsCount.size() > 0) { + + String secondaryContextPath = ""; + if (!contextPath.contains("/admin/visQuery")) { + secondaryContextPath = "/admin/visQuery"; + } + + String fullTimelineNetworkURL = contextPath + + secondaryContextPath + + "?" + + VisualizationFrameworkConstants.INDIVIDUAL_URI_URL_HANDLE + + "=" + URLEncoder.encode(individualURIParam, + VisualizationController.URL_ENCODING_SCHEME).toString() + + "&" + + VisualizationFrameworkConstants.VIS_TYPE_URL_HANDLE + + "=" + URLEncoder.encode("person_level", + VisualizationController.URL_ENCODING_SCHEME).toString() + + "&" + + VisualizationFrameworkConstants.VIS_CONTAINER_URL_HANDLE + + "=" + URLEncoder.encode("ego_sparkline", + VisualizationController.URL_ENCODING_SCHEME).toString() + + "&" + + VisualizationFrameworkConstants.RENDER_MODE_URL_HANDLE + + "=" + URLEncoder.encode(VisualizationFrameworkConstants.STANDALONE_RENDER_MODE_URL_VALUE, + VisualizationController.URL_ENCODING_SCHEME).toString(); + + System.out.println("context parth full n/w " + contextPath); + + fullTimelineLink = "View full timeline and co-author network
"; + + valueObjectContainer.setFullTimelineNetworkLink(fullTimelineNetworkURL); + + } else { + + fullTimelineLink = "No data available to render full timeline.
"; + + } + + divContextCode.append("

" + fullTimelineLink + "

"); + + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + + return divContextCode.toString(); + + } + + + private String generateDataTable() { + + StringBuilder dataTable = new StringBuilder(); + + dataTable.append("" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + ""); + + for (Entry currentEntry : yearToUniqueCoauthorsCount.entrySet()) { + dataTable.append("" + + "" + + "" + + ""); + } + + dataTable.append("\n" + +// "" + +// "" + +// "\n" + + "
Unique Co-Authors per year
YearCount
" + currentEntry.getKey() + "" + currentEntry.getValue() + "
*DNA - Data not available
\n"); + + + return dataTable.toString(); + } + + + + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/coauthorship/VisualizationRequestHandler.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/coauthorship/VisualizationRequestHandler.java new file mode 100644 index 000000000..a23c41a42 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/coauthorship/VisualizationRequestHandler.java @@ -0,0 +1,343 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.coauthorship; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.Map.Entry; + +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.logging.Log; +import org.skife.csv.CSVWriter; +import org.skife.csv.SimpleWriter; + +import com.hp.hpl.jena.query.DataSource; + +import edu.cornell.mannlib.vitro.webapp.beans.Portal; +import edu.cornell.mannlib.vitro.webapp.controller.Controllers; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.controller.visualization.VisualizationFrameworkConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.exceptions.MalformedQueryParametersException; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Node; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.VivoCollegeOrSchool; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.VivoDepartmentOrDivision; +import edu.cornell.mannlib.vitro.webapp.visualization.visutils.UtilityFunctions; + +public class VisualizationRequestHandler { + + private VitroRequest vitroRequest; + private HttpServletRequest request; + private HttpServletResponse response; + private Log log; + + public VisualizationRequestHandler(VitroRequest vitroRequest, + HttpServletRequest request, HttpServletResponse response, Log log) { + + this.vitroRequest = vitroRequest; + this.request = request; + this.response = response; + this.log = log; + + } + + public void generateVisualization(DataSource dataSource) { + + String resultFormatParam = "RS_TEXT"; + String rdfResultFormatParam = "RDF/XML-ABBREV"; + + String egoURIParam = vitroRequest.getParameter(VisualizationFrameworkConstants.INDIVIDUAL_URI_URL_HANDLE); + + String renderMode = vitroRequest.getParameter(VisualizationFrameworkConstants.RENDER_MODE_URL_HANDLE); + + String visMode = vitroRequest.getParameter(VisualizationFrameworkConstants.VIS_MODE_URL_HANDLE); + + String visContainer = vitroRequest.getParameter(VisualizationFrameworkConstants.VIS_CONTAINER_URL_HANDLE); + + String sparklineVisMode = "sparkline"; + + QueryHandler queryManager = + new QueryHandler(egoURIParam, + resultFormatParam, + rdfResultFormatParam, + dataSource, + + log); + + try { + + VisVOContainer authorNodesAndEdges = queryManager.getVisualizationJavaValueObjects(); + + /* + * In order to avoid unneeded computations we have pushed this "if" condition up. + * This case arises when the render mode is data. In that case we dont want to generate + * HTML code to render sparkline, tables etc. Ideally I would want to avoid this flow. + * It is ugly! + * */ + + if (VisualizationFrameworkConstants.DATA_RENDER_MODE_URL_VALUE.equalsIgnoreCase(renderMode)) { + + /* + * We will be using the same visualization package for both sparkline & coauthorship flash + * vis. We will use "VIS_MODE_URL_HANDLE" as a modifier to differentiate between these two. + * The defualt will be to render the coauthorship network vis. + * */ + + if (sparklineVisMode.equalsIgnoreCase(visMode)) { + /* + * When the csv file is required - based on which sparkline visualization will + * be rendered. + * */ + prepareVisualizationQuerySparklineDataResponse(authorNodesAndEdges); + return; + + } else { + /* + * When the graphML file is required - based on which coauthorship network visualization + * will be rendered. + * */ + prepareVisualizationQueryNetworkDataResponse(authorNodesAndEdges); + return; + } + } + + + + /* + * Computations required to generate HTML for the sparklines & related context. + * */ + + /* + * This is required because when deciding the range of years over which the vis + * was rendered we dont want to be influenced by the "DEFAULT_PUBLICATION_YEAR". + * */ +// publishedYearsForCollege.remove(VOConstants.DEFAULT_PUBLICATION_YEAR); + + /* + VisualizationCodeGenerator visualizationCodeGenerator = + new VisualizationCodeGenerator(yearToPublicationCount, log); + + String visContentCode = visualizationCodeGenerator + .getMainVisualizationCode(authorDocuments, + publishedYears, + visMode, + visContainer); + + String visContextCode = visualizationCodeGenerator + .getVisualizationContextCode(vitroRequest.getRequestURI(), + collegeURIParam, + visMode); + */ + + /* + * This is side-effecting because the response of this method is just to redirect to + * a page with visualization on it. + * */ + + RequestDispatcher requestDispatcher = null; + + prepareVisualizationQueryStandaloneResponse(egoURIParam, request, response, vitroRequest); + +// requestDispatcher = request.getRequestDispatcher(Controllers.BASIC_JSP); + requestDispatcher = request.getRequestDispatcher("/templates/page/blankPage.jsp"); + + try { + requestDispatcher.forward(request, response); + } catch (Exception e) { + log.error("EntityEditController could not forward to view."); + log.error(e.getMessage()); + log.error(e.getStackTrace()); + } + + } catch (MalformedQueryParametersException e) { + try { + handleMalformedParameters(e.getMessage()); + } catch (ServletException e1) { + log.error(e1.getStackTrace()); + } catch (IOException e1) { + log.error(e1.getStackTrace()); + } + return; + } + + } + + private void prepareVisualizationQueryNetworkDataResponse(VisVOContainer authorNodesAndEdges) { + + response.setContentType("text/xml"); + + try { + + PrintWriter responseWriter = response.getWriter(); + + /* + * We are side-effecting responseWriter since we are directly manipulating the response + * object of the servlet. + * */ + + CoAuthorshipGraphMLWriter coAuthorShipGraphMLWriter = new CoAuthorshipGraphMLWriter(authorNodesAndEdges); + + responseWriter.append(coAuthorShipGraphMLWriter.getCoAuthorshipGraphMLContent()); + + responseWriter.close(); + + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void prepareVisualizationQuerySparklineDataResponse(VisVOContainer authorNodesAndEdges) { + + String outputFileName = ""; + Map> yearToCoauthors = new TreeMap>(); + + if (authorNodesAndEdges.getNodes() == null || authorNodesAndEdges.getNodes().size() < 1 ) { + + outputFileName = "no-coauthors" + ".csv"; + + } else { + + outputFileName = UtilityFunctions.slugify(authorNodesAndEdges.getEgoNode().getNodeName()) + + "-coauthors" + ".csv"; + + yearToCoauthors = getCoAuthorsStats(authorNodesAndEdges); + + } + + + + response.setContentType("application/octet-stream"); + response.setHeader("Content-Disposition", "attachment;filename=" + outputFileName); + + try { + + PrintWriter responseWriter = response.getWriter(); + + /* + * We are side-effecting responseWriter since we are directly manipulating the response + * object of the servlet. + * */ + generateCsvFileBuffer(yearToCoauthors, + responseWriter); + + responseWriter.close(); + + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void generateCsvFileBuffer(Map> yearToCoauthors, PrintWriter printWriter) { + + printWriter.append("\"Year\", \"Number of Co-Authors\", \"Co-Author(s)\"\n"); + + for (Entry> currentEntry : yearToCoauthors.entrySet()) { + + printWriter.append("\"" + currentEntry.getKey() + "\"," + + "\"" + currentEntry.getValue().size() + "\"," + + "\"" + getCoauthorsString(currentEntry.getValue()) + "\"\n" + ); + + + } + + printWriter.flush(); + + } + + private String getCoauthorsString(Set coAuthors) { + + StringBuilder coAuthorsMerged = new StringBuilder(); + + for (Node currCoAuthor : coAuthors) { + coAuthorsMerged.append(currCoAuthor.getNodeName() + "; "); + } + + return coAuthorsMerged.toString(); + } + + private Map> getCoAuthorsStats(VisVOContainer authorNodesAndEdges) { + + Map> yearToCoAuthors = new TreeMap>(); + + Node egoNode = authorNodesAndEdges.getEgoNode(); + + for (Node currNode : authorNodesAndEdges.getNodes()) { + + /* + * We have already printed the Ego Node info. + * */ + if (currNode != egoNode) { + + for (String year : currNode.getYearToPublicationCount().keySet()) { + + Set coAuthorNodes; + + if (yearToCoAuthors.containsKey(year)) { + + coAuthorNodes = yearToCoAuthors.get(year); + coAuthorNodes.add(currNode); + + } else { + + coAuthorNodes = new HashSet(); + coAuthorNodes.add(currNode); + yearToCoAuthors.put(year, coAuthorNodes); + } + + } + + } + } + + + return yearToCoAuthors; + } + + private void prepareVisualizationQueryStandaloneResponse(String egoURIParam, + HttpServletRequest request, + HttpServletResponse response, + VitroRequest vreq) { + + Portal portal = vreq.getPortal(); + +// request.setAttribute("visContentCode", visContentCode); +// request.setAttribute("visContextCode", visContextCode); + + request.setAttribute("egoURIParam", egoURIParam); + + request.setAttribute("bodyJsp", "/templates/visualization/co_authorship.jsp"); + request.setAttribute("portalBean", portal); +// request.setAttribute("title", "Individual Publication Count Visualization"); +// request.setAttribute("scripts", "/templates/visualization/visualization_scripts.jsp"); + + } + + private void handleMalformedParameters(String errorMessage) + throws ServletException, IOException { + + Portal portal = vitroRequest.getPortal(); + + request.setAttribute("error", errorMessage); + + RequestDispatcher requestDispatcher = request.getRequestDispatcher(Controllers.BASIC_JSP); + request.setAttribute("bodyJsp", "/templates/visualization/visualization_error.jsp"); + request.setAttribute("portalBean", portal); + request.setAttribute("title", "Visualization Query Error - Individual Publication Count"); + + try { + requestDispatcher.forward(request, response); + } catch (Exception e) { + log.error("EntityEditController could not forward to view."); + log.error(e.getMessage()); + log.error(e.getStackTrace()); + } + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/collegepubcount/QueryHandler.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/collegepubcount/QueryHandler.java new file mode 100644 index 000000000..33a91f384 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/collegepubcount/QueryHandler.java @@ -0,0 +1,364 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.collegepubcount; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +import org.apache.commons.logging.Log; + +import com.hp.hpl.jena.iri.IRI; +import com.hp.hpl.jena.iri.IRIFactory; +import com.hp.hpl.jena.iri.Violation; +import com.hp.hpl.jena.query.DataSource; +import com.hp.hpl.jena.query.Query; +import com.hp.hpl.jena.query.QueryExecution; +import com.hp.hpl.jena.query.QueryExecutionFactory; +import com.hp.hpl.jena.query.QueryFactory; +import com.hp.hpl.jena.query.QuerySolution; +import com.hp.hpl.jena.query.ResultSet; +import com.hp.hpl.jena.query.Syntax; +import com.hp.hpl.jena.rdf.model.RDFNode; + +import edu.cornell.mannlib.vitro.webapp.visualization.constants.QueryConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.constants.QueryFieldLabels; +import edu.cornell.mannlib.vitro.webapp.visualization.constants.VOConstants.EmployeeType; +import edu.cornell.mannlib.vitro.webapp.visualization.exceptions.MalformedQueryParametersException; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.BiboDocument; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.VivoCollegeOrSchool; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.VivoDepartmentOrDivision; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.VivoEmployee; + + + +/** + * Very dumb name of the class. change it. + * @author cdtank + * + */ +public class QueryHandler { + + protected static final Syntax SYNTAX = Syntax.syntaxARQ; + + private String collegeURIParam, resultFormatParam, rdfResultFormatParam; + private Map collegeURLToVO = new HashMap(); + private DataSource dataSource; + + private Log log; + + public QueryHandler(String collegeURIParam, + String resultFormatParam, String rdfResultFormatParam, + DataSource dataSource, Log log) { + + this.collegeURIParam = collegeURIParam; + this.resultFormatParam = resultFormatParam; + this.rdfResultFormatParam = rdfResultFormatParam; + this.dataSource = dataSource; + this.log = log; + + } + + private Set createJavaValueObjects(ResultSet resultSet) { + + Set collegeAcademicEmployees = new HashSet(); + + Map departmentURLToVO = new HashMap(); + Map employeeURLToVO = new HashMap(); + + while (resultSet.hasNext()) { + QuerySolution solution = resultSet.nextSolution(); + + String collegeURL = solution.get(QueryFieldLabels.COLLEGE_URL).toString(); + + VivoCollegeOrSchool currentCollege; + + if (collegeURLToVO.containsKey(collegeURL)) { + currentCollege = collegeURLToVO.get(collegeURL); + } else { + currentCollege = new VivoCollegeOrSchool(collegeURL); + collegeURLToVO.put(collegeURL, currentCollege); + + RDFNode collegeLabelNode = solution.get(QueryFieldLabels.COLLEGE_LABEL); + if (collegeLabelNode != null) { + currentCollege.setCollegeLabel(collegeLabelNode.toString()); + } + } + + String departmentURL = solution.get(QueryFieldLabels.DEPARTMENT_URL).toString(); + + VivoDepartmentOrDivision currentDepartment; + + if (departmentURLToVO.containsKey(departmentURL)) { + currentDepartment = departmentURLToVO.get(departmentURL); + currentDepartment.addParentCollege(currentCollege); + } else { + currentDepartment = new VivoDepartmentOrDivision(departmentURL, currentCollege); + departmentURLToVO.put(departmentURL, currentDepartment); + + RDFNode departmentLabelNode = solution.get(QueryFieldLabels.DEPARTMENT_LABEL); + if (departmentLabelNode != null) { + currentDepartment.setDepartmentLabel(departmentLabelNode.toString()); + } + } + + currentCollege.addDepartment(currentDepartment); + + RDFNode employeeNode = solution.get(QueryFieldLabels.ACADEMIC_FACULTY_EMPLOYEE_URL); + EmployeeType currentEmployeeType; + VivoEmployee currentEmployee; + + if (employeeNode != null) { + currentEmployeeType = EmployeeType.ACADEMIC_FACULTY_EMPLOYEE; + } else { + currentEmployeeType = EmployeeType.ACADEMIC_STAFF_EMPLOYEE; + employeeNode = solution.get(QueryFieldLabels.ACADEMIC_STAFF_EMPLOYEE_URL); + } + + if (employeeURLToVO.containsKey(employeeNode.toString())) { + currentEmployee = employeeURLToVO.get(employeeNode.toString()); + currentEmployee.addParentDepartment(currentDepartment); + } else { + currentEmployee = new VivoEmployee(employeeNode.toString(), currentEmployeeType, currentDepartment); + RDFNode authorLabelNode = solution.get(QueryFieldLabels.AUTHOR_LABEL); + if (authorLabelNode != null) { + currentEmployee.setIndividualLabel(authorLabelNode.toString()); + } + employeeURLToVO.put(employeeNode.toString(), currentEmployee); + } + + RDFNode documentNode = solution.get(QueryFieldLabels.DOCUMENT_URL); + if (documentNode != null) { + + /* + * A document can have multiple authors but if the same author serves in multiple departments + * then we need to account for "An Authored Document" only once. This check will make sure that + * a document by same author is not added twice just because that author serves in 2 distinct + * department. + * */ + boolean isNewDocumentAlreadyAdded = testForDuplicateEntryOfDocument( + currentEmployee, + documentNode); + + if (!isNewDocumentAlreadyAdded) { + currentEmployee.addAuthorDocument(createAuthorDocumentsVO(solution, documentNode.toString())); + } + + } + + collegeAcademicEmployees.add(currentEmployee); + } + + +/* System.out.println(collegeURLToVO); + System.out.println("------------------------------------------------------------"); + System.out.println(departmentURLToVO); + System.out.println("------------------------------------------------------------"); + System.out.println(employeeURLToVO); + System.out.println("------------------------------------------------------------"); +*/ + return collegeAcademicEmployees; + } + + private boolean testForDuplicateEntryOfDocument( + VivoEmployee currentEmployee, RDFNode documentNode) { + boolean isNewDocumentAlreadyAdded = false; + + for (BiboDocument currentAuthoredDocument : currentEmployee.getAuthorDocuments()) { + if (currentAuthoredDocument.getDocumentURL().equalsIgnoreCase(documentNode.toString())) { + isNewDocumentAlreadyAdded = true; + break; + } + } + return isNewDocumentAlreadyAdded; + } + + public Map getCollegeURLToVO() { + return collegeURLToVO; + } + + private BiboDocument createAuthorDocumentsVO(QuerySolution solution, String documentURI) { + + BiboDocument biboDocument = new BiboDocument(documentURI); + + RDFNode documentLabelNode = solution.get(QueryFieldLabels.DOCUMENT_LABEL); + if (documentLabelNode != null) { + biboDocument.setDocumentLabel(documentLabelNode.toString()); + } + + RDFNode documentBlurbNode = solution.get(QueryFieldLabels.DOCUMENT_BLURB); + if (documentBlurbNode != null) { + biboDocument.setDocumentBlurb(documentBlurbNode.toString()); + } + + RDFNode documentMonikerNode = solution.get(QueryFieldLabels.DOCUMENT_MONIKER); + if (documentMonikerNode != null) { + biboDocument.setDocumentMoniker(documentMonikerNode.toString()); + } + + RDFNode documentDescriptionNode = solution.get(QueryFieldLabels.DOCUMENT_DESCRIPTION); + if (documentDescriptionNode != null) { + biboDocument.setDocumentDescription(documentDescriptionNode.toString()); + } + + RDFNode publicationYearNode = solution.get(QueryFieldLabels.DOCUMENT_PUBLICATION_YEAR); + if (publicationYearNode != null) { + biboDocument.setPublicationYear(publicationYearNode.toString()); + } + + return biboDocument; + } + + private ResultSet executeQuery(String queryText, + String resultFormatParam, + String rdfResultFormatParam, + DataSource dataSource) { + + QueryExecution queryExecution = null; + try{ + Query query = QueryFactory.create(queryText, SYNTAX); + +// QuerySolutionMap qs = new QuerySolutionMap(); +// qs.add("authPerson", queryParam); // bind resource to s + + queryExecution = QueryExecutionFactory.create(query, dataSource); + + + //remocve this if loop after knowing what is describe & construct sparql stuff. + if (query.isSelectType()){ + return queryExecution.execSelect(); + } + } finally { + if(queryExecution != null) { + queryExecution.close(); + } + + } + return null; + } + + private String generateCollegeEmployeeSparqlQuery(String queryURI) { +// Resource uri1 = ResourceFactory.createResource(queryURI); + + String sparqlQuery = QueryConstants.getSparqlPrefixQuery() + + "SELECT (str(?collegeLabel) as ?" + QueryFieldLabels.COLLEGE_LABEL + ") " + + " (str(?department) as ?" + QueryFieldLabels.DEPARTMENT_URL + ") " + + " (str(?departmentLabel) as ?" + QueryFieldLabels.DEPARTMENT_LABEL + ") " + + " (str(?academicFacultyEmployee) as ?" + QueryFieldLabels.ACADEMIC_FACULTY_EMPLOYEE_URL + ") " + + " (str(?academicStaffEmployee) as ?" + QueryFieldLabels.ACADEMIC_STAFF_EMPLOYEE_URL + ") " + + " (str(<" + queryURI + ">) as ?" + QueryFieldLabels.COLLEGE_URL + ") " + + " (str(?authorLabel) as ?" + QueryFieldLabels.AUTHOR_LABEL + ") " + + " (str(?document) as ?" + QueryFieldLabels.DOCUMENT_URL + ") " + + " (str(?documentMoniker) as ?" + QueryFieldLabels.DOCUMENT_MONIKER + ") " + + " (str(?documentLabel) as ?" + QueryFieldLabels.DOCUMENT_LABEL + ") " + + " (str(?documentBlurb) as ?" + QueryFieldLabels.DOCUMENT_BLURB + ") " + + " (str(?documentDescription) as ?" + QueryFieldLabels.DOCUMENT_DESCRIPTION + ") " + + " (str(?publicationYear) as ?" + QueryFieldLabels.DOCUMENT_PUBLICATION_YEAR + ") " + + "WHERE { " + + "<" + queryURI + "> rdf:type vivo:CollegeOrSchoolWithinUniversity; " + + "rdfs:label ?collegeLabel; " + + "vivo:hasAcademicDepartmentOrDivision ?department . " + + "?department rdfs:label ?departmentLabel ." + + "{ " + + getAcademicEmployeePublicationsSparqlQuery("academicFacultyEmployee", "vivo:hasEmployeeAcademicFacultyMember") + + " UNION " + + getAcademicEmployeePublicationsSparqlQuery("academicStaffEmployee", "vivo:hasEmployeeAcademicStaffMember") + + "}" + + "}"; + + System.out.println(sparqlQuery); + + return sparqlQuery; + } + + + private String getAcademicEmployeePublicationsSparqlQuery(String employeeHandle, + String ontologyHandle) { + + String sparqlQuery = " {?department " + ontologyHandle + " ?" + employeeHandle + " . " + + "?" + employeeHandle + " rdf:type foaf:Person; rdfs:label ?authorLabel. " + + "OPTIONAL { ?" + employeeHandle + " vivo:authorOf ?document ." + + " ?document rdf:type bibo:Document ." + + " ?document rdfs:label ?documentLabel ." + + " OPTIONAL { ?document vitro:moniker ?documentMoniker } ." + + " OPTIONAL { ?document vitro:blurb ?documentBlurb } ." + + " OPTIONAL { ?document vitro:description ?documentDescription } ." + + " OPTIONAL { ?document vivo:publicationYear ?publicationYear } ." + + "}" + + "} "; + + return sparqlQuery; + + } + + public Set getVisualizationJavaValueObjects() + throws MalformedQueryParametersException { + + if (this.collegeURIParam == null || "".equals(collegeURIParam)) { + throw new MalformedQueryParametersException("URI parameter is either null or empty."); + } else { + + /* + * To test for the validity of the URI submitted. + * */ + IRIFactory iRIFactory = IRIFactory.jenaImplementation(); + IRI iri = iRIFactory.create(this.collegeURIParam); + if (iri.hasViolation(false)) { + String errorMsg = ((Violation)iri.violations(false).next()).getShortMessage()+" "; + log.error("Pub Count Vis Query " + errorMsg); + throw new MalformedQueryParametersException("URI provided for an individual is malformed."); + } + } + + ResultSet resultSet = executeQuery(generateCollegeEmployeeSparqlQuery(this.collegeURIParam), + this.resultFormatParam, + this.rdfResultFormatParam, + this.dataSource); + + return createJavaValueObjects(resultSet); + } + + public Map getYearToPublicationCount( + Set authorDocuments) { + + /* + * Create a map from the year to number of publications. Use the BiboDocument's + * parsedPublicationYear to populate the data. + * */ + Map yearToPublicationCount = new TreeMap(); + + for (BiboDocument curr : authorDocuments) { + + /* + * Increment the count because there is an entry already available for + * that particular year. + * */ + String publicationYear; + if (curr.getPublicationYear() != null + && curr.getPublicationYear().length() != 0 + && curr.getPublicationYear().trim().length() != 0) { + publicationYear = curr.getPublicationYear(); + } else { + publicationYear = curr.getParsedPublicationYear(); + } + + if (yearToPublicationCount.containsKey(publicationYear)) { + yearToPublicationCount.put(publicationYear, + yearToPublicationCount + .get(publicationYear) + 1); + + } else { + yearToPublicationCount.put(publicationYear, 1); + } + + } + +// System.out.println("****************************\n" + yearToPublicationCount); + return yearToPublicationCount; + } + + + + + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/collegepubcount/VisualizationRequestHandler.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/collegepubcount/VisualizationRequestHandler.java new file mode 100644 index 000000000..f716ba749 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/collegepubcount/VisualizationRequestHandler.java @@ -0,0 +1,457 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.collegepubcount; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.Map.Entry; + +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.logging.Log; +import org.skife.csv.CSVWriter; +import org.skife.csv.SimpleWriter; + +import com.hp.hpl.jena.query.DataSource; +import com.itextpdf.text.Document; +import com.itextpdf.text.DocumentException; +import com.itextpdf.text.pdf.PdfWriter; + +import edu.cornell.mannlib.vitro.webapp.beans.Portal; +import edu.cornell.mannlib.vitro.webapp.controller.Controllers; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.controller.visualization.VisualizationFrameworkConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.PDFDocument; +import edu.cornell.mannlib.vitro.webapp.visualization.constants.VOConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.constants.VisConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.exceptions.MalformedQueryParametersException; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.BiboDocument; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Individual; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.VivoCollegeOrSchool; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.VivoDepartmentOrDivision; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.VivoEmployee; +import edu.cornell.mannlib.vitro.webapp.visualization.visutils.UtilityFunctions; + +public class VisualizationRequestHandler { + + private VitroRequest vitroRequest; + private HttpServletRequest request; + private HttpServletResponse response; + private Log log; + + + + public VisualizationRequestHandler(VitroRequest vitroRequest, + HttpServletRequest request, HttpServletResponse response, Log log) { + + this.vitroRequest = vitroRequest; + this.request = request; + this.response = response; + this.log = log; + + } + + public void generateVisualization(DataSource dataSource) { + + String resultFormatParam = "RS_TEXT"; + String rdfResultFormatParam = "RDF/XML-ABBREV"; + + String collegeURIParam = vitroRequest.getParameter(VisualizationFrameworkConstants.INDIVIDUAL_URI_URL_HANDLE); + + String renderMode = vitroRequest.getParameter(VisualizationFrameworkConstants.RENDER_MODE_URL_HANDLE); + + String visMode = vitroRequest.getParameter(VisualizationFrameworkConstants.VIS_MODE_URL_HANDLE); + + String visContainer = vitroRequest.getParameter(VisualizationFrameworkConstants.VIS_CONTAINER_URL_HANDLE); + + QueryHandler queryManager = + new QueryHandler(collegeURIParam, + resultFormatParam, + rdfResultFormatParam, + dataSource, + log); + + try { + + Set employees = queryManager.getVisualizationJavaValueObjects(); + + Map> departmentToPublicationsOverTime = + new HashMap>(); + + Set publishedYearsForCollege = new HashSet(); + + for (VivoEmployee currentEmployee : employees) { + + Map currentEmployeeYearToPublicationCount = + queryManager.getYearToPublicationCount(currentEmployee.getAuthorDocuments()); + + if (currentEmployeeYearToPublicationCount.size() > 0) { + + + publishedYearsForCollege.addAll(currentEmployeeYearToPublicationCount.keySet()); + + for (VivoDepartmentOrDivision currentDepartment : currentEmployee.getParentDepartments()) { + + departmentToPublicationsOverTime.put(currentDepartment, + getUpdatedDepartmentPublicationsOverTime( + currentEmployeeYearToPublicationCount, + departmentToPublicationsOverTime + .get(currentDepartment))); + + } + + } + } + + + /* + * In order to avoid unneeded computations we have pushed this "if" condition up. + * This case arises when the render mode is data. In that case we dont want to generate + * HTML code to render sparkline, tables etc. Ideally I would want to avoid this flow. + * It is ugly! + * */ + if (VisualizationFrameworkConstants.DATA_RENDER_MODE_URL_VALUE.equalsIgnoreCase(renderMode)) { + prepareVisualizationQueryDataResponse( + departmentToPublicationsOverTime, + queryManager.getCollegeURLToVO()); + + log.debug(publishedYearsForCollege); + return; + } + + + + /* + if (PDF_RENDER_MODE_URL_VALUE.equalsIgnoreCase(renderMode)) { + prepareVisualizationQueryPDFResponse(authorDocuments, + yearToPublicationCount); + return; + } + */ + + /* + * Computations required to generate HTML for the sparklines & related context. + * */ + + /* + * This is required because when deciding the range of years over which the vis + * was rendered we dont want to be influenced by the "DEFAULT_PUBLICATION_YEAR". + * */ + publishedYearsForCollege.remove(VOConstants.DEFAULT_PUBLICATION_YEAR); + + /* + VisualizationCodeGenerator visualizationCodeGenerator = + new VisualizationCodeGenerator(yearToPublicationCount, log); + + String visContentCode = visualizationCodeGenerator + .getMainVisualizationCode(authorDocuments, + publishedYears, + visMode, + visContainer); + + String visContextCode = visualizationCodeGenerator + .getVisualizationContextCode(vitroRequest.getRequestURI(), + collegeURIParam, + visMode); + */ + + /* + * This is side-effecting because the response of this method is just to redirect to + * a page with visualization on it. + * */ + + /* + RequestDispatcher requestDispatcher = null; + + if (DYNAMIC_RENDER_MODE_URL_VALUE.equalsIgnoreCase(renderMode)) { + + prepareVisualizationQueryDynamicResponse(request, response, vitroRequest, + visContentCode, visContextCode); + requestDispatcher = request.getRequestDispatcher("/templates/page/blankPage.jsp"); + + } else { + prepareVisualizationQueryStandaloneResponse(request, response, vitroRequest, + visContentCode, visContextCode); + + requestDispatcher = request.getRequestDispatcher(Controllers.BASIC_JSP); + } + + try { + requestDispatcher.forward(request, response); + } catch (Exception e) { + log.error("EntityEditController could not forward to view."); + log.error(e.getMessage()); + log.error(e.getStackTrace()); + } + +*/ + } catch (MalformedQueryParametersException e) { + try { + handleMalformedParameters(e.getMessage()); + } catch (ServletException e1) { + log.error(e1.getStackTrace()); + } catch (IOException e1) { + log.error(e1.getStackTrace()); + } + return; + } + + } + + private Map getUpdatedDepartmentPublicationsOverTime( + Map currentEmployeeYearToPublicationCount, + Map currentDepartmentYearToPublicationCount) { + + Map departmentYearToPublicationCount; + +// System.out.println("inside get updated dept pub obr time"); + + /* + * In case this is the first time we are consolidating publication counts over time for a department. + * */ + if (currentDepartmentYearToPublicationCount == null) { + departmentYearToPublicationCount = new TreeMap(); + +// System.out.println("new dept yr pub cnt"); + + } else { + departmentYearToPublicationCount = currentDepartmentYearToPublicationCount; + } + + + Iterator employeePubCountIterator = currentEmployeeYearToPublicationCount.entrySet().iterator(); + + while (employeePubCountIterator.hasNext()) { + Map.Entry employeePubCountEntry = (Map.Entry) employeePubCountIterator.next(); + + String employeePublicationYear = employeePubCountEntry.getKey(); + Integer employeePublicationCount = employeePubCountEntry.getValue(); + + try { + if (departmentYearToPublicationCount.containsKey(employeePublicationYear)) { + departmentYearToPublicationCount.put(employeePublicationYear, + departmentYearToPublicationCount + .get(employeePublicationYear) + + employeePublicationCount); + + } else { + departmentYearToPublicationCount.put(employeePublicationYear, employeePublicationCount); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + return departmentYearToPublicationCount; + } + + private void prepareVisualizationQueryPDFResponse(Individual college, + List authorDocuments, + Map yearToPublicationCount) { + + String authorName = null; + + /* + * To protect against cases where there are no author documents associated with the + * individual. + * */ + if (authorDocuments.size() > 0) { + authorName = college.getIndividualLabel(); + } + + /* + * To make sure that null/empty records for author names do not cause any mischief. + * */ + if (authorName == null) { + authorName = ""; + } + + String outputFileName = UtilityFunctions.slugify(authorName + "-report") + + ".pdf"; + + response.setContentType("application/pdf"); + response.setHeader("Content-Disposition","attachment;filename=" + outputFileName); + + ServletOutputStream responseOutputStream; + try { + responseOutputStream = response.getOutputStream(); + + + Document document = new Document(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PdfWriter pdfWriter = PdfWriter.getInstance(document, baos); + document.open(); + + PDFDocument pdfDocument = new PDFDocument(authorName, + yearToPublicationCount, + document, + pdfWriter); + document.close(); + + response.setHeader("Expires", "0"); + response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0"); + response.setHeader("Pragma", "public"); + response.setContentLength(baos.size()); + + baos.writeTo(responseOutputStream); + responseOutputStream.flush(); + responseOutputStream.close(); + + } catch (IOException e) { + e.printStackTrace(); + } catch (DocumentException e) { + e.printStackTrace(); + } + } + + private void prepareVisualizationQueryDataResponse( + Map> departmentToPublicationsOverTime, + Map collegeURLToVO) { + + String collegeName = null; + + /* + * To protect against cases where there are no author documents associated with the + * individual. + * */ +// System.out.println(collegeURLToVO); + if (collegeURLToVO.size() > 0) { + collegeName = ((VivoCollegeOrSchool) collegeURLToVO.values().iterator().next()).getCollegeLabel(); + } + + /* + * To make sure that null/empty records for author names do not cause any mischief. + * */ + if (collegeName == null) { + collegeName = ""; + } + + String outputFileName = UtilityFunctions.slugify(collegeName) + "depts-pub-count" + ".csv"; + + response.setContentType("application/octet-stream"); + response.setHeader("Content-Disposition","attachment;filename=" + outputFileName); + + try { + + PrintWriter responseWriter = response.getWriter(); + + /* + * We are side-effecting responseWriter since we are directly manipulating the response + * object of the servlet. + * */ + generateCsvFileBuffer(departmentToPublicationsOverTime, + collegeURLToVO, + responseWriter); + + responseWriter.close(); + + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void generateCsvFileBuffer( + Map> departmentToPublicationsOverTime, + Map collegeURLToVO, PrintWriter printWriter) { + + CSVWriter csvWriter = new SimpleWriter(printWriter); + + try { + csvWriter.append(new String[]{"School", "Department", "Year", "Publications"}); + + Iterator collegeIterator = collegeURLToVO.values().iterator(); + + while (collegeIterator.hasNext()) { + VivoCollegeOrSchool college = collegeIterator.next(); + String collegeLabel = college.getCollegeLabel(); + for (VivoDepartmentOrDivision currentDepartment : college.getDepartments()) { + + Map currentDepartmentPublicationsOverTime = departmentToPublicationsOverTime.get(currentDepartment); + + /* + * This because many departments might not have any publication. + * */ + if (currentDepartmentPublicationsOverTime != null) { + + for (Entry currentEntry : currentDepartmentPublicationsOverTime.entrySet()) { + csvWriter.append(new Object[]{collegeLabel, + currentDepartment.getDepartmentLabel(), + currentEntry.getKey(), + currentEntry.getValue()}); + } + + } + + } + } + + } catch (IOException e) { + e.printStackTrace(); + } + + printWriter.flush(); + + } + + private void prepareVisualizationQueryStandaloneResponse(HttpServletRequest request, + HttpServletResponse response, VitroRequest vreq, + String visContentCode, String visContextCode) { + + Portal portal = vreq.getPortal(); + + request.setAttribute("visContentCode", visContentCode); + request.setAttribute("visContextCode", visContextCode); + + request.setAttribute("bodyJsp", "/templates/visualization/publication_count.jsp"); + request.setAttribute("portalBean", portal); + request.setAttribute("title", "Individual Publication Count Visualization"); + request.setAttribute("scripts", "/templates/visualization/visualization_scripts.jsp"); + + } + + private void prepareVisualizationQueryDynamicResponse(HttpServletRequest request, + HttpServletResponse response, VitroRequest vreq, + String visContentCode, String visContextCode) { + + Portal portal = vreq.getPortal(); + + request.setAttribute("visContentCode", visContentCode); + request.setAttribute("visContextCode", visContextCode); + + request.setAttribute("portalBean", portal); + request.setAttribute("bodyJsp", "/templates/visualization/ajax_vis_content.jsp"); + + } + + private void handleMalformedParameters(String errorMessage) + throws ServletException, IOException { + + Portal portal = vitroRequest.getPortal(); + + request.setAttribute("error", errorMessage); + + RequestDispatcher requestDispatcher = request.getRequestDispatcher(Controllers.BASIC_JSP); + request.setAttribute("bodyJsp", "/templates/visualization/visualization_error.jsp"); + request.setAttribute("portalBean", portal); + request.setAttribute("title", "Visualization Query Error - Individual Publication Count"); + + try { + requestDispatcher.forward(request, response); + } catch (Exception e) { + log.error("EntityEditController could not forward to view."); + log.error(e.getMessage()); + log.error(e.getStackTrace()); + } + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/constants/QueryConstants.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/constants/QueryConstants.java new file mode 100644 index 000000000..6e1b5249d --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/constants/QueryConstants.java @@ -0,0 +1,59 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.constants; + +import java.util.HashMap; +import java.util.Map; + +public class QueryConstants { + + public static final Map PREFIX_TO_NAMESPACE = new HashMap() {{ + + put("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#"); + put("rdfs", "http://www.w3.org/2000/01/rdf-schema#"); + put("xsd", "http://www.w3.org/2001/XMLSchema#"); + put("owl", "http://www.w3.org/2002/07/owl#"); + put("swrl", "http://www.w3.org/2003/11/swrl#"); + put("swrlb", "http://www.w3.org/2003/11/swrlb#"); + put("vitro", "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#"); + put("far", "http://vitro.mannlib.cornell.edu/ns/reporting#"); + put("ai", "http://vitro.mannlib.cornell.edu/ns/hotel#"); + put("aktp", "http://www.aktors.org/ontology/portal#"); + put("akts", "http://www.aktors.org/ontology/support#"); + put("bibo", "http://purl.org/ontology/bibo/"); + put("hr", "http://vivo.cornell.edu/ns/hr/0.9/hr.owl#"); + put("dcterms", "http://purl.org/dc/terms/"); + put("dcelem", "http://purl.org/dc/elements/1.1/"); + put("event", "http://purl.org/NET/c4dm/event.owl#"); + put("foaf", "http://xmlns.com/foaf/0.1/"); + put("geo", "http://aims.fao.org/aos/geopolitical.owl#"); + put("mann", "http://vivo.cornell.edu/ns/mannadditions/0.1#"); + put("pubmed", "http://vitro.mannlib.cornell.edu/ns/pubmed#"); + put("rdfs", "http://www.w3.org/2000/01/rdf-schema#"); + put("rdfsyn", "http://www.w3.org/1999/02/22-rdf-syntax-ns#"); + put("skos", "http://www.w3.org/2004/02/skos/core#"); + put("socsci", "http://vivo.library.cornell.edu/ns/vivo/socsci/0.1#"); + put("stars", "http://vitro.mannlib.cornell.edu/ns/cornell/stars/classes#"); + put("temp", "http://vitro.mannlib.cornell.edu/ns/temp#"); + put("wos", "http://vivo.mannlib.cornell.edu/ns/ThomsonWOS/0.1#"); + put("core", "http://vivoweb.org/ontology/core#"); + put("vivo", "http://vivo.library.cornell.edu/ns/0.1#"); + + }}; + + + public static String getSparqlPrefixQuery() { + + StringBuilder prefixSection = new StringBuilder(); + + for (Map.Entry prefixEntry : PREFIX_TO_NAMESPACE.entrySet()) { + prefixSection.append("PREFIX " + prefixEntry.getKey() + ": <" + prefixEntry.getValue() + ">\n"); + } + + + return prefixSection.toString(); + + } + + +} + + diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/constants/QueryFieldLabels.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/constants/QueryFieldLabels.java new file mode 100644 index 000000000..01749d70a --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/constants/QueryFieldLabels.java @@ -0,0 +1,53 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.constants; + +public class QueryFieldLabels { + + /* + * Generic Query related field labels + * */ + public static final String PREDICATE = "predicateLit"; + public static final String OBJECT = "objectLit"; + + + /* + * Document related field labels + * */ + public static final String DOCUMENT_URL = "documentLit"; + public static final String DOCUMENT_MONIKER = "documentMonikerLit"; + public static final String DOCUMENT_LABEL = "documentLabelLit"; + public static final String DOCUMENT_BLURB = "documentBlurbLit"; + public static final String DOCUMENT_DESCRIPTION = "documentDescriptionLit"; + public static final String DOCUMENT_PUBLICATION_YEAR = "publicationYearLit"; + + + /* + * Author related field labels + * */ + public static final String AUTHOR_URL = "authPersonLit"; + public static final String AUTHOR_LABEL = "authorLabelLit"; + + /* + * Co-Author related field labels + * */ + public static final String CO_AUTHOR_URL = "coAuthPersonLit"; + public static final String CO_AUTHOR_LABEL = "coAuthPersonLabelLit"; + + /* + * College related field labels + * */ + public static final String COLLEGE_URL = "collegeLit"; + public static final String COLLEGE_LABEL = "collegeLabelLit"; + + /* + * Department related field labels + * */ + public static final String DEPARTMENT_URL = "departmentLit"; + public static final String DEPARTMENT_LABEL = "departmentLabelLit"; + + /* + * Employee related field labels + * */ + public static final String ACADEMIC_FACULTY_EMPLOYEE_URL = "academicFacultyEmployeeLit"; + public static final String ACADEMIC_STAFF_EMPLOYEE_URL = "academicStaffEmployeeLit"; + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/constants/VOConstants.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/constants/VOConstants.java new file mode 100644 index 000000000..5652c3ce0 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/constants/VOConstants.java @@ -0,0 +1,16 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.constants; + +public class VOConstants { + + public static final String DEFAULT_PUBLICATION_YEAR = "Unknown"; + + /* + * Employee related constants + * */ + public static enum EmployeeType { + ACADEMIC_FACULTY_EMPLOYEE, ACADEMIC_STAFF_EMPLOYEE + } + + + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/constants/VisConstants.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/constants/VisConstants.java new file mode 100644 index 000000000..6d36b1e9b --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/constants/VisConstants.java @@ -0,0 +1,8 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.constants; + +public class VisConstants { + + public static final int MAX_NAME_TEXT_LENGTH = 10; + + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/exceptions/DocumentFieldNotFoundException.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/exceptions/DocumentFieldNotFoundException.java new file mode 100644 index 000000000..63a6a512a --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/exceptions/DocumentFieldNotFoundException.java @@ -0,0 +1,19 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.exceptions; + +public class DocumentFieldNotFoundException extends Exception { + + private static final long serialVersionUID = 1L; + + public DocumentFieldNotFoundException(String message) { + super(message); + } + + public DocumentFieldNotFoundException(Exception cause) { + super(createMessage(cause), cause); + } + + private static String createMessage(Exception cause) { + return "Document Field is empty " + cause.getMessage(); + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/exceptions/MalformedQueryParametersException.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/exceptions/MalformedQueryParametersException.java new file mode 100644 index 000000000..8db7efb59 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/exceptions/MalformedQueryParametersException.java @@ -0,0 +1,19 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.exceptions; + +public class MalformedQueryParametersException extends Exception { + + private static final long serialVersionUID = 1L; + + public MalformedQueryParametersException(String message) { + super(message); + } + + public MalformedQueryParametersException(Exception cause) { + super(createMessage(cause), cause); + } + + private static String createMessage(Exception cause) { + return "Malformed Query Params " + cause.getMessage(); + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/personlevel/VisualizationRequestHandler.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/personlevel/VisualizationRequestHandler.java new file mode 100644 index 000000000..49d4a3213 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/personlevel/VisualizationRequestHandler.java @@ -0,0 +1,423 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.personlevel; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.Map.Entry; + +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +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.Controllers; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.controller.visualization.VisualizationFrameworkConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.coauthorship.CoAuthorshipGraphMLWriter; +import edu.cornell.mannlib.vitro.webapp.visualization.coauthorship.VisVOContainer; +import edu.cornell.mannlib.vitro.webapp.visualization.exceptions.MalformedQueryParametersException; +import edu.cornell.mannlib.vitro.webapp.visualization.personpubcount.VisualizationCodeGenerator; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.BiboDocument; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Node; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.SparklineVOContainer; +import edu.cornell.mannlib.vitro.webapp.visualization.visutils.UtilityFunctions; + +public class VisualizationRequestHandler { + + private VitroRequest vitroRequest; + private HttpServletRequest request; + private HttpServletResponse response; + private Log log; + + public VisualizationRequestHandler(VitroRequest vitroRequest, + HttpServletRequest request, HttpServletResponse response, Log log) { + + this.vitroRequest = vitroRequest; + this.request = request; + this.response = response; + this.log = log; + + } + + public void generateVisualization(DataSource dataSource) { + + String resultFormatParam = "RS_TEXT"; + String rdfResultFormatParam = "RDF/XML-ABBREV"; + + String egoURIParam = vitroRequest.getParameter(VisualizationFrameworkConstants.INDIVIDUAL_URI_URL_HANDLE); + + String renderMode = vitroRequest.getParameter(VisualizationFrameworkConstants.RENDER_MODE_URL_HANDLE); + + String visMode = vitroRequest.getParameter(VisualizationFrameworkConstants.VIS_MODE_URL_HANDLE); + + String coAuthorsListMode = "coauthors"; + + String egoPubSparklineVisContainerID = "ego_pub_sparkline"; + String uniqueCoauthorsSparklineVisContainerID = "unique_coauthors_sparkline"; + + edu.cornell.mannlib.vitro.webapp.visualization.coauthorship.QueryHandler coAuthorshipQueryManager = + new edu.cornell.mannlib.vitro.webapp.visualization.coauthorship.QueryHandler(egoURIParam, + resultFormatParam, + rdfResultFormatParam, + dataSource, + log); + + edu.cornell.mannlib.vitro.webapp.visualization.personpubcount.QueryHandler publicationQueryManager = + new edu.cornell.mannlib.vitro.webapp.visualization.personpubcount.QueryHandler(egoURIParam, + resultFormatParam, + rdfResultFormatParam, + dataSource, + log); + + try { + + edu.cornell.mannlib.vitro.webapp.visualization.coauthorship.VisVOContainer coAuthorshipVO = + coAuthorshipQueryManager.getVisualizationJavaValueObjects(); + + /* + * In order to avoid unneeded computations we have pushed this "if" condition up. + * This case arises when the render mode is data. In that case we dont want to generate + * HTML code to render sparkline, tables etc. Ideally I would want to avoid this flow. + * It is ugly! + * */ + if (VisualizationFrameworkConstants.DATA_RENDER_MODE_URL_VALUE.equalsIgnoreCase(renderMode)) { + + /* + * We will be using the same visualization package for providing data for both + * list of unique coauthors & network of coauthors (used in the flash vis). We will + * use "VIS_MODE_URL_HANDLE" as a modifier to differentiate between these two. + * The defualt will be to provide data used to render the coauthorship network vis. + * */ + + if (coAuthorsListMode.equalsIgnoreCase(visMode)) { + /* + * When the csv file is required - containing the unique co-authors vs how many times + * they have co-authored with the ego. + * */ + prepareVisualizationQueryListCoauthorsDataResponse(coAuthorshipVO); + return; + + } else { + /* + * When the graphML file is required - based on which coauthorship network visualization + * will be rendered. + * */ + prepareVisualizationQueryNetworkDataResponse(coAuthorshipVO); + return; + } + + + } + + List authorDocuments = publicationQueryManager.getVisualizationJavaValueObjects(); + + /* + * Create a map from the year to number of publications. Use the BiboDocument's + * parsedPublicationYear to populate the data. + * */ + Map yearToPublicationCount = publicationQueryManager + .getYearToPublicationCount(authorDocuments); + + Map yearToUniqueCoauthorCount = getUniqueCoauthorsCountPerYear(coAuthorshipVO); + + + /* + * Computations required to generate HTML for the sparklines & related context. + * */ + + SparklineVOContainer publicationSparklineVO = new SparklineVOContainer(); + SparklineVOContainer uniqueCoauthorsSparklineVO = new SparklineVOContainer(); + + edu.cornell.mannlib.vitro.webapp.visualization.personpubcount.VisualizationCodeGenerator personPubCountVisCodeGenerator = + new edu.cornell.mannlib.vitro.webapp.visualization.personpubcount.VisualizationCodeGenerator( + vitroRequest.getRequestURI(), + egoURIParam, + VisualizationCodeGenerator.FULL_SPARKLINE_MODE_URL_HANDLE, + egoPubSparklineVisContainerID, + authorDocuments, + yearToPublicationCount, + publicationSparklineVO, + log); + + edu.cornell.mannlib.vitro.webapp.visualization.coauthorship.VisualizationCodeGenerator uniqueCoauthorsVisCodeGenerator = + new edu.cornell.mannlib.vitro.webapp.visualization.coauthorship.VisualizationCodeGenerator( + vitroRequest.getRequestURI(), + egoURIParam, + VisualizationCodeGenerator.FULL_SPARKLINE_MODE_URL_HANDLE, + uniqueCoauthorsSparklineVisContainerID, + yearToUniqueCoauthorCount, + uniqueCoauthorsSparklineVO, + log); + + + RequestDispatcher requestDispatcher = null; + + prepareVisualizationQueryStandaloneResponse(egoURIParam, + publicationSparklineVO, + uniqueCoauthorsSparklineVO, + coAuthorshipVO, + egoPubSparklineVisContainerID, + uniqueCoauthorsSparklineVisContainerID, + request, + response, + vitroRequest); + +// requestDispatcher = request.getRequestDispatcher("/templates/page/blankPage.jsp"); + requestDispatcher = request.getRequestDispatcher(Controllers.BASIC_JSP); + + try { + requestDispatcher.forward(request, response); + } catch (Exception e) { + log.error("EntityEditController could not forward to view."); + log.error(e.getMessage()); + log.error(e.getStackTrace()); + } + + } catch (MalformedQueryParametersException e) { + try { + handleMalformedParameters(e.getMessage()); + } catch (ServletException e1) { + log.error(e1.getStackTrace()); + } catch (IOException e1) { + log.error(e1.getStackTrace()); + } + return; + } + + } + + private Map getUniqueCoauthorsCountPerYear( + edu.cornell.mannlib.vitro.webapp.visualization.coauthorship.VisVOContainer coAuthorshipVO) { + Map yearToUniqueCoauthorCount = new TreeMap(); + + Map> yearToUniqueCoauthors = getUniqueCoAuthorsPerYear(coAuthorshipVO); + + for (Entry> currentEntry : yearToUniqueCoauthors.entrySet()) { + + yearToUniqueCoauthorCount.put(currentEntry.getKey(), currentEntry.getValue().size()); + + } + return yearToUniqueCoauthorCount; + } + + private Map> getUniqueCoAuthorsPerYear(edu.cornell.mannlib.vitro.webapp.visualization.coauthorship.VisVOContainer authorNodesAndEdges) { + + Map> yearToCoAuthors = new TreeMap>(); + + Node egoNode = authorNodesAndEdges.getEgoNode(); + + for (Node currNode : authorNodesAndEdges.getNodes()) { + + /* + * We have already printed the Ego Node info. + * */ + if (currNode != egoNode) { + + for (String year : currNode.getYearToPublicationCount().keySet()) { + + Set coAuthorNodes; + + if (yearToCoAuthors.containsKey(year)) { + + coAuthorNodes = yearToCoAuthors.get(year); + coAuthorNodes.add(currNode); + + } else { + + coAuthorNodes = new HashSet(); + coAuthorNodes.add(currNode); + yearToCoAuthors.put(year, coAuthorNodes); + } + + } + + } + } + + + return yearToCoAuthors; + } + + private void prepareVisualizationQueryNetworkDataResponse(VisVOContainer coAuthorsipVO) { + + String outputFileName = ""; + + if (coAuthorsipVO.getNodes() == null || coAuthorsipVO.getNodes().size() < 1) { + + outputFileName = "no-coauthorship-net" + ".csv"; + + } else { + + outputFileName = UtilityFunctions.slugify(coAuthorsipVO.getEgoNode().getNodeName()) + + "-coauthor-net" + ".graphml"; + + } + + + + response.setContentType("application/octet-stream"); + response.setHeader("Content-Disposition", "attachment;filename=" + outputFileName); + + try { + + PrintWriter responseWriter = response.getWriter(); + + /* + * We are side-effecting responseWriter since we are directly manipulating the response + * object of the servlet. + * */ + CoAuthorshipGraphMLWriter coAuthorShipGraphMLWriter = new CoAuthorshipGraphMLWriter(coAuthorsipVO); + + responseWriter.append(coAuthorShipGraphMLWriter.getCoAuthorshipGraphMLContent()); + + responseWriter.close(); + + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void prepareVisualizationQueryListCoauthorsDataResponse(VisVOContainer coAuthorsipVO) { + + String outputFileName = ""; + Map coAuthorsToCount = new TreeMap(); + + if (coAuthorsipVO.getNodes() == null || coAuthorsipVO.getNodes().size() < 1 ) { + + outputFileName = "no-coauthors-list" + ".csv"; + + } else { + + outputFileName = UtilityFunctions.slugify(coAuthorsipVO.getEgoNode().getNodeName()) + + "-coauthors-list" + ".csv"; + + coAuthorsToCount = getCoAuthorsList(coAuthorsipVO); + + } + + response.setContentType("application/octet-stream"); + response.setHeader("Content-Disposition", "attachment;filename=" + outputFileName); + + try { + + PrintWriter responseWriter = response.getWriter(); + + /* + * We are side-effecting responseWriter since we are directly manipulating the response + * object of the servlet. + * */ + generateCsvFileBuffer(coAuthorsToCount, + responseWriter); + + responseWriter.close(); + + } catch (IOException e) { + e.printStackTrace(); + } + } + + + private Map getCoAuthorsList(VisVOContainer coAuthorsipVO) { + + Map coAuthorsToCount = new TreeMap(); + + for (Node currNode : coAuthorsipVO.getNodes()) { + + /* + * We have already printed the Ego Node info. + * */ + if (currNode != coAuthorsipVO.getEgoNode()) { + + coAuthorsToCount.put(currNode.getNodeName(), currNode.getNumOfAuthoredWorks()); + + } + + } + + + return coAuthorsToCount; + } + + private void generateCsvFileBuffer(Map coAuthorsToCount, PrintWriter printWriter) { + + printWriter.append("\"Co-Author\", \"Count\"\n"); + + for (Entry currentEntry : coAuthorsToCount.entrySet()) { + + printWriter.append("\"" + currentEntry.getKey() + "\"," + + "\"" + currentEntry.getValue() + "\"\n" + ); + } + + printWriter.flush(); + } + + + private void prepareVisualizationQueryStandaloneResponse( + String egoURIParam, + SparklineVOContainer egoPubSparklineVO, + SparklineVOContainer uniqueCoauthorsSparklineVO, + VisVOContainer coAuthorshipVO, + String egoPubSparklineVisContainer, + String uniqueCoauthorsSparklineVisContainer, + HttpServletRequest request, + HttpServletResponse response, + VitroRequest vreq) { + + Portal portal = vreq.getPortal(); + + request.setAttribute("egoURIParam", egoURIParam); + + if (coAuthorshipVO.getNodes() != null) { + request.setAttribute("numOfAuthors", coAuthorshipVO.getNodes().size()); + } + + if (coAuthorshipVO.getEdges() != null) { + request.setAttribute("numOfCoAuthorShips", coAuthorshipVO.getEdges().size()); + } + + + request.setAttribute("egoPubSparklineVO", egoPubSparklineVO); + request.setAttribute("uniqueCoauthorsSparklineVO", uniqueCoauthorsSparklineVO); + + request.setAttribute("egoPubSparklineContainerID", egoPubSparklineVisContainer); + request.setAttribute("uniqueCoauthorsSparklineVisContainerID", uniqueCoauthorsSparklineVisContainer); + + request.setAttribute("title", "Person Level Visualization"); + request.setAttribute("portalBean", portal); + request.setAttribute("scripts", "/templates/visualization/person_level_inject_head.jsp"); + + request.setAttribute("bodyJsp", "/templates/visualization/person_level.jsp"); + } + + private void handleMalformedParameters(String errorMessage) + throws ServletException, IOException { + + Portal portal = vitroRequest.getPortal(); + + request.setAttribute("error", errorMessage); + + RequestDispatcher requestDispatcher = request.getRequestDispatcher(Controllers.BASIC_JSP); + request.setAttribute("bodyJsp", "/templates/visualization/visualization_error.jsp"); + request.setAttribute("portalBean", portal); + request.setAttribute("title", "Visualization Query Error - Individual Publication Count"); + + try { + requestDispatcher.forward(request, response); + } catch (Exception e) { + log.error("EntityEditController could not forward to view."); + log.error(e.getMessage()); + log.error(e.getStackTrace()); + } + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/personpubcount/QueryHandler.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/personpubcount/QueryHandler.java new file mode 100644 index 000000000..809cffae5 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/personpubcount/QueryHandler.java @@ -0,0 +1,255 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.personpubcount; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import org.apache.commons.logging.Log; + +import com.hp.hpl.jena.iri.IRI; +import com.hp.hpl.jena.iri.IRIFactory; +import com.hp.hpl.jena.iri.Violation; +import com.hp.hpl.jena.query.DataSource; +import com.hp.hpl.jena.query.Query; +import com.hp.hpl.jena.query.QueryExecution; +import com.hp.hpl.jena.query.QueryExecutionFactory; +import com.hp.hpl.jena.query.QueryFactory; +import com.hp.hpl.jena.query.QuerySolution; +import com.hp.hpl.jena.query.ResultSet; +import com.hp.hpl.jena.query.Syntax; +import com.hp.hpl.jena.rdf.model.RDFNode; + +import edu.cornell.mannlib.vitro.webapp.visualization.constants.QueryConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.constants.QueryFieldLabels; +import edu.cornell.mannlib.vitro.webapp.visualization.exceptions.MalformedQueryParametersException; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.BiboDocument; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Individual; + + + +/** + * Very dumb name of the class. change it. + * @author cdtank + * + */ +public class QueryHandler { + + protected static final Syntax SYNTAX = Syntax.syntaxARQ; + + private String queryParam, resultFormatParam, rdfResultFormatParam; + private DataSource dataSource; + + private Individual author; + + public Individual getAuthor() { + return author; + } + + private Log log; + + private static final String SPARQL_QUERY_COMMON_SELECT_CLAUSE = "" + + "SELECT (str(?authorLabel) as ?authorLabelLit) " + + " (str(?document) as ?documentLit) " + + " (str(?documentMoniker) as ?documentMonikerLit) " + + " (str(?documentLabel) as ?documentLabelLit) " + + " (str(?documentBlurb) as ?documentBlurbLit) " + + " (str(?publicationYear) as ?publicationYearLit) " + + " (str(?documentDescription) as ?documentDescriptionLit) "; + + private static final String SPARQL_QUERY_COMMON_WHERE_CLAUSE = "" + + "?document rdf:type bibo:Document ." + + "?document rdfs:label ?documentLabel ." + + "OPTIONAL { ?document vivo:publicationYear ?publicationYear } ." + + "OPTIONAL { ?document vitro:moniker ?documentMoniker } ." + + "OPTIONAL { ?document vitro:blurb ?documentBlurb } ." + + "OPTIONAL { ?document vitro:description ?documentDescription }"; + + public QueryHandler(String queryParam, + String resultFormatParam, String rdfResultFormatParam, + DataSource dataSource, Log log) { + + this.queryParam = queryParam; + this.resultFormatParam = resultFormatParam; + this.rdfResultFormatParam = rdfResultFormatParam; + this.dataSource = dataSource; + this.log = log; + + } + + private List createJavaValueObjects(ResultSet resultSet) { + List authorDocuments = new ArrayList(); + + while (resultSet.hasNext()) { + QuerySolution solution = resultSet.nextSolution(); + + BiboDocument biboDocument = new BiboDocument( + solution.get(QueryFieldLabels.DOCUMENT_URL) + .toString()); + + RDFNode documentLabelNode = solution.get(QueryFieldLabels.DOCUMENT_LABEL); + if (documentLabelNode != null) { + biboDocument.setDocumentLabel(documentLabelNode.toString()); + } + + + RDFNode documentBlurbNode = solution.get(QueryFieldLabels.DOCUMENT_BLURB); + if (documentBlurbNode != null) { + biboDocument.setDocumentBlurb(documentBlurbNode.toString()); + } + + RDFNode documentmonikerNode = solution.get(QueryFieldLabels.DOCUMENT_MONIKER); + if (documentmonikerNode != null) { + biboDocument.setDocumentMoniker(documentmonikerNode.toString()); + } + + RDFNode documentDescriptionNode = solution.get(QueryFieldLabels.DOCUMENT_DESCRIPTION); + if (documentDescriptionNode != null) { + biboDocument.setDocumentDescription(documentDescriptionNode.toString()); + } + + RDFNode publicationYearNode = solution.get(QueryFieldLabels.DOCUMENT_PUBLICATION_YEAR); + if (publicationYearNode != null) { + biboDocument.setPublicationYear(publicationYearNode.toString()); + } + + /* + * Since we are getting publication count for just one author at a time we need + * to create only one "Individual" instance. We test against the null for "author" to + * make sure that it has not already been instantiated. + * */ + RDFNode authorURLNode = solution.get(QueryFieldLabels.AUTHOR_URL); + if (authorURLNode != null && author == null) { + author = new Individual(authorURLNode.toString()); + RDFNode authorLabelNode = solution.get(QueryFieldLabels.AUTHOR_LABEL); + if (authorLabelNode != null) { + author.setIndividualLabel(authorLabelNode.toString()); + } + + } + + authorDocuments.add(biboDocument); + } + return authorDocuments; + } + + private ResultSet executeQuery(String queryURI, + String resultFormatParam, String rdfResultFormatParam, DataSource dataSource) { + + QueryExecution queryExecution = null; + try{ + Query query = QueryFactory.create(generateSparqlQuery(queryURI), SYNTAX); + +// QuerySolutionMap qs = new QuerySolutionMap(); +// qs.add("authPerson", queryParam); // bind resource to s + + queryExecution = QueryExecutionFactory.create(query, dataSource); + + + //remocve this if loop after knowing what is describe & construct sparql stuff. + if( query.isSelectType() ){ + return queryExecution.execSelect(); + } + } finally { + if(queryExecution != null) { + queryExecution.close(); + } + + } + return null; + } + + private String generateSparqlQuery(String queryURI) { +// Resource uri1 = ResourceFactory.createResource(queryURI); + + String sparqlQuery = QueryConstants.getSparqlPrefixQuery() + + SPARQL_QUERY_COMMON_SELECT_CLAUSE + + "(str(<" + queryURI + ">) as ?authPersonLit) " + + "WHERE { " + + "<" + queryURI + "> rdf:type foaf:Person ; vivo:authorOf ?document ; rdfs:label ?authorLabel. " + + SPARQL_QUERY_COMMON_WHERE_CLAUSE + + "}"; + + log.debug("SPARQL query for person pub count -> \n" + sparqlQuery); + + return sparqlQuery; + } + + public List getVisualizationJavaValueObjects() + throws MalformedQueryParametersException { + + if(this.queryParam == null || "".equals(queryParam)) { + throw new MalformedQueryParametersException("URL parameter is either null or empty."); + } else { + + /* + * To test for the validity of the URI submitted. + * */ + IRIFactory iRIFactory = IRIFactory.jenaImplementation(); + IRI iri = iRIFactory.create(this.queryParam); + if (iri.hasViolation(false)) { + String errorMsg = ((Violation)iri.violations(false).next()).getShortMessage()+" "; + log.error("Pub Count vis Query " + errorMsg); + throw new MalformedQueryParametersException("URI provided for an individual is malformed."); + } + } + + + + ResultSet resultSet = executeQuery(this.queryParam, + this.resultFormatParam, + this.rdfResultFormatParam, + this.dataSource); + + return createJavaValueObjects(resultSet); + } + + public Map getYearToPublicationCount( + List authorDocuments) { + + //List publishedYears = new ArrayList(); + + /* + * Create a map from the year to number of publications. Use the BiboDocument's + * parsedPublicationYear to populate the data. + * */ + Map yearToPublicationCount = new TreeMap(); + + for (BiboDocument curr : authorDocuments) { + + /* + * Increment the count because there is an entry already available for + * that particular year. + * */ + String publicationYear; + if (curr.getPublicationYear() != null + && curr.getPublicationYear().length() != 0 + && curr.getPublicationYear().trim().length() != 0) { + publicationYear = curr.getPublicationYear(); + } else { + publicationYear = curr.getParsedPublicationYear(); + } + + if (yearToPublicationCount.containsKey(publicationYear)) { + yearToPublicationCount.put(publicationYear, + yearToPublicationCount + .get(publicationYear) + 1); + + } else { + yearToPublicationCount.put(publicationYear, 1); + } + +// if (!parsedPublicationYear.equalsIgnoreCase(BiboDocument.DEFAULT_PUBLICATION_YEAR)) { +// publishedYears.add(Integer.parseInt(parsedPublicationYear)); +// } + + } + + return yearToPublicationCount; + } + + + + + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/personpubcount/VisualizationCodeGenerator.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/personpubcount/VisualizationCodeGenerator.java new file mode 100644 index 000000000..22bfcf534 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/personpubcount/VisualizationCodeGenerator.java @@ -0,0 +1,660 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.personpubcount; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +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.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.valueobjects.BiboDocument; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.SparklineVOContainer; + + +public class VisualizationCodeGenerator { + + private final static Map visDivNames = new HashMap() {{ + + put("SHORT_SPARK", "pub_count_short_sparkline_vis"); + put("FULL_SPARK", "pub_count_full_sparkline_vis"); + + }}; + + private static final String visualizationStyleClass = "sparkline_style"; + + private static final String defaultVisContainerDivID = "pub_count_vis_container"; + + public static final String SHORT_SPARKLINE_MODE_URL_HANDLE = "short"; + + public static final String FULL_SPARKLINE_MODE_URL_HANDLE = "full"; + + private Map yearToPublicationCount; + + private Log log; + + private SparklineVOContainer valueObjectContainer; + + private String contextPath; + + private String individualURIParam; + + public VisualizationCodeGenerator(String contextPath, + String individualURIParam, + String visMode, + String visContainer, + List authorDocuments, + Map yearToPublicationCount, + SparklineVOContainer valueObjectContainer, + Log log) { + + this.contextPath = contextPath; + this.individualURIParam = individualURIParam; + + this.yearToPublicationCount = yearToPublicationCount; + this.valueObjectContainer = valueObjectContainer; + + this.log = log; + + + generateVisualizationCode(visMode, + visContainer, + authorDocuments); + + + } + + private void generateVisualizationCode(String visMode, + String visContainer, + List authorDocuments) { + + valueObjectContainer.setSparklineContent(getMainVisualizationCode(authorDocuments, + visMode, + visContainer)); + + + valueObjectContainer.setSparklineContext(getVisualizationContextCode(visMode)); + + } + + private String getMainVisualizationCode(List authorDocuments, + String visMode, + String providedVisContainerID) { + + int numOfYearsToBeRendered = 0; + int currentYear = Calendar.getInstance().get(Calendar.YEAR); + int shortSparkMinYear = currentYear - 10 + 1; + + /* + * This is required because when deciding the range of years over which the vis + * was rendered we dont want to be influenced by the "DEFAULT_PUBLICATION_YEAR". + * */ + Set publishedYears = new HashSet(yearToPublicationCount.keySet()); + publishedYears.remove(VOConstants.DEFAULT_PUBLICATION_YEAR); + + /* + * We are setting the default value of minPublishedYear to be 10 years before + * the current year (which is suitably represented by the shortSparkMinYear), + * this in case we run into invalid set of published years. + * */ + int minPublishedYear = shortSparkMinYear; + + String visContainerID = null; + + StringBuilder visualizationCode = new StringBuilder(); + +// System.out.println(yearToPublicationCount); + if (yearToPublicationCount.size() > 0) { + try { + minPublishedYear = Integer.parseInt(Collections.min(publishedYears)); + System.out.println("min pub year - " + minPublishedYear); + } catch (NoSuchElementException e1) { + log.debug("vis: " + e1.getMessage() + " error occurred for " + yearToPublicationCount.toString()); + } catch (NumberFormatException e2) { + log.debug("vis: " + e2.getMessage() + " error occurred for " + yearToPublicationCount.toString()); + } + } + + int minPubYearConsidered = 0; + + /* + * There might be a case that the author has made his first publication within the + * last 10 years but we want to make sure that the sparkline is representative of + * at least the last 10 years, so we will set the minPubYearConsidered to + * "currentYear - 10" which is also given by "shortSparkMinYear". + * */ + if (minPublishedYear > shortSparkMinYear) { + minPubYearConsidered = shortSparkMinYear; + } else { + minPubYearConsidered = minPublishedYear; + } + + numOfYearsToBeRendered = currentYear - minPubYearConsidered + 1; + + visualizationCode.append("\n"); + +// .sparkline {display:inline; margin:0; padding:0; width:600px } + + + +// td.sparkline-img {margin:0; padding:0; } + + + visualizationCode.append("\n"; + } + + private String getVisualizationContextCode(String visMode) { + + String visualizationContextCode = ""; + if (SHORT_SPARKLINE_MODE_URL_HANDLE.equalsIgnoreCase(visMode)) { + visualizationContextCode = generateShortVisContext(); + } else { + visualizationContextCode = generateFullVisContext(); + } + + + + + + +// System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); + log.debug(visualizationContextCode); +// System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); + + return visualizationContextCode; + } + + private String generateFullVisContext() { + + StringBuilder divContextCode = new StringBuilder(); + + String csvDownloadURLHref = ""; + + if (yearToPublicationCount.size() > 0) { + + try { + if (getCSVDownloadURL() != null) { + + csvDownloadURLHref = "Download data as .csv file.
"; + valueObjectContainer.setDownloadDataLink(getCSVDownloadURL()); + + } else { + + csvDownloadURLHref = ""; + + } + + } catch (UnsupportedEncodingException e) { + csvDownloadURLHref = ""; + } + + + } else { + csvDownloadURLHref = "No data available to export.
"; + } + + String tableCode = generateDataTable(); + + divContextCode.append("

" + tableCode + + csvDownloadURLHref + "

"); + + valueObjectContainer.setTable(tableCode); + + return divContextCode.toString(); + + } + + private String getCSVDownloadURL() + throws UnsupportedEncodingException { + + if (yearToPublicationCount.size() > 0) { + + String secondaryContextPath = ""; + if (!contextPath.contains("/admin/visQuery")) { + secondaryContextPath = "/admin/visQuery"; + } + + + String downloadURL = contextPath + + secondaryContextPath + + "?" + VisualizationFrameworkConstants.INDIVIDUAL_URI_URL_HANDLE + + "=" + URLEncoder.encode(individualURIParam, + VisualizationController.URL_ENCODING_SCHEME).toString() + + "&" + VisualizationFrameworkConstants.VIS_TYPE_URL_HANDLE + + "=" + URLEncoder.encode(VisualizationController + .PERSON_PUBLICATION_COUNT_VIS_URL_VALUE, + VisualizationController.URL_ENCODING_SCHEME).toString() + + "&" + VisualizationFrameworkConstants.RENDER_MODE_URL_HANDLE + + "=" + URLEncoder.encode(VisualizationFrameworkConstants.DATA_RENDER_MODE_URL_VALUE, + VisualizationController.URL_ENCODING_SCHEME).toString(); + System.out.println(" ----- >>>> " + contextPath + " XX " + individualURIParam + " XX " + downloadURL); + return downloadURL; + } else { + return null; + } + + } + + + private String generateShortVisContext() { + + StringBuilder divContextCode = new StringBuilder(); + + try { + + String fullTimelineLink; + if (yearToPublicationCount.size() > 0) { + + String secondaryContextPath = ""; + if (!contextPath.contains("/admin/visQuery")) { + secondaryContextPath = "/admin/visQuery"; + } + + String fullTimelineNetworkURL = contextPath + + secondaryContextPath + + "?" + + VisualizationFrameworkConstants.INDIVIDUAL_URI_URL_HANDLE + + "=" + URLEncoder.encode(individualURIParam, + VisualizationController.URL_ENCODING_SCHEME).toString() + + "&" + + VisualizationFrameworkConstants.VIS_TYPE_URL_HANDLE + + "=" + URLEncoder.encode("person_level", + VisualizationController.URL_ENCODING_SCHEME).toString() + + "&" + + VisualizationFrameworkConstants.RENDER_MODE_URL_HANDLE + + "=" + URLEncoder.encode(VisualizationFrameworkConstants.STANDALONE_RENDER_MODE_URL_VALUE, + VisualizationController.URL_ENCODING_SCHEME).toString(); + + System.out.println("context parth full n/w " + contextPath); + + fullTimelineLink = "View full timeline and co-author network
"; + + valueObjectContainer.setFullTimelineNetworkLink(fullTimelineNetworkURL); + + } else { + + fullTimelineLink = "No data available to render full timeline.
"; + + } + + divContextCode.append("" + fullTimelineLink + ""); + + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + + return divContextCode.toString(); + + } + + + private String generateDataTable() { + + String csvDownloadURLHref = ""; + + try { + if (getCSVDownloadURL() != null) { + + csvDownloadURLHref = "(.CSV File)"; + + } else { + + csvDownloadURLHref = ""; + + } + + } catch (UnsupportedEncodingException e) { + csvDownloadURLHref = ""; + } + + StringBuilder dataTable = new StringBuilder(); + + dataTable.append("" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + ""); + + for (Entry currentEntry : yearToPublicationCount.entrySet()) { + dataTable.append("" + + "" + + "" + + ""); + } + + dataTable.append("\n" + + "
Publications per year " + csvDownloadURLHref + "
YearPublications
" + currentEntry.getKey() + "" + currentEntry.getValue() + "
\n"); + + + return dataTable.toString(); + } + + + + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/personpubcount/VisualizationRequestHandler.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/personpubcount/VisualizationRequestHandler.java new file mode 100644 index 000000000..f5da0f583 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/personpubcount/VisualizationRequestHandler.java @@ -0,0 +1,333 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.personpubcount; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Map.Entry; + +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.logging.Log; +import org.skife.csv.CSVWriter; +import org.skife.csv.SimpleWriter; + +import com.hp.hpl.jena.query.DataSource; +import com.itextpdf.text.Document; +import com.itextpdf.text.DocumentException; +import com.itextpdf.text.pdf.PdfWriter; + +import edu.cornell.mannlib.vitro.webapp.beans.Portal; +import edu.cornell.mannlib.vitro.webapp.controller.Controllers; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.controller.visualization.VisualizationFrameworkConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.PDFDocument; +import edu.cornell.mannlib.vitro.webapp.visualization.constants.VOConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.constants.VisConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.exceptions.MalformedQueryParametersException; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.BiboDocument; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Individual; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.SparklineVOContainer; +import edu.cornell.mannlib.vitro.webapp.visualization.visutils.UtilityFunctions; + +public class VisualizationRequestHandler { + + private VitroRequest vitroRequest; + private HttpServletRequest request; + private HttpServletResponse response; + private Log log; + + + + public VisualizationRequestHandler(VitroRequest vitroRequest, + HttpServletRequest request, HttpServletResponse response, Log log) { + + this.vitroRequest = vitroRequest; + this.request = request; + this.response = response; + this.log = log; + + } + + public void generateVisualization(DataSource dataSource) { + + String resultFormatParam = "RS_TEXT"; + String rdfResultFormatParam = "RDF/XML-ABBREV"; + + String individualURIParam = vitroRequest.getParameter(VisualizationFrameworkConstants.INDIVIDUAL_URI_URL_HANDLE); + + String renderMode = vitroRequest.getParameter(VisualizationFrameworkConstants.RENDER_MODE_URL_HANDLE); + + String visMode = vitroRequest.getParameter(VisualizationFrameworkConstants.VIS_MODE_URL_HANDLE); + + String visContainer = vitroRequest.getParameter(VisualizationFrameworkConstants.VIS_CONTAINER_URL_HANDLE); + + QueryHandler queryManager = + new QueryHandler(individualURIParam, + resultFormatParam, + rdfResultFormatParam, + dataSource, + log); + + try { + List authorDocuments = queryManager.getVisualizationJavaValueObjects(); + + /* + * Create a map from the year to number of publications. Use the BiboDocument's + * parsedPublicationYear to populate the data. + * */ + Map yearToPublicationCount = + queryManager.getYearToPublicationCount(authorDocuments); + + /* + * In order to avoid unneeded computations we have pushed this "if" condition up. + * This case arises when the render mode is data. In that case we dont want to generate + * HTML code to render sparkline, tables etc. Ideally I would want to avoid this flow. + * It is ugly! + * */ + if (VisualizationFrameworkConstants.DATA_RENDER_MODE_URL_VALUE.equalsIgnoreCase(renderMode)) { + prepareVisualizationQueryDataResponse(queryManager.getAuthor(), + authorDocuments, + yearToPublicationCount); + return; + } + + + if (VisualizationFrameworkConstants.PDF_RENDER_MODE_URL_VALUE.equalsIgnoreCase(renderMode)) { + prepareVisualizationQueryPDFResponse(queryManager.getAuthor(), + authorDocuments, + yearToPublicationCount); + return; + } + + /* + * Computations required to generate HTML for the sparklines & related context. + * */ + + SparklineVOContainer valueObjectContainer = new SparklineVOContainer(); + + VisualizationCodeGenerator visualizationCodeGenerator = + new VisualizationCodeGenerator(vitroRequest.getContextPath(), + individualURIParam, + visMode, + visContainer, + authorDocuments, + yearToPublicationCount, + valueObjectContainer, + log); + + + /* + * 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_URL_VALUE.equalsIgnoreCase(renderMode)) { + + prepareVisualizationQueryDynamicResponse(request, response, vitroRequest, + valueObjectContainer); + requestDispatcher = request.getRequestDispatcher("/templates/page/blankPage.jsp"); + + } else { + prepareVisualizationQueryStandaloneResponse(request, response, vitroRequest, + valueObjectContainer); + + requestDispatcher = request.getRequestDispatcher(Controllers.BASIC_JSP); + } + + try { + requestDispatcher.forward(request, response); + } catch (Exception e) { + log.error("EntityEditController could not forward to view."); + log.error(e.getMessage()); + log.error(e.getStackTrace()); + } + + } catch (MalformedQueryParametersException e) { + try { + handleMalformedParameters(e.getMessage()); + } catch (ServletException e1) { + log.error(e1.getStackTrace()); + } catch (IOException e1) { + log.error(e1.getStackTrace()); + } + return; + } + + } + + private void prepareVisualizationQueryPDFResponse(Individual author, List authorDocuments, + Map yearToPublicationCount) { + + String authorName = null; + + /* + * To protect against cases where there are no author documents associated with the + * individual. + * */ + if (authorDocuments.size() > 0) { + authorName = author.getIndividualLabel(); + } + + /* + * To make sure that null/empty records for author names do not cause any mischief. + * */ + if (authorName == null) { + authorName = ""; + } + + String outputFileName = UtilityFunctions.slugify(authorName) + "report" + ".pdf"; + + response.setContentType("application/pdf"); + response.setHeader("Content-Disposition", "attachment;filename=" + outputFileName); + + ServletOutputStream responseOutputStream; + try { + responseOutputStream = response.getOutputStream(); + + + Document document = new Document(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PdfWriter pdfWriter = PdfWriter.getInstance(document, baos); + document.open(); + + PDFDocument pdfDocument = new PDFDocument(authorName, yearToPublicationCount, document, pdfWriter); + + document.close(); + + // setting some response headers & content type + response.setHeader("Expires", "0"); + response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0"); + response.setHeader("Pragma", "public"); + response.setContentLength(baos.size()); + // write ByteArrayOutputStream to the ServletOutputStream + baos.writeTo(responseOutputStream); + responseOutputStream.flush(); + responseOutputStream.close(); + + } catch (IOException e) { + e.printStackTrace(); + } catch (DocumentException e) { + e.printStackTrace(); + } + } + + private void prepareVisualizationQueryDataResponse(Individual author, List authorDocuments, + Map yearToPublicationCount) { + + String authorName = null; + + /* + * To protect against cases where there are no author documents associated with the + * individual. + * */ + if (authorDocuments.size() > 0) { + authorName = author.getIndividualLabel(); + } + + /* + * To make sure that null/empty records for author names do not cause any mischief. + * */ + if (authorName == null) { + authorName = ""; + } + + String outputFileName = UtilityFunctions.slugify(authorName) + "pub-count-sparkline" + ".csv"; + + response.setContentType("application/octet-stream"); + response.setHeader("Content-Disposition","attachment;filename=" + outputFileName); + + try { + + PrintWriter responseWriter = response.getWriter(); + + /* + * We are side-effecting responseWriter since we are directly manipulating the response + * object of the servlet. + * */ + generateCsvFileBuffer(yearToPublicationCount, + responseWriter); + + responseWriter.close(); + + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void generateCsvFileBuffer(Map yearToPublicationCount, + PrintWriter responseWriter) { + + CSVWriter csvWriter = new SimpleWriter(responseWriter); + + try { + csvWriter.append(new String[]{"Year", "Publications"}); + for (Entry currentEntry : yearToPublicationCount.entrySet()) { + csvWriter.append(new Object[]{currentEntry.getKey(), currentEntry.getValue()}); + } + + } catch (IOException e) { + e.printStackTrace(); + } + + responseWriter.flush(); + + } + + private void prepareVisualizationQueryStandaloneResponse(HttpServletRequest request, + HttpServletResponse response, VitroRequest vreq, + SparklineVOContainer valueObjectContainer) { + + Portal portal = vreq.getPortal(); + + request.setAttribute("sparklineVO", valueObjectContainer); + + request.setAttribute("bodyJsp", "/templates/visualization/publication_count.jsp"); + request.setAttribute("portalBean", portal); + request.setAttribute("title", "Individual Publication Count visualization"); + request.setAttribute("scripts", "/templates/visualization/visualization_scripts.jsp"); + + } + + private void prepareVisualizationQueryDynamicResponse(HttpServletRequest request, + HttpServletResponse response, VitroRequest vreq, SparklineVOContainer valueObjectContainer) { + + Portal portal = vreq.getPortal(); + + request.setAttribute("sparklineVO", valueObjectContainer); + + request.setAttribute("portalBean", portal); + request.setAttribute("bodyJsp", "/templates/visualization/ajax_vis_content.jsp"); + + } + + private void handleMalformedParameters(String errorMessage) + throws ServletException, IOException { + + Portal portal = vitroRequest.getPortal(); + + request.setAttribute("error", errorMessage); + + RequestDispatcher requestDispatcher = request.getRequestDispatcher(Controllers.BASIC_JSP); + request.setAttribute("bodyJsp", "/templates/visualization/visualization_error.jsp"); + request.setAttribute("portalBean", portal); + request.setAttribute("title", "Visualization Query Error - Individual Publication Count"); + + try { + requestDispatcher.forward(request, response); + } catch (Exception e) { + log.error("EntityEditController could not forward to view."); + log.error(e.getMessage()); + log.error(e.getStackTrace()); + } + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/utilities/VisualizationRequestHandler.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/utilities/VisualizationRequestHandler.java new file mode 100644 index 000000000..c848b9c77 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/utilities/VisualizationRequestHandler.java @@ -0,0 +1,268 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.utilities; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.Set; + +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.logging.Log; + +import com.google.gson.Gson; +import com.hp.hpl.jena.query.DataSource; + +import edu.cornell.mannlib.vitro.webapp.beans.Portal; +import edu.cornell.mannlib.vitro.webapp.controller.Controllers; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.controller.visualization.VisualizationController; +import edu.cornell.mannlib.vitro.webapp.controller.visualization.VisualizationFrameworkConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.constants.QueryConstants; +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.visutils.GenericQueryHandler; + +public class VisualizationRequestHandler { + + private VitroRequest vitroRequest; + private HttpServletRequest request; + private HttpServletResponse response; + private Log log; + + + + public VisualizationRequestHandler(VitroRequest vitroRequest, + HttpServletRequest request, HttpServletResponse response, Log log) { + + this.vitroRequest = vitroRequest; + this.request = request; + this.response = response; + this.log = log; + + } + + public void generateVisualization(DataSource dataSource) { + + String individualURIParam = vitroRequest.getParameter(VisualizationFrameworkConstants.INDIVIDUAL_URI_URL_HANDLE); + + String visMode = vitroRequest.getParameter(VisualizationFrameworkConstants.VIS_MODE_URL_HANDLE); + + String profileInfoMode = "PROFILE_INFO"; + String profileVisMode = "PROFILE_URL"; + String coAuthorVisMode = "COAUTHORSHIP_URL"; + String personLevelVisMode = "PERSON_LEVEL_URL"; + String imageVisMode = "IMAGE_URL"; + + String resultFormatParam = "RS_TEXT"; + String rdfResultFormatParam = "RDF/XML-ABBREV"; + + String preparedURL = ""; + + try { + + /* + * If the info being requested is about a profile which includes the name, moniker + * & image url. + * */ + if (profileInfoMode.equalsIgnoreCase(visMode)) { + + + String filterRule = "?predicate = vitro:imageThumb || ?predicate = vitro:moniker || ?predicate = rdfs:label"; + GenericQueryHandler imageQueryHandler = new GenericQueryHandler(individualURIParam, + filterRule, + resultFormatParam, + rdfResultFormatParam, + dataSource, + log); + + try { + + GenericQueryMap profilePropertiesToValues = imageQueryHandler.getJavaValueObjects(); + + profilePropertiesToValues.addEntry("imageContextPath", request.getContextPath() + "/images/"); + + Gson profileInformation = new Gson(); + + prepareVisualizationQueryResponse(profileInformation.toJson(profilePropertiesToValues)); + + return; + + + } catch (MalformedQueryParametersException e) { + try { + handleMalformedParameters(e.getMessage()); + } catch (ServletException e1) { + log.error(e1.getStackTrace()); + } catch (IOException e1) { + log.error(e1.getStackTrace()); + } + return; + } + + + } else if (imageVisMode.equalsIgnoreCase(visMode)) { + /* + * If the url being requested is about a standalone image, which is used when we want + * to render an image & other info for a co-author OR ego for that matter. + * */ + + + String filterRule = "?predicate = vitro:imageThumb"; + GenericQueryHandler imageQueryHandler = new GenericQueryHandler(individualURIParam, + filterRule, + resultFormatParam, + rdfResultFormatParam, + dataSource, + log); + + try { + + GenericQueryMap imagePropertyToValues = imageQueryHandler.getJavaValueObjects(); + + String imagePath = ""; + + if (imagePropertyToValues.size() > 0) { + + String vitroSparqlNamespace = QueryConstants.PREFIX_TO_NAMESPACE.get("vitro"); + String imageThumbProperty = vitroSparqlNamespace + "imageThumb"; + + Set personImageThumbPaths = imagePropertyToValues.get(imageThumbProperty); + + /* + * Although we know that there can be only one imagePath we are restricted by Java's + * expression power. + * */ + for (String providedImagePath : personImageThumbPaths) { + imagePath = request.getContextPath() + "/images/" + providedImagePath; + } + } + + prepareVisualizationQueryResponse(imagePath); + return; + + + } catch (MalformedQueryParametersException e) { + try { + handleMalformedParameters(e.getMessage()); + } catch (ServletException e1) { + log.error(e1.getStackTrace()); + } catch (IOException e1) { + log.error(e1.getStackTrace()); + } + return; + } + + + } else if (coAuthorVisMode.equalsIgnoreCase(visMode)) { + /* + * By default we will be generating profile url else some specific url like coAuthorShip vis + * url for that individual. + * */ + + preparedURL += request.getContextPath() + + "/admin/visQuery" + + "?" + + VisualizationFrameworkConstants.INDIVIDUAL_URI_URL_HANDLE + + "=" + URLEncoder.encode(individualURIParam, + VisualizationController.URL_ENCODING_SCHEME).toString() + + "&" + + VisualizationFrameworkConstants.VIS_TYPE_URL_HANDLE + + "=" + URLEncoder.encode("coauthorship", + VisualizationController.URL_ENCODING_SCHEME).toString() + + "&" + + VisualizationFrameworkConstants.RENDER_MODE_URL_HANDLE + + "=" + URLEncoder.encode(VisualizationFrameworkConstants.STANDALONE_RENDER_MODE_URL_VALUE, + VisualizationController.URL_ENCODING_SCHEME).toString(); + + + prepareVisualizationQueryResponse(preparedURL); + return; + + } else if (personLevelVisMode.equalsIgnoreCase(visMode)) { + /* + * By default we will be generating profile url else some specific url like coAuthorShip vis + * url for that individual. + * */ + + preparedURL += request.getContextPath() + + "/admin/visQuery" + + "?" + + VisualizationFrameworkConstants.INDIVIDUAL_URI_URL_HANDLE + + "=" + URLEncoder.encode(individualURIParam, + VisualizationController.URL_ENCODING_SCHEME).toString() + + "&" + + VisualizationFrameworkConstants.VIS_TYPE_URL_HANDLE + + "=" + URLEncoder.encode("person_level", + VisualizationController.URL_ENCODING_SCHEME).toString() + + "&" + + VisualizationFrameworkConstants.RENDER_MODE_URL_HANDLE + + "=" + URLEncoder.encode(VisualizationFrameworkConstants.STANDALONE_RENDER_MODE_URL_VALUE, + VisualizationController.URL_ENCODING_SCHEME).toString(); + + prepareVisualizationQueryResponse(preparedURL); + return; + + } else { + + preparedURL += request.getContextPath() + + "/individual" + + "?" + + VisualizationFrameworkConstants.INDIVIDUAL_URI_URL_HANDLE + + "=" + URLEncoder.encode(individualURIParam, + VisualizationController.URL_ENCODING_SCHEME).toString(); + + prepareVisualizationQueryResponse(preparedURL); + return; + + } + + } catch (UnsupportedEncodingException e) { + log.error(e.getLocalizedMessage()); + } + + } + + private void prepareVisualizationQueryResponse(String preparedURL) { + + response.setContentType("text/plain"); + + try { + + PrintWriter responseWriter = response.getWriter(); + + responseWriter.append(preparedURL); + + responseWriter.close(); + + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void handleMalformedParameters(String errorMessage) + throws ServletException, IOException { + + Portal portal = vitroRequest.getPortal(); + + request.setAttribute("error", errorMessage); + + RequestDispatcher requestDispatcher = request.getRequestDispatcher(Controllers.BASIC_JSP); + request.setAttribute("bodyJsp", "/templates/visualization/visualization_error.jsp"); + request.setAttribute("portalBean", portal); + request.setAttribute("title", "Visualization Query Error - Individual Publication Count"); + + try { + requestDispatcher.forward(request, response); + } catch (Exception e) { + log.error("EntityEditController could not forward to view."); + log.error(e.getMessage()); + log.error(e.getStackTrace()); + } + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/BiboDocument.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/BiboDocument.java new file mode 100644 index 000000000..6c8fad61b --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/BiboDocument.java @@ -0,0 +1,120 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.valueobjects; + +import java.util.Calendar; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import edu.cornell.mannlib.vitro.webapp.visualization.constants.VOConstants; + +public class BiboDocument extends Individual{ + + public static final int MINIMUM_PUBLICATION_YEAR = 1800; + private static final int CURRENT_YEAR = Calendar.getInstance().get(Calendar.YEAR); + + private String documentMoniker; + private String documentBlurb; + private String documentDescription; + private String publicationYear; + private String parsedPublicationYear = VOConstants.DEFAULT_PUBLICATION_YEAR; + + public BiboDocument(String documentURL) { + super(documentURL); + } + + public String getDocumentURL() { + return this.getIndividualURL(); + } + + public String getDocumentMoniker() { + return documentMoniker; + } + + public void setDocumentMoniker(String documentMoniker) { + this.documentMoniker = documentMoniker; + } + + public String getDocumentLabel() { + return this.getIndividualLabel(); + } + + public void setDocumentLabel(String documentLabel) { + this.setIndividualLabel(documentLabel); + } + + public String getDocumentBlurb() { + return documentBlurb; + } + + public void setDocumentBlurb(String documentBlurb) { + this.documentBlurb = documentBlurb; + + if (documentBlurb != null) { + this.setParsedPublicationYear(parsePublicationYear(documentBlurb)); + } + } + + private String parsePublicationYear(String documentBlurb) { + + /* + * This pattern will match all group of numbers which have only 4 digits + * delimited by the word boundary. + * */ +// String pattern = "\\b\\d{4}\\b"; + String pattern = "(?= MINIMUM_PUBLICATION_YEAR) { + publishedYear = candidateYearInteger.toString(); + } + + } + + return publishedYear; + } + + public String getDocumentDescription() { + return documentDescription; + } + public void setDocumentDescription(String documentDescription) { + this.documentDescription = documentDescription; + } + + /* + * Only the + * */ + private void setParsedPublicationYear(String parsedPublicationYear) { + this.parsedPublicationYear = parsedPublicationYear; + } + + public String getParsedPublicationYear() { + return parsedPublicationYear; + } + + /* + * This publicationYear value is directly from the data supported by the ontology. If this is empty only + * then use the parsedPublicationYear. + * */ + public String getPublicationYear() { + return publicationYear; + } + + public void setPublicationYear(String publicationYear) { + this.publicationYear = publicationYear; + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/Edge.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/Edge.java new file mode 100644 index 000000000..000a6a001 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/Edge.java @@ -0,0 +1,147 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.valueobjects; + +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import edu.cornell.mannlib.vitro.webapp.visualization.constants.VOConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.visutils.UniqueIDGenerator; +import edu.cornell.mannlib.vitro.webapp.visualization.visutils.UtilityFunctions; + +/** + * + * This is the Value Object for storing edge information mainly for co-author vis. + * @author cdtank + * + */ +public class Edge { + + private int edgeID; + private Map yearToPublicationCount; + private Set collaboratorDocuments = new HashSet(); + private Node sourceNode; + private Node targetNode; + + public Edge(Node sourceNode, Node targetNode, BiboDocument seedCoAuthoredDocument, + UniqueIDGenerator uniqueIDGenerator) { + edgeID = uniqueIDGenerator.getNextNumericID(); + this.sourceNode = sourceNode; + this.targetNode = targetNode; + this.collaboratorDocuments.add(seedCoAuthoredDocument); + } + + public int getEdgeID() { + return edgeID; + } + + public Node getSourceNode() { + return sourceNode; + } + + public Node getTargetNode() { + return targetNode; + } + + public Set getCollaboratorDocuments() { + return collaboratorDocuments; + } + + public int getNumOfCoAuthoredWorks() { + return collaboratorDocuments.size(); + } + + public void addCollaboratorDocument(BiboDocument authorDocument) { + this.collaboratorDocuments.add(authorDocument); + } + + /* + * getEarliest, Latest & Unknown Publication YearCount should only be used after + * the parsing of the entire sparql is done. Else it will give results based on + * incomplete dataset. + * */ + @SuppressWarnings("serial") + public Map getEarliestCollaborationYearCount() { + if (yearToPublicationCount == null) { + yearToPublicationCount = UtilityFunctions.getYearToPublicationCount(collaboratorDocuments); + } + + /* + * We do not want to consider the default publication year when we are checking + * for the min or max publication year. + * */ + Set yearsToBeConsidered = new HashSet(yearToPublicationCount.keySet()); + yearsToBeConsidered.remove(VOConstants.DEFAULT_PUBLICATION_YEAR); + + /* + * There can be a case when the only publication the author has no attached year to it + * so essentially an "Unknown". In that case Collections.max or min will throw an + * NoSuchElementException. + * + * If there is no maximum year available then we should imply so by returning a "null". + * */ + if (yearsToBeConsidered.size() > 0) { + final String earliestYear = Collections.min(yearsToBeConsidered); + final Integer earliestYearPubCount = yearToPublicationCount.get(earliestYear); + + return new HashMap(){{ + put(earliestYear, earliestYearPubCount); + }}; + } else { + return null; + } + } + + @SuppressWarnings("serial") + public Map getLatestCollaborationYearCount() { + if (yearToPublicationCount == null) { + yearToPublicationCount = UtilityFunctions.getYearToPublicationCount(collaboratorDocuments); + } + + /* + * We do not want to consider the default publication year when we are checking + * for the min or max publication year. + * */ + Set yearsToBeConsidered = new HashSet(yearToPublicationCount.keySet()); + yearsToBeConsidered.remove(VOConstants.DEFAULT_PUBLICATION_YEAR); + + /* + * There can be a case when the only publication the author has no attached year to it + * so essentially an "Unknown". In that case Collections.max or min will throw an + * NoSuchElementException. + * + * If there is no maximum year available then we should imply so by returning a "null". + * */ + if (yearsToBeConsidered.size() > 0) { + final String latestYear = Collections.max(yearsToBeConsidered); + final Integer latestYearPubCount = yearToPublicationCount.get(latestYear); + + return new HashMap(){{ + put(latestYear, latestYearPubCount); + }}; + } else { + return null; + } + } + + @SuppressWarnings("serial") + public Integer getUnknownCollaborationYearCount() { + if (yearToPublicationCount == null) { + yearToPublicationCount = UtilityFunctions.getYearToPublicationCount(collaboratorDocuments); + } + + Integer unknownYearPubCount = yearToPublicationCount.get(VOConstants.DEFAULT_PUBLICATION_YEAR); + + /* + * If there is no unknown year available then we should imply so by returning a "null". + * */ + if (unknownYearPubCount != null) { + return unknownYearPubCount; + } else { + return null; + } + } + + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/GenericQueryMap.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/GenericQueryMap.java new file mode 100644 index 000000000..1a35f2558 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/GenericQueryMap.java @@ -0,0 +1,39 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.valueobjects; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; + +/** + * Right now this is just acting as a hashmap but in future we would want to provide + * more detailed info other than just what properties had what values. E.g. we + * could parse properties (& its values) to look for what namespaces are used. + * @author cdtank + * + */ +@SuppressWarnings("serial") +public class GenericQueryMap extends HashMap> { + + public GenericQueryMap() { + super(); + } + + public void addEntry(String property, String value) { + + Set values; + + if (this.containsKey(property)) { + + values = this.get(property); + values.add(value); + + } else { + + values = new HashSet(); + values.add(value); + this.put(property, values); + + } + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/Individual.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/Individual.java new file mode 100644 index 000000000..57032200f --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/Individual.java @@ -0,0 +1,30 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.valueobjects; + +public class Individual { + + private String individualLabel; + private String individualURL; + + public Individual(String individualURL, String individualLabel) { + this.individualURL = individualURL; + this.individualLabel = individualLabel; + } + + public Individual(String individualURL) { + this(individualURL, ""); + } + + public String getIndividualLabel() { + return individualLabel; + } + + public void setIndividualLabel(String individualLabel) { + this.individualLabel = individualLabel; + } + + public String getIndividualURL() { + return individualURL; + } + + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/Node.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/Node.java new file mode 100644 index 000000000..d8811773f --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/Node.java @@ -0,0 +1,155 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.valueobjects; + +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import edu.cornell.mannlib.vitro.webapp.visualization.constants.VOConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.visutils.UniqueIDGenerator; +import edu.cornell.mannlib.vitro.webapp.visualization.visutils.UtilityFunctions; + +/** + * + * This is the Value Object for storing node information mainly for co-author vis. + * @author cdtank + * + */ +public class Node extends Individual { + + private int nodeID; + private Map yearToPublicationCount; + + private Set authorDocuments = new HashSet(); + + public Node(String nodeURL, + UniqueIDGenerator uniqueIDGenerator) { + super(nodeURL); + nodeID = uniqueIDGenerator.getNextNumericID(); + } + + public int getNodeID() { + return nodeID; + } + + public String getNodeURL() { + return this.getIndividualURL(); + } + + public String getNodeName() { + return this.getIndividualLabel(); + } + + public void setNodeName(String nodeName) { + this.setIndividualLabel(nodeName); + } + + public Set getAuthorDocuments() { + return authorDocuments; + } + + public int getNumOfAuthoredWorks() { + return authorDocuments.size(); + } + + public void addAuthorDocument(BiboDocument authorDocument) { + this.authorDocuments.add(authorDocument); + } + + + public Map getYearToPublicationCount() { + if (yearToPublicationCount == null) { + yearToPublicationCount = UtilityFunctions.getYearToPublicationCount(authorDocuments); + } + return yearToPublicationCount; + } + /* + * getEarliest, Latest & Unknown Publication YearCount should only be used after + * the parsing of the entire sparql is done. Else it will give results based on + * incomplete dataset. + * */ + @SuppressWarnings("serial") + public Map getEarliestPublicationYearCount() { + if (yearToPublicationCount == null) { + yearToPublicationCount = UtilityFunctions.getYearToPublicationCount(authorDocuments); + } + + /* + * We do not want to consider the default publication year when we are checking + * for the min or max publication year. + * */ + Set yearsToBeConsidered = new HashSet(yearToPublicationCount.keySet()); + yearsToBeConsidered.remove(VOConstants.DEFAULT_PUBLICATION_YEAR); + + /* + * There can be a case when the only publication the author has no attached year to it + * so essentially an "Unknown". In that case Collections.max or min will throw an + * NoSuchElementException. + * + * If there is no maximum year available then we should imply so by returning a "null". + * */ + if (yearsToBeConsidered.size() > 0) { + final String earliestYear = Collections.min(yearsToBeConsidered); + final Integer earliestYearPubCount = yearToPublicationCount.get(earliestYear); + + return new HashMap(){{ + put(earliestYear, earliestYearPubCount); + }}; + } else { + return null; + } + } + + @SuppressWarnings("serial") + public Map getLatestPublicationYearCount() { + if (yearToPublicationCount == null) { + yearToPublicationCount = UtilityFunctions.getYearToPublicationCount(authorDocuments); + } + + /* + * We do not want to consider the default publication year when we are checking + * for the min or max publication year. + * */ + Set yearsToBeConsidered = new HashSet(yearToPublicationCount.keySet()); + yearsToBeConsidered.remove(VOConstants.DEFAULT_PUBLICATION_YEAR); + + /* + * There can be a case when the only publication the author has no attached year to it + * so essentially an "Unknown". In that case Collections.max or min will throw an + * NoSuchElementException. + * + * If there is no maximum year available then we should imply so by returning a "null". + * */ + if (yearsToBeConsidered.size() > 0) { + final String latestYear = Collections.max(yearsToBeConsidered); + final Integer latestYearPubCount = yearToPublicationCount.get(latestYear); + + return new HashMap(){{ + put(latestYear, latestYearPubCount); + }}; + } else { + return null; + } + + } + + public Integer getUnknownPublicationYearCount() { + if (yearToPublicationCount == null) { + yearToPublicationCount = UtilityFunctions.getYearToPublicationCount(authorDocuments); + } + + Integer unknownYearPubCount = yearToPublicationCount.get(VOConstants.DEFAULT_PUBLICATION_YEAR); + + /* + * If there is no unknown year available then we should imply so by returning a "null". + * */ + if (unknownYearPubCount != null) { + return unknownYearPubCount; + } else { + return null; + } + } + + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/SparklineVOContainer.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/SparklineVOContainer.java new file mode 100644 index 000000000..f664c53f7 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/SparklineVOContainer.java @@ -0,0 +1,84 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.valueobjects; + +public class SparklineVOContainer { + + /* + * For now sparklineNumPublicationsText & sparklinePublicationRangeText is left + * as empty but later on we would want to leverage the granularity that this + * provides. + * */ + private String sparklineNumPublicationsText = ""; + private String sparklinePublicationRangeText = ""; + + private Integer earliestRenderedPublicationYear; + private Integer latestRenderedPublicationYear; + + private String table = ""; + + private String downloadDataLink = ""; + private String fullTimelineNetworkLink = ""; + + private String sparklineContent; + private String sparklineContext; + + public String getSparklineNumPublicationsText() { + return sparklineNumPublicationsText; + } + public void setSparklineNumPublicationsText(String sparklineNumPublicationsText) { + this.sparklineNumPublicationsText = sparklineNumPublicationsText; + } + public String getSparklinePublicationRangeText() { + return sparklinePublicationRangeText; + } + public void setSparklinePublicationRangeText( + String sparklinePublicationRangeText) { + this.sparklinePublicationRangeText = sparklinePublicationRangeText; + } + public Integer getEarliestRenderedPublicationYear() { + return earliestRenderedPublicationYear; + } + public void setEarliestRenderedPublicationYear( + Integer earliestRenderedPublicationYear) { + this.earliestRenderedPublicationYear = earliestRenderedPublicationYear; + } + public Integer getLatestRenderedPublicationYear() { + return latestRenderedPublicationYear; + } + public void setLatestRenderedPublicationYear( + Integer latestRenderedPublicationYear) { + this.latestRenderedPublicationYear = latestRenderedPublicationYear; + } + public String getTable() { + return table; + } + public void setTable(String table) { + this.table = table; + } + public String getDownloadDataLink() { + return downloadDataLink; + } + public void setDownloadDataLink(String downloadDataLink) { + this.downloadDataLink = downloadDataLink; + } + public String getFullTimelineNetworkLink() { + return fullTimelineNetworkLink; + } + public void setFullTimelineNetworkLink(String fullTimelineNetworkLink) { + this.fullTimelineNetworkLink = fullTimelineNetworkLink; + } + + public String getSparklineContent() { + return sparklineContent; + } + public void setSparklineContent(String shortSparklineContent) { + this.sparklineContent = shortSparklineContent; + } + + public String getSparklineContext() { + return sparklineContext; + } + public void setSparklineContext(String shortSparklineContext) { + this.sparklineContext = shortSparklineContext; + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/VivoCollegeOrSchool.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/VivoCollegeOrSchool.java new file mode 100644 index 000000000..7d795bf1c --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/VivoCollegeOrSchool.java @@ -0,0 +1,40 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.valueobjects; + +import java.util.HashSet; +import java.util.Set; + +/** + * + * This is the Value Object equivalent for vivo:CollegeOrSchoolWithinUniversity object type. + * @author cdtank + * + */ +public class VivoCollegeOrSchool extends Individual { + + private Set departments = new HashSet(); + + public VivoCollegeOrSchool(String collegeURL) { + super(collegeURL); + } + + public Set getDepartments() { + return departments; + } + + public void addDepartment(VivoDepartmentOrDivision department) { + this.departments.add(department); + } + + public String getCollegeURL() { + return this.getIndividualURL(); + } + + public String getCollegeLabel() { + return this.getIndividualLabel(); + } + + public void setCollegeLabel(String collegeLabel) { + this.setIndividualLabel(collegeLabel); + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/VivoDepartmentOrDivision.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/VivoDepartmentOrDivision.java new file mode 100644 index 000000000..e2ebe0682 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/VivoDepartmentOrDivision.java @@ -0,0 +1,41 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.valueobjects; + +import java.util.HashSet; +import java.util.Set; + +/** + * + * This is the Value Object equivalent for vivo:AcademicDepartmentOrDivision object type. + * @author cdtank + * + */ +public class VivoDepartmentOrDivision extends Individual { + + private Set parentColleges = new HashSet(); + + public VivoDepartmentOrDivision(String departmentURL, VivoCollegeOrSchool parentCollege) { + super(departmentURL); + addParentCollege(parentCollege); + } + + public Set getParentCollege() { + return parentColleges; + } + + public void addParentCollege(VivoCollegeOrSchool parentCollege) { + this.parentColleges.add(parentCollege); + } + + public String getDepartmentURL() { + return this.getIndividualURL(); + } + + public String getDepartmentLabel() { + return this.getIndividualLabel(); + } + + public void setDepartmentLabel(String departmentLabel) { + this.setIndividualLabel(departmentLabel); + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/VivoEmployee.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/VivoEmployee.java new file mode 100644 index 000000000..6863289d2 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/valueobjects/VivoEmployee.java @@ -0,0 +1,60 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.valueobjects; + +import java.util.HashSet; +import java.util.Set; + +import edu.cornell.mannlib.vitro.webapp.visualization.constants.VOConstants.EmployeeType; + +/** + * + * This is the Value Object equivalent for vivo's Employee object type. + * @author cdtank + * + */ +public class VivoEmployee extends Individual { + + private EmployeeType employeeType; + private Set parentDepartments = new HashSet(); + private Set authorDocuments = new HashSet(); + + public VivoEmployee(String employeeURL, + EmployeeType employeeType, + VivoDepartmentOrDivision parentDepartment) { + super(employeeURL); + addParentDepartment(parentDepartment); + } + + public String getEmployeeURL() { + return this.getIndividualURL(); + } + + public String getEmployeeName() { + return this.getIndividualLabel(); + } + + public EmployeeType getEmployeeType() { + return employeeType; + } + + public void setEmployeeType(EmployeeType employeeType) { + this.employeeType = employeeType; + } + + public Set getParentDepartments() { + return parentDepartments; + } + + public void addParentDepartment(VivoDepartmentOrDivision parentDepartment) { + this.parentDepartments.add(parentDepartment); + } + + public Set getAuthorDocuments() { + return authorDocuments; + } + + public void addAuthorDocument(BiboDocument authorDocument) { + this.authorDocuments.add(authorDocument); + } + + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/visutils/GenericQueryHandler.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/visutils/GenericQueryHandler.java new file mode 100644 index 000000000..e5a1141ff --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/visutils/GenericQueryHandler.java @@ -0,0 +1,161 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.visutils; + +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.valueobjects.GenericQueryMap; + + + +/** + * Very dumb name of the class. change it. + * @author cdtank + * + */ +public class GenericQueryHandler { + + protected static final Syntax SYNTAX = Syntax.syntaxARQ; + + private String filterRule, individualURLParam, resultFormatParam, rdfResultFormatParam; + private DataSource dataSource; + + private Log log; + + public GenericQueryHandler(String individualURLParam, + String filterRule, + String resultFormatParam, + String rdfResultFormatParam, + DataSource dataSource, + Log log) { + + this.individualURLParam = individualURLParam; + this.filterRule = filterRule; + this.resultFormatParam = resultFormatParam; + this.rdfResultFormatParam = rdfResultFormatParam; + this.dataSource = dataSource; + this.log = log; + + } + + private GenericQueryMap createJavaValueObjects(ResultSet resultSet) { + + GenericQueryMap queryResultVO = new GenericQueryMap(); + + while (resultSet.hasNext()) { + QuerySolution solution = resultSet.nextSolution(); + + + /* + * We only want to create only ONE ego node. + * */ + RDFNode predicateNode = solution.get(QueryFieldLabels.PREDICATE); + RDFNode objectNode = solution.get(QueryFieldLabels.OBJECT); + + if (predicateNode != null && objectNode != null) { + queryResultVO.addEntry(predicateNode.toString(), + objectNode.toString()); + } + + } + + return queryResultVO; + } + + + private ResultSet executeQuery(String queryText, + String resultFormatParam, + String rdfResultFormatParam, + DataSource dataSource) { + + QueryExecution queryExecution = null; + try{ + Query query = QueryFactory.create(queryText, SYNTAX); + +// QuerySolutionMap qs = new QuerySolutionMap(); +// qs.add("authPerson", queryParam); // bind resource to s + + queryExecution = QueryExecutionFactory.create(query, dataSource); + + + //remocve this if loop after knowing what is describe & construct sparql stuff. + if (query.isSelectType()){ + return queryExecution.execSelect(); + } + } finally { + if(queryExecution != null) { + queryExecution.close(); + } + + } + return null; + } + + private String generateGenericSparqlQuery(String queryURI, String filterRule) { +// Resource uri1 = ResourceFactory.createResource(queryURI); + String filterClause; + + if (filterRule == null || filterRule.trim().isEmpty()) { + filterClause = ""; + } else { + filterClause = "FILTER ( " + filterRule + " ) . "; + } + + String sparqlQuery = QueryConstants.getSparqlPrefixQuery() + + "SELECT " + + " (str(?predicate) as ?" + QueryFieldLabels.PREDICATE + ") " + + " (str(?object) as ?" + QueryFieldLabels.OBJECT + ") " + + "WHERE { " + + "<" + queryURI + "> ?predicate ?object. " + + filterClause + + "}"; + + System.out.println(sparqlQuery); + + return sparqlQuery; + } + + + public GenericQueryMap getJavaValueObjects() + throws MalformedQueryParametersException { + + if (this.individualURLParam == null || "".equals(individualURLParam)) { + throw new MalformedQueryParametersException("URI parameter is either null or empty."); + } else { + + /* + * To test for the validity of the URI submitted. + * */ + IRIFactory iRIFactory = IRIFactory.jenaImplementation(); + IRI iri = iRIFactory.create(this.individualURLParam); + if (iri.hasViolation(false)) { + String errorMsg = ((Violation)iri.violations(false).next()).getShortMessage()+" "; + log.error("Generic Query " + errorMsg); + throw new MalformedQueryParametersException("URI provided for an individual is malformed."); + } + } + + ResultSet resultSet = executeQuery(generateGenericSparqlQuery(this.individualURLParam, this.filterRule), + this.resultFormatParam, + this.rdfResultFormatParam, + this.dataSource); + + return createJavaValueObjects(resultSet); + } + + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/visutils/UniqueIDGenerator.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/visutils/UniqueIDGenerator.java new file mode 100644 index 000000000..a5d796951 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/visutils/UniqueIDGenerator.java @@ -0,0 +1,14 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.visutils; + +public class UniqueIDGenerator { + + private int nextNumericID = 1; + + public int getNextNumericID() { + int nextNumericID = this.nextNumericID; + this.nextNumericID++; + + return nextNumericID; + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/visutils/UtilityFunctions.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/visutils/UtilityFunctions.java new file mode 100644 index 000000000..6a80d0120 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/visualization/visutils/UtilityFunctions.java @@ -0,0 +1,67 @@ +package edu.cornell.mannlib.vitro.webapp.visualization.visutils; + +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +import edu.cornell.mannlib.vitro.webapp.visualization.constants.VisConstants; +import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.BiboDocument; + +public class UtilityFunctions { + + public static Map getYearToPublicationCount( + Set authorDocuments) { + + //List publishedYears = new ArrayList(); + + /* + * Create a map from the year to number of publications. Use the BiboDocument's + * parsedPublicationYear to populate the data. + * */ + Map yearToPublicationCount = new TreeMap(); + + for (BiboDocument curr : authorDocuments) { + + /* + * Increment the count because there is an entry already available for + * that particular year. + * */ + String publicationYear; + if (curr.getPublicationYear() != null + && curr.getPublicationYear().length() != 0 + && curr.getPublicationYear().trim().length() != 0) { + publicationYear = curr.getPublicationYear(); + } else { + publicationYear = curr.getParsedPublicationYear(); + } + + if (yearToPublicationCount.containsKey(publicationYear)) { + yearToPublicationCount.put(publicationYear, + yearToPublicationCount + .get(publicationYear) + 1); + + } else { + yearToPublicationCount.put(publicationYear, 1); + } + +// if (!parsedPublicationYear.equalsIgnoreCase(BiboDocument.DEFAULT_PUBLICATION_YEAR)) { +// publishedYears.add(Integer.parseInt(parsedPublicationYear)); +// } + + } + + return yearToPublicationCount; + } + + /** + * Currently the approach for slugifying filenames is naive. In future if there is need, + * we can write more sophisticated method. + * @param textToBeSlugified + * @return + */ + public static String slugify(String textToBeSlugified) { + return textToBeSlugified.toLowerCase().replaceAll("[^a-zA-Z0-9-]", "-") + .substring(0, VisConstants.MAX_NAME_TEXT_LENGTH); + } + +} diff --git a/webapp/web/images/people/erb_hollis_thumb.gif b/webapp/web/images/people/erb_hollis_thumb.gif new file mode 100644 index 000000000..0d6fb5b08 Binary files /dev/null and b/webapp/web/images/people/erb_hollis_thumb.gif differ diff --git a/webapp/web/js/visualization/coauthorship/AC_OETags.js b/webapp/web/js/visualization/coauthorship/AC_OETags.js new file mode 100644 index 000000000..6366467ea --- /dev/null +++ b/webapp/web/js/visualization/coauthorship/AC_OETags.js @@ -0,0 +1,292 @@ +// Flash Player Version Detection - Rev 1.6 +// Detect Client Browser type +// Copyright(c) 2005-2006 Adobe Macromedia Software, LLC. All rights reserved. +var isIE = (navigator.appVersion.indexOf("MSIE") != -1) ? true : false; +var isWin = (navigator.appVersion.toLowerCase().indexOf("win") != -1) ? true : false; +var isOpera = (navigator.userAgent.indexOf("Opera") != -1) ? true : false; + +function ControlVersion() +{ + var version; + var axo; + var e; + + // NOTE : new ActiveXObject(strFoo) throws an exception if strFoo isn't in the registry + + try { + // version will be set for 7.X or greater players + axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7"); + version = axo.GetVariable("$version"); + } catch (e) { + } + + if (!version) + { + try { + // version will be set for 6.X players only + axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6"); + + // installed player is some revision of 6.0 + // GetVariable("$version") crashes for versions 6.0.22 through 6.0.29, + // so we have to be careful. + + // default to the first public version + version = "WIN 6,0,21,0"; + + // throws if AllowScripAccess does not exist (introduced in 6.0r47) + axo.AllowScriptAccess = "always"; + + // safe to call for 6.0r47 or greater + version = axo.GetVariable("$version"); + + } catch (e) { + } + } + + if (!version) + { + try { + // version will be set for 4.X or 5.X player + axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3"); + version = axo.GetVariable("$version"); + } catch (e) { + } + } + + if (!version) + { + try { + // version will be set for 3.X player + axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3"); + version = "WIN 3,0,18,0"; + } catch (e) { + } + } + + if (!version) + { + try { + // version will be set for 2.X player + axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash"); + version = "WIN 2,0,0,11"; + } catch (e) { + version = -1; + } + } + + return version; +} + +// JavaScript helper required to detect Flash Player PlugIn version information +function GetSwfVer(){ + // NS/Opera version >= 3 check for Flash plugin in plugin array + var flashVer = -1; + + if (navigator.plugins != null && navigator.plugins.length > 0) { + if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) { + var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : ""; + var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description; + var descArray = flashDescription.split(" "); + var tempArrayMajor = descArray[2].split("."); + var versionMajor = tempArrayMajor[0]; + var versionMinor = tempArrayMajor[1]; + var versionRevision = descArray[3]; + if (versionRevision == "") { + versionRevision = descArray[4]; + } + if (versionRevision[0] == "d") { + versionRevision = versionRevision.substring(1); + } else if (versionRevision[0] == "r") { + versionRevision = versionRevision.substring(1); + if (versionRevision.indexOf("d") > 0) { + versionRevision = versionRevision.substring(0, versionRevision.indexOf("d")); + } + } else if (versionRevision[0] == "b") { + versionRevision = versionRevision.substring(1); + } + var flashVer = versionMajor + "." + versionMinor + "." + versionRevision; + } + } + // MSN/WebTV 2.6 supports Flash 4 + else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4; + // WebTV 2.5 supports Flash 3 + else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3; + // older WebTV supports Flash 2 + else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2; + else if ( isIE && isWin && !isOpera ) { + flashVer = ControlVersion(); + } + return flashVer; +} + +// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available +function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision) +{ + versionStr = GetSwfVer(); + if (versionStr == -1 ) { + return false; + } else if (versionStr != 0) { + if(isIE && isWin && !isOpera) { + // Given "WIN 2,0,0,11" + tempArray = versionStr.split(" "); // ["WIN", "2,0,0,11"] + tempString = tempArray[1]; // "2,0,0,11" + versionArray = tempString.split(","); // ['2', '0', '0', '11'] + } else { + versionArray = versionStr.split("."); + } + var versionMajor = versionArray[0]; + var versionMinor = versionArray[1]; + var versionRevision = versionArray[2]; + + // is the major.revision >= requested major.revision AND the minor version >= requested minor + if (versionMajor > parseFloat(reqMajorVer)) { + return true; + } else if (versionMajor == parseFloat(reqMajorVer)) { + if (versionMinor > parseFloat(reqMinorVer)) + return true; + else if (versionMinor == parseFloat(reqMinorVer)) { + if (versionRevision >= parseFloat(reqRevision)) + return true; + } + } + return false; + } +} + +function AC_AddExtension(src, ext) +{ + var qIndex = src.indexOf('?'); + if ( qIndex != -1) + { + // Add the extention (if needed) before the query params + var path = src.substring(0, qIndex); + if (path.length >= ext.length && path.lastIndexOf(ext) == (path.length - ext.length)) + return src; + else + return src.replace(/\?/, ext+'?'); + } + else + { + // Add the extension (if needed) to the end of the URL + if (src.length >= ext.length && src.lastIndexOf(ext) == (src.length - ext.length)) + return src; // Already have extension + else + return src + ext; + } +} + +function AC_Generateobj(objAttrs, params, embedAttrs) +{ + var str = ''; + if (isIE && isWin && !isOpera) + { + str += ' '; + str += ''; + } else { + str += ' -1) { + + imageRawPath = set[0]; + + } else if (key.search(/imageContextPath/i) > -1) { + + imageContextPath = set[0]; + + } else if (key.search(/moniker/i) > -1) { + + moniker = set[0]; + + } else if (key.search(/label/i) > -1) { + + name = set[0]; + + } + + }); + + setProfileName(nameContainerID, name); + setProfileMoniker(monikerContainerID, moniker); + setProfileImage(imageContainerID, imageRawPath, imageContextPath); + +} + + + +function nodeClickedJS(json){ + + var obj = jQuery.parseJSON(json); + + $("#newsLetter").attr("style","visibility:visible"); + $("#authorName").empty().append(obj.name); + $("#works").empty().append(obj.number_of_authored_works); + + /* + * Here obj.url points to the uri of that individual + */ + if(obj.url){ + $("#profileUrl").attr("href", getWellFormedURLs(obj.url, "profile")); + $("#coAuthorshipVisUrl").attr("href", getWellFormedURLs(obj.url, "coauthorship")); + processProfileInformation("", + "profileMoniker", + "profileImage", + jQuery.parseJSON(getWellFormedURLs(obj.url, "profile_info"))); + + } else{ + $("#profileUrl").attr("href","#"); + $("#coAuthorshipVisUrl").attr("href","#"); + } + + $("#coAuthorName").empty().append(obj.name); + + $("#coAuthors").empty().append(obj.num_coauthors); + $("#firstPublication").empty().append((obj.earliest_publication)?obj.earliest_publication+" First Publication":""); + $("#lastPublication").empty().append((obj.latest_publication)?obj.latest_publication+" Last Publication":""); + + // obj.url:the url parameter for node + +} + +function renderSparklineVisualization(visualizationURL) { + + $(document).ready(function() { + + //$("#ego_sparkline").empty().html(''); + + $.ajax({ + url: visualizationURL, + dataType: "html", + success:function(data){ + $("#ego_sparkline").html(data); + + } + }); + + + }); + +} + +function renderCoAuthorshipVisualization() { + + //Version check for the Flash Player that has the ability to start Player + //Product Install (6.0r65) + var hasProductInstall = DetectFlashVer(6, 0, 65); + + //Version check based upon the values defined in globals + var hasRequestedVersion = DetectFlashVer(requiredMajorVersion, requiredMinorVersion, requiredRevision); + + if ( hasProductInstall && !hasRequestedVersion ) { + // DO NOT MODIFY THE FOLLOWING FOUR LINES + // Location visited after installation is complete if installation is + // required + var MMPlayerType = (isIE == true) ? "ActiveX" : "PlugIn"; + var MMredirectURL = window.location; + document.title = document.title.slice(0, 47) + " - Flash Player Installation"; + var MMdoctitle = document.title; + + AC_FL_RunContent( + "src", "playerProductInstall", + "FlashVars", "MMredirectURL="+MMredirectURL+'&MMplayerType='+MMPlayerType+'&MMdoctitle='+MMdoctitle+"", + "width", "600", + "height", "800", + "align", "middle", + "id", "CoAuthor", + "quality", "high", + "bgcolor", "#ffffff", + "name", "CoAuthor", + "allowScriptAccess","sameDomain", + "type", "application/x-shockwave-flash", + "pluginspage", "http://www.adobe.com/go/getflashplayer" + ); + } else if (hasRequestedVersion) { + // if we've detected an acceptable version + // embed the Flash Content SWF when all tests are passed + AC_FL_RunContent( + "src", swfLink, + "flashVars", "graphmlUrl=" + egoCoAuthorshipDataURL, + "width", "600", + "height", "800", + "align", "middle", + "id", "CoAuthor", + "quality", "high", + "bgcolor", "#ffffff", + "name", "CoAuthor", + "allowScriptAccess","sameDomain", + "type", "application/x-shockwave-flash", + "pluginspage", "http://www.adobe.com/go/getflashplayer" + ); + } else { // flash is too old or we can't detect the plugin + var alternateContent = 'Alternate HTML content should be placed here. ' + + 'This content requires the Adobe Flash Player. ' + + 'Get Flash'; + document.write(alternateContent); // insert non-flash content + } + +} \ No newline at end of file diff --git a/webapp/web/js/visualization/personlevel/person_level.js b/webapp/web/js/visualization/personlevel/person_level.js new file mode 100644 index 000000000..20bab7ce6 --- /dev/null +++ b/webapp/web/js/visualization/personlevel/person_level.js @@ -0,0 +1,318 @@ +function getWellFormedURLs(given_uri, type) { + + // general best practice is to put javascript code inside document.ready + // but in this case when i do that the function does not get called + // properly. + // so removing it for now. + + // $(document).ready(function() { + + var finalURL; + + if (type == "coauthorship") { + + finalURL = $.ajax({ + url: contextPath + "/admin/visQuery", + data: ({vis: "utilities", vis_mode: "PERSON_LEVEL_URL", uri: given_uri}), + dataType: "text", + async: false, + success:function(data){ + // console.log("COA - " + data); + } + }).responseText; + + return finalURL; + + + } else if (type == "profile") { + + finalURL = $.ajax({ + url: contextPath + "/admin/visQuery", + data: ({vis: "utilities", vis_mode: "PROFILE_URL", uri: given_uri}), + dataType: "text", + async: false, + success:function(data){ + } + }).responseText; + + return finalURL; + + } else if (type == "image") { + + finalURL = $.ajax({ + url: contextPath + "/admin/visQuery", + data: ({vis: "utilities", vis_mode: "IMAGE_URL", uri: given_uri}), + dataType: "text", + async: false, + success:function(data){ + } + }).responseText; + + return finalURL; + + } else if (type == "profile_info") { + + var profileInfoJSON = $.ajax({ + url: contextPath + "/admin/visQuery", + data: ({vis: "utilities", vis_mode: "PROFILE_INFO", uri: given_uri}), + dataType: "json", + async: false, + success:function(data){ + } + }).responseText; + + return profileInfoJSON; + + } + + // }); +} + +$.fn.image = function(src, successFunc, failureFunc){ + return this.each(function(){ + var profileImage = new Image(); + profileImage.src = src; + profileImage.width = 90; + profileImage.onerror = failureFunc; + profileImage.onload = successFunc; + + + return profileImage; + }); +}; + +function setProfileImage(imageContainerID, rawPath, contextPath) { + + + if (imageContainerID == "") { + return; + } + + var imageLink = contextPath + rawPath; + + var imageContainer = $("#" + imageContainerID); + imageContainer.image(imageLink, + function(){ + imageContainer.empty().append(this); + }, + function(){ + // For performing any action on failure to + // find the image. + imageContainer.empty(); + } + ); + +} + +function setProfileMoniker(monikerContainerID, moniker, doEllipsis) { + + if (monikerContainerID == "") { + return; + } + + var finalDisplayMoniker; + + if (moniker.length > 30 && doEllipsis) { + + finalDisplayMoniker = moniker.substr(0,30) + "..."; + + } else { + + finalDisplayMoniker = moniker; + + } + + $("#" + monikerContainerID).empty().text(finalDisplayMoniker); + $("#" + monikerContainerID).attr('title', moniker); + +} + +function setProfileName(nameContainerID, name) { + + if (nameContainerID == "") { + return; + } + + $("#" + nameContainerID).empty().text(name); + + +} + +function processProfileInformation(nameContainerID, + monikerContainerID, + imageContainerID, + profileInfoJSON, + doMonikerEllipsis) { + + + var name, imageRawPath, imageContextPath, moniker; + + $.each(profileInfoJSON, function(key, set){ + + if (key.search(/imageThumb/i) > -1) { + + imageRawPath = set[0]; + + } else if (key.search(/imageContextPath/i) > -1) { + + imageContextPath = set[0]; + + } else if (key.search(/moniker/i) > -1) { + + moniker = set[0]; + + } else if (key.search(/label/i) > -1) { + + name = set[0]; + + } + + }); + + setProfileName(nameContainerID, name); + setProfileMoniker(monikerContainerID, moniker, doMonikerEllipsis); + setProfileImage(imageContainerID, imageRawPath, imageContextPath); + +} + +function visLoaded(nodes){ + + var jsonedNodes = jQuery.parseJSON(nodes); + + $(document).ready(function() { + createTable("coauthorships_table", "coauth_table_container", jsonedNodes.slice(1)); + }); + +} + +function createTable(tableID, tableContainer, tableData) { + + var table = $(''); + table.attr('id', tableID); + + table.append($(''); + + var row = $(''); + + var authorTH = $(''); + + row.append($('
').html("Co-Authors (.CSV File)")); + + var header = $('
'); + authorTH.html("Author"); + row.append(authorTH); + + row.append($('').html("Publications with
" + $('#ego_label').text())); + + header.append(row); + + table.append(header); + + $.each(tableData, function(i, item){ + + var row = $('
').html(item.name)); + row.append($('').html(item.number_of_authored_works)); + + table.append(row); + + }); + + table.prependTo('#' + tableContainer); + $('#' + tableContainer + " #loadingData").remove(); +} + +function nodeClickedJS(json){ + + var obj = jQuery.parseJSON(json); + + $("#dataPanel").attr("style","visibility:visible"); + $("#authorName").empty().append(obj.name); + $("#works").empty().append(obj.number_of_authored_works); + + /* + * Here obj.url points to the uri of that individual + */ + if(obj.url){ + $("#profileUrl").attr("href", getWellFormedURLs(obj.url, "profile")); + $("#coAuthorshipVisUrl").attr("href", getWellFormedURLs(obj.url, "coauthorship")); + processProfileInformation("", + "profileMoniker", + "profileImage", + jQuery.parseJSON(getWellFormedURLs(obj.url, "profile_info")), + true); + + } else{ + $("#profileUrl").attr("href","#"); + $("#coAuthorshipVisUrl").attr("href","#"); + } + + $("#coAuthorName").empty().append(obj.name); + + $("#coAuthors").empty().append(obj.num_coauthors); + + $("#firstPublication").empty().append(obj.earliest_publication); + (obj.earliest_publication)?$("#fPub").attr("style","visibility:visible"):$("#fPub").attr("style","visibility:hidden"); + $("#lastPublication").empty().append(obj.latest_publication); + (obj.latest_publication)?$("#lPub").attr("style","visibility:visible"):$("#lPub").attr("style","visibility:hidden"); + + // obj.url:the url parameter for node + +} + +function renderCoAuthorshipVisualization() { + + // Version check for the Flash Player that has the ability to start Player + // Product Install (6.0r65) + var hasProductInstall = DetectFlashVer(6, 0, 65); + + // Version check based upon the values defined in globals + var hasRequestedVersion = DetectFlashVer(requiredMajorVersion, requiredMinorVersion, requiredRevision); + + if ( hasProductInstall && !hasRequestedVersion ) { + // DO NOT MODIFY THE FOLLOWING FOUR LINES + // Location visited after installation is complete if installation is + // required + var MMPlayerType = (isIE == true) ? "ActiveX" : "PlugIn"; + var MMredirectURL = window.location; + document.title = document.title.slice(0, 47) + " - Flash Player Installation"; + var MMdoctitle = document.title; + + AC_FL_RunContent( + "src", "playerProductInstall", + "FlashVars", "MMredirectURL="+MMredirectURL+'&MMplayerType='+MMPlayerType+'&MMdoctitle='+MMdoctitle+"", + "width", "600", + "height", "840", + "align", "middle", + "id", "CoAuthor", + "quality", "high", + "bgcolor", "#ffffff", + "name", "CoAuthor", + "allowScriptAccess","sameDomain", + "type", "application/x-shockwave-flash", + "pluginspage", "http://www.adobe.com/go/getflashplayer" + ); + } else if (hasRequestedVersion) { + // if we've detected an acceptable version + // embed the Flash Content SWF when all tests are passed + AC_FL_RunContent( + "src", swfLink, + "flashVars", "graphmlUrl=" + egoCoAuthorshipDataFeederURL, + "width", "600", + "height", "790", + "align", "top", + "id", "CoAuthor", + "quality", "high", + "bgcolor", "#ffffff", + "name", "CoAuthor", + "allowScriptAccess","sameDomain", + "type", "application/x-shockwave-flash", + "pluginspage", "http://www.adobe.com/go/getflashplayer" + ); + } else { // flash is too old or we can't detect the plugin + var alternateContent = 'Alternate HTML content should be placed here. ' + + 'This content requires the Adobe Flash Player. ' + + 'Get Flash'; + document.write(alternateContent); // insert non-flash content + } + +} \ No newline at end of file diff --git a/webapp/web/templates/entity/entityBasic.jsp b/webapp/web/templates/entity/entityBasic.jsp index 5bf7b9e04..7cd191529 100644 --- a/webapp/web/templates/entity/entityBasic.jsp +++ b/webapp/web/templates/entity/entityBasic.jsp @@ -122,6 +122,10 @@ if (VitroRequestPrep.isSelfEditing(request) || LoginFormBean.loggedIn(request, L + + + + <%-- Links --%>