diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/auth/policy/RootUserPolicy.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/auth/policy/RootUserPolicy.java index e724361524..816bf7d515 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/auth/policy/RootUserPolicy.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/auth/policy/RootUserPolicy.java @@ -37,7 +37,14 @@ public class RootUserPolicy implements PolicyIface { private static final Log log = LogFactory.getLog(RootUserPolicy.class); private static final String PROPERTY_ROOT_USER_EMAIL = "rootUser.emailAddress"; + /* + * UQAM Add-Feature For parameterization of rootUser + */ + private static final String PROPERTY_ROOT_USER_PASSWORD = "rootUser.password"; + private static final String PROPERTY_ROOT_USER_PASSWORD_CHANGE_REQUIRED = "rootUser.passwordChangeRequired"; + private static final String ROOT_USER_INITIAL_PASSWORD = "rootPassword"; + private static final String ROOT_USER_INITIAL_PASSWORD_CHANGE_REQUIRED = "true"; /** * This is the entire policy. If you are a root user, you are authorized. @@ -150,10 +157,12 @@ private void createRootUser() { ua.setEmailAddress(configuredRootUser); ua.setFirstName("root"); ua.setLastName("user"); + // UQAM Add-Feature using getRootPasswordFromConfig() ua.setArgon2Password(Authenticator.applyArgon2iEncoding( - ROOT_USER_INITIAL_PASSWORD)); + getRootPasswordFromConfig())); ua.setMd5Password(""); - ua.setPasswordChangeRequired(true); + // UQAM Add-Feature using getRootPasswdChangeRequiredFromConfig() + ua.setPasswordChangeRequired(getRootPasswdChangeRequiredFromConfig().booleanValue()); ua.setStatus(Status.ACTIVE); ua.setRootUser(true); @@ -191,7 +200,31 @@ private void complainAboutWrongRootUsers() { ss.warning(this, "For security, " + "it is best to delete unneeded root user accounts."); } + /* + * UQAM Add-Feature + * Add for getting rootUser.password property value from runtime.properties + */ + private String getRootPasswordFromConfig() { + String passwd = ConfigurationProperties.getBean(ctx).getProperty( + PROPERTY_ROOT_USER_PASSWORD); + if (passwd == null) { + passwd = ROOT_USER_INITIAL_PASSWORD; + } + return passwd; + } + /* + * UQAM Add-Feature + * Add for getting rootUser.passwordChangeRequired property value from runtime.properties + */ + private Boolean getRootPasswdChangeRequiredFromConfig() { + String passwdCR = ConfigurationProperties.getBean(ctx).getProperty( + PROPERTY_ROOT_USER_PASSWORD_CHANGE_REQUIRED); + if (passwdCR == null) { + passwdCR = ROOT_USER_INITIAL_PASSWORD_CHANGE_REQUIRED; + } + return new Boolean(passwdCR); + } @Override public void contextDestroyed(ServletContextEvent sce) { // Nothing to destroy diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/beans/ApplicationBean.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/beans/ApplicationBean.java index c083d44f3d..563b1c9b44 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/beans/ApplicationBean.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/beans/ApplicationBean.java @@ -20,6 +20,7 @@ public class ApplicationBean { public final static int VIVO_SEARCHBOX_SIZE = 20; private final static String DEFAULT_APPLICATION_NAME = "Vitro"; + private final static String DEFAULT_APPLICATION_AVAILABLE_LANGS_FILE = "available-langs"; private final static String DEFAULT_ROOT_LOGOTYPE_IMAGE = ""; private final static int DEFAULT_ROOT_LOGOTYPE_WIDTH = 0; private final static int DEFAULT_ROOT_LOGOTYPE_HEIGHT = 0; @@ -33,6 +34,7 @@ public class ApplicationBean { private boolean initialized = false; private String sessionIdStr = null; private String applicationName = DEFAULT_APPLICATION_NAME; + private String availableLangsFile = DEFAULT_APPLICATION_AVAILABLE_LANGS_FILE; private String rootLogotypeImage = DEFAULT_ROOT_LOGOTYPE_IMAGE; private int rootLogotypeWidth = DEFAULT_ROOT_LOGOTYPE_WIDTH; @@ -52,6 +54,7 @@ public String toString() { output += " initialized from DB: [" + initialized + "]\n"; output += " session id: [" + sessionIdStr + "]\n"; output += " application name: [" + applicationName + "]\n"; + output += " available langs file: [" + availableLangsFile + "]\n"; output += " root logotype image: [" + rootLogotypeImage + "]\n"; output += " root logotype width: [" + rootLogotypeWidth + "]\n"; output += " root logotype height: [" + rootLogotypeHeight + "]\n"; @@ -177,6 +180,10 @@ public String getShortHand() { return ""; } + public String getAvailableLangsFile() { + return availableLangsFile; + } + /** * Directory to find the images. Subdirectories include css, jsp and site_icons. * Example: "themes/enhanced/" diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/admin/SparqlQueryController.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/admin/SparqlQueryController.java index 096263dab3..5369d26266 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/admin/SparqlQueryController.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/admin/SparqlQueryController.java @@ -17,6 +17,8 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import edu.cornell.mannlib.vitro.webapp.i18n.I18n; +import edu.cornell.mannlib.vitro.webapp.i18n.I18nBundle; import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -75,8 +77,8 @@ private static List buildDefaults() { private static final String[] SAMPLE_QUERY = { // "", // "#", // - "# This example query gets 20 geographic locations", // - "# and (if available) their labels", // + "i18n:sparql_query_description_0", // + "i18n:sparql_query_description_1", // "#", // "SELECT ?geoLocation ?label", // "WHERE", // @@ -193,9 +195,11 @@ private void do500InternalServerError(String message, Exception e, @Override protected ResponseValues processRequest(VitroRequest vreq) throws Exception { + I18nBundle i18n = I18n.bundle(vreq); + Map bodyMap = new HashMap<>(); - bodyMap.put("sampleQuery", buildSampleQuery(buildPrefixList(vreq))); - bodyMap.put("title", "SPARQL Query"); + bodyMap.put("sampleQuery", buildSampleQuery(i18n, buildPrefixList(vreq))); + bodyMap.put("title", i18n.text("sparql_query_title")); bodyMap.put("submitUrl", UrlBuilder.getUrl("admin/sparqlquery")); return new TemplateResponseValues(TEMPLATE_NAME, bodyMap); } @@ -222,7 +226,7 @@ private List buildPrefixList(VitroRequest vreq) { return prefixList; } - private String buildSampleQuery(List prefixList) { + private String buildSampleQuery(I18nBundle i18n, List prefixList) { StringWriter sw = new StringWriter(); PrintWriter writer = new PrintWriter(sw); @@ -230,6 +234,10 @@ private String buildSampleQuery(List prefixList) { writer.println(p); } for (String line : SAMPLE_QUERY) { + if (line.startsWith("i18n:")) { + // Get i18n translation + line = i18n.text(line.substring("i18n:".length())); + } writer.println(line); } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/Classes2ClassesRetryController.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/Classes2ClassesRetryController.java index d4417e6a3b..d51d904527 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/Classes2ClassesRetryController.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/Classes2ClassesRetryController.java @@ -43,7 +43,7 @@ public void doPost (HttpServletRequest req, HttpServletResponse response) { action = epo.getAction(); } - VClassDao vcDao = ModelAccess.on(getServletContext()).getWebappDaoFactory().getVClassDao(); + VClassDao vcDao = ModelAccess.on(request).getWebappDaoFactory().getVClassDao(); epo.setDataAccessObject(vcDao); Classes2Classes objectForEditing = new Classes2Classes(); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/ClassgroupRetryController.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/ClassgroupRetryController.java index 5c1535489a..82b6186652 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/ClassgroupRetryController.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/ClassgroupRetryController.java @@ -51,8 +51,7 @@ public void doPost (HttpServletRequest req, HttpServletResponse response) { action = epo.getAction(); } - VClassGroupDao cgDao = ModelAccess.on( - getServletContext()).getWebappDaoFactory().getVClassGroupDao(); + VClassGroupDao cgDao = ModelAccess.on(request).getWebappDaoFactory().getVClassGroupDao(); epo.setDataAccessObject(cgDao); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/DatapropRetryController.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/DatapropRetryController.java index c4b04c08bb..70d47a80a7 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/DatapropRetryController.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/DatapropRetryController.java @@ -50,11 +50,12 @@ public void doPost (HttpServletRequest request, HttpServletResponse response) { //create an EditProcessObject for this and put it in the session EditProcessObject epo = super.createEpo(request); + epo.setImplementationClass(DataProperty.class); epo.setBeanClass(DataProperty.class); VitroRequest vreq = new VitroRequest(request); - WebappDaoFactory wadf = ModelAccess.on(getServletContext()).getWebappDaoFactory(); + WebappDaoFactory wadf = ModelAccess.on(vreq).getWebappDaoFactory(); DatatypeDao dDao = wadf.getDatatypeDao(); DataPropertyDao dpDao = wadf.getDataPropertyDao(); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/FauxPropertyRetryController.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/FauxPropertyRetryController.java index 941c6e7f64..9f4d270923 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/FauxPropertyRetryController.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/FauxPropertyRetryController.java @@ -106,7 +106,7 @@ private static class EpoPopulator { this.epo = epo; - this.fpDao = ModelAccess.on(ctx).getWebappDaoFactory() + this.fpDao = ModelAccess.on(req).getWebappDaoFactory() .getFauxPropertyDao(); } @@ -114,6 +114,8 @@ private static class EpoPopulator { void populate() { epo.setDataAccessObject(fpDao); epo.setAction(determineAction()); + epo.setImplementationClass(FauxProperty.class); + epo.setBeanClass(FauxProperty.class); if (epo.getUseRecycledBean()) { beanForEditing = (FauxProperty) epo.getNewBean(); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/NamespacePrefixOperationController.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/NamespacePrefixOperationController.java index 356569c543..2223c69e65 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/NamespacePrefixOperationController.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/NamespacePrefixOperationController.java @@ -71,7 +71,7 @@ public void doPost(HttpServletRequest req, HttpServletResponse response) { if (request.getParameter("_cancel") == null) { - OntModel ontModel = ModelAccess.on(getServletContext()).getOntModel(); + OntModel ontModel = ModelAccess.on(req).getOntModel(); String namespaceStr = request.getParameter("namespace"); String prefixStr = request.getParameter("prefix"); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/PropertyGroupRetryController.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/PropertyGroupRetryController.java index d84b15db58..3ae22e5c1b 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/PropertyGroupRetryController.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/PropertyGroupRetryController.java @@ -51,7 +51,7 @@ public void doPost (HttpServletRequest req, HttpServletResponse response) { } PropertyGroupDao pgDao = ModelAccess.on( - getServletContext()).getWebappDaoFactory().getPropertyGroupDao(); + req).getWebappDaoFactory().getPropertyGroupDao(); epo.setDataAccessObject(pgDao); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/PropertyRetryController.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/PropertyRetryController.java index 5e35fb3693..909ebeff98 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/PropertyRetryController.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/PropertyRetryController.java @@ -53,6 +53,7 @@ public void doPost (HttpServletRequest req, HttpServletResponse response) { /*for testing*/ ObjectProperty testMask = new ObjectProperty(); + epo.setImplementationClass(ObjectProperty.class); epo.setBeanClass(ObjectProperty.class); epo.setBeanMask(testMask); @@ -64,7 +65,7 @@ public void doPost (HttpServletRequest req, HttpServletResponse response) { action = epo.getAction(); } - ObjectPropertyDao propDao = ModelAccess.on(getServletContext()).getWebappDaoFactory().getObjectPropertyDao(); + ObjectPropertyDao propDao = ModelAccess.on(req).getWebappDaoFactory().getObjectPropertyDao(); epo.setDataAccessObject(propDao); OntologyDao ontDao = request.getUnfilteredWebappDaoFactory().getOntologyDao(); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/RestrictionOperationController.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/RestrictionOperationController.java index f704b5b395..26956be747 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/RestrictionOperationController.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/RestrictionOperationController.java @@ -48,7 +48,7 @@ public void doPost(HttpServletRequest req, HttpServletResponse response) { String defaultLandingPage = getDefaultLandingPage(request); try { - OntModel ontModel = ModelAccess.on(getServletContext()) + OntModel ontModel = ModelAccess.on(req) .getOntModel(TBOX_ASSERTIONS); HashMap epoHash = null; diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/VclassEditController.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/VclassEditController.java index 340a846e4b..a9b018670f 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/VclassEditController.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/VclassEditController.java @@ -48,7 +48,7 @@ public void doPost (HttpServletRequest req, HttpServletResponse response) { EditProcessObject epo = super.createEpo(request, FORCE_NEW); request.setAttribute("epoKey", epo.getKey()); - VClassDao vcwDao = ModelAccess.on(getServletContext()).getWebappDaoFactory(ASSERTIONS_ONLY).getVClassDao(); + VClassDao vcwDao = ModelAccess.on(req).getWebappDaoFactory(ASSERTIONS_ONLY).getVClassDao(); VClass vcl = (VClass)vcwDao.getVClassByURI(request.getParameter("uri")); if (vcl == null) { @@ -152,8 +152,8 @@ public void doPost (HttpServletRequest req, HttpServletResponse response) { request.setAttribute("formSelect",formSelect); // if supported, we want to show only the asserted superclasses and subclasses. - VClassDao vcDao = ModelAccess.on(getServletContext()).getWebappDaoFactory(ASSERTIONS_ONLY).getVClassDao(); - VClassDao displayVcDao = ModelAccess.on(getServletContext()).getWebappDaoFactory().getVClassDao(); + VClassDao vcDao = ModelAccess.on(req).getWebappDaoFactory(ASSERTIONS_ONLY).getVClassDao(); + VClassDao displayVcDao = ModelAccess.on(req).getWebappDaoFactory().getVClassDao(); List superVClasses = getVClassesForURIList( vcDao.getSuperClassURIs(vcl.getURI(),false), displayVcDao); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/VclassRetryController.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/VclassRetryController.java index ee00bc64ee..326b4fb1db 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/VclassRetryController.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/VclassRetryController.java @@ -66,11 +66,10 @@ public void doPost (HttpServletRequest req, HttpServletResponse response) { action = epo.getAction(); } - WebappDaoFactory wadf = ModelAccess.on(getServletContext()).getWebappDaoFactory(); + WebappDaoFactory wadf = ModelAccess.on(req).getWebappDaoFactory(); VClassDao vcwDao = wadf.getVClassDao(); epo.setDataAccessObject(vcwDao); - VClassGroupDao cgDao = wadf.getVClassGroupDao(); OntologyDao oDao = wadf.getOntologyDao(); VClass vclassForEditing = null; diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/listing/jena/NamespacesListingController.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/listing/jena/NamespacesListingController.java index 05acd18add..79bc5f0710 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/listing/jena/NamespacesListingController.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/listing/jena/NamespacesListingController.java @@ -37,7 +37,7 @@ public void doGet(HttpServletRequest request, HttpServletResponse response) { VitroRequest vrequest = new VitroRequest(request); - OntModel ontModel = ModelAccess.on(getServletContext()).getOntModel(); + OntModel ontModel = ModelAccess.on(vrequest).getOntModel(); ArrayList results = new ArrayList(); request.setAttribute("results",results); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/listing/jena/RestrictionsListingController.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/listing/jena/RestrictionsListingController.java index 02b1769697..7461856210 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/listing/jena/RestrictionsListingController.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/edit/listing/jena/RestrictionsListingController.java @@ -54,7 +54,7 @@ public void doGet(HttpServletRequest request, HttpServletResponse response) { epo = super.createEpo(request); - OntModel ontModel = ModelAccess.on(getServletContext()).getOntModel(); + OntModel ontModel = ModelAccess.on(vrequest).getOntModel(); ObjectPropertyDao opDao = vrequest.getUnfilteredWebappDaoFactory().getObjectPropertyDao(); VClassDao vcDao = vrequest.getUnfilteredWebappDaoFactory().getVClassDao(); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/BrowseController.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/BrowseController.java index 0ee20f2fe7..fcf655e366 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/BrowseController.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/BrowseController.java @@ -3,6 +3,8 @@ package edu.cornell.mannlib.vitro.webapp.controller.freemarker; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -42,6 +44,8 @@ protected ResponseValues processRequest(VitroRequest vreq) { List groups = null; VClassGroupsForRequest vcgc = VClassGroupCache.getVClassGroups(vreq); groups =vcgc.getGroups(); + Collections.sort(groups, publicNameComparator); +// sortGroupListByPublicName(groups); List vcgroups = new ArrayList(groups.size()); for (VClassGroup group : groups) { vcgroups.add(new VClassGroupTemplateModel(group)); @@ -50,4 +54,35 @@ protected ResponseValues processRequest(VitroRequest vreq) { return new TemplateResponseValues(templateName, body); } + public Comparator publicNameComparator = new Comparator() { + + public int compare(VClassGroup s1, VClassGroup s2) { + String groupName1 = s1.getPublicName().toUpperCase(); + String groupName2 = s2.getPublicName().toUpperCase(); + + //ascending order + return groupName1.compareTo(groupName2); + + //descending order + //return groupName2.compareTo(groupName1); + }}; + +// +// public void sortGroupListByPublicName(List groupList) { +// groupList.sort(new Comparator() { +// public int compare(VClassGroup first, VClassGroup second) { +// if (first != null) { +// if (second != null) { +// return (first.getDisplayRank() - second.getDisplayRank()); +// } else { +// log.error("error--2nd VClassGroup is null in VClassGroupDao.getGroupList().compare()"); +// } +// } else { +// log.error("error--1st VClassGroup is null in VClassGroupDao.getGroupList().compare()"); +// } +// return 0; +// } +// }); +// } + } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/DeletePropertyController.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/DeletePropertyController.java index c62a2c87ab..18fb4f39f8 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/DeletePropertyController.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/DeletePropertyController.java @@ -10,6 +10,9 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.jena.rdf.model.Property; +import org.apache.jena.rdf.model.ResourceFactory; + import edu.cornell.mannlib.vitro.webapp.auth.permissions.SimplePermission; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.AuthorizationRequest; import edu.cornell.mannlib.vitro.webapp.beans.DataProperty; @@ -25,6 +28,8 @@ import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.N3EditUtils; import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess; import edu.cornell.mannlib.vitro.webapp.web.URLEncoder; + + /* * Custom deletion controller to which deletion requests from default property form are sent. May be replaced * later with additional features in process rdf form controller or alternative location. @@ -61,14 +66,14 @@ protected ResponseValues processRequest(VitroRequest vreq) { private String getRedirectUrl(VitroRequest vreq) { - // TODO Auto-generated method stub + // TODO Auto-generated method stub String subjectUri = EditConfigurationUtils.getSubjectUri(vreq); String predicateUri = EditConfigurationUtils.getPredicateUri(vreq); - int hashIndex = predicateUri.lastIndexOf("#"); - String localName = predicateUri.substring(hashIndex + 1); + Property prop = ResourceFactory.createProperty(predicateUri); + String localName = prop.getLocalName(); String redirectUrl = "/entity?uri=" + URLEncoder.encode(subjectUri); - return redirectUrl + "#" + URLEncoder.encode(localName); - } + return redirectUrl + "#" + URLEncoder.encode(localName); + } private String handleErrors(VitroRequest vreq) { diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerHttpServlet.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerHttpServlet.java index bc7766e83f..50f54e2e04 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerHttpServlet.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerHttpServlet.java @@ -8,6 +8,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; +import java.nio.charset.Charset; import java.util.Calendar; import java.util.Date; import java.util.HashMap; @@ -17,7 +18,6 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import edu.cornell.mannlib.vitro.webapp.dao.jena.MenuDaoJena; import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -93,6 +93,8 @@ public void doGet( HttpServletRequest request, HttpServletResponse response ) throws IOException, ServletException { super.doGet(request,response); +//UQAM-Optimization set for UTF-8 + response.setCharacterEncoding("UTF-8"); VitroRequest vreq = new VitroRequest(request); ResponseValues responseValues = null; @@ -103,8 +105,8 @@ public void doGet( HttpServletRequest request, HttpServletResponse response ) if (!isAuthorizedToDisplayPage(request, response, requiredActions(vreq))) { return; } - responseValues = processRequest(vreq); + doResponse(vreq, response, responseValues); } catch (Throwable e) { @@ -256,7 +258,7 @@ private void doNotAuthorized(VitroRequest vreq, protected void doTemplate(VitroRequest vreq, HttpServletResponse response, ResponseValues values) throws TemplateProcessingException { - Map templateDataModel = new HashMap(); + Map templateDataModel = new HashMap(); templateDataModel.putAll(getPageTemplateValues(vreq)); // Add the values that we got from the subcontroller processRequest() method, and merge to the template. @@ -276,8 +278,15 @@ protected void doTemplate(VitroRequest vreq, HttpServletResponse response, // is specified in the main page template. bodyString = ""; } + templateDataModel.put("body", bodyString); + String lang = vreq.getLocale().getLanguage(); + if (!vreq.getLocale().getCountry().isEmpty()) { + lang += "-" + vreq.getLocale().getCountry(); + } + templateDataModel.put("country", lang); + // Tell the template and any directives it uses that we're processing a page template. templateDataModel.put("templateType", PAGE_TEMPLATE_TYPE); @@ -462,7 +471,7 @@ private String normalizeServletName(String name) { protected MainMenu getDisplayModelMenu(VitroRequest vreq){ String url = vreq.getRequestURI().substring(vreq.getContextPath().length()); - return vreq.getWebappDaoFactory().getMenuDao().getMainMenu(vreq, url); + return vreq.getWebappDaoFactory().getMenuDao().getMainMenu(url); } // NIHVIVO-3307: we need this here instead of FreemarkerConfiguration.java so that updates to diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/TemplateProcessingHelper.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/TemplateProcessingHelper.java index 85d648f6b6..c5439d4a24 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/TemplateProcessingHelper.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/freemarker/TemplateProcessingHelper.java @@ -42,7 +42,7 @@ private void processTemplate(Template template, Map map, Writer try { Environment env = template.createProcessingEnvironment(map, writer); - + // Define a setup template to be included by every page template String templateType = (String) map.get("templateType"); if (FreemarkerHttpServlet.PAGE_TEMPLATE_TYPE.equals(templateType)) { diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/json/GetRandomSearchIndividualsByVClass.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/json/GetRandomSearchIndividualsByVClass.java index 8f3aaa3119..325683d542 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/json/GetRandomSearchIndividualsByVClass.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/controller/json/GetRandomSearchIndividualsByVClass.java @@ -4,6 +4,7 @@ import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import com.fasterxml.jackson.databind.node.ArrayNode; @@ -15,6 +16,7 @@ import edu.cornell.mannlib.vitro.webapp.beans.Individual; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.dao.IndividualDao; +import edu.cornell.mannlib.vitro.webapp.i18n.selection.SelectedLocale; import edu.cornell.mannlib.vitro.webapp.services.shortview.ShortViewService; import edu.cornell.mannlib.vitro.webapp.services.shortview.ShortViewService.ShortViewContext; import edu.cornell.mannlib.vitro.webapp.services.shortview.ShortViewServiceSetup; @@ -73,7 +75,11 @@ private String renderShortView(String individualUri, String vclassName) { modelMap.put("individual", IndividualTemplateModelBuilder.build(individual, vreq)); modelMap.put("vclass", vclassName); - + String langCtx = vreq.getLocale().getLanguage(); //UQAM-Linguistic-Management build the linguistic context + if (!vreq.getLocale().getCountry().isEmpty()) { + langCtx += "-" + vreq.getLocale().getCountry(); + } + modelMap.put("langCtx", langCtx); // UQAM-Linguistic-Management add the linguistic context to map ShortViewService svs = ShortViewServiceSetup.getService(ctx); return svs.renderShortView(individual, ShortViewContext.BROWSE, modelMap, vreq); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/WebappDaoFactory.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/WebappDaoFactory.java index 622367e233..7ebe8a2097 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/WebappDaoFactory.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/WebappDaoFactory.java @@ -5,6 +5,8 @@ import java.util.List; import java.util.Set; +import edu.cornell.mannlib.vitro.webapp.i18n.I18nBundle; + public interface WebappDaoFactory { /** @@ -132,4 +134,6 @@ public interface WebappDaoFactory { public MenuDao getMenuDao(); + public I18nBundle getI18nBundle(); + } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/WebappDaoFactoryConfig.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/WebappDaoFactoryConfig.java index 3d3dc4afd0..9ab5563f5c 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/WebappDaoFactoryConfig.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/WebappDaoFactoryConfig.java @@ -5,21 +5,25 @@ import java.util.Arrays; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; import edu.cornell.mannlib.vitro.webapp.dao.PropertyDao.FullPropertyKey; +import edu.cornell.mannlib.vitro.webapp.rdfservice.filter.LanguageFilteringUtils; public class WebappDaoFactoryConfig { private List preferredLanguages; + private List preferredLocales; private String defaultNamespace; private Set nonUserNamespaces; private boolean isUnderlyingStoreReasoned = false; public Map customListViewConfigFileMap; public WebappDaoFactoryConfig() { - preferredLanguages = Arrays.asList("en-US", "en", "EN"); + preferredLanguages = Arrays.asList("en-US", "en", "EN"); + preferredLocales = LanguageFilteringUtils.languagesToLocales(preferredLanguages); defaultNamespace = "http://vitro.mannlib.cornell.edu/ns/default#"; nonUserNamespaces = new HashSet(); nonUserNamespaces.add(VitroVocabulary.vitroURI); @@ -33,6 +37,14 @@ public void setPreferredLanguages(List pl) { this.preferredLanguages = pl; } + public List getPreferredLocales() { + return this.preferredLocales; + } + + public void setPreferredLocales(List pl) { + this.preferredLocales = pl; + } + public String getDefaultNamespace() { return defaultNamespace; } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/filtering/DataPropertyDaoFiltering.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/filtering/DataPropertyDaoFiltering.java index 85d21a14f2..9028f3c933 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/filtering/DataPropertyDaoFiltering.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/filtering/DataPropertyDaoFiltering.java @@ -17,7 +17,7 @@ import edu.cornell.mannlib.vitro.webapp.dao.InsertException; import edu.cornell.mannlib.vitro.webapp.dao.filtering.filters.VitroFilters; -class DataPropertyDaoFiltering extends BaseFiltering implements DataPropertyDao{ +public class DataPropertyDaoFiltering extends BaseFiltering implements DataPropertyDao{ final DataPropertyDao innerDataPropertyDao; final VitroFilters filters; diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/filtering/DataPropertyStatementDaoFiltering.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/filtering/DataPropertyStatementDaoFiltering.java index 5bcc788306..961763297b 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/filtering/DataPropertyStatementDaoFiltering.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/filtering/DataPropertyStatementDaoFiltering.java @@ -18,7 +18,7 @@ import edu.cornell.mannlib.vitro.webapp.dao.DataPropertyStatementDao; import edu.cornell.mannlib.vitro.webapp.dao.filtering.filters.VitroFilters; -class DataPropertyStatementDaoFiltering extends BaseFiltering implements DataPropertyStatementDao{ +public class DataPropertyStatementDaoFiltering extends BaseFiltering implements DataPropertyStatementDao{ final DataPropertyStatementDao innerDataPropertyStatementDao; final VitroFilters filters; diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/filtering/FauxPropertyDaoFiltering.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/filtering/FauxPropertyDaoFiltering.java index bc79e1443f..796bbc8dff 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/filtering/FauxPropertyDaoFiltering.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/filtering/FauxPropertyDaoFiltering.java @@ -26,47 +26,34 @@ public FauxPropertyDaoFiltering(FauxPropertyDao fauxPropertyDao, @Override public List getFauxPropertiesForBaseUri(String uri) { - // TODO Auto-generated method stub - throw new RuntimeException( - "FauxPropertyDao.getFauxPropertiesForBaseUri() not implemented."); + return innerFauxPropertyDao.getFauxPropertiesForBaseUri(uri); } @Override public FauxProperty getFauxPropertyFromContextUri(String contextUri) { - // TODO Auto-generated method stub - throw new RuntimeException( - "FauxPropertyDaoFiltering.getFauxPropertyFromConfigContextUri() not implemented."); - + return innerFauxPropertyDao.getFauxPropertyFromContextUri(contextUri); } @Override public FauxProperty getFauxPropertyByUris(String domainUri, String baseUri, String rangeUri) { - // TODO Auto-generated method stub - throw new RuntimeException( - "FauxPropertyDaoFiltering.getFauxPropertyByUris() not implemented."); - + return innerFauxPropertyDao.getFauxPropertyByUris(domainUri, baseUri, + rangeUri); } @Override public void updateFauxProperty(FauxProperty fp) { - // TODO Auto-generated method stub - throw new RuntimeException("FauxPropertyDaoFiltering.updateFauxProperty() not implemented."); - + innerFauxPropertyDao.updateFauxProperty(fp); } @Override public void deleteFauxProperty(FauxProperty fp) { - // TODO Auto-generated method stub - throw new RuntimeException("FauxPropertyDao.deleteFauxProperty() not implemented."); - + innerFauxPropertyDao.deleteFauxProperty(fp); } @Override public void insertFauxProperty(FauxProperty fp) { - // TODO Auto-generated method stub - throw new RuntimeException("FauxPropertyDao.insertFauxProperty() not implemented."); - + innerFauxPropertyDao.insertFauxProperty(fp); } } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/filtering/IndividualDaoFiltering.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/filtering/IndividualDaoFiltering.java index 74a275f8b6..e9121cd7fc 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/filtering/IndividualDaoFiltering.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/filtering/IndividualDaoFiltering.java @@ -20,7 +20,7 @@ import edu.cornell.mannlib.vitro.webapp.edit.EditLiteral; -class IndividualDaoFiltering extends BaseFiltering implements IndividualDao{ +public class IndividualDaoFiltering extends BaseFiltering implements IndividualDao{ IndividualDao innerIndividualDao; VitroFilters filters; diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/filtering/ObjectPropertyDaoFiltering.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/filtering/ObjectPropertyDaoFiltering.java index c85ca36a51..30cd705213 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/filtering/ObjectPropertyDaoFiltering.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/filtering/ObjectPropertyDaoFiltering.java @@ -17,7 +17,7 @@ import edu.cornell.mannlib.vitro.webapp.dao.ObjectPropertyDao; import edu.cornell.mannlib.vitro.webapp.dao.filtering.filters.VitroFilters; -class ObjectPropertyDaoFiltering extends BaseFiltering implements ObjectPropertyDao{ +public class ObjectPropertyDaoFiltering extends BaseFiltering implements ObjectPropertyDao{ final ObjectPropertyDao innerObjectPropertyDao; final VitroFilters filters; diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/filtering/ObjectPropertyStatementDaoFiltering.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/filtering/ObjectPropertyStatementDaoFiltering.java index 3aa4ea3ab5..8ccc636cc6 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/filtering/ObjectPropertyStatementDaoFiltering.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/filtering/ObjectPropertyStatementDaoFiltering.java @@ -16,7 +16,7 @@ import edu.cornell.mannlib.vitro.webapp.dao.ObjectPropertyStatementDao; import edu.cornell.mannlib.vitro.webapp.dao.filtering.filters.VitroFilters; -class ObjectPropertyStatementDaoFiltering extends BaseFiltering implements ObjectPropertyStatementDao{ +public class ObjectPropertyStatementDaoFiltering extends BaseFiltering implements ObjectPropertyStatementDao{ final ObjectPropertyStatementDao innerObjectPropertyStatementDao; final VitroFilters filters; diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/filtering/WebappDaoFactoryFiltering.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/filtering/WebappDaoFactoryFiltering.java index 84e2823d7f..fdb386a128 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/filtering/WebappDaoFactoryFiltering.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/filtering/WebappDaoFactoryFiltering.java @@ -24,6 +24,7 @@ import edu.cornell.mannlib.vitro.webapp.dao.VClassGroupDao; import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; import edu.cornell.mannlib.vitro.webapp.dao.filtering.filters.VitroFilters; +import edu.cornell.mannlib.vitro.webapp.i18n.I18nBundle; /** * This wraps a WebappDaoFactory and applies filtering. @@ -67,7 +68,7 @@ public class WebappDaoFactoryFiltering implements WebappDaoFactory { transient private PropertyGroupDao filteringPropertyGroupDao=null; transient private PropertyInstanceDao filteringPropertyInstanceDao=null; - public WebappDaoFactoryFiltering( WebappDaoFactory innerDao, VitroFilters filters){ + public WebappDaoFactoryFiltering(WebappDaoFactory innerDao, VitroFilters filters){ if( innerDao == null ) throw new Error("innerWebappDaoFactory must be non-null"); this.filters = filters; @@ -276,4 +277,9 @@ public DisplayModelDao getDisplayModelDao(){ public void close() { innerWebappDaoFactory.close(); } + + @Override + public I18nBundle getI18nBundle() { + return innerWebappDaoFactory.getI18nBundle(); + } } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/ApplicationDaoJena.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/ApplicationDaoJena.java index 884c5f9643..9e1898020b 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/ApplicationDaoJena.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/ApplicationDaoJena.java @@ -83,22 +83,21 @@ public void updateApplicationBean(ApplicationBean application) { } ontModel.enterCriticalSection(Lock.WRITE); try { - appInd.setLabel(application.getApplicationName(), null); - updatePropertyStringValue( - appInd, APPLICATION_ABOUTTEXT, application.getAboutText(), - ontModel); - updatePropertyStringValue( + updateRDFSLabel(appInd, application.getApplicationName()); + updatePlainLiteralValue( + appInd, APPLICATION_ABOUTTEXT, application.getAboutText()); + updatePlainLiteralValue( appInd, APPLICATION_ACKNOWLEGETEXT, - application.getAcknowledgeText(), ontModel); + application.getAcknowledgeText()); updatePropertyStringValue( appInd, APPLICATION_CONTACTMAIL, application.getContactMail(), ontModel); updatePropertyStringValue( appInd, APPLICATION_CORRECTIONMAIL, application.getCorrectionMail(), ontModel); - updatePropertyStringValue( + updatePlainLiteralValue( appInd, APPLICATION_COPYRIGHTANCHOR, - application.getCopyrightAnchor(), ontModel); + application.getCopyrightAnchor()); updatePropertyStringValue( appInd, APPLICATION_COPYRIGHTURL, application.getCopyrightURL(), ontModel); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/DataPropertyDaoJena.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/DataPropertyDaoJena.java index a17ef6ec1e..5c836281db 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/DataPropertyDaoJena.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/DataPropertyDaoJena.java @@ -516,9 +516,9 @@ public String insertDataProperty(DataProperty dtp, OntModel ontModel) throws Ins if (dtp.getFunctional()) { ontModel.add(jDataprop,RDF.type,OWL.FunctionalProperty); } - addPropertyStringValue(jDataprop, EXAMPLE, dtp.getExample(), ontModel); - addPropertyStringValue(jDataprop, DESCRIPTION_ANNOT, dtp.getDescription(), ontModel); - addPropertyStringValue(jDataprop, PUBLIC_DESCRIPTION_ANNOT, dtp.getPublicDescription(), ontModel); + updatePlainLiteralValue(jDataprop, EXAMPLE, dtp.getExample()); + updatePlainLiteralValue(jDataprop, DESCRIPTION_ANNOT, dtp.getDescription()); + updatePlainLiteralValue(jDataprop, PUBLIC_DESCRIPTION_ANNOT, dtp.getPublicDescription()); addPropertyStringValue(jDataprop, EDITING, dtp.getEditing(), ontModel); addPropertyNonNegativeIntValue(jDataprop, DISPLAY_RANK_ANNOT, dtp.getDisplayTier(), ontModel); addPropertyNonNegativeIntValue(jDataprop, DISPLAY_LIMIT, dtp.getDisplayLimit(), ontModel); @@ -587,9 +587,9 @@ public void updateDataProperty(DataProperty dtp, OntModel ontModel) { } } - updatePropertyStringValue(jDataprop, EXAMPLE, dtp.getExample(), ontModel); - updatePropertyStringValue(jDataprop, DESCRIPTION_ANNOT, dtp.getDescription(), ontModel); - updatePropertyStringValue(jDataprop, PUBLIC_DESCRIPTION_ANNOT, dtp.getPublicDescription(), ontModel); + updatePlainLiteralValue(jDataprop, EXAMPLE, dtp.getExample()); + updatePlainLiteralValue(jDataprop, DESCRIPTION_ANNOT, dtp.getDescription()); + updatePlainLiteralValue(jDataprop, PUBLIC_DESCRIPTION_ANNOT, dtp.getPublicDescription()); updatePropertyStringValue(jDataprop, EDITING, dtp.getEditing(), ontModel); updatePropertyNonNegativeIntValue(jDataprop, DISPLAY_RANK_ANNOT, dtp.getDisplayTier(), ontModel); updatePropertyNonNegativeIntValue(jDataprop, DISPLAY_LIMIT, dtp.getDisplayLimit(), ontModel); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/FauxPropertyDaoJena.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/FauxPropertyDaoJena.java index 744881f7f4..a454e1d1e5 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/FauxPropertyDaoJena.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/FauxPropertyDaoJena.java @@ -230,10 +230,9 @@ public void insertFauxProperty(FauxProperty fp) { OBJECT_PROPERTY_DISPLAY_CONFIG); addPropertyResourceURINotEmpty(config, PROPERTY_GROUP, fp.getGroupURI()); - addPropertyStringValue(config, DISPLAY_NAME, fp.getDisplayName(), - displayModel); - addPropertyStringValue(config, PUBLIC_DESCRIPTION_ANNOT, - fp.getPublicDescription(), displayModel); + updatePlainLiteralValue(config, DISPLAY_NAME, fp.getDisplayName()); + updatePlainLiteralValue(config, PUBLIC_DESCRIPTION_ANNOT, + fp.getPublicDescription()); addPropertyIntValue(config, DISPLAY_RANK_ANNOT, fp.getDisplayTier(), displayModel); addPropertyIntValue(config, DISPLAY_LIMIT, fp.getDisplayLimit(), @@ -328,10 +327,10 @@ public void updateFauxProperty(FauxProperty fp) { .getConfigUri()); updatePropertyResourceURIValue(config, PROPERTY_GROUP, fp.getGroupURI()); - updatePropertyStringValue(config, DISPLAY_NAME, - fp.getDisplayName(), displayModel); - updatePropertyStringValue(config, PUBLIC_DESCRIPTION_ANNOT, - fp.getPublicDescription(), displayModel); + updatePlainLiteralValue(config, DISPLAY_NAME, + fp.getDisplayName()); + updatePlainLiteralValue(config, PUBLIC_DESCRIPTION_ANNOT, + fp.getPublicDescription()); updatePropertyIntValue(config, DISPLAY_RANK_ANNOT, fp.getDisplayTier(), displayModel); updatePropertyIntValue(config, DISPLAY_LIMIT, fp.getDisplayLimit(), diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaBaseDao.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaBaseDao.java index f96349bcf4..9b04581094 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaBaseDao.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaBaseDao.java @@ -5,8 +5,8 @@ import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashSet; @@ -14,14 +14,14 @@ import java.util.List; import java.util.Set; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.jena.iri.IRI; -import org.apache.jena.iri.IRIFactory; - import org.apache.jena.datatypes.xsd.XSDDatatype; import org.apache.jena.graph.Node; import org.apache.jena.graph.NodeFactory; +import org.apache.jena.iri.IRI; +import org.apache.jena.iri.IRIFactory; import org.apache.jena.ontology.DatatypeProperty; import org.apache.jena.ontology.ObjectProperty; import org.apache.jena.ontology.OntClass; @@ -39,6 +39,7 @@ import org.apache.jena.rdf.model.Property; import org.apache.jena.rdf.model.RDFNode; import org.apache.jena.rdf.model.Resource; +import org.apache.jena.rdf.model.ResourceFactory; import org.apache.jena.rdf.model.Statement; import org.apache.jena.rdf.model.StmtIterator; import org.apache.jena.shared.Lock; @@ -752,22 +753,111 @@ protected void updatePropertyResourceURIValues(Resource res, Property prop, } } } + + /** + * Add to an OntResource an rdfs:label value with lexical form and default + * language tag. Remove any other existing values in default language. + * If lexicalForm parameter is null, remove all plain literal values of + * Property in default language. + * @param ontRes may not be null + * @param lexicalForm may be null. If null, existing values will be deleted + * but none will be added. + */ + protected void updateRDFSLabel(OntResource ontRes, String lexicalForm) { + updatePlainLiteralValue(ontRes, RDFS.label, lexicalForm); + } + + /** + * Add to an OntResource an rdfs:label value with lexical form and optional + * language tag. Remove any other existing plain literal values that match + * specified language or lack language tags if no language is supplied. + * If lexicalForm parameter is null, remove all plain literal labels in + * specified language, or all existing language-less labels + * if no language is specified. + * @param ontRes may not be null + * @param lexicalForm may be null. If null, existing values will be deleted + * but none will be added. + * @param lang may be null. If null, method acts on language-less plain + * literal labels and ignores those with language tags. + */ + protected void updateRDFSLabel(OntResource ontRes, String lexicalForm, String lang) { + updatePlainLiteralValue(ontRes, RDFS.label, lexicalForm, lang); + } /** - * convenience method for updating the RDFS label + * Add to an OntResource a Property value with lexical form and default + * language tag. Remove any other existing values in default language. + * If lexicalForm parameter is null, remove all plain literal values of + * Property in default language. + * @param ontRes may not be null + * @param lexicalForm may be null. If null, existing values will be deleted + * but none will be added. */ - protected void updateRDFSLabel(OntResource ontRes, String label) { - - if (label != null && label.length() > 0) { - - String existingValue = ontRes.getLabel(getDefaultLanguage()); - - if (existingValue == null || !existingValue.equals(label)) { - ontRes.setLabel(label, getDefaultLanguage()); - } - } else { - ontRes.removeAll(RDFS.label); - } + protected void updatePlainLiteralValue(OntResource ontRes, Property property, + String lexicalForm) { + updatePlainLiteralValue(ontRes, property, lexicalForm, getDefaultLanguage()); + } + + /** + * Add to an OntResource a Property value with lexical form and optional + * language tag. Remove any other existing plain literal values that match + * specified language or lack language tags if no language is supplied. + * If lexicalForm parameter is null, remove all plain literal values of + * Property in specified language, or all existing language-less literals + * if no language is specified. + * @param ontRes may not be null + * @param lexicalForm may be null. If null, existing values will be deleted + * but none will be added. + * @param lang may be null. If null, method acts on language-less + * plain literal values and ignores those with language tags. + */ + protected void updatePlainLiteralValue(OntResource ontRes, Property property, + String lexicalForm, String lang) { + if(ontRes == null) { + throw new IllegalArgumentException("ontRes may not be null."); + } + boolean addNew = true; + List toRemove = new ArrayList(); + StmtIterator existingStmts = ontRes.listProperties(property); + while(existingStmts.hasNext()) { + Statement stmt = existingStmts.next(); + if(stmt.getObject().isLiteral()) { + Literal lit = stmt.getObject().asLiteral(); + if( (lang == null && isLanguageLessPlainLiteral(lit)) + || (lang != null && lang.equals(lit.getLanguage())) ) { + if(!lit.getLexicalForm().equals(lexicalForm)) { + toRemove.add(stmt); + } else { + // New literal already exists in the model. + // Do not add it again. + addNew = false; + } + } + } + } + if(!toRemove.isEmpty()) { + ontRes.getModel().remove(toRemove); + } + if (addNew && (lexicalForm != null)) { + if(!StringUtils.isEmpty(lang)) { + ontRes.addProperty(property, ResourceFactory.createLangLiteral( + lexicalForm, lang)); + } else { + ontRes.addProperty(property, ResourceFactory.createPlainLiteral( + lexicalForm)); + } + } + } + + private boolean isLanguageLessPlainLiteral(Literal lit) { + // In RDF 1.1 all the language-less literals get datatype xsd:string. + // The null datatype check is here just in case this gets run on an older + // version of Jena. rdf:PlainLiteral is also a datatype, but doesn't + // (yet) seem to be used by Jena. + return StringUtils.isEmpty(lit.getLanguage()) + && ((lit.getDatatype() == null) + || XSDDatatype.XSDstring.equals(lit.getDatatype()) || + (RDF.getURI() + "PlainLiteral").equals(lit.getDatatypeURI())); } private Literal getLabel(String lang, ListlabelList) { @@ -780,6 +870,13 @@ private Literal getLabel(String lang, ListlabelList) { } if ((lang != null) && (lang.equals(labelLanguage))) { return labelLit; + } else + /* + * UQAM-Linguistic-Management + * Check for country-part of lang (ex: 'en' for default consideration of labelLanguage in english but not encoded by 'en-US' most case of labels in vivo.owl) + */ + if ((lang != null) && (Arrays.asList(lang.split("-")).get(0).equals(labelLanguage))) { + return labelLit; } } } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/MenuDaoJena.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/MenuDaoJena.java index 73da8f76b2..30dd022c94 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/MenuDaoJena.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/MenuDaoJena.java @@ -72,6 +72,7 @@ public MainMenu getMainMenu( String url ) { return getMenu( getOntModelSelector().getDisplayModel(), url ); } + @Override public MainMenu getMainMenu( ServletRequest req, String url ) { OntModel displayModel = LanguageFilteringUtils.wrapOntModelInALanguageFilter(getOntModelSelector().getDisplayModel(), req ); return getMenu(displayModel, url) ; diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/ObjectPropertyDaoJena.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/ObjectPropertyDaoJena.java index ea4d5f0415..9ae00d59e5 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/ObjectPropertyDaoJena.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/ObjectPropertyDaoJena.java @@ -714,14 +714,14 @@ private void doUpdate(ObjectProperty prop, OntProperty p, OntProperty inv, OntMo } } - updatePropertyStringValue(p,EXAMPLE_ANNOT,prop.getExample(),getOntModel()); - updatePropertyStringValue(p,DESCRIPTION_ANNOT,prop.getDescription(),getOntModel()); - updatePropertyStringValue(p,PUBLIC_DESCRIPTION_ANNOT,prop.getPublicDescription(),getOntModel()); + updatePlainLiteralValue(p, EXAMPLE_ANNOT, prop.getExample()); + updatePlainLiteralValue(p, DESCRIPTION_ANNOT, prop.getDescription()); + updatePlainLiteralValue(p, PUBLIC_DESCRIPTION_ANNOT, prop.getPublicDescription()); updatePropertyNonNegativeIntegerValue(p,DISPLAY_LIMIT,prop.getDomainDisplayLimitInteger(),getOntModel()); updatePropertyStringValue(p,PROPERTY_ENTITYSORTDIRECTION,prop.getDomainEntitySortDirection(),getOntModel()); if (inv != null) { - updatePropertyStringValue(inv,EXAMPLE_ANNOT,prop.getExample(),getOntModel()); - updatePropertyStringValue(inv,DESCRIPTION_ANNOT,prop.getDescription(),getOntModel()); + updatePlainLiteralValue(inv, EXAMPLE_ANNOT, prop.getExample()); + updatePlainLiteralValue(inv, DESCRIPTION_ANNOT, prop.getDescription()); updatePropertyNonNegativeIntegerValue(inv,DISPLAY_LIMIT,prop.getRangeDisplayLimitInteger(),getOntModel()); updatePropertyStringValue(inv,PROPERTY_ENTITYSORTDIRECTION,prop.getRangeEntitySortDirection(),getOntModel()); } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/RDFServiceGraph.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/RDFServiceGraph.java index 0b79646b60..ab509c82e0 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/RDFServiceGraph.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/RDFServiceGraph.java @@ -290,6 +290,11 @@ public static String sparqlNode(Node node, String varName) { literalBuff.append("\""); pyString(literalBuff, node.getLiteralLexicalForm()); literalBuff.append("\""); + /* + * UQAM-Bug-Correction + * reversing the condition tests. + * It is important to prioritize the language typology test in order to exploit the linguistic context in testing the type of data + */ if (!StringUtils.isEmpty(node.getLiteralLanguage())) { literalBuff.append("@").append(node.getLiteralLanguage()); } else if (node.getLiteralDatatypeURI() != null) { diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassDaoJena.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassDaoJena.java index 8d79155b18..0c3183f50b 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassDaoJena.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassDaoJena.java @@ -2,6 +2,8 @@ package edu.cornell.mannlib.vitro.webapp.dao.jena; +import static java.lang.String.format; + import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; @@ -60,15 +62,18 @@ import edu.cornell.mannlib.vitro.webapp.dao.VClassDao; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; import edu.cornell.mannlib.vitro.webapp.dao.jena.event.EditEvent; +import edu.cornell.mannlib.vitro.webapp.i18n.I18nBundle; import edu.cornell.mannlib.vitro.webapp.web.URLEncoder; public class VClassDaoJena extends JenaBaseDao implements VClassDao { protected static final Log log = LogFactory.getLog(VClassDaoJena.class); + private final I18nBundle i18n; private boolean isUnderlyingStoreReasoned = false; public VClassDaoJena(WebappDaoFactoryJena wadf, boolean isUnderlyingStoreReasoned) { super(wadf); + this.i18n = wadf.getI18nBundle(); this.isUnderlyingStoreReasoned = isUnderlyingStoreReasoned; } @@ -91,17 +96,19 @@ public String getLabelForClass(OntClass cls,boolean withPrefix,boolean forPickLi Restriction rest = cls.asRestriction(); OntProperty onProperty = rest.getOnProperty(); StringBuilder labelStr = new StringBuilder(); - labelStr.append("restriction on ").append(getLabelOrId(onProperty)).append(": "); + labelStr.append(format("%s ", i18n.text("restriction_on"))) + .append(getLabelOrId(onProperty)) + .append(": "); if (rest.isAllValuesFromRestriction() || rest.isSomeValuesFromRestriction()) { Resource fillerRes = null; if (rest.isAllValuesFromRestriction()) { AllValuesFromRestriction avfRest = rest.asAllValuesFromRestriction(); fillerRes = avfRest.getAllValuesFrom(); - labelStr.append("all values from "); + labelStr.append(format("%s ", i18n.text("all_values_from"))); } else { SomeValuesFromRestriction svfRest = rest.asSomeValuesFromRestriction(); fillerRes = svfRest.getSomeValuesFrom(); - labelStr.append("some values from "); + labelStr.append(format("%s ", i18n.text("some_values_from"))); } if (fillerRes.canAs(OntClass.class)) { OntClass avf = fillerRes.as(OntClass.class); @@ -115,7 +122,7 @@ public String getLabelForClass(OntClass cls,boolean withPrefix,boolean forPickLi } } else if (rest.isHasValueRestriction()) { HasValueRestriction hvRest = rest.asHasValueRestriction(); - labelStr.append("has value "); + labelStr.append(format("%s ", i18n.text("has_value"))); RDFNode fillerNode = hvRest.getHasValue(); try { if (fillerNode.isResource()) { @@ -128,22 +135,22 @@ public String getLabelForClass(OntClass cls,boolean withPrefix,boolean forPickLi } } else if (rest.isMinCardinalityRestriction()) { MinCardinalityRestriction mcRest = rest.asMinCardinalityRestriction(); - labelStr.append("minimum cardinality "); + labelStr.append(format("%s ", i18n.text("minimum_cardinality"))); labelStr.append(mcRest.getMinCardinality()); } else if (rest.isMaxCardinalityRestriction()) { MaxCardinalityRestriction mcRest = rest.asMaxCardinalityRestriction(); - labelStr.append("maximum cardinality "); + labelStr.append(format("%s ", i18n.text("maximum_cardinality"))); labelStr.append(mcRest.getMaxCardinality()); } else if (rest.isCardinalityRestriction()) { CardinalityRestriction cRest = rest.asCardinalityRestriction(); - labelStr.append("cardinality "); + labelStr.append(format("%s ", i18n.text("cardinality"))); labelStr.append(cRest.getCardinality()); } return labelStr.toString(); } else if (isBooleanClassExpression(cls)) { StringBuilder labelStr = new StringBuilder("("); if (cls.isComplementClass()) { - labelStr.append("not "); + labelStr.append(format("%s ", i18n.text("not"))); ComplementClass ccls = cls.as(ComplementClass.class); labelStr.append(getLabelForClass(ccls.getOperand(), withPrefix, forPickList)); } else if (cls.isIntersectionClass()) { @@ -153,7 +160,7 @@ public String getLabelForClass(OntClass cls,boolean withPrefix,boolean forPickLi OntClass operand = operandIt.next(); labelStr.append(getLabelForClass(operand, withPrefix, forPickList)); if (operandIt.hasNext()) { - labelStr.append(" and "); + labelStr.append(format(" %s ", i18n.text("and"))); } } } else if (cls.isUnionClass()) { @@ -163,7 +170,7 @@ public String getLabelForClass(OntClass cls,boolean withPrefix,boolean forPickLi OntClass operand = operandIt.next(); labelStr.append(getLabelForClass(operand, withPrefix, forPickList)); if (operandIt.hasNext()) { - labelStr.append(" or "); + labelStr.append(format(" %s ", i18n.text("or"))); } } } @@ -952,9 +959,9 @@ public int insertNewVClass(VClass cls, OntModel ontModel) throws InsertException } catch (Exception e) { log.error("error linking class "+cls.getURI()+" to class group"); } - addPropertyStringValue(ontCls,SHORTDEF,cls.getShortDef(),ontModel); - addPropertyStringValue(ontCls,EXAMPLE_ANNOT,cls.getExample(),ontModel); - addPropertyStringValue(ontCls,DESCRIPTION_ANNOT,cls.getDescription(),ontModel); + updatePlainLiteralValue(ontCls, SHORTDEF, cls.getShortDef()); + updatePlainLiteralValue(ontCls, EXAMPLE_ANNOT, cls.getExample()); + updatePlainLiteralValue(ontCls, DESCRIPTION_ANNOT, cls.getDescription()); addPropertyIntValue(ontCls,DISPLAY_LIMIT,cls.getDisplayLimit(),ontModel); addPropertyIntValue(ontCls,DISPLAY_RANK_ANNOT,cls.getDisplayRank(),ontModel); @@ -1011,9 +1018,9 @@ public void updateVClass(VClass cls, OntModel ontModel) { if (ontCls != null) { updateRDFSLabel(ontCls, cls.getName()); updatePropertyResourceURIValue(ontCls,IN_CLASSGROUP,cls.getGroupURI(),ontModel); - updatePropertyStringValue(ontCls,SHORTDEF,cls.getShortDef(),ontModel); - updatePropertyStringValue(ontCls,EXAMPLE_ANNOT,cls.getExample(),ontModel); - updatePropertyStringValue(ontCls,DESCRIPTION_ANNOT,cls.getDescription(),ontModel); + updatePlainLiteralValue(ontCls, SHORTDEF, cls.getShortDef()); + updatePlainLiteralValue(ontCls, EXAMPLE_ANNOT, cls.getExample()); + updatePlainLiteralValue(ontCls, DESCRIPTION_ANNOT, cls.getDescription()); updatePropertyNonNegativeIntValue(ontCls,DISPLAY_LIMIT,cls.getDisplayLimit(),ontModel); updatePropertyNonNegativeIntValue(ontCls,DISPLAY_RANK_ANNOT,cls.getDisplayRank(),ontModel); updatePropertyFloatValue(ontCls, SEARCH_BOOST_ANNOT, cls.getSearchBoost(), ontModel); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassGroupDaoJena.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassGroupDaoJena.java index 3ba868de8a..5a655660b4 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassGroupDaoJena.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassGroupDaoJena.java @@ -276,7 +276,7 @@ public void updateVClassGroup(VClassGroup vcg, OntModel ontModel) { try { Individual groupInd = ontModel.getIndividual(vcg.getURI()); try { - groupInd.setLabel(vcg.getPublicName(), getDefaultLanguage()); + updateRDFSLabel(groupInd, vcg.getPublicName(), getDefaultLanguage()); } catch (Exception e) { log.error("error updating name for "+groupInd.getURI()); } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/WebappDaoFactoryJena.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/WebappDaoFactoryJena.java index 26aabf0be9..813cf27ad1 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/WebappDaoFactoryJena.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dao/jena/WebappDaoFactoryJena.java @@ -50,6 +50,8 @@ import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactoryConfig; +import edu.cornell.mannlib.vitro.webapp.i18n.I18n; +import edu.cornell.mannlib.vitro.webapp.i18n.I18nBundle; import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.jena.model.RDFServiceModel; @@ -611,5 +613,10 @@ public String makePickListName(ResourceBean bean) { } } + @Override + public I18nBundle getI18nBundle() { + // return context based bundle for preferred locales + return I18n.bundle(config.getPreferredLocales()); + } } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/listener/impl/IndividualDataPropertyStatementProcessor.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/listener/impl/IndividualDataPropertyStatementProcessor.java index f2b6cad4f5..b2758c7fd6 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/listener/impl/IndividualDataPropertyStatementProcessor.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/listener/impl/IndividualDataPropertyStatementProcessor.java @@ -4,7 +4,6 @@ import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.Map; import org.apache.commons.logging.Log; diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/BasicValidationVTwo.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/BasicValidationVTwo.java index c5eb8280f6..1e942aa8e0 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/BasicValidationVTwo.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/BasicValidationVTwo.java @@ -24,15 +24,25 @@ import edu.cornell.mannlib.vitro.webapp.dao.jena.DatatypeDaoJena; import edu.cornell.mannlib.vitro.webapp.dao.jena.WebappDaoFactoryJena; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.fields.FieldVTwo; - +import edu.cornell.mannlib.vitro.webapp.i18n.I18nBundle; public class BasicValidationVTwo { + public final static String REQUIRED_FIELD_EMPTY_MSG = "required_field_empty_msg"; + + public final static String DATA_NOT_PAST_MSG = "data_not_past_msg"; + public final static String INVALID_DATE_FORM_MSG = "invalid_date_form_msg"; + public final static String FILE_MUST_BE_ENTERED_MSG = "file_must_be_entered_msg"; + public final static String INVALID_URL_MSG = "invalid_url_msg"; + + private I18nBundle i18n; + Map> varsToValidations; EditConfigurationVTwo editConfig; - public BasicValidationVTwo(EditConfigurationVTwo editConfig, MultiValueEditSubmission editSub){ + public BasicValidationVTwo(EditConfigurationVTwo editConfig, I18nBundle i18n){ this.editConfig = editConfig; + this.i18n = i18n; Map> validatorsForFields = new HashMap>(); for(String fieldName: editConfig.getFields().keySet()){ FieldVTwo field = editConfig.getField(fieldName); @@ -42,8 +52,9 @@ public BasicValidationVTwo(EditConfigurationVTwo editConfig, MultiValueEditSubmi checkValidations(); } - public BasicValidationVTwo(Map> varsToValidations){ + public BasicValidationVTwo(Map> varsToValidations, I18nBundle i18n){ this.varsToValidations = varsToValidations; + this.i18n = i18n; checkValidations(); } @@ -94,7 +105,7 @@ public Map validateLiterals(Map> varNamesTo //If no literals and this field was required, this is an error message //and can return if((literals == null || literals.size() == 0) && isRequiredField) { - errors.put(name, REQUIRED_FIELD_EMPTY_MSG); + errors.put(name, i18n.text(REQUIRED_FIELD_EMPTY_MSG)); break; } //Loop through literals if literals exist @@ -113,7 +124,7 @@ public Map validateLiterals(Map> varNamesTo // incorrectly generate errors. if (isEmpty(value)) { if (isRequiredField) { - errors.put(name, REQUIRED_FIELD_EMPTY_MSG); + errors.put(name, i18n.text(REQUIRED_FIELD_EMPTY_MSG)); } break; } @@ -154,11 +165,11 @@ public Map validateLiterals(Map> varNamesTo private String validate(String validationType, List fileItems) { if( "nonempty".equalsIgnoreCase(validationType)){ if( fileItems == null || fileItems.size() == 0 ){ - return "a file must be entered for this field."; + return i18n.text(FILE_MUST_BE_ENTERED_MSG); }else{ FileItem fileItem = fileItems.get(0); if( fileItem == null || fileItem.getName() == null || fileItem.getName().length() < 1 || fileItem.getSize() < 0){ - return "a file must be entered for this field."; + return i18n.text(FILE_MUST_BE_ENTERED_MSG); } } } @@ -174,14 +185,14 @@ public String validate(String validationType, String value){ // This case may be needed for validation of other field types. if( "nonempty".equalsIgnoreCase(validationType)){ if( isEmpty(value) ) - return REQUIRED_FIELD_EMPTY_MSG; + return i18n.text(REQUIRED_FIELD_EMPTY_MSG); } // Format validation else if("isDate".equalsIgnoreCase(validationType)){ if( isDate( value)) return SUCCESS; else - return "must be in valid date format mm/dd/yyyy."; + return i18n.text(INVALID_DATE_FORM_MSG); } else if( validationType.indexOf("datatype:") == 0 ) { String datatypeURI = validationType.substring(9); @@ -194,7 +205,7 @@ else if( validationType.indexOf("datatype:") == 0 ) { } else if ("httpUrl".equalsIgnoreCase(validationType)){ //check if it has http or https, we could do more but for now this is all. if(! value.startsWith("http://") && ! value.startsWith("https://") ){ - return "This URL must start with http:// or https://"; + return i18n.text(INVALID_URL_MSG); }else{ return SUCCESS; } @@ -216,7 +227,7 @@ else if( "dateNotPast".equalsIgnoreCase(validationType)){ dayParamStr = value.substring(monthDash + 1, value.length()); inputC.set(Integer.parseInt(yearParamStr), Integer.parseInt(monthParamStr) - 1, Integer.parseInt(dayParamStr)); if(inputC.before(c)) { - return this.DATE_NOT_PAST_MSG; + return i18n.text(DATA_NOT_PAST_MSG); //Returning null makes the error message "field is empty" display instead //return null; } else { @@ -278,14 +289,9 @@ private static boolean isEmpty(String value) { return (value == null || value.trim().length() == 0); } - - - private static Pattern urlRX = Pattern.compile("(([a-zA-Z][0-9a-zA-Z+\\-\\.]*:)/{0,2}[0-9a-zA-Z;/?:@&=+$\\.\\-_!~*'()%]+)(#[0-9a-zA-Z;/?:@&=+$\\.\\-_!~*'()%]+)?"); - /** we use null to indicate success */ public final static String SUCCESS = null; - public final static String REQUIRED_FIELD_EMPTY_MSG = "This field must not be empty."; - public final static String DATE_NOT_PAST_MSG = "Please enter a future target date for publication (past dates are invalid)."; + //public final static String MIN_FIELDS_NOT_POPULATED = "Please enter values for at least "; //public final static String FORM_ERROR_FIELD_ID = "formannotationerrors"; /** regex for strings like "12/31/2004" */ diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditConfigurationUtils.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditConfigurationUtils.java index e72e172c13..63164c0ddc 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditConfigurationUtils.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditConfigurationUtils.java @@ -28,6 +28,7 @@ import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.fields.FieldVTwo; import edu.cornell.mannlib.vitro.webapp.freemarker.config.FreemarkerConfiguration; import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess; +import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess.LanguageOption; import freemarker.template.Configuration; public class EditConfigurationUtils { @@ -61,18 +62,24 @@ public static String getRangeUri(VitroRequest vreq) { return vreq.getParameter("rangeUri"); } + public static String getTypeOfNew(VitroRequest vreq) { + return vreq.getParameter("typeOfNew"); + } + public static VClass getRangeVClass(VitroRequest vreq) { - // This needs a WebappDaoFactory with no filtering/RDFService - // funny business because it needs to be able to retrieve anonymous union - // classes by their "pseudo-bnode URIs". - // Someday we'll need to figure out a different way of doing this. WebappDaoFactory ctxDaoFact = ModelAccess.on( vreq.getSession().getServletContext()).getWebappDaoFactory(); return ctxDaoFact.getVClassDao().getVClassByURI(getRangeUri(vreq)); } + public static VClass getLangAwardRangeVClass(VitroRequest vreq) { + // UQAM-Linguistic-Management + WebappDaoFactory vreqDaoFact = ModelAccess.on(vreq).getWebappDaoFactory( + LanguageOption.LANGUAGE_AWARE); + return vreqDaoFact.getVClassDao().getVClassByURI(getRangeUri(vreq)); + } + //get individual - public static Individual getSubjectIndividual(VitroRequest vreq) { Individual subject = null; String subjectUri = getSubjectUri(vreq); @@ -122,12 +129,24 @@ public static ObjectProperty getObjectPropertyForPredicate(VitroRequest vreq, public static ObjectProperty getObjectPropertyForPredicate(VitroRequest vreq, String predicateUri, String domainUri, String rangeUri) { - WebappDaoFactory wdf = vreq.getWebappDaoFactory(); + // WebappDaoFactory wdf = vreq.getWebappDaoFactory(); + // UQAM-Linguistic-Management Use linguistic context + WebappDaoFactory wdf = ModelAccess.on(vreq).getWebappDaoFactory(LanguageOption.LANGUAGE_AWARE); ObjectProperty objectProp = wdf.getObjectPropertyDao().getObjectPropertyByURIs( predicateUri, domainUri, rangeUri); return objectProp; } + // UQAM Use linguistic context + public static ObjectProperty getObjectPropertyForPredicateLangAware(VitroRequest vreq, + String predicateUri, String domainUri, String rangeUri) { + // WebappDaoFactory wdf = vreq.getWebappDaoFactory(); + // UQAM Use linguistic context + WebappDaoFactory wdf = ModelAccess.on(vreq).getWebappDaoFactory(LanguageOption.LANGUAGE_AWARE); + ObjectProperty objectProp = wdf.getObjectPropertyDao().getObjectPropertyByURIs( + predicateUri, domainUri, rangeUri); + return objectProp; + } public static DataProperty getDataPropertyForPredicate(VitroRequest vreq, String predicateUri) { WebappDaoFactory wdf = vreq.getWebappDaoFactory(); //TODO: Check reason for employing unfiltered webapp dao factory and note if using a different version @@ -205,6 +224,7 @@ public static boolean isObjectProperty(String predicateUri, VitroRequest vreq) { return (op != null && dp == null); } + private static boolean isVitroLabel(String predicateUri) { return predicateUri.equals(VitroVocabulary.LABEL); } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditN3GeneratorVTwo.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditN3GeneratorVTwo.java index 0156524458..b81ce06d55 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditN3GeneratorVTwo.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditN3GeneratorVTwo.java @@ -366,6 +366,8 @@ protected static String formatLiteral(Literal literal) { sbuff.append("@") ; sbuff.append(lang) ; + // added by UQAM to exit at this point without adding datatype + return sbuff.toString() ; } // Format the datatype diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/MultiValueEditSubmission.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/MultiValueEditSubmission.java index 8f61f48700..306ebdce78 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/MultiValueEditSubmission.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/MultiValueEditSubmission.java @@ -10,23 +10,23 @@ import java.util.List; import java.util.Map; -import org.apache.commons.fileupload.FileItem; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.joda.time.format.DateTimeFormat; -import org.joda.time.format.DateTimeFormatter; import org.apache.jena.rdf.model.Literal; import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.ModelFactory; import org.apache.jena.rdf.model.ResourceFactory; import org.apache.jena.vocabulary.XSD; +import org.apache.jena.vocabulary.RDF; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.edit.EditLiteral; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.fields.FieldVTwo; +import edu.cornell.mannlib.vitro.webapp.i18n.I18n; public class MultiValueEditSubmission { @@ -34,21 +34,31 @@ public class MultiValueEditSubmission { private Map> literalsFromForm ; private Map> urisFromForm ; - private Map validationErrors; private BasicValidationVTwo basicValidation; - - private Map> filesFromForm; - + private static Model literalCreationModel; - private String entityToReturnTo; + private VitroRequest _vreq; + + private static final String TIME_URI = XSD.time.getURI(); + static{ literalCreationModel = ModelFactory.createDefaultModel(); } - - public MultiValueEditSubmission(Map queryParameters, EditConfigurationVTwo editConfig){ + /* + * UQAM + * replace + * public MultiValueEditSubmission(Map queryParameters, EditConfigurationVTwo editConfig) + * by this new signature + * This affect PostEditCleanupController and ProcessRdfFormController classes. + * This replacement is justified by the fact that we need a linguistic context in this class. + */ + public MultiValueEditSubmission(VitroRequest vreq, EditConfigurationVTwo editConfig){ + // UQAM add this both lines + _vreq = vreq; + Map queryParameters = vreq.getParameterMap(); if( editConfig == null ) throw new Error("EditSubmission needs an EditConfiguration"); this.editKey = editConfig.getEditKey(); @@ -92,11 +102,12 @@ public MultiValueEditSubmission(Map queryParameters, EditConfi processEditElementFields(editConfig,queryParameters); //Incorporating basic validation //Validate URIS - this.basicValidation = new BasicValidationVTwo(editConfig, this); + this.basicValidation = new BasicValidationVTwo(editConfig, I18n.bundle(vreq)); Map errors = basicValidation.validateUris( urisFromForm ); //Validate literals and add errors to the list of existing errors errors.putAll(basicValidation.validateLiterals( literalsFromForm )); - if( errors != null ) { + // UQAM Add empty contition + if( errors != null && !errors.isEmpty()) { validationErrors.putAll( errors); } @@ -141,9 +152,8 @@ protected void processEditElementFields(EditConfigurationVTwo editConfig, Map 0 ) return ResourceFactory.createLangLiteral(value, lang); + } + return literalCreationModel.createTypedLiteral(value, datatypeUri); + // UQAM take into account the linguistic context + } else if( lang != null && lang.length() > 0 ) + return ResourceFactory.createLangLiteral(value, lang); + return ResourceFactory.createPlainLiteral(value); + } public Map getValidationErrors(){ return validationErrors; @@ -264,12 +289,46 @@ public void addLiteralToForm(EditConfigurationVTwo editConfig, FieldVTwo field, for(String value:valueList) { value = N3EditUtils.stripInvalidXMLChars(value); //Add to array of literals corresponding to this variable + /* UQAM OLD if (!StringUtils.isEmpty(value)) { literalsArray.add(createLiteral( value, field.getRangeDatatypeUri(), field.getRangeLang())); } + */ + /* + * UQAM Replaced by this to take the linguistic context into consideration. + */ + if (!StringUtils.isEmpty(value)) { + String rangeLang = field.getRangeLang(); //UQAM Default value + try { + if (_vreq != null ) { + // only if the request comes from the rdfsLabelGenerator the language should be used + Boolean getLabelLanguage = false; + if (!StringUtils.isBlank(editConfig.formUrl) && editConfig.formUrl.contains("RDFSLabelGenerator")) { + getLabelLanguage = true; + } + // if the language is set in the given Literal, this language-tag should be used and remain the same + // for example when you edit an label with an langauge-tag (no matter which language is selected globally) + if (!StringUtils.isBlank(editConfig.getLiteralsInScope().get("label").get(0).getLanguage()) && getLabelLanguage) + { + rangeLang = editConfig.getLiteralsInScope().get("label").get(0).getLanguage(); + } else { // if the literal has no langauge-tag, use the language which is globally selected + rangeLang = _vreq.getLocale().getLanguage(); + if (!_vreq.getLocale().getCountry().isEmpty()) { + rangeLang += "-" + _vreq.getLocale().getCountry(); + } + } + } + + } catch (Exception e) { + } + literalsArray.add(createLiteral( + value, + field.getRangeDatatypeUri(), + rangeLang)); + } } literalsFromForm.put(var, literalsArray); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/ProcessRdfForm.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/ProcessRdfForm.java index 54fd7fb1b3..9652d72dc7 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/ProcessRdfForm.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/ProcessRdfForm.java @@ -9,15 +9,24 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - +import org.apache.jena.datatypes.xsd.XSDDatatype; import org.apache.jena.ontology.OntModel; import org.apache.jena.rdf.model.Literal; import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.ModelFactory; +import org.apache.jena.rdf.model.Property; +import org.apache.jena.rdf.model.RDFNode; +import org.apache.jena.rdf.model.Resource; +import org.apache.jena.rdf.model.ResourceFactory; +import org.apache.jena.rdf.model.Statement; import org.apache.jena.shared.Lock; +import org.apache.jena.vocabulary.RDF; +import org.apache.jena.vocabulary.XSD; +import org.apache.commons.lang3.StringUtils; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.dao.InsertException; @@ -41,6 +50,7 @@ public class ProcessRdfForm { private EditN3GeneratorVTwo populator; private Map urisForNewResources = null; +// private VitroRequest _vreq; /** * Construct the ProcessRdfForm object. */ @@ -76,9 +86,9 @@ public AdditionsAndRetractions process( AdditionsAndRetractions changes; if( configuration.isUpdate() ){ - changes = editExistingStatements(configuration, submission); + changes = editExistingStatements(configuration, submission, vreq); //UQAM vreq for getting linguistic context } else { - changes = createNewStatements(configuration, submission ); + changes = createNewStatements(configuration, submission, vreq ); //UQAM vreq for getting linguistic context } changes = getMinimalChanges(changes); @@ -99,12 +109,15 @@ public AdditionsAndRetractions process( * any optional N3 is to originally configure the * configuration.setN3Optional() to be empty. * + * UQAM add vreq for linguistic context managing + * * @throws Exception May throw an exception if the required N3 * does not parse. + * */ private AdditionsAndRetractions createNewStatements( EditConfigurationVTwo configuration, - MultiValueEditSubmission submission) throws Exception { + MultiValueEditSubmission submission, VitroRequest vreq) throws Exception { log.debug("in createNewStatements()" ); //getN3Required and getN3Optional will return copies of the @@ -113,10 +126,10 @@ private AdditionsAndRetractions createNewStatements( List optionalN3 = configuration.getN3Optional(); /* substitute in the form values and existing values */ - subInValuesToN3( configuration, submission, requiredN3, optionalN3, null , null); + subInValuesToN3( configuration, submission, requiredN3, optionalN3, null , null, vreq); /* parse N3 to RDF Models, No retractions since all of the statements are new. */ - return parseN3ToChange(requiredN3, optionalN3, null, null); + return parseN3ToChange(requiredN3, optionalN3, null, null, vreq, null); } /* for a list of N3 strings, substitute in the subject, predicate and object URIs @@ -140,10 +153,12 @@ protected void substituteInSubPredObjURIs( * retractions are mutually diff'ed before statements are added to or * removed from the model. The explicit change check can cause problems in * more complex setups, like the automatic form building in DataStaR. + * @param vreq For getting linguistic context + */ protected AdditionsAndRetractions editExistingStatements( EditConfigurationVTwo editConfig, - MultiValueEditSubmission submission) throws Exception { + MultiValueEditSubmission submission, VitroRequest vreq) throws Exception { log.debug("editing an existing resource: " + editConfig.getObject() ); @@ -156,18 +171,18 @@ protected AdditionsAndRetractions editExistingStatements( subInValuesToN3(editConfig, submission, N3RequiredAssert, N3OptionalAssert, - N3RequiredRetract, N3OptionalRetract); + N3RequiredRetract, N3OptionalRetract, vreq); return parseN3ToChange( N3RequiredAssert,N3OptionalAssert, - N3RequiredRetract, N3OptionalRetract); + N3RequiredRetract, N3OptionalRetract, vreq, editConfig); } @SuppressWarnings("unchecked") protected void subInValuesToN3( EditConfigurationVTwo editConfig, MultiValueEditSubmission submission, List requiredAsserts, List optionalAsserts, - List requiredRetracts, List optionalRetracts ) throws InsertException{ + List requiredRetracts, List optionalRetracts, VitroRequest vreq ) throws InsertException{ //need to substitute into the return to URL becase it may need new resource URIs List URLToReturnTo = Arrays.asList(submission.getEntityToReturnTo()); @@ -184,7 +199,41 @@ protected void subInValuesToN3( //Retractions does NOT get values from form. /* ******** Form submission Literals *********** */ - substituteInMultiLiterals( submission.getLiteralsFromForm(), requiredAsserts, optionalAsserts, URLToReturnTo); + /* + * UQAM Set all literals in the linguistic context + */ + Map> literalsFromForm = submission.getLiteralsFromForm(); + Set keys = literalsFromForm.keySet(); + for (String aKey : keys) { + List literalFromForm = literalsFromForm.get(aKey); + List newLiteralFromForm = new ArrayList<>(); + for (Literal aLiteral : literalFromForm) { + if (aLiteral != null) { + String aLiteratDT = aLiteral.getDatatype().getURI(); + Literal newLiteral = null; + String aText = aLiteral.getLexicalForm(); + /* + * do it only if aLiteral are xstring datatype + */ + if (RDF.dtLangString.getURI().equals(aLiteratDT) && !aLiteral.getLanguage().isEmpty()) { + newLiteral = aLiteral; + } + else if (XSD.xstring.getURI().equals(aLiteratDT) || RDF.dtLangString.getURI().equals(aLiteratDT)) { + String lang = vreq.getLocale().getLanguage(); + if (!vreq.getLocale().getCountry().isEmpty()) { + lang += "-" + vreq.getLocale().getCountry(); + } + newLiteral = ResourceFactory.createLangLiteral(aText, lang); + } else { + newLiteral = ResourceFactory.createTypedLiteral(aText, aLiteral.getDatatype()); + } + newLiteralFromForm.add(newLiteral); + } + } + literalsFromForm.replace(aKey, newLiteralFromForm); + } + + substituteInMultiLiterals( literalsFromForm, requiredAsserts, optionalAsserts, URLToReturnTo); logSubstitue( "Added form Literals", requiredAsserts, optionalAsserts, requiredRetracts, optionalRetracts); //Retractions does NOT get values from form. @@ -254,20 +303,106 @@ public static void applyChangesToWriteModel( protected AdditionsAndRetractions parseN3ToChange( List requiredAdds, List optionalAdds, - List requiredDels, List optionalDels) throws Exception{ + List requiredDels, List optionalDels, VitroRequest vreq, EditConfigurationVTwo editConfig) throws Exception{ List adds = parseN3ToRDF(requiredAdds, REQUIRED); adds.addAll( parseN3ToRDF(optionalAdds, OPTIONAL)); - List retracts = new ArrayList(); if( requiredDels != null && optionalDels != null ){ - retracts.addAll( parseN3ToRDF(requiredDels, REQUIRED) ); - retracts.addAll( parseN3ToRDF(optionalDels, OPTIONAL) ); + String lingCxt=null; + //UQAM Taking into account the linguistic context in retract + try { + // only if the request comes from the rdfsLabelGenerator the language should be used + Boolean getLabelLanguage = false; + if (!StringUtils.isBlank(editConfig.formUrl) && editConfig.formUrl.contains("RDFSLabelGenerator")) { + getLabelLanguage = true; + } + // if the language is set in the given Literal, this language-tag should be used and remain the same + // for example when you edit an label with an langauge-tag (no matter which language is selected globally) + if (editConfig != null && !StringUtils.isBlank(editConfig.getLiteralsInScope().get("label").get(0).getLanguage()) && getLabelLanguage) { + lingCxt = editConfig.getLiteralsInScope().get("label").get(0).getLanguage(); + } else { // if the literal has no langauge-tag, use the language which is globally selected + lingCxt = vreq.getLocale().getLanguage(); + if (!vreq.getLocale().getCountry().isEmpty()) { + lingCxt += "-" + vreq.getLocale().getCountry(); + } + } + } catch (Exception e) { + } + retracts.addAll( parseN3ToRDF(requiredDels, REQUIRED, lingCxt) ); + retracts.addAll( parseN3ToRDF(optionalDels, OPTIONAL, lingCxt) ); } return new AdditionsAndRetractions(adds,retracts); } + /** + * Parse the n3Strings to a List of RDF Model objects. + * + * @param n3Strings N3 Strings to parse + * @param parseType if OPTIONAL, then don't throw exceptions on errors + * @param linguisticContext For Literals, Making parse only if the literal linguisticContext are same than linguisticContext parameter //UQAM + * If REQUIRED, then throw exceptions on errors. + * @throws Exception + */ + protected static List parseN3ToRDF( + List n3Strings, N3ParseType parseType, String linguisticContext ) throws Exception { + // Use non-linguistic version of this method if no linguisticContext is provided + if (linguisticContext == null) { + return parseN3ToRDF(n3Strings, parseType); + } + + List errorMessages = new ArrayList(); + List rdfModels = new ArrayList(); + for(String n3 : n3Strings){ + try{ + Model model = ModelFactory.createDefaultModel(); + StringReader reader = new StringReader(n3); + model.read(reader, "", "N3"); + List stmts = model.listStatements().toList(); + for (Iterator iterator = stmts.iterator(); iterator.hasNext();) { + Statement stmt = (Statement) iterator.next(); + Resource subj = stmt.getSubject(); + Property pred = stmt.getPredicate(); + RDFNode obj = stmt.getObject(); + if (obj.isLiteral()) { + Literal lit = obj.asLiteral(); + String lang = lit.getLanguage(); + if (! linguisticContext.equals(lang)) { + //UQAM Remove if linguisticContext != lang of the Literal + model.remove(subj, pred, obj); + } + } + + } + rdfModels.add( model ); + }catch(Throwable t){ + errorMessages.add(t.getMessage() + "\nN3: \n" + n3 + "\n"); + } + } + + StringBuilder errors = new StringBuilder(); + for( String errorMsg : errorMessages){ + errors.append(errorMsg).append('\n'); + } + + if( !errorMessages.isEmpty() ){ + if( REQUIRED.equals(parseType) ){ + throw new Exception("Errors processing required N3. The EditConfiguration should " + + "be setup so that if a submission passes validation, there will not be errors " + + "in the required N3.\n" + errors ); + }else if( OPTIONAL.equals(parseType) ){ + log.debug("Some Optional N3 did not parse, if a optional N3 does not parse it " + + "will be ignored. This allows optional parts of a form submission to " + + "remain unfilled out and then the optional N3 does not get values subsituted in from" + + "the form submission values. It may also be the case that there are unintentional " + + "syntax errors the optional N3." ); + log.debug(errors.toString()); + } + } + + return rdfModels; + } /** * Parse the n3Strings to a List of RDF Model objects. * @@ -479,4 +614,4 @@ private void substituteInForcedNewURIs( private static Log log = LogFactory.getLog(ProcessRdfForm.class); -} +} \ No newline at end of file diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/ChildVClassesOptions.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/ChildVClassesOptions.java index f87dd8f488..0c7b44ef20 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/ChildVClassesOptions.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/ChildVClassesOptions.java @@ -7,6 +7,7 @@ import java.util.List; import java.util.Map; +import edu.cornell.mannlib.vitro.webapp.i18n.I18nBundle; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -40,7 +41,8 @@ public ChildVClassesOptions setDefaultOptionLabel(String label){ public Map getOptions( EditConfigurationVTwo editConfig, String fieldName, - WebappDaoFactory wDaoFact) throws Exception{ + WebappDaoFactory wDaoFact, + I18nBundle i18n) throws Exception{ // now create an empty HashMap to populate and return HashMap optionsMap = new LinkedHashMap(); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/ChildVClassesWithParent.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/ChildVClassesWithParent.java index 135b384748..22f5763a42 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/ChildVClassesWithParent.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/ChildVClassesWithParent.java @@ -1,6 +1,6 @@ /* $This file is distributed under the terms of the license in LICENSE$ */ -package edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.fields; +package edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.fields; import java.util.Comparator; import java.util.HashMap; import java.util.LinkedHashMap; @@ -15,6 +15,7 @@ import edu.cornell.mannlib.vitro.webapp.dao.VClassDao; import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo; +import edu.cornell.mannlib.vitro.webapp.i18n.I18nBundle; public class ChildVClassesWithParent implements FieldOptions { @@ -37,20 +38,24 @@ public ChildVClassesWithParent setDefaultOption(String label){ return this; } - @Override +/* + * UQAM-Linguistic-Management + * This method is polymorphism of getOptions(EditConfigurationVTwo editConfig,String fieldName, WebappDaoFactory wDaoFact) + * for the internationalization of word "other" in the scroling list of personHasAdvisorRelationship.ftl + */ public Map getOptions( EditConfigurationVTwo editConfig, String fieldName, - WebappDaoFactory wDaoFact) throws Exception { - + WebappDaoFactory wDaoFact, + I18nBundle i18n) throws Exception { HashMap optionsMap = new LinkedHashMap(); // first test to see whether there's a default "leave blank" value specified with the literal options if ( ! StringUtils.isEmpty( defaultOptionLabel ) ){ optionsMap.put(LEFT_BLANK, defaultOptionLabel); } - - optionsMap.put(classUri, "Other"); - + String other_i18n = i18n.text("other"); + // first character in capital + optionsMap.put(classUri, other_i18n.substring(0, 1).toUpperCase() + other_i18n.substring(1)); VClassDao vclassDao = wDaoFact.getVClassDao(); List subClassList = vclassDao.getAllSubClassURIs(classUri); if (subClassList != null && subClassList.size() > 0) { diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/ConstantFieldOptions.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/ConstantFieldOptions.java index 3c68ac14d8..9fc7662d58 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/ConstantFieldOptions.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/ConstantFieldOptions.java @@ -10,6 +10,7 @@ import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo; +import edu.cornell.mannlib.vitro.webapp.i18n.I18nBundle; public class ConstantFieldOptions implements FieldOptions { @@ -54,7 +55,8 @@ public ConstantFieldOptions(String fieldName2, public Map getOptions( EditConfigurationVTwo editConfig, String fieldName, - WebappDaoFactory wDaoFact) throws Exception { + WebappDaoFactory wDaoFact, + I18nBundle i18n) throws Exception { // originally not auto-sorted but sorted now, and empty values not removed or replaced HashMap optionsMap = new LinkedHashMap(); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/FieldOptions.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/FieldOptions.java index b2c67f5493..772b22913c 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/FieldOptions.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/FieldOptions.java @@ -6,6 +6,7 @@ import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo; +import edu.cornell.mannlib.vitro.webapp.i18n.I18nBundle; /** * Represents an object that can return a list of options @@ -28,7 +29,8 @@ public interface FieldOptions { public Map getOptions( EditConfigurationVTwo editConfig, String fieldName, - WebappDaoFactory wDaoFact) throws Exception; + WebappDaoFactory wDaoFact, + I18nBundle i18n) throws Exception; /* * Certain field options may have custom sorting requirements. If no sorting requirements exist, diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/IndividualsViaClassGroupOptions.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/IndividualsViaClassGroupOptions.java index b0a4990050..fa627a12e5 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/IndividualsViaClassGroupOptions.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/IndividualsViaClassGroupOptions.java @@ -6,6 +6,7 @@ import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo; +import edu.cornell.mannlib.vitro.webapp.i18n.I18nBundle; public class IndividualsViaClassGroupOptions implements FieldOptions { @@ -27,7 +28,8 @@ public IndividualsViaClassGroupOptions setDefaultOptionLabel(String label){ public Map getOptions( EditConfigurationVTwo editConfig, String fieldName, - WebappDaoFactory wDaoFact) throws Exception { + WebappDaoFactory wDaoFact, + I18nBundle i18n) throws Exception { throw new Error("not implemented"); } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/IndividualsViaObjectPropetyOptions.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/IndividualsViaObjectPropetyOptions.java index 6a5d30be55..0cd216ef79 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/IndividualsViaObjectPropetyOptions.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/IndividualsViaObjectPropetyOptions.java @@ -11,6 +11,7 @@ import javax.servlet.http.HttpServletRequest; +import edu.cornell.mannlib.vitro.webapp.i18n.I18nBundle; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -77,7 +78,8 @@ public IndividualsViaObjectPropetyOptions setDefaultOptionLabel(String label){ public Map getOptions( EditConfigurationVTwo editConfig, String fieldName, - WebappDaoFactory wDaoFact) { + WebappDaoFactory wDaoFact, + I18nBundle i18n) { HashMap optionsMap = new LinkedHashMap(); int optionsCount = 0; diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/IndividualsViaSearchQueryOptions.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/IndividualsViaSearchQueryOptions.java index ec7167c581..d752bfe28a 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/IndividualsViaSearchQueryOptions.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/IndividualsViaSearchQueryOptions.java @@ -8,6 +8,7 @@ import java.util.ListIterator; import java.util.Map; +import edu.cornell.mannlib.vitro.webapp.i18n.I18nBundle; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -90,7 +91,8 @@ protected Map getIndividualsForClass(String vclassURI, Webapp public Map getOptions( EditConfigurationVTwo editConfig, String fieldName, - WebappDaoFactory wDaoFact) throws Exception { + WebappDaoFactory wDaoFact, + I18nBundle i18n) throws Exception { Map individualMap = new HashMap(); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/IndividualsViaVClassOptions.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/IndividualsViaVClassOptions.java index 80c9cf273a..374d571ed0 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/IndividualsViaVClassOptions.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/IndividualsViaVClassOptions.java @@ -8,6 +8,7 @@ import java.util.List; import java.util.Map; +import edu.cornell.mannlib.vitro.webapp.i18n.I18nBundle; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -48,7 +49,8 @@ public FieldOptions setDefaultOptionLabel(String label){ public Map getOptions( EditConfigurationVTwo editConfig, String fieldName, - WebappDaoFactory wDaoFact) throws Exception { + WebappDaoFactory wDaoFact, + I18nBundle i18n) throws Exception { Map individualMap = new HashMap(); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/RdfTypeOptions.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/RdfTypeOptions.java index 9943856731..32c520fd38 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/RdfTypeOptions.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/RdfTypeOptions.java @@ -9,6 +9,7 @@ import edu.cornell.mannlib.vitro.webapp.beans.VClass; import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo; +import edu.cornell.mannlib.vitro.webapp.i18n.I18nBundle; public class RdfTypeOptions implements FieldOptions { @@ -29,7 +30,8 @@ public RdfTypeOptions(String ... superClassURIs) public Map getOptions( EditConfigurationVTwo editConfig, String fieldName, - WebappDaoFactory wdf) { + WebappDaoFactory wdf, + I18nBundle i18n) { Map uriToLabel = new HashMap(); for (String uri : typeURIs) { diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/SelectListGeneratorVTwo.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/SelectListGeneratorVTwo.java index 3e732ce588..c554cf39e6 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/SelectListGeneratorVTwo.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/SelectListGeneratorVTwo.java @@ -11,6 +11,8 @@ import java.util.List; import java.util.Map; +import edu.cornell.mannlib.vitro.webapp.i18n.I18n; +import edu.cornell.mannlib.vitro.webapp.i18n.I18nBundle; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -25,7 +27,8 @@ public class SelectListGeneratorVTwo { public static Map getOptions( EditConfigurationVTwo editConfig, String fieldName, - WebappDaoFactory wDaoFact){ + WebappDaoFactory wDaoFact, + I18nBundle i18n){ if( editConfig == null ){ @@ -48,13 +51,51 @@ public static Map getOptions( } try { - return field.getFieldOptions().getOptions(editConfig,fieldName,wDaoFact); + return field.getFieldOptions().getOptions(editConfig,fieldName,wDaoFact,i18n); } catch (Exception e) { log.error("Error runing getFieldOptionis()",e); return Collections.emptyMap(); } } + // UQAM Overcharge method for linguistic contexte processisng + // AWoods: This method appears to never be invoked. + public static Map getOptions( + EditConfigurationVTwo editConfig, + String fieldName, + VitroRequest vreq){ + + + if( editConfig == null ){ + log.error( "fieldToSelectItemList() must be called with a non-null EditConfigurationVTwo "); + return Collections.emptyMap(); + } + if( fieldName == null ){ + log.error( "fieldToSelectItemList() must be called with a non-null fieldName"); + return Collections.emptyMap(); + } + + FieldVTwo field = editConfig.getField(fieldName); + if (field==null) { + log.error("no field \""+fieldName+"\" found from editConfig."); + return Collections.emptyMap(); + } + + if( field.getFieldOptions() == null ){ + return Collections.emptyMap(); + } + + try { + //UQAM need vreq instead of WebappDaoFactory + Map parentClass = Collections.emptyMap(); + FieldOptions fieldOptions = field.getFieldOptions(); + return fieldOptions.getOptions(editConfig,fieldName,vreq.getWebappDaoFactory(), I18n.bundle(vreq)); + } catch (Exception e) { + log.error("Error runing getFieldOptionis()",e); + return Collections.emptyMap(); + } + } + //Methods to sort the options map // from http://forum.java.sun.com/thread.jspa?threadID=639077&messageID=4250708 diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DefaultAddMissingIndividualFormGenerator.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DefaultAddMissingIndividualFormGenerator.java index 702474da29..5537cecacf 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DefaultAddMissingIndividualFormGenerator.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DefaultAddMissingIndividualFormGenerator.java @@ -350,7 +350,7 @@ private String getRangeClassUri(VitroRequest vreq) { private void prepareForUpdate(VitroRequest vreq, HttpSession session, EditConfigurationVTwo editConfiguration) { //Here, retrieve model from - OntModel model = ModelAccess.on(session.getServletContext()).getOntModel(); + OntModel model = ModelAccess.on(vreq).getOntModel(); //if object property if(EditConfigurationUtils.isObjectProperty(EditConfigurationUtils.getPredicateUri(vreq), vreq)){ Individual objectIndividual = EditConfigurationUtils.getObjectIndividual(vreq); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DefaultObjectPropertyFormGenerator.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DefaultObjectPropertyFormGenerator.java index ce471ca98b..adb7e8bb88 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DefaultObjectPropertyFormGenerator.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DefaultObjectPropertyFormGenerator.java @@ -2,6 +2,8 @@ package edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators; +import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess.LANGUAGE_NEUTRAL; +import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess.POLICY_NEUTRAL; import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.DISPLAY; import java.util.ArrayList; @@ -35,6 +37,8 @@ import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.validators.AntiXssValidation; import edu.cornell.mannlib.vitro.webapp.i18n.I18n; import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess; +import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess.LanguageOption; +import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess.PolicyOption; import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchEngine; import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchEngineException; import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchQuery; @@ -125,7 +129,10 @@ protected List getRangeTypes(VitroRequest vreq) { // Someday we'll need to figure out a different way of doing this. //WebappDaoFactory ctxDaoFact = ModelAccess.on( // vreq.getSession().getServletContext()).getWebappDaoFactory(); - WebappDaoFactory ctxDaoFact = vreq.getLanguageNeutralWebappDaoFactory(); +// WebappDaoFactory ctxDaoFact = vreq.getLanguageNeutralWebappDaoFactory(); + //UQAM Linguistic-Management Manage linguistic context + WebappDaoFactory ctxDaoFact = ModelAccess.on(vreq).getWebappDaoFactory(LanguageOption.LANGUAGE_AWARE, PolicyOption.POLICY_NEUTRAL); + List types = new ArrayList(); Individual subject = EditConfigurationUtils.getSubjectIndividual(vreq); @@ -460,7 +467,7 @@ protected void setFields(EditConfigurationVTwo editConfiguration, VitroRequest v private void prepareForUpdate(VitroRequest vreq, HttpSession session, EditConfigurationVTwo editConfiguration) { //Here, retrieve model from - OntModel model = ModelAccess.on(session.getServletContext()).getOntModel(); + OntModel model = ModelAccess.on(vreq).getOntModel(); //if object property if(EditConfigurationUtils.isObjectProperty(EditConfigurationUtils.getPredicateUri(vreq), vreq)){ Individual objectIndividual = EditConfigurationUtils.getObjectIndividual(vreq); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/ManageLabelsForIndividualGenerator.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/ManageLabelsForIndividualGenerator.java index 15782747b7..d2a109895e 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/ManageLabelsForIndividualGenerator.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/ManageLabelsForIndividualGenerator.java @@ -224,6 +224,20 @@ private void addFormSpecificData(EditConfigurationVTwo config, config.addFormSpecificData("displayRemoveLink", (numberExistingLabels > 1)); + // get current selected locale + String rangeLang = vreq.getLocale().getLanguage(); + if (!vreq.getLocale().getCountry().isEmpty()) { + rangeLang += "-" + vreq.getLocale().getCountry(); + } + + // check if locale already has an entry (label) + boolean localeEntryExisting = true; + for (HashMap tmp : availableLocalesForAdd) { + if (tmp.get("code").equals(rangeLang)) localeEntryExisting = false; + } + config.addFormSpecificData("localeEntryExisting", localeEntryExisting); + config.addFormSpecificData("currentSelectedLocale", rangeLang); + //How do we edit? Will need to see config.addFormSpecificData("deleteWebpageUrl", "/edit/primitiveDelete"); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/NewIndividualFormGenerator.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/NewIndividualFormGenerator.java index 8c251467b5..fff4d67324 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/NewIndividualFormGenerator.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/NewIndividualFormGenerator.java @@ -233,7 +233,7 @@ private void setLabelField(EditConfigurationVTwo editConfiguration, private void prepareForUpdate(VitroRequest vreq, HttpSession session, EditConfigurationVTwo editConfiguration) { //Here, retrieve model from - OntModel model = ModelAccess.on(session.getServletContext()).getOntModel(); + OntModel model = ModelAccess.on(vreq).getOntModel(); //This form is always doing a non-update editConfiguration.prepareForNonUpdate( model ); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/RDFSLabelGenerator.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/RDFSLabelGenerator.java index 3a3e7f371e..13e845a868 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/RDFSLabelGenerator.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/RDFSLabelGenerator.java @@ -298,7 +298,7 @@ private List getFieldValidators(EditConfigurationVTwo editConfiguration, private void prepareForUpdate(VitroRequest vreq, HttpSession session, EditConfigurationVTwo editConfiguration) { //Here, retrieve model from - OntModel model = ModelAccess.on(session.getServletContext()).getOntModel(); + OntModel model = ModelAccess.on(vreq).getOntModel(); if( editConfiguration.isDataPropertyUpdate() ){ editConfiguration.prepareForDataPropUpdate(model, vreq.getWebappDaoFactory().getDataPropertyDao()); } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/LimitRemovalsToLanguage.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/LimitRemovalsToLanguage.java new file mode 100644 index 0000000000..acd94dfae7 --- /dev/null +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/LimitRemovalsToLanguage.java @@ -0,0 +1,92 @@ +package edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.preprocessors; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jena.rdf.model.Literal; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.RDFNode; +import org.apache.jena.rdf.model.Statement; +import org.apache.jena.rdf.model.StmtIterator; + +import edu.cornell.mannlib.vitro.webapp.rdfservice.filter.LanguageFilteringUtils; + +/** + * A model change preprocessor that discards triples with language tags + * in the retractionsModel that do not match the specified language, unless + * the additionsModel also contains a new value for the same subject and + * predicate in that language, or no values in any language are added for the + * same subject and predicate (such as when an entire resource is deleted) . + */ +public class LimitRemovalsToLanguage implements ModelChangePreprocessor { + + private static final Log log = LogFactory.getLog(LimitRemovalsToLanguage.class); + private String language; + + /** + * @param locale the Java locale object representing the language + * to which edits should be limited. May not be null. + */ + public LimitRemovalsToLanguage(Locale locale) { + if(locale == null) { + throw new IllegalArgumentException("Locale may not be null."); + } + this.language = LanguageFilteringUtils.localeToLanguage(locale); + } + + /** + * @param language string representing the RDF language tag to which + * edits should be limited. May not be null. + */ + public LimitRemovalsToLanguage(String language) { + if(language == null) { + throw new IllegalArgumentException("Language may not be null."); + } + this.language = language; + } + + @Override + public void preprocess(Model retractionsModel, Model additionsModel, + HttpServletRequest request) { + log.debug("limiting changes to " + language); + List eliminatedRetractions = new ArrayList(); + StmtIterator sit = retractionsModel.listStatements(); + while(sit.hasNext()) { + Statement stmt = sit.next(); + if(stmt.getObject().isLiteral()) { + Literal lit = stmt.getObject().asLiteral(); + if(!StringUtils.isEmpty(lit.getLanguage()) + && !lit.getLanguage().equals(language)) { + boolean eliminateRetraction = true; + StmtIterator replacements = additionsModel + .listStatements(stmt.getSubject(), + stmt.getPredicate(), (RDFNode) null); + if(!replacements.hasNext()) { + eliminateRetraction = false; + } else { + while(replacements.hasNext()) { + Statement replacement = replacements.next(); + if(replacement.getObject().isLiteral() + && lit.getLanguage().equals(replacement + .getObject().asLiteral() + .getLanguage())) { + eliminateRetraction = false; + } + } + } + if(eliminateRetraction) { + eliminatedRetractions.add(stmt); + } + } + } + } + retractionsModel.remove(eliminatedRetractions); + } + +} diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/EditRequestDispatchController.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/EditRequestDispatchController.java index 96d6556b8d..4ed5743478 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/EditRequestDispatchController.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/EditRequestDispatchController.java @@ -11,6 +11,7 @@ import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.jena.ontology.OntModel; @@ -68,9 +69,13 @@ public class EditRequestDispatchController extends FreemarkerHttpServlet { final String RDFS_LABEL_FORM = "edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators.RDFSLabelGenerator"; final String DEFAULT_DELETE_FORM = "edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators.DefaultDeleteGenerator"; - @Override - protected AuthorizationRequest requiredActions(VitroRequest vreq) { - //Check if this statement can be edited here and return unauthorized if not + @Override + protected AuthorizationRequest requiredActions(VitroRequest vreq) { + // If request is for new individual, return simple do back end editing action permission + if (StringUtils.isNotEmpty(EditConfigurationUtils.getTypeOfNew(vreq))) { + return SimplePermission.DO_BACK_END_EDITING.ACTION; + } + // Check if this statement can be edited here and return unauthorized if not String subjectUri = EditConfigurationUtils.getSubjectUri(vreq); String predicateUri = EditConfigurationUtils.getPredicateUri(vreq); String objectUri = EditConfigurationUtils.getObjectUri(vreq); @@ -148,7 +153,7 @@ protected ResponseValues processRequest(VitroRequest vreq) { templateData.put("editConfiguration", etm); templateData.put("editSubmission", submissionTemplateModel); //Corresponding to original note for consistency with selenium tests and 1.1.1 - templateData.put("title", "Edit"); + templateData.put("title", etm.getPageTitle()); templateData.put("submitUrl", getSubmissionUrl(vreq)); templateData.put("cancelUrl", etm.getCancelUrl()); templateData.put("editKey", editConfig.getEditKey()); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/PostEditCleanupController.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/PostEditCleanupController.java index 64f6051034..b1336b50f9 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/PostEditCleanupController.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/PostEditCleanupController.java @@ -74,9 +74,11 @@ protected static ResponseValues doPostEditRedirect( VitroRequest vreq , String e //The submission for getting the entity to return to is not retrieved from the session but needs //to be created - as it is in processRdfForm3.jsp if( entityToReturnTo == null ){ - //this will not work if there entityToReturnTo has a new resource URI, - //in that case entityToReturnTo should not have been passed to this method as null - MultiValueEditSubmission submission = new MultiValueEditSubmission(vreq.getParameterMap(), editConfig); + // this will not work if there entityToReturnTo has a new resource URI, + // in that case entityToReturnTo should not have been passed to this method as null + // UQAM-Linguistic-Management + // MultiValueEditSubmission submission = new MultiValueEditSubmission(vreq.getParameterMap(), editConfig); + MultiValueEditSubmission submission = new MultiValueEditSubmission(vreq, editConfig); entityToReturnTo = N3EditUtils.processEntityToReturnTo(editConfig, submission, vreq); } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/ProcessRdfFormController.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/ProcessRdfFormController.java index 790781a95e..1c82b034bd 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/ProcessRdfFormController.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/ProcessRdfFormController.java @@ -8,10 +8,11 @@ import java.util.List; import java.util.Map; +import javax.servlet.annotation.WebServlet; + import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - import org.apache.jena.rdf.model.Literal; import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.Property; @@ -37,8 +38,7 @@ import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.N3EditUtils; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.ProcessRdfForm; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.RdfLiteralHash; - -import javax.servlet.annotation.WebServlet; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.preprocessors.LimitRemovalsToLanguage; /** * This servlet will convert a request to an EditSubmission, @@ -66,7 +66,9 @@ protected ResponseValues processRequest(VitroRequest vreq) { return handleMissingConfiguration(vreq); //get the EditSubmission - MultiValueEditSubmission submission = new MultiValueEditSubmission(vreq.getParameterMap(), configuration); + // MultiValueEditSubmission submission = new MultiValueEditSubmission(vreq.getParameterMap(), configuration); + // Modified by UQAM-Linguistic-Management + MultiValueEditSubmission submission = new MultiValueEditSubmission(vreq, configuration); EditSubmissionUtils.putEditSubmissionInSession(vreq.getSession(), submission); //if errors, return error response @@ -101,8 +103,11 @@ protected ResponseValues processRequest(VitroRequest vreq) { if( configuration.isUseDependentResourceDelete() ) changes = ProcessRdfForm.addDependentDeletes(changes, queryModel); + // prevent form from removing literals in languages other than the one + // associated with the current request + configuration.addModelChangePreprocessor(new LimitRemovalsToLanguage(vreq.getLocale())); N3EditUtils.preprocessModels(changes, configuration, vreq); - + ProcessRdfForm.applyChangesToWriteModel(changes, queryModel, writeModel, N3EditUtils.getEditorUri(vreq) ); //Here we are trying to get the entity to return to URL, diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/filters/ModelSwitcher.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/filters/ModelSwitcher.java index 7c08132753..7e5f49a588 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/filters/ModelSwitcher.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/filters/ModelSwitcher.java @@ -35,6 +35,7 @@ import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess.WhichService; import edu.cornell.mannlib.vitro.webapp.modelaccess.impl.RequestModelAccessImpl; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; +import edu.cornell.mannlib.vitro.webapp.rdfservice.filter.LanguageFilteringUtils; import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils; /** @@ -88,8 +89,10 @@ public WebappDaoFactory checkForModelSwitching(VitroRequest vreq, WebappDaoFacto // If they asked for the display model, give it to them. if (isParameterPresent(vreq, SWITCH_TO_DISPLAY_MODEL)) { - OntModel mainOntModel = ModelAccess.on(_context).getOntModel(DISPLAY); - OntModel tboxOntModel = ModelAccess.on(_context).getOntModel(DISPLAY_TBOX); + OntModel mainOntModel = LanguageFilteringUtils.wrapOntModelInALanguageFilter( + ModelAccess.on(vreq).getOntModel(DISPLAY), vreq); + OntModel tboxOntModel = LanguageFilteringUtils.wrapOntModelInALanguageFilter( + ModelAccess.on(vreq).getOntModel(DISPLAY_TBOX), vreq); setSpecialWriteModel(vreq, mainOntModel); vreq.setAttribute(VitroRequest.ID_FOR_ABOX_MODEL, VitroModelSource.ModelName.DISPLAY.toString()); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/filters/PageRoutingFilter.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/filters/PageRoutingFilter.java index d956483f6b..0f739361cd 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/filters/PageRoutingFilter.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/filters/PageRoutingFilter.java @@ -63,6 +63,7 @@ public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain chai // get URL without hostname or servlet context HttpServletResponse response = (HttpServletResponse) arg1; HttpServletRequest req = (HttpServletRequest) arg0; + String path = req.getRequestURI().substring(req.getContextPath().length()); // check for first part of path diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/freemarker/config/FreemarkerConfiguration.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/freemarker/config/FreemarkerConfiguration.java index c0ab92d253..719b041ab9 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/freemarker/config/FreemarkerConfiguration.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/freemarker/config/FreemarkerConfiguration.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import javax.servlet.ServletContext; diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/i18n/I18n.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/i18n/I18n.java index 8f07f7301f..85f58495de 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/i18n/I18n.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/i18n/I18n.java @@ -8,6 +8,7 @@ import java.util.List; import java.util.Locale; import java.util.MissingResourceException; +import java.util.Objects; import java.util.ResourceBundle; import java.util.SortedSet; import java.util.TreeSet; @@ -20,7 +21,9 @@ import org.apache.commons.logging.LogFactory; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; import edu.cornell.mannlib.vitro.webapp.i18n.selection.SelectedLocale; +import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess; import edu.cornell.mannlib.vitro.webapp.utils.developer.DeveloperSettings; import edu.cornell.mannlib.vitro.webapp.utils.developer.Key; @@ -49,12 +52,27 @@ public class I18n { * This is where the work gets done. Not declared final, so it can be * modified in unit tests. */ - private static I18n instance = new I18n(); + private static I18n instance; + + private final ServletContext ctx; + + protected I18n(ServletContext ctx) { + this.ctx = ctx; + } // ---------------------------------------------------------------------- // Static methods // ---------------------------------------------------------------------- + /** + * This setup method must be called before I18n static methods can be used. + * It is currently called from LocaleSelectionSetup.contextInitialized, which + * should ensure it is called when the context is initialized. + */ + public static void setup(ServletContext ctx) { + I18n.instance = new I18n(ctx); + } + /** * A convenience method to get a bundle and format the text. */ @@ -72,19 +90,26 @@ public static String text(HttpServletRequest req, String key, } /** - * Get a I18nBundle by this name. + * Get a request I18nBundle by this name. */ public static I18nBundle bundle(String bundleName, HttpServletRequest req) { return instance.getBundle(bundleName, req); } /** - * Get the default I18nBundle. + * Get the default request I18nBundle. */ public static I18nBundle bundle(HttpServletRequest req) { return instance.getBundle(DEFAULT_BUNDLE_NAME, req); } + /** + * Get the default context I18nBundle for preferred locales. + */ + public static I18nBundle bundle(List preferredLocales) { + return instance.getBundle(DEFAULT_BUNDLE_NAME, preferredLocales); + } + // ---------------------------------------------------------------------- // The instance // ---------------------------------------------------------------------- @@ -106,25 +131,59 @@ public static I18nBundle bundle(HttpServletRequest req) { * Declared 'protected' so it can be overridden in unit tests. */ protected I18nBundle getBundle(String bundleName, HttpServletRequest req) { - log.debug("Getting bundle '" + bundleName + "'"); + log.debug("Getting request bundle '" + bundleName + "'"); + + checkDevelopmentMode(req); + checkForChangeInThemeDirectory(req); + + Locale locale = req.getLocale(); + + return getBundle(bundleName, locale); + } + + /** + * Get an I18nBundle by this name. The context provides the selectable + * Locale, the application directory, the theme directory and the + * development mode flag. Choosing matching locale from context by + * provided preferred locales. + * + * If the context indicates that the system is in development mode, then the + * cache is cleared on each request. + * + * If the theme directory has changed, the cache is cleared. + * + * Declared 'protected' so it can be overridden in unit tests. + */ + protected I18nBundle getBundle(String bundleName, List preferredLocales) { + log.debug("Getting context bundle '" + bundleName + "'"); + checkDevelopmentMode(); + checkForChangeInThemeDirectory(ctx); + + Locale locale = SelectedLocale.getPreferredLocale(ctx, preferredLocales); + + return getBundle(bundleName, locale); + } + + /** + * Get an I18nBundle by this name, context, and locale. + */ + private I18nBundle getBundle(String bundleName, Locale locale) { I18nLogger i18nLogger = new I18nLogger(); try { - checkDevelopmentMode(req); - checkForChangeInThemeDirectory(req); - String dir = themeDirectory.get(); - ServletContext ctx = req.getSession().getServletContext(); - ResourceBundle.Control control = new ThemeBasedControl(ctx, dir); ResourceBundle rb = ResourceBundle.getBundle(bundleName, - req.getLocale(), control); + locale, control); + return new I18nBundle(bundleName, rb, i18nLogger); } catch (MissingResourceException e) { log.warn("Didn't find text bundle '" + bundleName + "'"); + return I18nBundle.emptyBundle(bundleName, i18nLogger); } catch (Exception e) { log.error("Failed to create text bundle '" + bundleName + "'", e); + return I18nBundle.emptyBundle(bundleName, i18nLogger); } } @@ -139,6 +198,16 @@ private void checkDevelopmentMode(HttpServletRequest req) { } } + /** + * If we are in development mode, clear the cache. + */ + private void checkDevelopmentMode() { + if (DeveloperSettings.getInstance().getBoolean(Key.I18N_DEFEAT_CACHE)) { + log.debug("In development mode - clearing the cache."); + ResourceBundle.clearCache(); + } + } + /** * If the theme directory has changed from before, clear the cache of all * ResourceBundles. @@ -153,6 +222,30 @@ private void checkForChangeInThemeDirectory(HttpServletRequest req) { } } + /** + * If we have a complete model access and the theme directory has changed + * from before, clear the cache of all ResourceBundles. + */ + private void checkForChangeInThemeDirectory(ServletContext ctx) { + WebappDaoFactory wdf = ModelAccess.on(ctx) + .getWebappDaoFactory(); + // Only applicable if context has a complete model access + if (Objects.nonNull(wdf) + && Objects.nonNull(wdf.getApplicationDao()) + && Objects.nonNull(wdf.getApplicationDao().getApplicationBean())) { + String currentDir = wdf + .getApplicationDao() + .getApplicationBean() + .getThemeDir(); + String previousDir = themeDirectory.getAndSet(currentDir); + if (!currentDir.equals(previousDir)) { + log.debug("Theme directory changed from '" + previousDir + "' to '" + + currentDir + "' - clearing the cache."); + ResourceBundle.clearCache(); + } + } + } + /** Only clear the cache one time per request. */ private void clearCacheOnRequest(HttpServletRequest req) { if (req.getAttribute(ATTRIBUTE_CACHE_CLEARED) != null) { diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/i18n/selection/LocaleSelectionDataGetter.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/i18n/selection/LocaleSelectionDataGetter.java index 3fd949e87c..d0bff6349f 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/i18n/selection/LocaleSelectionDataGetter.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/i18n/selection/LocaleSelectionDataGetter.java @@ -89,8 +89,8 @@ private Map buildLocaleMap(Locale locale, Locale currentLocale) throws FileNotFoundException { Map map = new HashMap<>(); map.put("code", locale.toString()); - map.put("label", locale.getDisplayName(currentLocale)); - map.put("imageUrl", LocaleSelectorUtilities.getImageUrl(vreq, locale)); + map.put("label", locale.getDisplayLanguage(locale)); + map.put("country", locale.getDisplayCountry(locale)); map.put("selected", currentLocale.equals(locale)); return map; } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/i18n/selection/LocaleSelectionSetup.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/i18n/selection/LocaleSelectionSetup.java index 6530d8aff1..596880edd5 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/i18n/selection/LocaleSelectionSetup.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/i18n/selection/LocaleSelectionSetup.java @@ -14,6 +14,7 @@ import org.apache.commons.lang3.StringUtils; import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties; +import edu.cornell.mannlib.vitro.webapp.i18n.I18n; import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus; /** @@ -48,6 +49,10 @@ public void contextInitialized(ServletContextEvent sce) { ss = StartupStatus.getBean(ctx); props = ConfigurationProperties.getBean(sce); + // Instantiate I18n instance to afford access to ServletContext + // when requesting a bundle with or without a VitroRequest + I18n.setup(ctx); + readProperties(); if (isForcing() && hasSelectables()) { diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/i18n/selection/LocaleSelectorUtilities.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/i18n/selection/LocaleSelectorUtilities.java deleted file mode 100644 index 111181574a..0000000000 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/i18n/selection/LocaleSelectorUtilities.java +++ /dev/null @@ -1,58 +0,0 @@ -/* $This file is distributed under the terms of the license in LICENSE$ */ - -package edu.cornell.mannlib.vitro.webapp.i18n.selection; - -import java.io.FileNotFoundException; -import java.util.Locale; -import java.util.Set; - -import javax.servlet.ServletContext; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; - -/** - * Some static methods for the GUI aspects of selecting a Locale. - */ -public class LocaleSelectorUtilities { - private static final Log log = LogFactory - .getLog(LocaleSelectorUtilities.class); - - /** - * Look in the current theme directory to find a selection image for this - * Locale. - * - * Images are expected at a resource path like - * /[themeDir]/i18n/images/select_locale_[locale_code].* - * - * For example, /themes/wilma/i18n/images/select_locale_en.png - * /themes/wilma/i18n/images/select_locale_en.JPEG - * /themes/wilma/i18n/images/select_locale_en.gif - * - * To create a proper URL, prepend the context path. - */ - public static String getImageUrl(VitroRequest vreq, Locale locale) - throws FileNotFoundException { - String filename = "select_locale_" + locale + "."; - - String themeDir = vreq.getAppBean().getThemeDir(); - String imageDirPath = "/" + themeDir + "i18n/images/"; - - ServletContext ctx = vreq.getSession().getServletContext(); - @SuppressWarnings("unchecked") - Set resourcePaths = ctx.getResourcePaths(imageDirPath); - if (resourcePaths != null) { - for (String resourcePath : resourcePaths) { - if (resourcePath.contains(filename)) { - String fullPath = vreq.getContextPath() + resourcePath; - log.debug("Found image for " + locale + " at '" + fullPath - + "'"); - return fullPath; - } - } - } - throw new FileNotFoundException("Can't find an image for " + locale); - } -} diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/i18n/selection/SelectedLocale.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/i18n/selection/SelectedLocale.java index 4605436a49..ce2bb147d6 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/i18n/selection/SelectedLocale.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/i18n/selection/SelectedLocale.java @@ -6,6 +6,8 @@ import java.util.Collections; import java.util.List; import java.util.Locale; +import java.util.Objects; +import java.util.Optional; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; @@ -61,13 +63,10 @@ public static Locale getOverridingLocale(HttpServletRequest req) { ServletContext ctx = session.getServletContext(); Object ctxInfo = ctx.getAttribute(ATTRIBUTE_NAME); - if (ctxInfo instanceof ContextSelectedLocale) { - Locale forcedLocale = ((ContextSelectedLocale) ctxInfo) - .getForcedLocale(); - if (forcedLocale != null) { - log.debug("Found forced locale in the context: " + forcedLocale); - return forcedLocale; - } + + Optional forcedLocale = getForcedLocale(ctxInfo); + if (forcedLocale.isPresent()) { + return forcedLocale.get(); } Object sessionInfo = session.getAttribute(ATTRIBUTE_NAME); @@ -95,6 +94,49 @@ public static Locale getOverridingLocale(HttpServletRequest req) { return null; } + /** + * Get the overriding Locale to use, which is the first of these to be found: + *
    + *
  • The forced Locale in the servlet context
  • + *
  • The first selectable locale matching a preferred locale
  • + *
  • The first of the preferred locale
  • + *
  • null
  • + *
+ */ + public static Locale getOverridingLocale(ServletContext ctx, List preferredLocales) { + Object ctxInfo = ctx.getAttribute(ATTRIBUTE_NAME); + Optional forcedLocale = getForcedLocale(ctxInfo); + if (forcedLocale.isPresent()) { + return forcedLocale.get(); + } + + if (ctxInfo instanceof ContextSelectedLocale) { + List selectableLocales = ((ContextSelectedLocale) ctxInfo) + .getSelectableLocales(); + + if (Objects.nonNull(selectableLocales) && Objects.nonNull(preferredLocales)) { + for (Locale preferredLocal : preferredLocales) { + for (Locale selectableLocale : selectableLocales) { + if (selectableLocale.equals(preferredLocal)) { + log.debug("Using first matching selectable locale from context: " + + selectableLocale); + return selectableLocale; + } + } + } + } + } + + if (Objects.nonNull(preferredLocales) && !preferredLocales.isEmpty()) { + Locale preferredLocal = preferredLocales.get(0); + log.debug("Using first preferred locale as default: " + + preferredLocal); + return preferredLocal; + } + + return null; + } + /** * Get the current Locale to use, which is the first of these to be found: *
    @@ -121,6 +163,42 @@ public static Locale getCurrentLocale(HttpServletRequest req) { return Locale.getDefault(); } + /** + * Get the preferred Locale to use, which is the first of these to be found: + *
      + *
    • The forced Locale in the servlet context
    • + *
    • The first selectable locale matching a preferred locale
    • + *
    • The first of the preferred locale
    • + *
    • The default Locale for the JVM
    • + *
    + */ + public static Locale getPreferredLocale(ServletContext ctx, List preferredLocales) { + Locale overridingLocale = getOverridingLocale(ctx, preferredLocales); + + if (overridingLocale != null) { + return overridingLocale; + } + + log.debug("Using default locale: " + Locale.getDefault()); + return Locale.getDefault(); + } + + /** + * Check for forced locale on the context. + */ + private static Optional getForcedLocale(Object ctxInfo) { + if (ctxInfo instanceof ContextSelectedLocale) { + Locale forcedLocale = ((ContextSelectedLocale) ctxInfo) + .getForcedLocale(); + if (forcedLocale != null) { + log.debug("Found forced locale in the context: " + forcedLocale); + return Optional.of(forcedLocale); + } + } + + return Optional.empty(); + } + /** * Store a list of selectable Locales in the servlet context, so we can * easily build the selection panel in the GUI. Clears any forced locale. diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/modelaccess/ModelNames.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/modelaccess/ModelNames.java index 245ca9908a..10493a0c34 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/modelaccess/ModelNames.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/modelaccess/ModelNames.java @@ -13,20 +13,27 @@ public class ModelNames { public static final String ABOX_ASSERTIONS = "http://vitro.mannlib.cornell.edu/default/vitro-kb-2"; public static final String ABOX_INFERENCES = "http://vitro.mannlib.cornell.edu/default/vitro-kb-inf"; public static final String ABOX_UNION = "vitro:aboxOntModel"; + public static final String ABOX_ASSERTIONS_FIRSTTIME_BACKUP = ABOX_ASSERTIONS + "FirsttimeBackup"; public static final String TBOX_ASSERTIONS = "http://vitro.mannlib.cornell.edu/default/asserted-tbox"; public static final String TBOX_INFERENCES = "http://vitro.mannlib.cornell.edu/default/inferred-tbox"; public static final String TBOX_UNION = "vitro:tboxOntModel"; + public static final String TBOX_ASSERTIONS_FIRSTTIME_BACKUP = TBOX_ASSERTIONS + "FirsttimeBackup"; public static final String FULL_ASSERTIONS = "vitro:baseOntModel"; public static final String FULL_INFERENCES = "vitro:inferenceOntModel"; public static final String FULL_UNION = "vitro:jenaOntModel"; public static final String APPLICATION_METADATA = "http://vitro.mannlib.cornell.edu/default/vitro-kb-applicationMetadata"; + public static final String APPLICATION_METADATA_FIRSTTIME_BACKUP = APPLICATION_METADATA + "FirsttimeBackup"; public static final String USER_ACCOUNTS = "http://vitro.mannlib.cornell.edu/default/vitro-kb-userAccounts"; + public static final String USER_ACCOUNTS_FIRSTTIME_BACKUP = USER_ACCOUNTS + "FirsttimeBackup"; public static final String DISPLAY = "http://vitro.mannlib.cornell.edu/default/vitro-kb-displayMetadata"; + public static final String DISPLAY_FIRSTTIME_BACKUP = DISPLAY + "FirsttimeBackup"; public static final String DISPLAY_TBOX = "http://vitro.mannlib.cornell.edu/default/vitro-kb-displayMetadataTBOX"; + public static final String DISPLAY_TBOX_FIRSTTIME_BACKUP = DISPLAY_TBOX + "FirsttimeBackup"; public static final String DISPLAY_DISPLAY = "http://vitro.mannlib.cornell.edu/default/vitro-kb-displayMetadata-displayModel"; + public static final String DISPLAY_DISPLAY_FIRSTTIME_BACKUP = DISPLAY_DISPLAY + "FirsttimeBackup"; /** * A map of the URIS, keyed by their short names, intended only for display @@ -39,17 +46,24 @@ private static Map populateNamesMap() { map.put("ABOX_ASSERTIONS", ABOX_ASSERTIONS); map.put("ABOX_INFERENCES", ABOX_INFERENCES); map.put("ABOX_UNION", ABOX_UNION); + map.put("ABOX_ASSERTIONS_FIRSTTIME_BACKUP", ABOX_ASSERTIONS_FIRSTTIME_BACKUP); map.put("TBOX_ASSERTIONS", TBOX_ASSERTIONS); map.put("TBOX_INFERENCES", TBOX_INFERENCES); map.put("TBOX_UNION", TBOX_UNION); + map.put("TBOX_ASSERTIONS_FIRSTTIME_BACKUP", TBOX_ASSERTIONS_FIRSTTIME_BACKUP); map.put("FULL_ASSERTIONS", FULL_ASSERTIONS); map.put("FULL_INFERENCES", FULL_INFERENCES); map.put("FULL_UNION", FULL_UNION); map.put("APPLICATION_METADATA", APPLICATION_METADATA); + map.put("APPLICATION_METADATA_FIRSTTIME_BACKUP", APPLICATION_METADATA_FIRSTTIME_BACKUP); map.put("USER_ACCOUNTS", USER_ACCOUNTS); + map.put("USER_ACCOUNTS_FIRSTTIME_BACKUP", USER_ACCOUNTS_FIRSTTIME_BACKUP); map.put("DISPLAY", DISPLAY); + map.put("DISPLAY_FIRSTTIME_BACKUP", DISPLAY_FIRSTTIME_BACKUP); map.put("DISPLAY_TBOX", DISPLAY_TBOX); + map.put("DISPLAY_TBOX_FIRSTTIME_BACKUP", DISPLAY_TBOX_FIRSTTIME_BACKUP); map.put("DISPLAY_DISPLAY", DISPLAY_DISPLAY); + map.put("DISPLAY_DISPLAY_FIRSTTIME_BACKUP", DISPLAY_DISPLAY_FIRSTTIME_BACKUP); return Collections.unmodifiableMap(map); } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/modelaccess/impl/RequestModelAccessImpl.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/modelaccess/impl/RequestModelAccessImpl.java index 63d70691cc..3f47566fef 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/modelaccess/impl/RequestModelAccessImpl.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/modelaccess/impl/RequestModelAccessImpl.java @@ -202,7 +202,7 @@ public OntModel getOntModel(LanguageOption... options) { @Override public OntModel getOntModel(String name, LanguageOption... options) { - return getOntModel(new OntModelKey(name, options)); + return addLanguageAwareness(getOntModel(new OntModelKey(name, options))); } private OntModel getOntModel(OntModelKey key) { diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/modules/tripleSource/ConfigurationTripleSource.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/modules/tripleSource/ConfigurationTripleSource.java index fa1725af57..fe766329ba 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/modules/tripleSource/ConfigurationTripleSource.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/modules/tripleSource/ConfigurationTripleSource.java @@ -6,6 +6,14 @@ import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.DISPLAY_DISPLAY; import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.DISPLAY_TBOX; import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.USER_ACCOUNTS; +import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.ABOX_ASSERTIONS_FIRSTTIME_BACKUP; +import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.TBOX_ASSERTIONS_FIRSTTIME_BACKUP; +import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.APPLICATION_METADATA_FIRSTTIME_BACKUP; +import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.USER_ACCOUNTS_FIRSTTIME_BACKUP; +import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.DISPLAY_FIRSTTIME_BACKUP; +import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.DISPLAY_TBOX_FIRSTTIME_BACKUP; +import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.DISPLAY_DISPLAY_FIRSTTIME_BACKUP; + import org.apache.jena.rdf.model.ModelMaker; @@ -18,7 +26,10 @@ public abstract class ConfigurationTripleSource implements TripleSource { * add memory-mapping. */ protected static final String[] CONFIGURATION_MODELS = { DISPLAY, - DISPLAY_TBOX, DISPLAY_DISPLAY, USER_ACCOUNTS }; + DISPLAY_TBOX, DISPLAY_DISPLAY, USER_ACCOUNTS, ABOX_ASSERTIONS_FIRSTTIME_BACKUP, + TBOX_ASSERTIONS_FIRSTTIME_BACKUP, APPLICATION_METADATA_FIRSTTIME_BACKUP, + USER_ACCOUNTS_FIRSTTIME_BACKUP, DISPLAY_FIRSTTIME_BACKUP, + DISPLAY_TBOX_FIRSTTIME_BACKUP, DISPLAY_DISPLAY_FIRSTTIME_BACKUP }; /** * These decorators are added to a Configuration ModelMaker, regardless of diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/RDFService.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/RDFService.java index babac6c529..06a17e4f4f 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/RDFService.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/RDFService.java @@ -10,6 +10,8 @@ import org.apache.jena.rdf.model.ModelChangedListener; import org.apache.jena.rdf.model.RDFNode; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; + /** * Interface for API to write, read, and update Vitro's RDF store, with support * to allow listening, logging and auditing. @@ -263,4 +265,10 @@ public void unregisterJenaModelChangedListener(ModelChangedListener changeListen * multiple invocations do not cause an error. */ public void close(); + /** + * UQAM-Bug-Correction Useful among other things to transport the linguistic context in the service + * @param vitroRequest + */ + public void setVitroRequest(VitroRequest vitroRequest); + public VitroRequest getVitroRequest(); } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/adapters/AbstractGraphDecorator.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/adapters/AbstractGraphDecorator.java new file mode 100644 index 0000000000..c2f9faa67f --- /dev/null +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/adapters/AbstractGraphDecorator.java @@ -0,0 +1,136 @@ +package edu.cornell.mannlib.vitro.webapp.rdfservice.adapters; + +import org.apache.jena.graph.Capabilities; +import org.apache.jena.graph.Graph; +import org.apache.jena.graph.GraphEventManager; +import org.apache.jena.graph.GraphStatisticsHandler; +import org.apache.jena.graph.Node; +import org.apache.jena.graph.TransactionHandler; +import org.apache.jena.graph.Triple; +import org.apache.jena.shared.AddDeniedException; +import org.apache.jena.shared.DeleteDeniedException; +import org.apache.jena.shared.PrefixMapping; +import org.apache.jena.util.iterator.ExtendedIterator; + +import edu.cornell.mannlib.vitro.webapp.utils.logging.ToString; + +/** + * The base class for a delegating graph decorator. + * + * As implemented, all methods simply delegate to the inner graph. Subclasses + * should override selected methods to provide functionality. + */ +public abstract class AbstractGraphDecorator implements + Graph { + + private final Graph inner; + + protected AbstractGraphDecorator(Graph g) { + if (g == null) { + throw new IllegalArgumentException("g may not be null."); + } + this.inner = g; + } + + @Override + public String toString() { + return ToString.simpleName(this) + "[" + ToString.hashHex(this) + + ", inner=" + ToString.graphToString(inner) + "]"; + } + + @Override + public void add(Triple arg0) throws AddDeniedException { + inner.add(arg0); + } + + @Override + public void clear() { + inner.clear(); + } + + @Override + public void close() { + inner.close(); + } + + @Override + public boolean contains(Triple arg0) { + return inner.contains(arg0); + } + + @Override + public boolean contains(Node arg0, Node arg1, Node arg2) { + return inner.contains(arg0, arg1, arg2); + } + + @Override + public void delete(Triple arg0) throws DeleteDeniedException { + inner.delete(arg0); + } + + @Override + public boolean dependsOn(Graph arg0) { + return inner.dependsOn(arg0); + } + + @Override + public ExtendedIterator find(Triple arg0) { + return inner.find(arg0); + } + + @Override + public ExtendedIterator find(Node arg0, Node arg1, Node arg2) { + return inner.find(arg0, arg1, arg2); + } + + @Override + public Capabilities getCapabilities() { + return inner.getCapabilities(); + } + + @Override + public GraphEventManager getEventManager() { + return inner.getEventManager(); + } + + @Override + public PrefixMapping getPrefixMapping() { + return inner.getPrefixMapping(); + } + + @Override + public GraphStatisticsHandler getStatisticsHandler() { + return inner.getStatisticsHandler(); + } + + @Override + public TransactionHandler getTransactionHandler() { + return inner.getTransactionHandler(); + } + + @Override + public boolean isClosed() { + return inner.isClosed(); + } + + @Override + public boolean isEmpty() { + return inner.isEmpty(); + } + + @Override + public boolean isIsomorphicWith(Graph arg0) { + return inner.isIsomorphicWith(arg0); + } + + @Override + public void remove(Node arg0, Node arg1, Node arg2) { + inner.remove(arg0, arg1, arg2); + } + + @Override + public int size() { + return inner.size(); + } + +} \ No newline at end of file diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/adapters/AbstractModelDecorator.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/adapters/AbstractModelDecorator.java index e72e785201..6a5fc0f90f 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/adapters/AbstractModelDecorator.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/adapters/AbstractModelDecorator.java @@ -54,7 +54,7 @@ public abstract class AbstractModelDecorator implements Model { protected AbstractModelDecorator(Model m) { if (m == null) { - throw new NullPointerException("m may not be null."); + throw new IllegalArgumentException("m may not be null."); } this.inner = m; } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/AcceptableLanguages.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/AcceptableLanguages.java new file mode 100644 index 0000000000..01e96c9ccc --- /dev/null +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/AcceptableLanguages.java @@ -0,0 +1,36 @@ +package edu.cornell.mannlib.vitro.webapp.rdfservice.filter; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * A normalized list of languages/locales acceptable in results + * returned by language-filtering RDFServices, graphs, models, etc. + */ +public class AcceptableLanguages extends ArrayList{ + + private static final long serialVersionUID = 1L; + private static final Log log = LogFactory.getLog(AcceptableLanguages.class); + + /** + * Construct a normalized list of acceptable language strings + * from a set of raw language strings. For any values of form 'aa-BB', + * the base language ('aa') will be also added to the list. + * @param rawLanguageStrs may not be null + */ + public AcceptableLanguages(List rawLanguageStrs) { + log.debug("Raw language strings:" + rawLanguageStrs); + for (String lang : rawLanguageStrs) { + this.add(lang); + String baseLang = lang.split("-")[0]; + if (!lang.equals(baseLang) && !this.contains(baseLang)) { + this.add(baseLang); + } + } + log.debug("Normalized language strings:" + this); + } + +} diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/LangSort.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/LangSort.java new file mode 100644 index 0000000000..933da13c24 --- /dev/null +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/LangSort.java @@ -0,0 +1,72 @@ +package edu.cornell.mannlib.vitro.webapp.rdfservice.filter; + +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * A class for sorting language strings by acceptability according to a + * supplied list of language preferences. + * Refactored from LanguageFilteringRDFService for reuse by classes performing + * similar functions. + */ +public class LangSort { + + private static final Log log = LogFactory.getLog(LangSort.class); + + protected List langs; + private int inexactMatchPenalty; + private int noLanguage; + private int noMatch; + + /** + * Construct a language string sorter with a supplied list of preferred + * language strings + * @param preferredLanguageStrings list of preferred languages of form + * 'en-US', 'es', 'fr-CA'. May not be null. + */ + public LangSort(List preferredLanguageStrings) { + this.langs = preferredLanguageStrings; + this.inexactMatchPenalty = langs.size(); + // no language is worse than any inexact match (if the preferred list does not include ""). + this.noLanguage = 2 * inexactMatchPenalty; + // no match is worse than no language. + this.noMatch = noLanguage + 1; + } + + protected int compareLangs(String t1lang, String t2lang) { + return languageIndex(t1lang) - languageIndex(t2lang); + } + + /** + * Return index of exact match, or index of partial match, or + * language-free, or no match. + */ + private int languageIndex(String lang) { + if (lang == null) { + lang = ""; + } + + int index = langs.indexOf(lang); + if (index >= 0) { + log.debug("languageIndex for '" + lang + "' is " + index); + return index; + } + + if (lang.length() > 2) { + index = langs.indexOf(lang.substring(0, 2)); + if (index >= 0) { + log.debug("languageIndex for '" + lang + "' is " + index + inexactMatchPenalty); + return index + inexactMatchPenalty; + } + } + + if (lang.isEmpty()) { + log.debug("languageIndex for '" + lang + "' is " + noLanguage); + return noLanguage; + } + + return noMatch; + } +} diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/LanguageFilterModel.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/LanguageFilterModel.java new file mode 100644 index 0000000000..0b1e5ce2fb --- /dev/null +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/LanguageFilterModel.java @@ -0,0 +1,104 @@ +package edu.cornell.mannlib.vitro.webapp.rdfservice.filter; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.RDFNode; +import org.apache.jena.rdf.model.Statement; +import org.apache.jena.rdf.model.StmtIterator; + +/** + * A filter of literal statements from Models according to language preferences. + */ +public class LanguageFilterModel { + + private static final Log log = LogFactory.getLog(LanguageFilterModel.class); + + /** + * + * @param m the model to filter. May not be null. + * @param langs list of strings of type 'en-US'. May not be null. + * @return model with language-inappropriate literal statements filtered out. + */ + public Model filterModel(Model m, List langs) { + log.debug("filterModel"); + List retractions = new ArrayList(); + StmtIterator stmtIt = m.listStatements(); + while (stmtIt.hasNext()) { + Statement stmt = stmtIt.nextStatement(); + if (stmt.getObject().isLiteral()) { + List candidatesForRemoval = m.listStatements( + stmt.getSubject(), stmt.getPredicate(), (RDFNode) null).toList(); + if (candidatesForRemoval.size() == 1) { + continue; + } + candidatesForRemoval.sort(new StatementSortByLang(langs)); + log.debug("sorted statements: " + showSortedStatements(candidatesForRemoval)); + Iterator candIt = candidatesForRemoval.iterator(); + String langRegister = null; + boolean chuckRemaining = false; + while(candIt.hasNext()) { + Statement s = candIt.next(); + if (!s.getObject().isLiteral()) { + continue; + } else if (chuckRemaining) { + retractions.add(s); + } + String lang = s.getObject().asLiteral().getLanguage(); + if (langRegister == null) { + langRegister = lang; + } else if (!langRegister.equals(lang)) { + chuckRemaining = true; + retractions.add(s); + } + } + } + + } + m.remove(retractions); + return m; + } + + private String showSortedStatements(List candidatesForRemoval) { + List langStrings = new ArrayList(); + for (Statement stmt: candidatesForRemoval) { + if (stmt == null) { + langStrings.add("null stmt"); + } else { + RDFNode node = stmt.getObject(); + if (!node.isLiteral()) { + langStrings.add("not literal"); + } else { + langStrings.add(node.asLiteral().getLanguage()); + } + } + } + return langStrings.toString(); + } + + private class StatementSortByLang extends LangSort implements Comparator { + + public StatementSortByLang(List langs) { + super(langs); + } + + public int compare(Statement s1, Statement s2) { + if (s1 == null || s2 == null) { + return 0; + } else if (!s1.getObject().isLiteral() || !s2.getObject().isLiteral()) { + return 0; + } + + String s1lang = s1.getObject().asLiteral().getLanguage(); + String s2lang = s2.getObject().asLiteral().getLanguage(); + + return compareLangs(s1lang, s2lang); + } + } + +} diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/LanguageFilteringGraph.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/LanguageFilteringGraph.java new file mode 100644 index 0000000000..b578fddebb --- /dev/null +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/LanguageFilteringGraph.java @@ -0,0 +1,59 @@ +package edu.cornell.mannlib.vitro.webapp.rdfservice.filter; + +import java.util.List; + +import org.apache.jena.graph.Graph; +import org.apache.jena.graph.Node; +import org.apache.jena.graph.Triple; +import org.apache.jena.mem.GraphMem; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.ModelFactory; +import org.apache.jena.util.iterator.ExtendedIterator; + +import edu.cornell.mannlib.vitro.webapp.rdfservice.adapters.AbstractGraphDecorator; + +/** + * A graph decorator that filters find() results according to a list of + * preferred language strings + */ +public class LanguageFilteringGraph extends AbstractGraphDecorator + implements Graph { + + private List langs; + private LanguageFilterModel filterModel = new LanguageFilterModel(); + + /** + * Return a graph wrapped in a decorator that will filter find() results + * according to the supplied list of acceptable languages + * @param g the graph to wrap with language awareness. May not be null. + * @param preferredLanguages a list of preferred language strings. May not + * be null. + */ + protected LanguageFilteringGraph(Graph g, List preferredLanguages) { + super(g); + this.langs = preferredLanguages; + } + + @Override + public ExtendedIterator find(Triple arg0) { + return filter(super.find(arg0)); + + } + + @Override + public ExtendedIterator find(Node arg0, Node arg1, Node arg2) { + return filter(super.find(arg0, arg1, arg2)); + } + + private ExtendedIterator filter(ExtendedIterator triples) { + Graph tmp = new GraphMem(); + while(triples.hasNext()) { + Triple t = triples.next(); + tmp.add(t); + } + Model filteredModel = filterModel.filterModel( + ModelFactory.createModelForGraph(tmp), langs); + return filteredModel.getGraph().find(); + } + +} diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/LanguageFilteringRDFService.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/LanguageFilteringRDFService.java index 903711e529..5e59118dd7 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/LanguageFilteringRDFService.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/LanguageFilteringRDFService.java @@ -7,14 +7,14 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; -import java.util.Collections; import java.util.Comparator; +import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - import org.apache.jena.query.QuerySolution; import org.apache.jena.query.ResultSet; import org.apache.jena.query.ResultSetFactory; @@ -22,11 +22,9 @@ import org.apache.jena.rdf.model.Literal; import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.ModelChangedListener; -import org.apache.jena.rdf.model.ModelFactory; import org.apache.jena.rdf.model.RDFNode; -import org.apache.jena.rdf.model.Statement; -import org.apache.jena.rdf.model.StmtIterator; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeListener; import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeSet; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; @@ -39,27 +37,13 @@ public class LanguageFilteringRDFService implements RDFService { private static final Log log = LogFactory.getLog(LanguageFilteringRDFService.class); private RDFService s; private List langs; + private LanguageFilterModel filterModel = new LanguageFilterModel(); public LanguageFilteringRDFService(RDFService service, List langs) { this.s = service; - this.langs = normalizeLangs(langs); + this.langs = new AcceptableLanguages(langs); } - private List normalizeLangs(List langs) { - log.debug("Preferred languages:" + langs); - - List normalizedLangs = new ArrayList(langs); - for (String lang : langs) { - String baseLang = lang.split("-")[0]; - if (!normalizedLangs.contains(baseLang)) { - normalizedLangs.add(baseLang); - } - } - - log.debug("Normalized languages:" + normalizedLangs); - return normalizedLangs; - } - @Override public boolean changeSetUpdate(ChangeSet changeSet) throws RDFServiceException { @@ -83,23 +67,17 @@ public void newIndividual(String individualURI, public InputStream sparqlConstructQuery(String query, ModelSerializationFormat resultFormat) throws RDFServiceException { - Model m = RDFServiceUtils.parseModel(s.sparqlConstructQuery(query, resultFormat), resultFormat); - InputStream in = outputModel(filterModel(m), resultFormat); + Model m = RDFServiceUtils.parseModel(s.sparqlConstructQuery( + query, resultFormat), resultFormat); + InputStream in = outputModel(filterModel.filterModel( + m, langs), resultFormat); return in; } @Override public void sparqlConstructQuery(String query, Model model) throws RDFServiceException { - if (model.isEmpty()) { - s.sparqlConstructQuery(query, model); - filterModel(model); - } else { - Model constructedModel = ModelFactory.createDefaultModel(); - s.sparqlConstructQuery(query, constructedModel); - filterModel(constructedModel); - model.add(constructedModel); - } + s.sparqlConstructQuery(query, model); } @Override @@ -107,7 +85,7 @@ public InputStream sparqlDescribeQuery(String query, ModelSerializationFormat resultFormat) throws RDFServiceException { Model m = RDFServiceUtils.parseModel(s.sparqlDescribeQuery(query, resultFormat), resultFormat); - return outputModel(filterModel(m), resultFormat); + return outputModel(filterModel.filterModel(m, langs), resultFormat); } private InputStream outputModel(Model m, ModelSerializationFormat resultFormat) { @@ -116,62 +94,6 @@ private InputStream outputModel(Model m, ModelSerializationFormat resultFormat) return new ByteArrayInputStream(out.toByteArray()); } - private Model filterModel(Model m) { - log.debug("filterModel"); - List retractions = new ArrayList(); - StmtIterator stmtIt = m.listStatements(); - while (stmtIt.hasNext()) { - Statement stmt = stmtIt.nextStatement(); - if (stmt.getObject().isLiteral()) { - List candidatesForRemoval = m.listStatements( - stmt.getSubject(), stmt.getPredicate(), (RDFNode) null).toList(); - if (candidatesForRemoval.size() == 1) { - continue; - } - candidatesForRemoval.sort(new StatementSortByLang()); - log.debug("sorted statements: " + showSortedStatements(candidatesForRemoval)); - Iterator candIt = candidatesForRemoval.iterator(); - String langRegister = null; - boolean chuckRemaining = false; - while(candIt.hasNext()) { - Statement s = candIt.next(); - if (!s.getObject().isLiteral()) { - continue; - } else if (chuckRemaining) { - retractions.add(s); - } - String lang = s.getObject().asLiteral().getLanguage(); - if (langRegister == null) { - langRegister = lang; - } else if (!langRegister.equals(lang)) { - chuckRemaining = true; - retractions.add(s); - } - } - } - - } - m.remove(retractions); - return m; - } - - private String showSortedStatements(List candidatesForRemoval) { - List langStrings = new ArrayList(); - for (Statement stmt: candidatesForRemoval) { - if (stmt == null) { - langStrings.add("null stmt"); - } else { - RDFNode node = stmt.getObject(); - if (!node.isLiteral()) { - langStrings.add("not literal"); - } else { - langStrings.add(node.asLiteral().getLanguage()); - } - } - } - return langStrings.toString(); - } - @Override public InputStream sparqlSelectQuery(String query, ResultFormat resultFormat) throws RDFServiceException { @@ -180,7 +102,16 @@ public InputStream sparqlSelectQuery(String query, s.sparqlSelectQuery(query, RDFService.ResultFormat.JSON)); List solnList = getSolutionList(resultSet); List vars = resultSet.getResultVars(); + + // This block loops all of the Query variables; + // for each QuerySolution, creates a map of the values of the other variables than the current + // 'variable' --> a list of RowIndexedLiterals. + // In this way, all of the QuerySolutions with equal values of their other variables are grouped. + // This map is used subsequently to filter Literals based on lang for (String var : vars) { + Map, List> nonVarToRowIndexedLiterals = new HashMap<>(); + + // First pass of solnList to populate map for (int i = 0; i < solnList.size(); i++) { QuerySolution s = solnList.get(i); if (s == null) { @@ -190,23 +121,32 @@ public InputStream sparqlSelectQuery(String query, if (node == null || !node.isLiteral()) { continue; } - List candidatesForRemoval = - new ArrayList(); - candidatesForRemoval.add(new RowIndexedLiteral(node.asLiteral(), i)); - for (int j = i + 1; j < solnList.size(); j++) { - QuerySolution t = solnList.get(j); - if (t == null) { - continue; - } - if (matchesExceptForVar(s, t, var, vars)) { - candidatesForRemoval.add( - new RowIndexedLiteral(t.getLiteral(var), j)); + + // Create entry representing values other than current 'var' for this QuerySolution + List nonVarList = new ArrayList(vars.size() - 1); + for (String v : vars) { + if (!v.equals(var)) { + nonVarList.add(s.get(v)); } } + + List rowIndexedLiterals = nonVarToRowIndexedLiterals.get(nonVarList); + if (rowIndexedLiterals == null) { + rowIndexedLiterals = new ArrayList(); + } + rowIndexedLiterals.add(new RowIndexedLiteral(node.asLiteral(), i)); + + // Add RowIndexedLiterals to the map + nonVarToRowIndexedLiterals.put(nonVarList, rowIndexedLiterals); + } + + // Second pass of solnList (via the map) to evaluate candidatesForRemoval + for (List key : nonVarToRowIndexedLiterals.keySet()) { + List candidatesForRemoval = nonVarToRowIndexedLiterals.get(key); if (candidatesForRemoval.size() == 1) { continue; } - candidatesForRemoval.sort(new RowIndexedLiteralSortByLang()); + candidatesForRemoval.sort(new RowIndexedLiteralSortByLang(langs)); log.debug("sorted RowIndexedLiterals: " + showSortedRILs(candidatesForRemoval)); Iterator candIt = candidatesForRemoval.iterator(); String langRegister = null; @@ -254,10 +194,9 @@ public InputStream sparqlSelectQuery(String query, @Override public void sparqlSelectQuery(String query, ResultSetConsumer consumer) throws RDFServiceException { log.debug("sparqlSelectQuery: " + query.replaceAll("\\s+", " ")); - s.sparqlSelectQuery(query, new ResultSetConsumer.Chaining(consumer) { List vars; - List solnList = new ArrayList(); + List solnList = new ArrayList<>(); @Override protected void processQuerySolution(QuerySolution qs) { @@ -273,7 +212,15 @@ protected void startProcessing() { protected void endProcessing() { chainStartProcessing(); + // This block loops all of the Query variables; + // for each QuerySolution, creates a map of the values of the other variables than the current + // 'variable' --> a list of RowIndexedLiterals. + // In this way, all of the QuerySolutions with equal values of their other variables are grouped. + // This map is used subsequently to filter Literals based on lang for (String var : vars) { + Map, List> nonVarToRowIndexedLiterals = new HashMap<>(); + + // First pass of solnList to populate map for (int i = 0; i < solnList.size(); i++) { QuerySolution s = solnList.get(i); if (s == null) { @@ -283,23 +230,32 @@ protected void endProcessing() { if (node == null || !node.isLiteral()) { continue; } - List candidatesForRemoval = - new ArrayList(); - candidatesForRemoval.add(new RowIndexedLiteral(node.asLiteral(), i)); - for (int j = i + 1; j < solnList.size(); j++) { - QuerySolution t = solnList.get(j); - if (t == null) { - continue; - } - if (matchesExceptForVar(s, t, var, vars)) { - candidatesForRemoval.add( - new RowIndexedLiteral(t.getLiteral(var), j)); + + // Create entry representing values other than current 'var' for this QuerySolution + List nonVarList = new ArrayList(vars.size() - 1); + for (String v : vars) { + if (!v.equals(var)) { + nonVarList.add(s.get(v)); } } + + List rowIndexedLiterals = nonVarToRowIndexedLiterals.get(nonVarList); + if (rowIndexedLiterals == null) { + rowIndexedLiterals = new ArrayList(); + } + rowIndexedLiterals.add(new RowIndexedLiteral(node.asLiteral(), i)); + + // Add RowIndexedLiterals to the map + nonVarToRowIndexedLiterals.put(nonVarList, rowIndexedLiterals); + } + + // Second pass of solnList (via the map) to evaluate candidatesForRemoval + for (List key : nonVarToRowIndexedLiterals.keySet()) { + List candidatesForRemoval = nonVarToRowIndexedLiterals.get(key); if (candidatesForRemoval.size() == 1) { continue; } - candidatesForRemoval.sort(new RowIndexedLiteralSortByLang()); + candidatesForRemoval.sort(new RowIndexedLiteralSortByLang(langs)); log.debug("sorted RowIndexedLiterals: " + showSortedRILs(candidatesForRemoval)); Iterator candIt = candidatesForRemoval.iterator(); String langRegister = null; @@ -357,34 +313,6 @@ public int getIndex() { } - private boolean matchesExceptForVar(QuerySolution a, QuerySolution b, - String varName, List varList) { - if (varName == null) { - throw new RuntimeException("expected non-null variable nane"); - } - for (String var : varList) { - RDFNode nodea = a.get(var); - RDFNode nodeb = b.get(var); - if (var.equals(varName)) { - if (nodea == null || !nodea.isLiteral() || nodeb == null || !nodeb.isLiteral()) { - return false; - } - } else { - if (nodea == null && nodeb == null) { - continue; - } else if (nodea == null && nodeb != null) { - return false; - } else if (nodeb == null && nodea != null) { - return false; - } - if (!a.get(var).equals(b.get(var))) { - return false; - } - } - } - return true; - } - private List getSolutionList(ResultSet resultSet) { List solnList = new ArrayList(); while (resultSet.hasNext()) { @@ -489,52 +417,12 @@ public void close() { s.close(); } - private class LangSort { - // any inexact match is worse than any exact match - private int inexactMatchPenalty = langs.size(); - // no language is worse than any inexact match (if the preferred list does not include ""). - private int noLanguage = 2 * inexactMatchPenalty; - // no match is worse than no language. - private int noMatch = noLanguage + 1; - - protected int compareLangs(String t1lang, String t2lang) { - return languageIndex(t1lang) - languageIndex(t2lang); - } - - /** - * Return index of exact match, or index of partial match, or - * language-free, or no match. - */ - private int languageIndex(String lang) { - if (lang == null) { - lang = ""; - } - - int index = langs.indexOf(lang); - if (index >= 0) { - log.debug("languageIndex for '" + lang + "' is " + index); - return index; - } - - if (lang.length() > 2) { - index = langs.indexOf(lang.substring(0, 2)); - if (index >= 0) { - log.debug("languageIndex for '" + lang + "' is " + index + inexactMatchPenalty); - return index + inexactMatchPenalty; - } - } - - if (lang.isEmpty()) { - log.debug("languageIndex for '" + lang + "' is " + noLanguage); - return noLanguage; - } - - return noMatch; - } - } - private class RowIndexedLiteralSortByLang extends LangSort implements Comparator { + public RowIndexedLiteralSortByLang(List langs) { + super(langs); + } + public int compare(RowIndexedLiteral rilit1, RowIndexedLiteral rilit2) { if (rilit1 == null || rilit2 == null) { return 0; @@ -547,21 +435,20 @@ public int compare(RowIndexedLiteral rilit1, RowIndexedLiteral rilit2) { } } - private class StatementSortByLang extends LangSort implements Comparator { + /* + * UQAM-Linguistic-Management Useful among other things to transport the linguistic context in the service + * (non-Javadoc) + * @see edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService#setVitroRequest(edu.cornell.mannlib.vitro.webapp.controller.VitroRequest) + */ + private VitroRequest vitroRequest; - public int compare(Statement s1, Statement s2) { - if (s1 == null || s2 == null) { - return 0; - } else if (!s1.getObject().isLiteral() || !s2.getObject().isLiteral()) { - return 0; - } - - String s1lang = s1.getObject().asLiteral().getLanguage(); - String s2lang = s2.getObject().asLiteral().getLanguage(); + public void setVitroRequest(VitroRequest vitroRequest) { + this.vitroRequest = vitroRequest; + } - return compareLangs(s1lang, s2lang); - } - } + public VitroRequest getVitroRequest() { + return vitroRequest; + } } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/LanguageFilteringUtils.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/LanguageFilteringUtils.java index 5a03364624..720bcc1485 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/LanguageFilteringUtils.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/LanguageFilteringUtils.java @@ -4,26 +4,62 @@ import java.util.ArrayList; import java.util.Enumeration; +import java.util.HashSet; import java.util.List; import java.util.Locale; +import java.util.Set; import javax.servlet.ServletRequest; +import org.apache.commons.lang3.LocaleUtils; import org.apache.jena.ontology.OntModel; import org.apache.jena.ontology.OntModelSpec; import org.apache.jena.rdf.model.ModelFactory; -import edu.cornell.mannlib.vitro.webapp.dao.jena.RDFServiceGraph; -import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.jena.model.RDFServiceModel; - /** * Some methods that will come in handy when dealing with Language Filtering */ public class LanguageFilteringUtils { + private static final String UNDERSCORE = "_"; + private static final String HYPHEN = "-"; + private static final String DEFAULT_LANG_STRING = "en"; + + /** + * Take a Locale object, such as we might get from a + * request, and convert to a language string used in RDF. + * + * While converting, change all underscores (as in Locale names) to hyphens + * (as in RDF language specifiers). + */ + public static String localeToLanguage(Locale locale) { + return locale.toString().replace(UNDERSCORE, HYPHEN); + } + + /** + * Take a language string and convert to a Locale. + * + * While converting, change all hyphens (as in RDF language specifiers) to + * underscores (as in Locale names). Ensure language string is lowercase + * and country abbreviation is uppercase. + */ + public static Locale languageToLocale(String langStr) { + String[] langParts = langStr.split(HYPHEN); + if (langParts.length > 2) { + langStr = String.join(UNDERSCORE, langParts[0].toLowerCase(), + langParts[1].toUpperCase(), langParts[2]); + } else if (langParts.length > 1) { + langStr = String.join(UNDERSCORE, langParts[0].toLowerCase(), + langParts[1].toUpperCase()); + } else { + langStr = langParts[0].toLowerCase(); + } + return LocaleUtils.toLocale(langStr); + } + /** * Take an Enumeration of Locale objects, such as we might get from a - * request, and convert to a List of langauage strings, such as are needed + * request, and convert to a List of language strings, such as are needed * by the LanguageFilteringRDFService. * * While converting, change all underscores (as in Locale names) to hyphens @@ -33,27 +69,43 @@ public static List localesToLanguages(Enumeration locales) { List langs = new ArrayList<>(); while (locales.hasMoreElements()) { Locale locale = (Locale) locales.nextElement(); - langs.add(locale.toString().replace("_", "-")); + langs.add(locale.toString().replace(UNDERSCORE, HYPHEN)); } if (langs.isEmpty()) { - langs.add("en"); + langs.add(DEFAULT_LANG_STRING); } + return langs; + } + + /** + * Take a List of language strings and convert to a List of Locale. + * + * While converting, change all hyphens (as in RDF language specifiers) to + * under scores (as in Locale names). Ensure language string is lowercase + * and country abbreviation is uppercase. + */ + public static List languagesToLocales(List langs) { + Set locales = new HashSet<>(); + langs.forEach(langStr -> { + locales.add(languageToLocale(langStr)); + }); + if (locales.isEmpty()) { + locales.add(LocaleUtils.toLocale(DEFAULT_LANG_STRING)); + } + return new ArrayList<>(locales); } /** - * Add a Language Filtering layer to an OntModel by treating it as an RDFService. + * Add a Language Filtering layer to an OntModel */ public static OntModel wrapOntModelInALanguageFilter(OntModel rawModel, ServletRequest req) { - /** This is some nasty layering. Could we do this more easily? */ - List languages = localesToLanguages(req.getLocales()); + List languages = new AcceptableLanguages(localesToLanguages(req.getLocales())); return ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM, - RDFServiceGraph.createRDFServiceModel( - new RDFServiceGraph( - new LanguageFilteringRDFService( - new RDFServiceModel(rawModel), languages)))); + ModelFactory.createModelForGraph(new LanguageFilteringGraph( + rawModel.getGraph(), languages))); } private LanguageFilteringUtils() { diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceFactorySingle.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceFactorySingle.java index f44d2b59fe..44bd2aabb5 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceFactorySingle.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceFactorySingle.java @@ -9,6 +9,7 @@ import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.ModelChangedListener; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeListener; import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeSet; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; @@ -218,7 +219,20 @@ public String toString() { return ToString.simpleName(this) + "[" + ToString.hashHex(this) + ", inner=" + s + "]"; } + /* + * UQAM-Linguistic-Management Useful among other things to transport the linguistic context in the service + * (non-Javadoc) + * @see edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService#setVitroRequest(edu.cornell.mannlib.vitro.webapp.controller.VitroRequest) + */ + private VitroRequest vitroRequest; + public void setVitroRequest(VitroRequest vitroRequest) { + this.vitroRequest = vitroRequest; + } + + public VitroRequest getVitroRequest() { + return vitroRequest; + } } } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceImpl.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceImpl.java index 7962c1041a..6ff9613828 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceImpl.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceImpl.java @@ -32,6 +32,7 @@ import org.apache.jena.riot.out.NodeFormatterTTL; import org.apache.jena.vocabulary.RDF; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeListener; import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeSet; import edu.cornell.mannlib.vitro.webapp.rdfservice.ModelChange; @@ -141,8 +142,8 @@ protected void notifyListenersOfChanges(ChangeSet changeSet) } protected void notifyListeners(ModelChange modelChange) throws IOException { + modelChange.getSerializedModel().reset(); for (ChangeListener listener : registeredListeners) { - modelChange.getSerializedModel().reset(); listener.notifyModelChange(modelChange); } log.debug(registeredJenaListeners.size() + " registered Jena listeners"); @@ -259,6 +260,7 @@ protected static String sparqlNode(Node node, String varName) { } else if (node.getLiteralDatatypeURI() != null) { literalBuff.append("^^<").append(node.getLiteralDatatypeURI()).append(">"); } + return literalBuff.toString(); } else { return varName; @@ -453,4 +455,19 @@ protected void processQuerySolution(QuerySolution qs) { } } } + /* + * UQAM Useful among other things to transport the linguistic context in the service + * (non-Javadoc) + * @see edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService#setVitroRequest(edu.cornell.mannlib.vitro.webapp.controller.VitroRequest) + */ + private VitroRequest vitroRequest; + + public void setVitroRequest(VitroRequest vitroRequest) { + this.vitroRequest = vitroRequest; + } + + public VitroRequest getVitroRequest() { + return vitroRequest; + } + } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/jena/RDFServiceJena.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/jena/RDFServiceJena.java index dadccfed4a..888a51506f 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/jena/RDFServiceJena.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/jena/RDFServiceJena.java @@ -42,6 +42,7 @@ import org.apache.jena.shared.Lock; import org.apache.jena.sparql.core.Quad; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.dao.jena.DatasetWrapper; import edu.cornell.mannlib.vitro.webapp.dao.jena.RDFServiceDataset; import edu.cornell.mannlib.vitro.webapp.dao.jena.SparqlGraph; @@ -704,4 +705,19 @@ public void close() { protected QueryExecution createQueryExecution(String queryString, Query q, Dataset d) { return QueryExecutionFactory.create(q, d); } + /* + * UQAM-Linguistic-Management Useful among other things to transport the linguistic context in the service + * (non-Javadoc) + * @see edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService#setVitroRequest(edu.cornell.mannlib.vitro.webapp.controller.VitroRequest) + */ + private VitroRequest vitroRequest; + + public void setVitroRequest(VitroRequest vitroRequest) { + this.vitroRequest = vitroRequest; + } + + public VitroRequest getVitroRequest() { + return vitroRequest; + } + } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/jena/model/RDFServiceModel.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/jena/model/RDFServiceModel.java index 496928fbcc..4b910b568c 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/jena/model/RDFServiceModel.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/jena/model/RDFServiceModel.java @@ -13,6 +13,7 @@ import org.apache.jena.query.DatasetFactory; import org.apache.jena.rdf.model.Model; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.dao.jena.DatasetWrapper; import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeSet; import edu.cornell.mannlib.vitro.webapp.rdfservice.ModelChange; @@ -119,4 +120,18 @@ public boolean changeSetUpdate(ChangeSet changeSet) return true; } + /* + * UQAM-Linguistic-Management Useful among other things to transport the linguistic context in the service + * (non-Javadoc) + * @see edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService#setVitroRequest(edu.cornell.mannlib.vitro.webapp.controller.VitroRequest) + */ + private VitroRequest vitroRequest; + + public void setVitroRequest(VitroRequest vitroRequest) { + this.vitroRequest = vitroRequest; + } + + public VitroRequest getVitroRequest() { + return vitroRequest; + } } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/logging/LoggingRDFService.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/logging/LoggingRDFService.java index 5a0189f411..abae2aeb91 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/logging/LoggingRDFService.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/logging/LoggingRDFService.java @@ -9,6 +9,7 @@ import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.ModelChangedListener; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeListener; import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeSet; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; @@ -207,4 +208,19 @@ public void close() { public String toString() { return "LoggingRDFService[inner=" + innerService + "]"; } + /* + * UQAM-Linguistic-Management Useful among other things to transport the linguistic context in the service + * (non-Javadoc) + * @see edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService#setVitroRequest(edu.cornell.mannlib.vitro.webapp.controller.VitroRequest) + */ + private VitroRequest vitroRequest; + + public void setVitroRequest(VitroRequest vitroRequest) { + this.vitroRequest = vitroRequest; + } + + public VitroRequest getVitroRequest() { + return vitroRequest; + } + } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/search/controller/PagedSearchController.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/search/controller/PagedSearchController.java index 6596878b28..578c6a4a6d 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/search/controller/PagedSearchController.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/search/controller/PagedSearchController.java @@ -10,7 +10,6 @@ import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Map; diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/services/shortview/FakeApplicationOntologyService.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/services/shortview/FakeApplicationOntologyService.java index 383177cd78..770aab1818 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/services/shortview/FakeApplicationOntologyService.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/services/shortview/FakeApplicationOntologyService.java @@ -445,14 +445,26 @@ public ShortViewConfigException(String message, Throwable cause) { * "display model". The query finds a preferred title for the individual. */ private static class FakeVivoPeopleDataGetter extends SparqlQueryDataGetter { - private static String QUERY_STRING = "" + // private static String QUERY_STRING = "" + // + "PREFIX obo: \n" + // + "PREFIX vcard: \n" + // + "SELECT ?pt \n" + "WHERE { \n" + // + " ?uri obo:ARG_2000028 ?vIndividual . \n" + // + " ?vIndividual vcard:hasTitle ?vTitle . \n" + // + " ?vTitle vcard:title ?pt . \n" + "} LIMIT 1"; + + /* + * UQAM-Optimization New query including Linguistic context + */ + private static String QUERY_STRING_LANG = "" + "PREFIX obo: \n" + "PREFIX vcard: \n" + "SELECT ?pt \n" + "WHERE { \n" + " ?uri obo:ARG_2000028 ?vIndividual . \n" + " ?vIndividual vcard:hasTitle ?vTitle . \n" - + " ?vTitle vcard:title ?pt . \n" + "} LIMIT 1"; - + + " ?vTitle vcard:title ?pt . \n" + + " FILTER (lang(?pt) = '?langCtx' ) \n" + + " } LIMIT 1"; private static final String FAKE_VIVO_PEOPLE_DATA_GETTER_URI = "http://FakeVivoPeopleDataGetter"; private static OntModel fakeDisplayModel = initializeFakeDisplayModel(); @@ -467,7 +479,7 @@ private static OntModel initializeFakeDisplayModel() { Property saveToVarProperty = m .getProperty(DisplayVocabulary.SAVE_TO_VAR); - m.add(dataGetter, queryProperty, QUERY_STRING); + m.add(dataGetter, queryProperty, QUERY_STRING_LANG); //UQAM-Optimization Using query with linguistic context m.add(dataGetter, saveToVarProperty, "extra"); return m; } @@ -475,18 +487,24 @@ private static OntModel initializeFakeDisplayModel() { private String individualUri; private VitroRequest vreq; private ServletContext ctx; + private String langCtx = "en-US"; public FakeVivoPeopleDataGetter(VitroRequest vreq, String individualUri) { - super(vreq, fakeDisplayModel, "http://FakeVivoPeopleDataGetter"); + super(vreq, initializeFakeDisplayModel(), "http://FakeVivoPeopleDataGetter"); this.individualUri = individualUri; this.vreq = vreq; this.ctx = vreq.getSession().getServletContext(); + this.langCtx = vreq.getLocale().getLanguage(); // UQAM-Optimization add the linguistic context + if (!vreq.getLocale().getCountry().isEmpty()) { + this.langCtx += "-" + vreq.getLocale().getCountry(); + } } @Override public Map getData(Map pageData) { Map parms = new HashMap<>(); parms.put("uri", individualUri); + parms.put("langCtx", langCtx); //UQAM-Optimization add the linguistic context return super.getData(parms); } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/servlet/setup/ConfigurationModelsSetup.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/servlet/setup/ConfigurationModelsSetup.java index 1c0ea33ce3..6c6429327f 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/servlet/setup/ConfigurationModelsSetup.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/servlet/setup/ConfigurationModelsSetup.java @@ -12,15 +12,30 @@ import javax.servlet.ServletContextListener; import org.apache.jena.ontology.OntModel; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.Property; +import org.apache.jena.rdf.model.RDFNode; +import org.apache.jena.rdf.model.Resource; +import org.apache.jena.rdf.model.Statement; +import org.apache.jena.rdf.model.StmtIterator; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.List; import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess; import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus; +import edu.cornell.mannlib.vitro.webapp.rdfservice.adapters.VitroModelFactory; /** * Set up the models that use the CONFIGURATION RDFService. They are all mapped * to memory-based models. */ public class ConfigurationModelsSetup implements ServletContextListener { + private static final Log log = LogFactory.getLog(ConfigurationModelsSetup.class); + @Override public void contextInitialized(ServletContextEvent sce) { ServletContext ctx = sce.getServletContext(); @@ -31,33 +46,223 @@ public void contextInitialized(ServletContextEvent sce) { setupModel(ctx, DISPLAY_TBOX, "displayTbox"); setupModel(ctx, DISPLAY_DISPLAY, "displayDisplay"); setupModel(ctx, USER_ACCOUNTS, "auth"); - ss.info(this, - "Set up the display models and the user accounts model."); + ss.info(this, "Set up the display models and the user accounts model."); } catch (Exception e) { ss.fatal(this, e.getMessage(), e.getCause()); } } - private void setupModel(ServletContext ctx, String modelUri, - String modelPath) { + private void setupModel(ServletContext ctx, String modelUri, String modelPath) { try { OntModel ontModel = ModelAccess.on(ctx).getOntModel(modelUri); - loadFirstTimeFiles(ctx, modelPath, ontModel); + if (ontModel.isEmpty()) { + loadFirstTimeFiles(ctx, modelPath, ontModel); + // backup firsttime files + OntModel baseModelFirsttime = ModelAccess.on(ctx).getOntModel(modelUri + "FirsttimeBackup"); + baseModelFirsttime.add(ontModel); + } else { + // Check if the firsttime files have changed since the firsttime startup, + // if so, then apply the changes but not overwrite the whole user model + applyFirstTimeChanges(ctx, modelPath, modelUri, ontModel); + } + loadEveryTimeFiles(ctx, modelPath, ontModel); } catch (Exception e) { - throw new RuntimeException("Failed to create the '" + modelPath - + "' model (" + modelUri + ").", e); + throw new RuntimeException("Failed to create the '" + modelPath + "' model (" + modelUri + ").", e); + } + } + + private void loadFirstTimeFiles(ServletContext ctx, String modelPath, OntModel baseModel) { + RDFFilesLoader.loadFirstTimeFiles(ctx, modelPath, baseModel, baseModel.isEmpty()); + } + + private void loadEveryTimeFiles(ServletContext ctx, String modelPath, OntModel memoryModel) { + RDFFilesLoader.loadEveryTimeFiles(ctx, modelPath, memoryModel); + } + + /* + * Check if the firsttime files have changed since the firsttime startup, if so, + * then apply the changes but not overwrite the whole user model + */ + private void applyFirstTimeChanges(ServletContext ctx, String modelPath, String modelUri, OntModel userModel) { + + log.info("Reload firsttime files on start-up if changed: '" + modelPath +"', URI: '" + modelUri + "'"); + boolean updatedFiles = false; + + // get configuration models from the firsttime start up (backup state) + OntModel baseModelFirsttimeBackup = ModelAccess.on(ctx).getOntModel(modelUri + "FirsttimeBackup"); + + // compare firsttime files with configuration models + log.debug("compare firsttime files with configuration models (backup from first start) for " + modelPath); + + OntModel baseModelFirsttime = VitroModelFactory.createOntologyModel(); + RDFFilesLoader.loadFirstTimeFiles(ctx, modelPath, baseModelFirsttime, true); + + if (baseModelFirsttime.isIsomorphicWith(baseModelFirsttimeBackup)) { + log.debug("They are the same, so do nothing: '" + modelPath + "'"); + } else { + log.debug("They differ:" + modelPath + ", compare values in configuration models with user's triplestore"); + + updatedFiles = applyChanges(baseModelFirsttimeBackup, baseModelFirsttime, userModel, modelPath); + if (updatedFiles) + log.info("The model was updated, " + modelPath); + } + } + + /* + * This method is designed to compare configuration models (baseModel) with firsttime files (newModel): + * if they are the same, stop + * else, if they differ, compare values in configuration models (baseModel) with user's triplestore + * if they are the same, update user's triplestore with value in new firsttime files + * else, if they differ, leave user's triplestore statement alone + * finally, overwrite the configuration models with content of the updated firstime files + * + * @param baseModel The backup firsttime model (from the first startup) + * @param newModel The current state of the firsttime files in the directory + * @param userModel The current state of the user model + * @param modelIdString Just an string for the output for better debugging + * (display, displayTbox, displayDisplay, auth) + */ + private boolean applyChanges(Model baseModel, Model newModel, Model userModel, String modelIdString) { + boolean updatedFiles = false; + StringWriter out = new StringWriter(); + StringWriter out2 = new StringWriter(); + Model difOldNew = baseModel.difference(newModel); + Model difNewOld = newModel.difference(baseModel); + + // remove special cases for display, problem with blank nodes + if (modelIdString.equals("display")) { + + removeBlankTriples(difOldNew); + removeBlankTriples(difNewOld); + } + + if (difOldNew.isEmpty() && difNewOld.isEmpty()) { + // if there is no difference, nothing needs to be done + log.debug("For the " + modelIdString + " model, there is no difference in both directions. So do nothing."); + } else { + // if there is a difference, we need to remove the triples in difOldNew and + // add the triples in difNewOld to the back up firsttime model + + if (!difOldNew.isEmpty()) { + difOldNew.write(out, "TTL"); + log.debug("Difference for " + modelIdString + " (old -> new), these triples should be removed: " + out); + + // Check if the UI-changes Overlap with the changes made in the fristtime-files + checkUiChangesOverlapWithFileChanges(baseModel, userModel, difOldNew); + + // before we remove the triples, we need to compare values in back up firsttime with user's triplestore + // if the triples which should be removed are still in user´s triplestore, remove them + if (userModel.containsAny(difOldNew)) { + log.debug("Some of these triples are in the user triples store, so they will be removed now"); + userModel.remove(difOldNew); + updatedFiles = true; + } + + // remove the triples from the backup firsttime model for the next check + baseModel.remove(difOldNew); + } + if (!difNewOld.isEmpty()) { + difNewOld.write(out2, "TTL"); + log.debug("Difference for " + modelIdString + " (new -> old), these triples should be added: " + out2); + + // Check if the UI-changes Overlap with the changes made in the fristtime-files + checkUiChangesOverlapWithFileChanges(baseModel, userModel, difNewOld); + + // before we add the triples, we need to compare values in back up firsttime with user's triplestore + // if the triples which should be added are not already in user´s triplestore, add them + if (!userModel.containsAll(difNewOld)) { + log.debug("Some of these triples are not in the user triples store, so they will be added now"); + // but only the triples that are no already there + Model tmp = difNewOld.difference(userModel); + userModel.add(tmp); + updatedFiles = true; + } + + // add the triples from the back up firsttime model for the next check + baseModel.add(difNewOld); + } } + return updatedFiles; } - private void loadFirstTimeFiles(ServletContext ctx, String modelPath, - OntModel baseModel) { - RDFFilesLoader.loadFirstTimeFiles(modelPath, baseModel, baseModel.isEmpty()); + /** + * Check if the UI-changes Overlap with the changes made in the fristtime-files, if they overlap these changes are not applied to the user-model (UI) + * + * @param baseModel firsttime backup model + * @param userModel current state in the system (user/UI-model) + * @param changesModel the changes between firsttime-files and firttime-backup + */ + private void checkUiChangesOverlapWithFileChanges(Model baseModel, Model userModel, Model changesModel) { + log.debug("Beginn check if subtractions from Backup-firsttime model to current state of firsttime-files were changed in user-model (via UI)"); + Model changesUserModel = userModel.difference(baseModel); + List changedInUIandFileStatements = new ArrayList(); + + if(!changesUserModel.isEmpty()) + { + removeBlankTriples(changesUserModel); + + StringWriter out3 = new StringWriter(); + changesUserModel.write(out3, "TTL"); + log.debug("There were changes in the user-model via UI which have also changed in the firsttime files, the following triples will not be updated"); + + // iterate all statements and check if the ones which should be removed were not changed via the UI + StmtIterator iter = changesUserModel.listStatements(); + while (iter.hasNext()) { + Statement stmt = iter.nextStatement(); // get next statement + Resource subject = stmt.getSubject(); // get the subject + Property predicate = stmt.getPredicate(); // get the predicate + RDFNode object = stmt.getObject(); // get the object + + StmtIterator iter2 = changesModel.listStatements(); + + while (iter2.hasNext()) { + Statement stmt2 = iter2.nextStatement(); // get next statement + Resource subject2 = stmt2.getSubject(); // get the subject + Property predicate2 = stmt2.getPredicate(); // get the predicate + RDFNode object2 = stmt2.getObject(); // get the object + + // if subject and predicate are equal but the object differs and the language tag is the same, do not update these triples + // this case indicates an change in the UI, which should not be overwriten from the firsttime files + if(subject.equals(subject2) && predicate.equals(predicate2) && !object.equals(object2) ) { + // if object is an literal, check the language tag + if (object.isLiteral() && object2.isLiteral()) { + // if the langauge tag is the same, remove this triple from the update list + if(object.asLiteral().getLanguage().equals(object2.asLiteral().getLanguage())) { + log.debug("This two triples changed UI and files: \n UI: " + stmt + " \n file: " +stmt2); + changedInUIandFileStatements.add(stmt2); + } + } else { + log.debug("This two triples changed UI and files: \n UI: " + stmt + " \n file: " +stmt2); + changedInUIandFileStatements.add(stmt2); + } + } + } + } + // remove triples which were changed in the user model (UI) from the list + changesModel.remove(changedInUIandFileStatements); + } else { + log.debug("There were no changes in the user-model via UI compared to the backup-firsttime-model"); + } } + + /** + * Remove all triples where subject or object is blank (Anon) + */ + private void removeBlankTriples(Model model) { + StmtIterator iter = model.listStatements(); + List removeStatement = new ArrayList(); + while (iter.hasNext()) { + Statement stmt = iter.nextStatement(); // get next statement + Resource subject = stmt.getSubject(); // get the subject + RDFNode object = stmt.getObject(); // get the object - private void loadEveryTimeFiles(ServletContext ctx, String modelPath, - OntModel memoryModel) { - RDFFilesLoader.loadEveryTimeFiles(modelPath, memoryModel); + if(subject.isAnon() || object.isAnon()) + { + removeStatement.add(stmt); + } + } + model.remove(removeStatement); } @Override diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/servlet/setup/ContentModelSetup.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/servlet/setup/ContentModelSetup.java index 84e2d68093..2024e59e82 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/servlet/setup/ContentModelSetup.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/servlet/setup/ContentModelSetup.java @@ -5,9 +5,13 @@ import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.ABOX_ASSERTIONS; import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.APPLICATION_METADATA; import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.TBOX_ASSERTIONS; +import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.ABOX_ASSERTIONS_FIRSTTIME_BACKUP; +import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.TBOX_ASSERTIONS_FIRSTTIME_BACKUP; +import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.APPLICATION_METADATA_FIRSTTIME_BACKUP; import java.util.ArrayList; import java.util.List; +import java.io.StringWriter; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; @@ -17,12 +21,16 @@ import org.apache.jena.ontology.OntModel; import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.Property; import org.apache.jena.rdf.model.ResIterator; import org.apache.jena.rdf.model.Resource; import org.apache.jena.shared.Lock; import org.apache.jena.util.ResourceUtils; import org.apache.jena.util.iterator.ClosableIterator; import org.apache.jena.vocabulary.RDF; +import org.apache.jena.rdf.model.Statement; +import org.apache.jena.rdf.model.StmtIterator; +import org.apache.jena.rdf.model.RDFNode; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; import edu.cornell.mannlib.vitro.webapp.modelaccess.ContextModelAccess; @@ -60,22 +68,39 @@ private void setUpJenaDataSource(ServletContext ctx) { Model applicationMetadataModel = models.getOntModel(APPLICATION_METADATA); if (applicationMetadataModel.isEmpty()) { firstTimeStartup = true; - initializeApplicationMetadata(ctx, applicationMetadataModel); + initializeApplicationMetadata(ctx, applicationMetadataModel); + + // backup copy from firsttime files + OntModel applicationMetadataModelFirsttime = models.getOntModel(APPLICATION_METADATA_FIRSTTIME_BACKUP); + applicationMetadataModelFirsttime.add(applicationMetadataModel); + } else { + // check if some of the firsttime files have changed since the first start up and + // if they changed, apply these changes to the user models + applyFirstTimeChanges(ctx); + checkForNamespaceMismatch( applicationMetadataModel, ctx ); } OntModel baseABoxModel = models.getOntModel(ABOX_ASSERTIONS); if (firstTimeStartup) { - RDFFilesLoader.loadFirstTimeFiles("abox", baseABoxModel, true); + RDFFilesLoader.loadFirstTimeFiles(ctx, "abox", baseABoxModel, true); + + // backup copy from firsttime files + OntModel baseABoxModelFirsttime = models.getOntModel(ABOX_ASSERTIONS_FIRSTTIME_BACKUP); + baseABoxModelFirsttime.add(baseABoxModel); } - RDFFilesLoader.loadEveryTimeFiles("abox", baseABoxModel); + RDFFilesLoader.loadEveryTimeFiles(ctx, "abox", baseABoxModel); OntModel baseTBoxModel = models.getOntModel(TBOX_ASSERTIONS); if (firstTimeStartup) { - RDFFilesLoader.loadFirstTimeFiles("tbox", baseTBoxModel, true); + RDFFilesLoader.loadFirstTimeFiles(ctx, "tbox", baseTBoxModel, true); + + // backup copy from firsttime files + OntModel baseTBoxModelFirsttime = models.getOntModel(TBOX_ASSERTIONS_FIRSTTIME_BACKUP); + baseTBoxModelFirsttime.add(baseTBoxModel); } - RDFFilesLoader.loadEveryTimeFiles("tbox", baseTBoxModel); + RDFFilesLoader.loadEveryTimeFiles(ctx, "tbox", baseTBoxModel); } private long secondsSince(long startTime) { @@ -94,7 +119,7 @@ private long secondsSince(long startTime) { private void initializeApplicationMetadata(ServletContext ctx, Model applicationMetadataModel) { OntModel temporaryAMModel = VitroModelFactory.createOntologyModel(); - RDFFilesLoader.loadFirstTimeFiles("applicationMetadata", temporaryAMModel, true); + RDFFilesLoader.loadFirstTimeFiles(ctx, "applicationMetadata", temporaryAMModel, true); setPortalUriOnFirstTime(temporaryAMModel, ctx); applicationMetadataModel.add(temporaryAMModel); } @@ -191,6 +216,188 @@ private void renamePortal(Resource portal, String namespace, Model model) { } } + /* + * Check if the firsttime files have changed since the firsttime startup for all ContentModels, + * if so, then apply the changes but not overwrite the whole user model + */ + private void applyFirstTimeChanges(ServletContext ctx) { + + applyFirstTimeChanges(ctx, "applicationMetadata", APPLICATION_METADATA_FIRSTTIME_BACKUP, APPLICATION_METADATA); + + applyFirstTimeChanges(ctx, "abox", ABOX_ASSERTIONS_FIRSTTIME_BACKUP, ABOX_ASSERTIONS); + + applyFirstTimeChanges(ctx, "tbox", TBOX_ASSERTIONS_FIRSTTIME_BACKUP, TBOX_ASSERTIONS); + } + + + /* + * Check if the firsttime files have changed since the firsttime startup for one ContentModel, + * if so, then apply the changes but not overwrite the whole user model + */ + private void applyFirstTimeChanges(ServletContext ctx, String modelPath, String firsttimeBackupModelUri, String userModelUri) { + log.info("Reload firsttime files on start-up if changed: '" + modelPath +"', URI: '" +userModelUri+ "'"); + ContextModelAccess models = ModelAccess.on(ctx); + OntModel firsttimeBackupModel = models.getOntModel(firsttimeBackupModelUri); + + // compare firsttime files with configuration models + log.debug("compare firsttime files with configuration models (backup from first start) for " + modelPath); + OntModel firsttimeFilesModel = VitroModelFactory.createOntologyModel(); + RDFFilesLoader.loadFirstTimeFiles(ctx, modelPath, firsttimeFilesModel, true); + + // special initialization for application metadata model + if (firsttimeBackupModelUri.equals(APPLICATION_METADATA_FIRSTTIME_BACKUP)) { + setPortalUriOnFirstTime(firsttimeFilesModel, ctx); + } + + if ( firsttimeBackupModel.isIsomorphicWith(firsttimeFilesModel) ) { + log.debug("They are the same, so do nothing: '" + modelPath + "'"); + } else { + log.debug("They differ: '" + modelPath + "', compare values in configuration models with user's triplestore"); + OntModel userModel = models.getOntModel(userModelUri); + + // double check the statements (blank notes, etc.) and apply the changes + boolean updatedFiles = applyChanges(firsttimeBackupModel, firsttimeFilesModel, userModel, modelPath); + if (updatedFiles) log.info("The model was updated, " + modelPath); + } + } + + /* + * This method is designed to compare configuration models (baseModel) with firsttime files (newModel): + * if they are the same, stopFirstTime + * else, if they differ, compare values in configuration models (baseModel) with user's triplestore + * if they are the same, update user's triplestore with value in new firsttime files + * else, if they differ, leave user's triplestore statement alone + * finally, overwrite the configuration models with content of the updated firstime files + * + * @param baseModel The backup firsttime model (from the first startup) + * @param newModel The current state of the firsttime files in the directory + * @param userModel The current state of the user model + * @param modelIdString Just an string for the output for better debugging (tbox, abox, applicationMetadata) + */ + private boolean applyChanges(Model baseModel, Model newModel, Model userModel, String modelIdString) { + boolean updatedFiles = false; + StringWriter out = new StringWriter(); + StringWriter out2 = new StringWriter(); + Model difOldNew = baseModel.difference(newModel); + Model difNewOld = newModel.difference(baseModel); + + // special case for "rootTab" triple, do not need an update (is it still used in general? if not remove this case) + if(modelIdString.equals("applicationMetadata")) { + + Property p = userModel.createProperty("http://vitro.mannlib.cornell.edu/ns/vitro/0.7#", "rootTab"); + difOldNew.removeAll(null, p, null); + difNewOld.removeAll(null, p, null); + } + + if (difOldNew.isEmpty() && difNewOld.isEmpty()) { + // if there is no difference, nothing needs to be done + log.debug("For the " + modelIdString + " model, there is no difference in both directions. So do nothing."); + } else { + // if there is a difference, we need to remove the triples in difOldNew and + // add the triples in difNewOld to the back up firsttime model + + if (!difOldNew.isEmpty()) { + difOldNew.write(out, "TTL"); + log.debug("Difference for " + modelIdString + " (old -> new), these triples should be removed: " + out); + + // Check if the UI-changes Overlap with the changes made in the fristtime-files + checkUiChangesOverlapWithFileChanges(baseModel, userModel, difOldNew); + + // before we remove the triples, we need to compare values in back up firsttime with user's triplestore + // if the triples which should be removed are still in user´s triplestore, remove them + if (userModel.containsAny(difOldNew)) { + log.debug("Some of these triples are in the user triples store, so they will be removed now"); + userModel.remove(difOldNew); + updatedFiles = true; + } + + // remove the triples from the back up firsttime model for the next check + baseModel.remove(difOldNew); + + } + if (!difNewOld.isEmpty()) { + difNewOld.write(out2, "TTL"); + log.debug("Difference for " + modelIdString + " (new -> old), these triples should be added: " + out2); + + // Check if the UI-changes Overlap with the changes made in the fristtime-files + checkUiChangesOverlapWithFileChanges(baseModel, userModel, difNewOld); + + // before we add the triples, we need to compare values in back up firsttime with user's triplestore + // if the triples which should be added are not already in user´s triplestore, add them + if (!userModel.containsAll(difNewOld)) { + log.debug("Some of these triples are not in the user triples store, so they will be added now"); + // but only the triples that are no already there + Model tmp = difNewOld.difference(userModel); + userModel.add(tmp); + updatedFiles = true; + } + + // add the triples from the back up firsttime model for the next check + baseModel.add(difNewOld); + } + } + return updatedFiles; + } + + /** + * Check if the UI-changes Overlap with the changes made in the fristtime-files, if they overlap these changes are not applied to the user-model (UI) + * + * @param baseModel firsttime backup model + * @param userModel current state in the system (user/UI-model) + * @param changesModel the changes between firsttime-files and firttime-backup + */ + private void checkUiChangesOverlapWithFileChanges(Model baseModel, Model userModel, Model changesModel) { + log.debug("Beginn check if subtractions from Backup-firsttime model to current state of firsttime-files were changed in user-model (via UI)"); + Model changesUserModel = userModel.difference(baseModel); + List changedInUIandFileStatements = new ArrayList(); + + if(!changesUserModel.isEmpty()) + { + + StringWriter out3 = new StringWriter(); + changesUserModel.write(out3, "TTL"); + log.debug("There were changes in the user-model via UI which have also changed in the firsttime files, the following triples will not be updated"); + + // iterate all statements and check if the ones which should be removed were not changed via the UI + StmtIterator iter = changesUserModel.listStatements(); + while (iter.hasNext()) { + Statement stmt = iter.nextStatement(); // get next statement + Resource subject = stmt.getSubject(); // get the subject + Property predicate = stmt.getPredicate(); // get the predicate + RDFNode object = stmt.getObject(); // get the object + + StmtIterator iter2 = changesModel.listStatements(); + + while (iter2.hasNext()) { + Statement stmt2 = iter2.nextStatement(); // get next statement + Resource subject2 = stmt2.getSubject(); // get the subject + Property predicate2 = stmt2.getPredicate(); // get the predicate + RDFNode object2 = stmt2.getObject(); // get the object + + // if subject and predicate are equal but the object differs and the language tag is the same, do not update these triples + // this case indicates an change in the UI, which should not be overwriten from the firsttime files + if(subject.equals(subject2) && predicate.equals(predicate2) && !object.equals(object2) ) { + // if object is an literal, check the language tag + if (object.isLiteral() && object2.isLiteral()) { + // if the langauge tag is the same, remove this triple from the update list + if(object.asLiteral().getLanguage().equals(object2.asLiteral().getLanguage())) { + log.debug("This two triples changed UI and files: \n UI: " + stmt + " \n file: " +stmt2); + changedInUIandFileStatements.add(stmt2); + } + } else { + log.debug("This two triples changed UI and files: \n UI: " + stmt + " \n file: " +stmt2); + changedInUIandFileStatements.add(stmt2); + } + } + } + } + // remove triples which were changed in the user model (UI) from the list + changesModel.remove(changedInUIandFileStatements); + } else { + log.debug("There were no changes in the user-model via UI compared to the backup-firsttime-model"); + } + } + /* ===================================================================== */ @Override diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/servlet/setup/FileGraphSetup.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/servlet/setup/FileGraphSetup.java index e49f0e3dfc..80656403b9 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/servlet/setup/FileGraphSetup.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/servlet/setup/FileGraphSetup.java @@ -3,6 +3,7 @@ package edu.cornell.mannlib.vitro.webapp.servlet.setup; import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess.WhichService.CONTENT; +import static edu.cornell.mannlib.vitro.webapp.servlet.setup.RDFFilesLoader.getEnabledLocales; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -46,6 +47,7 @@ public class FileGraphSetup implements ServletContextListener { private static final Log log = LogFactory.getLog(FileGraphSetup.class); private static final String RDF = "rdf"; + private static final String I18N = "i18n"; private static final String ABOX = "abox"; private static final String TBOX = "tbox"; private static final String FILEGRAPH = "filegraph"; @@ -76,6 +78,12 @@ public void contextInitialized(ServletContextEvent sce) { // ABox files Set paths = getFilegraphPaths(ctx, RDF, ABOX, FILEGRAPH); + // Load ABox files from enabled languages + Set enabledLocales = getEnabledLocales(ctx); + for (String locale : enabledLocales) { + paths.addAll(getFilegraphPaths(ctx, RDF, I18N, locale, ABOX, FILEGRAPH)); + } + cleanupDB(dataset, pathsToURIs(paths, ABOX), ABOX); // Just update the ABox filegraphs in the DB; don't attach them to a base model. @@ -84,6 +92,11 @@ public void contextInitialized(ServletContextEvent sce) { // TBox files paths = getFilegraphPaths(ctx, RDF, TBOX, FILEGRAPH); + // Load TBox files from enabled languages + for (String locale : enabledLocales) { + paths.addAll(getFilegraphPaths(ctx, RDF, I18N, locale, TBOX, FILEGRAPH)); + } + cleanupDB(dataset, pathsToURIs(paths, TBOX),TBOX); OntModel tboxBaseModel = ModelAccess.on(ctx).getOntModel(ModelNames.TBOX_ASSERTIONS); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/servlet/setup/RDFFilesLoader.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/servlet/setup/RDFFilesLoader.java index 35fdaf54df..1710674260 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/servlet/setup/RDFFilesLoader.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/servlet/setup/RDFFilesLoader.java @@ -2,7 +2,6 @@ package edu.cornell.mannlib.vitro.webapp.servlet.setup; -import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; @@ -10,9 +9,13 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; import java.util.Set; import java.util.TreeSet; +import edu.cornell.mannlib.vitro.webapp.i18n.selection.SelectedLocale; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -23,6 +26,8 @@ import edu.cornell.mannlib.vitro.webapp.application.ApplicationUtils; +import javax.servlet.ServletContext; + /** * Help to load RDF files on first time and on every startup. */ @@ -31,11 +36,12 @@ public class RDFFilesLoader { private static final String DEFAULT_RDF_FORMAT = "RDF/XML"; private static final String RDF = "rdf"; + private static final String I18N = "i18n"; private static final String FIRST_TIME = "firsttime"; private static final String EVERY_TIME = "everytime"; /** - * Path filter that ignores sub-directories, hidden files, and markdown + * Path filter that ignores sub-directories, hidden files and markdown * files. */ private static final DirectoryStream.Filter RDF_FILE_FILTER = new DirectoryStream.Filter() { @@ -64,11 +70,20 @@ public boolean accept(Path p) throws IOException { * * The files from the directory are added to the model. */ - public static void loadFirstTimeFiles(String modelPath, Model model, + public static void loadFirstTimeFiles(ServletContext ctx, String modelPath, Model model, boolean firstTime) { if (firstTime) { String home = locateHomeDirectory(); + + // Load common files Set paths = getPaths(home, RDF, modelPath, FIRST_TIME); + + // Load enabled languages + Set enabledLocales = getEnabledLocales(ctx); + for (String locale : enabledLocales) { + paths.addAll(getPaths(home, RDF, I18N, locale, modelPath, FIRST_TIME)); + } + for (Path p : paths) { log.info("Loading " + relativePath(p, home)); readOntologyFileIntoModel(p, model); @@ -87,11 +102,20 @@ public static void loadFirstTimeFiles(String modelPath, Model model, * * The files from the directory become a sub-model of the model. */ - public static void loadEveryTimeFiles(String modelPath, OntModel model) { + public static void loadEveryTimeFiles(ServletContext ctx, String modelPath, OntModel model) { OntModel everytimeModel = ModelFactory .createOntologyModel(OntModelSpec.OWL_MEM); String home = locateHomeDirectory(); + + // Load common files Set paths = getPaths(home, RDF, modelPath, EVERY_TIME); + + // Load enabled languages + Set enabledLocales = getEnabledLocales(ctx); + for (String locale : enabledLocales) { + paths.addAll(getPaths(home, RDF, I18N, locale, modelPath, EVERY_TIME)); + } + for (Path p : paths) { log.info("Loading " + relativePath(p, home)); readOntologyFileIntoModel(p, everytimeModel); @@ -99,6 +123,23 @@ public static void loadEveryTimeFiles(String modelPath, OntModel model) { model.addSubModel(everytimeModel); } + public static Set getEnabledLocales(ServletContext ctx) { + Set enabledLocales = new HashSet<>(); + + // Which locales are enabled in runtime.properties? + List locales = SelectedLocale.getSelectableLocales(ctx); + for (Locale locale : locales) { + enabledLocales.add(locale.toLanguageTag().replace('-', '_')); + } + + // If no languages were enabled in runtime.properties, add 'en_US' as the default + if (enabledLocales.isEmpty()) { + enabledLocales.add("en_US"); + } + + return enabledLocales; + } + private static Path relativePath(Path p, String home) { try { return Paths.get(home).relativize(p); @@ -107,36 +148,9 @@ private static Path relativePath(Path p, String home) { } } - /** - * Create a model from all the RDF files in the specified directory. - */ - public static OntModel getModelFromDir(File dir) { - OntModel model = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); - if (dir == null) { - log.warn("Must pass a File to getModelFromDir()"); - return model; - } - if (!dir.isDirectory()) { - log.warn("Directory must be a File object for a directory"); - return model; - } - if (!dir.canRead()) { - log.warn("getModelFromDir(): Directory " - + " must be readable, check permissions on " - + dir.getAbsolutePath()); - return model; - } - - Set paths = getPaths(dir.getPath()); - for (Path p : paths) { - readOntologyFileIntoModel(p, model); - } - return model; - } - /** * Find the paths to RDF files in this directory. Sub-directories, hidden - * files, and markdown files are ignored. + * files, markdown, and non-enabled language files are ignored. */ private static Set getPaths(String parentDir, String... strings) { Path dir = Paths.get(parentDir, strings); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/servlet/setup/ThemeInfoSetup.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/servlet/setup/ThemeInfoSetup.java index 9cc824748d..1adb6c694f 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/servlet/setup/ThemeInfoSetup.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/servlet/setup/ThemeInfoSetup.java @@ -6,7 +6,6 @@ import java.io.File; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import javax.servlet.ServletContext; diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateKnowledgeBase.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateKnowledgeBase.java index 00fdcf1b0c..1bce3fbad6 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateKnowledgeBase.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateKnowledgeBase.java @@ -534,8 +534,12 @@ private void readFile(File f, OntModel om, String path) { try { if (f.getName().endsWith(".md")) { // Markdown files are documentation - skip. - } else if (f.getName().endsWith(".n3")) { + // UQAM-Optimization accept lower and upper case in fn extension + } else if (f.getName().toLowerCase().endsWith(".n3")) { om.read(fis, null, "N3"); + // UQAM-Optimization Accept Turtle (Must for us) + } else if (f.getName().toLowerCase().endsWith(".ttl")) { + om.read(fis, null, "TURTLE"); } else { om.read(fis, null, "RDF/XML"); } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/triplesource/impl/BasicShortTermCombinedTripleSource.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/triplesource/impl/BasicShortTermCombinedTripleSource.java index 5d43d04b7a..93bc5f8958 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/triplesource/impl/BasicShortTermCombinedTripleSource.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/triplesource/impl/BasicShortTermCombinedTripleSource.java @@ -98,9 +98,11 @@ public OntModelCache getOntModelCache() { @Override public WebappDaoFactoryConfig getWebappDaoFactoryConfig() { List langs = getPreferredLanguages(); + List locales = Collections.list(getPreferredLocales()); WebappDaoFactoryConfig config = new WebappDaoFactoryConfig(); config.setDefaultNamespace(props.getProperty("Vitro.defaultNamespace")); config.setPreferredLanguages(langs); + config.setPreferredLocales(locales); config.setUnderlyingStoreReasoned(isStoreReasoned()); config.setCustomListViewConfigFileMap(getCustomListViewConfigFileMap()); return config; @@ -111,7 +113,6 @@ private List getPreferredLanguages() { return LanguageFilteringUtils.localesToLanguages(getPreferredLocales()); } - @SuppressWarnings("unchecked") private Enumeration getPreferredLocales() { return req.getLocales(); } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/SparqlQueryDataGetter.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/SparqlQueryDataGetter.java index 7c1da263e4..e5c0577782 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/SparqlQueryDataGetter.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/SparqlQueryDataGetter.java @@ -165,7 +165,16 @@ private Map mergeParameters( private String bindParameters(String text, Map merged) { String bound = text; for (String key : merged.keySet()) { - bound = bound.replaceAll("([?$]" + key + ")([^a-zA-Z0-9_\\-])", "<" + merged.get(key) + ">$2"); + String value = merged.get(key); + if (value.startsWith("http://") || value.startsWith("https://")) { + /* + * UQAM-Optimization if the "value" looks like an URI then wrap the value with the characters '<' '>' + * + */ + bound = bound.replaceAll("([?$]" + key + ")([^a-zA-Z0-9_\\-])", "<" + value + ">$2"); + } else { + bound = bound.replaceAll("([?$]" + key + ")([^a-zA-Z0-9_\\-])", value + "$2"); + } } if (log.isDebugEnabled()) { log.debug("parameters: " + merged); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/threads/VitroBackgroundThread.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/threads/VitroBackgroundThread.java index d0ff197f71..2d38449332 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/threads/VitroBackgroundThread.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/utils/threads/VitroBackgroundThread.java @@ -21,6 +21,10 @@ * check their current status. */ public class VitroBackgroundThread extends Thread { + // UQAM-Bug-Correction add start + public synchronized void start() { + super.start(); + } private static final Log log = LogFactory.getLog(VitroBackgroundThread.class); private static final ConcurrentLinkedQueue> allThreads = new ConcurrentLinkedQueue>(); diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/web/templatemodels/customlistview/CustomListViewConfigFile.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/web/templatemodels/customlistview/CustomListViewConfigFile.java index 081690415f..89dc8c1bb2 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/web/templatemodels/customlistview/CustomListViewConfigFile.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/web/templatemodels/customlistview/CustomListViewConfigFile.java @@ -20,8 +20,6 @@ import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; -import edu.cornell.mannlib.vitro.webapp.beans.ApplicationBean; -import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.w3c.dom.Document; diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/web/templatemodels/edit/EditConfigurationTemplateModel.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/web/templatemodels/edit/EditConfigurationTemplateModel.java index 7f88848ecf..c3bd701dd0 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/web/templatemodels/edit/EditConfigurationTemplateModel.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/web/templatemodels/edit/EditConfigurationTemplateModel.java @@ -6,7 +6,6 @@ import java.net.URLDecoder; import java.text.Collator; import java.util.ArrayList; -import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; @@ -39,6 +38,8 @@ import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.fields.SelectListGeneratorVTwo; import edu.cornell.mannlib.vitro.webapp.i18n.I18n; import edu.cornell.mannlib.vitro.webapp.i18n.I18nBundle; +import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess; +import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess.LanguageOption; import edu.cornell.mannlib.vitro.webapp.web.beanswrappers.ReadOnlyBeansWrapper; import edu.cornell.mannlib.vitro.webapp.web.templatemodels.BaseTemplateModel; import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.ObjectPropertyStatementTemplateModel; @@ -98,7 +99,9 @@ private void retrieveEditData() throws Exception { private void populateDropdowns() throws Exception { //For each field with an optionType defined, create the options - WebappDaoFactory wdf = vreq.getWebappDaoFactory(); +// WebappDaoFactory wdf = vreq.getWebappDaoFactory(); + // UQAM-Optimization Manage Linguistic context + WebappDaoFactory wdf = ModelAccess.on(vreq).getWebappDaoFactory(LanguageOption.LANGUAGE_AWARE); for(String fieldName: editConfig.getFields().keySet()){ FieldVTwo field = editConfig.getField(fieldName); //TODO: Check if we even need empty options if field options do not exist @@ -106,7 +109,8 @@ private void populateDropdowns() throws Exception { //empty options field.setOptions(new ConstantFieldOptions()); } - Map optionsMap = SelectListGeneratorVTwo.getOptions(editConfig, fieldName, wdf); + //UQAM-Optimization changing signature for including internationalization in scroll-down menu + Map optionsMap = SelectListGeneratorVTwo.getOptions(editConfig, fieldName, wdf, I18n.bundle(vreq)); optionsMap = SelectListGeneratorVTwo.getSortedMap(optionsMap, field.getFieldOptions().getCustomComparator(), vreq); if(pageData.containsKey(fieldName)) { log.error("Check the edit configuration setup as pageData already contains " + fieldName + " and this will be overwritten now with empty collection"); @@ -129,6 +133,11 @@ private String getSelectedValue(String field) { return selectedValue; } + public String getPageTitle() { + String pageTitle = i18n.text("edit_page_title"); + return pageTitle != null ? pageTitle : "Edit"; + } + private void setFormTitle() { String predicateUri = editConfig.getPredicateUri(); if(predicateUri != null) { @@ -184,7 +193,7 @@ public String getObjectPropertyNameForDisplay() { Individual objectIndividual = EditConfigurationUtils.getObjectIndividual(vreq); ObjectProperty prop = EditConfigurationUtils.getObjectProperty(vreq); Individual subject = EditConfigurationUtils.getSubjectIndividual(vreq); - VClass rangeClass = EditConfigurationUtils.getRangeVClass(vreq); + VClass rangeClass = EditConfigurationUtils.getLangAwardRangeVClass(vreq); if(objectIndividual != null) { propertyTitle = prop.getDomainPublic(); } else { @@ -529,14 +538,17 @@ private String getDataLiteralValuesFromParameter() { //TODO:Check where this logic should actually go, copied from input element formatting tag //Updating to enable multiple vclasses applicable to subject to be analyzed to understand possible range of types public Map getOfferTypesCreateNew() { - WebappDaoFactory wdf = vreq.getWebappDaoFactory(); +// WebappDaoFactory wdf = vreq.getWebappDaoFactory(); + // UQAM-Optimization Manage Linguistic context + WebappDaoFactory wdf = ModelAccess.on(vreq).getWebappDaoFactory(LanguageOption.LANGUAGE_AWARE); ObjectProperty op = wdf.getObjectPropertyDao().getObjectPropertyByURI(editConfig.getPredicateUri()); Individual sub = wdf.getIndividualDao().getIndividualByURI(editConfig.getSubjectUri()); - VClass rangeClass = EditConfigurationUtils.getRangeVClass(vreq); + // UQAM-Optimization Manage Linguistic context + VClass rangeClass = EditConfigurationUtils.getLangAwardRangeVClass(vreq); List vclasses = null; List subjectVClasses = sub.getVClasses(); diff --git a/api/src/test/java/edu/cornell/mannlib/vitro/testing/AbstractTestClass.java b/api/src/test/java/edu/cornell/mannlib/vitro/testing/AbstractTestClass.java index fa5e4fe013..77d669415c 100644 --- a/api/src/test/java/edu/cornell/mannlib/vitro/testing/AbstractTestClass.java +++ b/api/src/test/java/edu/cornell/mannlib/vitro/testing/AbstractTestClass.java @@ -56,6 +56,7 @@ import org.apache.jena.ontology.OntModelSpec; import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.ModelFactory; +import stubs.edu.cornell.mannlib.vitro.webapp.i18n.I18nStub; /** * A collection of useful routines to help when testing. @@ -85,8 +86,21 @@ public abstract class AbstractTestClass { * {@link Level#INFO}. */ @Before + public void setUp() { + initializeLogging(); + useI18nStubBundles(); + } + @After - public void initializeLogging() { + public void tearDown() { + initializeLogging(); + } + + protected void useI18nStubBundles() { + I18nStub.setup(); + } + + private void initializeLogging() { LogManager.resetConfiguration(); Logger.getRootLogger().addAppender(new ConsoleAppender(patternLayout)); Logger.getRootLogger().setLevel(Level.INFO); diff --git a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/auth/policy/SelfEditingPolicyTest.java b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/auth/policy/SelfEditingPolicyTest.java index 68b0ab4cd4..17ef2333a4 100644 --- a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/auth/policy/SelfEditingPolicyTest.java +++ b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/auth/policy/SelfEditingPolicyTest.java @@ -67,7 +67,7 @@ public class SelfEditingPolicyTest extends AbstractTestClass { private OntModel ontModel; @Before - public void setUp() throws Exception { + public void setUp() { ctx = new ServletContextStub(); PropertyRestrictionBeanStub diff --git a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/auth/policy/SelfEditingPolicy_2_Test.java b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/auth/policy/SelfEditingPolicy_2_Test.java index 044318139c..ce77498684 100644 --- a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/auth/policy/SelfEditingPolicy_2_Test.java +++ b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/auth/policy/SelfEditingPolicy_2_Test.java @@ -75,7 +75,7 @@ public class SelfEditingPolicy_2_Test extends AbstractTestClass { @Before - public void setUp() throws Exception { + public void setUp() { ServletContextStub ctx = new ServletContextStub(); PropertyRestrictionBeanStub.getInstance(new String[] { ADMIN_NS }); diff --git a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/controller/edit/AuthenticateTest.java b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/controller/edit/AuthenticateTest.java index f15e055678..c849fa411a 100644 --- a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/controller/edit/AuthenticateTest.java +++ b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/controller/edit/AuthenticateTest.java @@ -48,7 +48,6 @@ import edu.cornell.mannlib.vitro.webapp.beans.PermissionSet; import edu.cornell.mannlib.vitro.webapp.beans.UserAccount; import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties; -import edu.cornell.mannlib.vitro.webapp.controller.authenticate.Authenticator; import edu.cornell.mannlib.vitro.webapp.controller.authenticate.AuthenticatorStub; import edu.cornell.mannlib.vitro.webapp.controller.login.LoginProcessBean; import edu.cornell.mannlib.vitro.webapp.controller.login.LoginProcessBean.State; diff --git a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/DataPropertyDaoJenaTest.java b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/DataPropertyDaoJenaTest.java index 8548ea76d7..6e436c8f85 100644 --- a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/DataPropertyDaoJenaTest.java +++ b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/DataPropertyDaoJenaTest.java @@ -11,6 +11,7 @@ import org.apache.jena.ontology.OntModelSpec; import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.ModelFactory; +import org.apache.jena.rdf.model.ResourceFactory; import org.apache.jena.vocabulary.OWL; import org.apache.jena.vocabulary.RDF; import org.apache.jena.vocabulary.RDFS; @@ -65,9 +66,9 @@ public void minimalUpdates(){ property1.setPropertyValue(RDFS.domain, subModel.createResource("http://thisIsTheDomainClassURI")); property1.setPropertyValue(RDFS.range, subModel.createResource("http://thisIsTheRangeClassURI")); property1.addProperty(RDF.type, OWL.FunctionalProperty); - property1.setPropertyValue(subModel.createProperty(VitroVocabulary.EXAMPLE_ANNOT), subModel.createTypedLiteral("this is the example")); - property1.setPropertyValue(subModel.createProperty(VitroVocabulary.DESCRIPTION_ANNOT), subModel.createTypedLiteral("this is the description")); - property1.setPropertyValue(subModel.createProperty(VitroVocabulary.PUBLIC_DESCRIPTION_ANNOT), subModel.createTypedLiteral("this is the public description")); + property1.setPropertyValue(subModel.createProperty(VitroVocabulary.EXAMPLE_ANNOT), ResourceFactory.createLangLiteral("this is the example", lang)); + property1.setPropertyValue(subModel.createProperty(VitroVocabulary.DESCRIPTION_ANNOT), ResourceFactory.createLangLiteral("this is the description", lang)); + property1.setPropertyValue(subModel.createProperty(VitroVocabulary.PUBLIC_DESCRIPTION_ANNOT), ResourceFactory.createLangLiteral("this is the public description", lang)); property1.setPropertyValue(subModel.createProperty(VitroVocabulary.DISPLAY_RANK_ANNOT), subModel.createTypedLiteral(21)); property1.setPropertyValue(subModel.createProperty(VitroVocabulary.DISPLAY_LIMIT), subModel.createTypedLiteral(5)); property1.setPropertyValue(subModel.createProperty(VitroVocabulary.HIDDEN_FROM_DISPLAY_BELOW_ROLE_LEVEL_ANNOT), subModel.createResource("http://vitro.mannlib.cornell.edu/ns/vitro/role#curator")); diff --git a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/DependentResourceDeleteJenaTest.java b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/DependentResourceDeleteJenaTest.java index 2428b56de1..24b98809d5 100644 --- a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/DependentResourceDeleteJenaTest.java +++ b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/DependentResourceDeleteJenaTest.java @@ -5,6 +5,7 @@ import java.io.StringReader; import java.util.List; +import edu.cornell.mannlib.vitro.testing.AbstractTestClass; import org.junit.Assert; import org.apache.jena.rdf.model.Model; @@ -16,7 +17,7 @@ import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; -public class DependentResourceDeleteJenaTest { +public class DependentResourceDeleteJenaTest extends AbstractTestClass { String isDependentRelation = " <"+VitroVocabulary.PROPERTY_STUBOBJECTPROPERTYANNOT+"> \"true\"^^xsd:boolean .\n" ; diff --git a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaBaseDaoTest.java b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaBaseDaoTest.java index 01058f799b..fe3938974a 100644 --- a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaBaseDaoTest.java +++ b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaBaseDaoTest.java @@ -2,26 +2,29 @@ package edu.cornell.mannlib.vitro.webapp.dao.jena; +import static org.junit.Assert.assertEquals; + import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.io.StringReader; -import org.junit.Assert; - -import org.junit.Test; - import org.apache.jena.ontology.OntClass; import org.apache.jena.ontology.OntModel; import org.apache.jena.ontology.OntModelSpec; import org.apache.jena.ontology.OntProperty; +import org.apache.jena.ontology.OntResource; import org.apache.jena.ontology.Restriction; import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.ModelFactory; +import org.apache.jena.rdf.model.ResourceFactory; import org.apache.jena.vocabulary.OWL; import org.apache.jena.vocabulary.RDF; import org.apache.jena.vocabulary.RDFS; import org.apache.jena.vocabulary.XSD; +import org.junit.Assert; +import org.junit.Test; +import edu.cornell.mannlib.vitro.testing.AbstractTestClass; import edu.cornell.mannlib.vitro.webapp.beans.DataProperty; import edu.cornell.mannlib.vitro.webapp.beans.DataPropertyStatement; import edu.cornell.mannlib.vitro.webapp.beans.DataPropertyStatementImpl; @@ -35,7 +38,7 @@ import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; -public class JenaBaseDaoTest { +public class JenaBaseDaoTest extends AbstractTestClass { String isDependentRelation = " <"+VitroVocabulary.PROPERTY_STUBOBJECTPROPERTYANNOT+"> \"true\"^^xsd:boolean .\n" ; @@ -457,6 +460,53 @@ public void testPreventInvalidRestrictionsOnDeletion() { Assert.assertEquals(m.size(), 2); // just rdf:type for Class1 and Prop } + + @Test + /** + * Test that a resource's labels in one language are correctly updated without + * affecting labels in other languages. + */ + public void testUpdateRDFSLabel() { + OntModel m = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); + WebappDaoFactoryJena wadf = new WebappDaoFactoryJena(m); + JenaBaseDao dao = new JenaBaseDao(wadf); + OntResource ontRes = m.createOntResource("http://example.com/i/n1"); + // update one language + m.add(ontRes, RDFS.label, ResourceFactory.createLangLiteral("engLabel1", "en-US")); + m.add(ontRes, RDFS.label, ResourceFactory.createLangLiteral("esLabel1", "es-ES")); + dao.updateRDFSLabel(ontRes, "engLabel2", "en-US"); + assertEquals(2, m.size()); + Assert.assertTrue(m.contains(ontRes, RDFS.label, ResourceFactory.createLangLiteral("engLabel2", "en-US"))); + Assert.assertTrue(m.contains(ontRes, RDFS.label, ResourceFactory.createLangLiteral("esLabel1", "es-ES"))); + m.removeAll(); + // update language-less + m.add(ontRes, RDFS.label, ResourceFactory.createLangLiteral("engLabel1", "en-US")); + m.add(ontRes, RDFS.label, ResourceFactory.createLangLiteral("esLabel1", "es-ES")); + m.add(ontRes, RDFS.label, "languageLessLabel1"); + dao.updateRDFSLabel(ontRes, "languageLessLabel2", null); + assertEquals(3, m.size()); + Assert.assertTrue(m.contains(ontRes, RDFS.label, ResourceFactory.createLangLiteral("engLabel1", "en-US"))); + Assert.assertTrue(m.contains(ontRes, RDFS.label, ResourceFactory.createLangLiteral("esLabel1", "es-ES"))); + Assert.assertTrue(m.contains(ontRes, RDFS.label, "languageLessLabel2")); + m.removeAll(); + // remove a language + m.add(ontRes, RDFS.label, ResourceFactory.createLangLiteral("engLabel1", "en-US")); + m.add(ontRes, RDFS.label, ResourceFactory.createLangLiteral("esLabel1", "es-ES")); + m.add(ontRes, RDFS.label, m.createTypedLiteral("stringLabel1")); + dao.updateRDFSLabel(ontRes, null, "en-US"); + assertEquals(2, m.size()); + Assert.assertTrue(m.contains(ontRes, RDFS.label, ResourceFactory.createLangLiteral("esLabel1", "es-ES"))); + Assert.assertTrue(m.contains(ontRes, RDFS.label, m.createTypedLiteral("stringLabel1"))); + m.removeAll(); + // remove language-less labels + m.add(ontRes, RDFS.label, ResourceFactory.createLangLiteral("engLabel1", "en-US")); + m.add(ontRes, RDFS.label, ResourceFactory.createLangLiteral("esLabel1", "es-ES")); + m.add(ontRes, RDFS.label, ResourceFactory.createPlainLiteral("languageLessLabel1")); + dao.updateRDFSLabel(ontRes, null, null); + assertEquals(2, m.size()); + Assert.assertTrue(m.contains(ontRes, RDFS.label, ResourceFactory.createLangLiteral("engLabel1", "en-US"))); + Assert.assertTrue(m.contains(ontRes, RDFS.label, ResourceFactory.createLangLiteral("esLabel1", "es-ES"))); + } /** * Compare the contents of the expected model with the actual model (not counting modification times). diff --git a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaBaseDao_2_Test.java b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaBaseDao_2_Test.java index 9e448c651e..5bbce84bfa 100644 --- a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaBaseDao_2_Test.java +++ b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaBaseDao_2_Test.java @@ -48,6 +48,8 @@ public class JenaBaseDao_2_Test extends AbstractTestClass { @Before public void initializeThings() { + super.setUp(); + ontModel = ModelFactory.createOntologyModel(); prop1 = ontModel.createProperty("property1"); diff --git a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/MenuDaoJenaTest.java b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/MenuDaoJenaTest.java index 59a8d8bc5c..f7d5ca528e 100644 --- a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/MenuDaoJenaTest.java +++ b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/MenuDaoJenaTest.java @@ -27,7 +27,9 @@ public class MenuDaoJenaTest extends AbstractTestClass { OntModel displayModel; @Before - public void setUp() throws Exception { + public void setUp() { + super.setUp(); + // Suppress error logging. setLoggerLevel(RDFDefaultErrorHandler.class, Level.OFF); diff --git a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/ObjectPropertyDaoJenaTest.java b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/ObjectPropertyDaoJenaTest.java index 5df2360605..32aab2131f 100644 --- a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/ObjectPropertyDaoJenaTest.java +++ b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/ObjectPropertyDaoJenaTest.java @@ -9,6 +9,7 @@ import org.apache.jena.ontology.OntModelSpec; import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.ModelFactory; +import org.apache.jena.rdf.model.ResourceFactory; import org.apache.jena.vocabulary.RDFS; import edu.cornell.mannlib.vitro.testing.AbstractTestClass; @@ -136,9 +137,9 @@ public void minimalUpdates(){ property1.setPropertyValue(RDFS.domain, subModel.createResource("http://thisIsTheDomainClassURI")); property1.setPropertyValue(RDFS.range, subModel.createResource("http://thisIsTheRangeClassURI")); - property1.setPropertyValue(subModel.createProperty(VitroVocabulary.EXAMPLE_ANNOT), subModel.createTypedLiteral("this is the example")); - property1.setPropertyValue(subModel.createProperty(VitroVocabulary.DESCRIPTION_ANNOT), subModel.createTypedLiteral("this is the description")); - property1.setPropertyValue(subModel.createProperty(VitroVocabulary.PUBLIC_DESCRIPTION_ANNOT), subModel.createTypedLiteral("this is the public description")); + property1.setPropertyValue(subModel.createProperty(VitroVocabulary.EXAMPLE_ANNOT), ResourceFactory.createLangLiteral("this is the example", lang)); + property1.setPropertyValue(subModel.createProperty(VitroVocabulary.DESCRIPTION_ANNOT), ResourceFactory.createLangLiteral("this is the description", lang)); + property1.setPropertyValue(subModel.createProperty(VitroVocabulary.PUBLIC_DESCRIPTION_ANNOT), ResourceFactory.createLangLiteral("this is the public description", lang)); property1.setPropertyValue(subModel.createProperty(VitroVocabulary.DISPLAY_LIMIT), subModel.createTypedLiteral(6)); property1.setPropertyValue(subModel.createProperty(VitroVocabulary.PROPERTY_ENTITYSORTFIELD), subModel.createTypedLiteral("this is the entity sort field")); property1.setPropertyValue(subModel.createProperty(VitroVocabulary.PROPERTY_ENTITYSORTDIRECTION), subModel.createTypedLiteral("this is the entity sort direction")); diff --git a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/ObjectPropertyStatementDaoJenaTest.java b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/ObjectPropertyStatementDaoJenaTest.java index bc5c8bdef4..6488a107b6 100644 --- a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/ObjectPropertyStatementDaoJenaTest.java +++ b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/ObjectPropertyStatementDaoJenaTest.java @@ -4,12 +4,13 @@ import static org.junit.Assert.*; +import edu.cornell.mannlib.vitro.testing.AbstractTestClass; import org.junit.Test; import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.ModelFactory; -public class ObjectPropertyStatementDaoJenaTest { +public class ObjectPropertyStatementDaoJenaTest extends AbstractTestClass { /** * Test if jena lib can parse N3 that it generates. diff --git a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/OntModelSegementationTest.java b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/OntModelSegementationTest.java index 8867ce9cc3..7800acedf0 100644 --- a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/OntModelSegementationTest.java +++ b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/OntModelSegementationTest.java @@ -2,6 +2,7 @@ package edu.cornell.mannlib.vitro.webapp.dao.jena; +import edu.cornell.mannlib.vitro.testing.AbstractTestClass; import org.junit.Assert; import org.junit.Ignore; @@ -28,11 +29,12 @@ * @author bjl23 * */ -public class OntModelSegementationTest { +public class OntModelSegementationTest extends AbstractTestClass { private WebappDaoFactoryJena wadf; @org.junit.Before public void setUpWebappDaoFactoryJena() { + super.setUp(); wadf = new WebappDaoFactoryJena(new SimpleOntModelSelector()); } diff --git a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/PropertyInstanceDaoJenaTest.java b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/PropertyInstanceDaoJenaTest.java index d4b55a5402..76e681466f 100644 --- a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/PropertyInstanceDaoJenaTest.java +++ b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/PropertyInstanceDaoJenaTest.java @@ -7,6 +7,7 @@ import java.util.HashMap; import java.util.Map; +import edu.cornell.mannlib.vitro.testing.AbstractTestClass; import org.junit.Assert; import org.apache.jena.ontology.OntModel; @@ -20,7 +21,7 @@ import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; -public class PropertyInstanceDaoJenaTest { +public class PropertyInstanceDaoJenaTest extends AbstractTestClass { String isDependentRelation = " <"+VitroVocabulary.PROPERTY_STUBOBJECTPROPERTYANNOT+"> \"true\"^^xsd:boolean .\n" ; diff --git a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/UserAccountsDaoJenaTest.java b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/UserAccountsDaoJenaTest.java index e6a3013669..7f755bf426 100644 --- a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/UserAccountsDaoJenaTest.java +++ b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/UserAccountsDaoJenaTest.java @@ -74,6 +74,8 @@ public class UserAccountsDaoJenaTest extends AbstractTestClass { @Before public void setup() throws IOException { + super.setUp(); + InputStream stream = UserAccountsDaoJenaTest.class .getResourceAsStream(N3_DATA_FILENAME); Model model = ModelFactory.createDefaultModel(); @@ -90,6 +92,8 @@ public void setup() throws IOException { @Before public void createUserAccountValues() { + super.setUp(); + user1 = userAccount(URI_USER1, "email@able.edu", "Zack", "Roberts", "garbage", "" ,"", 0L, false, 5, 12345678L, Status.ACTIVE, "user1", false, collection(URI_ROLE1), false, EMPTY); diff --git a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassDaoTest.java b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassDaoTest.java index 4bca1fd7e0..94068bf978 100644 --- a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassDaoTest.java +++ b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassDaoTest.java @@ -3,19 +3,25 @@ package edu.cornell.mannlib.vitro.webapp.dao.jena; -import java.util.List; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; -import static org.junit.Assert.*; -import org.junit.Test; +import java.io.StringWriter; +import java.util.List; +import org.apache.jena.atlas.logging.Log; import org.apache.jena.ontology.ObjectProperty; import org.apache.jena.ontology.OntClass; import org.apache.jena.ontology.OntModel; import org.apache.jena.ontology.OntModelSpec; import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.ModelFactory; +import org.apache.jena.rdf.model.ResourceFactory; import org.apache.jena.vocabulary.OWL; +import org.junit.Test; +import edu.cornell.mannlib.vitro.testing.AbstractTestClass; import edu.cornell.mannlib.vitro.webapp.beans.VClass; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; @@ -24,7 +30,7 @@ * */ -public class VClassDaoTest { +public class VClassDaoTest extends AbstractTestClass { @Test // Test that the VClassDaoJena::updateVClass method will only update the jena model for @@ -62,9 +68,9 @@ public void modelIsolation(){ class1.setLabel(rdfsLabel,lang); //rdfs:label class1.setPropertyValue(subModel.createProperty(VitroVocabulary.IN_CLASSGROUP), subModel.createResource("http://thisIsTheClassGroupURI")); - class1.setPropertyValue(subModel.createProperty(VitroVocabulary.SHORTDEF), subModel.createTypedLiteral("this is the short definition")); - class1.setPropertyValue(subModel.createProperty(VitroVocabulary.EXAMPLE_ANNOT), subModel.createTypedLiteral("this is the example - why is this a string?")); - class1.setPropertyValue(subModel.createProperty(VitroVocabulary.DESCRIPTION_ANNOT), subModel.createTypedLiteral("this is the description")); + class1.setPropertyValue(subModel.createProperty(VitroVocabulary.SHORTDEF), ResourceFactory.createLangLiteral("this is the short definition", lang)); + class1.setPropertyValue(subModel.createProperty(VitroVocabulary.EXAMPLE_ANNOT), ResourceFactory.createLangLiteral("this is the example - why is this a string?", lang)); + class1.setPropertyValue(subModel.createProperty(VitroVocabulary.DESCRIPTION_ANNOT), ResourceFactory.createLangLiteral("this is the description", lang)); class1.setPropertyValue(subModel.createProperty(VitroVocabulary.DISPLAY_LIMIT), subModel.createTypedLiteral(-1)); class1.setPropertyValue(subModel.createProperty(VitroVocabulary.DISPLAY_RANK_ANNOT), subModel.createTypedLiteral(-11)); class1.setPropertyValue(subModel.createProperty(VitroVocabulary.SEARCH_BOOST_ANNOT), subModel.createTypedLiteral(2.4f)); @@ -120,7 +126,7 @@ public void modelIsolation(){ wipeOutModTime(superModel); assertTrue(subModel.isIsomorphicWith(origSubModel)); - assertTrue(superModel.isIsomorphicWith(origSuperModel)); + assertTrue(superModel.isIsomorphicWith(origSuperModel)); } diff --git a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassGroupCacheTest.java b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassGroupCacheTest.java index 684686a074..6a60adb2dd 100644 --- a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassGroupCacheTest.java +++ b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassGroupCacheTest.java @@ -4,6 +4,7 @@ import java.io.StringReader; +import edu.cornell.mannlib.vitro.testing.AbstractTestClass; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -14,10 +15,12 @@ import org.apache.jena.rdf.model.Statement; import org.apache.jena.vocabulary.RDFS; -public class VClassGroupCacheTest { +public class VClassGroupCacheTest extends AbstractTestClass { @Before - public void setUp() throws Exception { + public void setUp() { + // Not calling super.setUp() because we do not want to change the logging level + super.useI18nStubBundles(); } @Test diff --git a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassJenaTest.java b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassJenaTest.java index e252292d0c..3aeb732fc2 100644 --- a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassJenaTest.java +++ b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassJenaTest.java @@ -7,6 +7,7 @@ import java.util.Iterator; import java.util.List; +import edu.cornell.mannlib.vitro.testing.AbstractTestClass; import org.junit.Assert; import org.junit.Test; @@ -49,7 +50,7 @@ * */ -public class VClassJenaTest { +public class VClassJenaTest extends AbstractTestClass { @Test // NIHVIVO-1157 introduced VClassJena.java, a lazy-loading version of VClass.java. diff --git a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/BasicValidationVTwoTest.java b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/BasicValidationVTwoTest.java index 678ca76d15..4b3b27cfe6 100644 --- a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/BasicValidationVTwoTest.java +++ b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/BasicValidationVTwoTest.java @@ -4,44 +4,46 @@ import java.util.Collections; -import org.junit.Assert; +import javax.servlet.http.HttpServletRequest; +import org.junit.Assert; +import org.junit.Before; import org.junit.Test; +import stubs.edu.cornell.mannlib.vitro.webapp.i18n.I18nStub; +import stubs.javax.servlet.http.HttpServletRequestStub; + public class BasicValidationVTwoTest { + @Before + public void useI18nStubBundles() { + I18nStub.setup(); + } @SuppressWarnings("unchecked") @Test public void testHttpUrlValidate() { - BasicValidationVTwo bv = new BasicValidationVTwo(Collections.EMPTY_MAP); + HttpServletRequest req = new HttpServletRequestStub(); + BasicValidationVTwo bv = new BasicValidationVTwo(Collections.EMPTY_MAP, I18nStub.bundle(req)); String res; res = bv.validate("httpUrl", "http://example.com/index"); - Assert.assertEquals(res, BasicValidationVTwo.SUCCESS); + Assert.assertEquals(BasicValidationVTwo.SUCCESS, res); res = bv.validate("httpUrl", "http://example.com/index?bogus=skjd%20skljd&something=sdkf"); - Assert.assertEquals(res, BasicValidationVTwo.SUCCESS); + Assert.assertEquals(BasicValidationVTwo.SUCCESS, res); res = bv.validate("httpUrl", "http://example.com/index#2.23?bogus=skjd%20skljd&something=sdkf"); - Assert.assertEquals(res, BasicValidationVTwo.SUCCESS); + Assert.assertEquals(BasicValidationVTwo.SUCCESS, res); } @SuppressWarnings("unchecked") @Test public void testEmptyValidate(){ - BasicValidationVTwo bv = new BasicValidationVTwo(Collections.EMPTY_MAP); - - Assert.assertEquals( - bv.validate("nonempty", null) - , BasicValidationVTwo.REQUIRED_FIELD_EMPTY_MSG); - - - Assert.assertEquals( - bv.validate("nonempty", "") - , BasicValidationVTwo.REQUIRED_FIELD_EMPTY_MSG); + HttpServletRequest req = new HttpServletRequestStub(); + BasicValidationVTwo bv = new BasicValidationVTwo(Collections.EMPTY_MAP, I18nStub.bundle(req)); - Assert.assertEquals( - bv.validate("nonempty", "some value") - , BasicValidationVTwo.SUCCESS); + Assert.assertEquals(BasicValidationVTwo.REQUIRED_FIELD_EMPTY_MSG, bv.validate("nonempty", null)); + Assert.assertEquals(BasicValidationVTwo.REQUIRED_FIELD_EMPTY_MSG, bv.validate("nonempty", "")); + Assert.assertEquals(BasicValidationVTwo.SUCCESS, bv.validate("nonempty", "some value")); } } diff --git a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/ProcessRdfFormTest.java b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/ProcessRdfFormTest.java index 79ee543655..56a4b4d7cc 100644 --- a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/ProcessRdfFormTest.java +++ b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/ProcessRdfFormTest.java @@ -19,11 +19,13 @@ import org.apache.jena.vocabulary.RDFS; import edu.cornell.mannlib.vitro.testing.AbstractTestClass; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.dao.InsertException; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.fields.FieldVTwo; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.EditConfigurationConstants; +import stubs.javax.servlet.http.HttpServletRequestStub; -public class ProcessRdfFormTest extends AbstractTestClass{ +public class ProcessRdfFormTest extends AbstractTestClass { @Test public void basicNewStatementTest() throws Exception{ @@ -40,14 +42,16 @@ public void basicNewStatementTest() throws Exception{ values.put("test3", (new String[] {"http://test.com/uri3"})); values.put("editKey", (new String[] {"mockEditKey"})); - MultiValueEditSubmission submission = new MultiValueEditSubmission(values, config); + VitroRequest vreq = createRequestWithParameters(values); + + MultiValueEditSubmission submission = new MultiValueEditSubmission(vreq, config); ProcessRdfForm processor = new ProcessRdfForm(config,getMockNewURIMaker()); /* test just the N3 substitution part */ Listreq = config.getN3Required(); Listopt = config.getN3Optional(); - processor.subInValuesToN3( config , submission, req, opt, null , null); + processor.subInValuesToN3( config , submission, req, opt, null , null, vreq); assertNotNull(req); assertTrue( req.size() > 0); assertNotNull(req.get(0)); @@ -102,7 +106,10 @@ public void basicEditStatement() throws Exception{ Map values = new HashMap(); values.put("testZ", (new String[] {testZURIChanged})); values.put("editKey", (new String[] {"mockEditKey"})); - MultiValueEditSubmission submission = new MultiValueEditSubmission(values, config); + + VitroRequest vreq = createRequestWithParameters(values); + + MultiValueEditSubmission submission = new MultiValueEditSubmission(vreq, config); ProcessRdfForm processor = new ProcessRdfForm(config,getMockNewURIMaker()); AdditionsAndRetractions changes = processor.process( config, submission, null ); @@ -176,14 +183,17 @@ public void unicodeTest() throws Exception{ values.put("test2", (new String[] {test2})); values.put("test3", (new String[] {test3})); values.put("editKey", (new String[] {"mockEditKey"})); - MultiValueEditSubmission submission = new MultiValueEditSubmission(values, config); + + VitroRequest vreq = createRequestWithParameters(values); + + MultiValueEditSubmission submission = new MultiValueEditSubmission(vreq, config); ProcessRdfForm processor = new ProcessRdfForm(config,getMockNewURIMaker()); /* test just the N3 substitution part */ Listreq = config.getN3Required(); Listopt = config.getN3Optional(); - processor.subInValuesToN3( config , submission, req, opt, null , null); + processor.subInValuesToN3( config , submission, req, opt, null , null, vreq); assertNotNull(req); assertTrue( req.size() > 0); assertNotNull(req.get(0)); @@ -220,14 +230,16 @@ public void basicNewResourceTest() throws Exception{ values.put("test3", (new String[] {"http://test.com/uri3"})); values.put("editKey", (new String[] {"mockEditKey"})); - MultiValueEditSubmission submission = new MultiValueEditSubmission(values, config); + VitroRequest vreq = createRequestWithParameters(values); + + MultiValueEditSubmission submission = new MultiValueEditSubmission(vreq, config); ProcessRdfForm processor = new ProcessRdfForm(config,getMockNewURIMaker()); /* test just the N3 substitution part */ Listreq = config.getN3Required(); Listopt = config.getN3Optional(); - processor.subInValuesToN3( config , submission, req, opt, null , null); + processor.subInValuesToN3( config , submission, req, opt, null , null, vreq); assertNotNull(req); assertTrue( req.size() > 0); assertNotNull(req.get(0)); @@ -270,14 +282,16 @@ public void forcedNewResourceTest() throws Exception{ values.put("test3", (new String[] {"http://test.com/uri3"})); values.put("editKey", (new String[] {"mockEditKey"})); - MultiValueEditSubmission submission = new MultiValueEditSubmission(values, config); + VitroRequest vreq = createRequestWithParameters(values); + + MultiValueEditSubmission submission = new MultiValueEditSubmission(vreq, config); ProcessRdfForm processor = new ProcessRdfForm(config,getMockNewURIMaker()); /* test just the N3 substitution part */ Listreq = config.getN3Required(); Listopt = config.getN3Optional(); - processor.subInValuesToN3( config , submission, req, opt, null , null); + processor.subInValuesToN3( config , submission, req, opt, null , null, vreq); assertNotNull(req); assertTrue( req.size() > 0); assertNotNull(req.get(0)); @@ -357,10 +371,13 @@ public void basicEditReplaceStatement() throws Exception{ values.put("testZ", (new String[] {testZURIChanged})); values.put("zLabel", (new String[] {"New Z Label"})); values.put("editKey", (new String[] {"mockEditKey"})); - MultiValueEditSubmission submission = new MultiValueEditSubmission(values, config); + + VitroRequest vreq = createRequestWithParameters(values); + + MultiValueEditSubmission submission = new MultiValueEditSubmission(vreq, config); ProcessRdfForm processor = new ProcessRdfForm(config,getMockNewURIMaker()); - AdditionsAndRetractions changes = processor.process( config, submission, null ); + AdditionsAndRetractions changes = processor.process( config, submission, vreq ); assertNotNull( changes ); assertNotNull( changes.getAdditions() ); @@ -396,4 +413,16 @@ public String getUnusedNewURI(String prefixURI) throws InsertException { } }; } + + private VitroRequest createRequestWithParameters(Map parameters) { + HttpServletRequestStub req = new HttpServletRequestStub(); + for (String key : parameters.keySet()) { + for (String value : parameters.get(key)) { + req.addParameter(key, value); + } + } + + return new VitroRequest(req); + } + } diff --git a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/LimitRemovalsToLanguageTest.java b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/LimitRemovalsToLanguageTest.java new file mode 100644 index 0000000000..d1f6b84337 --- /dev/null +++ b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/LimitRemovalsToLanguageTest.java @@ -0,0 +1,62 @@ +package edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.preprocessors; + +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.ModelFactory; +import org.apache.jena.rdf.model.Resource; +import org.apache.jena.rdf.model.ResourceFactory; +import org.apache.jena.vocabulary.RDFS; +import org.junit.Test; +import org.testng.Assert; + +import edu.cornell.mannlib.vitro.testing.AbstractTestClass; + +public class LimitRemovalsToLanguageTest extends AbstractTestClass { + + @Test + /** + * Test that retractions are properly limited to the specified language + */ + public void testPreprocess() { + LimitRemovalsToLanguage preproc = new LimitRemovalsToLanguage("en-US"); + Model additions = ModelFactory.createDefaultModel(); + Model retractions = ModelFactory.createDefaultModel(); + Resource res = ResourceFactory.createResource("http://example.com/i/n1"); + // eliminate Spanish retraction if only English is being edited + retractions.add(res, RDFS.label, ResourceFactory.createLangLiteral("en-US1", "en-US")); + retractions.add(res, RDFS.label, ResourceFactory.createLangLiteral("es1", "es")); + additions.add(res, RDFS.label, ResourceFactory.createLangLiteral("en-US2", "en-US")); + preproc.preprocess(retractions, additions, null); + Assert.assertEquals(retractions.size(), 1); + Assert.assertTrue(retractions.contains(res, RDFS.label, ResourceFactory.createLangLiteral("en-US1", "en-US"))); + Assert.assertEquals(additions.size(), 1); + Assert.assertTrue(additions.contains(res, RDFS.label, ResourceFactory.createLangLiteral("en-US2", "en-US"))); + additions.removeAll(); + retractions.removeAll(); + // Keep all retractions unmolested if no labels at all are being re-added. + // (The form may be trying to delete the entire individual.) + retractions.add(res, RDFS.label, ResourceFactory.createLangLiteral("en-US1", "en-US")); + retractions.add(res, RDFS.label, ResourceFactory.createLangLiteral("es1", "es")); + preproc.preprocess(retractions, additions, null); + Assert.assertEquals(retractions.size(), 2); + Assert.assertTrue(retractions.contains(res, RDFS.label, ResourceFactory.createLangLiteral("en-US1", "en-US"))); + Assert.assertTrue(retractions.contains(res, RDFS.label, ResourceFactory.createLangLiteral("es1", "es"))); + Assert.assertEquals(additions.size(), 0); + additions.removeAll(); + retractions.removeAll(); + // Keep both retractions if the form supplies new values for both languages + retractions.add(res, RDFS.label, ResourceFactory.createLangLiteral("en-US1", "en-US")); + retractions.add(res, RDFS.label, ResourceFactory.createLangLiteral("es1", "es")); + additions.add(res, RDFS.label, ResourceFactory.createLangLiteral("en-US2", "en-US")); + additions.add(res, RDFS.label, ResourceFactory.createLangLiteral("es2", "es")); + preproc.preprocess(retractions, additions, null); + Assert.assertEquals(retractions.size(), 2); + Assert.assertTrue(retractions.contains(res, RDFS.label, ResourceFactory.createLangLiteral("en-US1", "en-US"))); + Assert.assertTrue(retractions.contains(res, RDFS.label, ResourceFactory.createLangLiteral("es1", "es"))); + Assert.assertEquals(additions.size(), 2); + Assert.assertTrue(additions.contains(res, RDFS.label, ResourceFactory.createLangLiteral("en-US2", "en-US"))); + Assert.assertTrue(additions.contains(res, RDFS.label, ResourceFactory.createLangLiteral("es2", "es"))); + additions.removeAll(); + retractions.removeAll(); + } + +} diff --git a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/validators/AntiXssValidationTest.java b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/validators/AntiXssValidationTest.java index e9e2c463d7..3c238facd2 100644 --- a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/validators/AntiXssValidationTest.java +++ b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/validators/AntiXssValidationTest.java @@ -9,10 +9,13 @@ import org.junit.Assert; import org.junit.Test; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.MultiValueEditSubmission; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.fields.FieldVTwo; +import stubs.javax.servlet.http.HttpServletRequestStub; + public class AntiXssValidationTest { @Test @@ -29,8 +32,10 @@ public void testLiteral( ){ String[] vals= { "some sort of string" }; params.put("X", vals); + VitroRequest vreq = createRequestWithParameters(params); + MultiValueEditSubmission mvEditSub = - new MultiValueEditSubmission(params,eConf); + new MultiValueEditSubmission(vreq,eConf); Map res = validator.validate(eConf, mvEditSub); Assert.assertEquals(null, res); @@ -53,8 +58,10 @@ public void testAllURI( ){ String[] strings2 = {"no problem 2"}; params.put("Z", strings2 ); + VitroRequest vreq = createRequestWithParameters(params); + MultiValueEditSubmission mvEditSub = - new MultiValueEditSubmission(params,eConf); + new MultiValueEditSubmission(vreq,eConf); Map res = validator.validate(eConf, mvEditSub); Assert.assertNull( res ); @@ -72,8 +79,10 @@ protected Map testURI( String ... strings){ Map params = new HashMap(); params.put("X", strings ); + VitroRequest vreq = createRequestWithParameters(params); + MultiValueEditSubmission mvEditSub = - new MultiValueEditSubmission(params,eConf); + new MultiValueEditSubmission(vreq,eConf); return validator.validate(eConf, mvEditSub); } @@ -125,5 +134,15 @@ public void testURIValidationWithScriptTagLevel2(){ Assert.assertNotNull(result); } + private VitroRequest createRequestWithParameters(Map parameters) { + HttpServletRequestStub req = new HttpServletRequestStub(); + for (String key : parameters.keySet()) { + for (String value : parameters.get(key)) { + req.addParameter(key, value); + } + } + + return new VitroRequest(req); + } } diff --git a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/LanguageFilteringRDFServiceTest.java b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/LanguageFilteringRDFServiceTest.java index 261718d6d2..a062798f1b 100644 --- a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/LanguageFilteringRDFServiceTest.java +++ b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/LanguageFilteringRDFServiceTest.java @@ -282,12 +282,12 @@ private Object buildRowIndexedLiteral(String language) { private Comparator buildRowIndexedLiteralSortByLang() { try { Class clazz = Class.forName(COLLATOR_CLASSNAME); - Class[] argTypes = { LanguageFilteringRDFService.class }; - Constructor constructor = clazz.getDeclaredConstructor(argTypes); + Class[] argTypes = { LanguageFilteringRDFService.class, List.class }; + Constructor constructor = clazz.getDeclaredConstructor(argTypes); constructor.setAccessible(true); - return (Comparator) constructor - .newInstance(filteringRDFService); + .newInstance(filteringRDFService, new AcceptableLanguages( + preferredLanguages)); } catch (Exception e) { throw new RuntimeException("Could not create a collator", e); } diff --git a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/searchindex/documentBuilding/ThumbnailImageURLTest.java b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/searchindex/documentBuilding/ThumbnailImageURLTest.java index cd33c59f6b..9f304f9986 100644 --- a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/searchindex/documentBuilding/ThumbnailImageURLTest.java +++ b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/searchindex/documentBuilding/ThumbnailImageURLTest.java @@ -37,7 +37,7 @@ public class ThumbnailImageURLTest extends AbstractTestClass{ * @throws java.lang.Exception */ @Before - public void setUp() throws Exception { + public void setUp() { setLoggerLevel(RDFDefaultErrorHandler.class, Level.OFF); ApplicationStub.setup(new ServletContextStub(), new SearchEngineStub()); diff --git a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/DataGetterUtilsTest.java b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/DataGetterUtilsTest.java index 5906724f6c..4dd63f99d0 100644 --- a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/DataGetterUtilsTest.java +++ b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/DataGetterUtilsTest.java @@ -32,7 +32,7 @@ public class DataGetterUtilsTest extends AbstractTestClass{ String dataGetterX = "http://vitro.mannlib.cornell.edu/ontologies/display/1.1#pageDataGetterX"; @Before - public void setUp() throws Exception { + public void setUp() { // Suppress error logging. setLoggerLevel(RDFDefaultErrorHandler.class, Level.OFF); diff --git a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/SparqlQueryDataGetterTest.java b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/SparqlQueryDataGetterTest.java index 8cb9279ef5..a02516e1d4 100644 --- a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/SparqlQueryDataGetterTest.java +++ b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/SparqlQueryDataGetterTest.java @@ -36,7 +36,7 @@ public class SparqlQueryDataGetterTest extends AbstractTestClass{ VitroRequest vreq; @Before - public void setUp() throws Exception { + public void setUp() { // Suppress error logging. setLoggerLevel(RDFDefaultErrorHandler.class, Level.OFF); diff --git a/api/src/test/java/stubs/edu/cornell/mannlib/vitro/webapp/dao/WebappDaoFactoryStub.java b/api/src/test/java/stubs/edu/cornell/mannlib/vitro/webapp/dao/WebappDaoFactoryStub.java index 24efa68858..732ae32091 100644 --- a/api/src/test/java/stubs/edu/cornell/mannlib/vitro/webapp/dao/WebappDaoFactoryStub.java +++ b/api/src/test/java/stubs/edu/cornell/mannlib/vitro/webapp/dao/WebappDaoFactoryStub.java @@ -23,6 +23,7 @@ import edu.cornell.mannlib.vitro.webapp.dao.VClassDao; import edu.cornell.mannlib.vitro.webapp.dao.VClassGroupDao; import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; +import edu.cornell.mannlib.vitro.webapp.i18n.I18nBundle; /** * A minimal implementation of the WebappDaoFactory. @@ -267,4 +268,9 @@ public void close() { throw new RuntimeException("WebappDaoFactory.close() not implemented."); } + @Override + public I18nBundle getI18nBundle() { + throw new RuntimeException("WebappDaoFactory.getI18nBundle() not implemented."); + } + } diff --git a/api/src/test/java/stubs/edu/cornell/mannlib/vitro/webapp/i18n/I18nStub.java b/api/src/test/java/stubs/edu/cornell/mannlib/vitro/webapp/i18n/I18nStub.java index 76d3a37275..372eedc695 100644 --- a/api/src/test/java/stubs/edu/cornell/mannlib/vitro/webapp/i18n/I18nStub.java +++ b/api/src/test/java/stubs/edu/cornell/mannlib/vitro/webapp/i18n/I18nStub.java @@ -14,6 +14,7 @@ import edu.cornell.mannlib.vitro.webapp.i18n.I18n; import edu.cornell.mannlib.vitro.webapp.i18n.I18nBundle; +import stubs.javax.servlet.ServletContextStub; /** * An implementation of I18n for unit tests. Construct a new instance and it @@ -45,6 +46,7 @@ public static void setup() { /** Make it private, so they will use the setup() method. */ private I18nStub() { + super(new ServletContextStub()); // Nothing to initialize. } diff --git a/api/src/test/java/stubs/javax/servlet/http/HttpServletRequestStub.java b/api/src/test/java/stubs/javax/servlet/http/HttpServletRequestStub.java index 27bb5e69fa..35b8da99c4 100644 --- a/api/src/test/java/stubs/javax/servlet/http/HttpServletRequestStub.java +++ b/api/src/test/java/stubs/javax/servlet/http/HttpServletRequestStub.java @@ -510,8 +510,7 @@ public DispatcherType getDispatcherType() { @Override public Locale getLocale() { - throw new RuntimeException( - "HttpServletRequestStub.getLocale() not implemented."); + return Locale.ENGLISH; } @Override diff --git a/home/src/main/resources/config/default.runtime.properties b/home/src/main/resources/config/default.runtime.properties index 6cde4b25eb..4d046873e8 100644 --- a/home/src/main/resources/config/default.runtime.properties +++ b/home/src/main/resources/config/default.runtime.properties @@ -124,9 +124,9 @@ proxy.eligibleTypeList = http://www.w3.org/2002/07/owl#Thing # # A list of supported languages or Locales that the user may choose to -# use instead of the one specified by the browser. Selection images must -# be available in the i18n/images directory of the theme. This affects -# RDF data retrieved from the model, if RDFService.languageFilter is true. +# use instead of the one specified by the browser. The selected language(s) +# must exist in the Vitro-languages repository. This affects RDF data +# retrieved from the model, if RDFService.languageFilter is true. # This also affects the text of pages that have been modified to support # multiple languages. # diff --git a/installer/pom.xml b/installer/pom.xml index 0323adcf4b..a79aaa4c97 100644 --- a/installer/pom.xml +++ b/installer/pom.xml @@ -10,6 +10,13 @@ 1.11.2-SNAPSHOT pom + + org.vivoweb + vitro-project + 1.11.2-SNAPSHOT + .. + + Vitro Installer diff --git a/installer/webapp/pom.xml b/installer/webapp/pom.xml index a17179d147..4be7c1604f 100644 --- a/installer/webapp/pom.xml +++ b/installer/webapp/pom.xml @@ -45,11 +45,11 @@ war - + @@ -148,12 +148,12 @@ war - + javax.servlet diff --git a/webapp/src/main/webapp/css/vitro.css b/webapp/src/main/webapp/css/vitro.css index 8bafa59223..f784acd7fe 100644 --- a/webapp/src/main/webapp/css/vitro.css +++ b/webapp/src/main/webapp/css/vitro.css @@ -252,10 +252,11 @@ ul.dropdown li:hover > ul { /* -------------------------------------------------> */ ul.language-dropdown { position: relative; + min-width: 160px; } ul.language-dropdown li#language-menu { background: url(../images/arrowDownOverAccount.gif) right 9px no-repeat; - min-width:110px; + min-width: 170px; position: relative; margin-right: -10px !important; } diff --git a/webapp/src/main/webapp/i18n/all.properties b/webapp/src/main/webapp/i18n/all.properties deleted file mode 100644 index 1909545ade..0000000000 --- a/webapp/src/main/webapp/i18n/all.properties +++ /dev/null @@ -1,928 +0,0 @@ -# -# Text strings for the controllers and templates -# -# Default (English) -# -save_changes=Save changes -save_entry=Save entry -select_existing=Select existing -select_an_existing=Select an existing -add_an_entry_to=Add an entry of type -change_entry_for=Change entry for: -add_new_entry_for=Add new entry for: -change_text_for=Change text for: -cancel_link = Cancel -cancel_title = cancel -required_fields = required fields -or = or -alt_error_alert = Error alert icon -alt_confirmation = Confirmation icon -for=for -email_address = Email address -first_name = First name -last_name = Last name -roles = Roles -status = Status - -ascending_order = ascending order -descending_order = descending order -select_one = Select one - -type_more_characters = type more characters -no_match = no match - -request_failed = Request failed. Please contact your system administrator. - -# -# Image upload pages -# -upload_page_title = Upload image -upload_page_title_with_name = Upload image for {0} -upload_heading = Photo Upload - -replace_page_title = Replace image -replace_page_title_with_name = Replace image for {0} - -crop_page_title = Crop image -crop_page_title_with_name = Crop image for {0} - -current_photo = Current Photo -upload_photo = Upload a photo -replace_photo = Replace Photo -photo_types = (JPEG, GIF or PNG) -maximum_file_size = Maximum file size: {0} megabytes -minimum_image_dimensions = Minimum image dimensions: {0} x {1} pixels - -cropping_caption = Your profile photo will look like the image below. -cropping_note = To make adjustments, you can drag around and resize the photo to the right. \ -When you are happy with your photo click the "Save Photo" button. - -alt_thumbnail_photo = Individual photo -alt_image_to_crop = Image to be cropped -alt_preview_crop = Preview of photo cropped - -delete_link = Delete photo -submit_upload = Upload photo -submit_save = Save photo - -confirm_delete = Are you sure you want to delete this photo? - -imageUpload.errorNoURI = No entity URI was provided -imageUpload.errorUnrecognizedURI = This URI is not recognized as belonging to anyone: ''{0}'' -imageUpload.errorNoImageForCropping = There is no image file to be cropped. -imageUpload.errorImageTooSmall = The uploaded image should be at least {0} pixels high and {1} pixels wide. -imageUpload.errorUnknown = Sorry, we were unable to process the photo you provided. Please try another photo. -imageUpload.errorFileTooBig = Please upload an image smaller than {0} megabytes. -imageUpload.errorUnrecognizedFileType = ''{0}'' is not a recognized image file type. Please upload JPEG, GIF, or PNG files only. -imageUpload.errorNoPhotoSelected = Please browse and select a photo. -imageUpload.errorBadMultipartRequest = Failed to parse the multi-part request for uploading an image. -imageUpload.errorFormFieldMissing = The form did not contain a ''{0}'' field." - -# -# User Accounts pages -# -account_management = Account Management -user_accounts_link = User accounts -user_accounts_title = user accounts - -login_count = Login count -last_login = Last Login - -add_new_account = Add new account -edit_account = Edit account -external_auth_only = Externally Authenticated Only -reset_password = Reset password -reset_password_note = Note: Instructions for resetting the password will \ -be emailed to the address entered above. The password will not \ -be reset until the user follows the link provided in this email. -new_password = New password -confirm_password = Confirm new password -minimum_password_length = Minimum of {0} characters in length; maximum of {1}. -leave_password_unchanged = Leaving this blank means that the password will not be changed. -confirm_initial_password = Confirm initial password - -new_account_1 = A new account for -new_account_2 = was successfully created. -new_account_title = new account -new_account_notification = A notification email has been sent to {0} \ -with instructions for activating the account and creating a password. -updated_account_1 = The account for -updated_account_2 = has been updated. -updated_account_title = updated account -updated_account_notification = A confirmation email has been sent to {0} \ -with instructions for resetting a password. \ -The password will not be reset until the user follows the link provided in this email. -deleted_accounts = Deleted {0} {0, choice, 0#accounts|1#account|1