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/opensocial/shindig_example_gadgets.sql b/opensocial/shindig_example_gadgets.sql index afad1dc44..ae04919df 100644 --- a/opensocial/shindig_example_gadgets.sql +++ b/opensocial/shindig_example_gadgets.sql @@ -4,13 +4,13 @@ DELETE FROM `orng_apps`; INSERT INTO `orng_apps` (`appid`, `name`, `url`, `PersonFilterID`, `enabled`, `channels`) VALUES -(100, 'Google Search', 'http://dev-profiles.ucsf.edu/orng/GoogleSearch.xml', NULL, 1, NULL), -(101, 'Featured Presentations', 'http://dev-profiles.ucsf.edu/orng/SlideShare.xml', NULL, 1, NULL), -(102, 'Faculty Mentor', 'http://dev-profiles.ucsf.edu/orng/Mentor.xml', NULL, 0, NULL), -(103, 'Websites', 'http://dev-profiles.ucsf.edu/orng/Links.xml', NULL, 1, NULL), -(104, 'Profile List', 'http://dev-profiles.ucsf.edu/orng/ProfileListTool.xml', NULL, 1, 'JSONPersonIds'), -(106, 'RDF Test Gadget', 'http://dev-profiles.ucsf.edu/orng/RDFTest.xml', NULL, 1, NULL), -(112, 'Twitter', 'http://dev-profiles.ucsf.edu/ORNG/Twitter.xml', NULL, 1, NULL); +(100, 'Google Search', 'http://stage-profiles.ucsf.edu/apps/ucsfsearch.xml', NULL, 1, NULL), +(101, 'Featured Presentations', 'http://stage-profiles.ucsf.edu/apps/SlideShare.xml', NULL, 1, NULL), +(102, 'Faculty Mentor', 'http://stage-profiles.ucsf.edu/apps/Mentor.xml', NULL, 0, NULL), +(103, 'Websites', 'http://stage-profiles.ucsf.edu/apps/Links.xml', NULL, 1, NULL), +(104, 'Profile List', 'http://stage-profiles.ucsf.edu/apps/ProfileListTool.xml', NULL, 1, 'JSONPersonIds'), +(106, 'RDF Test Gadget', 'http://stage-profiles.ucsf.edu/apps/RDFTest.xml', NULL, 1, NULL), +(112, 'Twitter', 'http://stage-profiles.ucsf.edu/apps/Twitter.xml', NULL, 1, NULL); DELETE FROM `orng_app_views`; 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..8c8d081a5 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. @@ -873,3 +857,5 @@ processing_icon = tratamiento selection_in_process = Su selección se está procesando.view_labels_capitalized = Ver etiquetas view_labels_capitalized = Ver etiquetas view_labels_for = Ver Etiquetas de + +select_an_existing_document = Seleccione un documento existente 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/vedit/util/FormUtils.java b/webapp/src/edu/cornell/mannlib/vedit/util/FormUtils.java index c28ebf2a6..77e8fdefb 100644 --- a/webapp/src/edu/cornell/mannlib/vedit/util/FormUtils.java +++ b/webapp/src/edu/cornell/mannlib/vedit/util/FormUtils.java @@ -241,6 +241,9 @@ public class FormUtils { option.setValue(vclass.getURI()); option.setBody(vclass.getPickListName()); vclassOptionList.add(option); + if(selectedVClassURI != null && selectedVClassURI.equals(vclass.getURI())) { + option.setSelected(true); + } } return vclassOptionList; } 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/freemarker/ListDatatypePropertiesController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ListDatatypePropertiesController.java index 36f513f0d..6272cd553 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ListDatatypePropertiesController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ListDatatypePropertiesController.java @@ -64,7 +64,9 @@ public class ListDatatypePropertiesController extends FreemarkerHttpServlet { List props = new ArrayList(); if (vreq.getParameter("propsForClass") != null) { noResultsMsgStr = "There are no data properties that apply to this class."; - Collection dataProps = dao.getDataPropertiesForVClass(vreq.getParameter("vclassUri")); + Collection dataProps = vreq.getLanguageNeutralWebappDaoFactory() + .getDataPropertyDao().getDataPropertiesForVClass( + vreq.getParameter("vclassUri")); Iterator dataPropIt = dataProps.iterator(); HashSet propURIs = new HashSet(); while (dataPropIt.hasNext()) { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ListPropertyWebappsController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ListPropertyWebappsController.java index 973f50c67..5e2213a61 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ListPropertyWebappsController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ListPropertyWebappsController.java @@ -59,7 +59,7 @@ public class ListPropertyWebappsController extends FreemarkerHttpServlet { String ontologyUri = vreq.getParameter("ontologyUri"); ObjectPropertyDao dao = vreq.getUnfilteredWebappDaoFactory().getObjectPropertyDao(); - PropertyInstanceDao piDao = vreq.getUnfilteredWebappDaoFactory().getPropertyInstanceDao(); + PropertyInstanceDao piDao = vreq.getLanguageNeutralWebappDaoFactory().getPropertyInstanceDao(); VClassDao vcDao = vreq.getUnfilteredWebappDaoFactory().getVClassDao(); PropertyGroupDao pgDao = vreq.getUnfilteredWebappDaoFactory().getPropertyGroupDao(); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ListVClassWebappsController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ListVClassWebappsController.java index d76ac897c..8c964ad5b 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ListVClassWebappsController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ListVClassWebappsController.java @@ -51,7 +51,7 @@ public class ListVClassWebappsController extends FreemarkerHttpServlet { List classes = null; if (vreq.getParameter("showPropertyRestrictions") != null) { - PropertyDao pdao = vreq.getUnfilteredWebappDaoFactory().getObjectPropertyDao(); + PropertyDao pdao = vreq.getLanguageNeutralWebappDaoFactory().getObjectPropertyDao(); classes = pdao.getClassesWithRestrictionOnProperty(vreq.getParameter("propertyURI")); } else { VClassDao vcdao = vreq.getUnfilteredWebappDaoFactory().getVClassDao(); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/individual/IndividualRdfAssembler.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/individual/IndividualRdfAssembler.java index 90e79cde7..d2c7f5702 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/individual/IndividualRdfAssembler.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/individual/IndividualRdfAssembler.java @@ -2,6 +2,7 @@ package edu.cornell.mannlib.vitro.webapp.controller.individual; +import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashSet; import java.util.Set; @@ -343,7 +344,9 @@ public class IndividualRdfAssembler { } private Literal createDateLiteral(OntModel o) { - return o.createTypedLiteral(new Date(), XSDDatatype.XSDdate); + String date = new SimpleDateFormat("YYYY-MM-dd'T'HH:mm:ss") + .format(new Date()); + return o.createTypedLiteral(date, XSDDatatype.XSDdateTime); } } 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..ecdc2bfbc 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,43 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp } public ObjectProperty getObjectPropertyByURI(String propertyURI) { + 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); + Resource prop = ontModel.getResource(propertyURI); + localModel.add(ontModel.listStatements(prop, null, (RDFNode) null)); + StmtIterator invit = ontModel.listStatements(prop, OWL.inverseOf, (RDFNode) null); + while (invit.hasNext()) { + Statement invSit = invit.nextStatement(); + if (invSit.getObject().isURIResource()) { + Resource invProp = (Resource) invSit.getObject(); + localModel.add(ontModel.listStatements(invProp, 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,11 +315,11 @@ 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" + - " ?publicDescription \n" + + " ?publicDescription ?stubDeletion \n" + " WHERE { \n" + " ?context config:configContextFor <" + propertyURI + "> . \n"; if (domainURI != null) { @@ -308,7 +330,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" + @@ -326,6 +349,7 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp " OPTIONAL { ?configuration <" + PROPERTY_SELECTFROMEXISTINGANNOT.getURI() + "> ?selectFromExisting } \n" + " OPTIONAL { ?configuration <" + PROPERTY_OFFERCREATENEWOPTIONANNOT.getURI() + "> ?offerCreateNew } \n" + " OPTIONAL { ?configuration <" + PUBLIC_DESCRIPTION_ANNOT.getURI() + "> ?publicDescription } \n" + + " OPTIONAL { ?configuration <" + PROPERTY_STUBOBJECTPROPERTYANNOT.getURI() + "> ?stubDeletion } \n" + "}"; Query q = QueryFactory.create(propQuery); @@ -334,6 +358,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()); @@ -400,6 +433,10 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp if (offerCreateNewLit != null) { op.setOfferCreateNewOption(offerCreateNewLit.getBoolean()); } + Literal stubDeletionLit = qsoln.getLiteral("stubDeletion"); + if (stubDeletionLit != null) { + op.setStubObjectRelation(stubDeletionLit.getBoolean()); + } Literal publicDescriptionLit = qsoln.getLiteral("publicDescription"); if (publicDescriptionLit != null) { op.setPublicDescription(publicDescriptionLit.getLexicalForm()); @@ -407,7 +444,7 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp } } finally { qe.close(); - } + } return op; } @@ -918,24 +955,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 +997,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 { + ObjectProperty newProperty = getObjectPropertyByURI(uri); + if (newProperty != null) { + propRegister = newProperty; + // add canonical instance of the property first in the list + // before the range-changed versions + properties.add(newProperty); + // isolate the canonical prop from what's about to happen next + property = newProperty.clone(); + } + } if (property != null) { + property.setRangeVClassURI(objTypeUri); properties.add(property); } } @@ -998,12 +1061,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 +1102,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..381f56bd8 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; @@ -45,10 +44,13 @@ import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty; import edu.cornell.mannlib.vitro.webapp.beans.Property; import edu.cornell.mannlib.vitro.webapp.beans.PropertyInstance; import edu.cornell.mannlib.vitro.webapp.beans.VClass; +import edu.cornell.mannlib.vitro.webapp.dao.ObjectPropertyDao; 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 +76,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 +91,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 +423,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 +433,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; } /** @@ -577,17 +595,32 @@ public class PropertyDaoJena extends JenaBaseDao implements PropertyDao { private void updatePropertyRangeMap(Map map, String propURI, - Resource[] ranges) { + Resource[] ranges, + boolean replaceIfMoreSpecific) { Resource[] existingRanges = map.get(propURI); if (existingRanges == null) { map.put(propURI, ranges); } else if (existingRanges[0] == null && existingRanges[1] != null) { existingRanges[0] = ranges[0]; map.put(propURI, existingRanges); - } else if (existingRanges[0] != null && existingRanges[1] == null) { - existingRanges[1] = ranges[1]; + } else if (existingRanges[0] != null) { + if (existingRanges[1] == null) { + existingRanges[1] = ranges[1]; + } + if (ranges[0] != null && moreSpecificThan(ranges[0], existingRanges[0])) { + existingRanges[0] = ranges[0]; + } map.put(propURI, existingRanges); + } + } + + private boolean moreSpecificThan(Resource r1, Resource r2) { + if(r1.getURI() == null) { + return false; + } else if (r2.getURI() == null) { + return true; } + return getWebappDaoFactory().getVClassDao().isSubClassOf(r1.getURI(), r2.getURI()); } private List listSuperClasses(OntClass ontClass) { @@ -693,10 +726,11 @@ public class PropertyDaoJena extends JenaBaseDao implements PropertyDao { Resource[] ranges = new Resource[2]; if (rest.isAllValuesFromRestriction()) { ranges[0] = (rest.asAllValuesFromRestriction()).getAllValuesFrom(); + updatePropertyRangeMap(applicableProperties, onProperty.getURI(), ranges, true); } else if (rest.isSomeValuesFromRestriction()) { ranges[1] = (rest.asSomeValuesFromRestriction()).getSomeValuesFrom(); + updatePropertyRangeMap(applicableProperties, onProperty.getURI(), ranges, false); } - updatePropertyRangeMap(applicableProperties, onProperty.getURI(), ranges); } } @@ -718,7 +752,7 @@ public class PropertyDaoJena extends JenaBaseDao implements PropertyDao { Resource[] ranges = new Resource[2]; ranges[0] = rangeRes; updatePropertyRangeMap( - applicableProperties, prop.getURI(), ranges); + applicableProperties, prop.getURI(), ranges, false); } } @@ -744,8 +778,7 @@ public class PropertyDaoJena extends JenaBaseDao implements PropertyDao { ? foundRanges[1] : op.getRange(); Resource domainRes = op.getDomain(); - propInsts.add(getPropInst( - op, domainRes, rangeRes, applicableProperties)); + propInsts.add(getPropInst(op, domainRes, rangeRes)); List> additionalFauxSubpropertyDomainAndRangeURIs = getAdditionalFauxSubpropertyDomainAndRangeURIsForPropertyURI( propertyURI); @@ -770,8 +803,8 @@ public class PropertyDaoJena extends JenaBaseDao implements PropertyDao { propInsts.add(getPropInst( op, ResourceFactory.createResource(domainAndRangeURIs.getLeft()), - ResourceFactory.createResource(domainAndRangeURIs.getRight()), - applicableProperties)); + ResourceFactory.createResource(domainAndRangeURIs.getRight()) + )); } } } @@ -780,13 +813,32 @@ public class PropertyDaoJena extends JenaBaseDao implements PropertyDao { } finally { ontModel.leaveCriticalSection(); } - + + // add any faux properties with applicable domain where the predicate URI + // is not already on the list + List stragglers = getAdditionalFauxSubpropertiesForVClasses( + vclasses, propInsts); + for (ObjectProperty op : stragglers) { + propInsts.add(makePropInst(op)); + } + return propInsts; } - private PropertyInstance getPropInst(OntProperty op, Resource domainRes, Resource rangeRes, - Map applicableProperties) { + private PropertyInstance makePropInst(ObjectProperty op) { + PropertyInstance pi = new PropertyInstance(); + pi.setDomainClassURI(op.getDomainVClassURI()); + pi.setRangeClassURI(op.getRangeVClassURI()); + pi.setSubjectSide(true); + pi.setPropertyURI(op.getURI()); + pi.setPropertyName(op.getLabel()); + pi.setDomainPublic(op.getDomainPublic()); + return pi; + } + + private PropertyInstance getPropInst(OntProperty op, Resource domainRes, + Resource rangeRes) { if (log.isDebugEnabled() && domainRes != null && rangeRes != null) { log.debug("getPropInst() op: " + op.getURI() + " domain: " + domainRes.getURI() + " range: " + rangeRes.getURI()); @@ -795,9 +847,9 @@ public class PropertyDaoJena extends JenaBaseDao implements PropertyDao { String domainURIStr = (domainRes != null && !domainRes.isAnon()) ? domainURIStr = domainRes.getURI() : null; - if (rangeRes == null) { - pi.setRangeClassURI(OWL.Thing.getURI()); // TODO see above - } else { +// if (rangeRes == null) { +// pi.setRangeClassURI(OWL.Thing.getURI()); // TODO see above + if(rangeRes != null) { String rangeClassURI; if (rangeRes.isAnon()) { rangeClassURI = PSEUDO_BNODE_NS + rangeRes.getId() @@ -834,6 +886,58 @@ public class PropertyDaoJena extends JenaBaseDao implements PropertyDao { return pi; } + private List getAdditionalFauxSubpropertiesForVClasses( + List vclasses, List propInsts) { + + List opList = new ArrayList(); + if (vclasses.size() == 0) { + return opList; + } + ObjectPropertyDao opDao = getWebappDaoFactory().getObjectPropertyDao(); + String propQuery = "PREFIX rdfs: \n" + + "PREFIX config: \n" + + "PREFIX vitro: \n" + + "SELECT ?property ?domain ?range WHERE { \n" + + " ?context config:configContextFor ?property . \n" + + " ?context config:qualifiedByDomain ?domain . \n" + + " ?context config:qualifiedBy ?range . \n"; + for(PropertyInstance propInst : propInsts) { + propQuery += " FILTER (?property != <" + propInst.getPropertyURI() + "> ) \n"; + } + Iterator classIt = vclasses.iterator(); + if(classIt.hasNext()) { + propQuery += " FILTER ( \n"; + propQuery += " (?domain = <" + OWL.Thing.getURI() + "> )\n"; + while (classIt.hasNext()) { + VClass vclass = classIt.next(); + if(vclass.isAnonymous()) { + continue; + } + propQuery += " || (?domain = <" + vclass.getURI() + "> ) \n"; + } + propQuery += ") \n"; + } + propQuery += "} \n"; + log.debug(propQuery); + Query q = QueryFactory.create(propQuery); + QueryExecution qe = QueryExecutionFactory.create( + q, getOntModelSelector().getDisplayModel()); + try { + ResultSet rs = qe.execSelect(); + while (rs.hasNext()) { + QuerySolution qsoln = rs.nextSolution(); + String propertyURI = qsoln.getResource("property").getURI(); + String domainURI = qsoln.getResource("domain").getURI(); + String rangeURI = qsoln.getResource("range").getURI(); + opList.add(opDao.getObjectPropertyByURIs( + propertyURI, domainURI, rangeURI, null)); + } + } finally { + qe.close(); + } + return opList; + } + private List> getAdditionalFauxSubpropertyDomainAndRangeURIsForPropertyURI(String propertyURI) { List> domainAndRangeURIs = new ArrayList>(); String propQuery = "PREFIX rdfs: \n" + @@ -865,20 +969,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..e03ed48c5 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) { @@ -59,7 +62,6 @@ public class PropertyInstanceDaoJena extends PropertyDaoJena implements baseModel.notifyEvent(new IndividualUpdateEvent(userUri,true,subjectURI)); try { ontModel.remove(subjRes,pred,objRes); - updatePropertyDateTimeValue(subjRes,MODTIME,Calendar.getInstance().getTime(),ontModel); } finally { baseModel.notifyEvent(new IndividualUpdateEvent(userUri,false,subjectURI)); } @@ -75,7 +77,6 @@ public class PropertyInstanceDaoJena extends PropertyDaoJena implements baseModel.notifyEvent(new IndividualUpdateEvent(userUri,true,objectURI)); try { ontModel.remove(objRes,invPred,subjRes); - updatePropertyDateTimeValue(objRes,MODTIME,Calendar.getInstance().getTime(),ontModel); } finally { baseModel.notifyEvent(new IndividualUpdateEvent(userUri,false,subjectURI)); } @@ -212,7 +213,6 @@ public class PropertyInstanceDaoJena extends PropertyDaoJena implements getOntModel().getBaseModel().notifyEvent(new IndividualUpdateEvent(getWebappDaoFactory().getUserURI(),true,prop.getSubjectEntURI())); try { ontModel.add(subjRes,pred,objRes); - updatePropertyDateTimeValue(subjRes,MODTIME,Calendar.getInstance().getTime(),getOntModel()); } finally { getOntModel().getBaseModel().notifyEvent(new IndividualUpdateEvent(getWebappDaoFactory().getUserURI(),false,prop.getSubjectEntURI())); } @@ -221,7 +221,6 @@ public class PropertyInstanceDaoJena extends PropertyDaoJena implements getOntModel().getBaseModel().notifyEvent(new IndividualUpdateEvent(getWebappDaoFactory().getUserURI(),true,prop.getObjectEntURI())); try { ontModel.add(objRes,invPred,subjRes); - updatePropertyDateTimeValue(objRes,MODTIME,Calendar.getInstance().getTime(),getOntModel()); } finally { getOntModel().getBaseModel().notifyEvent(new IndividualUpdateEvent(getWebappDaoFactory().getUserURI(),false,prop.getSubjectEntURI())); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/QueryUtils.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/QueryUtils.java index e2c1df90b..f2c686657 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/QueryUtils.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/QueryUtils.java @@ -9,18 +9,16 @@ import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import com.hp.hpl.jena.query.Dataset; -import com.hp.hpl.jena.query.QueryExecution; -import com.hp.hpl.jena.query.QueryExecutionFactory; 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.rdf.model.Literal; import com.hp.hpl.jena.rdf.model.RDFNode; import com.hp.hpl.jena.rdf.model.Resource; -import com.hp.hpl.jena.shared.Lock; -import com.hp.hpl.jena.sparql.resultset.ResultSetMem; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException; /** * Utilities for executing queries and working with query results. @@ -115,31 +113,21 @@ public class QueryUtils { } public static ResultSet getQueryResults(String queryStr, VitroRequest vreq) { - return getQueryResults(queryStr, vreq.getDataset()); + return getQueryResults(queryStr, vreq.getRDFService()); } public static ResultSet getLanguageNeutralQueryResults(String queryStr, VitroRequest vreq) { - return getQueryResults(queryStr, vreq.getUnfilteredDataset()); + return getQueryResults(queryStr, vreq.getUnfilteredRDFService()); } /** Already have the dataset, so process the query and return the results. */ - private static ResultSet getQueryResults(String queryStr, Dataset dataset) { - dataset.getLock().enterCriticalSection(Lock.READ); - QueryExecution qexec = null; - ResultSet results = null; - try { - qexec = QueryExecutionFactory.create(queryStr, dataset); - results = new ResultSetMem(qexec.execSelect()); - } catch (Exception e) { - log.error(e, e); - } finally { - dataset.getLock().leaveCriticalSection(); - if (qexec != null) { - qexec.close(); - } - } - - return results; + private static ResultSet getQueryResults(String queryStr, RDFService rdfService) { + try { + return ResultSetFactory.fromJSON( + rdfService.sparqlSelectQuery(queryStr, RDFService.ResultFormat.JSON)); + } catch (RDFServiceException e) { + throw new RuntimeException(e); + } } } 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/VTwo/EditConfigurationUtils.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditConfigurationUtils.java index 3ecb8c289..a53e3f65e 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditConfigurationUtils.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditConfigurationUtils.java @@ -105,10 +105,7 @@ public class EditConfigurationUtils { public static ObjectProperty getObjectProperty(VitroRequest vreq) { - //gets the predicate uri from the request - String predicateUri = getPredicateUri(vreq); - String rangeUri = getRangeUri(vreq); - return getObjectPropertyForPredicate(vreq, predicateUri, rangeUri); + return getObjectPropertyForPredicate(vreq, getPredicateUri(vreq)); } public static DataProperty getDataProperty(VitroRequest vreq) { @@ -116,17 +113,18 @@ public class EditConfigurationUtils { return getDataPropertyForPredicate(vreq, predicateUri); } - public static ObjectProperty getObjectPropertyForPredicate(VitroRequest vreq, String predicateUri) { - return getObjectPropertyForPredicate(vreq, predicateUri, null); + public static ObjectProperty getObjectPropertyForPredicate(VitroRequest vreq, + String predicateUri) { + String domainUri = getDomainUri(vreq); + String rangeUri = getRangeUri(vreq); + return getObjectPropertyForPredicate(vreq, predicateUri, domainUri, rangeUri); } - public static ObjectProperty getObjectPropertyForPredicate(VitroRequest vreq, String predicateUri, String rangeUri) { + public static ObjectProperty getObjectPropertyForPredicate(VitroRequest vreq, + String predicateUri, String domainUri, String rangeUri) { WebappDaoFactory wdf = vreq.getWebappDaoFactory(); - ObjectProperty objectProp = wdf.getObjectPropertyDao().getObjectPropertyByURI(predicateUri); - if (rangeUri != null) { - objectProp.setRangeVClassURI(rangeUri); - // TODO implement this in the DAO? - } + ObjectProperty objectProp = wdf.getObjectPropertyDao().getObjectPropertyByURIs( + predicateUri, domainUri, rangeUri); return objectProp; } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/IndividualsViaObjectPropetyOptions.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/IndividualsViaObjectPropetyOptions.java index fdc1f008a..fcc1453b6 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/IndividualsViaObjectPropetyOptions.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/IndividualsViaObjectPropetyOptions.java @@ -19,6 +19,7 @@ import edu.cornell.mannlib.vitro.webapp.beans.VClass; import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; import edu.cornell.mannlib.vitro.webapp.dao.VClassDao; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo; +import edu.cornell.mannlib.vitro.webapp.utils.fields.FieldUtils; public class IndividualsViaObjectPropetyOptions implements FieldOptions { @@ -100,7 +101,7 @@ public class IndividualsViaObjectPropetyOptions implements FieldOptions { List stmts = subject.getObjectPropertyStatements(); - individuals = removeIndividualsAlreadyInRange( + individuals = FieldUtils.removeIndividualsAlreadyInRange( individuals, stmts, predicateUri, objectUri); // Collections.sort(individuals,new compareIndividualsByName());a @@ -162,28 +163,7 @@ public class IndividualsViaObjectPropetyOptions implements FieldOptions { return filteredVClassesURIs; } - // copied from OptionsForPropertyTag.java in the thought that class may be deprecated - private static List removeIndividualsAlreadyInRange(List individuals, - List stmts, String predicateUri, String objectUriBeingEdited){ - HashSet range = new HashSet(); - - for(ObjectPropertyStatement ops : stmts){ - if( ops.getPropertyURI().equals(predicateUri)) - range.add( ops.getObjectURI() ); - } - - int removeCount=0; - ListIterator it = individuals.listIterator(); - while(it.hasNext()){ - Individual ind = it.next(); - if( range.contains( ind.getURI()) && !(ind.getURI().equals(objectUriBeingEdited)) ) { - it.remove(); - ++removeCount; - } - } - - return individuals; - } + public Comparator getCustomComparator() { return null; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/IndividualsViaSolrQueryOptions.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/IndividualsViaSolrQueryOptions.java new file mode 100644 index 000000000..75cac343e --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/IndividualsViaSolrQueryOptions.java @@ -0,0 +1,154 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ +package edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.fields; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; + +import javax.servlet.ServletContext; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.solr.client.solrj.SolrQuery; +import org.apache.solr.client.solrj.SolrServer; +import org.apache.solr.client.solrj.response.QueryResponse; +import org.apache.solr.common.SolrDocument; +import org.apache.solr.common.SolrDocumentList; + +import edu.cornell.mannlib.vitro.webapp.beans.Individual; +import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatement; +import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; +import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo; +import edu.cornell.mannlib.vitro.webapp.search.VitroSearchTermNames; +import edu.cornell.mannlib.vitro.webapp.search.solr.SolrSetup; +import edu.cornell.mannlib.vitro.webapp.utils.fields.FieldUtils; + +/* + * This runs a solr query to get individuals of a certain class instead of relying on the dao classes. + * Also it gets individuals that belong to the most specific type(s) specified. + */ +public class IndividualsViaSolrQueryOptions extends IndividualsViaVClassOptions implements FieldOptions { + private Log log = LogFactory.getLog(IndividualsViaSolrQueryOptions.class); + + private ServletContext servletContext; + private String subjectUri; + private String predicateUri; + private String objectUri; + public IndividualsViaSolrQueryOptions(ServletContext context, String inputSubjectUri, String inputPredicateUri, String inputObjectUri, String ... vclassURIs) throws Exception { + super(vclassURIs); + this.servletContext = context; + this.subjectUri = inputSubjectUri; + this.predicateUri = inputPredicateUri; + this.objectUri = inputObjectUri; + } + + @Override + protected Map getIndividualsForClass(String vclassURI, WebappDaoFactory wDaoFact ){ + Map individualMap = new HashMap(); + try { + SolrServer solrServer = SolrSetup.getSolrServer(servletContext); + + //solr query for type count. + SolrQuery query = new SolrQuery(); + if( VitroVocabulary.OWL_THING.equals( vclassURI )){ + query.setQuery( "*:*" ); + }else{ + query.setQuery( VitroSearchTermNames.MOST_SPECIFIC_TYPE_URIS + ":" + vclassURI); + } + query.setStart(0) + .setRows(1000); + query.setFields(VitroSearchTermNames.URI); // fields to retrieve + + QueryResponse rsp = solrServer.query(query); + SolrDocumentList docs = rsp.getResults(); + long found = docs.getNumFound(); + if(found > 0) { + for (SolrDocument doc : docs) { + try { + String uri = doc.get(VitroSearchTermNames.URI).toString(); + Individual individual = wDaoFact.getIndividualDao().getIndividualByURI(uri); + if (individual == null) { + log.debug("No individual for search document with uri = " + uri); + } else { + individualMap.put(individual.getURI(), individual); + log.debug("Adding individual " + uri + " to individual list"); + } + } + catch(Exception ex) { + log.error("An error occurred retrieving the individual solr query resutls", ex); + } + } + } + + } catch(Exception ex) { + log.error("Error occurred in executing solr query ", ex); + } + return individualMap; + } + + @Override + public Map getOptions( + EditConfigurationVTwo editConfig, + String fieldName, + WebappDaoFactory wDaoFact) throws Exception { + + Map individualMap = new HashMap(); + + for( String vclassURI : vclassURIs){ + individualMap.putAll( getIndividualsForClass( vclassURI, wDaoFact) ); + } + + //sort the individuals + List individuals = new ArrayList(); + individuals.addAll(individualMap.values()); + + //Here we will remove individuals already in the range + Individual subject = wDaoFact.getIndividualDao().getIndividualByURI(subjectUri); + List stmts = subject.getObjectPropertyStatements(); + + individuals = FieldUtils.removeIndividualsAlreadyInRange( + individuals, stmts, predicateUri, objectUri); + //Also remove subjectUri if it + individuals = removeSubjectUri(individuals, subjectUri); + //sort the list + Collections.sort(individuals); + //set up the options map + Map optionsMap = new HashMap(); + + if (defaultOptionLabel != null) { + optionsMap.put(LEFT_BLANK, defaultOptionLabel); + } + + if (individuals.size() == 0) { + //return empty map, unlike individualsViaVclass + return optionsMap ; + } else { + for (Individual ind : individuals) { + if (ind.getURI() != null) { + optionsMap.put(ind.getURI(), ind.getName().trim()); + } + } + } + return optionsMap; + + } + + //TODO: Check if this can be done simply by reference + private List removeSubjectUri(List individuals, + String subjectUri) { + ListIterator it = individuals.listIterator(); + while(it.hasNext()){ + Individual ind = it.next(); + if( ind.getURI().equals(subjectUri)) { + it.remove(); + } + } + return individuals; + } + + +} \ No newline at end of file diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/IndividualsViaVClassOptions.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/IndividualsViaVClassOptions.java index cebc7d23e..741624e5a 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/IndividualsViaVClassOptions.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/fields/IndividualsViaVClassOptions.java @@ -18,8 +18,8 @@ import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTw public class IndividualsViaVClassOptions implements FieldOptions { public static final String LEFT_BLANK = ""; - private List vclassURIs; - private String defaultOptionLabel; + protected List vclassURIs; + protected String defaultOptionLabel; public IndividualsViaVClassOptions(String ... vclassURIs) throws Exception { super(); 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/edit/n3editing/controller/PostEditCleanupController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/PostEditCleanupController.java index 9c7d6b9a0..b62254878 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/PostEditCleanupController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/PostEditCleanupController.java @@ -55,6 +55,15 @@ public class PostEditCleanupController extends FreemarkerHttpServlet{ return new RedirectResponseValues( UrlBuilder.getHomeUrl() ); } + //In some cases, a generator/form may have a regular URL to return to but the same generator + //may be used from different pages, so a parameter allowing the form to return to a specific page + //would be useful + + String returnURLParameter = vreq.getParameter("returnURL"); + if(returnURLParameter != null) { + return new DirectRedirectResponseValues( returnURLParameter ); + } + // If there is a urlToReturnTo that takes precedence if( editConfig.getUrlToReturnTo() != null && ! editConfig.getUrlToReturnTo().trim().isEmpty()){ //this does not get value substitution or the predicate anchor 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..00e854d83 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,6 +596,7 @@ public class ABoxUpdater { return; } + long start = System.currentTimeMillis(); Iterator graphIt = dataset.listNames(); while(graphIt.hasNext()) { String graph = graphIt.next(); @@ -604,11 +607,23 @@ public class ABoxUpdater { Model renamePropAddModel = ModelFactory.createDefaultModel(); Model renamePropRetractModel = ModelFactory.createDefaultModel(); - + log.debug("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.debug(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 +631,13 @@ public class ABoxUpdater { newProperty, tempStatement.getObject() ); } + log.debug(System.currentTimeMillis() - start + " to make new statements"); + start = System.currentTimeMillis(); aboxModel.remove(renamePropRetractModel); + log.debug(System.currentTimeMillis() - start + " to retract old statements"); + start = System.currentTimeMillis(); aboxModel.add(renamePropAddModel); + log.debug(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..3e685ed1e 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 @@ -83,7 +83,7 @@ public class KnowledgeBaseUpdater { logger.closeLogs(); long elapsedSecs = (System.currentTimeMillis() - startTime)/1000; - log.info("Finished knowledge base migration in " + elapsedSecs + " second" + (elapsedSecs != 1 ? "s" : "")); + log.info("Finished checking knowledge base in " + elapsedSecs + " second" + (elapsedSecs != 1 ? "s" : "")); return record.hasRecordedChanges(); } @@ -95,20 +95,20 @@ public class KnowledgeBaseUpdater { AtomicOntologyChangeLists changes = new AtomicOntologyChangeLists(rawChanges,settings.getNewTBoxModel(),settings.getOldTBoxModel()); // update ABox data any time - log.info("performing SPARQL CONSTRUCT additions"); + log.debug("performing SPARQL CONSTRUCT additions"); performSparqlConstructs(settings.getSparqlConstructAdditionsDir(), settings.getRDFService(), ADD); - log.info("performing SPARQL CONSTRUCT retractions"); + log.debug("performing SPARQL CONSTRUCT retractions"); performSparqlConstructs(settings.getSparqlConstructDeletionsDir(), settings.getRDFService(), RETRACT); - log.info("\tupdating the abox"); + log.info("\tchecking the abox"); updateABox(changes); - log.info("performing post-processing SPARQL CONSTRUCT additions"); + log.debug("performing post-processing SPARQL CONSTRUCT additions"); performSparqlConstructs(settings.getSparqlConstructAdditionsDir() + "/post/", settings.getRDFService(), ADD); - log.info("performing post-processing SPARQL CONSTRUCT retractions"); + log.debug("performing post-processing SPARQL CONSTRUCT retractions"); performSparqlConstructs(settings.getSparqlConstructDeletionsDir() + "/post/", settings.getRDFService(), RETRACT); @@ -145,7 +145,7 @@ public class KnowledgeBaseUpdater { boolean add) throws IOException { Dataset dataset = new RDFServiceDataset(rdfService); File sparqlConstructDirectory = new File(sparqlConstructDir); - log.info("Using SPARQL CONSTRUCT directory " + sparqlConstructDirectory); + log.debug("Using SPARQL CONSTRUCT directory " + sparqlConstructDirectory); if (!sparqlConstructDirectory.isDirectory()) { String logMsg = this.getClass().getName() + "performSparqlConstructs() expected to find a directory " + @@ -178,7 +178,7 @@ public class KnowledgeBaseUpdater { } Model anonModel = ModelFactory.createDefaultModel(); try { - log.info("\t\tprocessing SPARQL construct query from file " + sparqlFile.getName()); + log.debug("\t\tprocessing SPARQL construct query from file " + sparqlFile.getName()); anonModel = RDFServiceUtils.parseModel( rdfService.sparqlConstructQuery(fileContents.toString(), 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..aecdffdec --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/logging/RDFServiceLogger.java @@ -0,0 +1,188 @@ +/* $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. It also omits + * any Jena classes. 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); + removeJenaClassesFromStackTrace(list); + + if (list.isEmpty()) { + this.methodName = "UNKNOWN"; + } else { + this.methodName = list.get(0).getMethodName(); + } + + this.trace = list; + log.debug("Stack array: " + Arrays.toString(stack)); + log.debug("Stack trace: " + this.trace); + } + + 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 void removeJenaClassesFromStackTrace(List list) { + ListIterator iter = list.listIterator(); + while (iter.hasNext()) { + StackTraceElement ste = iter.next(); + if (ste.getClassName().startsWith("com.hp.hpl.jena.")) { + iter.remove(); + } + } + } + + private boolean passesRestrictions() { + if (restriction == null) { + return true; + } + for (StackTraceElement ste : trace) { + if (restriction.matcher(ste.getClassName()).find()) { + 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 line %d4, %s", + ste.getLineNumber(), ste.getClassName())); + } + sb.append("\n ..."); + } + + return sb.toString(); + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/search/indexing/AdditionalURIsForContextNodes.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/search/indexing/AdditionalURIsForContextNodes.java deleted file mode 100644 index 96216d636..000000000 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/search/indexing/AdditionalURIsForContextNodes.java +++ /dev/null @@ -1,811 +0,0 @@ -/* $This file is distributed under the terms of the license in /doc/license.txt$ */ - -package edu.cornell.mannlib.vitro.webapp.search.indexing; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Set; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import com.hp.hpl.jena.ontology.OntModel; -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.QuerySolutionMap; -import com.hp.hpl.jena.query.ResultSet; -import com.hp.hpl.jena.query.Syntax; -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.rdf.model.Statement; -import com.hp.hpl.jena.shared.Lock; - -import edu.cornell.mannlib.vitro.webapp.search.beans.StatementToURIsToUpdate; - -public class AdditionalURIsForContextNodes implements StatementToURIsToUpdate { - - private OntModel model; - private Set alreadyChecked; - private long accumulatedTime = 0; - - private static final List multiValuedQueriesForAgent = new ArrayList(); - private static final String multiValuedQueryForInformationResource; - private static final List multiValuedQueriesForRole = new ArrayList(); - private static final ListqueryList; - - private Log log = LogFactory.getLog(AdditionalURIsForContextNodes.class); - - - public AdditionalURIsForContextNodes( OntModel jenaOntModel){ - this.model = jenaOntModel; - } - - @Override - public List findAdditionalURIsToIndex(Statement stmt) { - - if( stmt != null ){ - long start = System.currentTimeMillis(); - - ListurisToIndex = new ArrayList(); - if(stmt.getSubject() != null && stmt.getSubject().isURIResource() ){ - String subjUri = stmt.getSubject().getURI(); - if( subjUri != null && ! alreadyChecked.contains( subjUri )){ - urisToIndex.addAll( findAdditionalURIsToIndex(subjUri)); - alreadyChecked.add(subjUri); - } - } - - if( stmt.getObject() != null && stmt.getObject().isURIResource() ){ - String objUri = stmt.getSubject().getURI(); - if( objUri != null && ! alreadyChecked.contains(objUri)){ - urisToIndex.addAll( findAdditionalURIsToIndex(objUri)); - alreadyChecked.add(objUri); - } - } - - accumulatedTime += (System.currentTimeMillis() - start ) ; - return urisToIndex; - }else{ - return Collections.emptyList(); - } - } - - @Override - public void startIndexing() { - alreadyChecked = new HashSet(); - accumulatedTime = 0L; - } - - @Override - public void endIndxing() { - log.debug( "Accumulated time for this run of the index: " + accumulatedTime + " msec"); - alreadyChecked = null; - } - - protected List findAdditionalURIsToIndex(String uri) { - - List uriList = new ArrayList(); - - for(String query : queryList){ - - //log.info("Executing query: "+ query); - - QuerySolutionMap initialBinding = new QuerySolutionMap(); - Resource uriResource = ResourceFactory.createResource(uri); - initialBinding.add("uri", uriResource); - - Query sparqlQuery = QueryFactory.create( query, Syntax.syntaxARQ); - model.getLock().enterCriticalSection(Lock.READ); - try{ - QueryExecution qExec = QueryExecutionFactory.create(sparqlQuery, model, initialBinding); - try{ - ResultSet results = qExec.execSelect(); - while(results.hasNext()){ - QuerySolution soln = results.nextSolution(); - Iterator iter = soln.varNames() ; - while( iter.hasNext()){ - String name = iter.next(); - RDFNode node = soln.get( name ); - if( node != null ){ - uriList.add("" + node.toString()); - }else{ - log.debug(name + " is null"); - } - } - } - }catch(Throwable t){ - log.error(t,t); - } finally{ - qExec.close(); - } - }finally{ - model.getLock().leaveCriticalSection(); - } - } - - if( log.isDebugEnabled() ) - log.debug( "additional uris for " + uri + " are " + uriList); - - return uriList; - } - - - private static final String prefix = "prefix owl: \n" - + " prefix vitroDisplay: \n" - + " prefix rdf: \n" - + " prefix core: \n" - + " prefix foaf: \n" - + " prefix obo: \n" - + " prefix vcard: \n" - + " prefix event: \n" - + " prefix rdfs: \n" - + " prefix localNav: \n" - + " prefix bibo: \n"; - - static{ - - // If a person changes then update - // organizations for positions - multiValuedQueriesForAgent.add(prefix + - "SELECT DISTINCT \n" + - " (str(?i) as ?positionInOrganization) \n" + - " WHERE {\n" - - + "?uri rdf:type foaf:Agent ; core:relatedBy ?c . \n" - + " ?c rdf:type core:Position . \n" - - + " OPTIONAL { ?c core:relates ?i . ?i rdf:type foaf:Organization } . \n" - + " }"); - - // If a person changes then update - // advisee, linkedAuthor and informationResource - multiValuedQueriesForAgent.add(prefix + - "SELECT (str(?d) as ?advisee) \n" + - " (str(?f) as ?linkedAuthor) (str(?h) as ?linkedInformationResource) WHERE { {\n" - - + "?uri rdf:type foaf:Agent . \n" - + "?uri core:relatedBy ?c . \n" - + "?c rdf:type core:AdvisingRelationship . \n" - + "?c core:relates ?d . \n" - + "?d rdf:type core:AdviseeRole . \n" - + "?d obo:RO_0000052 ?e . \n" - + "?e rdf:type foaf:Person . \n" - + "} \n" - + "UNION { \n" - + " ?uri rdf:type foaf:Agent . \n" - + " ?uri core:relatedBy ?c . \n" - + " ?c rdf:type core:Authorship . \n" - + " OPTIONAL {?c core:relates ?f . \n" - + " ?f rdf:type foaf:Person . } \n" - + " OPTIONAL { ?c core:relates ?h . \n" - + " ?h rdf:type obo:IAO_0000030 . } \n" - + " } } "); - - // If a person changes then update - // award giver - multiValuedQueriesForAgent.add(prefix + - "SELECT (str(?d) as ?awardConferredBy) \n" + - "WHERE {\n" - - + "?uri rdf:type foaf:Agent ; ?b ?c . \n" - + " ?c rdf:type core:AwardReceipt . \n" - - + " OPTIONAL { ?c core:assignedBy ?d . } . \n" - + " }"); - - // If a person changes then update - // organization for role - multiValuedQueriesForAgent.add(prefix + - "SELECT (str(?Organization) as ?organization) \n" + - "WHERE {\n" - - + "?uri rdf:type foaf:Agent ; ?b ?c . \n" - + " ?c rdf:type obo:BFO_0000023 ; obo:BFO_0000054 ?Organization .\n" - + " }"); - - // If a person changes then update - // organization in educational training - multiValuedQueriesForAgent.add(prefix + - "SELECT \n" + - "(str(?e) as ?trainingAtOrganization) WHERE {\n" - - + " ?uri rdf:type foaf:Agent ; ?b ?c . \n" - + " ?c rdf:type core:EducationalProcess . \n" - - + " OPTIONAL { ?c obo:RO_0000057 ?e . \n" - + " ?e rdf:type foaf:Organization . } . " - +"}"); - - // If an organization changes then update - // people in head of relations - multiValuedQueriesForAgent.add( - " # for organization, get leader \n" + - prefix + - "SELECT \n" + - "(str(?e) as ?LeaderPerson ) WHERE {\n" - - + " ?uri rdf:type foaf:Agent . \n" - + " ?uri core:contributingRole ?c . \n" - + " ?c rdf:type core:LeaderRole . \n" - - + " OPTIONAL { ?c obo:RO_0000052 ?e . \n" - + " ?e rdf:type foaf:Person . } . " - +"}"); - - } - - //multivalued query for core:InformationResource - static { - - multiValuedQueryForInformationResource = prefix + - "SELECT (str(?b) as ?linkedAuthor) (str(?d) as ?linkedInformationResource) \n" - + "(str(?f) as ?editor) \n" + - "(str(?i) as ?features) WHERE {\n" - - + " ?uri rdf:type obo:IAO_0000030 . \n" - - + " OPTIONAL { ?uri core:relatedBy ?a . \n" - + " ?a rdf:type core:Authorship . \n" - + " ?a core:relates ?b . ?b rdf:type foaf:Person .\n" - + " ?a core:relates ?d . ?d rdf:type obo:IAO_0000030 .\n" - + "} . " - - + " OPTIONAL { ?uri core:relatedBy ?e . \n" - + " ?e rdf:type core:Editorship . \n" - + " ?e core:relates ?f . ?f rdf:type foaf:Person .\n" - + "} . " - + " OPTIONAL { ?uri core:features ?i . } . \n" - - +"}" ; - - } - - protected static List queriesForAuthorship(){ - List queries = new ArrayList(); - - //get additional URIs of information resources from author side - queries.add( - prefix - + "SELECT (str(?a) as ?infoResource) WHERE {\n" - - + " ?uri rdf:type foaf:Person . \n" - + " ?uri core:relatedBy ?aship .\n" - + " ?aship rdf:type core:Authorship .\n" - + "OPTIONAL { ?aship core:relates ?a . ?a rdf:type obo:IAO_0000030 } .\n" - +"}" ); - - //get additional URIs of authors from information resource side - queries.add( - prefix - + "SELECT (str(?a) as ?author ) WHERE {\n" - - + " ?uri rdf:type obo:IAO_0000030 . \n" - + " ?uri core:relatedBy ?aship . ?aship rdf:type core:Authorship . \n" - + "OPTIONAL { ?aship core:relates ?a . ?a rdf:type foaf:Person } .\n" - +"}" ); - return queries; - } - - protected static List queriesForURLLink(){ - List queries = new ArrayList(); - - //get additional URIs when URLLink is changed - queries.add( - prefix - + "SELECT (str(?x) as ?individual) WHERE {\n" - - + " ?i rdf:type vcard:Individual . \n" - + " ?i vcard:hasURL ?uri . \n" - + " ?i obo:ARG_2000029 ?x . \n" - +"}" ); - - return queries; - } - - protected static List queriesForEducationalTraining(){ - List queries = new ArrayList(); - - //if person changes, no additional URIs need to be - //changed because the person is not displayed on the - //degree individual or on the degree granting organization - - //if the degree changes, the person needs to be updated - //since the degree name is shown on the person page. - queries.add( - prefix - + " SELECT (str(?person) as ?personUri) WHERE {\n" - - + " ?uri rdf:type core:AcademicDegree . \n" - + " ?uri core:relatedBy ?awardedDegree .\n" - + " ?awardedDegree rdf:type core:AwardedDegree .\n" - + " ?awardedDegree core:relates ?person .\n" - + " ?person rdf:type foaf:Person .\n" - +"}" ); - - //if the organization changes the person needs to be updated - //since the organization name is shown on the person page. - queries.add( - prefix - + " SELECT (str(?person) as ?personUri) WHERE {\n" - - + " ?uri rdf:type foaf:Organization . \n" - + " ?uri obo:RO_0000056 ?edTrainingNode .\n" - + " ?edTrainingNode rdf:type core:EducationalProcess . \n" - + " ?edTrainingNode obo:RO_0000057 ?person . \n" - + " ?person rdf:type foaf:Person ." - +"}" ); - return queries; - } - - protected static List queriesForPosition(){ - List queries = new ArrayList(); - - //If an organization changes, update people - queries.add( - prefix - + " SELECT (str(?person) as ?personUri) WHERE {\n" - - + " ?uri rdf:type foaf:Organization . \n" - + " ?uri core:relatedBy ?positionNode .\n" - + " ?positionNode rdf:type core:Position .\n" - + " ?positionNode core:relates ?person . \n" - + " ?person rdf:type foaf:Person .\n" - +"}" ); - - - //if people change, update organizations - queries.add( - prefix - + " SELECT (str(?org) as ?orgUri) WHERE {\n" - - + " ?uri rdf:type foaf:Person . \n" - + " ?uri core:relatedBy ?positionNode .\n" - + " ?positionNode rdf:type core:Position .\n" - + " ?positionNode core:relates ?org . \n" - + " ?org rdf:type foaf:Organization .\n" - +"}" ); - return queries; - } - - static{ - // core:AttendeeRole - // If the person changes, update the attendee role in organization - // core:AttendeeRole applies to events, not organizations; updating accordingly - tlw72 - multiValuedQueriesForRole.add(prefix + - "SELECT (str(?d) as ?event) \n " + - "WHERE {\n" - + "?uri rdf:type foaf:Person . \n" - + "?uri obo:RO_0000053 ?c . \n" - + "?c rdf:type core:AttendeeRole . \n" - + "?c obo:BFO_0000054 ?d . \n" - + "?d rdf:type event:Event .\n" - + " }"); - - // If the organization changes, update the attendee role of person - // core:AttendeeRole applies to events, not organizations; updating accordingly - tlw72 - multiValuedQueriesForRole.add(prefix + - "SELECT (str(?d) as ?person) \n" + - "WHERE {\n" - - + "?uri rdf:type event:Event . \n" - + "?uri obo:BFO_0000055 ?c . \n" - + "?c rdf:type core:AttendeeRole . \n" - + "?c obo:RO_0000052 ?d . \n" - + "?d rdf:type foaf:Person .\n" - + " }"); - - // core:ClinicalRole -- core:clinicalRoleOf - - // If the person changes, update the clinical role in project - multiValuedQueriesForRole.add(prefix + - "SELECT (str(?d) as ?project) \n" + - "WHERE {\n" - + "?uri rdf:type foaf:Person . \n" - + "?uri obo:RO_0000053 ?c . \n" - + "?c rdf:type core:ClinicalRole . \n" - + "?c obo:BFO_0000054 ?d .\n" - + "?d rdf:type core:Project .\n" - + " }"); - - - // If the person changes, update the clinical role in service - multiValuedQueriesForRole.add(prefix + - "SELECT (str(?d) as ?service) \n" + - "WHERE {\n" - + "?uri rdf:type foaf:Person . \n" - + "?uri obo:RO_0000053 ?c . \n" - + "?c rdf:type core:ClinicalRole . \n" - + "?c core:roleContributesTo ?d .\n" - + "?d rdf:type obo:ERO_0000005 .\n" - + " }"); - - // If the project changes, update the clinical role of person - multiValuedQueriesForRole.add(prefix + - "SELECT (str(?d) as ?person) \n" + - "WHERE {\n" - + "?uri rdf:type core:Project . \n" - + "?uri obo:BFO_0000055 ?c . \n" - + "?c rdf:type core:ClinicalRole . \n" - + "?c obo:RO_0000052 ?d .\n " - + "?d rdf:type foaf:Person .\n " - + " }"); - - // If the service changes, update the clinical role of person - multiValuedQueriesForRole.add(prefix + - "SELECT (str(?d) as ?person) \n" + - "WHERE {\n" - + "?uri rdf:type obo:ERO_0000005 . \n" - + "?uri core:contributingRole ?c . \n" - + "?c rdf:type core:ClinicalRole . \n" - + "?c obo:RO_0000052 ?d .\n " - + "?d rdf:type foaf:Person .\n " - + " }"); - - // If the person changes, update the leader role in organization - multiValuedQueriesForRole.add(prefix + - "SELECT (str(?d) as ?organization) \n" + - "WHERE {\n" - + "?uri rdf:type foaf:Person . \n" - + "?uri obo:RO_0000053 ?c . \n" - + "?c rdf:type core:LeaderRole . \n" - + "?c core:roleContributesTo ?d .\n" - + "?d rdf:type foaf:Organization .\n " - + " }"); - - // If the organization changes, update the leader role of person - multiValuedQueriesForRole.add(prefix + - "SELECT (str(?d) as ?person) \n" + - "WHERE {\n" - + "?uri rdf:type foaf:Organization . \n" - + "?uri core:contributingRole ?c . \n" - + "?c rdf:type core:LeaderRole . \n" - + "?c obo:RO_0000052 ?d .\n " - + "?d rdf:type foaf:Person .\n " - + " }"); - - // core:MemberRole -- core:memberRoleOf - - // If the person changes, update the member role in organization - multiValuedQueriesForRole.add(prefix + - "SELECT (str(?d) as ?organization) \n" + - "WHERE \n{" - + "?uri rdf:type foaf:Person . \n" - + "?uri obo:RO_0000053 ?c . \n" - + "?c rdf:type core:MemberRole . \n" - + "?c core:roleContributesTo ?d .\n" - + "?d rdf:type foaf:Organization .\n " - + " }"); - - // If the organization changes, update the member role of person - multiValuedQueriesForRole.add(prefix + - "SELECT (str(?d) as ?person) \n" + - "WHERE {" - + "?uri rdf:type foaf:Organization . \n" - + "?uri core:contributingRole ?c . \n" - + "?c rdf:type core:MemberRole . \n" - + "?c obo:RO_0000052 ?d .\n " - + "?d rdf:type foaf:Person .\n " - + " }"); - - // core:OrganizerRole -- core:organizerRoleOf - - // If the person changes, update the organizer role in organization - // organizerRole appplies to events not organizations; updating accordingly - tlw72 - multiValuedQueriesForRole.add(prefix + - "SELECT (str(?d) as ?event) \n" + - "WHERE {" - + "?uri rdf:type foaf:Person . \n" - + "?uri obo:RO_0000053 ?c . \n" - + "?c rdf:type core:OrganizerRole .\n" - + "?c obo:BFO_0000054 ?d .\n" - + "?d rdf:type event:Event .\n " - + " }"); - - // If the organization changes, update the organizer role of person - // organizerRole appplies to events not organizations; updating accordingly - tlw72 - multiValuedQueriesForRole.add(prefix + - "SELECT (str(?d) as ?person) \n" + - "WHERE {\n" - + "?uri rdf:type event:Event . \n" - + "?uri obo:BFO_0000055 ?c . \n" - + "?c rdf:type core:OrganizerRole . \n" - + "?c obo:RO_0000052 ?d .\n " - + "?d rdf:type foaf:Person .\n " - + " }"); - - // core:OutreachProviderRole -- core:outreachProviderRoleOf - - // If the person changes, update the outreach provider role in organization - multiValuedQueriesForRole.add(prefix + - "SELECT (str(?d) as ?organization) \n" + - "WHERE {\n" - + "?uri rdf:type foaf:Person . \n" - + "?uri obo:RO_0000053 ?c . \n" - + "?c rdf:type core:OutreachProviderRole .\n" - + "?c core:roleContributesTo ?d .\n" - + "?d rdf:type foaf:Organization .\n " - + " }"); - - // If the organization changes, update the outreach provider role of person - multiValuedQueriesForRole.add(prefix + - "SELECT (str(?d) as ?person) \n" + - "WHERE {\n" - + "?uri rdf:type foaf:Organization . \n" - + "?uri core:contributingRole ?c . \n" - + "?c rdf:type core:OutreachProviderRole . \n" - + "?c obo:RO_0000052 ?d .\n " - + "?d rdf:type foaf:Person .\n " - + " }"); - - // core:PresenterRole -- core:presenterRoleOf - - // If the person changes, update the presentation - multiValuedQueriesForRole.add(prefix + - "SELECT (str(?d) as ?presentation) \n" + - "WHERE {\n" - + "?uri rdf:type foaf:Person . \n" - + "?uri obo:RO_0000053 ?c . \n" - + " ?c rdf:type core:PresenterRole . \n" - + " ?c obo:BFO_0000054 ?d .\n" - + " ?d rdf:type core:Presentation . \n" - + " }"); - - // If the presentation changes, update the person - multiValuedQueriesForRole.add(prefix + - "SELECT (str(?d) as ?person) \n" + - "WHERE {\n" - + "?uri rdf:type core:Presentation . \n" - + "?uri obo:BFO_0000055 ?c . \n" - + " ?c rdf:type core:PresenterRole . \n " - + "?c obo:RO_0000052 ?d .\n " - + "?d rdf:type foaf:Person .\n " - + " }"); - - // core:ResearcherRole -- core:researcherRoleOf - - // If the person changes, update the grant - multiValuedQueriesForRole.add(prefix + - "SELECT (str(?d) as ?grant) \n" + - "WHERE {\n" - + "?uri rdf:type foaf:Person . \n" - + "?uri obo:RO_0000053 ?c . \n" - + " ?c rdf:type core:ResearcherRole . \n " - + " ?c core:relatedBy ?d .\n" - + " ?d rdf:type core:Grant . \n" - + " }"); - - // If the grant changes, update the researcher - multiValuedQueriesForRole.add(prefix + - "SELECT (str(?d) as ?person) \n" + - "WHERE {\n" - + "?uri rdf:type core:Grant . \n" - + "?uri core:relates ?c . \n" - + " ?c rdf:type core:ResearcherRole . \n " - + " ?c obo:RO_0000052 ?d .\n" - + "?d rdf:type foaf:Person .\n " - + " }"); - - // If the grant changes, update the principal investigator - multiValuedQueriesForRole.add(prefix + - "SELECT (str(?d) as ?person) \n" + - "WHERE {\n" - + "?uri rdf:type core:Grant . \n" - + " ?uri core:relates ?c . \n" - + " ?c rdf:type core:PrincipalInvestigatorRole . \n " - + " ?c obo:RO_0000052 ?d .\n" - + "?d rdf:type foaf:Person .\n " - + " }"); - - // If the grant changes, update the co-principal investigator - multiValuedQueriesForRole.add(prefix + - "SELECT (str(?d) as ?person) \n" + - "WHERE {\n" - + "?uri rdf:type core:Grant . \n" - + " ?uri core:relates ?c . \n" - + " ?c rdf:type core:CoPrincipalInvestigatorRole . \n " - + " ?c obo:RO_0000052 ?d .\n" - + "?d rdf:type foaf:Person .\n " - + " }"); - - - // If the grant changes, update the investigator - multiValuedQueriesForRole.add(prefix + - "SELECT (str(?d) as ?person) \n" + - "WHERE {\n" - + "?uri rdf:type core:Grant . \n" - + " ?uri core:relates ?c . \n" - + " ?c rdf:type core:InvestigatorRole . \n " - + " ?c obo:RO_0000052 ?d .\n" - + "?d rdf:type foaf:Person .\n " - + " }"); - - // If the person changes, update the project - multiValuedQueriesForRole.add(prefix + - "SELECT (str(?d) as ?project) \n" + - "WHERE {\n" - + "?uri rdf:type foaf:Person . \n" - + "?uri obo:RO_0000053 ?c . \n" - + " ?c rdf:type core:ResearcherRole . \n " - + " ?c obo:BFO_0000054 ?d .\n" - + " ?d rdf:type core:Project . \n" - + " }"); - - // If the project changes, update the researcher - multiValuedQueriesForRole.add(prefix + - "SELECT (str(?d) as ?person) \n" + - "WHERE {\n" - + "?uri rdf:type core:Project . \n" - + " ?uri obo:BFO_0000055 ?c .\n" - + " ?c rdf:type core:ResearcherRole . \n " - + " ?c obo:RO_0000052 ?d .\n" - + "?d rdf:type foaf:Person .\n " - + " }"); - - // core:EditorRole -- core:editorRoleOf, core:forInformationResource (person, informationresource) - - // If the person changes, update the editor role of the info resource - // changing foaf:Organization to info content entity. Org no longer applies here - tlw72 - multiValuedQueriesForRole.add(prefix + - "SELECT (str(?d) as ?informationResource) \n" + - "WHERE {\n" - + "?uri rdf:type foaf:Person . \n" - + "?uri obo:RO_0000053 ?c . \n" - + " ?c rdf:type core:EditorRole . \n " - + " ?c core:roleContributesTo ?d .\n" - + "?d rdf:type obo:IAO_0000030 .\n " - + " }"); - - - // If the info respource changes, update the editor role of person - // changing foaf:Organization to info content entity. Org no longer applies here - tlw72 - multiValuedQueriesForRole.add(prefix + - "SELECT (str(?d) as ?person) \n" + - "WHERE {\n" - + "?uri rdf:type obo:IAO_0000030 . \n" - + "?uri core:contributingRole ?c . \n" - + " ?c rdf:type core:EditorRole . \n " - + " ?c obo:RO_0000052 ?d .\n" - + "?d rdf:type foaf:Person .\n " - + " }"); - - // Next two queries are covered by the previous two. Commenting them out - tlw72 - // If the person changes, update the information resource associated with editor role -/* multiValuedQueriesForRole.add(prefix + - "SELECT (str(?d) as ?informationResource) \n" + - "WHERE {\n" - - + "?uri rdf:type foaf:Person ; ?b ?c . \n" - + " ?c rdf:type core:EditorRole ; core:forInformationResource ?d .\n" - + " }"); - - // If the organization changes, update the information resource associated with editor role - multiValuedQueriesForRole.add(prefix + - "SELECT (str(?d) as ?informationResource) \n" + - "WHERE {\n" - - + "?uri rdf:type foaf:Organization ; ?b ?c . \n" - + " ?c rdf:type core:EditorRole ; core:forInformationResource ?d .\n" - + " }"); -*/ - // core:ServiceProviderRole -- core:serviceProviderRoleOf - - // If the person changes, update the service provider role in organization - multiValuedQueriesForRole.add(prefix + - "SELECT (str(?d) as ?organization) \n" + - "WHERE {\n" - + "?uri rdf:type foaf:Person . \n" - + "?uri obo:RO_0000053 ?c . \n" - + " ?c rdf:type obo:ERO_0000012 . \n" - + " ?c core:roleContributesTo ?d .\n" - + " ?d rdf:type foaf:Organization .\n " - + " }"); - - // If the organization changes, update the service provider role of person - multiValuedQueriesForRole.add(prefix + - "SELECT (str(?d) as ?person) \n" + - "WHERE {\n" - + "?uri rdf:type foaf:Organization . \n" - + "?uri core:contributingRole ?c . \n" - + " ?c rdf:type obo:ERO_0000012 . \n " - + " ?c obo:RO_0000052 ?d .\n" - + "?d rdf:type foaf:Person .\n " - + " }"); - - - // core:TeacherRole -- core:teacherRoleOf - - // If the person changes, update the teacher role in organization - // updated to make this an Event (e.g., a course) not an organization - tlw72 - multiValuedQueriesForRole.add(prefix + - "SELECT (str(?d) as ?event) \n" + - "WHERE {\n" - + "?uri rdf:type foaf:Person . \n" - + "?uri obo:RO_0000053 ?c . \n" - + " ?c rdf:type core:TeacherRole . \n" - + " ?c obo:BFO_0000054 ?d .\n" - + " ?d rdf:type event:Event .\n " - + " }"); - - // If the organization changes, update the teacher role of person - // updated to make this an Event (e.g., a course) not an organization - tlw72 - multiValuedQueriesForRole.add(prefix + - "SELECT (str(?d) as ?person) \n" + - "WHERE {\n" - + "?uri rdf:type event:Event . \n" - + "?uri obo:BFO_0000055 ?c . \n" - + " ?c rdf:type core:TeacherRole . \n " - + " ?c obo:RO_0000052 ?d .\n" - + "?d rdf:type foaf:Person .\n " - + " }"); - - - // core:ReviewerRole -- core:forInformationResource, core:reviewerRoleOf -// core:PeerReviewerRole -- core:forInformationResource, core:reviewerRoleOf - - // If the person changes, update the reviewer role in organization - // There is no relationship between a reviewerRole and an organization; commenting - // the next two queries out - tlw72 -/* multiValuedQueriesForRole.add(prefix + - "SELECT (str(?d) as ?organization) \n" + - "WHERE {\n" - - + "?uri rdf:type foaf:Person ; ?b ?c . \n" - + " ?c rdf:type core:ReviewerRole ; core:roleIn ?d .\n" - + " }"); - - - // If the organization changes, update the reviewer role of person - - multiValuedQueriesForRole.add(prefix + - "SELECT (str(?d) as ?person) \n" + - "WHERE {\n" - - + "?uri rdf:type foaf:Organization ; ?b ?c . \n" - + " ?c rdf:type core:ReviewerRole ; core:reviewerRoleOf ?d .\n" - + " }"); -*/ - // If the person changes, update the information resource associated with reviewer role - multiValuedQueriesForRole.add(prefix + - "SELECT (str(?d) as ?informationResource) \n " + - "WHERE {\n" - + "?uri rdf:type foaf:Person . \n" - + "?uri obo:RO_0000053 ?c . \n" - + " ?c rdf:type core:ReviewerRole . \n" - + " ?c core:roleContributesTo ?d .\n" - + " ?d rdf:type obo:IAO_0000030 .\n " - + " }"); - - // If the organization changes, update the information resource associated with reviewer role - multiValuedQueriesForRole.add(prefix + - "SELECT (str(?d) as ?informationResource) \n" + - "WHERE {\n" - + "?uri rdf:type obo:IAO_0000030 . \n" - + "?uri core:contributingRole ?c . \n" - + " ?c rdf:type core:ReviewerRole. \n " - + " ?c obo:RO_0000052 ?d .\n" - + "?d rdf:type foaf:Person .\n " - + " }"); - - } - - static{ - List tmpList = new ArrayList(); - tmpList.add(multiValuedQueryForInformationResource); - tmpList.addAll(multiValuedQueriesForAgent); - tmpList.addAll(multiValuedQueriesForRole); - tmpList.addAll( queriesForAuthorship()); - tmpList.addAll(queriesForURLLink()); - tmpList.addAll(queriesForEducationalTraining()); - tmpList.addAll(queriesForPosition()); - - queryList = Collections.unmodifiableList(tmpList); - } - -} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/search/indexing/AdditionalUriFinders.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/search/indexing/AdditionalUriFinders.java new file mode 100644 index 000000000..498d74334 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/search/indexing/AdditionalUriFinders.java @@ -0,0 +1,30 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.search.indexing; + +import java.util.ArrayList; +import java.util.List; + +import com.hp.hpl.jena.ontology.OntModel; + +import edu.cornell.mannlib.vitro.webapp.dao.IndividualDao; +import edu.cornell.mannlib.vitro.webapp.search.beans.StatementToURIsToUpdate; + +/** + * Make a list of StatementToURIsToUpdate objects for use by the + * IndexBuidler. + */ +public class AdditionalUriFinders { + + public static List getList(OntModel jenaOntModel, + IndividualDao indDao) { + // TODO How many of these are only relevant to VIVO? + List uriFinders = new ArrayList<>(); + uriFinders.add(new AdditionalURIsForDataProperties()); + uriFinders.add(new AdditionalURIsForObjectProperties(jenaOntModel)); + uriFinders.add(new AdditionalURIsForTypeStatements()); + uriFinders.add(new URIsForClassGroupChange(indDao)); + return uriFinders; + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/search/indexing/IndexBuilder.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/search/indexing/IndexBuilder.java index 0d7fea706..69e2ba3ee 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/search/indexing/IndexBuilder.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/search/indexing/IndexBuilder.java @@ -281,11 +281,24 @@ public class IndexBuilder extends VitroBackgroundThread { //keep uris unique by using a HashSet Collection urisToUpdate = new HashSet(); - for( Statement stmt : getAndClearChangedStmts() ){ - for( StatementToURIsToUpdate stu : stmtToURIsToIndexFunctions ){ - urisToUpdate.addAll( stu.findAdditionalURIsToIndex(stmt) ); - } - } + Statement[] changedStatements = getAndClearChangedStmts(); + int howManyChanges = changedStatements.length; + + if (howManyChanges > 100) { + log.info("Finding URIs that are affected by " + howManyChanges + + " changed statements."); + } + + for (int i = 0; i < howManyChanges; i++) { + Statement stmt = changedStatements[i]; + for (StatementToURIsToUpdate stu : stmtToURIsToIndexFunctions) { + urisToUpdate.addAll(stu.findAdditionalURIsToIndex(stmt)); + } + if ((i > 0) && (i % 1000 == 0)) { + log.info("Processed " + i + " changed statements; found " + + urisToUpdate.size() + " affected URIs."); + } + } //inform StatementToURIsToUpdate that they are done for( StatementToURIsToUpdate stu : stmtToURIsToIndexFunctions ) { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/search/indexing/IndexWorkerThread.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/search/indexing/IndexWorkerThread.java index 6008d330f..57caebb5d 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/search/indexing/IndexWorkerThread.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/search/indexing/IndexWorkerThread.java @@ -12,8 +12,10 @@ import edu.cornell.mannlib.vitro.webapp.beans.Individual; import edu.cornell.mannlib.vitro.webapp.search.IndexingException; import edu.cornell.mannlib.vitro.webapp.search.beans.IndexerIface; import edu.cornell.mannlib.vitro.webapp.search.solr.documentBuilding.IndividualToSolrDocument; +import edu.cornell.mannlib.vitro.webapp.utils.threads.VitroBackgroundThread; -class IndexWorkerThread extends Thread{ +class IndexWorkerThread extends VitroBackgroundThread{ + private static final Log log = LogFactory.getLog(IndexWorkerThread.class); protected final int threadNum; protected IndividualToSolrDocument individualToSolrDoc; @@ -21,7 +23,6 @@ class IndexWorkerThread extends Thread{ protected final Iterator individualsToIndex; protected boolean stopRequested = false; - private Log log = LogFactory.getLog(IndexWorkerThread.class); private static AtomicLong countCompleted= new AtomicLong(); private static AtomicLong countToIndex= new AtomicLong(); private static long starttime = 0; @@ -38,7 +39,8 @@ class IndexWorkerThread extends Thread{ } public void run(){ - + setWorkLevel(WorkLevel.WORKING, "indexing " + individualsToIndex + " individuals"); + while( ! stopRequested ){ //do the actual indexing work @@ -48,7 +50,9 @@ class IndexWorkerThread extends Thread{ // done so shut this thread down. stopRequested = true; } - log.debug("Worker number " + threadNum + " exiting."); + setWorkLevel(WorkLevel.IDLE); + + log.debug("Worker number " + threadNum + " exiting."); } protected void addDocsToIndex() { @@ -82,8 +86,8 @@ class IndexWorkerThread extends Thread{ } } }catch(Throwable th){ - //on tomcat shutdown odd exceptions get thrown and log can be null - if( log != null && ! stopRequested ) + //on tomcat shutdown odd exceptions get thrown + if( ! stopRequested ) log.error("Exception during index building",th); } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/search/solr/SolrSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/search/solr/SolrSetup.java index d8f72363c..04ae6971d 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/search/solr/SolrSetup.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/search/solr/SolrSetup.java @@ -2,8 +2,6 @@ package edu.cornell.mannlib.vitro.webapp.search.solr; -import java.net.MalformedURLException; -import java.net.URL; import java.util.ArrayList; import java.util.List; @@ -18,7 +16,6 @@ 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.IndividualDao; import edu.cornell.mannlib.vitro.webapp.dao.ModelAccess; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; @@ -29,13 +26,9 @@ import edu.cornell.mannlib.vitro.webapp.dao.jena.ModelContext; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceFactory; import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils; import edu.cornell.mannlib.vitro.webapp.search.beans.StatementToURIsToUpdate; -import edu.cornell.mannlib.vitro.webapp.search.indexing.AdditionalURIsForContextNodes; -import edu.cornell.mannlib.vitro.webapp.search.indexing.AdditionalURIsForDataProperties; -import edu.cornell.mannlib.vitro.webapp.search.indexing.AdditionalURIsForObjectProperties; -import edu.cornell.mannlib.vitro.webapp.search.indexing.AdditionalURIsForTypeStatements; +import edu.cornell.mannlib.vitro.webapp.search.indexing.AdditionalUriFinders; import edu.cornell.mannlib.vitro.webapp.search.indexing.IndexBuilder; import edu.cornell.mannlib.vitro.webapp.search.indexing.SearchReindexingListener; -import edu.cornell.mannlib.vitro.webapp.search.indexing.URIsForClassGroupChange; import edu.cornell.mannlib.vitro.webapp.search.solr.documentBuilding.DocumentModifier; import edu.cornell.mannlib.vitro.webapp.search.solr.documentBuilding.ExcludeBasedOnNamespace; import edu.cornell.mannlib.vitro.webapp.search.solr.documentBuilding.ExcludeBasedOnType; @@ -140,7 +133,7 @@ public class SolrSetup implements javax.servlet.ServletContextListener{ wadf = new WebappDaoFactoryFiltering(wadf, vf); // make objects that will find additional URIs for context nodes etc - List uriFinders = makeURIFinders(jenaOntModel,wadf.getIndividualDao()); + List uriFinders = AdditionalUriFinders.getList(jenaOntModel,wadf.getIndividualDao()); // Make the IndexBuilder IndexBuilder builder = new IndexBuilder( solrIndexer, wadf, uriFinders ); @@ -159,22 +152,6 @@ public class SolrSetup implements javax.servlet.ServletContextListener{ } - /** - * Make a list of StatementToURIsToUpdate objects for use by the - * IndexBuidler. - * @param indDao - */ - public List makeURIFinders( OntModel jenaOntModel, IndividualDao indDao ){ - List uriFinders = new ArrayList(); - uriFinders.add( new AdditionalURIsForDataProperties() ); - uriFinders.add( new AdditionalURIsForObjectProperties(jenaOntModel) ); - uriFinders.add( new AdditionalURIsForContextNodes(jenaOntModel) ); - uriFinders.add( new AdditionalURIsForTypeStatements() ); - uriFinders.add( new URIsForClassGroupChange( indDao )); - return uriFinders; - } - - @Override public void contextDestroyed(ServletContextEvent sce) { IndexBuilder builder = (IndexBuilder)sce.getServletContext().getAttribute(IndexBuilder.class.getName()); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/search/solr/documentBuilding/CalculateParameters.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/search/solr/documentBuilding/CalculateParameters.java deleted file mode 100644 index 0ae3eca19..000000000 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/search/solr/documentBuilding/CalculateParameters.java +++ /dev/null @@ -1,300 +0,0 @@ -/* $This file is distributed under the terms of the license in /doc/license.txt$ */ - -package edu.cornell.mannlib.vitro.webapp.search.solr.documentBuilding; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.StringTokenizer; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.solr.common.SolrInputDocument; -import org.apache.solr.common.SolrInputField; - -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.QuerySolutionMap; -import com.hp.hpl.jena.query.ResultSet; -import com.hp.hpl.jena.query.Syntax; -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; - -import edu.cornell.mannlib.vitro.webapp.beans.Individual; -import edu.cornell.mannlib.vitro.webapp.search.VitroSearchTermNames; - - -public class CalculateParameters implements DocumentModifier { - - private boolean shutdown = false; - private Dataset dataset; - // public static int totalInd=1; - - private static final String prefix = "prefix owl: " - + " prefix vitroDisplay: " - + " prefix rdf: " - + " prefix core: " - + " prefix foaf: " - + " prefix rdfs: " - + " prefix localNav: " - + " prefix bibo: "; - - private static final String betaQuery = prefix + " SELECT count(distinct ?inLinks) " + - " WHERE { " + - " ?uri rdf:type owl:Thing . " + - " ?inLinks ?prop ?uri . " + - " } "; - - private static final String totalCountQuery = prefix + " SELECT count(distinct ?ind) " + - " WHERE { " + - " ?ind rdf:type owl:Thing . " + - " } "; - - private static Log log = LogFactory.getLog(CalculateParameters.class); - - public CalculateParameters(Dataset dataset){ - this.dataset =dataset; - // new Thread(new TotalInd(this.dataset,totalCountQuery)).start(); - } - - public CalculateParameters(){ - super(); - } - - public float calculateBeta(String uri){ - float beta=0; - int Conn=0; - Query query; - QuerySolutionMap initialBinding = new QuerySolutionMap(); - QuerySolution soln = null; - Resource uriResource = ResourceFactory.createResource(uri); - initialBinding.add("uri", uriResource); - dataset.getLock().enterCriticalSection(Lock.READ); - QueryExecution qexec=null; - try{ - query = QueryFactory.create(betaQuery,Syntax.syntaxARQ); - qexec = QueryExecutionFactory.create(query,dataset,initialBinding); - ResultSet results = qexec.execSelect(); - List resultVars = results.getResultVars(); - if(resultVars!=null && resultVars.size()!=0){ - soln = results.next(); - Conn = Integer.parseInt(soln.getLiteral(resultVars.get(0)).getLexicalForm()); - } - }catch(Throwable t){ - if( ! shutdown ) - log.error(t,t); - }finally{ - if( qexec != null ) - qexec.close(); - dataset.getLock().leaveCriticalSection(); - } - - beta = (float)Conn; - //beta *= 100; - beta += 1; - - // sigmoid function to keep beta between 0 to 1; - - beta = (float) (1 / ( 1 + Math.pow(Math.E,(-beta)))); - - if(beta > 1) - log.info("Beta higher than 1 : " + beta); - else if(beta <= 0) - log.info("Beta lower < = 0 : " + beta); - return beta; - } - - - public String[] getAdjacentNodes(String uri){ - - List queryList = new ArrayList(); - Set adjacentNodes = new HashSet(); - Set coauthorNames = new HashSet(); - String[] info = new String[]{"",""}; - StringBuffer adjacentNodesConcat = new StringBuffer(); - StringBuffer coauthorBuff = new StringBuffer(); - adjacentNodesConcat.append(""); - coauthorBuff.append(""); - - queryList.add(prefix + - " SELECT ?adjobj (str(?adjobjLabel) as ?coauthor) " + - " WHERE { " + - " ?uri rdf:type . " + - " ?uri ?prop ?obj . " + - " ?obj rdf:type . " + - " ?obj ?prop2 ?obj2 . " + - " ?obj2 rdf:type . " + - " ?obj2 ?prop3 ?obj3 . " + - " ?obj3 rdf:type . " + - " ?obj3 ?prop4 ?adjobj . " + - " ?adjobj rdfs:label ?adjobjLabel . " + - " ?adjobj rdf:type . " + - - " FILTER (?prop !=rdf:type) . " + - " FILTER (?prop2!=rdf:type) . " + - " FILTER (?prop3!=rdf:type) . " + - " FILTER (?prop4!=rdf:type) . " + - " FILTER (?adjobj != ?uri) . " + - "}"); - - queryList.add(prefix + - " SELECT ?adjobj " + - " WHERE{ " + - - " ?uri rdf:type foaf:Agent . " + - " ?uri ?prop ?obj . " + - " ?obj ?prop2 ?adjobj . " + - - - " FILTER (?prop !=rdf:type) . " + - " FILTER isURI(?obj) . " + - - " FILTER (?prop2!=rdf:type) . " + - " FILTER (?adjobj != ?uri) . " + - " FILTER isURI(?adjobj) . " + - - " { ?adjobj rdf:type . } " + - " UNION " + - " { ?adjobj rdf:type . } " + - " UNION " + - " { ?adjobj rdf:type . } " + - " UNION " + - " { ?adjobj rdf:type . } ." + - "}"); - - Query query; - - QuerySolution soln; - QuerySolutionMap initialBinding = new QuerySolutionMap(); - Resource uriResource = ResourceFactory.createResource(uri); - - initialBinding.add("uri", uriResource); - - Iterator queryItr = queryList.iterator(); - - dataset.getLock().enterCriticalSection(Lock.READ); - Resource adjacentIndividual = null; - RDFNode coauthor = null; - try{ - while(queryItr.hasNext()){ - /*if(!isPerson){ - queryItr.next(); // we don't want first query to execute if the ind is not a person. - }*/ - query = QueryFactory.create(queryItr.next(),Syntax.syntaxARQ); - QueryExecution qexec = QueryExecutionFactory.create(query,dataset,initialBinding); - try{ - ResultSet results = qexec.execSelect(); - while(results.hasNext()){ - soln = results.nextSolution(); - - adjacentIndividual = (Resource)soln.get("adjobj"); - if(adjacentIndividual!=null){ - adjacentNodes.add(adjacentIndividual.getURI()); - } - - coauthor = soln.get("coauthor"); - if(coauthor!=null){ - coauthorNames.add(" co-authors " + coauthor.toString() + " co-authors "); - } - } - }catch(Exception e){ - if( ! shutdown ) - log.error("Error found in getAdjacentNodes method of SearchQueryHandler"); - }finally{ - qexec.close(); - } - } - queryList = null; - Iterator itr = adjacentNodes.iterator(); - while(itr.hasNext()){ - adjacentNodesConcat.append(itr.next() + " "); - } - - info[0] = adjacentNodesConcat.toString(); - - itr = coauthorNames.iterator(); - while(itr.hasNext()){ - coauthorBuff.append(itr.next()); - } - - info[1] = coauthorBuff.toString(); - - } - catch(Throwable t){ - if( ! shutdown ) - log.error(t,t); - }finally{ - dataset.getLock().leaveCriticalSection(); - adjacentNodes = null; - adjacentNodesConcat = null; - coauthorBuff = null; - } - return info; - } - - @Override - public void modifyDocument(Individual individual, SolrInputDocument doc, StringBuffer addUri) { - // TODO Auto-generated method stub - // calculate beta value. - log.debug("Parameter calculation starts.."); - float beta = calculateBeta(individual.getURI()); - doc.addField(VitroSearchTermNames.BETA, beta); - doc.setDocumentBoost(beta + doc.getDocumentBoost() ); - log.debug("Parameter calculation is done"); - } - - - public void shutdown(){ - shutdown=true; - } -} - -class TotalInd implements Runnable{ - private Dataset dataset; - private String totalCountQuery; - private static Log log = LogFactory.getLog(TotalInd.class); - - public TotalInd(Dataset dataset,String totalCountQuery){ - this.dataset = dataset; - this.totalCountQuery = totalCountQuery; - - } - public void run(){ - int totalInd=0; - Query query; - QuerySolution soln = null; - dataset.getLock().enterCriticalSection(Lock.READ); - QueryExecution qexec = null; - - try{ - query = QueryFactory.create(totalCountQuery,Syntax.syntaxARQ); - qexec = QueryExecutionFactory.create(query,dataset); - ResultSet results = qexec.execSelect(); - List resultVars = results.getResultVars(); - - if(resultVars!=null && resultVars.size()!=0){ - soln = results.next(); - totalInd = Integer.parseInt(soln.getLiteral(resultVars.get(0)).getLexicalForm()); - } - //CalculateParameters.totalInd = totalInd; - //log.info("Total number of individuals in the system are : " + CalculateParameters.totalInd); - }catch(Throwable t){ - log.error(t,t); - }finally{ - if( qexec != null ) - qexec.close(); - dataset.getLock().leaveCriticalSection(); - } - - } -} 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..92fcc8ae7 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 ?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"; @@ -475,10 +479,10 @@ public class FakeApplicationOntologyService { @Override public Map getData(Map pageData) { - Map parms = new HashMap(); - parms.put("uri", new String[] { individualUri }); + Map parms = new HashMap<>(); + parms.put("uri", individualUri); - return doQuery(parms, getModel(ctx, vreq, null)); + return super.getData(parms); } } 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..b882faba1 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, true); + } + /* * 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..6d99d4c52 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; @@ -35,6 +33,7 @@ import edu.cornell.mannlib.vitro.webapp.reasoner.ReasonerPlugin; import edu.cornell.mannlib.vitro.webapp.reasoner.SimpleReasoner; import edu.cornell.mannlib.vitro.webapp.reasoner.SimpleReasonerTBoxListener; import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus; +import edu.cornell.mannlib.vitro.webapp.utils.threads.VitroBackgroundThread; public class SimpleReasonerSetup implements ServletContextListener { @@ -117,7 +116,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 VitroBackgroundThread( + new ABoxRecomputer( + simpleReasoner),"ABoxRecomputer").start(); + } } catch (Throwable t) { t.printStackTrace(); @@ -179,15 +187,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 +261,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..0f739dd5d 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 @@ -12,6 +12,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Arrays; import java.util.Date; import java.util.List; @@ -24,6 +25,10 @@ import org.apache.commons.logging.LogFactory; import com.hp.hpl.jena.ontology.OntModel; import com.hp.hpl.jena.ontology.OntModelSpec; +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.rdf.model.Model; import com.hp.hpl.jena.rdf.model.ModelFactory; import com.hp.hpl.jena.rdf.model.RDFNode; @@ -42,8 +47,6 @@ import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; import edu.cornell.mannlib.vitro.webapp.ontology.update.KnowledgeBaseUpdater; import edu.cornell.mannlib.vitro.webapp.ontology.update.UpdateSettings; import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils; -import edu.cornell.mannlib.vitro.webapp.reasoner.ABoxRecomputer; -import edu.cornell.mannlib.vitro.webapp.reasoner.SimpleReasoner; import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus; /** @@ -157,42 +160,26 @@ 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(); - } - } + removeBadRestrictions(settings.getAssertionOntModelSelector().getTBoxModel()); + + 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(); - } - } /** @@ -549,6 +536,51 @@ public class UpdateKnowledgeBase implements ServletContextListener { } } + /** + * Remove restrictions with missing owl:onProperty or obsolete core class + * This should be worked into the main migration later. + */ + private void removeBadRestrictions(Model tboxModel) { + List queryStrs = Arrays.asList("PREFIX owl: \n " + + "CONSTRUCT { \n" + + " ?rest ?p ?o . \n" + + " ?oo ?pp ?rest \n" + + "} WHERE { \n" + + " ?rest a owl:Restriction . \n" + + " FILTER NOT EXISTS { ?rest owl:onProperty ?x } \n" + + " ?rest ?p ?o . \n" + + " ?oo ?pp ?rest \n" + + "} \n" , + "PREFIX owl: \n " + + "CONSTRUCT { \n" + + " ?rest ?p ?o . \n" + + " ?oo ?pp ?rest \n" + + "} WHERE { \n" + + " ?rest a owl:Restriction . \n" + + " { ?rest owl:someValuesFrom ?c } UNION { ?rest owl:allValuesFrom ?c } \n" + + " FILTER (regex(str(?c), \"vivoweb.org\")) \n" + + " FILTER NOT EXISTS { ?c ?cp ?co } \n" + + " ?rest ?p ?o . \n" + + " ?oo ?pp ?rest \n" + + "} \n" ); + for (String queryStr : queryStrs) { + Query query = QueryFactory.create(queryStr); + QueryExecution qe = QueryExecutionFactory.create(query, tboxModel); + try { + Model bad = qe.execConstruct(); + tboxModel.remove(bad); + if (bad.size() > 0) { + log.info("Deleted " + bad.size() + + " triples of syntactically invalid restrictions"); + } + } finally { + if (qe != null) { + qe.close(); + } + } + } + } + @Override public void contextDestroyed(ServletContextEvent arg0) { // nothing to do 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/dataGetter/SparqlQueryDataGetter.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/SparqlQueryDataGetter.java index b1533acb7..341e2e030 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/SparqlQueryDataGetter.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/SparqlQueryDataGetter.java @@ -29,8 +29,18 @@ import com.hp.hpl.jena.shared.Lock; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.dao.DisplayVocabulary; +import edu.cornell.mannlib.vitro.webapp.dao.jena.QueryUtils; + +public class SparqlQueryDataGetter extends DataGetterBase implements DataGetter{ + private final static Log log = LogFactory.getLog(SparqlQueryDataGetter.class); + + private static final String queryPropertyURI = "<" + DisplayVocabulary.QUERY + ">"; + private static final String saveToVarPropertyURI= "<" + DisplayVocabulary.SAVE_TO_VAR+ ">"; + private static final String queryModelPropertyURI= "<" + DisplayVocabulary.QUERY_MODEL+ ">"; + + public static final String defaultVarNameForResults = "results"; + private static final String defaultTemplate = "menupage--defaultSparql.ftl"; -public class SparqlQueryDataGetter extends DataGetterBase implements DataGetter{ String dataGetterURI; String queryText; String saveToVar; @@ -38,11 +48,6 @@ public class SparqlQueryDataGetter extends DataGetterBase implements DataGetter{ VitroRequest vreq; ServletContext context; - - final static Log log = LogFactory.getLog(SparqlQueryDataGetter.class); - //default template - private final static String defaultTemplate = "menupage--defaultSparql.ftl"; - /** * Constructor with display model and data getter URI that will be called by reflection. */ @@ -50,21 +55,11 @@ public class SparqlQueryDataGetter extends DataGetterBase implements DataGetter{ this.configure(vreq, displayModel,dataGetterURI); } - @Override - public Map getData(Map pageData) { - // Merge the pageData with the request parameters. PageData overrides - Map merged = new HashMap(); - merged.putAll(vreq.getParameterMap()); - for (String key: pageData.keySet()) { - merged.put(key, new String[] {String.valueOf(pageData.get(key))}); - } - return doQuery( merged, getModel(context, vreq, modelURI)); - } - - /** + /** * Configure this instance based on the URI and display model. */ - protected void configure(VitroRequest vreq, Model displayModel, String dataGetterURI) { + @SuppressWarnings("hiding") + protected void configure(VitroRequest vreq, Model displayModel, String dataGetterURI) { if( vreq == null ) throw new IllegalArgumentException("VitroRequest may not be null."); if( displayModel == null ) @@ -79,7 +74,6 @@ public class SparqlQueryDataGetter extends DataGetterBase implements DataGetter{ QuerySolutionMap initBindings = new QuerySolutionMap(); initBindings.add("dataGetterURI", ResourceFactory.createResource(this.dataGetterURI)); - int count = 0; Query dataGetterConfigurationQuery = QueryFactory.create(dataGetterQuery) ; displayModel.enterCriticalSection(Lock.READ); try{ @@ -88,7 +82,6 @@ public class SparqlQueryDataGetter extends DataGetterBase implements DataGetter{ ResultSet res = qexec.execSelect(); try{ while( res.hasNext() ){ - count++; QuerySolution soln = res.next(); //query is NOT OPTIONAL @@ -121,56 +114,128 @@ public class SparqlQueryDataGetter extends DataGetterBase implements DataGetter{ } /** - * Do the query and return a result. This is in its own method - * to make testing easy. + * Query to get the definition of the SparqlDataGetter for a given URI. */ - protected Map doQuery(MapparameterMap, Model queryModel){ + private static final String dataGetterQuery = + "PREFIX display: <" + DisplayVocabulary.DISPLAY_NS +"> \n" + + "SELECT ?query ?saveToVar ?queryModel WHERE { \n" + + " ?dataGetterURI "+queryPropertyURI+" ?query . \n" + + " OPTIONAL{ ?dataGetterURI "+saveToVarPropertyURI+" ?saveToVar } \n " + + " OPTIONAL{ ?dataGetterURI "+queryModelPropertyURI+" ?queryModel } \n" + + "}"; - if( this.queryText == null ){ - log.error("no SPARQL query defined for page " + this.dataGetterURI); + + @Override + public Map getData(Map pageData) { + Map merged = mergeParameters(vreq.getParameterMap(), pageData); + + String boundQueryText = bindParameters(queryText, merged); + + if (modelURI != null) { + return doQueryOnModel(boundQueryText, getModel(context, vreq, modelURI)); + } else { + return doQueryOnRDFService(boundQueryText); + } + } + + /** Merge the pageData with the request parameters. PageData overrides. */ + private Map mergeParameters( + Map parameterMap, Map pageData) { + Map merged = new HashMap<>(); + for (String key: parameterMap.keySet()) { + merged.put(key, parameterMap.get(key)[0]); + } + for (String key: pageData.keySet()) { + merged.put(key, String.valueOf(pageData.get(key))); + } + if (log.isDebugEnabled()) { + log.debug("Merging request parameters " + parameterMap + + " with page data " + pageData + " results in " + merged); + } + return merged; + } + + /** + * InitialBindings don't always work, and besides, RDFService doesn't accept + * them. So do a text-based substitution. + * + * This assumes that every parameter is a URI. What if we want to substitute + * a string value? + */ + private String bindParameters(String text, Map merged) { + String bound = text; + for (String key : merged.keySet()) { + bound = bound.replace('?' + key, '<' + merged.get(key) + '>'); + } + if (log.isDebugEnabled()) { + log.debug("parameters: " + merged); + log.debug("query before binding parameters:" + text); + log.debug("query after binding parameters: " + bound); + } + return bound; + } + + /** + * Do the query and return a result. This is in its own method, with + * protected access, to make testing easy. + */ + protected Map doQueryOnRDFService(String q) { + log.debug("Going to RDFService with " + q); + ResultSet results = QueryUtils.getQueryResults(q, vreq); + return assembleMap(parseResults(results)); + } + + /** + * Do the query and return a result. This is in its own method, with + * protected access, to make testing easy. + */ + protected Map doQueryOnModel(String q, Model queryModel){ + log.debug("Going to model " + modelURI + " with " + q); + if (q == null) { + return Collections.emptyMap(); + } + + Query query = makeQuery(q); + if (query == null) { return Collections.emptyMap(); } - //this may throw a SPARQL syntax error - Query query = QueryFactory.create( this.queryText ); - - //build query bindings - QuerySolutionMap initialBindings = createBindings( parameterMap); - - //execute query - List> results = executeQuery( query, queryModel, initialBindings); - - //put results in page data, what key to use for results? - Map rmap = new HashMap(); - //also store the variable name within which results will be returned - rmap.put("variableName", this.saveToVar); - rmap.put(this.saveToVar, results); - //This will be overridden at page level in display model if template specified there - rmap.put("bodyTemplate", defaultTemplate); - return rmap; + return assembleMap(executeQuery( query, queryModel)); } - private List> executeQuery(Query query, Model model, - QuerySolutionMap initialBindings) { - - List> rows = new ArrayList>(); - + private Query makeQuery(String q) { + try { + return QueryFactory.create(q); + } catch (Exception e) { + log.error("Failed to build a query from ''", e); + return null; + } + } + + private List> executeQuery(Query query, Model model) { model.enterCriticalSection(Lock.READ); try{ - QueryExecution qexec= QueryExecutionFactory.create(query, model,initialBindings ); + QueryExecution qexec= QueryExecutionFactory.create(query, model ); ResultSet results = qexec.execSelect(); try{ - while (results.hasNext()) { - QuerySolution soln = results.nextSolution(); - rows.add( toRow( soln ) ); - } + return parseResults(results); }finally{ qexec.close(); } }finally{ model.leaveCriticalSection(); } - - return rows; } /** + * Converts a ResultSet into a List of Maps. + */ + private List> parseResults(ResultSet results) { + List> rows = new ArrayList>(); + while (results.hasNext()) { + QuerySolution soln = results.nextSolution(); + rows.add( toRow( soln ) ); + } + return rows; + } + + /** * Converts a row from a QuerySolution to a Map */ private Map toRow(QuerySolution soln) { @@ -186,8 +251,8 @@ public class SparqlQueryDataGetter extends DataGetterBase implements DataGetter{ private String toCell(RDFNode rdfNode) { if( rdfNode == null){ return ""; - }else if( rdfNode.canAs( Literal.class )){ - return ((Literal)rdfNode.as(Literal.class)).getLexicalForm(); + }else if( rdfNode.isLiteral() ){ + return rdfNode.asLiteral().getLexicalForm(); }else if( rdfNode.isResource() ){ Resource resource = (Resource)rdfNode; if( ! resource.isAnon() ){ @@ -200,40 +265,17 @@ public class SparqlQueryDataGetter extends DataGetterBase implements DataGetter{ } } - - - private QuerySolutionMap createBindings(MapparameterMap) { - QuerySolutionMap initBindings = new QuerySolutionMap(); - - //could have bindings from HTTP parameters - for( String var : parameterMap.keySet() ) { - String[] values = parameterMap.get(var); - if( values != null && values.length == 1 ){ - //what do do when we don't want a Resource? - initBindings.add(var, ResourceFactory.createResource(values[0]) ); - }else if( values.length > 1){ - log.error("more than 1 http parameter for " + var); - } - } - return initBindings; - } - - private static final String queryPropertyURI = "<" + DisplayVocabulary.QUERY + ">"; - private static final String saveToVarPropertyURI= "<" + DisplayVocabulary.SAVE_TO_VAR+ ">"; - private static final String queryModelPropertyURI= "<" + DisplayVocabulary.QUERY_MODEL+ ">"; - - public static final String defaultVarNameForResults = "results"; - - /** - * Query to get the definition of the SparqlDataGetter for a given URI. - */ - private static final String dataGetterQuery = - "PREFIX display: <" + DisplayVocabulary.DISPLAY_NS +"> \n" + - "SELECT ?query ?saveToVar ?queryModel WHERE { \n" + - " ?dataGetterURI "+queryPropertyURI+" ?query . \n" + - " OPTIONAL{ ?dataGetterURI "+saveToVarPropertyURI+" ?saveToVar } \n " + - " OPTIONAL{ ?dataGetterURI "+queryModelPropertyURI+" ?queryModel } \n" + - "}"; - - + private Map assembleMap(List> results) { + Map rmap = new HashMap(); + + //put results in page data + rmap.put(this.saveToVar, results); + //also store the variable name within which results will be returned + rmap.put("variableName", this.saveToVar); + //This will be overridden at page level in display model if template specified there + rmap.put("bodyTemplate", defaultTemplate); + + return rmap; + } + } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/fields/FieldUtils.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/fields/FieldUtils.java new file mode 100644 index 000000000..15a042232 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/fields/FieldUtils.java @@ -0,0 +1,44 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ +package edu.cornell.mannlib.vitro.webapp.utils.fields; + +import java.util.HashSet; +import java.util.List; +import java.util.ListIterator; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import edu.cornell.mannlib.vitro.webapp.beans.Individual; +import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatement; + +public class FieldUtils { + + private static final Log log = LogFactory.getLog(FieldUtils.class); + + + // copied from OptionsForPropertyTag.java in the thought that class may be deprecated + public static List removeIndividualsAlreadyInRange(List individuals, + List stmts, String predicateUri, String objectUriBeingEdited){ + HashSet range = new HashSet(); + + for(ObjectPropertyStatement ops : stmts){ + if( ops.getPropertyURI().equals(predicateUri)) + range.add( ops.getObjectURI() ); + } + + int removeCount=0; + ListIterator it = individuals.listIterator(); + while(it.hasNext()){ + Individual ind = it.next(); + if( range.contains( ind.getURI()) && !(ind.getURI().equals(objectUriBeingEdited)) ) { + it.remove(); + ++removeCount; + } + } + + return individuals; + } + + + +} 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/edit/EditConfigurationTemplateModel.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/edit/EditConfigurationTemplateModel.java index fec05b51e..cac4c484e 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/edit/EditConfigurationTemplateModel.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/edit/EditConfigurationTemplateModel.java @@ -367,6 +367,14 @@ public class EditConfigurationTemplateModel extends BaseTemplateModel { return editConfig.getObject(); } + public String getDomainUri() { + return EditConfigurationUtils.getDomainUri(vreq); + } + + public String getRangeUri() { + return EditConfigurationUtils.getRangeUri(vreq); + } + //data literal //Thus would depend on the literals on the form @@ -666,7 +674,13 @@ public class EditConfigurationTemplateModel extends BaseTemplateModel { //this url is for canceling public String getCancelUrl() { String editKey = editConfig.getEditKey(); - return EditConfigurationUtils.getCancelUrlBase(vreq) + "?editKey=" + editKey + "&cancel=true"; + String cancelURL = EditConfigurationUtils.getCancelUrlBase(vreq) + "?editKey=" + editKey + "&cancel=true"; + //Check for special return url parameter + String returnURLParameter = vreq.getParameter("returnURL"); + if(returnURLParameter != null && !returnURLParameter.isEmpty() ) { + cancelURL += "&returnURL=" + returnURLParameter; + } + return cancelURL; } //Get confirm deletion url 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..1240285c3 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"); @@ -93,7 +105,7 @@ public class GroupedPropertyList extends BaseTemplateModel { // unpopulated, so the properties are displayed to allow statements to be added to these properties. // RY In future, we should limit this to properties that the user has permission to add properties to. if (editing) { - mergeAllPossibleObjectProperties(populatedObjectPropertyList, propertyList); + propertyList = mergeAllPossibleObjectProperties(populatedObjectPropertyList, propertyList); } // Now do much the same with data properties: get the list of populated data properties, then add in placeholders for missing ones @@ -110,12 +122,17 @@ public class GroupedPropertyList extends BaseTemplateModel { mergeAllPossibleDataProperties(propertyList); } - propertyList = correctLanguageForProperties(propertyList); +// Not currently necessary since the language-specific version is now added +// during the merge +// if (editing) { +// propertyList = correctLanguageForProperties(propertyList); +// } + sort(propertyList); // Put the list into groups List propertyGroupList = addPropertiesToGroups(propertyList); - + // Build the template data model from the groupList groups = new ArrayList( propertyGroupList.size()); @@ -131,6 +148,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 +232,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 { @@ -197,7 +255,7 @@ public class GroupedPropertyList extends BaseTemplateModel { } } - private void mergeAllPossibleObjectProperties( + private List mergeAllPossibleObjectProperties( List populatedObjectPropertyList, List propertyList) { @@ -215,10 +273,27 @@ public class GroupedPropertyList extends BaseTemplateModel { if (allPropInstColl != null) { for (PropertyInstance pi : allPropInstColl) { if (pi != null) { - if (!alreadyOnObjectPropertyList( - populatedObjectPropertyList, pi)) { - addObjectPropertyToPropertyList(pi.getPropertyURI(), pi.getDomainClassURI(), pi.getRangeClassURI(), - propertyList); + // use the language-aware wdf because redundancy check + // for display will depend on public label match + ObjectProperty piOp = wdf.getObjectPropertyDao().getObjectPropertyByURIs( + pi.getPropertyURI(), pi.getDomainClassURI(), pi.getRangeClassURI()); + if (piOp == null) { + continue; + } + boolean addToList = true; + int opIndex = 0; + for(ObjectProperty op : populatedObjectPropertyList) { + if(redundant(op, piOp)) { + addToList = false; + if (moreRestrictiveRange(piOp, op, wadf)) { + propertyList = replaceOpWithPiOpInList(piOp, op, opIndex, propertyList); + } + break; + } + opIndex++; + } + if(addToList) { + propertyList.add(piOp); } } else { log.error("a property instance in the Collection created by PropertyInstanceDao.getAllPossiblePropInstForIndividual() is unexpectedly null"); @@ -236,30 +311,73 @@ public class GroupedPropertyList extends BaseTemplateModel { addObjectPropertyToPropertyList(propertyUri, null, null, propertyList); } } + + return propertyList; } - - private boolean alreadyOnObjectPropertyList(List opList, - PropertyInstance pi) { - if (pi.getPropertyURI() == null) { + + private boolean moreRestrictiveRange(ObjectProperty piOp, ObjectProperty op, + WebappDaoFactory wadf) { + if(piOp.getRangeVClassURI() == null) { + return false; + } else if (op.getRangeVClassURI() == null) { + return (piOp.getRangeVClassURI() != null); + } else { + return (wadf.getVClassDao().isSubClassOf( + piOp.getRangeVClassURI(), op.getRangeVClassURI())); + } + } + + private List replaceOpWithPiOpInList(ObjectProperty piOp, + ObjectProperty op, int opIndex, List propertyList) { + + List returnList = new ArrayList(); + int index = 0; + for(Property p : propertyList) { + if(index == opIndex /* p.equals(op) */) { + returnList.add(piOp); + } else { + returnList.add(p); + } + index++; + } + return returnList; + } + + private boolean redundant(ObjectProperty op, ObjectProperty op2) { + if (op2.getURI() == null) { return false; } - for (ObjectProperty op : opList) { - if (op.getURI() != null && op.getURI().equals(pi.getPropertyURI())) { - if(op.getDomainVClassURI() == null) { - if(pi.getDomainClassURI() == null) { - return true; - } - } else if (op.getDomainVClassURI().equals(pi.getDomainClassURI())) { - return true; - } - if(op.getRangeVClassURI() == null) { - if (pi.getDomainClassURI() == null) { - return true; - } - } else if (op.getRangeVClassURI().equals(pi.getRangeClassURI())) { - return true; - } + boolean uriMatches = (op.getURI() != null + && op.getURI().equals(op2.getURI())); + boolean domainMatches = false; + boolean rangeMatches = false; + boolean labelMatches = false; + if(op.getDomainPublic() == null) { + if(op2.getDomainPublic() == null) { + labelMatches = true; } + } else if (op.getDomainPublic().equals(op2.getDomainPublic())) { + labelMatches = true; + } + if(uriMatches && labelMatches) { + return true; + } + if(op.getDomainVClassURI() == null) { + if(op2.getDomainVClassURI() == null) { + domainMatches = true; + } + } else if (op.getDomainVClassURI().equals(op2.getDomainVClassURI())) { + domainMatches = true; + } + if(op.getRangeVClassURI() == null) { + if (op2.getRangeVClassURI() == null) { + rangeMatches = true; + } + } else if (op.getRangeVClassURI().equals(op2.getRangeVClassURI())) { + rangeMatches = true; + } + if (uriMatches && domainMatches && rangeMatches) { + return true; } return false; } @@ -325,10 +443,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 +473,7 @@ public class GroupedPropertyList extends BaseTemplateModel { */ PropertyGroup groupForUnassignedProperties = pgDao .createDummyPropertyGroup("", MAX_GROUP_DISPLAY_RANK); - + if (groupCount > 1) { try { Collections.sort(groupList); @@ -377,6 +497,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/ObjectPropertyStatementTemplateModel.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/ObjectPropertyStatementTemplateModel.java index c9da36ce8..8ba4577b0 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/ObjectPropertyStatementTemplateModel.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/ObjectPropertyStatementTemplateModel.java @@ -47,11 +47,11 @@ public class ObjectPropertyStatementTemplateModel extends PropertyStatementTempl ops.setProperty(predicate); // Do delete url first, since it is used in building edit url - this.deleteUrl = makeDeleteUrl(); + this.deleteUrl = makeDeleteUrl(ops); this.editUrl = makeEditUrl(ops); } - private String makeDeleteUrl() { + private String makeDeleteUrl(ObjectPropertyStatement ops) { // Is the delete link suppressed for this property? if (property.isDeleteLinkSuppressed()) { return ""; @@ -87,6 +87,13 @@ public class ObjectPropertyStatementTemplateModel extends PropertyStatementTempl } } + if (ops.getProperty()!= null && ops.getProperty().getDomainVClassURI() != null) { + params.put("domainUri", ops.getProperty().getDomainVClassURI()); + } + if (ops.getProperty()!= null && ops.getProperty().getRangeVClassURI() != null) { + params.put("rangeUri", ops.getProperty().getRangeVClassURI()); + } + params.put("templateName", templateName); params.putAll(UrlBuilder.getModelParams(vreq)); 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/edu/cornell/mannlib/vitro/webapp/search/indexing/AdditionalURIsForContextNodesTest.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/search/indexing/AdditionalURIsForContextNodesTest.java deleted file mode 100644 index f73674d80..000000000 --- a/webapp/test/edu/cornell/mannlib/vitro/webapp/search/indexing/AdditionalURIsForContextNodesTest.java +++ /dev/null @@ -1,670 +0,0 @@ -/* $This file is distributed under the terms of the license in /doc/license.txt$ */ - -package edu.cornell.mannlib.vitro.webapp.search.indexing; - -import static org.junit.Assert.assertTrue; - -import java.io.StringReader; -import java.util.List; - -import org.junit.Test; - -import com.hp.hpl.jena.ontology.OntModel; -import com.hp.hpl.jena.rdf.model.ModelFactory; - -import edu.cornell.mannlib.vitro.webapp.search.indexing.AdditionalURIsForContextNodes; - - -public class AdditionalURIsForContextNodesTest { - - @Test - public void testPositionChanges(){ - String n3 = - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" ; - - //make a test model with an person, an authorship context node and a book - OntModel model = ModelFactory.createOntologyModel(); - model.read( new StringReader(n3), null, "N3"); - - //make an AdditionalURIsForContextNodesTest object with that model - AdditionalURIsForContextNodes uriFinder = new AdditionalURIsForContextNodes( model ); - - //if the person changes then the org needs to be updated - List uris = uriFinder.findAdditionalURIsToIndex( "http://caruso-laptop.mannlib.cornell.edu:8090/vivo/individual/n932"); - assertTrue("did not find org for context node", uris.contains("http://caruso-laptop.mannlib.cornell.edu:8090/vivo/individual/n5423" )); - - //if the org changes then the person needs to be updated - uris = uriFinder.findAdditionalURIsToIndex( "http://caruso-laptop.mannlib.cornell.edu:8090/vivo/individual/n5423"); - assertTrue("did not find person for context node", uris.contains("http://caruso-laptop.mannlib.cornell.edu:8090/vivo/individual/n932" )); - } - - @Test - public void testPersonOnOrgChange() { - - String n3 ="@prefix dc: . \n" + - "@prefix rdfs: . \n" + - "@prefix swrl: . \n" + - "@prefix vitro: . \n" + - "@prefix xsd: . \n" + - "@prefix swrlb: . \n" + - "@prefix owl: . \n" + - "@prefix rdf: . \n" + - "@prefix core: . \n" + - "@prefix vivo: . \n" + - "@prefix obo: . \n" + - " " + - " \n" + - " a owl:Thing , core:Role , core:LeaderRole ; \n" + - " rdfs:label \"head\"^^xsd:string ; \n" + - " vitro:mostSpecificType \n" + - " core:LeaderRole ; \n" + - " core:dateTimeInterval \n" + - " ; \n" + - " obo:RO_0000052 ; \n" + - " core:roleContributesTo . \n" + - " \n" + - " a , owl:Thing , , core:ClinicalOrganization ; \n" + - " rdfs:label \"Organization XYZ\"^^xsd:string ; \n" + - " vitro:mostSpecificType \n" + - " core:ClinicalOrganization ; \n" + - " core:contributingRole . \n" + - " a , owl:Thing , . \n"; - - - //make a test model with an person, an authorship context node and a book - OntModel model = ModelFactory.createOntologyModel(); - model.read( new StringReader(n3), null, "N3"); - - - //make an AdditionalURIsForContextNodesTest object with that model - AdditionalURIsForContextNodes uriFinder = new AdditionalURIsForContextNodes( model ); - - //get additional uris for org - List uris = uriFinder.findAdditionalURIsToIndex( "http://caruso-laptop.mannlib.cornell.edu:8090/vivo/individual/n2592"); - - assertTrue("did not find person for context node", uris.contains("http://vivo.scripps.edu/individual/n14979" )); - - } - - @Test - public void testLeaderRoleChanges(){ - String n3= - - " \"1, Test\" . \n " + -// " \"1\"^^ . \n " + -// " \"Test\"^^ . \n " + - " . \n " + - " . \n " + - " . \n " + - " . \n " + - " . \n " + - - - " \"Leader Role\"^^ . \n " + - " . \n " + - " . \n " + - " . \n " + - " . \n " + - " . \n " + - " . \n " + - - " \"University1\"^^ . \n " + - " . \n " + - " .\n " + - " . \n " + - " . \n " + - " . \n " + - " . \n " ; - - - //make a test model with an person, a leader role node and a university - OntModel model = ModelFactory.createOntologyModel(); - model.read( new StringReader(n3), null, "N3"); - - //make an AdditionalURIsForContextNodesTest object with that model - AdditionalURIsForContextNodes uriFinder = new AdditionalURIsForContextNodes( model ); - - //if the person changes then the university needs to be updated - List uris = uriFinder.findAdditionalURIsToIndex( "http://vivo.scripps.edu/individual/n2027"); - assertTrue("did not find org for context node", uris.contains("http://vivo.scripps.edu/individual/n7080" )); - - //if the university changes then the person needs to be updated - uris = uriFinder.findAdditionalURIsToIndex( "http://vivo.scripps.edu/individual/n7080"); - assertTrue("did not find person for context node", uris.contains("http://vivo.scripps.edu/individual/n2027" )); - - - } - - - @Test - public void testMemberRoleChanges(){ - String n3 = - - " . \n " + - " \"2, Test\" . \n " + -// " \"2\"^^ . \n " + -// " \"Test\"^^ . \n " + - " . \n " + - " . \n " + - " . \n " + - " . \n " + - - " \"Member Role\"^^ . \n " + - " . \n " + - " . \n " + - " . \n " + - " . \n " + - " . \n " + - " . \n " + - " . \n " + - - - " \"University2\"^^ . \n " + - " . \n " + - " . \n " + - " . \n " + - " . \n " + - " . \n " + - " . \n " ; - - - - //make a test model with an person, a member role node and a university - OntModel model = ModelFactory.createOntologyModel(); - model.read( new StringReader(n3), null, "N3"); - - //make an AdditionalURIsForContextNodesTest object with that model - AdditionalURIsForContextNodes uriFinder = new AdditionalURIsForContextNodes( model ); - - //if the person changes then the university needs to be updated - List uris = uriFinder.findAdditionalURIsToIndex( "http://vivo.scripps.edu/individual/n4519"); - assertTrue("did not find org for context node", uris.contains("http://vivo.scripps.edu/individual/n6004" )); - - //if the university changes then the person needs to be updated - uris = uriFinder.findAdditionalURIsToIndex( "http://vivo.scripps.edu/individual/n6004"); - assertTrue("did not find person for context node", uris.contains("http://vivo.scripps.edu/individual/n4519" )); - - - } - - - @Test - public void testClinicalRoleChangesForProject(){ - - String n3 = - - " \"3, Test\" . \n" + -// " \"3\"^^ .\n" + -// " \"Test\"^^ . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - - " . \n" + - " \"Clinical Role\"^^ . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - - " \"Project1\"^^ . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" ; - - - - //make a test model with an person, a clinical role node and a project - OntModel model = ModelFactory.createOntologyModel(); - model.read( new StringReader(n3), null, "N3"); - - //make an AdditionalURIsForContextNodesTest object with that model - AdditionalURIsForContextNodes uriFinder = new AdditionalURIsForContextNodes( model ); - - //if the person changes then the project needs to be updated - List uris = uriFinder.findAdditionalURIsToIndex( "http://vivo.scripps.edu/individual/n4858"); - assertTrue("did not find project for clinical role", uris.contains("http://vivo.scripps.edu/individual/n5177" )); - - //if the project changes then the person needs to be updated - uris = uriFinder.findAdditionalURIsToIndex( "http://vivo.scripps.edu/individual/n5177"); - assertTrue("did not find person for clinical role", uris.contains("http://vivo.scripps.edu/individual/n4858" )); - - } - - @Test - public void testClinicalRoleChangesForService(){ - - String n3 = - - " \"4, Test\" . \n" + -// " \"4\"^^ . \n" + -// " \"Test\"^^ . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - - " . \n" + - " \"Clinical Role 2\"^^ . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - - " \"Service1\"^^ . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" ; - - //make a test model with an person, a clinical role node and a service - OntModel model = ModelFactory.createOntologyModel(); - model.read( new StringReader(n3), null, "N3"); - - //make an AdditionalURIsForContextNodesTest object with that model - AdditionalURIsForContextNodes uriFinder = new AdditionalURIsForContextNodes( model ); - - //if the person changes then the service needs to be updated - List uris = uriFinder.findAdditionalURIsToIndex( "http://vivo.scripps.edu/individual/n5651"); - assertTrue("did not find service for clinical role", uris.contains("http://vivo.scripps.edu/individual/n4442" )); - - //if the service changes then the person needs to be updated - uris = uriFinder.findAdditionalURIsToIndex( "http://vivo.scripps.edu/individual/n4442"); - assertTrue("did not find person for clinical role", uris.contains("http://vivo.scripps.edu/individual/n5651" )); - - - } - - - @Test - public void testPresenterRoleChangesForPresentation(){ - String n3 = - " . \n" + - " \"5, Test\" . \n" + -// " \"5\"^^ . \n" + -// " \"Test\"^^ . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - - " . \n" + - " \"Presenter Role\"^^ . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - - " \"Presentation 1\"^^ . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" ; - - - //make a test model with an person, a presenter role node and a presentation - OntModel model = ModelFactory.createOntologyModel(); - model.read( new StringReader(n3), null, "N3"); - - //make an AdditionalURIsForContextNodesTest object with that model - AdditionalURIsForContextNodes uriFinder = new AdditionalURIsForContextNodes( model ); - - //if the person changes then the presentation needs to be updated - List uris = uriFinder.findAdditionalURIsToIndex( "http://vivo.scripps.edu/individual/n5596"); - assertTrue("did not find service for clinical role", uris.contains("http://vivo.scripps.edu/individual/n1305" )); - - //if the presentation changes then the person needs to be updated - uris = uriFinder.findAdditionalURIsToIndex( "http://vivo.scripps.edu/individual/n1305"); - assertTrue("did not find person for clinical role", uris.contains("http://vivo.scripps.edu/individual/n5596" )); - - } - - - @Test - public void testPresenterRoleChangesForInvitedTalk(){ - String n3 = - - " . \n " + - " \"6, Test\" . \n " + -// " \"6\"^^ . \n " + -// " \"Test\"^^ . \n " + - " . \n " + - " . \n " + - " . \n " + - " . \n " + - - " . \n " + - " \"Presenter Role 2\"^^ . \n " + - " . \n " + - " . \n " + - " . \n " + - " . \n " + - " . \n " + - " . \n " + - - " \"Invited Talk 1\"^^ . \n " + - " . \n " + - " . \n " + - " . \n " + - " . \n " + - " . \n " + - " . \n " ; - - //make a test model with an person, a presenter role node and an invited talk - OntModel model = ModelFactory.createOntologyModel(); - model.read( new StringReader(n3), null, "N3"); - - //make an AdditionalURIsForContextNodesTest object with that model - AdditionalURIsForContextNodes uriFinder = new AdditionalURIsForContextNodes( model ); - - //if the person changes then the invited talk needs to be updated - List uris = uriFinder.findAdditionalURIsToIndex( "http://vivo.scripps.edu/individual/n4112"); - assertTrue("did not find invited talk for person", uris.contains("http://vivo.scripps.edu/individual/n4107" )); - - //if the invited talk changes then the person needs to be updated - uris = uriFinder.findAdditionalURIsToIndex( "http://vivo.scripps.edu/individual/n4107"); - assertTrue("did not find person for invited talk", uris.contains("http://vivo.scripps.edu/individual/n4112" )); - - } - - - @Test - public void testResearcherRoleForGrant(){ - - String n3 = - - " \"7, Test\" . \n" + -// " \"7\"^^ . \n" + -// " \"Test\"^^ . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - - " \"Researcher Role\"^^ . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - - " \"Grant1\"^^ . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" ; - - - //make a test model with an person, a researcher role node and a grant - OntModel model = ModelFactory.createOntologyModel(); - model.read( new StringReader(n3), null, "N3"); - - //make an AdditionalURIsForContextNodesTest object with that model - AdditionalURIsForContextNodes uriFinder = new AdditionalURIsForContextNodes( model ); - - //if the person changes then the grant needs to be updated - List uris = uriFinder.findAdditionalURIsToIndex( "http://vivo.scripps.edu/individual/n4957"); - assertTrue("did not find service for clinical role", uris.contains("http://vivo.scripps.edu/individual/n4252" )); - - //if the grant changes then the person needs to be updated - uris = uriFinder.findAdditionalURIsToIndex( "http://vivo.scripps.edu/individual/n4252"); - assertTrue("did not find person for clinical role", uris.contains("http://vivo.scripps.edu/individual/n4957" )); - - - } - - @Test - public void testResearcherRoleForProject(){ - - String n3 = - - " \"8, Test\" . \n " + -// " \"8\"^^ . \n " + -// " \"Test\"^^ . \n " + - " . \n " + - " . \n " + - " . \n " + - " . \n " + - " . \n " + - - " \"Researcher Role 2\"^^ . \n " + - " . \n " + - " . \n " + - " . \n " + - " . \n " + - " . \n " + - " . \n " + - " . \n " + - - - " \"Project2\"^^ . \n " + - " . \n " + - " . \n " + - " . \n " + - " . \n " + - " . \n " ; - - - - //make a test model with an person, a researcher role node and a project - OntModel model = ModelFactory.createOntologyModel(); - model.read( new StringReader(n3), null, "N3"); - - //make an AdditionalURIsForContextNodesTest object with that model - AdditionalURIsForContextNodes uriFinder = new AdditionalURIsForContextNodes( model ); - - //if the person changes then the project needs to be updated - List uris = uriFinder.findAdditionalURIsToIndex( "http://vivo.scripps.edu/individual/n2029"); - assertTrue("did not find service for clinical role", uris.contains("http://vivo.scripps.edu/individual/n564" )); - - //if the project changes then the person needs to be updated - uris = uriFinder.findAdditionalURIsToIndex( "http://vivo.scripps.edu/individual/n564"); - assertTrue("did not find person for clinical role", uris.contains("http://vivo.scripps.edu/individual/n2029" )); - - - } - - @Test - public void testPrincipalInvestigatorRoleChanges(){ - - String n3 = - - " . \n" + - " \"8, Test\" . \n" + -// " \"8\"^^ . \n" + -// " \"Test\"^^ . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - - " \"Grant 2\"^^ . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" ; - - - //make a test model with an person, a principal investigator role node and a grant - OntModel model = ModelFactory.createOntologyModel(); - model.read( new StringReader(n3), null, "N3"); - - //make an AdditionalURIsForContextNodesTest object with that model - AdditionalURIsForContextNodes uriFinder = new AdditionalURIsForContextNodes( model ); - - //if the person changes then the grant needs to be updated - List uris = uriFinder.findAdditionalURIsToIndex( "http://vivo.scripps.edu/individual/n2368"); - assertTrue("did not find grant for pi", uris.contains("http://vivo.scripps.edu/individual/n1742" )); - - //if the grant changes then the person needs to be updated - uris = uriFinder.findAdditionalURIsToIndex( "http://vivo.scripps.edu/individual/n1742"); - assertTrue("did not find pi for grant", uris.contains("http://vivo.scripps.edu/individual/n2368" )); - - - } - - @Test - public void testCoPrincipalInvestigatorRoleChanges(){ - - String n3 = - - " \"9, Test\" . \n" + -// " \"9\"^^ . \n" + -// " \"Test\"^^ . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - - " \"Grant 3\"^^ . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" ; - - //make a test model with an person, a co-principal investigator role node and a grant - OntModel model = ModelFactory.createOntologyModel(); - model.read( new StringReader(n3), null, "N3"); - - //make an AdditionalURIsForContextNodesTest object with that model - AdditionalURIsForContextNodes uriFinder = new AdditionalURIsForContextNodes( model ); - - //if the copi changes then the grant needs to be updated - List uris = uriFinder.findAdditionalURIsToIndex( "http://vivo.scripps.edu/individual/n1373"); - assertTrue("did not find grant for co-pi", uris.contains("http://vivo.scripps.edu/individual/n4931" )); - - //if the grant changes then the copi needs to be updated - uris = uriFinder.findAdditionalURIsToIndex( "http://vivo.scripps.edu/individual/n4931"); - assertTrue("did not find co-pi for grant", uris.contains("http://vivo.scripps.edu/individual/n1373" )); - - } - - - @Test - public void testInvestigatorRoleChanges(){ - - String n3 = - - " \"10, Test\" . \n" + -// " \"10\"^^ . \n" + -// " \"Test\"^^ . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - - " \"Grant 4\"^^ . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" + - " . \n" ; - - - //make a test model with an person, a investigator role node and a grant - OntModel model = ModelFactory.createOntologyModel(); - model.read( new StringReader(n3), null, "N3"); - - //make an AdditionalURIsForContextNodesTest object with that model - AdditionalURIsForContextNodes uriFinder = new AdditionalURIsForContextNodes( model ); - - //if the investigator changes then the grant needs to be updated - List uris = uriFinder.findAdditionalURIsToIndex( "http://vivo.scripps.edu/individual/n5282"); - assertTrue("did not find grant for investigator", uris.contains("http://vivo.scripps.edu/individual/n160" )); - - //if the grant changes then the investigator needs to be updated - uris = uriFinder.findAdditionalURIsToIndex( "http://vivo.scripps.edu/individual/n160"); - assertTrue("did not find investigator for grant", uris.contains("http://vivo.scripps.edu/individual/n5282" )); - - - - } - - -} diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/search/indexing/IndexBuilderThreadTest.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/search/indexing/IndexBuilderThreadTest.java index 450694ed1..9301ee435 100644 --- a/webapp/test/edu/cornell/mannlib/vitro/webapp/search/indexing/IndexBuilderThreadTest.java +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/search/indexing/IndexBuilderThreadTest.java @@ -5,13 +5,14 @@ package edu.cornell.mannlib.vitro.webapp.search.indexing; import junit.framework.Assert; import org.apache.log4j.Level; +import org.junit.Ignore; import org.junit.Test; import edu.cornell.mannlib.vitro.testing.AbstractTestClass; public class IndexBuilderThreadTest extends AbstractTestClass { - + @Ignore @Test public void testStoppingTheThread(){ setLoggerLevel(IndexBuilder.class, Level.OFF); diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/SparqlQueryDataGetterTest.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/SparqlQueryDataGetterTest.java index 6dd1dc7e4..8e7faafb7 100644 --- a/webapp/test/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/SparqlQueryDataGetterTest.java +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/SparqlQueryDataGetterTest.java @@ -67,9 +67,9 @@ public class SparqlQueryDataGetterTest extends AbstractTestClass{ String bobURI = "http://example.com/p/bob"; dataModel.add(ResourceFactory.createResource(bobURI), RDF.type, ResourceFactory.createResource("http://xmlns.com/foaf/0.1/Person")); - Map params = Collections.emptyMap(); + Map params = Collections.emptyMap(); - Map mapOut = sdg.doQuery(params, dataModel); + Map mapOut = sdg.doQueryOnModel(sdg.queryText, dataModel); Assert.assertNotNull(mapOut); Assert.assertTrue("should contain key people" , mapOut.containsKey("people")); 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/themes/vitro/templates/page.ftl b/webapp/themes/vitro/templates/page.ftl index f234c0dac..7bdc24f56 100644 --- a/webapp/themes/vitro/templates/page.ftl +++ b/webapp/themes/vitro/templates/page.ftl @@ -10,20 +10,7 @@ <#include "identity.ftl"> - - - + <#include "search.ftl"> <#include "menu.ftl"> ${body} diff --git a/webapp/themes/vitro/templates/search.ftl b/webapp/themes/vitro/templates/search.ftl new file mode 100644 index 000000000..383d4fe1c --- /dev/null +++ b/webapp/themes/vitro/templates/search.ftl @@ -0,0 +1,14 @@ + <#-- $This file is distributed under the terms of the license in /doc/license.txt$ --> + + \ No newline at end of file diff --git a/webapp/web/i18n/all.properties b/webapp/web/i18n/all.properties index 193c8a2e7..8bc0a1aeb 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. @@ -884,4 +868,6 @@ manage_labels_intro = In the case where multiple labels exist in the same langua processing_icon = processing selection_in_process = Your selection is being processed. view_labels_capitalized = View Labels -view_labels_for = View Labels for \ No newline at end of file +view_labels_for = View Labels for + +select_an_existing_document = Select an existing document \ No newline at end of file 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/individual/individual-menu.ftl b/webapp/web/templates/freemarker/body/individual/individual-menu.ftl index 2099c0c96..40a901d1b 100644 --- a/webapp/web/templates/freemarker/body/individual/individual-menu.ftl +++ b/webapp/web/templates/freemarker/body/individual/individual-menu.ftl @@ -5,8 +5,7 @@ <#include "individual-setup.ftl"> <#assign hasElement = propertyGroups.pullProperty("${namespaces.display}hasElement")!> - -<#assign addNewMenuItemUrl = "${urls.base}/menuManagementController?cmd=add" > +<#assign returnURL = "/vivo/individual?uri=http%3A%2F%2Fvitro.mannlib.cornell.edu%2Fontologies%2Fdisplay%2F1.1%23DefaultMenu&switchToDisplayModel=true" /> <#if hasElement?has_content>