From 0b43a4409715cd0f7a549ae69c8835c3302b35b2 Mon Sep 17 00:00:00 2001 From: j2blake Date: Mon, 25 Nov 2013 11:48:11 -0500 Subject: [PATCH 01/14] VIVO-522 fix memory leak in FreemarkerConfigurationImpl --- .../config/FreemarkerConfigurationImpl.java | 47 ++++++++++++++----- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/freemarker/config/FreemarkerConfigurationImpl.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/freemarker/config/FreemarkerConfigurationImpl.java index 617a09f6c..7d2c05c9d 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/freemarker/config/FreemarkerConfigurationImpl.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/freemarker/config/FreemarkerConfigurationImpl.java @@ -3,6 +3,7 @@ package edu.cornell.mannlib.vitro.webapp.freemarker.config; import java.io.IOException; +import java.lang.ref.WeakReference; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -35,28 +36,52 @@ import freemarker.template.utility.DeepUnwrap; * Extend the Freemarker Configuration class to include some information that is * particular to the current request. * - * Takes advantage of the fact that each servlet request runs in a separate - * thread. Stores the request-based information in a ThreadLocal. Override any - * methods that should return that information instead of (or in addition to) - * the common info. + * A reference to the current request is not always available to the Freemarker + * Configuration, so we take advantage of the fact that each request runs in a + * separate thread, and store a reference to that request in a ThreadLocal + * object. + * + * Then, we override any methods that should return that request-based + * information instead of (or in addition to) the common info. * * Only the getters are overridden, not the setters. So if you call * setAllSharedVariables(), for example, it will have no effect on the * request-based information. + * + * Notice that the reference to the current request is actually stored through a + * WeakReference. This is because the ThreadLocal will not be cleared when the + * webapp is stopped, so none of the references from that ThreadLocal are + * eligible for garbage collection. If any of those references is an instance of + * a class that is loaded by the webapp, then the webapp ClassLoader is not + * eligible for garbage collection. This would be a huge memory leak. + * + * Thanks to the WeakReference, the request is eligible for garbage collection + * if nothing else refers to it. In theory, this means that the WeakReference + * could return a null, but if the garbage collector has taken the request, then + * who is invoking this object? */ public class FreemarkerConfigurationImpl extends Configuration { private static final Log log = LogFactory .getLog(FreemarkerConfigurationImpl.class); - private final ThreadLocal rbiRef = new ThreadLocal<>(); + private static final String ATTRIBUTE_NAME = RequestBasedInformation.class + .getName(); + + private final ThreadLocal> reqRef = new ThreadLocal<>(); void setRequestInfo(HttpServletRequest req) { - rbiRef.set(new RequestBasedInformation(req, this)); + reqRef.set(new WeakReference<>(req)); + req.setAttribute(ATTRIBUTE_NAME, new RequestBasedInformation(req, this)); + } + + private RequestBasedInformation getRequestInfo() { + HttpServletRequest req = reqRef.get().get(); + return (RequestBasedInformation) req.getAttribute(ATTRIBUTE_NAME); } @Override public Object getCustomAttribute(String name) { - Map attribs = rbiRef.get().getCustomAttributes(); + Map attribs = getRequestInfo().getCustomAttributes(); if (attribs.containsKey(name)) { return attribs.get(name); } else { @@ -66,13 +91,13 @@ public class FreemarkerConfigurationImpl extends Configuration { @Override public String[] getCustomAttributeNames() { - Set rbiNames = rbiRef.get().getCustomAttributes().keySet(); + Set rbiNames = getRequestInfo().getCustomAttributes().keySet(); return joinNames(rbiNames, super.getCustomAttributeNames()); } @Override public TemplateModel getSharedVariable(String name) { - Map vars = rbiRef.get().getSharedVariables(); + Map vars = getRequestInfo().getSharedVariables(); if (vars.containsKey(name)) { return vars.get(name); } else { @@ -82,7 +107,7 @@ public class FreemarkerConfigurationImpl extends Configuration { @Override public Set getSharedVariableNames() { - Set rbiNames = rbiRef.get().getSharedVariables().keySet(); + Set rbiNames = getRequestInfo().getSharedVariables().keySet(); @SuppressWarnings("unchecked") Set superNames = super.getSharedVariableNames(); @@ -94,7 +119,7 @@ public class FreemarkerConfigurationImpl extends Configuration { @Override public Locale getLocale() { - return rbiRef.get().getReq().getLocale(); + return getRequestInfo().getReq().getLocale(); } private String[] joinNames(Set nameSet, String[] nameArray) { From 70298026ea242c2190198f6927235a1a08233468 Mon Sep 17 00:00:00 2001 From: j2blake Date: Mon, 25 Nov 2013 12:31:51 -0500 Subject: [PATCH 02/14] Reduce warning messages in unit tests. We get a warning on any attempt to use anything that may be affected by DeveloperSettings, because DeveloperSetting tries to use ConfigurationProperties to find its properties file. We could avoid this by requiring the use of a ConfigurationPropertiesStub, but it seems to make more sense to routinely create a DeveloperSettingsStub on each ServletContextStub. --- .../utils/developer/DeveloperSettings.java | 4 +-- .../developer/DeveloperSettingsStub.java | 33 +++++++++++++++++++ .../javax/servlet/ServletContextStub.java | 7 ++++ 3 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/utils/developer/DeveloperSettingsStub.java 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 169491372..f883281f9 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 @@ -179,7 +179,7 @@ public class DeveloperSettings { // The factory // ---------------------------------------------------------------------- - private static final String ATTRIBUTE_NAME = DeveloperSettings.class + protected static final String ATTRIBUTE_NAME = DeveloperSettings.class .getName(); public static DeveloperSettings getBean(HttpServletRequest req) { @@ -203,7 +203,7 @@ public class DeveloperSettings { private final Map settings = new EnumMap<>(Keys.class); - private DeveloperSettings(ServletContext ctx) { + protected DeveloperSettings(ServletContext ctx) { updateFromFile(ctx); } diff --git a/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/utils/developer/DeveloperSettingsStub.java b/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/utils/developer/DeveloperSettingsStub.java new file mode 100644 index 000000000..6e2871596 --- /dev/null +++ b/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/utils/developer/DeveloperSettingsStub.java @@ -0,0 +1,33 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package stubs.edu.cornell.mannlib.vitro.webapp.utils.developer; + +import javax.servlet.ServletContext; + +import edu.cornell.mannlib.vitro.webapp.utils.developer.DeveloperSettings; + +/** + * Do everything that a standard DeveloperSettings would do, except loading from + * a properties file. + * + * That way, we don't require ConfigurationProperties to find the Vitro home + * directory, so we don't throw errors if there is no ConfigurationProperties. + */ +public class DeveloperSettingsStub extends DeveloperSettings { + /** + * Factory method. Create the stub and set it into the ServletContext. + */ + public static void set(ServletContext ctx) { + ctx.setAttribute(ATTRIBUTE_NAME, new DeveloperSettingsStub(ctx)); + } + + protected DeveloperSettingsStub(ServletContext ctx) { + super(ctx); + } + + @Override + protected void updateFromFile(ServletContext ctx) { + // Don't bother. + } + +} diff --git a/webapp/test/stubs/javax/servlet/ServletContextStub.java b/webapp/test/stubs/javax/servlet/ServletContextStub.java index 46e592d60..eb1e5eab7 100644 --- a/webapp/test/stubs/javax/servlet/ServletContextStub.java +++ b/webapp/test/stubs/javax/servlet/ServletContextStub.java @@ -21,6 +21,8 @@ import javax.servlet.ServletException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import stubs.edu.cornell.mannlib.vitro.webapp.utils.developer.DeveloperSettingsStub; + /** * A simple stand-in for the {@link ServletContext}, for use in unit tests. */ @@ -36,6 +38,11 @@ public class ServletContextStub implements ServletContext { private final Map mockResources = new HashMap(); private final Map realPaths = new HashMap(); + public ServletContextStub() { + // Assume that unit tests won't want to use Developer mode. + DeveloperSettingsStub.set(this); + } + public void setContextPath(String contextPath) { if (contextPath == null) { throw new NullPointerException("contextPath may not be null."); From 0e2ae52c5a695f162c8797bbaa54ef74e6e32ec2 Mon Sep 17 00:00:00 2001 From: brianjlowe Date: Mon, 25 Nov 2013 16:17:19 -0500 Subject: [PATCH 03/14] fixes duplication bug when a faux has the same label as its "parent" --- .../individual/GroupedPropertyList.java | 80 ++++--------------- 1 file changed, 17 insertions(+), 63 deletions(-) diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/GroupedPropertyList.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/GroupedPropertyList.java index 1240285c3..8235202a6 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/GroupedPropertyList.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/GroupedPropertyList.java @@ -81,7 +81,7 @@ public class GroupedPropertyList extends BaseTemplateModel { // save applicable ranges before deduping to filter later populatedObjectPropertyList = dedupe(populatedObjectPropertyList); - + Collection additions = ApplicationConfigurationOntologyUtils .getAdditionalFauxSubpropertiesForList( populatedObjectPropertyList, subject, vreq); @@ -121,13 +121,7 @@ public class GroupedPropertyList extends BaseTemplateModel { if (editing) { mergeAllPossibleDataProperties(propertyList); } - -// Not currently necessary since the language-specific version is now added -// during the merge -// if (editing) { -// propertyList = correctLanguageForProperties(propertyList); -// } - + sort(propertyList); // Put the list into groups @@ -176,35 +170,6 @@ public class GroupedPropertyList extends BaseTemplateModel { return filteredAdditions; } - // Use the language-filtering WebappDaoFactory to get the right version of - // each property. When editing, the methods that add to the property list - // are blissfully (and intentionally) language-unaware. - private List correctLanguageForProperties(List properties) { - List languageCorrectedProps = new ArrayList(); - for (Property p : properties) { - Property correctedProp = null; - if (p instanceof ObjectProperty) { - ObjectProperty op = (ObjectProperty) p; - correctedProp = wdf.getObjectPropertyDao() - .getObjectPropertyByURIs(op.getURI(), - op.getDomainVClassURI(), op.getRangeVClassURI()); - } else if (p instanceof DataProperty) { - correctedProp = wdf.getDataPropertyDao() - .getDataPropertyByURI(((DataProperty) p).getURI()); - } else { - log.warn("Ignoring " + p.getURI() + " which is neither an " + - "ObjectProperty nor a DatatypeProperty."); - } - if (correctedProp != null) { - languageCorrectedProps.add(correctedProp); - } else { - log.error("Unable to retrieve property " + p.getURI() + - " using the WebappDaoFactory associated with the request."); - } - } - return languageCorrectedProps; - } - // It's possible that an object property retrieved in the call to getPopulatedObjectPropertyList() // is now empty of statements, because if not editing, some statements without a linked individual // are not retrieved by the query. (See elements in queries.) @@ -281,16 +246,17 @@ public class GroupedPropertyList extends BaseTemplateModel { continue; } boolean addToList = true; - int opIndex = 0; for(ObjectProperty op : populatedObjectPropertyList) { - if(redundant(op, piOp)) { + RedundancyReason reason = redundant(op, piOp); + if(reason != null) { addToList = false; - if (moreRestrictiveRange(piOp, op, wadf)) { - propertyList = replaceOpWithPiOpInList(piOp, op, opIndex, propertyList); + if (reason == RedundancyReason.LABEL_AND_URI_MATCH + && moreRestrictiveRange(piOp, op, wadf)) { + op.setRangeVClassURI(piOp.getRangeVClassURI()); + op.setRangeVClass(piOp.getRangeVClass()); } break; } - opIndex++; } if(addToList) { propertyList.add(piOp); @@ -315,6 +281,10 @@ public class GroupedPropertyList extends BaseTemplateModel { return propertyList; } + private enum RedundancyReason { + LABEL_AND_URI_MATCH, LABEL_URI_DOMAIN_AND_RANGE_MATCH + } + private boolean moreRestrictiveRange(ObjectProperty piOp, ObjectProperty op, WebappDaoFactory wadf) { if(piOp.getRangeVClassURI() == null) { @@ -327,25 +297,9 @@ public class GroupedPropertyList extends BaseTemplateModel { } } - private List replaceOpWithPiOpInList(ObjectProperty piOp, - ObjectProperty op, int opIndex, List propertyList) { - - List returnList = new ArrayList(); - int index = 0; - for(Property p : propertyList) { - if(index == opIndex /* p.equals(op) */) { - returnList.add(piOp); - } else { - returnList.add(p); - } - index++; - } - return returnList; - } - - private boolean redundant(ObjectProperty op, ObjectProperty op2) { + private RedundancyReason redundant(ObjectProperty op, ObjectProperty op2) { if (op2.getURI() == null) { - return false; + return null; } boolean uriMatches = (op.getURI() != null && op.getURI().equals(op2.getURI())); @@ -360,7 +314,7 @@ public class GroupedPropertyList extends BaseTemplateModel { labelMatches = true; } if(uriMatches && labelMatches) { - return true; + return RedundancyReason.LABEL_AND_URI_MATCH; } if(op.getDomainVClassURI() == null) { if(op2.getDomainVClassURI() == null) { @@ -377,9 +331,9 @@ public class GroupedPropertyList extends BaseTemplateModel { rangeMatches = true; } if (uriMatches && domainMatches && rangeMatches) { - return true; + return RedundancyReason.LABEL_URI_DOMAIN_AND_RANGE_MATCH; } - return false; + return null; } private void addObjectPropertyToPropertyList(String propertyUri, String domainUri, String rangeUri, From 27c8d4410e48cb21e3a304321dbb9ce5508a7a05 Mon Sep 17 00:00:00 2001 From: j2blake Date: Tue, 26 Nov 2013 10:22:37 -0500 Subject: [PATCH 04/14] VIVO-530 Fix logic bug in authorization Required actions from the DataGetters were being ignored. --- .../vitro/webapp/controller/freemarker/PageController.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/PageController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/PageController.java index 785bb031b..a98434bc0 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/PageController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/PageController.java @@ -58,10 +58,12 @@ public class PageController extends FreemarkerHttpServlet{ if( pageActs == null && dgActs == null){ return Actions.AUTHORIZED; - }else if( pageActs == null && dgActs != null ){ + }else if( pageActs == null ){ return dgActs; + }else if( dgActs == null ){ + return pageActs; }else{ - return pageActs; + return pageActs.and(dgActs); } } catch (Exception e) { From 60102fbf28f1ddc57da4c74d602a59db7d6dd564 Mon Sep 17 00:00:00 2001 From: j2blake Date: Tue, 26 Nov 2013 16:02:52 -0500 Subject: [PATCH 05/14] VIVO-530 Adjust SPARQL Update API --- .../utilities/testrunner/test-user-model.owl | 116 +++++----- .../rdf/auth/everytime/permission_config.n3 | 9 +- .../auth/permissions/SimplePermission.java | 7 +- .../webapp/auth/policy/PolicyHelper.java | 6 +- .../api/SparqlUpdateApiController.java | 201 ++++++++++++++++++ .../controller/freemarker/PageController.java | 3 +- .../webapp/servlet/setup/ThemeInfoSetup.java | 4 +- .../webapp/utils/dataGetter/SparqlUpdate.java | 96 --------- webapp/web/WEB-INF/web.xml | 10 + .../body/menupage/page-sparqlUpdateTest.ftl | 12 -- 10 files changed, 286 insertions(+), 178 deletions(-) create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/controller/api/SparqlUpdateApiController.java delete mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/SparqlUpdate.java delete mode 100644 webapp/web/templates/freemarker/body/menupage/page-sparqlUpdateTest.ftl diff --git a/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/test-user-model.owl b/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/test-user-model.owl index a0acf6afa..a84b13707 100644 --- a/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/test-user-model.owl +++ b/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/test-user-model.owl @@ -1,58 +1,58 @@ - - - - - testAdmin@cornell.edu - testAdmin - Test - Admin - DC647EB65E6711E155375218212B3964 - ACTIVE - 1 - 0 - - - - - johnCurator@cornell.edu - johnCurator - John - Curator - DC647EB65E6711E155375218212B3964 - ACTIVE - 1 - 0 - - - - - sallyEditor@cornell.edu - sallyEditor - Sally - Editor - DC647EB65E6711E155375218212B3964 - ACTIVE - 1 - 0 - - - - - joeUser@cornell.edu - joeUser - Joe - User - DC647EB65E6711E155375218212B3964 - ACTIVE - 1 - 0 - - - - + + + + + testAdmin@cornell.edu + testAdmin + Test + Admin + DC647EB65E6711E155375218212B3964 + ACTIVE + 1 + 0 + + + + + johnCurator@cornell.edu + johnCurator + John + Curator + DC647EB65E6711E155375218212B3964 + ACTIVE + 1 + 0 + + + + + sallyEditor@cornell.edu + sallyEditor + Sally + Editor + DC647EB65E6711E155375218212B3964 + ACTIVE + 1 + 0 + + + + + joeUser@cornell.edu + joeUser + Joe + User + DC647EB65E6711E155375218212B3964 + ACTIVE + 1 + 0 + + + + diff --git a/webapp/rdf/auth/everytime/permission_config.n3 b/webapp/rdf/auth/everytime/permission_config.n3 index c4a88018a..e0b1c1960 100644 --- a/webapp/rdf/auth/everytime/permission_config.n3 +++ b/webapp/rdf/auth/everytime/permission_config.n3 @@ -12,6 +12,7 @@ auth:ADMIN # ADMIN-only permissions auth:hasPermission simplePermission:AccessSpecialDataModels ; + auth:hasPermission simplePermission:EnableDeveloperPanel ; auth:hasPermission simplePermission:LoginDuringMaintenance ; auth:hasPermission simplePermission:ManageMenus ; auth:hasPermission simplePermission:ManageProxies ; @@ -23,8 +24,12 @@ auth:ADMIN auth:hasPermission simplePermission:UseAdvancedDataToolsPages ; auth:hasPermission simplePermission:UseMiscellaneousAdminPages ; auth:hasPermission simplePermission:UseSparqlQueryPage ; - auth:hasPermission simplePermission:PageViewableAdmin ; - auth:hasPermission simplePermission:EnableDeveloperPanel ; + auth:hasPermission simplePermission:PageViewableAdmin ; + + # Uncomment the following permission line to enable the SPARQL update API. + # Before enabling, be sure that the URL api/sparqlUpdate is secured by SSH, + # so passwords will not be sent in clear text. +# auth:hasPermission simplePermission:UseSparqlUpdateApi ; # permissions for CURATOR and above. auth:hasPermission simplePermission:EditOntology ; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/permissions/SimplePermission.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/permissions/SimplePermission.java index 33c609c5b..0484638bd 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/permissions/SimplePermission.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/permissions/SimplePermission.java @@ -38,6 +38,8 @@ public class SimplePermission extends Permission { NAMESPACE + "EditOwnAccount"); public static final SimplePermission EDIT_SITE_INFORMATION = new SimplePermission( NAMESPACE + "EditSiteInformation"); + public static final SimplePermission ENABLE_DEVELOPER_PANEL = new SimplePermission( + NAMESPACE + "EnableDeveloperPanel"); public static final SimplePermission LOGIN_DURING_MAINTENANCE = new SimplePermission( NAMESPACE + "LoginDuringMaintenance"); public static final SimplePermission MANAGE_MENUS = new SimplePermission( @@ -76,9 +78,8 @@ public class SimplePermission extends Permission { NAMESPACE + "UseAdvancedDataToolsPages"); public static final SimplePermission USE_SPARQL_QUERY_PAGE = new SimplePermission( NAMESPACE + "UseSparqlQueryPage"); - public static final SimplePermission ENABLE_DEVELOPER_PANEL = new SimplePermission( - NAMESPACE + "EnableDeveloperPanel"); - + public static final SimplePermission USE_SPARQL_UPDATE_API = new SimplePermission( + NAMESPACE + "UseSparqlUpdateApi"); // ---------------------------------------------------------------------- // These instances are "catch all" permissions to cover poorly defined diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/PolicyHelper.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/PolicyHelper.java index d8a606efb..b1250a855 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/PolicyHelper.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/PolicyHelper.java @@ -83,11 +83,11 @@ public class PolicyHelper { } try{ - Authenticator basicAuth = new BasicAuthenticator(req); - UserAccount user = basicAuth.getAccountForInternalAuth( email ); + Authenticator auth = Authenticator.getInstance(req); + UserAccount user = auth.getAccountForInternalAuth( email ); log.debug("userAccount is " + user==null?"null":user.getUri() ); - if( ! basicAuth.isCurrentPassword( user, password ) ){ + if( ! auth.isCurrentPassword( user, password ) ){ log.debug(String.format("UNAUTHORIZED, password not accepted for %s, account URI: %s", user.getEmailAddress(), user.getUri())); return false; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/api/SparqlUpdateApiController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/api/SparqlUpdateApiController.java new file mode 100644 index 000000000..60a0e6af0 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/api/SparqlUpdateApiController.java @@ -0,0 +1,201 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.controller.api; + +import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST; +import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN; +import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR; +import static javax.servlet.http.HttpServletResponse.SC_OK; + +import java.io.IOException; +import java.io.PrintWriter; + +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import com.hp.hpl.jena.query.Dataset; +import com.hp.hpl.jena.update.GraphStore; +import com.hp.hpl.jena.update.GraphStoreFactory; +import com.hp.hpl.jena.update.UpdateAction; +import com.hp.hpl.jena.update.UpdateFactory; +import com.hp.hpl.jena.update.UpdateRequest; + +import edu.cornell.mannlib.vitro.webapp.auth.permissions.SimplePermission; +import edu.cornell.mannlib.vitro.webapp.auth.policy.PolicyHelper; +import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.Actions; +import edu.cornell.mannlib.vitro.webapp.beans.UserAccount; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.controller.authenticate.Authenticator; +import edu.cornell.mannlib.vitro.webapp.dao.jena.RDFServiceDataset; +import edu.cornell.mannlib.vitro.webapp.search.indexing.IndexBuilder; + +/** + * This extends HttpServlet instead of VitroHttpServlet because we want to have + * full control over the response: + *
    + *
  • No redirecting to the login page if not authorized
  • + *
  • No redirecting to the home page on insufficient authorization
  • + *
  • No support for GET or HEAD requests, only POST.
  • + *
+ * + * So these responses will be produced: + * + *
+ * 200 Success
+ * 400 Failed to parse SPARQL update
+ * 400 SPARQL update must specify a GRAPH URI.
+ * 403 username/password combination is not valid
+ * 403 Account is not authorized
+ * 405 Method not allowed
+ * 500 Unknown error
+ * 
+ */ +public class SparqlUpdateApiController extends HttpServlet { + private static final Log log = LogFactory + .getLog(SparqlUpdateApiController.class); + + private static final Actions REQUIRED_ACTIONS = SimplePermission.USE_SPARQL_UPDATE_API.ACTIONS; + + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + try { + checkAuthorization(req); + UpdateRequest parsed = parseUpdateString(req); + executeUpdate(req, parsed); + do200response(resp); + } catch (AuthException e) { + do403response(resp, e); + } catch (ParseException e) { + do400response(resp, e); + } catch (Exception e) { + do500response(resp, e); + } + } + + private void checkAuthorization(HttpServletRequest req) + throws AuthException { + String email = req.getParameter("email"); + String password = req.getParameter("password"); + + Authenticator auth = Authenticator.getInstance(req); + UserAccount account = auth.getAccountForInternalAuth(email); + if (!auth.isCurrentPassword(account, password)) { + log.debug("Invalid: '" + email + "'/'" + password + "'"); + throw new AuthException("email/password combination is not valid"); + } + + if (!PolicyHelper.isAuthorizedForActions(req, email, password, + REQUIRED_ACTIONS)) { + log.debug("Not authorized: '" + email + "'"); + throw new AuthException("Account is not authorized"); + } + + log.debug("Authorized for '" + email + "'"); + } + + private UpdateRequest parseUpdateString(HttpServletRequest req) + throws ParseException { + String update = req.getParameter("update"); + if (StringUtils.isBlank(update)) { + log.debug("No update parameter."); + throw new ParseException("No 'update' parameter."); + } + + if (!StringUtils.containsIgnoreCase(update, "GRAPH")) { + if (log.isDebugEnabled()) { + log.debug("No GRAPH uri in '" + update + "'"); + } + throw new ParseException("SPARQL update must specify a GRAPH URI."); + } + + try { + return UpdateFactory.create(update); + } catch (Exception e) { + log.debug("Problem parsing", e); + throw new ParseException("Failed to parse SPARQL update", e); + } + } + + private void executeUpdate(HttpServletRequest req, UpdateRequest parsed) { + ServletContext ctx = req.getSession().getServletContext(); + VitroRequest vreq = new VitroRequest(req); + + IndexBuilder.getBuilder(ctx).pause(); + try { + Dataset ds = new RDFServiceDataset(vreq.getUnfilteredRDFService()); + GraphStore graphStore = GraphStoreFactory.create(ds); + UpdateAction.execute(parsed, graphStore); + } finally { + IndexBuilder.getBuilder(ctx).unpause(); + } + } + + private void do200response(HttpServletResponse resp) throws IOException { + doResponse(resp, SC_OK, "SPARQL update accepted."); + } + + private void do403response(HttpServletResponse resp, AuthException e) + throws IOException { + doResponse(resp, SC_FORBIDDEN, e.getMessage()); + } + + private void do400response(HttpServletResponse resp, ParseException e) + throws IOException { + if (e.getCause() == null) { + doResponse(resp, SC_BAD_REQUEST, e.getMessage()); + } else { + doResponse(resp, SC_BAD_REQUEST, e.getMessage(), e.getCause()); + } + } + + private void do500response(HttpServletResponse resp, Exception e) + throws IOException { + doResponse(resp, SC_INTERNAL_SERVER_ERROR, "Unknown error", e); + } + + private void doResponse(HttpServletResponse resp, int statusCode, + String message) throws IOException { + resp.setStatus(statusCode); + PrintWriter writer = resp.getWriter(); + writer.println("

" + statusCode + " " + message + "

"); + } + + private void doResponse(HttpServletResponse resp, int statusCode, + String message, Throwable e) throws IOException { + resp.setStatus(statusCode); + PrintWriter writer = resp.getWriter(); + writer.println("

" + statusCode + " " + message + "

"); + writer.println("
");
+		e.printStackTrace(writer);
+		writer.println("
"); + } + + // ---------------------------------------------------------------------- + // Helper classes + // ---------------------------------------------------------------------- + + private static class AuthException extends Exception { + private AuthException(String message) { + super(message); + } + } + + private static class ParseException extends Exception { + private ParseException(String message) { + super(message); + } + + private ParseException(String message, Throwable cause) { + super(message, cause); + } + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/PageController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/PageController.java index a98434bc0..fe08c7d95 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/PageController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/PageController.java @@ -67,8 +67,7 @@ public class PageController extends FreemarkerHttpServlet{ } } catch (Exception e) { - // TODO Auto-generated catch block - log.debug(e); + log.warn(e); return Actions.UNAUTHORIZED; } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/ThemeInfoSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/ThemeInfoSetup.java index 6b917c43f..5ccea3bfd 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/ThemeInfoSetup.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/ThemeInfoSetup.java @@ -73,8 +73,8 @@ public class ThemeInfoSetup implements ServletContextListener { ApplicationBean.themeInfo = new ThemeInfo(themesBaseDir, defaultThemeName, themeNames); - ss.info(this, ", current theme: " + currentThemeName - + "default theme: " + defaultThemeName + ", available themes: " + ss.info(this, "current theme: " + currentThemeName + + ", default theme: " + defaultThemeName + ", available themes: " + themeNames); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/SparqlUpdate.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/SparqlUpdate.java deleted file mode 100644 index 7bb33194b..000000000 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/SparqlUpdate.java +++ /dev/null @@ -1,96 +0,0 @@ -/* $This file is distributed under the terms of the license in /doc/license.txt$ */ - -package edu.cornell.mannlib.vitro.webapp.utils.dataGetter; - -import java.util.HashMap; -import java.util.Map; - -import javax.servlet.ServletContext; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import com.hp.hpl.jena.query.Dataset; -import com.hp.hpl.jena.rdf.model.Model; -import com.hp.hpl.jena.update.GraphStore; -import com.hp.hpl.jena.update.GraphStoreFactory; -import com.hp.hpl.jena.update.UpdateAction; - -import edu.cornell.mannlib.vitro.webapp.auth.permissions.SimplePermission; -import edu.cornell.mannlib.vitro.webapp.auth.policy.PolicyHelper; -import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.Actions; -import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequiresActions; -import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; -import edu.cornell.mannlib.vitro.webapp.dao.jena.RDFServiceDataset; -import edu.cornell.mannlib.vitro.webapp.search.indexing.IndexBuilder; - -/** - * Handle a SPARQL Update request. This uses Jena ARQ and the RDFServiceDataset to - * evaluate a SPARQL Update with the RDFService. - * - * The reason to make this a DataGettere was to allow configuration in RDF of this - * service. - */ -public class SparqlUpdate implements DataGetter, RequiresActions{ - - private static final Log log = LogFactory.getLog(SparqlUpdate.class); - - VitroRequest vreq; - ServletContext context; - - public SparqlUpdate( - VitroRequest vreq, Model displayModel, String dataGetterURI ) { - if( vreq == null ) - throw new IllegalArgumentException("VitroRequest may not be null."); - this.vreq = vreq; - this.context = vreq.getSession().getServletContext(); - } - - - /** - * Gets the update from the request and then executes it on - * the RDFService. - */ - @Override - public Map getData( Map valueMap ) { - HashMap data = new HashMap(); - - String update = vreq.getParameter("update"); - - if( update != null && !update.trim().isEmpty()){ - try{ - IndexBuilder.getBuilder(context).pause(); - Dataset ds = new RDFServiceDataset( vreq.getUnfilteredRDFService() ); - GraphStore graphStore = GraphStoreFactory.create(ds); - log.warn("The SPARQL update is '"+vreq.getParameter("update")+"'"); - UpdateAction.parseExecute( vreq.getParameter("update") , graphStore ); - }finally{ - IndexBuilder.getBuilder(context).unpause(); - } - - } - - data.put("bodyTemplate", "page-sparqlUpdateTest.ftl"); - return data; - } - - - /** - * Check if this request is authorized by the email/password. - * If not do normal authorization. - */ - @Override - public Actions requiredActions(VitroRequest vreq) { - String email = vreq.getParameter("email"); - String password = vreq.getParameter("password"); - - boolean isAuth = PolicyHelper.isAuthorizedForActions(vreq, - email, password, SimplePermission.MANAGE_SEARCH_INDEX.ACTIONS); - - if( isAuth ) - return Actions.AUTHORIZED; - else - return SimplePermission.MANAGE_SEARCH_INDEX.ACTIONS; - } - -} diff --git a/webapp/web/WEB-INF/web.xml b/webapp/web/WEB-INF/web.xml index 3a5377bda..1d393a7b9 100644 --- a/webapp/web/WEB-INF/web.xml +++ b/webapp/web/WEB-INF/web.xml @@ -1025,6 +1025,16 @@ /admin/sparqlquery + + SparqlUpdateApi + edu.cornell.mannlib.vitro.webapp.controller.api.SparqlUpdateApiController + + + + SparqlUpdateApi + /api/sparqlUpdate + + primitiveRdfEdit edu.cornell.mannlib.vitro.webapp.controller.edit.PrimitiveRdfEdit diff --git a/webapp/web/templates/freemarker/body/menupage/page-sparqlUpdateTest.ftl b/webapp/web/templates/freemarker/body/menupage/page-sparqlUpdateTest.ftl deleted file mode 100644 index 17274f829..000000000 --- a/webapp/web/templates/freemarker/body/menupage/page-sparqlUpdateTest.ftl +++ /dev/null @@ -1,12 +0,0 @@ -<#-- $This file is distributed under the terms of the license in /doc/license.txt$ --> - -

SPARQL Update Test

- -

This is an expermental SPARQL update service.

- -
-

- - -

-
\ No newline at end of file From 80130c14f1285aad02e7efd5c34562a40947a157 Mon Sep 17 00:00:00 2001 From: j2blake Date: Tue, 26 Nov 2013 17:58:50 -0500 Subject: [PATCH 06/14] Fast forward the changes to develop --- .../utilities/testrunner/test-user-model.owl | 116 +++++++++--------- 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/test-user-model.owl b/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/test-user-model.owl index a0acf6afa..c6e9a3523 100644 --- a/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/test-user-model.owl +++ b/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/test-user-model.owl @@ -1,58 +1,58 @@ - - - - - testAdmin@cornell.edu - testAdmin - Test - Admin - DC647EB65E6711E155375218212B3964 - ACTIVE - 1 - 0 - - - - - johnCurator@cornell.edu - johnCurator - John - Curator - DC647EB65E6711E155375218212B3964 - ACTIVE - 1 - 0 - - - - - sallyEditor@cornell.edu - sallyEditor - Sally - Editor - DC647EB65E6711E155375218212B3964 - ACTIVE - 1 - 0 - - - - - joeUser@cornell.edu - joeUser - Joe - User - DC647EB65E6711E155375218212B3964 - ACTIVE - 1 - 0 - - - - + + + + + testAdmin@cornell.edu + testAdmin + Test + Admin + DC647EB65E6711E155375218212B3964 + ACTIVE + 1 + 0 + + + + + johnCurator@cornell.edu + johnCurator + John + Curator + DC647EB65E6711E155375218212B3964 + ACTIVE + 1 + 0 + + + + + sallyEditor@cornell.edu + sallyEditor + Sally + Editor + DC647EB65E6711E155375218212B3964 + ACTIVE + 1 + 0 + + + + + joeUser@cornell.edu + joeUser + Joe + User + DC647EB65E6711E155375218212B3964 + ACTIVE + 1 + 0 + + + + From f981fd2c532a799da7a1360ca2f277494a7fabe1 Mon Sep 17 00:00:00 2001 From: j2blake Date: Sun, 1 Dec 2013 19:30:57 -0500 Subject: [PATCH 07/14] VIVO-588 Fixed a typo to fix the deadlocked threads. --- .../edu/cornell/mannlib/vitro/webapp/dao/jena/PageDaoJena.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/PageDaoJena.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/PageDaoJena.java index 23e300013..fd333560b 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/PageDaoJena.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/PageDaoJena.java @@ -537,13 +537,14 @@ public class PageDaoJena extends JenaBaseDao implements PageDao { List actions = new ArrayList(); Model dModel = getOntModelSelector().getDisplayModel(); + dModel.enterCriticalSection(false); try{ QueryExecution qe = QueryExecutionFactory.create( requiredActionsQuery, dModel, initialBindings); actions = executeQueryToList( qe ); qe.close(); }finally{ - dModel.enterCriticalSection(false); + dModel.leaveCriticalSection(); } return actions; } From 356e86de704e5ef74f7a3ddb9d5fc9027fdc59a7 Mon Sep 17 00:00:00 2001 From: j2blake Date: Sun, 1 Dec 2013 19:32:43 -0500 Subject: [PATCH 08/14] =?UTF-8?q?VIVO-581=20Don=E2=80=99t=20check=20for=20?= =?UTF-8?q?=E2=80=9Cregular=20files=E2=80=9D,=20just=20check=20for=20?= =?UTF-8?q?=E2=80=9Cnot=20directory=E2=80=9D.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../webapp/freemarker/loader/FreemarkerTemplateLoader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/freemarker/loader/FreemarkerTemplateLoader.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/freemarker/loader/FreemarkerTemplateLoader.java index 2ae556862..0bef38b30 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/freemarker/loader/FreemarkerTemplateLoader.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/freemarker/loader/FreemarkerTemplateLoader.java @@ -285,7 +285,7 @@ public class FreemarkerTemplateLoader implements TemplateLoader { } public boolean fileQualifies(Path path) { - return Files.isRegularFile(path) && Files.isReadable(path); + return Files.isReadable(path) && !Files.isDirectory(path); } public SortedSet getMatches() { From de93fd4f3e52827f60dc0936b012d04e1e15e11a Mon Sep 17 00:00:00 2001 From: hudajkhan Date: Mon, 2 Dec 2013 11:55:29 -0500 Subject: [PATCH 09/14] problem with line end character --- .../utilities/testrunner/test-user-model.owl | 116 +++++++++--------- 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/test-user-model.owl b/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/test-user-model.owl index a0acf6afa..c6e9a3523 100644 --- a/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/test-user-model.owl +++ b/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/test-user-model.owl @@ -1,58 +1,58 @@ - - - - - testAdmin@cornell.edu - testAdmin - Test - Admin - DC647EB65E6711E155375218212B3964 - ACTIVE - 1 - 0 - - - - - johnCurator@cornell.edu - johnCurator - John - Curator - DC647EB65E6711E155375218212B3964 - ACTIVE - 1 - 0 - - - - - sallyEditor@cornell.edu - sallyEditor - Sally - Editor - DC647EB65E6711E155375218212B3964 - ACTIVE - 1 - 0 - - - - - joeUser@cornell.edu - joeUser - Joe - User - DC647EB65E6711E155375218212B3964 - ACTIVE - 1 - 0 - - - - + + + + + testAdmin@cornell.edu + testAdmin + Test + Admin + DC647EB65E6711E155375218212B3964 + ACTIVE + 1 + 0 + + + + + johnCurator@cornell.edu + johnCurator + John + Curator + DC647EB65E6711E155375218212B3964 + ACTIVE + 1 + 0 + + + + + sallyEditor@cornell.edu + sallyEditor + Sally + Editor + DC647EB65E6711E155375218212B3964 + ACTIVE + 1 + 0 + + + + + joeUser@cornell.edu + joeUser + Joe + User + DC647EB65E6711E155375218212B3964 + ACTIVE + 1 + 0 + + + + From 495982ddab1b22ff1c5e49ae5acece7c4cc699e8 Mon Sep 17 00:00:00 2001 From: brianjlowe Date: Mon, 2 Dec 2013 15:38:37 -0500 Subject: [PATCH 10/14] fixes bug that caused misrendering of certain restrictions on vclass edit page --- .../webapp/controller/edit/VclassEditController.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/VclassEditController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/VclassEditController.java index 83ac3b051..69960f546 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/VclassEditController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/VclassEditController.java @@ -143,24 +143,25 @@ public class VclassEditController extends BaseEditController { // if supported, we want to show only the asserted superclasses and subclasses. VClassDao vcDao = ModelAccess.on(getServletContext()).getBaseWebappDaoFactory().getVClassDao(); + VClassDao displayVcDao = ModelAccess.on(getServletContext()).getWebappDaoFactory().getVClassDao(); List superVClasses = getVClassesForURIList( - vcDao.getSuperClassURIs(vcl.getURI(),false), vcDao); + vcDao.getSuperClassURIs(vcl.getURI(),false), displayVcDao); sortForPickList(superVClasses, request); request.setAttribute("superclasses",superVClasses); List subVClasses = getVClassesForURIList( - vcDao.getSubClassURIs(vcl.getURI()), vcDao); + vcDao.getSubClassURIs(vcl.getURI()), displayVcDao); sortForPickList(subVClasses, request); request.setAttribute("subclasses",subVClasses); List djVClasses = getVClassesForURIList( - vcDao.getDisjointWithClassURIs(vcl.getURI()), vcDao); + vcDao.getDisjointWithClassURIs(vcl.getURI()), displayVcDao); sortForPickList(djVClasses, request); request.setAttribute("disjointClasses",djVClasses); List eqVClasses = getVClassesForURIList( - vcDao.getEquivalentClassURIs(vcl.getURI()), vcDao); + vcDao.getEquivalentClassURIs(vcl.getURI()), displayVcDao); sortForPickList(eqVClasses, request); request.setAttribute("equivalentClasses",eqVClasses); From 21e2ae264b904e0d4ab5788df26b39f0a8eaae29 Mon Sep 17 00:00:00 2001 From: brianjlowe Date: Mon, 2 Dec 2013 15:54:30 -0500 Subject: [PATCH 11/14] fix line ending problem --- .../utilities/testrunner/test-user-model.owl | 116 +++++++++--------- 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/test-user-model.owl b/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/test-user-model.owl index a0acf6afa..c6e9a3523 100644 --- a/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/test-user-model.owl +++ b/utilities/testrunner/src/edu/cornell/mannlib/vitro/utilities/testrunner/test-user-model.owl @@ -1,58 +1,58 @@ - - - - - testAdmin@cornell.edu - testAdmin - Test - Admin - DC647EB65E6711E155375218212B3964 - ACTIVE - 1 - 0 - - - - - johnCurator@cornell.edu - johnCurator - John - Curator - DC647EB65E6711E155375218212B3964 - ACTIVE - 1 - 0 - - - - - sallyEditor@cornell.edu - sallyEditor - Sally - Editor - DC647EB65E6711E155375218212B3964 - ACTIVE - 1 - 0 - - - - - joeUser@cornell.edu - joeUser - Joe - User - DC647EB65E6711E155375218212B3964 - ACTIVE - 1 - 0 - - - - + + + + + testAdmin@cornell.edu + testAdmin + Test + Admin + DC647EB65E6711E155375218212B3964 + ACTIVE + 1 + 0 + + + + + johnCurator@cornell.edu + johnCurator + John + Curator + DC647EB65E6711E155375218212B3964 + ACTIVE + 1 + 0 + + + + + sallyEditor@cornell.edu + sallyEditor + Sally + Editor + DC647EB65E6711E155375218212B3964 + ACTIVE + 1 + 0 + + + + + joeUser@cornell.edu + joeUser + Joe + User + DC647EB65E6711E155375218212B3964 + ACTIVE + 1 + 0 + + + + From eebbaba3ca0aa5fbbbb6b60be26be916bc936586 Mon Sep 17 00:00:00 2001 From: brianjlowe Date: Mon, 2 Dec 2013 16:23:10 -0500 Subject: [PATCH 12/14] VIVO-604 getting rid of ExternalIdRetryController --- .../edit/ExternalIdRetryController.java | 120 ------------------ .../web/templates/edit/specific/ents_edit.jsp | 5 - 2 files changed, 125 deletions(-) delete mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/ExternalIdRetryController.java diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/ExternalIdRetryController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/ExternalIdRetryController.java deleted file mode 100644 index 51509e580..000000000 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/ExternalIdRetryController.java +++ /dev/null @@ -1,120 +0,0 @@ -/* $This file is distributed under the terms of the license in /doc/license.txt$ */ - -package edu.cornell.mannlib.vitro.webapp.controller.edit; - -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; - -import javax.servlet.RequestDispatcher; -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.EditProcessObject; -import edu.cornell.mannlib.vedit.beans.FormObject; -import edu.cornell.mannlib.vedit.beans.Option; -import edu.cornell.mannlib.vedit.controller.BaseEditController; -import edu.cornell.mannlib.vedit.util.FormUtils; -import edu.cornell.mannlib.vitro.webapp.auth.permissions.SimplePermission; -import edu.cornell.mannlib.vitro.webapp.beans.DataPropertyStatement; -import edu.cornell.mannlib.vitro.webapp.beans.DataPropertyStatementImpl; -import edu.cornell.mannlib.vitro.webapp.beans.Individual; -import edu.cornell.mannlib.vitro.webapp.controller.Controllers; -import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; -import edu.cornell.mannlib.vitro.webapp.dao.DataPropertyDao; -import edu.cornell.mannlib.vitro.webapp.dao.DataPropertyStatementDao; -import edu.cornell.mannlib.vitro.webapp.dao.IndividualDao; - -public class ExternalIdRetryController extends BaseEditController { - - private static final Log log = LogFactory.getLog(ExternalIdRetryController.class.getName()); - - public void doPost (HttpServletRequest request, HttpServletResponse response) { - if (!isAuthorizedToDisplayPage(request, response, - SimplePermission.DO_BACK_END_EDITING.ACTIONS)) { - return; - } - - VitroRequest vreq = new VitroRequest(request); - - //create an EditProcessObject for this and put it in the session - EditProcessObject epo = super.createEpo(request); - - String action = "insert"; - - DataPropertyDao dpDao = vreq.getUnfilteredWebappDaoFactory().getDataPropertyDao(); - DataPropertyStatementDao edDao = vreq.getUnfilteredWebappDaoFactory().getDataPropertyStatementDao(); - epo.setDataAccessObject(edDao); - epo.setBeanClass(DataPropertyStatement.class); - - IndividualDao eDao = vreq.getUnfilteredWebappDaoFactory().getIndividualDao(); - - DataPropertyStatement eidForEditing = null; - if (!epo.getUseRecycledBean()){ - eidForEditing = new DataPropertyStatementImpl(); - populateBeanFromParams(eidForEditing,vreq); - if (vreq.getParameter(MULTIPLEXED_PARAMETER_NAME) != null) { - action = "update"; - } - epo.setOriginalBean(eidForEditing); - } else { - eidForEditing = (DataPropertyStatement) epo.getNewBean(); - } - - //make a simple mask for the class's id - Object[] simpleMaskPair = new Object[2]; - simpleMaskPair[0]="Id"; - //simpleMaskPair[1]=Integer.valueOf(eidForEditing.getId()); - epo.getSimpleMask().add(simpleMaskPair); - - //set up any listeners - - FormObject foo = new FormObject(); - HashMap OptionMap = new HashMap(); - List entityList = new LinkedList(); - if (eidForEditing.getIndividualURI() != null) { - Individual individual = eDao.getIndividualByURI(eidForEditing.getIndividualURI()); - entityList.add(new Option(individual.getURI(),individual.getName(),true)); - } else { - entityList.add(new Option ("-1", "Error: the entity must be specified", true)); - } - OptionMap.put("IndividualURI",entityList); - // TOOD change following DAO call to getAllExternalIdDataProperties once implemented - List allExternalIdDataProperties = dpDao.getAllExternalIdDataProperties(); - Collections.sort(allExternalIdDataProperties); - OptionMap.put("DatapropURI", FormUtils.makeOptionListFromBeans(allExternalIdDataProperties, "URI", "PublicName", eidForEditing.getDatapropURI(),"")); - foo.setOptionLists(OptionMap); - foo.setErrorMap(epo.getErrMsgMap()); - - epo.setFormObject(foo); - - FormUtils.populateFormFromBean(eidForEditing,action,foo,epo.getBadValueMap()); - - RequestDispatcher rd = request.getRequestDispatcher(Controllers.BASIC_JSP); - request.setAttribute("bodyJsp","/templates/edit/formBasic.jsp"); - request.setAttribute("formJsp","/templates/edit/specific/externalIds_retry.jsp"); - request.setAttribute("scripts","/templates/edit/formBasic.js"); - request.setAttribute("title","External Id Editing Form"); - request.setAttribute("_action",action); - request.setAttribute("unqualifiedClassName","External Id"); - setRequestAttributes(request,epo); - - try { - rd.forward(request, response); - } catch (Exception e) { - log.error("ExternalIdRetryController could not forward to view."); - log.error(e.getMessage()); - log.error(e.getStackTrace()); - } - - } - - public void doGet (HttpServletRequest request, HttpServletResponse response) { - doPost(request, response); - } - -} diff --git a/webapp/web/templates/edit/specific/ents_edit.jsp b/webapp/web/templates/edit/specific/ents_edit.jsp index 10e1764cb..f6f6ba9b2 100644 --- a/webapp/web/templates/edit/specific/ents_edit.jsp +++ b/webapp/web/templates/edit/specific/ents_edit.jsp @@ -99,11 +99,6 @@
- - - -
-
From 1abbdfc86df7670a634f12f6ef62be43a7a35410 Mon Sep 17 00:00:00 2001 From: hudajkhan Date: Tue, 3 Dec 2013 13:39:53 -0500 Subject: [PATCH 13/14] vivo-608 only display classes that are part of classgroup in type dropdown --- .../edit/EditConfigurationTemplateModel.java | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/edit/EditConfigurationTemplateModel.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/edit/EditConfigurationTemplateModel.java index 8a3e273ca..651cfb6b0 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/edit/EditConfigurationTemplateModel.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/edit/EditConfigurationTemplateModel.java @@ -547,11 +547,14 @@ public class EditConfigurationTemplateModel extends BaseTemplateModel { rangeVClasses.addAll(rangeClass.getUnionComponents()); } for(VClass rangeVClass : rangeVClasses) { - vclasses.add(rangeVClass); + if(rangeVClass.getGroupURI() != null) { + vclasses.add(rangeVClass); + } List subURIs = wdf.getVClassDao().getAllSubClassURIs(rangeVClass.getURI()); for (String subClassURI : subURIs) { VClass subClass = wdf.getVClassDao().getVClassByURI(subClassURI); - if (subClass != null) { + //if the subclass exists and also belongs to a particular class group + if (subClass != null && subClass.getGroupURI() != null) { vclasses.add(subClass); } } @@ -567,7 +570,8 @@ public class EditConfigurationTemplateModel extends BaseTemplateModel { //add range vclass to hash if(rangeVclasses != null) { for(VClass v: rangeVclasses) { - if(!vclassesURIs.contains(v.getURI())) { + //Need to make sure any class added will belong to a class group + if(!vclassesURIs.contains(v.getURI()) && v.getGroupURI() != null) { vclassesURIs.add(v.getURI()); vclasses.add(v); } @@ -577,7 +581,13 @@ public class EditConfigurationTemplateModel extends BaseTemplateModel { } //if each subject vclass resulted in null being returned for range vclasses, then size of vclasses would be zero if(vclasses.size() == 0) { - vclasses = wdf.getVClassDao().getAllVclasses(); + List allVClasses = wdf.getVClassDao().getAllVclasses(); + //Since these are all vclasses, we should check whether vclasses included are in a class group + for(VClass v:allVClasses) { + if(v.getGroupURI() != null) { + vclasses.add(v); + } + } } From 95d7f28259cc943ad1f4b73b0e2d1e78b4590ce3 Mon Sep 17 00:00:00 2001 From: hudajkhan Date: Wed, 4 Dec 2013 11:46:44 -0500 Subject: [PATCH 14/14] vivo610 when rangeUri empty ensure error does not occur for adding new object of type --- .../DefaultObjectPropertyFormGenerator.java | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DefaultObjectPropertyFormGenerator.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DefaultObjectPropertyFormGenerator.java index 11cf0210d..4d29a23d1 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DefaultObjectPropertyFormGenerator.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DefaultObjectPropertyFormGenerator.java @@ -112,7 +112,7 @@ public class DefaultObjectPropertyFormGenerator implements EditConfigurationGene Individual subject = EditConfigurationUtils.getSubjectIndividual(vreq); String predicateUri = EditConfigurationUtils.getPredicateUri(vreq); String rangeUri = EditConfigurationUtils.getRangeUri(vreq); - if (rangeUri != null) { + if (rangeUri != null && !rangeUri.isEmpty()) { VClass rangeVClass = ctxDaoFact.getVClassDao().getVClassByURI(rangeUri); if (!rangeVClass.isUnion()) { types.add(rangeVClass); @@ -125,18 +125,23 @@ public class DefaultObjectPropertyFormGenerator implements EditConfigurationGene } WebappDaoFactory wDaoFact = vreq.getWebappDaoFactory(); //Get all vclasses applicable to subject - List vClasses = subject.getVClasses(); - HashMap typesHash = new HashMap(); - for(VClass vclass: vClasses) { - List rangeVclasses = wDaoFact.getVClassDao().getVClassesForProperty(vclass.getURI(),predicateUri); - if(rangeVclasses != null) { - for(VClass range: rangeVclasses) { - //a hash will keep a unique list of types and so prevent duplicates - typesHash.put(range.getURI(), range); + if(subject != null) { + List vClasses = subject.getVClasses(); + HashMap typesHash = new HashMap(); + for(VClass vclass: vClasses) { + List rangeVclasses = wDaoFact.getVClassDao().getVClassesForProperty(vclass.getURI(),predicateUri); + if(rangeVclasses != null) { + for(VClass range: rangeVclasses) { + //a hash will keep a unique list of types and so prevent duplicates + typesHash.put(range.getURI(), range); + } } - } - } - types.addAll(typesHash.values()); + } + types.addAll(typesHash.values()); + } else { + log.error("Subject individual was null for"); + } + return types; }