From 00f3e363e5b28a15b285f04c52151712598b643f Mon Sep 17 00:00:00 2001 From: j2blake Date: Wed, 20 Nov 2013 15:50:51 -0500 Subject: [PATCH] VIVO-541 Add functions and formatting to the developer panel. --- webapp/config/example.developer.properties | 40 ++++++- .../impl/logging/RDFServiceLogger.java | 78 +++++++++---- .../FakeApplicationOntologyService.java | 6 + .../services/shortview/ShortViewLogger.java | 47 ++++++++ .../shortview/ShortViewServiceImpl.java | 4 +- .../utils/developer/DeveloperSettings.java | 24 +++- .../customlistview/CustomListViewLogger.java | 38 +++++++ .../customlistview/PropertyListConfig.java | 2 + webapp/web/js/developer/developerPanel.js | 10 +- .../page/partials/developerPanel.ftl | 103 +++++++++++++----- 10 files changed, 288 insertions(+), 64 deletions(-) create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/services/shortview/ShortViewLogger.java create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/customlistview/CustomListViewLogger.java diff --git a/webapp/config/example.developer.properties b/webapp/config/example.developer.properties index 482cecd21..78a1d2a72 100644 --- a/webapp/config/example.developer.properties +++ b/webapp/config/example.developer.properties @@ -32,6 +32,7 @@ # # developer.permitAnonymousControl + #------------------------------------------------------------------------------ # Freemarker #------------------------------------------------------------------------------ @@ -52,6 +53,25 @@ # # developer.defeatFreemarkerCache = true + +#------------------------------------------------------------------------------ +# Page configuration +#------------------------------------------------------------------------------ + +# +# Turn on logging of custom list view configuration files. Each time a property +# uses a list view other than the default, note it in the log. The default is +# 'false'. +# +# developer.pageContents.logCustomListView = true + +# +# Turn on logging of custom short views. Each time an individual uses a short +# view other than the default, note it in the log. The default is 'false'. +# +# developer.pageContents.logCustomShortView = true + + #------------------------------------------------------------------------------ # Internationalization #------------------------------------------------------------------------------ @@ -98,10 +118,18 @@ # developer.loggingRDFService.stackTrace = true # -# If SPARQL query logging is enabled, a regular expression can be used to -# restrict the number of entries that are produced. The expression is -# tested against each line in the (unabridged) stack trace. If the -# expression doesn't match any line in the stack trace, then no log entry -# is made. The default is 'false'. +# If SPARQL query logging is enabled, restrict the number of log entries by +# matching a regular expression against the query string. If the expression +# doesn't match the string, then no log entry is made. The default is "", +# which means no restriction. # -# developer.loggingRDFService.restriction = true +# developer.loggingRDFService.queryRestriction = .* + +# +# If SPARQL query logging is enabled, restrict the number of log entries by +# matching a regular expression against the stack trace. The abridged stack +# trace is concatenated into a single string of fully qualified class names +# and method names. If the expression doesn't match the string, then no log +# entry is made. The default is "", which means no restriction. +# +# developer.loggingRDFService.stackRestriction = .* diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/logging/RDFServiceLogger.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/logging/RDFServiceLogger.java index d7f0ffa7a..c0950e967 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/logging/RDFServiceLogger.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/logging/RDFServiceLogger.java @@ -23,9 +23,12 @@ import edu.cornell.mannlib.vitro.webapp.utils.developer.DeveloperSettings.Keys; * * If not enabled, or if the logging level is insufficient, this does nothing. * - * If enabled, it checks for restrictions. If there is a restriction pattern - * (regular expression), the a log message will only be printed if one of the - * fully-qualified class names in the stack trace matches that pattern. + * If enabled, it checks for restrictions. If there is a restriction on the call + * stack (regular expression), then a log message will only be printed if the + * pattern is found in the concatenated call stack (fully-qualified class names + * and method names). If there is a restriction on the query string (regular + * expression) then a log message will only be printed if the pattern is found + * in the query string. * * If everything passes muster, the constructor will record the time that the * instance was created. @@ -47,7 +50,8 @@ public class RDFServiceLogger implements AutoCloseable { private boolean isEnabled; private boolean traceRequested; - private Pattern restriction; + private Pattern queryStringRestriction; + private Pattern callStackRestriction; private String methodName; private List trace = Collections.emptyList(); @@ -62,7 +66,7 @@ public class RDFServiceLogger implements AutoCloseable { if (isEnabled && log.isInfoEnabled()) { loadStackTrace(); - if (passesRestrictions()) { + if (passesQueryRestriction() && passesStackRestriction()) { this.startTime = System.currentTimeMillis(); } } @@ -72,20 +76,23 @@ public class RDFServiceLogger implements AutoCloseable { DeveloperSettings settings = DeveloperSettings.getBean(ctx); isEnabled = settings.getBoolean(Keys.LOGGING_RDF_ENABLE); traceRequested = settings.getBoolean(Keys.LOGGING_RDF_STACK_TRACE); + queryStringRestriction = patternFromSettings(settings, + Keys.LOGGING_RDF_QUERY_RESTRICTION); + callStackRestriction = patternFromSettings(settings, + Keys.LOGGING_RDF_STACK_RESTRICTION); + } - String restrictionString = settings - .getString(Keys.LOGGING_RDF_RESTRICTION); - if (StringUtils.isBlank(restrictionString)) { - restriction = null; - } else { - try { - restriction = Pattern.compile(restrictionString); - } catch (Exception e) { - log.error("Failed to compile the pattern for " - + Keys.LOGGING_RDF_RESTRICTION + " = " + restriction - + " " + e); - isEnabled = false; - } + private Pattern patternFromSettings(DeveloperSettings settings, Keys key) { + String patternString = settings.getString(key); + if (StringUtils.isBlank(patternString)) { + return null; + } + try { + return Pattern.compile(patternString); + } catch (Exception e) { + log.error("Failed to compile the pattern for " + key + " = " + + patternString + " " + e); + return Pattern.compile("^_____NEVER MATCH_____$"); } } @@ -144,16 +151,39 @@ public class RDFServiceLogger implements AutoCloseable { } } - private boolean passesRestrictions() { - if (restriction == null) { + private boolean passesQueryRestriction() { + if (queryStringRestriction == null) { return true; } - for (StackTraceElement ste : trace) { - if (restriction.matcher(ste.getClassName()).find()) { - return true; + String q = assembleQueryString(); + return queryStringRestriction.matcher(q).find(); + } + + private String assembleQueryString() { + StringBuilder query = new StringBuilder(); + for (Object arg : args) { + if (arg instanceof String) { + query.append((String) arg).append(" "); } } - return false; + return query.deleteCharAt(query.length() - 1).toString(); + } + + private boolean passesStackRestriction() { + if (callStackRestriction == null) { + return true; + } + String q = assembleCallStackString(); + return callStackRestriction.matcher(q).find(); + } + + private String assembleCallStackString() { + StringBuilder stack = new StringBuilder(); + for (StackTraceElement ste : trace) { + stack.append(ste.getClassName()).append(" ") + .append(ste.getMethodName()).append(" "); + } + return stack.deleteCharAt(stack.length() - 1).toString(); } @Override diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/services/shortview/FakeApplicationOntologyService.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/services/shortview/FakeApplicationOntologyService.java index 92fcc8ae7..a650620cc 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/services/shortview/FakeApplicationOntologyService.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/services/shortview/FakeApplicationOntologyService.java @@ -380,6 +380,12 @@ public class FakeApplicationOntologyService { return dataGetters; } + @Override + public String toString() { + return "[template=" + templateName + ", dataGetters=" + dataGetters + + "]"; + } + } /** The view specifications that we read from the config file. */ diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/services/shortview/ShortViewLogger.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/services/shortview/ShortViewLogger.java new file mode 100644 index 000000000..220185445 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/services/shortview/ShortViewLogger.java @@ -0,0 +1,47 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.services.shortview; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import edu.cornell.mannlib.vitro.webapp.beans.Individual; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.services.shortview.FakeApplicationOntologyService.TemplateAndDataGetters; +import edu.cornell.mannlib.vitro.webapp.utils.developer.DeveloperSettings; +import edu.cornell.mannlib.vitro.webapp.utils.developer.DeveloperSettings.Keys; + +/** + * When we use a short view other than the default, log it. + */ +public class ShortViewLogger { + private static final Log log = LogFactory.getLog(ShortViewLogger.class); + + public static void log(VitroRequest vreq, String contextName, + Individual individual, String classUri, TemplateAndDataGetters tdg) { + if (isLogging(vreq)) { + log.info("Using custom short view in " + contextName + " because '" + + individual.getURI() + "' (" + individual.getLabel() + + ") has type '" + classUri + "': " + tdg); + } + } + + public static void log(VitroRequest vreq, String contextName, + Individual individual) { + if (isLogging(vreq)) { + log.info("Using default short view in " + contextName + " for '" + + individual.getURI() + "' (" + individual.getLabel() + ")"); + } + } + + private static boolean isLogging(VitroRequest vreq) { + if (!log.isInfoEnabled()) { + return false; + } + DeveloperSettings settings = DeveloperSettings.getBean(vreq); + return settings.getBoolean(Keys.ENABLED) + && settings + .getBoolean(Keys.PAGE_CONTENTS_LOG_CUSTOM_SHORT_VIEW); + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/services/shortview/ShortViewServiceImpl.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/services/shortview/ShortViewServiceImpl.java index 8e18208a0..c072f866e 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/services/shortview/ShortViewServiceImpl.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/services/shortview/ShortViewServiceImpl.java @@ -15,9 +15,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import edu.cornell.mannlib.vitro.webapp.beans.Individual; -import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatement; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; -import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; import edu.cornell.mannlib.vitro.webapp.services.freemarker.FreemarkerProcessingService; import edu.cornell.mannlib.vitro.webapp.services.freemarker.FreemarkerProcessingService.TemplateParsingException; import edu.cornell.mannlib.vitro.webapp.services.freemarker.FreemarkerProcessingService.TemplateProcessingException; @@ -116,11 +114,13 @@ public class ShortViewServiceImpl implements ShortViewService { TemplateAndDataGetters tdg = faker.getShortViewProperties(vreq, individual, classUri, svContext.name()); if (tdg != null) { + ShortViewLogger.log(vreq, svContext.name(), individual, classUri, tdg); return tdg; } } // Didn't find one? Use the default values. + ShortViewLogger.log(vreq, svContext.name(), individual); return new TemplateAndDataGetters(svContext.getDefaultTemplateName()); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/developer/DeveloperSettings.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/developer/DeveloperSettings.java index 822e434e4..169491372 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/developer/DeveloperSettings.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/developer/DeveloperSettings.java @@ -82,9 +82,29 @@ public class DeveloperSettings { * Don't log with the LoggingRDFService unless the calling stack meets * this restriction. */ - LOGGING_RDF_RESTRICTION("developer.loggingRDFService.restriction", - false); + LOGGING_RDF_QUERY_RESTRICTION( + "developer.loggingRDFService.queryRestriction", false), + /** + * Don't log with the LoggingRDFService unless the calling stack meets + * this restriction. + */ + LOGGING_RDF_STACK_RESTRICTION( + "developer.loggingRDFService.stackRestriction", false), + + /** + * Tell the CustomListViewLogger to note the use of non-default custom + * list views. + */ + PAGE_CONTENTS_LOG_CUSTOM_LIST_VIEW( + "developer.pageContents.logCustomListView", true), + + /** + * Tell the ShortViewLogger to note the use of non-default short views. + */ + PAGE_CONTENTS_LOG_CUSTOM_SHORT_VIEW( + "developer.pageContents.logCustomShortView", true); + private final String propertyName; private final String elementId; private final boolean bool; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/customlistview/CustomListViewLogger.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/customlistview/CustomListViewLogger.java new file mode 100644 index 000000000..2509af61c --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/customlistview/CustomListViewLogger.java @@ -0,0 +1,38 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.web.templatemodels.customlistview; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.utils.developer.DeveloperSettings; +import edu.cornell.mannlib.vitro.webapp.utils.developer.DeveloperSettings.Keys; + +/** + * If enabled in the developer settings (and log levels), log every non-default + * custom list view. + */ +public class CustomListViewLogger { + private static final Log log = LogFactory + .getLog(CustomListViewLogger.class); + + public static void log(VitroRequest vreq, ObjectProperty op, + String configFileName) { + if (isLogging(vreq)) { + log.info("Using list view: '" + configFileName + "' for " + + op.getURI() + " (" + op.getLabel() + ")"); + + } + } + + private static boolean isLogging(VitroRequest vreq) { + if (!log.isInfoEnabled()) { + return false; + } + DeveloperSettings settings = DeveloperSettings.getBean(vreq); + return settings.getBoolean(Keys.ENABLED) + && settings.getBoolean(Keys.PAGE_CONTENTS_LOG_CUSTOM_LIST_VIEW); + } +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/customlistview/PropertyListConfig.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/customlistview/PropertyListConfig.java index 651114aff..ad645f393 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/customlistview/PropertyListConfig.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/customlistview/PropertyListConfig.java @@ -61,6 +61,8 @@ public class PropertyListConfig { String configFileName = wadf.getObjectPropertyDao().getCustomListViewConfigFileName(op); if (configFileName == null) { // no custom config; use default config configFileName = DEFAULT_CONFIG_FILE_NAME; + } else { + CustomListViewLogger.log(vreq, op, configFileName); } log.debug("Using list view config file " + configFileName + " for object property " + op.getURI()); diff --git a/webapp/web/js/developer/developerPanel.js b/webapp/web/js/developer/developerPanel.js index 8c0c9a2b1..f7d881709 100644 --- a/webapp/web/js/developer/developerPanel.js +++ b/webapp/web/js/developer/developerPanel.js @@ -42,13 +42,16 @@ function DeveloperPanel(developerAjaxUrl) { var developerEnabled = document.getElementById("developerEnabled").checked; document.getElementById("developerDefeatFreemarkerCache").disabled = !developerEnabled; document.getElementById("developerInsertFreemarkerDelimiters").disabled = !developerEnabled; + document.getElementById("developerPageContentsLogCustomListView").disabled = !developerEnabled; + document.getElementById("developerPageContentsLogCustomShortView").disabled = !developerEnabled; document.getElementById("developerI18nDefeatCache").disabled = !developerEnabled; document.getElementById("developerI18nLogStringRequests").disabled = !developerEnabled; document.getElementById("developerLoggingRDFServiceEnable").disabled = !developerEnabled; var rdfServiceEnabled = developerEnabled && document.getElementById("developerLoggingRDFServiceEnable").checked; document.getElementById("developerLoggingRDFServiceStackTrace").disabled = !rdfServiceEnabled; - document.getElementById("developerLoggingRDFServiceRestriction").disabled = !rdfServiceEnabled; + document.getElementById("developerLoggingRDFServiceQueryRestriction").disabled = !rdfServiceEnabled; + document.getElementById("developerLoggingRDFServiceStackRestriction").disabled = !rdfServiceEnabled; } function collectFormData() { @@ -56,11 +59,14 @@ function DeveloperPanel(developerAjaxUrl) { getCheckbox("developerEnabled", data); getCheckbox("developerDefeatFreemarkerCache", data); getCheckbox("developerInsertFreemarkerDelimiters", data); + getCheckbox("developerPageContentsLogCustomListView", data); + getCheckbox("developerPageContentsLogCustomShortView", data); getCheckbox("developerI18nDefeatCache", data); getCheckbox("developerI18nLogStringRequests", data); getCheckbox("developerLoggingRDFServiceEnable", data); getCheckbox("developerLoggingRDFServiceStackTrace", data); - getText("developerLoggingRDFServiceRestriction", data); + getText("developerLoggingRDFServiceQueryRestriction", data); + getText("developerLoggingRDFServiceStackRestriction", data); return data; } diff --git a/webapp/web/templates/freemarker/page/partials/developerPanel.ftl b/webapp/web/templates/freemarker/page/partials/developerPanel.ftl index 533de3d2c..a8b429f26 100644 --- a/webapp/web/templates/freemarker/page/partials/developerPanel.ftl +++ b/webapp/web/templates/freemarker/page/partials/developerPanel.ftl @@ -6,7 +6,7 @@ <#macro showTextbox key> - + @@ -14,17 +14,40 @@ div.developer { background-color: #f7dd8a; padding: 0px 10px 0px 10px; - font-size: small; font-variant: small-caps; } div.developer #developerPanelBody { display: none; + line-height: 1em; + font-size: small; } -div.developer .container { - border: thin groove black +div.developer div.devleft { + width: 49% } + +div.developer div.devright { + float: right; + width: 49% +} + +div.developer div.container { + border: thin groove black; + padding: 3px 10px 0px 10px; + margin: 3px 0px 3px 0px; +} + +div.developer div.within { + padding-left: 1em; +} + +div.developer input[type="text"] { + padding: 2px 10px 2px 10px; + line-height: 1em; + margin: 2px 2px 2px 2px; + } + <#if !settings.developerEnabled> @@ -38,40 +61,26 @@ div.developer .container { (click for Options)
-
+
- +
+ +
- Freemarker templates + Page configuration
-
- SPARQL Queries - - - -
-
Language support
+
+ +
+
+ Freemarker templates + + +
+
+ SPARQL Queries + +
+ + + +
+
+
+ +
- +
\ No newline at end of file