diff --git a/doc/install.html b/doc/install.html index c409b190c..cd048e367 100644 --- a/doc/install.html +++ b/doc/install.html @@ -67,7 +67,7 @@

Vitro inside Tomcat

When you run the build script to compile and deploy Vitro - (see installation step VI, below), + (see installation step V, below), the files will be deployed to a directory inside Tomcat. This is the actual executing code for Vitro, but you won’t need to look at it or change it. If you need to change @@ -86,7 +86,7 @@ build.properties file (see installation step IV, below). You must create this directory before starting Vitro, you must create the runtime.properties file in this directory - (see Step V, below), and you + (see Step VI, below), and you must ensure that Tomcat has permission to read and write to this directory when it runs.

@@ -186,10 +186,10 @@ Specify build properties
  • - Specify runtime properties + Compile and deploy
  • - Compile and deploy + Specify runtime properties
  • Configure Tomcat @@ -226,20 +226,19 @@

    @@ -320,8 +319,8 @@

    These properties are used in compilation and deployment. They will be incorporated into Vitro when it is compiled in - Step VI. If you want to change these properties at - a later date, you will need to stop Tomcat, repeat Step VI, + Step V. If you want to change these properties at + a later date, you will need to stop Tomcat, repeat Step V, and restart Tomcat.

    @@ -394,22 +393,64 @@ -

    V. Specify runtime properties

    +

    V. Compile and deploy

    - In Step IV, you defined the location of the Vitro home directory, + In Step IV, you defined the location of the VIVO home directory, by specifying vitro.home in the build.properties file. Create that directory now.

    - In the webapp/config subdirectory of the Vitro distribution, you will find a file called - example.runtime.properties. Copy this to the Vitro home directory you have created, - renaming the copy to runtime.properties. - Edit the file to suit your installation, as described in the following table. + At the command line, change to the webapp directory inside the Vitro distribution + directory. Then type: +

    +
        ant all
    +

    + to build Vitro and deploy to Tomcat's webapps directory. +

    +

    + The build script may run for as much as five minutes, + and creates more than 100 lines of output. + The process comprises several steps: +

    +

    +

    + The output of the build may include a variety of warning messages. + The Java compiler may warn of code that is outdated. + Unit tests may produce warning messages, + and some tests may be ignored if they do not produce consistent results. +

    +
    + BUILD SUCCESSFUL
    Total time: 1 minute 49 seconds +
    +

    + If the output ends with a success message, the build was successful. + Proceed to the next step. +

    +
    + BUILD FAILED
    Total time: 35 seconds +
    +

    + If the output ends with a failure message, the build has failed. + Find the cause of the failure, fix the problem, and run the script again. +

    + +

    VI. Specify runtime properties

    +

    + The build process in Step V created a file called example.runtime.properties + in your Vitro home directory (vitro.home in the build.properties file). + Rename this file to runtime.properties, and + edit the file to suit your installation, as described in the following table.

    These properties are loaded when Vitro starts up. If you want to change these properties at a later date, you will need to restart Tomcat for them to take - effect. You will not need to repeat Step VI. + effect. You will not need to repeat Step V.

    Windows: @@ -800,47 +841,6 @@ -

    VI. Compile and deploy

    -

    - At the command line, change to the webapp directory inside the Vitro distribution - directory. Then type: -

    -
        ant all
    -

    - to build Vitro and deploy to Tomcat's webapps directory. -

    -

    - The build script may run for as much as five minutes, - and creates more than 100 lines of output. - The process comprises several steps: -

    -

    -

    - The output of the build may include a variety of warning messages. - The Java compiler may warn of code that is outdated. - Unit tests may produce warning messages, - and some tests may be ignored if they do not produce consistent results. -

    -
    - BUILD SUCCESSFUL
    Total time: 1 minute 49 seconds -
    -

    - If the output ends with a success message, the build was successful. - Proceed to the next step. -

    -
    - BUILD FAILED
    Total time: 35 seconds -
    -

    - If the output ends with a failure message, the build has failed. - Find the cause of the failure, fix the problem, and run the script again. -

    VII. Configure Tomcat

    Set JVM parameters

    @@ -921,8 +921,8 @@ problem is detected, the normal Vitro pages will redirect to a startup status page describing the problem. You can stop tomcat, attempt to fix the problem and - proceeded from Step VI. The - startup status page may offer a continue link which + proceed from Step V. If the problem is not serious, the + startup status page may offer a continue link which will allow you to use VIVO in spite of the problems.

    diff --git a/webapp/build.xml b/webapp/build.xml index 6b60d1fe4..00f61f423 100644 --- a/webapp/build.xml +++ b/webapp/build.xml @@ -102,6 +102,24 @@ + + + + + + + Tomcat home directory '${tomcat.home}' does not exist. + Check the value of 'tomcat.home' in your build.properties file. + + + + + + + + '${tomcat.home}' does not refer to a valid Tomcat instance: it has no 'webapps' sub-directory. + Check the value of 'tomcat.home' in your build.properties file." + diff --git a/webapp/languages/example/i18n/all_es.properties b/webapp/languages/example/i18n/all_es.properties index e556063d6..49e8eb110 100644 --- a/webapp/languages/example/i18n/all_es.properties +++ b/webapp/languages/example/i18n/all_es.properties @@ -126,10 +126,6 @@ submit_add_new_account = Añadir nueva cuenta account_created = Su {0} cuenta ha sido creada. account_created_subject = Su {0} cuenta ha sido creada. -account_created_email_html = @@file files/accountCreatedEmail.html -account_created_email_text = @@file files/accountCreatedEmail.txt -account_created_external_email_html = @@file files/accountCreatedExternalOnlyEmail.html -account_created_external_email_text = @@file files/accountCreatedExternalOnlyEmail.txt confirm_delete_account_singular = ¿Está seguro de que desea eliminar esta cuenta? confirm_delete_account_plural = ¿Está seguro de que desea eliminar estas cuentas? @@ -148,21 +144,11 @@ select_associated_profile = Seleccione el perfil asociado create_associated_profile = Cree el perfil asociado email_changed_subject = Su {0} cuenta de correo electrónico ha cambiado. -email_changed_html = @@file files/accountEmailChanged.html -email_changed_text = @@file files/accountEmailChanged.txt create_your_password = Crea tu Contraseña password_created_subject = Su {0} contraseña ha sido creado con éxito. -password_created_email_html = @@file files/passwordCreatedEmail.html -password_created_email_text = @@file files/passwordCreatedEmail.txt - password_reset_pending_subject = {0} restablecer solicitud de contraseña -password_reset_pending_email_html = @@file files/passwordResetPending.html -password_reset_pending_email_text = @@file files/passwordResetPending.txt - password_reset_complete_subject = Su {0} ha cambiado la contraseña. -password_reset_complete_email_html = @@file files/passwordResetComplete.html -password_reset_complete_email_text = @@file files/passwordResetComplete.txt reset_your_password = Renovar su contraseña first_time_login = Log Por primera vez en @@ -181,8 +167,6 @@ password_saved_please_login = Su contraseña ha sido guardada. Por favor, ingres please_provide_contact_information = Por favor proporcione su información de contacto para terminar de crear la cuenta. first_time_login_note = Nota: Un correo electrónico será enviado a la dirección indicada anteriormente notificar que una cuenta ha sido creada. -first_time_external_email_html = @@file files/accountFirstTimeExternal.html -first_time_external_email_text = @@file files/accountFirstTimeExternal.txt myAccount_heading = Mi cuenta myAccount_confirm_changes = Los cambios se han guardado. diff --git a/webapp/languages/example/templates/freemarker/userAccounts-acctCreatedEmail.ftl b/webapp/languages/example/templates/freemarker/userAccounts-acctCreatedEmail.ftl new file mode 100644 index 000000000..e5ab4bc0b --- /dev/null +++ b/webapp/languages/example/templates/freemarker/userAccounts-acctCreatedEmail.ftl @@ -0,0 +1,68 @@ +<#-- $This file is distributed under the terms of the license in /doc/license.txt$ --> + +<#-- Confirmation that an account has been created. --> + +<#assign subject = "Su cuenta ${siteName} ha sido creado." /> + +<#assign html> + + + ${subject} + + +

    + ${userAccount.firstName} ${userAccount.lastName} +

    + +

    + Enhorabuena! +

    + +

    + Hemos creado la nueva cuenta en ${siteName}, asociada con ${userAccount.emailAddress}. +

    + +

    + Si no has solicitado esta nueva cuenta puede ignorar este mensaje. + Esta solicitud caducará si no se hubiere pronunciado sobre durante 30 días. +

    + +

    + Haga clic en el enlace de abajo para crear la contraseña de su cuenta usando nuestro servidor seguro. +

    + +

    + ${passwordLink} +

    + +

    + Si el enlace no funciona, puedes copiar y pegar el enlace directamente en la barra de direcciones de su navegador. +

    + +

    + ¡Gracias! +

    + + + + +<#assign text> +${userAccount.firstName} ${userAccount.lastName} + +Enhorabuena! + +Hemos creado la nueva cuenta en ${siteName}, +asociada con ${userAccount.emailAddress}. + +Si no has solicitado esta nueva cuenta puede ignorar este mensaje. +Esta solicitud caducará si no se hubiere pronunciado sobre durante 30 días. + +Pega el siguiente enlace en la barra de direcciones de su navegador para +crear su contraseña para su nueva cuenta usando nuestro servidor seguro. + +${passwordLink} + +¡Gracias! + + +<@email subject=subject html=html text=text /> diff --git a/webapp/languages/example/templates/freemarker/userAccounts-acctCreatedExternalOnlyEmail.ftl b/webapp/languages/example/templates/freemarker/userAccounts-acctCreatedExternalOnlyEmail.ftl new file mode 100644 index 000000000..0b91545fe --- /dev/null +++ b/webapp/languages/example/templates/freemarker/userAccounts-acctCreatedExternalOnlyEmail.ftl @@ -0,0 +1,43 @@ +<#-- $This file is distributed under the terms of the license in /doc/license.txt$ --> + +<#-- Confirmation that an account has been created. --> + +<#assign subject = "Su cuenta ${siteName} ha sido creada." /> + +<#assign html> + + + ${subject} + + +

    + ${userAccount.firstName} ${userAccount.lastName} +

    + +

    + ¡Enhorabuena! +

    + +

    + Hemos creado la nueva cuenta VIVO asociado con ${userAccount.emailAddress}. +

    + +

    + ¡Gracias! +

    + + + + +<#assign text> +${userAccount.firstName} ${userAccount.lastName} + +¡Enhorabuena! + +Hemos creado la nueva cuenta VIVO asociado con +${userAccount.emailAddress}. + +¡Gracias! + + +<@email subject=subject html=html text=text /> diff --git a/webapp/languages/example/templates/freemarker/userAccounts-confirmEmailChangedEmail.ftl b/webapp/languages/example/templates/freemarker/userAccounts-confirmEmailChangedEmail.ftl new file mode 100644 index 000000000..a3674c8cf --- /dev/null +++ b/webapp/languages/example/templates/freemarker/userAccounts-confirmEmailChangedEmail.ftl @@ -0,0 +1,38 @@ +<#-- $This file is distributed under the terms of the license in /doc/license.txt$ --> + +<#-- Confirmation that the user has changed his email account. --> + +<#assign subject = "Su cuenta de correo electrónico ${siteName} ha cambiado." /> + +<#assign html> + + + ${subject} + + +

    + Hola, ${userAccount.firstName} ${userAccount.lastName} +

    + +

    + Ha cambiado recientemente la dirección de correo electrónico asociada a + ${userAccount.firstName} ${userAccount.lastName} +

    + +

    + Gracias. +

    + + + + +<#assign text> +Hola, ${userAccount.firstName} ${userAccount.lastName} + +Ha cambiado recientemente la dirección de correo electrónico asociada a +${userAccount.firstName} ${userAccount.lastName} + +Gracias. + + +<@email subject=subject html=html text=text /> diff --git a/webapp/languages/example/templates/freemarker/userAccounts-firstTimeExternalEmail.ftl b/webapp/languages/example/templates/freemarker/userAccounts-firstTimeExternalEmail.ftl new file mode 100644 index 000000000..5c6558a52 --- /dev/null +++ b/webapp/languages/example/templates/freemarker/userAccounts-firstTimeExternalEmail.ftl @@ -0,0 +1,43 @@ +<#-- $This file is distributed under the terms of the license in /doc/license.txt$ --> + +<#-- Confirmation that an account has been created for an externally-authenticated user. --> + +<#assign subject = "Su cuenta ${siteName} ha sido creada." /> + +<#assign html> + + + ${subject} + + +

    + ${userAccount.firstName} ${userAccount.lastName} +

    + +

    + ¡Enhorabuena! +

    + +

    + Hemos creado la nueva cuenta VIVO asociado con ${userAccount.emailAddress}. +

    + +

    + ¡Gracias! +

    + + + + +<#assign text> +${userAccount.firstName} ${userAccount.lastName} + +¡Enhorabuena! + +Hemos creado la nueva cuenta VIVO asociado con +${userAccount.emailAddress}. + +¡Gracias! + + +<@email subject=subject html=html text=text /> diff --git a/webapp/languages/example/templates/freemarker/userAccounts-passwordCreatedEmail.ftl b/webapp/languages/example/templates/freemarker/userAccounts-passwordCreatedEmail.ftl new file mode 100644 index 000000000..f3e272055 --- /dev/null +++ b/webapp/languages/example/templates/freemarker/userAccounts-passwordCreatedEmail.ftl @@ -0,0 +1,43 @@ +<#-- $This file is distributed under the terms of the license in /doc/license.txt$ --> + +<#-- Confirmation that an password has been created. --> + +<#assign subject = "El ${siteName} contraseña ha sido creado con éxito." /> + +<#assign html> + + + ${subject} + + +

    + ${userAccount.firstName} ${userAccount.lastName} +

    + +

    + Contraseña creado con éxito. +

    + +

    + Su nueva contraseña asociada con ${userAccount.emailAddress} se ha creado. +

    + +

    + Gracias. +

    + + + + +<#assign text> +${userAccount.firstName} ${userAccount.lastName} + +Contraseña creado con éxito. + +Su nueva contraseña asociada con ${userAccount.emailAddress} +se ha creado. + +Gracias. + + +<@email subject=subject html=html text=text /> diff --git a/webapp/languages/example/templates/freemarker/userAccounts-passwordResetCompleteEmail.ftl b/webapp/languages/example/templates/freemarker/userAccounts-passwordResetCompleteEmail.ftl new file mode 100644 index 000000000..64ca61dae --- /dev/null +++ b/webapp/languages/example/templates/freemarker/userAccounts-passwordResetCompleteEmail.ftl @@ -0,0 +1,44 @@ +<#-- $This file is distributed under the terms of the license in /doc/license.txt$ --> + +<#-- Confirmation that a password has been reset. --> + +<#assign subject = "El ${siteName} contraseña cambiada." /> + +<#assign html> + + + ${subject} + + + +

    + ${userAccount.firstName} ${userAccount.lastName} +

    + +

    + Contraseña cambiada con éxito. +

    + +

    + Su nueva contraseña asociada con ${userAccount.emailAddress} ha sido cambiado. +

    + +

    + Gracias. +

    + + + + +<#assign text> +${userAccount.firstName} ${userAccount.lastName} + +Contraseña cambiada con éxito. + +Su nueva contraseña asociada con ${userAccount.emailAddress} +ha sido cambiado. + +Gracias. + + +<@email subject=subject html=html text=text /> diff --git a/webapp/languages/example/templates/freemarker/userAccounts-passwordResetPendingEmail.ftl b/webapp/languages/example/templates/freemarker/userAccounts-passwordResetPendingEmail.ftl new file mode 100644 index 000000000..2f0bccc98 --- /dev/null +++ b/webapp/languages/example/templates/freemarker/userAccounts-passwordResetPendingEmail.ftl @@ -0,0 +1,62 @@ +<#-- $This file is distributed under the terms of the license in /doc/license.txt$ --> + +<#-- Confirmation email for user account password reset --> + +<#assign subject = "${siteName} restablecer solicitud de contraseña" /> + +<#assign html> + + + ${subject} + + +

    + Estimado ${userAccount.firstName} ${userAccount.lastName}: +

    + +

    + Hemos recibido una solicitud para restablecer la contraseña de su cuenta ${siteName} + (${userAccount.emailAddress}). +

    + +

    + Por favor, siga las siguientes instrucciones para proceder con su restablecimiento de contraseña. +

    + +

    + Si no has solicitado esta nueva cuenta puede ignorar este mensaje. + Esta solicitud caducará si no se hubiere pronunciado en un plazo de 30 días. +

    + +

    + Haga clic en el enlace de abajo o pegarlo en la barra de direcciones de su navegador para + restablecer su contraseña usando nuestro servidor seguro. +

    + +

    ${passwordLink}

    + +

    ¡Gracias!

    + + + + +<#assign text> +Estimado ${userAccount.firstName} ${userAccount.lastName}: + +Hemos recibido una solicitud para restablecer la contraseña de su cuenta ${siteName} +(${userAccount.emailAddress}). + +Por favor, siga las siguientes instrucciones para proceder con su restablecimiento de contraseña. + +Si no has solicitado esta nueva cuenta puede ignorar este mensaje. +Esta solicitud caducará si no se hubiere pronunciado en un plazo de 30 días. + +Pega el siguiente enlace en la barra de direcciones de su navegador para +restablecer su contraseña usando nuestro servidor seguro. + +${passwordLink} + +¡Gracias! + + +<@email subject=subject html=html text=text /> diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/PolicyHelper.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/PolicyHelper.java index 11c351044..d8a606efb 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/PolicyHelper.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/PolicyHelper.java @@ -11,7 +11,6 @@ import com.hp.hpl.jena.ontology.OntModel; import com.hp.hpl.jena.ontology.OntModelSpec; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.ModelFactory; -import com.hp.hpl.jena.rdf.model.Property; import com.hp.hpl.jena.rdf.model.RDFNode; import com.hp.hpl.jena.rdf.model.Resource; import com.hp.hpl.jena.rdf.model.Statement; @@ -20,7 +19,6 @@ import com.hp.hpl.jena.rdf.model.StmtIterator; import edu.cornell.mannlib.vitro.webapp.auth.identifier.ActiveIdentifierBundleFactories; import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle; import edu.cornell.mannlib.vitro.webapp.auth.identifier.RequestIdentifiers; -import edu.cornell.mannlib.vitro.webapp.auth.permissions.SimplePermission; import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyIface; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.Actions; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestedAction; @@ -136,7 +134,8 @@ public class PolicyHelper { .asResource().getURI()); } else { action = new AddDataPropertyStatement(modelToBeModified, - subject.getURI(), predicate.getURI()); + subject.getURI(), predicate.getURI(), objectNode + .asLiteral().getString()); } return isAuthorizedForActions(req, action); } @@ -169,7 +168,8 @@ public class PolicyHelper { .asResource().getURI()); } else { action = new DropDataPropertyStatement(modelToBeModified, - subject.getURI(), predicate.getURI()); + subject.getURI(), predicate.getURI(), objectNode + .asLiteral().getString()); } return isAuthorizedForActions(req, action); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/propstmt/AbstractDataPropertyStatementAction.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/propstmt/AbstractDataPropertyStatementAction.java index bfcf98c2a..8e49ec193 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/propstmt/AbstractDataPropertyStatementAction.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/propstmt/AbstractDataPropertyStatementAction.java @@ -16,15 +16,17 @@ public abstract class AbstractDataPropertyStatementAction extends private final String subjectUri; private final String predicateUri; private final Property predicate; + private final String dataValue; public AbstractDataPropertyStatementAction(OntModel ontModel, - String subjectUri, String predicateUri) { + String subjectUri, String predicateUri, String dataValue) { super(ontModel); this.subjectUri = subjectUri; this.predicateUri = predicateUri; Property dataProperty = new Property(); dataProperty.setURI(predicateUri); this.predicate = dataProperty; + this.dataValue = dataValue; } public AbstractDataPropertyStatementAction(OntModel ontModel, @@ -36,12 +38,14 @@ public abstract class AbstractDataPropertyStatementAction extends Property dataProperty = new Property(); dataProperty.setURI(predicateUri); this.predicate = dataProperty; + this.dataValue = dps.getData(); } public String getSubjectUri() { return subjectUri; } + @Override public Property getPredicate() { return predicate; } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/propstmt/AddDataPropertyStatement.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/propstmt/AddDataPropertyStatement.java index 5f550d058..39c1e20ab 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/propstmt/AddDataPropertyStatement.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/propstmt/AddDataPropertyStatement.java @@ -13,8 +13,8 @@ public class AddDataPropertyStatement extends AbstractDataPropertyStatementAction { public AddDataPropertyStatement(OntModel ontModel, String subjectUri, - String predicateUri) { - super(ontModel, subjectUri, predicateUri); + String predicateUri, String dataValue) { + super(ontModel, subjectUri, predicateUri, dataValue); } public AddDataPropertyStatement(OntModel ontModel, DataPropertyStatement dps) { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/propstmt/DropDataPropertyStatement.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/propstmt/DropDataPropertyStatement.java index 07138aa8f..b1f84cb2a 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/propstmt/DropDataPropertyStatement.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/propstmt/DropDataPropertyStatement.java @@ -14,8 +14,8 @@ public class DropDataPropertyStatement extends AbstractDataPropertyStatementAction { public DropDataPropertyStatement(OntModel ontModel, String subjectUri, - String predicateUri) { - super(ontModel, subjectUri, predicateUri); + String predicateUri, String dataValue) { + super(ontModel, subjectUri, predicateUri, dataValue); } public DropDataPropertyStatement(OntModel ontModel, diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/propstmt/EditDataPropertyStatement.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/propstmt/EditDataPropertyStatement.java index 5ef3b918f..8243a2031 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/propstmt/EditDataPropertyStatement.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/propstmt/EditDataPropertyStatement.java @@ -12,8 +12,8 @@ import edu.cornell.mannlib.vitro.webapp.beans.DataPropertyStatement; public class EditDataPropertyStatement extends AbstractDataPropertyStatementAction { public EditDataPropertyStatement(OntModel ontModel, String subjectUri, - String predicateUri) { - super(ontModel, subjectUri, predicateUri); + String predicateUri, String dataValue) { + super(ontModel, subjectUri, predicateUri, dataValue); } public EditDataPropertyStatement(OntModel ontModel, diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/beans/Individual.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/beans/Individual.java index e9892ba4b..0f19cc9c7 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/beans/Individual.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/beans/Individual.java @@ -34,6 +34,13 @@ public interface Individual extends ResourceBean, Comparable { List getObjectPropertyList(); void setPropertyList(List propertyList); + /** + * Returns a list of ObjectProperty objects for which statements exist about + * the individual. Note that this method now returns multiple copies of + * a given predicate, with the rangeVClassURI changed to indicate the distinct + * types of the related objects. This supports finding the approriate list + * views for the "faux" qualified properties. + */ List getPopulatedObjectPropertyList(); void setPopulatedObjectPropertyList(List propertyList); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/beans/ObjectProperty.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/beans/ObjectProperty.java index 1c4e8a9b1..7d1d908fb 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/beans/ObjectProperty.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/beans/ObjectProperty.java @@ -22,7 +22,7 @@ import com.hp.hpl.jena.datatypes.xsd.XSDDatatype; * a class representing an object property * */ -public class ObjectProperty extends Property implements Comparable, ResourceBean +public class ObjectProperty extends Property implements Comparable, ResourceBean, Cloneable { private static final Log log = LogFactory.getLog(ObjectProperty.class.getName()); @@ -610,6 +610,55 @@ public class ObjectProperty extends Property implements Comparable map = getResultsForVClass( + IndividualListResults vcResults = getResultsForVClass( vclass.getURI(), page, alpha, vreq.getWebappDaoFactory().getIndividualDao(), getServletContext()); - body.putAll(map); + body.putAll(vcResults.asFreemarkerMap()); - @SuppressWarnings("unchecked") - List inds = (List)map.get("entities"); + List inds = vcResults.getEntities(); List indsTm = new ArrayList(); if (inds != null) { for ( Individual ind : inds ) { @@ -154,13 +149,12 @@ public class IndividualListController extends FreemarkerHttpServlet { return SolrQueryUtils.getPageParameter(request); } - public static Map getResultsForVClass(String vclassURI, int page, String alpha, IndividualDao indDao, ServletContext context) + public static IndividualListResults getResultsForVClass(String vclassURI, int page, String alpha, IndividualDao indDao, ServletContext context) throws SearchException{ - Map rvMap = new HashMap(); try{ List classUris = Collections.singletonList(vclassURI); IndividualListQueryResults results = SolrQueryUtils.buildAndExecuteVClassQuery(classUris, alpha, page, INDIVIDUALS_PER_PAGE, context, indDao); - rvMap = getResultsForVClassQuery(results, page, INDIVIDUALS_PER_PAGE, alpha); + return getResultsForVClassQuery(results, page, INDIVIDUALS_PER_PAGE, alpha); } catch (SolrServerException e) { String msg = "An error occurred retrieving results for vclass query"; log.error(msg, e); @@ -168,31 +162,29 @@ public class IndividualListController extends FreemarkerHttpServlet { throw new SearchException(msg); } catch(Throwable th) { log.error("An error occurred retrieving results for vclass query", th); + return IndividualListResults.EMPTY; } - return rvMap; } - public static Map getResultsForVClassIntersections(List vclassURIs, int page, int pageSize, String alpha, IndividualDao indDao, ServletContext context) { - Map rvMap = new HashMap(); + public static IndividualListResults getResultsForVClassIntersections(List vclassURIs, int page, int pageSize, String alpha, IndividualDao indDao, ServletContext context) { try{ IndividualListQueryResults results = SolrQueryUtils.buildAndExecuteVClassQuery(vclassURIs, alpha, page, pageSize, context, indDao); - rvMap = getResultsForVClassQuery(results, page, pageSize, alpha); + return getResultsForVClassQuery(results, page, pageSize, alpha); } catch(Throwable th) { log.error("Error retrieving individuals corresponding to intersection multiple classes." + vclassURIs.toString(), th); + return IndividualListResults.EMPTY; } - return rvMap; } - public static Map getRandomResultsForVClass(String vclassURI, int page, int pageSize, IndividualDao indDao, ServletContext context) { - Map rvMap = new HashMap(); + public static IndividualListResults getRandomResultsForVClass(String vclassURI, int page, int pageSize, IndividualDao indDao, ServletContext context) { try{ List classUris = Collections.singletonList(vclassURI); IndividualListQueryResults results = SolrQueryUtils.buildAndExecuteRandomVClassQuery(classUris, page, pageSize, context, indDao); - rvMap = getResultsForVClassQuery(results, page, pageSize, ""); + return getResultsForVClassQuery(results, page, pageSize, ""); } catch(Throwable th) { log.error("An error occurred retrieving random results for vclass query", th); + return IndividualListResults.EMPTY; } - return rvMap; } //TODO: Get rid of this method and utilize SolrQueryUtils - currently appears to be referenced @@ -201,24 +193,13 @@ public class IndividualListController extends FreemarkerHttpServlet { return SolrQueryUtils.getIndividualCount(vclassUris, indDao, context); } - private static Map getResultsForVClassQuery(IndividualListQueryResults results, int page, int pageSize, String alpha) { - Map rvMap = new HashMap(); - + private static IndividualListResults getResultsForVClassQuery(IndividualListQueryResults results, int page, int pageSize, String alpha) { long hitCount = results.getHitCount(); if ( hitCount > pageSize ){ - rvMap.put("showPages", Boolean.TRUE); - List pageRecords = makePagesList(hitCount, pageSize, page); - rvMap.put("pages", pageRecords); + return new IndividualListResults(hitCount, results.getIndividuals(), alpha, true, makePagesList(hitCount, pageSize, page)); }else{ - rvMap.put("showPages", Boolean.FALSE); - rvMap.put("pages", Collections.emptyList()); + return new IndividualListResults(hitCount, results.getIndividuals(), alpha, false, Collections.emptyList()); } - - rvMap.put("alpha",alpha); - rvMap.put("totalCount", hitCount); - rvMap.put("entities", results.getIndividuals()); - - return rvMap; } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/individual/IndividualRequestAnalysisContextImpl.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/individual/IndividualRequestAnalysisContextImpl.java index 5f3ebc7e4..a6ad31af7 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/individual/IndividualRequestAnalysisContextImpl.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/individual/IndividualRequestAnalysisContextImpl.java @@ -4,11 +4,6 @@ package edu.cornell.mannlib.vitro.webapp.controller.individual; import java.util.List; -import javax.servlet.ServletContext; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - import edu.cornell.mannlib.vitro.webapp.beans.Individual; import edu.cornell.mannlib.vitro.webapp.beans.SelfEditingConfiguration; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; @@ -22,18 +17,13 @@ import edu.cornell.mannlib.vitro.webapp.filestorage.model.FileInfo; */ public class IndividualRequestAnalysisContextImpl implements IndividualRequestAnalysisContext { - private static final Log log = LogFactory - .getLog(IndividualRequestAnalysisContextImpl.class); - - - private final VitroRequest vreq; - private final ServletContext ctx; + + private final VitroRequest vreq; private final WebappDaoFactory wadf; private final IndividualDao iDao; public IndividualRequestAnalysisContextImpl(VitroRequest vreq) { - this.vreq = vreq; - this.ctx = vreq.getSession().getServletContext(); + this.vreq = vreq; this.wadf = vreq.getWebappDaoFactory(); this.iDao = wadf.getIndividualDao(); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/individuallist/IndividualJsonWrapper.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/individuallist/IndividualJsonWrapper.java new file mode 100644 index 000000000..1fda3985a --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/individuallist/IndividualJsonWrapper.java @@ -0,0 +1,48 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.controller.individuallist; + +import java.util.Collection; +import java.util.Map; + +import org.json.JSONException; +import org.json.JSONObject; + +import edu.cornell.mannlib.vitro.webapp.beans.Individual; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; +import edu.cornell.mannlib.vitro.webapp.dao.ObjectPropertyStatementDao; +import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; + +/** + * Wrap an Individual in a JSON object for display by the script. + * + * This will be overridden in VIVO so we can have more info in the display. + */ +public class IndividualJsonWrapper { + static JSONObject packageIndividualAsJson(VitroRequest vreq, Individual ind) + throws JSONException { + // need an unfiltered dao to get firstnames and lastnames + WebappDaoFactory fullWdf = vreq.getUnfilteredWebappDaoFactory(); + + JSONObject jo = new JSONObject(); + jo.put("URI", ind.getURI()); + jo.put("label", ind.getRdfsLabel()); + jo.put("name", ind.getName()); + jo.put("thumbUrl", ind.getThumbUrl()); + jo.put("imageUrl", ind.getImageUrl()); + jo.put("profileUrl", UrlBuilder.getIndividualProfileUrl(ind, vreq)); + jo.put("mostSpecificTypes", getMostSpecificTypes(ind, fullWdf)); + return jo; + } + + public static Collection getMostSpecificTypes( + Individual individual, WebappDaoFactory wdf) { + ObjectPropertyStatementDao opsDao = wdf.getObjectPropertyStatementDao(); + Map mostSpecificTypes = opsDao + .getMostSpecificTypesInClassgroupsForIndividual(individual + .getURI()); + return mostSpecificTypes.values(); + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/individuallist/IndividualListResults.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/individuallist/IndividualListResults.java new file mode 100644 index 000000000..68cbc1d09 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/individuallist/IndividualListResults.java @@ -0,0 +1,87 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.controller.individuallist; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import edu.cornell.mannlib.vitro.webapp.beans.Individual; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.IndividualListController.PageRecord; + +/** + * These are the paged results of a query for Individuals. + * + * The criteria for the search are the index of the desired page, the number of + * results displayed on each page, and an optional initial letter to search + * against. + * + * By the time this is built, the results have already been partially processed. + * A list of PageRecord object is included, with values that the GUI can use to + * create Alphabetical links. Maybe this processing should have been done later. + * Maybe it should have been left to the GUI. + */ +public class IndividualListResults { + private static final Log log = LogFactory + .getLog(IndividualListResults.class); + + public static final IndividualListResults EMPTY = new IndividualListResults(); + + private final long totalCount; + private final List entities; + private final String alpha; + private final boolean showPages; + private final List pages; + + public IndividualListResults(long totalCount, List entities, + String alpha, boolean showPages, List pages) { + this.totalCount = totalCount; + this.entities = entities; + this.alpha = alpha; + this.showPages = showPages; + this.pages = pages; + } + + private IndividualListResults() { + this(0L, Collections. emptyList(), "", false, Collections + . emptyList()); + } + + public long getTotalCount() { + return totalCount; + } + + public String getAlpha() { + return alpha; + } + + public List getEntities() { + return entities; + } + + public List getPages() { + return pages; + } + + public boolean isShowPages() { + return showPages; + } + + /** + * Some controllers put this data directly into the Freemarker body map. + * Others wrap it in JSON. + */ + public Map asFreemarkerMap() { + Map m = new HashMap<>(); + m.put("showPages", showPages); + m.put("pages", pages); + m.put("alpha", alpha); + m.put("totalCount", totalCount); + m.put("entities", entities); + return m; + } +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/individuallist/IndividualListResultsUtils.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/individuallist/IndividualListResultsUtils.java new file mode 100644 index 000000000..e06f35af9 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/individuallist/IndividualListResultsUtils.java @@ -0,0 +1,148 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.controller.individuallist; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import edu.cornell.mannlib.vitro.webapp.beans.Individual; +import edu.cornell.mannlib.vitro.webapp.beans.VClass; +import edu.cornell.mannlib.vitro.webapp.controller.Controllers; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.IndividualListController.PageRecord; + +/** + * Utility methods for procesing the paged results of a query for a list of Individuals. + * + * Right now, there is only a method to wrap the results in Json. + */ +public class IndividualListResultsUtils { + private static final Log log = LogFactory + .getLog(IndividualListResultsUtils.class); + + /** + * Process results related to VClass or vclasses. Handles both single and + * multiple vclasses being sent. + */ + public static JSONObject wrapIndividualListResultsInJson(IndividualListResults results, VitroRequest vreq, + boolean multipleVclasses) { + JSONObject rObj = new JSONObject(); + + if (log.isDebugEnabled()) { + dumpParametersFromRequest(vreq); + } + + try { + List vclasses = buildListOfRequestedVClasses(vreq); + + VClass vclass = null; + // if single vclass expected, then include vclass. + // This relates to what the expected behavior is, not size of list + if (!multipleVclasses) { + vclass = vclasses.get(0); + // currently used for ClassGroupPage + } else { + // For now, utilize very last VClass (assume that that is the one to be employed) + // TODO: Find more general way of dealing with this: put multiple ones in? + vclass = vclasses.get(vclasses.size() - 1); + // rObj.put("vclasses", new JSONObject().put("URIs",vitroClassIdStr).put("name",vclass.getName())); + } + + rObj.put("vclass", packageVClassAsJson(vclass)); + rObj.put("totalCount", results.getTotalCount()); + rObj.put("alpha", results.getAlpha()); + rObj.put("individuals", packageIndividualsAsJson(vreq, results.getEntities())); + rObj.put("pages", packagePageRecordsAsJson(results.getPages())); + rObj.put("letters", packageLettersAsJson()); + } catch (Exception ex) { + log.error("Error occurred in processing JSON object", ex); + } + return rObj; + } + + private static List buildListOfRequestedVClasses(VitroRequest vreq) + throws Exception { + String[] vitroClassIdStr = vreq.getParameterValues("vclassId"); + if (ArrayUtils.isEmpty(vitroClassIdStr)) { + log.error("parameter vclassId URI parameter expected "); + throw new Exception("parameter vclassId URI parameter expected "); + } + + List list = new ArrayList<>(); + for (String vclassId : vitroClassIdStr) { + VClass vclass = vreq.getWebappDaoFactory().getVClassDao() + .getVClassByURI(vclassId); + if (vclass == null) { + log.error("Couldn't retrieve vclass "); + throw new Exception("Class " + vclassId + " not found"); + } + list.add(vclass); + } + return list; + } + + private static JSONObject packageVClassAsJson(VClass vclass) + throws JSONException { + JSONObject jvclass = new JSONObject(); + jvclass.put("URI", vclass.getURI()); + jvclass.put("name", vclass.getName()); + return jvclass; + } + + private static JSONArray packageLettersAsJson() throws JSONException, + UnsupportedEncodingException { + List letters = Controllers.getLetters(); + JSONArray jletters = new JSONArray(); + for (String s : letters) { + JSONObject jo = new JSONObject(); + jo.put("text", s); + jo.put("param", "alpha=" + URLEncoder.encode(s, "UTF-8")); + jletters.put(jo); + } + return jletters; + } + + private static JSONArray packagePageRecordsAsJson(List pages) + throws JSONException { + JSONArray wpages = new JSONArray(); + for (PageRecord pr : pages) { + JSONObject p = new JSONObject(); + p.put("text", pr.text); + p.put("param", pr.param); + p.put("index", pr.index); + wpages.put(p); + } + return wpages; + } + + private static JSONArray packageIndividualsAsJson(VitroRequest vreq, + List inds) throws JSONException { + log.debug("Number of individuals returned from request: " + inds.size()); + + JSONArray jInds = new JSONArray(); + for (Individual ind : inds) { + jInds.put(IndividualJsonWrapper.packageIndividualAsJson(vreq, ind)); + } + return jInds; + } + + private static void dumpParametersFromRequest(VitroRequest vreq) { + Map pMap = vreq.getParameterMap(); + for (String name : pMap.keySet()) { + for (String value : pMap.get(name)) { + log.debug("value for " + name + ": '" + value + "'"); + } + } + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/json/JsonServlet.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/json/JsonServlet.java index baf72ec82..6ed8a362e 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/json/JsonServlet.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/json/JsonServlet.java @@ -3,11 +3,8 @@ package edu.cornell.mannlib.vitro.webapp.controller.json; import java.io.IOException; -import java.net.URLEncoder; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.Enumeration; import java.util.List; import java.util.Map; @@ -18,18 +15,15 @@ import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.json.JSONArray; import org.json.JSONObject; import edu.cornell.mannlib.vitro.webapp.beans.DataProperty; import edu.cornell.mannlib.vitro.webapp.beans.Individual; -import edu.cornell.mannlib.vitro.webapp.beans.VClass; -import edu.cornell.mannlib.vitro.webapp.controller.Controllers; import edu.cornell.mannlib.vitro.webapp.controller.VitroHttpServlet; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.IndividualListController; -import edu.cornell.mannlib.vitro.webapp.controller.freemarker.IndividualListController.PageRecord; -import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; +import edu.cornell.mannlib.vitro.webapp.controller.individuallist.IndividualListResultsUtils; +import edu.cornell.mannlib.vitro.webapp.controller.individuallist.IndividualListResults; import edu.cornell.mannlib.vitro.webapp.dao.ObjectPropertyStatementDao; import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; import edu.cornell.mannlib.vitro.webapp.utils.log.LogUtils; @@ -94,29 +88,28 @@ public class JsonServlet extends VitroHttpServlet { List vclassURIs = Collections.singletonList(vclassURI); VitroRequest vreq = new VitroRequest(req); - Map map = getSolrVClassIntersectionResults(vclassURIs, vreq, context); + IndividualListResults vcResults = getSolrVClassIntersectionResults(vclassURIs, vreq, context); //last parameter indicates single vclass instead of multiple vclasses - return processVclassResultsJSON(map, vreq, false); + return IndividualListResultsUtils.wrapIndividualListResultsInJson(vcResults, vreq, false); } public static JSONObject getSolrIndividualsByVClasses(List vclassURIs, HttpServletRequest req, ServletContext context) throws Exception { VitroRequest vreq = new VitroRequest(req); log.debug("Retrieve solr results for vclasses" + vclassURIs.toString()); - Map map = getSolrVClassIntersectionResults(vclassURIs, vreq, context); - log.debug("Results returned from Solr for " + vclassURIs.toString() + " are of size " + map.size()); + IndividualListResults vcResults = getSolrVClassIntersectionResults(vclassURIs, vreq, context); + log.debug("Results returned from Solr for " + vclassURIs.toString() + " are of size " + vcResults.getTotalCount()); - return processVclassResultsJSON(map, vreq, true); + return IndividualListResultsUtils.wrapIndividualListResultsInJson(vcResults, vreq, true); } //Including version for Solr query for Vclass Intersections - private static Map getSolrVClassIntersectionResults(List vclassURIs, VitroRequest vreq, ServletContext context){ + private static IndividualListResults getSolrVClassIntersectionResults(List vclassURIs, VitroRequest vreq, ServletContext context){ log.debug("Retrieving Solr intersection results for " + vclassURIs.toString()); String alpha = IndividualListController.getAlphaParameter(vreq); int page = IndividualListController.getPageParameter(vreq); log.debug("Alpha and page parameters are " + alpha + " and " + page); - Map map = null; try { - map = IndividualListController.getResultsForVClassIntersections( + return IndividualListController.getResultsForVClassIntersections( vclassURIs, page, INDIVIDUALS_PER_PAGE, alpha, @@ -124,23 +117,10 @@ public class JsonServlet extends VitroHttpServlet { context); } catch(Exception ex) { log.error("Error in retrieval of search results for VClass " + vclassURIs.toString(), ex); + return IndividualListResults.EMPTY; } - - return map; } - // Map given to process method includes the actual individuals returned from the search -// public static JSONObject processVClassResults(Map map, VitroRequest vreq, ServletContext context, boolean multipleVclasses) throws Exception{ -// JSONObject rObj = processVclassResultsJSON(map, vreq, multipleVclasses); -// return rObj; -// } - - public static Collection getMostSpecificTypes(Individual individual, WebappDaoFactory wdf) { - ObjectPropertyStatementDao opsDao = wdf.getObjectPropertyStatementDao(); - Map mostSpecificTypes = opsDao.getMostSpecificTypesInClassgroupsForIndividual(individual.getURI()); - return mostSpecificTypes.values(); - } - public static String getDataPropertyValue(Individual ind, DataProperty dp, WebappDaoFactory wdf){ String value = ind.getDataValue(dp.getURI()); if( value == null || value.isEmpty() ) @@ -152,21 +132,20 @@ public class JsonServlet extends VitroHttpServlet { public static JSONObject getRandomSolrIndividualsByVClass(String vclassURI, HttpServletRequest req, ServletContext context) throws Exception { VitroRequest vreq = new VitroRequest(req); - Map map = getRandomSolrVClassResults(vclassURI, vreq, context); + IndividualListResults vcResults = getRandomSolrVClassResults(vclassURI, vreq, context); //last parameter indicates single vclass instead of multiple vclasses - return processVclassResultsJSON(map, vreq, false); + return IndividualListResultsUtils.wrapIndividualListResultsInJson(vcResults, vreq, false); } //Including version for Random Solr query for Vclass Intersections - private static Map getRandomSolrVClassResults(String vclassURI, VitroRequest vreq, ServletContext context){ + private static IndividualListResults getRandomSolrVClassResults(String vclassURI, VitroRequest vreq, ServletContext context){ log.debug("Retrieving random Solr intersection results for " + vclassURI); int page = IndividualListController.getPageParameter(vreq); int pageSize = Integer.parseInt(vreq.getParameter("pageSize")); log.debug("page and pageSize parameters = " + page + " and " + pageSize); - Map map = null; try { - map = IndividualListController.getRandomResultsForVClass( + return IndividualListController.getRandomResultsForVClass( vclassURI, page, pageSize, @@ -174,126 +153,8 @@ public class JsonServlet extends VitroHttpServlet { context); } catch(Exception ex) { log.error("Error in retrieval of search results for VClass " + vclassURI, ex); + return IndividualListResults.EMPTY; } - - return map; } - - /** - * Process results related to VClass or vclasses. Handles both single and multiple vclasses being sent. - */ - public static JSONObject processVclassResultsJSON(Map map, VitroRequest vreq, boolean multipleVclasses) { - JSONObject rObj = new JSONObject(); - VClass vclass=null; - - try { - - // Properties from ontologies used by VIVO - should not be in vitro - DataProperty fNameDp = (new DataProperty()); - fNameDp.setURI("http://xmlns.com/foaf/0.1/firstName"); - DataProperty lNameDp = (new DataProperty()); - lNameDp.setURI("http://xmlns.com/foaf/0.1/lastName"); - DataProperty preferredTitleDp = (new DataProperty()); - preferredTitleDp.setURI("http://vivoweb.org/ontology/core#preferredTitle"); - - if( log.isDebugEnabled() ){ - @SuppressWarnings("unchecked") - Enumeration e = vreq.getParameterNames(); - while(e.hasMoreElements()){ - String name = e.nextElement(); - log.debug("parameter: " + name); - for( String value : vreq.getParameterValues(name) ){ - log.debug("value for " + name + ": '" + value + "'"); - } - } - } - - //need an unfiltered dao to get firstnames and lastnames - WebappDaoFactory fullWdf = vreq.getUnfilteredWebappDaoFactory(); - - String[] vitroClassIdStr = vreq.getParameterValues("vclassId"); - if ( vitroClassIdStr != null && vitroClassIdStr.length > 0){ - for(String vclassId: vitroClassIdStr) { - vclass = vreq.getWebappDaoFactory().getVClassDao().getVClassByURI(vclassId); - if (vclass == null) { - log.error("Couldn't retrieve vclass "); - throw new Exception ("Class " + vclassId + " not found"); - } - } - }else{ - log.error("parameter vclassId URI parameter expected "); - throw new Exception("parameter vclassId URI parameter expected "); - } - List vclassIds = Arrays.asList(vitroClassIdStr); - //if single vclass expected, then include vclass. This relates to what the expected behavior is, not size of list - if(!multipleVclasses) { - //currently used for ClassGroupPage - rObj.put("vclass", - new JSONObject().put("URI",vclass.getURI()) - .put("name",vclass.getName())); - } else { - //For now, utilize very last VClass (assume that that is the one to be employed) - //TODO: Find more general way of dealing with this - //put multiple ones in? - if(vclassIds.size() > 0) { - int numberVClasses = vclassIds.size(); - vclass = vreq.getWebappDaoFactory().getVClassDao().getVClassByURI(vclassIds.get(numberVClasses - 1)); - rObj.put("vclass", new JSONObject().put("URI",vclass.getURI()) - .put("name",vclass.getName())); - } - // rObj.put("vclasses", new JSONObject().put("URIs",vitroClassIdStr) - // .put("name",vclass.getName())); - } - if (vclass != null) { - - rObj.put("totalCount", map.get("totalCount")); - rObj.put("alpha", map.get("alpha")); - - List inds = (List)map.get("entities"); - log.debug("Number of individuals returned from request: " + inds.size()); - JSONArray jInds = new JSONArray(); - for(Individual ind : inds ){ - JSONObject jo = new JSONObject(); - jo.put("URI", ind.getURI()); - jo.put("label",ind.getRdfsLabel()); - jo.put("name",ind.getName()); - jo.put("thumbUrl", ind.getThumbUrl()); - jo.put("imageUrl", ind.getImageUrl()); - jo.put("profileUrl", UrlBuilder.getIndividualProfileUrl(ind, vreq)); - - jo.put("mostSpecificTypes", JsonServlet.getMostSpecificTypes(ind,fullWdf)); - jo.put("preferredTitle", JsonServlet.getDataPropertyValue(ind, preferredTitleDp, fullWdf)); - - jInds.put(jo); - } - rObj.put("individuals", jInds); - - JSONArray wpages = new JSONArray(); - //Made sure that PageRecord here is SolrIndividualListController not IndividualListController - List pages = (List)map.get("pages"); - for( PageRecord pr: pages ){ - JSONObject p = new JSONObject(); - p.put("text", pr.text); - p.put("param", pr.param); - p.put("index", pr.index); - wpages.put( p ); - } - rObj.put("pages",wpages); - - JSONArray jletters = new JSONArray(); - List letters = Controllers.getLetters(); - for( String s : letters){ - JSONObject jo = new JSONObject(); - jo.put("text", s); - jo.put("param", "alpha=" + URLEncoder.encode(s, "UTF-8")); - jletters.put( jo ); - } - rObj.put("letters", jletters); - } - } catch(Exception ex) { - log.error("Error occurred in processing JSON object", ex); - } - return rObj; - } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/ObjectPropertyDao.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/ObjectPropertyDao.java index 6c120ee79..76eddf603 100755 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/ObjectPropertyDao.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/ObjectPropertyDao.java @@ -16,6 +16,18 @@ public interface ObjectPropertyDao extends PropertyDao { public ObjectProperty getObjectPropertyByURI(String objectPropertyURI); public ObjectProperty getObjectPropertyByURIs(String objectPropertyURI, String domainURI, String rangeURI); + + /** + * Use this method to supply a base ObjectProperty whose fields will be updated + * as necessary to correspond to the configuration for the specified Domain + * and Range. + * @param objectPropertyURI + * @param domainURI + * @param rangeURI + * @param base + * @return ObjectProperty + */ + public ObjectProperty getObjectPropertyByURIs(String objectPropertyURI, String domainURI, String rangeURI, ObjectProperty base); public List getObjectPropertiesForObjectPropertyStatements(List /*of ObjectPropertyStatement */ objectPropertyStatements); @@ -54,8 +66,22 @@ public interface ObjectPropertyDao extends PropertyDao { List getRootObjectProperties(); + /** + * Returns a list of ObjectProperty objects for which statements exist about + * the individual. Note that this method now returns multiple copies of + * a given predicate, with the rangeVClassURI changed to indicate the distinct + * types of the related objects. This supports finding the approriate list + * views for the "faux" qualified properties. + */ public List getObjectPropertyList(Individual subject); + /** + * Returns a list of ObjectProperty objects for which statements exist about + * the individual. Note that this method now returns multiple copies of + * a given predicate, with the rangeVClassURI changed to indicate the distinct + * types of the related objects. This supports finding the approriate list + * views for the "faux" qualified properties. + */ public List getObjectPropertyList(String subjectUri); public String getCustomListViewConfigFileName(ObjectProperty objectProperty); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/WebappDaoFactoryConfig.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/WebappDaoFactoryConfig.java index aea5acc1c..ee5eaf2de 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/WebappDaoFactoryConfig.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/WebappDaoFactoryConfig.java @@ -5,14 +5,20 @@ package edu.cornell.mannlib.vitro.webapp.dao; import java.util.Arrays; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; +import org.openjena.atlas.lib.Pair; + +import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty; + public class WebappDaoFactoryConfig { private List preferredLanguages; private String defaultNamespace; private Set nonUserNamespaces; private boolean isUnderlyingStoreReasoned = false; + public Map>, String> customListViewConfigFileMap; public WebappDaoFactoryConfig() { preferredLanguages = Arrays.asList("en-US", "en", "EN"); @@ -53,4 +59,13 @@ public class WebappDaoFactoryConfig { return this.isUnderlyingStoreReasoned; } + public Map>, String> getCustomListViewConfigFileMap() { + return this.getCustomListViewConfigFileMap(); + } + + public void setCustomListViewConfigFileMap( + Map>, String> map) { + this.customListViewConfigFileMap = map; + } + } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/ObjectPropertyDaoFiltering.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/ObjectPropertyDaoFiltering.java index 525301c3b..0a5848d98 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/ObjectPropertyDaoFiltering.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/ObjectPropertyDaoFiltering.java @@ -54,6 +54,11 @@ class ObjectPropertyDaoFiltering extends BaseFiltering implements ObjectProperty return (newOprop == null) ? null : new ObjectPropertyFiltering(newOprop, filters); } + public ObjectProperty getObjectPropertyByURIs(String objectPropertyURI, String domainURI, String rangeURI, ObjectProperty base) { + ObjectProperty newOprop=innerObjectPropertyDao.getObjectPropertyByURIs(objectPropertyURI, domainURI, rangeURI, base); + return (newOprop == null) ? null : new ObjectPropertyFiltering(newOprop, filters); + } + public List getStatementsUsingObjectProperty(ObjectProperty op) { return ObjectPropertyStatementDaoFiltering.filterAndWrapList(innerObjectPropertyDao.getStatementsUsingObjectProperty(op),filters); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/DataPropertyDaoJena.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/DataPropertyDaoJena.java index c137de39c..71714fae7 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/DataPropertyDaoJena.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/DataPropertyDaoJena.java @@ -45,15 +45,14 @@ import edu.cornell.mannlib.vitro.webapp.beans.BaseResourceBean; import edu.cornell.mannlib.vitro.webapp.beans.DataProperty; import edu.cornell.mannlib.vitro.webapp.beans.DataPropertyStatement; import edu.cornell.mannlib.vitro.webapp.beans.Individual; -import edu.cornell.mannlib.vitro.webapp.beans.Ontology; import edu.cornell.mannlib.vitro.webapp.beans.PropertyInstance; import edu.cornell.mannlib.vitro.webapp.beans.VClass; import edu.cornell.mannlib.vitro.webapp.dao.DataPropertyDao; import edu.cornell.mannlib.vitro.webapp.dao.InsertException; -import edu.cornell.mannlib.vitro.webapp.dao.OntologyDao; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; import edu.cornell.mannlib.vitro.webapp.dao.jena.event.EditEvent; import edu.cornell.mannlib.vitro.webapp.dao.jena.pellet.PelletListener; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; public class DataPropertyDaoJena extends PropertyDaoJena implements DataPropertyDao { @@ -71,9 +70,10 @@ public class DataPropertyDaoJena extends PropertyDaoJena implements } } - public DataPropertyDaoJena(DatasetWrapperFactory dwf, + public DataPropertyDaoJena(RDFService rdfService, + DatasetWrapperFactory dwf, WebappDaoFactoryJena wadf) { - super(dwf, wadf); + super(rdfService, dwf, wadf); } public void deleteDataProperty(DataProperty dtp) { @@ -672,7 +672,7 @@ public class DataPropertyDaoJena extends PropertyDaoJena implements PREFIXES + "\n" + "SELECT DISTINCT ?property WHERE { \n" + " ?subject ?property ?object . \n" + - " ?property a owl:DatatypeProperty . \n" + + //" ?property a owl:DatatypeProperty . \n" + " FILTER ( \n" + " isLiteral(?object) && \n" + " ( !regex(str(?property), \"^" + VitroVocabulary.PUBLIC + "\" )) && \n" + @@ -708,7 +708,7 @@ public class DataPropertyDaoJena extends PropertyDaoJena implements } log.debug("Data property query string:\n" + query); - ResultSet results = getPropertyQueryResults(query); + ResultSet results = getPropertyQueryResults(queryString); List properties = new ArrayList(); while (results.hasNext()) { QuerySolution sol = results.next(); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/ObjectPropertyDaoJena.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/ObjectPropertyDaoJena.java index fbaef1052..9c38774ab 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/ObjectPropertyDaoJena.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/ObjectPropertyDaoJena.java @@ -13,11 +13,13 @@ import java.util.Map; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.openjena.atlas.lib.Pair; import com.hp.hpl.jena.datatypes.xsd.XSDDatatype; import com.hp.hpl.jena.ontology.ConversionException; import com.hp.hpl.jena.ontology.DatatypeProperty; import com.hp.hpl.jena.ontology.OntModel; +import com.hp.hpl.jena.ontology.OntModelSpec; import com.hp.hpl.jena.ontology.OntProperty; import com.hp.hpl.jena.ontology.OntResource; import com.hp.hpl.jena.ontology.ProfileException; @@ -28,7 +30,6 @@ import com.hp.hpl.jena.query.QueryFactory; import com.hp.hpl.jena.query.QuerySolution; import com.hp.hpl.jena.query.ResultSet; import com.hp.hpl.jena.rdf.model.Literal; -import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.ModelFactory; import com.hp.hpl.jena.rdf.model.Property; import com.hp.hpl.jena.rdf.model.RDFNode; @@ -37,30 +38,31 @@ import com.hp.hpl.jena.rdf.model.ResourceFactory; import com.hp.hpl.jena.rdf.model.Statement; import com.hp.hpl.jena.rdf.model.StmtIterator; import com.hp.hpl.jena.shared.Lock; -import com.hp.hpl.jena.sparql.expr.NodeValue; import com.hp.hpl.jena.util.iterator.ClosableIterator; import com.hp.hpl.jena.vocabulary.OWL; import com.hp.hpl.jena.vocabulary.RDF; import com.hp.hpl.jena.vocabulary.RDFS; -import com.hp.hpl.jena.sdb.util.Pair; import edu.cornell.mannlib.vitro.webapp.beans.BaseResourceBean; import edu.cornell.mannlib.vitro.webapp.beans.Individual; import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty; import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatement; -import edu.cornell.mannlib.vitro.webapp.beans.Ontology; import edu.cornell.mannlib.vitro.webapp.dao.InsertException; import edu.cornell.mannlib.vitro.webapp.dao.ObjectPropertyDao; -import edu.cornell.mannlib.vitro.webapp.dao.OntologyDao; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; import edu.cornell.mannlib.vitro.webapp.dao.jena.event.EditEvent; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectPropertyDao { private static final Log log = LogFactory.getLog(ObjectPropertyDaoJena.class.getName()); - - public ObjectPropertyDaoJena(DatasetWrapperFactory dwf, + + public ObjectPropertyDaoJena(RDFService rdfService, + DatasetWrapperFactory dwf, + Map>, String> + customListViewConfigFileMap, WebappDaoFactoryJena wadf) { - super(dwf, wadf); + super(rdfService, dwf, wadf); + this.customListViewConfigFileMap = customListViewConfigFileMap; } @Override @@ -69,7 +71,6 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp } public void deleteObjectProperty(String propertyURI) { - OntProperty p = getOntModel().getOntProperty(propertyURI); ObjectProperty op = new ObjectProperty(); op.setURI(propertyURI); deleteObjectProperty(op); @@ -269,22 +270,35 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp } public ObjectProperty getObjectPropertyByURI(String propertyURI) { + + long start = System.currentTimeMillis(); if( propertyURI == null ) return null; - getOntModel().enterCriticalSection(Lock.READ); + OntModel ontModel = getOntModel(); + OntModel localModel = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); + + ontModel.enterCriticalSection(Lock.READ); try { - OntProperty op = getOntModel().getObjectProperty(propertyURI); + localModel.add(ontModel.listStatements(ontModel.getResource(propertyURI), null, (RDFNode) null)); + OntProperty op = localModel.getObjectProperty(propertyURI); return propertyFromOntProperty(op); } finally { - getOntModel().leaveCriticalSection(); + ontModel.leaveCriticalSection(); } } - public ObjectProperty getObjectPropertyByURIs(String propertyURI, String domainURI, String rangeURI) { + public ObjectProperty getObjectPropertyByURIs(String propertyURI, + String domainURI, String rangeURI) { + return getObjectPropertyByURIs(propertyURI, domainURI, rangeURI, null); + } + + public ObjectProperty getObjectPropertyByURIs(String propertyURI, + String domainURI, String rangeURI, ObjectProperty base) { if(log.isDebugEnabled()) { log.debug("Getting " + propertyURI + " with domain " + domainURI + " and range " + rangeURI); } - ObjectProperty op = getObjectPropertyByURI(propertyURI); + long start = System.currentTimeMillis(); + ObjectProperty op = (base != null) ? base : getObjectPropertyByURI(propertyURI); if (op == null || rangeURI == null) { return op; } @@ -293,7 +307,7 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp String propQuery = "PREFIX rdfs: \n" + "PREFIX config: \n" + "PREFIX vitro: \n" + - "SELECT ?range ?label ?group ?customForm ?displayRank ?displayLevel " + + "SELECT ?range ?rangeRoot ?label ?group ?customForm ?displayRank ?displayLevel " + " ?updateLevel ?editLinkSuppressed ?addLinkSuppressed ?deleteLinkSuppressed \n" + " ?collateBySubclass ?displayLimit ?individualSortProperty \n" + " ?entitySortDirection ?selectFromExisting ?offerCreateNew \n" + @@ -308,7 +322,8 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp if (rangeURI != null) { propQuery += " ?context config:qualifiedBy <" + rangeURI + "> . \n"; }; - propQuery += " ?context config:hasConfiguration ?configuration . \n" + + propQuery += " OPTIONAL { ?context config:qualifiedByRoot ?rangeRoot } \n" + + " ?context config:hasConfiguration ?configuration . \n" + " ?configuration a config:ObjectPropertyDisplayConfig . \n" + " OPTIONAL { ?configuration config:propertyGroup ?group } \n" + " OPTIONAL { ?configuration config:displayName ?label } \n" + @@ -334,6 +349,15 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp ResultSet rs = qe.execSelect(); if (rs.hasNext()) { QuerySolution qsoln = rs.nextSolution(); + // This is a bit of hack, used for things where the type of the + // immediately-related object ("root," for lack of a better term) + // is important to record but not the type directly associated with + // a configuration + Resource rangeRootRes = qsoln.getResource("rangeRoot"); + if (rangeRootRes != null) { + // reusing this obsolete field for now + op.setRangeEntityURI(rangeRootRes.getURI()); + } Resource groupRes = qsoln.getResource("group"); if (groupRes != null) { op.setGroupURI(groupRes.getURI()); @@ -407,7 +431,7 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp } } finally { qe.close(); - } + } return op; } @@ -918,24 +942,30 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp "?property = vitro:additionalLink ||" + "!regex(str(?property), \"^http://vitro.mannlib.cornell.edu/ns/vitro/0.7#\" ))"); PROPERTY_FILTERS = StringUtils.join(namespaceFilters, " && "); - } + } protected static final String OBJECT_PROPERTY_QUERY_STRING = PREFIXES + "\n" + - "SELECT DISTINCT ?property WHERE { \n" + - " ?subject ?property ?object . \n" + + "SELECT DISTINCT ?property ?objType WHERE { \n" + + " ?subject ?property ?object . \n" + + " ?object a ?objType . \n" + // " ?property a owl:ObjectProperty . \n" + " FILTER ( \n" + " isURI(?object) && \n" + PROPERTY_FILTERS + "\n" + " ) \n" + - "}"; + "} ORDER BY ?property ?objType"; @Override public List getObjectPropertyList(Individual subject) { return getObjectPropertyList(subject.getURI()); } - + + // Returns a list of ObjectProperty objects for which statements exist about + // the individual. Note that this method now returns additional copies of + // a given predicate, with the rangeVClassURI changed to indicate the distinct + // types of the related objects. This supports finding the approriate list + // views for the "faux" qualified properties. @Override public List getObjectPropertyList(String subjectUri) { @@ -954,15 +984,35 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp } log.debug("Object property query:\n" + query); - ResultSet results = getPropertyQueryResults(query); + ObjectProperty propRegister = new ObjectProperty(); + propRegister.setURI(""); + + ResultSet results = getPropertyQueryResults(queryString); List properties = new ArrayList(); while (results.hasNext()) { QuerySolution soln = results.next(); Resource resource = soln.getResource("property"); String uri = resource.getURI(); - log.debug("Found populated object property " + uri); - ObjectProperty property = getObjectPropertyByURI(uri); + Resource objType = soln.getResource("objType"); + String objTypeUri = objType.getURI(); + log.debug("Found populated object property " + uri + + " with object type " + objType); + ObjectProperty property = null; + if (uri.equals(propRegister.getURI())) { + property = propRegister.clone(); + } else { + property = getObjectPropertyByURI(uri); + if (property != null) { + propRegister = property; + // add canonical instance of the property first in the list + // before the range-changed versions + properties.add(property); + // isolate the canonical prop from what's about to happen next + property = property.clone(); + } + } if (property != null) { + property.setRangeVClassURI(objTypeUri); properties.add(property); } } @@ -998,12 +1048,15 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp // Map key is inner pair of object property and range class URI, // with first member of outer pair being a domain class URI. // If domain or range is unspecified, OWL.Thing.getURI() is used in the key. - Map>, String> customListViewConfigFileMap = null; + Map>, String> customListViewConfigFileMap; @Override public String getCustomListViewConfigFileName(ObjectProperty op) { if (customListViewConfigFileMap == null) { customListViewConfigFileMap = new HashMap>, String>(); + } + if (customListViewConfigFileMap.isEmpty()) { + long start = System.currentTimeMillis(); OntModel displayModel = getOntModelSelector().getDisplayModel(); //Get all property to list view config file mappings in the system QueryExecution qexec = QueryExecutionFactory.create(listViewConfigFileQuery, displayModel); @@ -1036,10 +1089,19 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp domainUri, new Pair( prop, rangeUri)), filename); } - } + } + // If there are no custom list views, put a bogus entry in the map + // to avoid further recomputation + if (customListViewConfigFileMap.isEmpty()) { + ObjectProperty bottom = new ObjectProperty(); + bottom.setURI(OWL.NS + "bottomObjectProperty"); + customListViewConfigFileMap.put( + new Pair>( + null, new Pair( + bottom, null)), "nothing"); + } qexec.close(); - } - + } String customListViewConfigFileName = customListViewConfigFileMap.get(new Pair>(op.getDomainVClassURI(), new Pair(op, op.getRangeVClassURI()))); if (customListViewConfigFileName == null) { log.debug("no list view found for " + op.getURI() + " qualified by range " + op.getRangeVClassURI() + " and domain " + op.getDomainVClassURI()); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/ObjectPropertyStatementDaoJena.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/ObjectPropertyStatementDaoJena.java index 45810e361..34eeb6dd8 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/ObjectPropertyStatementDaoJena.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/ObjectPropertyStatementDaoJena.java @@ -11,7 +11,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -25,6 +24,7 @@ import com.hp.hpl.jena.query.QueryFactory; import com.hp.hpl.jena.query.QuerySolution; import com.hp.hpl.jena.query.QuerySolutionMap; import com.hp.hpl.jena.query.ResultSet; +import com.hp.hpl.jena.query.ResultSetFactory; import com.hp.hpl.jena.query.Syntax; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.ModelFactory; @@ -35,6 +35,7 @@ import com.hp.hpl.jena.rdf.model.ResourceFactory; import com.hp.hpl.jena.rdf.model.Statement; import com.hp.hpl.jena.rdf.model.StmtIterator; import com.hp.hpl.jena.shared.Lock; +import com.hp.hpl.jena.sparql.resultset.ResultSetMem; import com.hp.hpl.jena.util.iterator.ClosableIterator; import com.hp.hpl.jena.vocabulary.OWL; @@ -46,6 +47,7 @@ import edu.cornell.mannlib.vitro.webapp.dao.ObjectPropertyStatementDao; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; import edu.cornell.mannlib.vitro.webapp.dao.jena.event.IndividualUpdateEvent; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException; public class ObjectPropertyStatementDaoJena extends JenaBaseDao implements ObjectPropertyStatementDao { @@ -92,7 +94,8 @@ public class ObjectPropertyStatementDaoJena extends JenaBaseDao implements Objec else { Map uriToObjectProperty = new HashMap(); - ObjectPropertyDaoJena opDaoJena = new ObjectPropertyDaoJena(dwf, getWebappDaoFactory()); + ObjectPropertyDaoJena opDaoJena = (ObjectPropertyDaoJena) getWebappDaoFactory().getObjectPropertyDao(); + //new ObjectPropertyDaoJena(rdfService, dwf, getWebappDaoFactory()); OntModel ontModel = getOntModelSelector().getABoxModel(); ontModel.enterCriticalSection(Lock.READ); @@ -278,26 +281,77 @@ public class ObjectPropertyStatementDaoJena extends JenaBaseDao implements Objec Set constructQueryStrings, String sortDirection) { - Model constructedModel = constructModelForSelectQueries( - subjectUri, propertyUri, constructQueryStrings); - - if(log.isDebugEnabled()) { - log.debug("Constructed model has " + constructedModel.size() + " statements."); + List> list = new ArrayList>(); + + long start = System.currentTimeMillis(); + + try { + Model constructedModel = constructModelForSelectQueries( + subjectUri, propertyUri, rangeUri, constructQueryStrings); + + if(log.isDebugEnabled()) { + log.debug("Constructed model has " + constructedModel.size() + " statements."); + } + + if("desc".equalsIgnoreCase( sortDirection ) ){ + queryString = queryString.replaceAll(" ASC\\(", " DESC("); + } + + ResultSet results = (constructedModel == null) ? selectFromRDFService( + queryString, subjectUri, propertyUri, domainUri, rangeUri) : selectFromConstructedModel( + queryString, subjectUri, propertyUri, domainUri, rangeUri, constructedModel); + + while (results.hasNext()) { + QuerySolution soln = results.nextSolution(); + RDFNode node = soln.get(objectKey); + if (node.isURIResource()) { + list.add(QueryUtils.querySolutionToStringValueMap(soln)); + } + } + if(log.isDebugEnabled()) { + long duration = System.currentTimeMillis() - start; + log.debug(duration + " to do list view for " + + propertyUri + " / " + domainUri + " / " + rangeUri); + } + } catch (Exception e) { + log.error("Error getting object property values for subject " + subjectUri + " and property " + propertyUri, e); + return Collections.emptyList(); } - - if("desc".equalsIgnoreCase( sortDirection ) ){ - queryString = queryString.replaceAll(" ASC\\(", " DESC("); - } - + return list; + } + + private ResultSet selectFromRDFService(String queryString, String subjectUri, + String propertyUri, String domainUri, String rangeUri) { + String[] part = queryString.split("[Ww][Hh][Ee][Rr][Ee]"); + part[1] = part[1].replace("?subject", "<" + subjectUri + ">"); + part[1] = part[1].replace("?property", "<" + propertyUri + ">"); + if (domainUri != null && !domainUri.startsWith(VitroVocabulary.PSEUDO_BNODE_NS)) { + part[1] = part[1].replace("?subjectType", "<" + domainUri + ">"); + } + if (rangeUri != null && !rangeUri.startsWith(VitroVocabulary.PSEUDO_BNODE_NS)) { + part[1] = part[1].replace("?objectType", "<" + rangeUri + ">"); + } + queryString = part[0] + "WHERE" + part[1]; + try { + return ResultSetFactory.fromJSON( + rdfService.sparqlSelectQuery(queryString, RDFService.ResultFormat.JSON)); + } catch (RDFServiceException e) { + throw new RuntimeException(e); + } + } + + private ResultSet selectFromConstructedModel(String queryString, + String subjectUri, String propertyUri, String domainUri, String rangeUri, + Model constructedModel) { Query query = null; try { query = QueryFactory.create(queryString, Syntax.syntaxARQ); } catch(Throwable th){ log.error("Could not create SPARQL query for query string. " + th.getMessage()); log.error(queryString); - return Collections.emptyList(); + throw new RuntimeException(th); } - + QuerySolutionMap initialBindings = new QuerySolutionMap(); initialBindings.add("subject", ResourceFactory.createResource(subjectUri)); initialBindings.add("property", ResourceFactory.createResource(propertyUri)); @@ -307,52 +361,31 @@ public class ObjectPropertyStatementDaoJena extends JenaBaseDao implements Objec if (rangeUri != null && !rangeUri.startsWith(VitroVocabulary.PSEUDO_BNODE_NS)) { initialBindings.add("objectType", ResourceFactory.createResource(rangeUri)); } - - log.debug("Query string for object property " + propertyUri + ": " + queryString); - + + if(log.isDebugEnabled()) { + log.debug("Query string for object property " + propertyUri + ": " + queryString); + } + // Run the SPARQL query to get the properties - List> list = new ArrayList>(); - DatasetWrapper w = dwf.getDatasetWrapper(); - Dataset dataset = w.getDataset(); - dataset.getLock().enterCriticalSection(Lock.READ); + QueryExecution qexec = null; try { - - qexec = (constructedModel == null) - ? QueryExecutionFactory.create( - query, dataset, initialBindings) - : QueryExecutionFactory.create( - query, constructedModel, initialBindings); - - ResultSet results = qexec.execSelect(); - - while (results.hasNext()) { - QuerySolution soln = results.nextSolution(); - RDFNode node = soln.get(objectKey); - if (node.isURIResource()) { - list.add(QueryUtils.querySolutionToStringValueMap(soln)); - } - } - return list; - - } catch (Exception e) { - log.error("Error getting object property values for subject " + subjectUri + " and property " + propertyUri); - return Collections.emptyList(); + qexec = QueryExecutionFactory.create( + query, constructedModel, initialBindings); + return new ResultSetMem(qexec.execSelect()); } finally { - dataset.getLock().leaveCriticalSection(); - w.close(); if (qexec != null) { qexec.close(); } - } - + } } private Model constructModelForSelectQueries(String subjectUri, - String propertyUri, + String propertyUri, + String rangeUri, Set constructQueries) { - if (constructQueries == null) { + if (constructQueries.size() == 0 || constructQueries == null) { return null; } @@ -362,24 +395,18 @@ public class ObjectPropertyStatementDaoJena extends JenaBaseDao implements Objec queryString = queryString.replace("?subject", "<" + subjectUri + ">"); queryString = queryString.replace("?property", "<" + propertyUri + ">"); + if (rangeUri != null) { + queryString = queryString.replace("?objectType", "<" + rangeUri + ">"); + } - log.debug("CONSTRUCT query string for object property " + - propertyUri + ": " + queryString); + if (log.isDebugEnabled()) { + log.debug("CONSTRUCT query string for object property " + + propertyUri + ": " + queryString); + } - // we no longer need this query object, but we might want to do this - // query parse step to improve debugging, depending on the error returned - // through the RDF API -// try { -// QueryFactory.create(queryString, Syntax.syntaxARQ); -// } catch(Throwable th){ -// log.error("Could not create CONSTRUCT SPARQL query for query " + -// "string. " + th.getMessage()); -// log.error(queryString); -// return constructedModel; -// } - try { - //If RDFService is null, will do what code used to do before, otherwise employ rdfservice + //If RDFService is null, will do what code used to do before, + //otherwise employ rdfservice if(rdfService == null) { log.debug("RDF Service null, Using CONSTRUCT query string for object property " + propertyUri + ": " + queryString); @@ -402,7 +429,8 @@ public class ObjectPropertyStatementDaoJena extends JenaBaseDao implements Objec query, dataset); qe.execConstruct(constructedModel); } catch (Exception e) { - log.error("Error getting constructed model for subject " + subjectUri + " and property " + propertyUri); + log.error("Error getting constructed model for subject " + + subjectUri + " and property " + propertyUri); } finally { if (qe != null) { qe.close(); @@ -412,28 +440,31 @@ public class ObjectPropertyStatementDaoJena extends JenaBaseDao implements Objec } } else { String parseFormat = "N3"; - RDFService.ModelSerializationFormat resultFormat = RDFService.ModelSerializationFormat.N3; + RDFService.ModelSerializationFormat resultFormat = RDFService + .ModelSerializationFormat.N3; - /* If the test ObjectPropertyStatementDaoJenaTest.testN3WithSameAs() fails - * this code can be removed: */ + /* If the test ObjectPropertyStatementDaoJenaTest.testN3WithSameAs() + * fails this code can be removed: */ if( OWL.sameAs.getURI().equals( propertyUri )){ - // VIVO-111: owl:sameAs can be represented as = in n3 but Jena's parser does not recognize it. - // Switch to rdf/xml only for sameAs since it seems like n3 would be faster the rest of the time. + // VIVO-111: owl:sameAs can be represented as = in n3 but + // Jena's parser does not recognize it. + // Switch to rdf/xml only for sameAs since it seems like n3 + // would be faster the rest of the time. parseFormat = "RDF/XML"; resultFormat = RDFService.ModelSerializationFormat.RDFXML; } /* end of removal */ - InputStream is = rdfService.sparqlConstructQuery(queryString, resultFormat); + InputStream is = rdfService.sparqlConstructQuery( + queryString, resultFormat); constructedModel.read( is, null, parseFormat); } } catch (Exception e) { - log.error("Error getting constructed model for subject " + subjectUri + " and property " + propertyUri, e); + log.error("Error getting constructed model for subject " + + subjectUri + " and property " + propertyUri, e); } } - - return constructedModel; - + return constructedModel; } protected static final String MOST_SPECIFIC_TYPE_QUERY = "" diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/PropertyDaoJena.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/PropertyDaoJena.java index 057df054e..dc87b7065 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/PropertyDaoJena.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/PropertyDaoJena.java @@ -21,13 +21,13 @@ import com.hp.hpl.jena.ontology.OntClass; import com.hp.hpl.jena.ontology.OntModel; import com.hp.hpl.jena.ontology.OntProperty; import com.hp.hpl.jena.ontology.Restriction; -import com.hp.hpl.jena.query.Dataset; import com.hp.hpl.jena.query.Query; import com.hp.hpl.jena.query.QueryExecution; import com.hp.hpl.jena.query.QueryExecutionFactory; import com.hp.hpl.jena.query.QueryFactory; import com.hp.hpl.jena.query.QuerySolution; import com.hp.hpl.jena.query.ResultSet; +import com.hp.hpl.jena.query.ResultSetFactory; import com.hp.hpl.jena.query.Syntax; import com.hp.hpl.jena.rdf.model.RDFNode; import com.hp.hpl.jena.rdf.model.Resource; @@ -36,7 +36,6 @@ import com.hp.hpl.jena.rdf.model.Statement; import com.hp.hpl.jena.rdf.model.StmtIterator; import com.hp.hpl.jena.sdb.util.Pair; import com.hp.hpl.jena.shared.Lock; -import com.hp.hpl.jena.sparql.resultset.ResultSetMem; import com.hp.hpl.jena.vocabulary.OWL; import com.hp.hpl.jena.vocabulary.RDFS; @@ -49,6 +48,8 @@ import edu.cornell.mannlib.vitro.webapp.dao.PropertyDao; 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.rdfservice.RDFService; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException; public class PropertyDaoJena extends JenaBaseDao implements PropertyDao { @@ -74,11 +75,14 @@ public class PropertyDaoJena extends JenaBaseDao implements PropertyDao { log.debug("Query prefixes: " + PREFIXES); } + protected RDFService rdfService; protected DatasetWrapperFactory dwf; - public PropertyDaoJena(DatasetWrapperFactory dwf, + public PropertyDaoJena(RDFService rdfService, + DatasetWrapperFactory dwf, WebappDaoFactoryJena wadf) { super(wadf); + this.rdfService = rdfService; this.dwf = dwf; } @@ -86,6 +90,10 @@ public class PropertyDaoJena extends JenaBaseDao implements PropertyDao { protected OntModel getOntModel() { return getOntModelSelector().getTBoxModel(); } + + protected RDFService getRDFService() { + return this.rdfService; + } public void addSuperproperty(ObjectProperty property, ObjectProperty superproperty) { addSuperproperty(property.getURI(),superproperty.getURI()); @@ -414,8 +422,8 @@ public class PropertyDaoJena extends JenaBaseDao implements PropertyDao { return classSet; } - protected ResultSet getPropertyQueryResults(Query query) { - log.debug("SPARQL query:\n" + query.toString()); + protected ResultSet getPropertyQueryResults(String queryString) { + log.debug("SPARQL query:\n" + queryString); // RY Removing prebinding due to Jena bug: when isLiteral(?object) or // isURI(?object) is added to the query as a filter, the query fails with prebinding @@ -424,23 +432,32 @@ public class PropertyDaoJena extends JenaBaseDao implements PropertyDao { //subjectBinding.add("subject", ResourceFactory.createResource(subjectUri)); // Run the SPARQL query to get the properties - DatasetWrapper w = dwf.getDatasetWrapper(); - Dataset dataset = w.getDataset(); - dataset.getLock().enterCriticalSection(Lock.READ); - ResultSet rs = null; + try { - QueryExecution qexec = QueryExecutionFactory.create( - query, dataset); //, subjectBinding); - try { - rs = new ResultSetMem(qexec.execSelect()); - } finally { - qexec.close(); - } - } finally { - dataset.getLock().leaveCriticalSection(); - w.close(); + return ResultSetFactory.fromJSON( + getRDFService().sparqlSelectQuery( + queryString, RDFService.ResultFormat.JSON)); + } catch (RDFServiceException e) { + throw new RuntimeException(e); } - return rs; + +// DatasetWrapper w = dwf.getDatasetWrapper(); +// Dataset dataset = w.getDataset(); +// dataset.getLock().enterCriticalSection(Lock.READ); +// ResultSet rs = null; +// try { +// QueryExecution qexec = QueryExecutionFactory.create( +// query, dataset); //, subjectBinding); +// try { +// rs = new ResultSetMem(qexec.execSelect()); +// } finally { +// qexec.close(); +// } +// } finally { +// dataset.getLock().leaveCriticalSection(); +// w.close(); +// } +// return rs; } /** @@ -865,20 +882,6 @@ public class PropertyDaoJena extends JenaBaseDao implements PropertyDao { } return domainAndRangeURIs; } - - private String getURIStr(Resource res) { - String URIStr; - if (res == null) { - URIStr = OWL.Thing.getURI(); // TODO: rdf:Resource if using RDF model; or option to turn off entirely - } else { - if (res.isAnon()) { - URIStr = PSEUDO_BNODE_NS+res.getId().toString(); - } else { - URIStr = res.getURI(); - } - } - return URIStr; - } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/PropertyInstanceDaoJena.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/PropertyInstanceDaoJena.java index 19cbdffeb..e68caf10f 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/PropertyInstanceDaoJena.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/PropertyInstanceDaoJena.java @@ -29,11 +29,14 @@ import edu.cornell.mannlib.vitro.webapp.beans.VClass; import edu.cornell.mannlib.vitro.webapp.dao.PropertyInstanceDao; import edu.cornell.mannlib.vitro.webapp.dao.jena.event.IndividualDeletionEvent; import edu.cornell.mannlib.vitro.webapp.dao.jena.event.IndividualUpdateEvent; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; public class PropertyInstanceDaoJena extends PropertyDaoJena implements PropertyInstanceDao { - public PropertyInstanceDaoJena(DatasetWrapperFactory dwf, WebappDaoFactoryJena wadf) { - super(dwf, wadf); + public PropertyInstanceDaoJena(RDFService rdfService, + DatasetWrapperFactory dwf, + WebappDaoFactoryJena wadf) { + super(rdfService, dwf, wadf); } public void deleteObjectPropertyStatement(String subjectURI, String propertyURI, String objectURI) { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/WebappDaoFactoryJena.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/WebappDaoFactoryJena.java index 9668c60e8..d75f4a204 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/WebappDaoFactoryJena.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/WebappDaoFactoryJena.java @@ -50,6 +50,7 @@ import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactoryConfig; import edu.cornell.mannlib.vitro.webapp.dao.jena.pellet.PelletListener; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; +import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.jena.model.RDFServiceModel; import edu.cornell.mannlib.vitro.webapp.servlet.setup.JenaDataSourceSetupBase; import edu.cornell.mannlib.vitro.webapp.utils.jena.URIUtils; @@ -109,6 +110,8 @@ public class WebappDaoFactoryJena implements WebappDaoFactory { Dataset dataset = makeInMemoryDataset(assertions, inferences); this.dwf = new StaticDatasetFactory(dataset); + this.rdfService = new RDFServiceModel(ontModelSelector.getFullModel()); + } public WebappDaoFactoryJena(OntModelSelector ontModelSelector, @@ -327,7 +330,7 @@ public class WebappDaoFactoryJena implements WebappDaoFactory { DataPropertyDao dataPropertyDao = null; public DataPropertyDao getDataPropertyDao() { if( dataPropertyDao == null ) - dataPropertyDao = new DataPropertyDaoJena(dwf, this); + dataPropertyDao = new DataPropertyDaoJena(rdfService, dwf, this); return dataPropertyDao; } @@ -358,14 +361,15 @@ public class WebappDaoFactoryJena implements WebappDaoFactory { private ObjectPropertyDao objectPropertyDao = null; public ObjectPropertyDao getObjectPropertyDao() { if( objectPropertyDao == null ) - objectPropertyDao = new ObjectPropertyDaoJena(dwf, this); + objectPropertyDao = new ObjectPropertyDaoJena( + rdfService, dwf, config.customListViewConfigFileMap, this); return objectPropertyDao; } private PropertyInstanceDao propertyInstanceDao = null; public PropertyInstanceDao getPropertyInstanceDao() { if( propertyInstanceDao == null ) - propertyInstanceDao = new PropertyInstanceDaoJena(dwf, this); + propertyInstanceDao = new PropertyInstanceDaoJena(rdfService, dwf, this); return propertyInstanceDao; } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DateTimeValueFormGenerator.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DateTimeValueFormGenerator.java index ebb7b298e..7ecf1695e 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DateTimeValueFormGenerator.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DateTimeValueFormGenerator.java @@ -39,7 +39,7 @@ public class DateTimeValueFormGenerator extends BaseEditConfigurationGenerator initBasics(conf, vreq); initPropertyParameters(vreq, session, conf); - initObjectPropForm(conf, vreq); + initObjectPropForm(conf, vreq); conf.setTemplate(this.getTemplate()); @@ -126,6 +126,7 @@ public class DateTimeValueFormGenerator extends BaseEditConfigurationGenerator public void addFormSpecificData(EditConfigurationVTwo editConfiguration, VitroRequest vreq) { HashMap formSpecificData = new HashMap(); formSpecificData.put("editMode", getEditMode(vreq).name().toLowerCase()); + formSpecificData.put("domainUri", getDomainUri(vreq)); editConfiguration.setFormSpecificData(formSpecificData); } @@ -140,4 +141,10 @@ public class DateTimeValueFormGenerator extends BaseEditConfigurationGenerator } return editMode; } + + private String getDomainUri(VitroRequest vreq) { + String domainUri = vreq.getParameter("domainUri"); + + return domainUri; + } } \ No newline at end of file diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DefaultObjectPropertyFormGenerator.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DefaultObjectPropertyFormGenerator.java index 583a97fd1..11cf0210d 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DefaultObjectPropertyFormGenerator.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DefaultObjectPropertyFormGenerator.java @@ -145,16 +145,16 @@ public class DefaultObjectPropertyFormGenerator implements EditConfigurationGene SolrServer solrServer = SolrSetup.getSolrServer(session.getServletContext()); List types = new ArrayList(); + for (VClass vclass : rangeTypes) { + if (vclass.getURI() != null) { + types.add(vclass.getURI()); + } + } + //empty list means the range is not set to anything, force Thing - if(types.size() == 0 ){ - types.add(VitroVocabulary.OWL_THING); - } else { - for (VClass vclass : rangeTypes) { - if (vclass.getURI() != null) { - types.add(vclass.getURI()); - } - } - } + if(types.size() == 0 ){ + types.add(VitroVocabulary.OWL_THING); + } long count = 0; for( String type:types){ diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/ManageLabelsForIndividualGenerator.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/ManageLabelsForIndividualGenerator.java index 855a2d8ed..39e268a48 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/ManageLabelsForIndividualGenerator.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/ManageLabelsForIndividualGenerator.java @@ -1,6 +1,10 @@ /* $This file is distributed under the terms of the license in /doc/license.txt$ */ package edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators; +import static edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestActionConstants.SOME_LITERAL; +import static edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestActionConstants.SOME_PREDICATE; +import static edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestActionConstants.SOME_URI; + import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.Arrays; @@ -24,14 +28,12 @@ import com.hp.hpl.jena.vocabulary.RDFS; import edu.cornell.mannlib.vitro.webapp.auth.policy.PolicyHelper; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.Actions; -import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestActionConstants; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.AddDataPropertyStatement; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.AddObjectPropertyStatement; import edu.cornell.mannlib.vitro.webapp.beans.Individual; import edu.cornell.mannlib.vitro.webapp.beans.Property; import edu.cornell.mannlib.vitro.webapp.beans.VClass; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; -import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; import edu.cornell.mannlib.vitro.webapp.dao.jena.QueryUtils; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationUtils; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo; @@ -271,11 +273,10 @@ public class ManageLabelsForIndividualGenerator extends BaseEditConfigurationGen Individual individual = EditConfigurationUtils.getIndividual(vreq, config.getSubjectUri()); AddDataPropertyStatement adps = new AddDataPropertyStatement( vreq.getJenaOntModel(), individual.getURI(), - RequestActionConstants.SOME_URI); + SOME_URI, SOME_LITERAL); AddObjectPropertyStatement aops = new AddObjectPropertyStatement( vreq.getJenaOntModel(), individual.getURI(), - RequestActionConstants.SOME_PREDICATE, - RequestActionConstants.SOME_URI); + SOME_PREDICATE, SOME_URI); return PolicyHelper.isAuthorizedForActions(vreq, new Actions(adps).or(aops)); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/EditRequestDispatchController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/EditRequestDispatchController.java index 692f9212d..30ee3b8c3 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/EditRequestDispatchController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/EditRequestDispatchController.java @@ -164,7 +164,9 @@ public class EditRequestDispatchController extends FreemarkerHttpServlet { //edit key is set here, NOT in the generator class EditConfigurationVTwo editConfig = null; EditConfigurationVTwo existingConfig = EditConfigurationVTwo.getConfigFromSession(session, vreq); - if(existingConfig != null) { + //if delete form from the editing page, then edit configuration already exists and the + //delete generator wouldn't be used, we need to make sure that it is used if it's a delete option + if(existingConfig != null && !isDeleteForm(vreq)) { editConfig = existingConfig; } else { editConfig = diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/filters/RequestModelsPrep.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/filters/RequestModelsPrep.java index 0edcf0e1e..d4da08f70 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/filters/RequestModelsPrep.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/filters/RequestModelsPrep.java @@ -10,6 +10,8 @@ import java.text.Collator; import java.util.Enumeration; import java.util.List; import java.util.Locale; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Pattern; import javax.servlet.Filter; @@ -24,6 +26,7 @@ import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.openjena.atlas.lib.Pair; import com.hp.hpl.jena.graph.BulkUpdateHandler; import com.hp.hpl.jena.graph.Graph; @@ -35,6 +38,7 @@ import com.hp.hpl.jena.rdf.model.ModelFactory; import edu.cornell.mannlib.vitro.webapp.auth.identifier.RequestIdentifiers; import edu.cornell.mannlib.vitro.webapp.auth.policy.ServletPolicyList; +import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty; import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties; import edu.cornell.mannlib.vitro.webapp.controller.VitroHttpServlet; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; @@ -311,6 +315,8 @@ public class RequestModelsPrep implements Filter { config.setDefaultNamespace(defaultNamespace); config.setPreferredLanguages(langs); config.setUnderlyingStoreReasoned(isStoreReasoned(req)); + config.setCustomListViewConfigFileMap(getCustomListViewConfigFileMap( + req.getSession().getServletContext())); return config; } @@ -365,6 +371,18 @@ public class RequestModelsPrep implements Filter { "VitroConnection.DataSource.isStoreReasoned", "true"); return ("true".equals(isStoreReasoned)); } + + private Map>, String> + getCustomListViewConfigFileMap(ServletContext ctx) { + Map>, String> map = + (Map>, String>) + ctx.getAttribute("customListViewConfigFileMap"); + if (map == null) { + map = new ConcurrentHashMap>, String>(); + ctx.setAttribute("customListViewConfigFileMap", map); + } + return map; + } @Override public void destroy() { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/ABoxUpdater.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/ABoxUpdater.java index 74de6f79e..7679689f6 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/ABoxUpdater.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/ABoxUpdater.java @@ -31,6 +31,8 @@ import com.hp.hpl.jena.vocabulary.RDF; import edu.cornell.mannlib.vitro.webapp.dao.jena.RDFServiceDataset; import edu.cornell.mannlib.vitro.webapp.ontology.update.AtomicOntologyChange.AtomicChangeType; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException; +import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils; /** * Performs knowledge base updates to the abox to align with a new ontology version @@ -594,9 +596,11 @@ public class ABoxUpdater { return; } + long start = System.currentTimeMillis(); Iterator graphIt = dataset.listNames(); while(graphIt.hasNext()) { String graph = graphIt.next(); + //log.info(System.currentTimeMillis() - start + " to get graph"); if(!KnowledgeBaseUpdater.isUpdatableABoxGraph(graph)){ continue; } @@ -604,11 +608,23 @@ public class ABoxUpdater { Model renamePropAddModel = ModelFactory.createDefaultModel(); Model renamePropRetractModel = ModelFactory.createDefaultModel(); - + log.info("renaming " + oldProperty.getURI() + " in graph " + graph); aboxModel.enterCriticalSection(Lock.WRITE); try { + start = System.currentTimeMillis(); + +// String queryStr = "CONSTRUCT { ?s <" + oldProperty.getURI() + "> ?o } WHERE { GRAPH<" + graph + "> { ?s <" + oldProperty.getURI() + "> ?o } } "; +// try { +// renamePropRetractModel = RDFServiceUtils.parseModel(rdfService.sparqlConstructQuery(queryStr, RDFService.ModelSerializationFormat.NTRIPLE), RDFService.ModelSerializationFormat.NTRIPLE); +// } catch (RDFServiceException e) { +// log.error(e,e); +// } +// log.info(System.currentTimeMillis() - start + " to run sparql construct for " + renamePropRetractModel.size() + " statements" ); + start = System.currentTimeMillis(); renamePropRetractModel.add( aboxModel.listStatements( (Resource) null, oldProperty, (RDFNode) null)); + log.info(System.currentTimeMillis() - start + " to list " + renamePropRetractModel.size() + " old statements"); + start = System.currentTimeMillis(); StmtIterator stmItr = renamePropRetractModel.listStatements(); while(stmItr.hasNext()) { Statement tempStatement = stmItr.nextStatement(); @@ -616,8 +632,13 @@ public class ABoxUpdater { newProperty, tempStatement.getObject() ); } + log.info(System.currentTimeMillis() - start + " to make new statements"); + start = System.currentTimeMillis(); aboxModel.remove(renamePropRetractModel); + log.info(System.currentTimeMillis() - start + " to retract old statements"); + start = System.currentTimeMillis(); aboxModel.add(renamePropAddModel); + log.info(System.currentTimeMillis() - start + " to add new statements"); } finally { aboxModel.leaveCriticalSection(); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/KnowledgeBaseUpdater.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/KnowledgeBaseUpdater.java index 90707edca..305937dbc 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/KnowledgeBaseUpdater.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/KnowledgeBaseUpdater.java @@ -96,10 +96,10 @@ public class KnowledgeBaseUpdater { // update ABox data any time log.info("performing SPARQL CONSTRUCT additions"); - performSparqlConstructs(settings.getSparqlConstructAdditionsDir(), settings.getRDFService(), ADD); + //performSparqlConstructs(settings.getSparqlConstructAdditionsDir(), settings.getRDFService(), ADD); log.info("performing SPARQL CONSTRUCT retractions"); - performSparqlConstructs(settings.getSparqlConstructDeletionsDir(), settings.getRDFService(), RETRACT); + //performSparqlConstructs(settings.getSparqlConstructDeletionsDir(), settings.getRDFService(), RETRACT); log.info("\tupdating the abox"); updateABox(changes); @@ -207,9 +207,11 @@ public class KnowledgeBaseUpdater { StmtIterator sit = anonModel.listStatements(); while (sit.hasNext()) { Statement stmt = sit.nextStatement(); + long start = System.currentTimeMillis(); Iterator graphIt = dataset.listNames(); while(graphIt.hasNext()) { String graph = graphIt.next(); + log.info(System.currentTimeMillis() - start + " to get graph"); if(!isUpdatableABoxGraph(graph)) { continue; } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceUtils.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceUtils.java index 1f013e571..c71908418 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceUtils.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceUtils.java @@ -23,6 +23,7 @@ import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService.ModelSerialization import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService.ResultFormat; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceFactory; +import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.logging.LoggingRDFServiceFactory; public class RDFServiceUtils { @@ -34,7 +35,18 @@ public class RDFServiceUtils { public static RDFServiceFactory getRDFServiceFactory(ServletContext context) { Object o = context.getAttribute(RDFSERVICEFACTORY_ATTR); - return (o instanceof RDFServiceFactory) ? (RDFServiceFactory) o : null; + if (o instanceof RDFServiceFactory) { + RDFServiceFactory factory = (RDFServiceFactory) o; + + /* + * Every factory is wrapped in a logger, so we can dynamically + * enable or disable logging. + */ + return new LoggingRDFServiceFactory(context, factory); + } else { + log.error("Expecting an RDFServiceFactory on the context, but found " + o); + return null; + } } public static void setRDFServiceFactory(ServletContext context, diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/logging/LoggingRDFService.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/logging/LoggingRDFService.java new file mode 100644 index 000000000..78ccd8a41 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/logging/LoggingRDFService.java @@ -0,0 +1,125 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.rdfservice.impl.logging; + +import java.io.InputStream; +import java.util.List; + +import javax.servlet.ServletContext; + +import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeListener; +import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeSet; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException; + +/** + * This RDFService wrapper adds instrumentation to the time-consuming methods of + * the inner RDFService. + * + * For the other methods, it just delegates to the inner RDFService. + */ +public class LoggingRDFService implements RDFService { + private final ServletContext ctx; + private final RDFService innerService; + + LoggingRDFService(ServletContext ctx, RDFService innerService) { + this.ctx = ctx; + this.innerService = innerService; + } + + // ---------------------------------------------------------------------- + // Timed methods + // ---------------------------------------------------------------------- + + @Override + public boolean changeSetUpdate(ChangeSet changeSet) + throws RDFServiceException { + try (RDFServiceLogger l = new RDFServiceLogger(ctx, changeSet)) { + return innerService.changeSetUpdate(changeSet); + } + } + + @Override + public InputStream sparqlConstructQuery(String query, + ModelSerializationFormat resultFormat) throws RDFServiceException { + try (RDFServiceLogger l = new RDFServiceLogger(ctx, resultFormat, query)) { + return innerService.sparqlConstructQuery(query, resultFormat); + } + } + + @Override + public InputStream sparqlDescribeQuery(String query, + ModelSerializationFormat resultFormat) throws RDFServiceException { + try (RDFServiceLogger l = new RDFServiceLogger(ctx, resultFormat, query)) { + return innerService.sparqlDescribeQuery(query, resultFormat); + } + } + + @Override + public InputStream sparqlSelectQuery(String query, ResultFormat resultFormat) + throws RDFServiceException { + try (RDFServiceLogger l = new RDFServiceLogger(ctx, resultFormat, query)) { + return innerService.sparqlSelectQuery(query, resultFormat); + } + } + + @Override + public boolean sparqlAskQuery(String query) throws RDFServiceException { + try (RDFServiceLogger l = new RDFServiceLogger(ctx, query)) { + return innerService.sparqlAskQuery(query); + } + } + + // ---------------------------------------------------------------------- + // Untimed methods + // ---------------------------------------------------------------------- + + @Override + public void newIndividual(String individualURI, String individualTypeURI) + throws RDFServiceException { + innerService.newIndividual(individualURI, individualTypeURI); + } + + @Override + public void newIndividual(String individualURI, String individualTypeURI, + String graphURI) throws RDFServiceException { + innerService.newIndividual(individualURI, individualTypeURI, graphURI); + } + + @Override + public List getGraphURIs() throws RDFServiceException { + return innerService.getGraphURIs(); + } + + @Override + public void getGraphMetadata() throws RDFServiceException { + innerService.getGraphMetadata(); + } + + @Override + public String getDefaultWriteGraphURI() throws RDFServiceException { + return innerService.getDefaultWriteGraphURI(); + } + + @Override + public void registerListener(ChangeListener changeListener) + throws RDFServiceException { + innerService.registerListener(changeListener); + } + + @Override + public void unregisterListener(ChangeListener changeListener) + throws RDFServiceException { + innerService.unregisterListener(changeListener); + } + + @Override + public ChangeSet manufactureChangeSet() { + return innerService.manufactureChangeSet(); + } + + @Override + public void close() { + innerService.close(); + } +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/logging/LoggingRDFServiceFactory.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/logging/LoggingRDFServiceFactory.java new file mode 100644 index 000000000..8e97346e4 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/logging/LoggingRDFServiceFactory.java @@ -0,0 +1,48 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.rdfservice.impl.logging; + +import javax.servlet.ServletContext; + +import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeListener; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceFactory; + +/** + * If the RDFServiceFactory is wrapped in this, then all RDFServices will be + * wrapped in a LoggingRDFService. + */ +public class LoggingRDFServiceFactory implements RDFServiceFactory { + private final ServletContext ctx; + private final RDFServiceFactory factory; + + public LoggingRDFServiceFactory(ServletContext ctx, + RDFServiceFactory factory) { + this.ctx = ctx; + this.factory = factory; + } + + @Override + public RDFService getRDFService() { + return new LoggingRDFService(ctx, factory.getRDFService()); + } + + @Override + public RDFService getShortTermRDFService() { + return new LoggingRDFService(ctx, factory.getShortTermRDFService()); + } + + @Override + public void registerListener(ChangeListener changeListener) + throws RDFServiceException { + factory.registerListener(changeListener); + } + + @Override + public void unregisterListener(ChangeListener changeListener) + throws RDFServiceException { + factory.unregisterListener(changeListener); + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/logging/RDFServiceLogger.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/logging/RDFServiceLogger.java new file mode 100644 index 000000000..d529497c7 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/logging/RDFServiceLogger.java @@ -0,0 +1,175 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.rdfservice.impl.logging; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.ListIterator; +import java.util.regex.Pattern; + +import javax.servlet.ServletContext; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties; + +/** + * Writes the log message for the LoggingRDFService. + * + * If not enabled, or if the logging level is insufficient, this does nothing. + * + * If enabled, it checks for restrictions. If there is a restriction pattern + * (regular expression), the a log message will only be printed if one of the + * fully-qualified class names in the stack trace matches that pattern. + * + * If everything passes muster, the constructor will record the time that the + * instance was created. + * + * When close() is called, if a start time was recorded, then a log record is + * produced. This contains the elapsed time, the name of the method, and any + * arguments passed to the constructor. It may also include a stack trace, if + * requested. + * + * The stack trace is abbreviated. It will reach into this class, and will not + * extend past the first reference to the ApplicationFilterChain. Perhaps it + * should be abbreviated further? + */ +public class RDFServiceLogger implements AutoCloseable { + private static final Log log = LogFactory.getLog(RDFServiceLogger.class); + + private static final String PROPERTY_ENABLED = "developer.loggingRDFService.enable"; + private static final String PROPERTY_STACK_TRACE = "developer.loggingRDFService.stackTrace"; + private static final String PROPERTY_RESTRICTION = "developer.loggingRDFService.restriction"; + + private final ServletContext ctx; + private final Object[] args; + + private boolean isEnabled; + private boolean traceRequested; + private Pattern restriction; + + private String methodName; + private List trace = Collections.emptyList(); + + private long startTime; + + public RDFServiceLogger(ServletContext ctx, Object... args) { + this.ctx = ctx; + this.args = args; + + getProperties(); + + if (isEnabled && log.isInfoEnabled()) { + loadStackTrace(); + if (passesRestrictions()) { + this.startTime = System.currentTimeMillis(); + } + } + } + + private void getProperties() { + ConfigurationProperties props = ConfigurationProperties.getBean(ctx); + isEnabled = Boolean.valueOf(props.getProperty(PROPERTY_ENABLED)); + traceRequested = Boolean.valueOf(props + .getProperty(PROPERTY_STACK_TRACE)); + + String restrictionString = props.getProperty(PROPERTY_RESTRICTION); + if (StringUtils.isNotBlank(restrictionString)) { + try { + restriction = Pattern.compile(restrictionString); + } catch (Exception e) { + log.error("Failed to compile the pattern for " + + PROPERTY_RESTRICTION + " = " + restriction + " " + e); + isEnabled = false; + } + } + } + + private void loadStackTrace() { + StackTraceElement[] stack = Thread.currentThread().getStackTrace(); + List list = new ArrayList( + Arrays.asList(stack)); + + trimStackTraceAtBeginning(list); + trimStackTraceAtEnd(list); + + if (list.isEmpty()) { + this.methodName = "UNKNOWN"; + } else { + this.methodName = list.get(0).getMethodName(); + } + + this.trace = list; + } + + private void trimStackTraceAtBeginning(List list) { + ListIterator iter = list.listIterator(); + while (iter.hasNext()) { + StackTraceElement ste = iter.next(); + if (ste.getClassName().equals(LoggingRDFService.class.getName())) { + break; + } else { + iter.remove(); + } + } + } + + private void trimStackTraceAtEnd(List list) { + ListIterator iter = list.listIterator(); + boolean trimming = false; + while (iter.hasNext()) { + StackTraceElement ste = iter.next(); + if (trimming) { + iter.remove(); + } else if (ste.getClassName().contains("ApplicationFilterChain")) { + trimming = true; + } + } + } + + private boolean passesRestrictions() { + if (restriction == null) { + return true; + } + for (StackTraceElement ste : trace) { + if (restriction.matcher(ste.getClassName()).matches()) { + return true; + } + } + return false; + } + + @Override + public void close() { + if (startTime != 0L) { + long endTime = System.currentTimeMillis(); + + float elapsedSeconds = (endTime - startTime) / 1000.0F; + String cleanArgs = Arrays.deepToString(args).replaceAll( + "[\\n\\r\\t]+", " "); + String formattedTrace = formatStackTrace(); + + log.info(String.format("%8.3f %s %s %s", elapsedSeconds, + methodName, cleanArgs, formattedTrace)); + } + } + + private String formatStackTrace() { + StringBuilder sb = new StringBuilder(); + + if (traceRequested) { + for (StackTraceElement ste : trace) { + sb.append(String.format("\n %d %s", ste.getLineNumber(), + ste.getClassName())); + } + sb.append("\n ..."); + } + + return sb.toString(); + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/services/shortview/FakeApplicationOntologyService.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/services/shortview/FakeApplicationOntologyService.java index c3a0b6be4..794837d24 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/services/shortview/FakeApplicationOntologyService.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/services/shortview/FakeApplicationOntologyService.java @@ -439,9 +439,13 @@ public class FakeApplicationOntologyService { * "display model". The query finds a preferred title for the individual. */ private static class FakeVivoPeopleDataGetter extends SparqlQueryDataGetter { - private static final String QUERY_STRING = "SELECT ?uri ?pt WHERE {\n" - + " ?uri ?pt\n" - + "} LIMIT 1"; + private static String QUERY_STRING = "" + + "PREFIX obo: \n" + + "PREFIX vcard: \n" + + "SELECT ?uri ?pt \n" + "WHERE { \n" + + " ?uri obo:ARG_2000028 ?vIndividual . \n" + + " ?vIndividual vcard:hasTitle ?vTitle . \n" + + " ?vTitle vcard:title ?pt . \n" + "} LIMIT 1"; private static final String FAKE_VIVO_PEOPLE_DATA_GETTER_URI = "http://FakeVivoPeopleDataGetter"; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/FileGraphSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/FileGraphSetup.java index a58a52386..aef019ae8 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/FileGraphSetup.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/FileGraphSetup.java @@ -79,7 +79,8 @@ public class FileGraphSetup implements ServletContextListener { cleanupDB(dataset, pathsToURIs(paths, ABOX), ABOX); OntModel aboxBaseModel = baseOms.getABoxModel(); - aboxChanged = readGraphs(paths, maker, ABOX, aboxBaseModel); + // Just update the ABox filegraphs in the DB; don't attach them to a base model. + aboxChanged = readGraphs(paths, maker, ABOX, /* aboxBaseModel */ null); // TBox files paths = getFilegraphPaths(ctx, RDF, TBOX, FILEGRAPH); @@ -108,7 +109,7 @@ public class FileGraphSetup implements ServletContextListener { if ( (aboxChanged || tboxChanged) && !isUpdateRequired(sce.getServletContext())) { log.info("a full recompute of the Abox will be performed because" + " the filegraph abox(s) and/or tbox(s) have changed or are being read for the first time." ); - SimpleReasonerSetup.setRecomputeRequired(sce.getServletContext()); + SimpleReasonerSetup.setRecomputeRequired(sce.getServletContext(), SimpleReasonerSetup.RecomputeMode.BACKGROUND); } } @@ -140,6 +141,14 @@ public class FileGraphSetup implements ServletContextListener { return paths; } + /* + * Reads graphs without using submodels to separate filegraph content from the + * base model. + */ + public boolean readGraphs(Set pathSet, RDFServiceModelMaker dataset, String type, OntModel baseModel) { + return readGraphs(pathSet, dataset, type, baseModel, false); + } + /* * Reads the graphs stored as files in sub-directories of * 1. updates the SDB store to reflect the current contents of the graph. @@ -148,7 +157,7 @@ public class FileGraphSetup implements ServletContextListener { * Note: no connection needs to be maintained between the in-memory copy of the * graph and the DB copy. */ - public boolean readGraphs(Set pathSet, RDFServiceModelMaker dataset, String type, OntModel baseModel) { + public boolean readGraphs(Set pathSet, RDFServiceModelMaker dataset, String type, OntModel baseModel, boolean useSubmodels) { int count = 0; @@ -172,9 +181,14 @@ public class FileGraphSetup implements ServletContextListener { log.warn("Ignoring " + type + " file graph " + p + " because the file extension is unrecognized."); } - if ( !model.isEmpty() ) { - baseModel.addSubModel(model); + if ( !model.isEmpty() && baseModel != null ) { + if (useSubmodels) { + baseModel.addSubModel(model); + } else { + baseModel.add(model); + } log.info("Attached file graph as " + type + " submodel " + p.getFileName()); + } modelChanged = modelChanged | updateGraphInDB(dataset, model, type, p); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/RDFFilesLoader.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/RDFFilesLoader.java index f01b5b244..89b6dbfe6 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/RDFFilesLoader.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/RDFFilesLoader.java @@ -87,14 +87,23 @@ public class RDFFilesLoader { OntModel model) { OntModel everytimeModel = ModelFactory .createOntologyModel(OntModelSpec.OWL_MEM); - Set paths = getPaths(locateHomeDirectory(ctx), RDF, modelPath, - EVERY_TIME); + String home = locateHomeDirectory(ctx); + Set paths = getPaths(home, RDF, modelPath, EVERY_TIME); for (Path p : paths) { + log.info("Loading " + relativePath(p, home)); readOntologyFileIntoModel(p, everytimeModel); } model.addSubModel(everytimeModel); } + private static Path relativePath(Path p, String home) { + try { + return Paths.get(home).relativize(p); + } catch (Exception e) { + return p; + } + } + /** * Create a model from all the RDF files in the specified directory. */ @@ -148,7 +157,7 @@ public class RDFFilesLoader { private static void readOntologyFileIntoModel(Path p, Model model) { String format = getRdfFormat(p); - log.info("Loading "+ p); + log.debug("Loading "+ p); try (InputStream stream = new FileInputStream(p.toFile())) { model.read(stream, null, format); log.debug("...successful"); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/SimpleReasonerSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/SimpleReasonerSetup.java index 43f6fa7d2..4256de861 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/SimpleReasonerSetup.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/SimpleReasonerSetup.java @@ -12,7 +12,6 @@ import java.util.List; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; -import javax.sql.DataSource; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -21,7 +20,6 @@ import com.hp.hpl.jena.query.Dataset; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.vocabulary.OWL; -import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties; import edu.cornell.mannlib.vitro.webapp.dao.ModelAccess; import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; import edu.cornell.mannlib.vitro.webapp.dao.jena.OntModelSelector; @@ -117,7 +115,16 @@ public class SimpleReasonerSetup implements ServletContextListener { assertionsOms.getTBoxModel().register(simpleReasonerTBoxListener); inferencesOms.getTBoxModel().register(simpleReasonerTBoxListener); - log.info("Simple reasoner connected for the ABox"); + RecomputeMode mode = getRecomputeRequired(ctx); + if (RecomputeMode.FOREGROUND.equals(mode)) { + log.info("ABox inference recompute required."); + simpleReasoner.recompute(); + } else if (RecomputeMode.BACKGROUND.equals(mode)) { + log.info("starting ABox inference recompute in a separate thread."); + new Thread( + new ABoxRecomputer( + simpleReasoner),"ABoxRecomputer").start(); + } } catch (Throwable t) { t.printStackTrace(); @@ -179,15 +186,19 @@ public class SimpleReasonerSetup implements ServletContextListener { } } + public enum RecomputeMode { + FOREGROUND, BACKGROUND + } + private static final String RECOMPUTE_REQUIRED_ATTR = SimpleReasonerSetup.class.getName() + ".recomputeRequired"; - public static void setRecomputeRequired(ServletContext ctx) { - ctx.setAttribute(RECOMPUTE_REQUIRED_ATTR, true); + public static void setRecomputeRequired(ServletContext ctx, RecomputeMode mode) { + ctx.setAttribute(RECOMPUTE_REQUIRED_ATTR, mode); } - public static boolean isRecomputeRequired(ServletContext ctx) { - return (ctx.getAttribute(RECOMPUTE_REQUIRED_ATTR) != null); + public static RecomputeMode getRecomputeRequired(ServletContext ctx) { + return (RecomputeMode) ctx.getAttribute(RECOMPUTE_REQUIRED_ATTR); } private static final String MSTCOMPUTE_REQUIRED_ATTR = @@ -249,6 +260,18 @@ public class SimpleReasonerSetup implements ServletContextListener { log.debug("Classnames of reasoner plugins = " + list); return list; - + } + + private class ABoxRecomputer implements Runnable { + + private SimpleReasoner simpleReasoner; + + public ABoxRecomputer(SimpleReasoner simpleReasoner) { + this.simpleReasoner = simpleReasoner; + } + + public void run() { + simpleReasoner.recompute(); + } } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateKnowledgeBase.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateKnowledgeBase.java index 817ce52db..58d2c66d1 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateKnowledgeBase.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateKnowledgeBase.java @@ -157,42 +157,24 @@ public class UpdateKnowledgeBase implements ServletContextListener { ss.fatal(this, "Exception updating knowledge base for ontology changes: ", ioe); } } - - SimpleReasoner simpleReasoner = (SimpleReasoner) sce.getServletContext() - .getAttribute(SimpleReasoner.class.getName()); - if (simpleReasoner != null) { - if ( (requiredUpdate && migrationChangesMade) - || JenaDataSourceSetupBase.isFirstStartup()) { - log.info("ABox inference recompute required."); - simpleReasoner.recompute(); - } else if (SimpleReasonerSetup.isRecomputeRequired(sce.getServletContext()) || migrationChangesMade) { - log.info("starting ABox inference recompute in a separate thread."); - new Thread( - new ABoxRecomputer( - simpleReasoner),"ABoxRecomputer").start(); - } - } + log.info("Simple reasoner connected for the ABox"); + if(JenaDataSourceSetupBase.isFirstStartup() + || (migrationChangesMade && requiredUpdate)) { + SimpleReasonerSetup.setRecomputeRequired( + ctx, SimpleReasonerSetup.RecomputeMode.FOREGROUND); + } else if (migrationChangesMade) { + SimpleReasonerSetup.setRecomputeRequired( + ctx, SimpleReasonerSetup.RecomputeMode.BACKGROUND); + } + } catch (Throwable t){ ss.fatal(this, "Exception updating knowledge base for ontology changes: ", t); } - - } - private class ABoxRecomputer implements Runnable { - private SimpleReasoner simpleReasoner; - - public ABoxRecomputer(SimpleReasoner simpleReasoner) { - this.simpleReasoner = simpleReasoner; - } - - public void run() { - simpleReasoner.recompute(); - } - } /** diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/ApplicationConfigurationOntologyUtils.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/ApplicationConfigurationOntologyUtils.java index 24341a0f4..62a5e5d9f 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/ApplicationConfigurationOntologyUtils.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/ApplicationConfigurationOntologyUtils.java @@ -83,7 +83,7 @@ public class ApplicationConfigurationOntologyUtils { String rangeURI = qsoln.getResource("range").getURI(); if (appropriateDomain(domainRes, subject, tboxModel)) { ObjectProperty faux = opDao.getObjectPropertyByURIs( - opURI, domainURI, rangeURI); + opURI, domainURI, rangeURI, (prop != null) ? prop.clone() : null); if (faux != null) { additionalProps.add(faux); } else { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/DataGetterUtils.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/DataGetterUtils.java index 008a3870f..f8aa99ce1 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/DataGetterUtils.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/DataGetterUtils.java @@ -3,10 +3,7 @@ package edu.cornell.mannlib.vitro.webapp.utils.dataGetter; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; -import java.net.URLEncoder; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -17,7 +14,6 @@ import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.json.JSONArray; import org.json.JSONObject; import com.hp.hpl.jena.query.Query; @@ -35,20 +31,13 @@ import com.hp.hpl.jena.rdf.model.ResourceFactory; import com.hp.hpl.jena.shared.Lock; import com.hp.hpl.jena.vocabulary.OWL; -import edu.cornell.mannlib.vitro.webapp.beans.DataProperty; -import edu.cornell.mannlib.vitro.webapp.beans.Individual; import edu.cornell.mannlib.vitro.webapp.beans.VClass; import edu.cornell.mannlib.vitro.webapp.beans.VClassGroup; -import edu.cornell.mannlib.vitro.webapp.controller.Controllers; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.IndividualListController; -import edu.cornell.mannlib.vitro.webapp.controller.freemarker.IndividualListController.PageRecord; -import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; -import edu.cornell.mannlib.vitro.webapp.controller.json.JsonServlet; import edu.cornell.mannlib.vitro.webapp.dao.DisplayVocabulary; import edu.cornell.mannlib.vitro.webapp.dao.VClassGroupsForRequest; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; -import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; import edu.cornell.mannlib.vitro.webapp.dao.jena.VClassGroupCache; @@ -324,123 +313,6 @@ public class DataGetterUtils { return classGroupUri; } - /** - * Process results related to VClass or vclasses. Handles both single and multiple vclasses being sent. - */ - public static JSONObject processVclassResultsJSON(Map map, VitroRequest vreq, boolean multipleVclasses) { - JSONObject rObj = new JSONObject(); - VClass vclass=null; - - try { - - // Properties from ontologies used by VIVO - should not be in vitro - DataProperty fNameDp = (new DataProperty()); - fNameDp.setURI("http://xmlns.com/foaf/0.1/firstName"); - DataProperty lNameDp = (new DataProperty()); - lNameDp.setURI("http://xmlns.com/foaf/0.1/lastName"); - DataProperty preferredTitleDp = (new DataProperty()); - preferredTitleDp.setURI("http://vivoweb.org/ontology/core#preferredTitle"); - - if( log.isDebugEnabled() ){ - @SuppressWarnings("unchecked") - Enumeration e = vreq.getParameterNames(); - while(e.hasMoreElements()){ - String name = e.nextElement(); - log.debug("parameter: " + name); - for( String value : vreq.getParameterValues(name) ){ - log.debug("value for " + name + ": '" + value + "'"); - } - } - } - - //need an unfiltered dao to get firstnames and lastnames - WebappDaoFactory fullWdf = vreq.getUnfilteredWebappDaoFactory(); - - String[] vitroClassIdStr = vreq.getParameterValues("vclassId"); - if ( vitroClassIdStr != null && vitroClassIdStr.length > 0){ - for(String vclassId: vitroClassIdStr) { - vclass = vreq.getWebappDaoFactory().getVClassDao().getVClassByURI(vclassId); - if (vclass == null) { - log.error("Couldn't retrieve vclass "); - throw new Exception ("Class " + vclassId + " not found"); - } - } - }else{ - log.error("parameter vclassId URI parameter expected "); - throw new Exception("parameter vclassId URI parameter expected "); - } - List vclassIds = Arrays.asList(vitroClassIdStr); - //if single vclass expected, then include vclass. This relates to what the expected behavior is, not size of list - if(!multipleVclasses) { - //currently used for ClassGroupPage - rObj.put("vclass", - new JSONObject().put("URI",vclass.getURI()) - .put("name",vclass.getName())); - } else { - //For now, utilize very last VClass (assume that that is the one to be employed) - //TODO: Find more general way of dealing with this - //put multiple ones in? - if(vclassIds.size() > 0) { - int numberVClasses = vclassIds.size(); - vclass = vreq.getWebappDaoFactory().getVClassDao().getVClassByURI(vclassIds.get(numberVClasses - 1)); - rObj.put("vclass", new JSONObject().put("URI",vclass.getURI()) - .put("name",vclass.getName())); - } - // rObj.put("vclasses", new JSONObject().put("URIs",vitroClassIdStr) - // .put("name",vclass.getName())); - } - if (vclass != null) { - - rObj.put("totalCount", map.get("totalCount")); - rObj.put("alpha", map.get("alpha")); - - List inds = (List)map.get("entities"); - log.debug("Number of individuals returned from request: " + inds.size()); - JSONArray jInds = new JSONArray(); - for(Individual ind : inds ){ - JSONObject jo = new JSONObject(); - jo.put("URI", ind.getURI()); - jo.put("label",ind.getRdfsLabel()); - jo.put("name",ind.getName()); - jo.put("thumbUrl", ind.getThumbUrl()); - jo.put("imageUrl", ind.getImageUrl()); - jo.put("profileUrl", UrlBuilder.getIndividualProfileUrl(ind, vreq)); - - jo.put("mostSpecificTypes", JsonServlet.getMostSpecificTypes(ind,fullWdf)); - jo.put("preferredTitle", JsonServlet.getDataPropertyValue(ind, preferredTitleDp, fullWdf)); - - jInds.put(jo); - } - rObj.put("individuals", jInds); - - JSONArray wpages = new JSONArray(); - //Made sure that PageRecord here is SolrIndividualListController not IndividualListController - List pages = (List)map.get("pages"); - for( PageRecord pr: pages ){ - JSONObject p = new JSONObject(); - p.put("text", pr.text); - p.put("param", pr.param); - p.put("index", pr.index); - wpages.put( p ); - } - rObj.put("pages",wpages); - - JSONArray jletters = new JSONArray(); - List letters = Controllers.getLetters(); - for( String s : letters){ - JSONObject jo = new JSONObject(); - jo.put("text", s); - jo.put("param", "alpha=" + URLEncoder.encode(s, "UTF-8")); - jletters.put( jo ); - } - rObj.put("letters", jletters); - } - } catch(Exception ex) { - log.error("Error occurred in processing JSON object", ex); - } - return rObj; - } - private static final String forClassGroupURI = "<" + DisplayVocabulary.FOR_CLASSGROUP + ">"; private static final String classGroupForDataGetterQuery = diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/IndividualsForClassesDataGetter.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/IndividualsForClassesDataGetter.java index 1788e3fa4..45c4a3eba 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/IndividualsForClassesDataGetter.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/IndividualsForClassesDataGetter.java @@ -353,14 +353,15 @@ public class IndividualsForClassesDataGetter extends DataGetterBase implements D public String getDataServiceUrl() { return UrlBuilder.getUrl("/dataservice?getRenderedSolrIndividualsByVClass=1&vclassId="); } + /** * For processig of JSONObject */ - public JSONObject convertToJSON(Map map, VitroRequest vreq) { - JSONObject rObj = DataGetterUtils.processVclassResultsJSON(map, vreq, true); + public JSONObject convertToJSON(Map dataMap, VitroRequest vreq) { + JSONObject rObj = null; return rObj; } - + protected static void setAllClassCountsToZero(VClassGroup vcg){ for(VClass vc : vcg){ vc.setEntityCount(0); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/SolrIndividualsDataGetter.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/SolrIndividualsDataGetter.java index 278b8c645..cb5e89c67 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/SolrIndividualsDataGetter.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/SolrIndividualsDataGetter.java @@ -3,9 +3,7 @@ package edu.cornell.mannlib.vitro.webapp.utils.dataGetter; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; @@ -23,7 +21,6 @@ import com.hp.hpl.jena.query.QuerySolutionMap; import com.hp.hpl.jena.query.ResultSet; import com.hp.hpl.jena.rdf.model.Literal; import com.hp.hpl.jena.rdf.model.Model; -import com.hp.hpl.jena.rdf.model.RDFNode; import com.hp.hpl.jena.rdf.model.Resource; import com.hp.hpl.jena.rdf.model.ResourceFactory; import com.hp.hpl.jena.shared.Lock; @@ -33,8 +30,9 @@ import edu.cornell.mannlib.vitro.webapp.beans.VClass; import edu.cornell.mannlib.vitro.webapp.beans.VClassGroup; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.IndividualListController; -import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.IndividualListController.SearchException; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; +import edu.cornell.mannlib.vitro.webapp.controller.individuallist.IndividualListResults; import edu.cornell.mannlib.vitro.webapp.dao.DisplayVocabulary; import edu.cornell.mannlib.vitro.webapp.utils.solr.SolrQueryUtils; import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individuallist.ListedIndividual; @@ -174,16 +172,15 @@ public class SolrIndividualsDataGetter extends DataGetterBase implements DataGet try { String alpha = SolrQueryUtils.getAlphaParameter(vreq); int page = SolrQueryUtils.getPageParameter(vreq); - Map map = IndividualListController.getResultsForVClass( + IndividualListResults vcResults = IndividualListController.getResultsForVClass( vclass.getURI(), page, alpha, vreq.getWebappDaoFactory().getIndividualDao(), vreq.getSession().getServletContext()); - body.putAll(map); + body.putAll(vcResults.asFreemarkerMap()); - @SuppressWarnings("unchecked") - List inds = (List)map.get("entities"); + List inds = vcResults.getEntities(); List indsTm = new ArrayList(); if (inds != null) { for ( Individual ind : inds ) { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/solr/SolrQueryUtils.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/solr/SolrQueryUtils.java index 608ae0efc..924a5cd58 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/solr/SolrQueryUtils.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/solr/SolrQueryUtils.java @@ -4,8 +4,6 @@ package edu.cornell.mannlib.vitro.webapp.utils.solr; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Map; @@ -20,9 +18,7 @@ import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.client.solrj.response.QueryResponse; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; -import edu.cornell.mannlib.vitro.webapp.controller.freemarker.IndividualListController; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.IndividualListQueryResults; -import edu.cornell.mannlib.vitro.webapp.controller.freemarker.IndividualListController.SearchException; import edu.cornell.mannlib.vitro.webapp.dao.IndividualDao; import edu.cornell.mannlib.vitro.webapp.search.VitroSearchTermNames; import edu.cornell.mannlib.vitro.webapp.search.solr.SolrSetup; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/BaseIndividualTemplateModel.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/BaseIndividualTemplateModel.java index bed1d0daf..0d8901251 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/BaseIndividualTemplateModel.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/BaseIndividualTemplateModel.java @@ -2,6 +2,10 @@ package edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual; +import static edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestActionConstants.SOME_LITERAL; +import static edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestActionConstants.SOME_PREDICATE; +import static edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestActionConstants.SOME_URI; + import java.util.Collection; import java.util.List; import java.util.Map; @@ -16,7 +20,6 @@ import edu.cornell.mannlib.vedit.beans.LoginStatusBean; import edu.cornell.mannlib.vitro.webapp.auth.permissions.SimplePermission; import edu.cornell.mannlib.vitro.webapp.auth.policy.PolicyHelper; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.Actions; -import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestActionConstants; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.AddDataPropertyStatement; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.AddObjectPropertyStatement; import edu.cornell.mannlib.vitro.webapp.beans.DataPropertyStatement; @@ -116,11 +119,10 @@ public abstract class BaseIndividualTemplateModel extends BaseTemplateModel { public boolean isEditable() { AddDataPropertyStatement adps = new AddDataPropertyStatement( vreq.getJenaOntModel(), individual.getURI(), - RequestActionConstants.SOME_URI); + SOME_URI, SOME_LITERAL); AddObjectPropertyStatement aops = new AddObjectPropertyStatement( vreq.getJenaOntModel(), individual.getURI(), - RequestActionConstants.SOME_PREDICATE, - RequestActionConstants.SOME_URI); + SOME_PREDICATE, SOME_URI); return PolicyHelper.isAuthorizedForActions(vreq, new Actions(adps).or(aops)); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/DataPropertyTemplateModel.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/DataPropertyTemplateModel.java index 621c35998..0011726e4 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/DataPropertyTemplateModel.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/DataPropertyTemplateModel.java @@ -2,6 +2,8 @@ package edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual; +import static edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestActionConstants.SOME_LITERAL; + import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -118,7 +120,7 @@ public class DataPropertyTemplateModel extends PropertyTemplateModel { // Determine whether a new statement can be added RequestedAction action = new AddDataPropertyStatement( - vreq.getJenaOntModel(), subjectUri, propertyUri); + vreq.getJenaOntModel(), subjectUri, propertyUri, SOME_LITERAL); if ( ! PolicyHelper.isAuthorizedForActions(vreq, action) ) { return; } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/GroupedPropertyList.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/GroupedPropertyList.java index cedb9bde0..a009847c9 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/GroupedPropertyList.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/GroupedPropertyList.java @@ -6,8 +6,10 @@ import java.util.ArrayList; import java.util.Collection; 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; @@ -73,13 +75,23 @@ public class GroupedPropertyList extends BaseTemplateModel { // so we cannot just rely on getting that list. List populatedObjectPropertyList = subject .getPopulatedObjectPropertyList(); + + Map> populatedObjTypes = makePopulatedObjTypeMap( + populatedObjectPropertyList); + + // save applicable ranges before deduping to filter later + populatedObjectPropertyList = dedupe(populatedObjectPropertyList); Collection additions = ApplicationConfigurationOntologyUtils .getAdditionalFauxSubpropertiesForList( populatedObjectPropertyList, subject, vreq); + + additions = filterAdditions(additions, populatedObjTypes); + if (log.isDebugEnabled()) { for (ObjectProperty t : additions) { - log.debug(t.getDomainPublic() + " " + t.getGroupURI() + " domain " + t.getDomainVClassURI()); + log.debug(t.getDomainPublic() + " " + t.getGroupURI() + " domain " + + t.getDomainVClassURI()); } log.debug("Added " + additions.size() + " properties due to application configuration ontology"); @@ -110,12 +122,15 @@ public class GroupedPropertyList extends BaseTemplateModel { mergeAllPossibleDataProperties(propertyList); } - propertyList = correctLanguageForProperties(propertyList); + if (editing) { + propertyList = correctLanguageForProperties(propertyList); + } + sort(propertyList); // Put the list into groups List propertyGroupList = addPropertiesToGroups(propertyList); - + // Build the template data model from the groupList groups = new ArrayList( propertyGroupList.size()); @@ -131,6 +146,34 @@ public class GroupedPropertyList extends BaseTemplateModel { } + private Map> makePopulatedObjTypeMap(List props) { + Map> map = new HashMap>(); + for (ObjectProperty prop : props) { + if(prop.getRangeVClassURI() != null) { + List typeList = map.get(prop.getURI()); + if(typeList == null) { + typeList = new ArrayList(); + map.put(prop.getURI(), typeList); + } + typeList.add(prop.getRangeVClassURI()); + } + } + return map; + } + + private List filterAdditions(Collection additions, + Map> populatedObjTypes) { + List filteredAdditions = new ArrayList(); + for (ObjectProperty prop : additions) { + List allowedTypes = populatedObjTypes.get(prop.getURI()); + if(allowedTypes != null && (allowedTypes.contains(prop.getRangeVClassURI()) + || allowedTypes.contains(prop.getRangeEntityURI()) ) ) { + filteredAdditions.add(prop); + } + } + return filteredAdditions; + } + // Use the language-filtering WebappDaoFactory to get the right version of // each property. When editing, the methods that add to the property list // are blissfully (and intentionally) language-unaware. @@ -187,6 +230,19 @@ public class GroupedPropertyList extends BaseTemplateModel { } } } + + //assumes sorted list + protected List dedupe(List propList) { + List dedupedList = new ArrayList(); + String uriRegister = ""; + for (ObjectProperty prop : propList) { + if(!uriRegister.equals(prop.getURI())) { + uriRegister = prop.getURI(); + dedupedList.add(prop); + } + } + return dedupedList; + } protected void sort(List propertyList) { try { @@ -325,10 +381,12 @@ public class GroupedPropertyList extends BaseTemplateModel { // Get the property groups PropertyGroupDao pgDao = wdf.getPropertyGroupDao(); + long start = System.currentTimeMillis(); List groupList = pgDao.getPublicGroups(false); // may be returned empty but not null // To test no property groups defined, use: // List groupList = new ArrayList(); + start = System.currentTimeMillis(); int groupCount = groupList.size(); /* @@ -353,7 +411,7 @@ public class GroupedPropertyList extends BaseTemplateModel { */ PropertyGroup groupForUnassignedProperties = pgDao .createDummyPropertyGroup("", MAX_GROUP_DISPLAY_RANK); - + if (groupCount > 1) { try { Collections.sort(groupList); @@ -377,6 +435,7 @@ public class GroupedPropertyList extends BaseTemplateModel { log.error("Exception on trying to prune unpopulated groups from group list: " + ex.getMessage()); } + log.debug(System.currentTimeMillis() - start + " to remove unpopulated groups"); // If the group for unassigned properties is populated, add it to the // group list. diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/PropertyGroupTemplateModel.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/PropertyGroupTemplateModel.java index 10b5ce4d9..b50469188 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/PropertyGroupTemplateModel.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/PropertyGroupTemplateModel.java @@ -8,6 +8,9 @@ import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import edu.cornell.mannlib.vitro.webapp.auth.policy.PolicyHelper; +import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.display.DisplayObjectProperty; +import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestedAction; import edu.cornell.mannlib.vitro.webapp.beans.DataProperty; import edu.cornell.mannlib.vitro.webapp.beans.Individual; import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty; @@ -37,6 +40,10 @@ public class PropertyGroupTemplateModel extends BaseTemplateModel { for (Property p : propertyList) { if (p instanceof ObjectProperty) { ObjectProperty op = (ObjectProperty) p; + RequestedAction dop = new DisplayObjectProperty(op); + if (!PolicyHelper.isAuthorizedForActions(vreq, dop)) { + continue; + } ObjectPropertyTemplateModel tm = ObjectPropertyTemplateModel.getObjectPropertyTemplateModel( op, subject, vreq, editing, populatedObjectPropertyList); if (!tm.isEmpty() || (editing && !tm.getAddUrl().isEmpty())) { diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/auth/policy/SelfEditingPolicyTest.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/auth/policy/SelfEditingPolicyTest.java index 9459e6ca5..365983216 100644 --- a/webapp/test/edu/cornell/mannlib/vitro/webapp/auth/policy/SelfEditingPolicyTest.java +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/auth/policy/SelfEditingPolicyTest.java @@ -4,6 +4,7 @@ package edu.cornell.mannlib.vitro.webapp.auth.policy; import static edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.Authorization.AUTHORIZED; import static edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.Authorization.INCONCLUSIVE; +import static edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestActionConstants.SOME_LITERAL; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertNull; @@ -31,6 +32,7 @@ import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.admin.RebuildTextIn import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.admin.RemoveUser; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.admin.ServerStatus; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.admin.UpdateTextIndex; +import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestActionConstants; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestedAction; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ontology.CreateOwlClass; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ontology.DefineDataProperty; @@ -125,19 +127,19 @@ public class SelfEditingPolicyTest extends AbstractTestClass { // now with dataprop statements whatToAuth = new AddDataPropertyStatement(ontModel, SELFEDITOR_URI, - "http://mannlib.cornell.edu/bad#prp234"); + "http://mannlib.cornell.edu/bad#prp234", SOME_LITERAL); assertDecision(INCONCLUSIVE, policy.isAuthorized(ids, whatToAuth)); whatToAuth = new AddDataPropertyStatement(ontModel, SELFEDITOR_URI, - "http://mannlib.cornell.edu/bad#prp999"); + "http://mannlib.cornell.edu/bad#prp999", SOME_LITERAL); assertDecision(INCONCLUSIVE, policy.isAuthorized(ids, whatToAuth)); whatToAuth = new AddDataPropertyStatement(ontModel, SELFEDITOR_URI, - SAFE_PREDICATE.getURI()); + SAFE_PREDICATE.getURI(), SOME_LITERAL); assertDecision(AUTHORIZED, policy.isAuthorized(ids, whatToAuth)); whatToAuth = new AddDataPropertyStatement(ontModel, SELFEDITOR_URI, - UNSAFE_PREDICATE.getURI()); + UNSAFE_PREDICATE.getURI(), SOME_LITERAL); assertDecision(INCONCLUSIVE, policy.isAuthorized(ids, whatToAuth)); } @@ -219,16 +221,16 @@ public class SelfEditingPolicyTest extends AbstractTestClass { // @Test public void testVisitIdentifierBundleEditDataPropStmt() { - whatToAuth = new EditDataPropertyStatement(ontModel, SELFEDITOR_URI,SAFE_PREDICATE.getURI()); + whatToAuth = new EditDataPropertyStatement(ontModel, SELFEDITOR_URI,SAFE_PREDICATE.getURI(), SOME_LITERAL); assertDecision(AUTHORIZED, policy.isAuthorized(ids, whatToAuth)); - whatToAuth = new EditDataPropertyStatement(ontModel, SELFEDITOR_URI, UNSAFE_PREDICATE.getURI()); + whatToAuth = new EditDataPropertyStatement(ontModel, SELFEDITOR_URI, UNSAFE_PREDICATE.getURI(), SOME_LITERAL); assertDecision(INCONCLUSIVE, policy.isAuthorized(ids, whatToAuth)); - whatToAuth = new EditDataPropertyStatement(ontModel, UNSAFE_RESOURCE, SAFE_PREDICATE.getURI()); + whatToAuth = new EditDataPropertyStatement(ontModel, UNSAFE_RESOURCE, SAFE_PREDICATE.getURI(), SOME_LITERAL); assertDecision(INCONCLUSIVE, policy.isAuthorized(ids, whatToAuth)); - whatToAuth = new EditDataPropertyStatement(ontModel, SAFE_RESOURCE, SAFE_PREDICATE.getURI()); + whatToAuth = new EditDataPropertyStatement(ontModel, SAFE_RESOURCE, SAFE_PREDICATE.getURI(), SOME_LITERAL); assertDecision(INCONCLUSIVE, policy.isAuthorized(ids, whatToAuth)); } @@ -288,7 +290,7 @@ public class SelfEditingPolicyTest extends AbstractTestClass { public void twoSEIsFindDataPropertySubject() { setUpTwoSEIs(); - whatToAuth = new EditDataPropertyStatement(ontModel, SELFEDITOR_URI, SAFE_PREDICATE.getURI()); + whatToAuth = new EditDataPropertyStatement(ontModel, SELFEDITOR_URI, SAFE_PREDICATE.getURI(), SOME_LITERAL); assertDecision(AUTHORIZED, policy.isAuthorized(ids, whatToAuth)); } @@ -296,7 +298,7 @@ public class SelfEditingPolicyTest extends AbstractTestClass { public void twoSEIsDontFindInDataProperty() { setUpTwoSEIs(); - whatToAuth = new EditDataPropertyStatement(ontModel, SAFE_RESOURCE, SAFE_PREDICATE.getURI()); + whatToAuth = new EditDataPropertyStatement(ontModel, SAFE_RESOURCE, SAFE_PREDICATE.getURI(), SOME_LITERAL); assertDecision(INCONCLUSIVE, policy.isAuthorized(ids, whatToAuth)); } diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/auth/policy/SelfEditingPolicy_2_Test.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/auth/policy/SelfEditingPolicy_2_Test.java index aa5aa6ac0..f1448b0e4 100644 --- a/webapp/test/edu/cornell/mannlib/vitro/webapp/auth/policy/SelfEditingPolicy_2_Test.java +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/auth/policy/SelfEditingPolicy_2_Test.java @@ -2,6 +2,8 @@ package edu.cornell.mannlib.vitro.webapp.auth.policy; +import static edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestActionConstants.SOME_LITERAL; + import java.io.InputStream; import org.apache.commons.logging.Log; @@ -306,7 +308,7 @@ public class SelfEditingPolicy_2_Test extends AbstractTestClass { private void assertEditDataPropStmt(String individualURI, String datapropURI, String data, Authorization expectedAuthorization) { EditDataPropertyStatement whatToAuth = new EditDataPropertyStatement( - ontModel, individualURI, datapropURI); + ontModel, individualURI, datapropURI, SOME_LITERAL); PolicyDecision dec = policy.isAuthorized(ids, whatToAuth); log.debug(dec); Assert.assertNotNull(dec); diff --git a/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/dao/ObjectPropertyDaoStub.java b/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/dao/ObjectPropertyDaoStub.java index 54ba17477..dacbdbc88 100644 --- a/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/dao/ObjectPropertyDaoStub.java +++ b/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/dao/ObjectPropertyDaoStub.java @@ -67,7 +67,14 @@ public class ObjectPropertyDaoStub implements ObjectPropertyDao { } @Override - public ObjectProperty getObjectPropertyByURIs(String objectPropertyURI, String domainURI, String rangeURI) { + public ObjectProperty getObjectPropertyByURIs(String objectPropertyURI, + String domainURI, String rangeURI) { + return getObjectPropertyByURI(objectPropertyURI); + } + + @Override + public ObjectProperty getObjectPropertyByURIs(String objectPropertyURI, + String domainURI, String rangeURI, ObjectProperty base) { return getObjectPropertyByURI(objectPropertyURI); } diff --git a/webapp/web/i18n/all.properties b/webapp/web/i18n/all.properties index 193c8a2e7..38912ca5f 100644 --- a/webapp/web/i18n/all.properties +++ b/webapp/web/i18n/all.properties @@ -134,10 +134,6 @@ submit_add_new_account = Add new account account_created = Your {0} account has been created. account_created_subject = Your {0} account has been created. -account_created_email_html = @@file files/accountCreatedEmail.html -account_created_email_text = @@file files/accountCreatedEmail.txt -account_created_external_email_html = @@file files/accountCreatedExternalOnlyEmail.html -account_created_external_email_text = @@file files/accountCreatedExternalOnlyEmail.txt confirm_delete_account_singular = Are you sure you want to delete this account? confirm_delete_account_plural = Are you sure you want to delete these accounts? @@ -156,21 +152,11 @@ select_associated_profile = Select the associated profile create_associated_profile = Create the associated profile email_changed_subject = Your {0} email account has been changed. -email_changed_html = @@file files/accountEmailChanged.html -email_changed_text = @@file files/accountEmailChanged.txt create_your_password = Create your Password password_created_subject = Your {0} password has successfully been created. -password_created_email_html = @@file files/passwordCreatedEmail.html -password_created_email_text = @@file files/passwordCreatedEmail.txt - password_reset_pending_subject = {0} reset password request -password_reset_pending_email_html = @@file files/passwordResetPending.html -password_reset_pending_email_text = @@file files/passwordResetPending.txt - password_reset_complete_subject = Your {0} password changed. -password_reset_complete_email_html = @@file files/passwordResetComplete.html -password_reset_complete_email_text = @@file files/passwordResetComplete.txt reset_your_password = Reset your Password first_time_login = First time log in @@ -193,8 +179,6 @@ password_saved_please_login = Your password has been saved. Please log in. please_provide_contact_information = Please provide your contact information to finish creating your account. first_time_login_note = Note: An email will be sent to the address entered above notifying \ that an account has been created. -first_time_external_email_html = @@file files/accountFirstTimeExternal.html -first_time_external_email_text = @@file files/accountFirstTimeExternal.txt myAccount_heading = My account myAccount_confirm_changes = Your changes have been saved. diff --git a/webapp/web/i18n/files/accountCreatedEmail.html b/webapp/web/i18n/files/accountCreatedEmail.html deleted file mode 100644 index 96b84d727..000000000 --- a/webapp/web/i18n/files/accountCreatedEmail.html +++ /dev/null @@ -1,39 +0,0 @@ - - - {1} - - -

    - {2} {3} -

    - -

    - Congratulations! -

    - -

    - We have created your new account on {0}, associated with {4}. -

    - -

    - If you did not request this new account you can safely ignore this email. - This request will expire if not acted upon for 30 days. -

    - -

    - Click the link below to create your password for your new account using our secure server. -

    - -

    - {5} -

    - -

    - If the link above doesn't work, you can copy and paste the link directly into your browser's address bar. -

    - -

    - Thanks! -

    - - diff --git a/webapp/web/i18n/files/accountCreatedEmail.txt b/webapp/web/i18n/files/accountCreatedEmail.txt deleted file mode 100644 index 4dcd900c8..000000000 --- a/webapp/web/i18n/files/accountCreatedEmail.txt +++ /dev/null @@ -1,17 +0,0 @@ -{2} {3} - -Congratulations! - -We have created your new account on {0}, -associated with {4}. - -If you did not request this new account you can safely ignore this email. -This request will expire if not acted upon for 30 days. - -Paste the link below into your browser's address bar to create your password -for your new account using our secure server. - -{5} - -Thanks! - diff --git a/webapp/web/i18n/files/accountCreatedExternalOnlyEmail.html b/webapp/web/i18n/files/accountCreatedExternalOnlyEmail.html deleted file mode 100644 index 164bf87ae..000000000 --- a/webapp/web/i18n/files/accountCreatedExternalOnlyEmail.html +++ /dev/null @@ -1,22 +0,0 @@ - - - ${1} - - -

    - ${2} ${3} -

    - -

    - Congratulations! -

    - -

    - We have created your new VIVO account associated with ${4}. -

    - -

    - Thanks! -

    - - diff --git a/webapp/web/i18n/files/accountCreatedExternalOnlyEmail.txt b/webapp/web/i18n/files/accountCreatedExternalOnlyEmail.txt deleted file mode 100644 index c55cb3f9a..000000000 --- a/webapp/web/i18n/files/accountCreatedExternalOnlyEmail.txt +++ /dev/null @@ -1,9 +0,0 @@ -${2} ${3} - -Congratulations! - -We have created your new VIVO account associated with -${4}. - -Thanks! - diff --git a/webapp/web/i18n/files/accountEmailChanged.html b/webapp/web/i18n/files/accountEmailChanged.html deleted file mode 100644 index 5a2e51e50..000000000 --- a/webapp/web/i18n/files/accountEmailChanged.html +++ /dev/null @@ -1,19 +0,0 @@ - - - {1} - - -

    - Hi, {2} ${3} -

    - -

    - You recently changed the email address associated with - ${2} ${3} -

    - -

    - Thank you. -

    - - diff --git a/webapp/web/i18n/files/accountEmailChanged.txt b/webapp/web/i18n/files/accountEmailChanged.txt deleted file mode 100644 index 5f560dca1..000000000 --- a/webapp/web/i18n/files/accountEmailChanged.txt +++ /dev/null @@ -1,6 +0,0 @@ -Hi, {2} {3} - -You recently changed the email address associated with -{2} {3} - -Thank you. diff --git a/webapp/web/i18n/files/accountFirstTimeExternal.html b/webapp/web/i18n/files/accountFirstTimeExternal.html deleted file mode 100644 index 61dca7f3c..000000000 --- a/webapp/web/i18n/files/accountFirstTimeExternal.html +++ /dev/null @@ -1,22 +0,0 @@ - - - {1} - - -

    - {2} {3} -

    - -

    - Congratulations! -

    - -

    - We have created your new {0} account associated with {4}. -

    - -

    - Thanks! -

    - - diff --git a/webapp/web/i18n/files/accountFirstTimeExternal.txt b/webapp/web/i18n/files/accountFirstTimeExternal.txt deleted file mode 100644 index 1cb60552b..000000000 --- a/webapp/web/i18n/files/accountFirstTimeExternal.txt +++ /dev/null @@ -1,8 +0,0 @@ -{2} {3} - -Congratulations! - -We have created your new {0} account associated with -{4} - -Thanks! diff --git a/webapp/web/i18n/files/passwordCreatedEmail.html b/webapp/web/i18n/files/passwordCreatedEmail.html deleted file mode 100644 index 15cf8bb0d..000000000 --- a/webapp/web/i18n/files/passwordCreatedEmail.html +++ /dev/null @@ -1,22 +0,0 @@ - - - {1} - - -

    - {2} {3} -

    - -

    - Password successfully created. -

    - -

    - Your new password associated with {4} has been created. -

    - -

    - Thank you. -

    - - diff --git a/webapp/web/i18n/files/passwordCreatedEmail.txt b/webapp/web/i18n/files/passwordCreatedEmail.txt deleted file mode 100644 index dbd9e9da0..000000000 --- a/webapp/web/i18n/files/passwordCreatedEmail.txt +++ /dev/null @@ -1,8 +0,0 @@ -{2} {3} - -Password successfully created. - -Your new password associated with {4} -has been created. - -Thank you. diff --git a/webapp/web/i18n/files/passwordRequestPending.html b/webapp/web/i18n/files/passwordRequestPending.html deleted file mode 100644 index bd20cb392..000000000 --- a/webapp/web/i18n/files/passwordRequestPending.html +++ /dev/null @@ -1,34 +0,0 @@ - - - {1} - - -

    - Dear {2} {3}: -

    - -

    - We have received a request to reset the password for your {0} account ({4}). -

    - -

    - Please follow the instructions below to proceed with your password reset. -

    - -

    - If you did not request this new account you can safely ignore this email. - This request will expire if not acted upon within 30 days. -

    - -

    - Click on the link below or paste it into your browser's address bar to reset your password - using our secure server. -

    - -

    - {5} -

    - -

    Thank you!

    - - diff --git a/webapp/web/i18n/files/passwordRequestPending.txt b/webapp/web/i18n/files/passwordRequestPending.txt deleted file mode 100644 index e8c92b5f2..000000000 --- a/webapp/web/i18n/files/passwordRequestPending.txt +++ /dev/null @@ -1,16 +0,0 @@ -Dear {2} {3}: - -We have received a request to reset the password for your {0} account -({4}). - -Please follow the instructions below to proceed with your password reset. - -If you did not request this new account you can safely ignore this email. -This request will expire if not acted upon within 30 days. - -Paste the link below into your browser's address bar to reset your password -using our secure server. - -{5} - -Thank you! diff --git a/webapp/web/i18n/files/passwordResetComplete.html b/webapp/web/i18n/files/passwordResetComplete.html deleted file mode 100644 index bfa756f15..000000000 --- a/webapp/web/i18n/files/passwordResetComplete.html +++ /dev/null @@ -1,22 +0,0 @@ - - - {1} - - -

    - {2} {3} -

    - -

    - Password successfully changed. -

    - -

    - Your new password associated with {4} has been changed. -

    - -

    - Thank you. -

    - - diff --git a/webapp/web/i18n/files/passwordResetComplete.txt b/webapp/web/i18n/files/passwordResetComplete.txt deleted file mode 100644 index 99503085c..000000000 --- a/webapp/web/i18n/files/passwordResetComplete.txt +++ /dev/null @@ -1,8 +0,0 @@ -{2} {3} - -Password successfully changed. - -Your new password associated with {4} -has been changed. - -Thank you. diff --git a/webapp/web/i18n/files/passwordResetPending.html b/webapp/web/i18n/files/passwordResetPending.html deleted file mode 100644 index bd20cb392..000000000 --- a/webapp/web/i18n/files/passwordResetPending.html +++ /dev/null @@ -1,34 +0,0 @@ - - - {1} - - -

    - Dear {2} {3}: -

    - -

    - We have received a request to reset the password for your {0} account ({4}). -

    - -

    - Please follow the instructions below to proceed with your password reset. -

    - -

    - If you did not request this new account you can safely ignore this email. - This request will expire if not acted upon within 30 days. -

    - -

    - Click on the link below or paste it into your browser's address bar to reset your password - using our secure server. -

    - -

    - {5} -

    - -

    Thank you!

    - - diff --git a/webapp/web/i18n/files/passwordResetPending.txt b/webapp/web/i18n/files/passwordResetPending.txt deleted file mode 100644 index 5d34952f3..000000000 --- a/webapp/web/i18n/files/passwordResetPending.txt +++ /dev/null @@ -1,16 +0,0 @@ -Dear {2} {3}: - -We have received a request to reset the password for your {0} account -({4}). - -Please follow the instructions below to proceed with your password reset. - -If you did not request this new account you can safely ignore this email. -This request will expire if not acted upon within 30 days. - -Paste the link below into your browser's address bar to reset your password -using our secure server. - -{5} - -Thank you! \ No newline at end of file diff --git a/webapp/web/templates/freemarker/body/accounts/userAccounts-acctCreatedEmail.ftl b/webapp/web/templates/freemarker/body/accounts/userAccounts-acctCreatedEmail.ftl index b02c2e415..ce80a5481 100644 --- a/webapp/web/templates/freemarker/body/accounts/userAccounts-acctCreatedEmail.ftl +++ b/webapp/web/templates/freemarker/body/accounts/userAccounts-acctCreatedEmail.ftl @@ -2,22 +2,67 @@ <#-- Confirmation that an account has been created. --> -<#assign strings = i18n() /> +<#assign subject = "Your ${siteName} account has been created." /> -<#assign subject = strings.account_created(siteName) /> +<#assign html> + + + ${subject} + + +

    + ${userAccount.firstName} ${userAccount.lastName} +

    -<#assign html = strings.account_created_email_html(siteName, - subject, - userAccount.firstName, - userAccount.lastName, - userAccount.emailAddress, - passwordLink) /> +

    + Congratulations! +

    -<#assign text = strings.account_created_email_text(siteName, - subject, - userAccount.firstName, - userAccount.lastName, - userAccount.emailAddress, - passwordLink) /> +

    + We have created your new account on ${siteName}, associated with ${userAccount.emailAddress}. +

    -<@email subject=subject html=html text=text /> \ No newline at end of file +

    + If you did not request this new account you can safely ignore this email. + This request will expire if not acted upon for 30 days. +

    + +

    + Click the link below to create your password for your new account using our secure server. +

    + +

    + ${passwordLink} +

    + +

    + If the link above doesn't work, you can copy and paste the link directly into your browser's address bar. +

    + +

    + Thanks! +

    + + + + +<#assign text> +${userAccount.firstName} ${userAccount.lastName} + +Congratulations! + +We have created your new account on ${siteName}, +associated with ${userAccount.emailAddress}. + +If you did not request this new account you can safely ignore this email. +This request will expire if not acted upon for 30 days. + +Paste the link below into your browser's address bar to create your password +for your new account using our secure server. + +${passwordLink} + +Thanks! + + +<@email subject=subject html=html text=text /> diff --git a/webapp/web/templates/freemarker/body/accounts/userAccounts-acctCreatedExternalOnlyEmail.ftl b/webapp/web/templates/freemarker/body/accounts/userAccounts-acctCreatedExternalOnlyEmail.ftl index 9b787983c..844df023c 100644 --- a/webapp/web/templates/freemarker/body/accounts/userAccounts-acctCreatedExternalOnlyEmail.ftl +++ b/webapp/web/templates/freemarker/body/accounts/userAccounts-acctCreatedExternalOnlyEmail.ftl @@ -2,18 +2,42 @@ <#-- Confirmation that an account has been created. --> -<#assign subject = strings.account_created(siteName) /> +<#assign subject = "Your ${siteName} account has been created." /> -<#assign html = strings.account_created_external_email_html(siteName, - subject, - userAccount.firstName, - userAccount.lastName, - userAccount.emailAddress) /> +<#assign html> + + + ${subject} + + +

    + ${userAccount.firstName} ${userAccount.lastName} +

    -<#assign text = string.account_created_external_email_text(siteName, - subject, - userAccount.firstName, - userAccount.lastName, - userAccount.emailAddress) /> +

    + Congratulations! +

    -<@email subject=subject html=html text=text /> \ No newline at end of file +

    + We have created your new VIVO account associated with ${userAccount.emailAddress}. +

    + +

    + Thanks! +

    + + + + +<#assign text> +${userAccount.firstName} ${userAccount.lastName} + +Congratulations! + +We have created your new VIVO account associated with +${userAccount.emailAddress}. + +Thanks! + + +<@email subject=subject html=html text=text /> diff --git a/webapp/web/templates/freemarker/body/accounts/userAccounts-confirmEmailChangedEmail.ftl b/webapp/web/templates/freemarker/body/accounts/userAccounts-confirmEmailChangedEmail.ftl index d091af468..2f55508f7 100644 --- a/webapp/web/templates/freemarker/body/accounts/userAccounts-confirmEmailChangedEmail.ftl +++ b/webapp/web/templates/freemarker/body/accounts/userAccounts-confirmEmailChangedEmail.ftl @@ -2,20 +2,37 @@ <#-- Confirmation that the user has changed his email account. --> -<#assign strings = i18n() /> +<#assign subject = "Your ${siteName} email account has been changed." /> -<#assign subject = strings.email_changed_subject(siteName) /> +<#assign html> + + + ${subject} + + +

    + Hi, ${userAccount.firstName} ${userAccount.lastName} +

    -<#assign html = strings.email_changed_html(siteName, - subject, - userAccount.firstName, - userAccount.lastName, - userAccount.emailAddress) /> +

    + You recently changed the email address associated with + ${userAccount.firstName} ${userAccount.lastName} +

    -<#assign text = strings.email_changed_text(siteName, - subject, - userAccount.firstName, - userAccount.lastName, - userAccount.emailAddress) /> +

    + Thank you. +

    + + + + +<#assign text> +Hi, ${userAccount.firstName} ${userAccount.lastName} + +You recently changed the email address associated with +${userAccount.firstName} ${userAccount.lastName} + +Thank you. + <@email subject=subject html=html text=text /> diff --git a/webapp/web/templates/freemarker/body/accounts/userAccounts-firstTimeExternalEmail.ftl b/webapp/web/templates/freemarker/body/accounts/userAccounts-firstTimeExternalEmail.ftl index 27cb200d7..04a8e6e2b 100644 --- a/webapp/web/templates/freemarker/body/accounts/userAccounts-firstTimeExternalEmail.ftl +++ b/webapp/web/templates/freemarker/body/accounts/userAccounts-firstTimeExternalEmail.ftl @@ -2,20 +2,42 @@ <#-- Confirmation that an account has been created for an externally-authenticated user. --> -<#assign strings = i18n() /> +<#assign subject = "Your ${siteName} account has been created." /> -<#assign subject = strings.account_created(siteName) /> +<#assign html> + + + ${subject} + + +

    + ${userAccount.firstName} ${userAccount.lastName} +

    -<#assign html = strings.first_time_external_email_html(siteName, - subject, - userAccount.firstName, - userAccount.lastName, - userAccount.emailAddress) /> +

    + Congratulations! +

    -<#assign text = strings.first_time_external_email_text(siteName, - subject, - userAccount.firstName, - userAccount.lastName, - userAccount.emailAddress) /> +

    + We have created your new VIVO account associated with ${userAccount.emailAddress}. +

    -<@email subject=subject html=html text=text /> \ No newline at end of file +

    + Thanks! +

    + + + + +<#assign text> +${userAccount.firstName} ${userAccount.lastName} + +Congratulations! + +We have created your new VIVO account associated with +${userAccount.emailAddress}. + +Thanks! + + +<@email subject=subject html=html text=text /> diff --git a/webapp/web/templates/freemarker/body/accounts/userAccounts-passwordCreatedEmail.ftl b/webapp/web/templates/freemarker/body/accounts/userAccounts-passwordCreatedEmail.ftl index 60cc436d7..2f80d500d 100644 --- a/webapp/web/templates/freemarker/body/accounts/userAccounts-passwordCreatedEmail.ftl +++ b/webapp/web/templates/freemarker/body/accounts/userAccounts-passwordCreatedEmail.ftl @@ -2,20 +2,42 @@ <#-- Confirmation that an password has been created. --> -<#assign strings = i18n() /> +<#assign subject = "Your ${siteName} password has successfully been created." /> -<#assign subject = strings.password_created_subject(siteName) /> +<#assign html> + + + ${subject} + + +

    + ${userAccount.firstName} ${userAccount.lastName} +

    -<#assign html = strings.password_created_email_html(siteName, - subject, - userAccount.firstName, - userAccount.lastName, - userAccount.emailAddress) /> +

    + Password successfully created. +

    -<#assign text = strings.password_created_email_text(siteName, - subject, - userAccount.firstName, - userAccount.lastName, - userAccount.emailAddress) /> +

    + Your new password associated with ${userAccount.emailAddress} has been created. +

    -<@email subject=subject html=html text=text /> \ No newline at end of file +

    + Thank you. +

    + + + + +<#assign text> +${userAccount.firstName} ${userAccount.lastName} + +Password successfully created. + +Your new password associated with ${userAccount.emailAddress} +has been created. + +Thank you. + + +<@email subject=subject html=html text=text /> diff --git a/webapp/web/templates/freemarker/body/accounts/userAccounts-passwordResetCompleteEmail.ftl b/webapp/web/templates/freemarker/body/accounts/userAccounts-passwordResetCompleteEmail.ftl index 55af25bfa..c4e64c1cc 100644 --- a/webapp/web/templates/freemarker/body/accounts/userAccounts-passwordResetCompleteEmail.ftl +++ b/webapp/web/templates/freemarker/body/accounts/userAccounts-passwordResetCompleteEmail.ftl @@ -2,20 +2,43 @@ <#-- Confirmation that a password has been reset. --> -<#assign strings = i18n() /> +<#assign subject = "Your ${siteName} password changed." /> -<#assign subject = strings.password_reset_complete_subject(siteName) /> +<#assign html> + + + ${subject} + -<#assign html = strings.password_reset_complete_email_html(siteName, - subject, - userAccount.firstName, - userAccount.lastName, - userAccount.emailAddress) /> + +

    + ${userAccount.firstName} ${userAccount.lastName} +

    -<#assign text = strings.password_reset_complete_email_text(siteName, - subject, - userAccount.firstName, - userAccount.lastName, - userAccount.emailAddress) /> +

    + Password successfully changed. +

    -<@email subject=subject html=html text=text /> \ No newline at end of file +

    + Your new password associated with ${userAccount.emailAddress} has been changed. +

    + +

    + Thank you. +

    + + + + +<#assign text> +${userAccount.firstName} ${userAccount.lastName} + +Password successfully changed. + +Your new password associated with ${userAccount.emailAddress} +has been changed. + +Thank you. + + +<@email subject=subject html=html text=text /> diff --git a/webapp/web/templates/freemarker/body/accounts/userAccounts-passwordResetPendingEmail.ftl b/webapp/web/templates/freemarker/body/accounts/userAccounts-passwordResetPendingEmail.ftl index e02bdfd9a..9ac0438ee 100644 --- a/webapp/web/templates/freemarker/body/accounts/userAccounts-passwordResetPendingEmail.ftl +++ b/webapp/web/templates/freemarker/body/accounts/userAccounts-passwordResetPendingEmail.ftl @@ -2,22 +2,60 @@ <#-- Confirmation email for user account password reset --> -<#assign strings = i18n() /> +<#assign subject = "${siteName} reset password request" /> -<#assign subject = strings.password_reset_pending_subject(siteName) /> +<#assign html> + + + ${subject} + + +

    + Dear ${userAccount.firstName} ${userAccount.lastName}: +

    + +

    + We have received a request to reset the password for your ${siteName} account (${userAccount.emailAddress}). +

    + +

    + Please follow the instructions below to proceed with your password reset. +

    + +

    + If you did not request this new account you can safely ignore this email. + This request will expire if not acted upon within 30 days. +

    + +

    + Click on the link below or paste it into your browser's address bar to reset your password + using our secure server. +

    + +

    ${passwordLink}

    + +

    Thank you!

    + + + -<#assign html = strings.password_reset_pending_email_html(siteName, - subject, - userAccount.firstName, - userAccount.lastName, - userAccount.emailAddress, - passwordLink) /> +<#assign text> +Dear ${userAccount.firstName} ${userAccount.lastName}: + +We have received a request to reset the password for your ${siteName} account +(${userAccount.emailAddress}). -<#assign text = strings.password_reset_pending_email_text(siteName, - subject, - userAccount.firstName, - userAccount.lastName, - userAccount.emailAddress, - passwordLink) /> +Please follow the instructions below to proceed with your password reset. -<@email subject=subject html=html text=text /> \ No newline at end of file +If you did not request this new account you can safely ignore this email. +This request will expire if not acted upon within 30 days. + +Paste the link below into your browser's address bar to reset your password +using our secure server. + +${passwordLink} + +Thank you! + + +<@email subject=subject html=html text=text /> diff --git a/webapp/web/templates/freemarker/body/partials/individual/individual-property-group-menus.ftl b/webapp/web/templates/freemarker/body/partials/individual/individual-property-group-menus.ftl index 0cd78b2b0..df68bbd06 100644 --- a/webapp/web/templates/freemarker/body/partials/individual/individual-property-group-menus.ftl +++ b/webapp/web/templates/freemarker/body/partials/individual/individual-property-group-menus.ftl @@ -4,7 +4,6 @@ <#import "lib-properties.ftl" as p> <#assign subjectUri = individual.controlPanelUrl()?split("=") > -<#assign nameForOtherGroup = nameForOtherGroup!"other"> <#if (propertyGroups.all)??> <#assign groups = propertyGroups.all> @@ -13,6 +12,7 @@ - - + + <#list propertyGroups.all as group> + <#if (group.properties?size > 0)> <#assign groupName = group.getName(nameForOtherGroup)> <#assign verbose = (verbosePropertySwitch.currentValue)!false> @@ -50,4 +52,5 @@ <#-- List the properties in the group --> <#include "individual-properties.ftl"> + diff --git a/webapp/web/templates/freemarker/body/partials/individual/individual-property-group-tabs.ftl b/webapp/web/templates/freemarker/body/partials/individual/individual-property-group-tabs.ftl index bb9bd9dc8..2c8d83e27 100644 --- a/webapp/web/templates/freemarker/body/partials/individual/individual-property-group-tabs.ftl +++ b/webapp/web/templates/freemarker/body/partials/individual/individual-property-group-tabs.ftl @@ -11,14 +11,14 @@
  •  
  • <#list propertyGroups.all as groupTabs> <#if ( groupTabs.properties?size > 0 ) > - <#assign groupName = groupTabs.getName(nameForOtherGroup)> - <#if groupName?has_content> - <#--the function replaces spaces in the name with underscores, also called for the property group menu--> - <#assign groupNameHtmlId = p.createPropertyGroupHtmlId(groupName) > - <#else> - <#assign groupName = "${i18n().properties_capitalized}"> - <#assign groupNameHtmlId = "${i18n().properties}" > - + <#assign groupName = groupTabs.getName(nameForOtherGroup)> + <#if groupName?has_content> + <#--the function replaces spaces in the name with underscores, also called for the property group menu--> + <#assign groupNameHtmlId = p.createPropertyGroupHtmlId(groupName) > + <#else> + <#assign groupName = "${i18n().properties_capitalized}"> + <#assign groupNameHtmlId = "${i18n().properties}" > + <#if tabCount = 1 >
  • ${groupName?capitalize}
  •  
  • @@ -35,30 +35,32 @@ <#list propertyGroups.all as group> - <#assign groupName = group.getName(nameForOtherGroup)> - <#assign groupNameHtmlId = p.createPropertyGroupHtmlId(groupName) > - <#assign verbose = (verbosePropertySwitch.currentValue)!false> -
    - + <#if (group.properties?size > 0)> + <#assign groupName = group.getName(nameForOtherGroup)> + <#assign groupNameHtmlId = p.createPropertyGroupHtmlId(groupName) > + <#assign verbose = (verbosePropertySwitch.currentValue)!false> +
    + - <#-- Display the group heading --> - <#if groupName?has_content> - <#--the function replaces spaces in the name with underscores, also called for the property group menu--> - <#assign groupNameHtmlId = p.createPropertyGroupHtmlId(groupName) > - - <#else> - - + <#-- Display the group heading --> + <#if groupName?has_content> + <#--the function replaces spaces in the name with underscores, also called for the property group menu--> + <#assign groupNameHtmlId = p.createPropertyGroupHtmlId(groupName) > + + <#else> + +
    <#-- List the properties in the group --> <#include "individual-properties.ftl">
    -
    -<#assign sectionCount = 2 > +
    + <#assign sectionCount = 2 > +