diff --git a/utilities/buildutils/src/edu/cornell/mannlib/vitro/utilities/testing/VitroTestRunListener.java b/utilities/buildutils/src/edu/cornell/mannlib/vitro/utilities/testing/VitroTestRunListener.java index 01245e92f..acfe6ef71 100644 --- a/utilities/buildutils/src/edu/cornell/mannlib/vitro/utilities/testing/VitroTestRunListener.java +++ b/utilities/buildutils/src/edu/cornell/mannlib/vitro/utilities/testing/VitroTestRunListener.java @@ -1,7 +1,7 @@ /* $This file is distributed under the terms of the license in /doc/license.txt$ */ -package edu.cornell.mannlib.vitro.utilities.testing; - +package edu.cornell.mannlib.vitro.utilities.testing; + import static edu.cornell.mannlib.vitro.utilities.testing.VitroTestRunner.ReportLevel.BRIEF; import static edu.cornell.mannlib.vitro.utilities.testing.VitroTestRunner.ReportLevel.FULL; import static edu.cornell.mannlib.vitro.utilities.testing.VitroTestRunner.ReportLevel.MORE; @@ -20,327 +20,327 @@ import org.junit.runner.notification.Failure; import org.junit.runner.notification.RunListener; import edu.cornell.mannlib.vitro.utilities.testing.VitroTestRunner.ReportLevel; - -/** - * Listen to events as they come from the JUnit test runner. The events from the - * lifecycle methods are broken down into semantic chunks and executed. Three - * levels of output are available. - * - * On the surface, JUnit treats "failures" (failed assertions) the same as - * "errors" (unexpected exceptions). We're going to distinguish between them. - * - * @author jeb228 - */ -public class VitroTestRunListener extends RunListener { - private final ReportLevel reportLevel; - - private int classCount; - private int testsTotal; - private int errorsTotal; - private int failuresTotal; - private int ignoresTotal; - private long overallStartTime; - - private Class currentClass; - private int testsCurrentClass; - private int errorsCurrentClass; - private int failuresCurrentClass; - private int ignoresCurrentClass; - private long classStartTime; - - private String currentTest; - private boolean testHadError; - private boolean testFailed; - private boolean testIgnored; - private long testStartTime; - - public VitroTestRunListener(ReportLevel reportLevel) { - this.reportLevel = reportLevel; - } - - /** Did any of the tests fail or have errors? */ - public boolean didEverythingPass() { - return (failuresTotal == 0) && (errorsTotal == 0); - } - - // ------------------------------------------------------------------------- - // Life-cycle methods that will be called by the test runner. - // ------------------------------------------------------------------------- - - @Override - public void testRunStarted(Description description) throws Exception { - openTestRun(); - reportTestRunStart(); - } - - @Override - public void testStarted(Description description) throws Exception { - if (currentClass != description.getTestClass()) { - if (currentClass != null) { - closeCurrentClass(); - reportCurrentClass(); - } - - openCurrentClass(description); - reportCurrentClassStart(); - } - - openCurrentTest(description); - } - - @Override - public void testAssumptionFailure(Failure failure) { - if (isError(failure)) { - testHadError = true; - reportError(failure); - } else { - testFailed = true; - reportFailure(failure); - } - } - - @Override - public void testFailure(Failure failure) throws Exception { - if (isError(failure)) { - testHadError = true; - reportError(failure); - } else { - testFailed = true; - reportFailure(failure); - } - } - - @Override - public void testFinished(Description description) throws Exception { - closeCurrentTest(); - reportCurrentTest(); - } - - @Override - public void testIgnored(Description description) throws Exception { - testStarted(description); - testIgnored = true; - testFinished(description); - } - - @Override - public void testRunFinished(Result result) throws Exception { - if (currentClass != null) { - closeCurrentClass(); - reportCurrentClass(); - } - closeTestRun(); - reportTestRun(); - System.out.println(); - } - - // ------------------------------------------------------------------------- - // Handling the logical events. - // ------------------------------------------------------------------------- - - private void openTestRun() { - overallStartTime = System.currentTimeMillis(); - } - - private void closeTestRun() { - // Nothing to close. - } - - private void reportTestRunStart() { - if (reportLevel == FULL) { - System.out - .println("Starting test run at " + time(overallStartTime)); - System.out.println(); - } - - if (reportLevel == MORE) { - System.out - .println("Starting test run at " + time(overallStartTime)); - System.out.println(); - System.out.println("Tests Pass Error Fail Ignore Seconds"); - } - } - - private void reportTestRun() { - int successes = testsTotal - errorsTotal - failuresTotal - ignoresTotal; - - if (reportLevel != BRIEF) { - System.out.println(); - } - - System.out.format( - "Tests Pass Error Fail Ignore Seconds TOTAL (%d classes)\n", - classCount); - System.out.format(" %4d %4d %4d %4d %4d %6s\n", testsTotal, - successes, errorsTotal, failuresTotal, ignoresTotal, - elapsed(overallStartTime)); - - if (reportLevel != BRIEF) { - System.out.println("Ending test run at " - + time(System.currentTimeMillis())); - } - } - - private void openCurrentClass(Description description) { - currentClass = description.getTestClass(); - classStartTime = System.currentTimeMillis(); - testsCurrentClass = 0; - errorsCurrentClass = 0; - failuresCurrentClass = 0; - ignoresCurrentClass = 0; - } - - private void closeCurrentClass() { - classCount++; - testsTotal += testsCurrentClass; - errorsTotal += errorsCurrentClass; - failuresTotal += failuresCurrentClass; - ignoresTotal += ignoresCurrentClass; - } - - private void reportCurrentClassStart() { - if (reportLevel == FULL) { - System.out.format("Tests Pass Error Fail Ignore Seconds %s\n", - currentClass.getName()); - } - } - - private void reportCurrentClass() { - int successes = testsCurrentClass - errorsCurrentClass - - failuresCurrentClass - ignoresCurrentClass; - if (reportLevel == MORE) { - System.out.format(" %4d %4d %4d %4d %4d %6s %s\n", - testsCurrentClass, successes, errorsCurrentClass, - failuresCurrentClass, ignoresCurrentClass, - elapsed(classStartTime), currentClass.getSimpleName()); - } - if (reportLevel == FULL) { - System.out.println("-----------------------------------"); - System.out.format(" %4d %4d %4d %4d %4d %6s\n", - testsCurrentClass, successes, errorsCurrentClass, - failuresCurrentClass, ignoresCurrentClass, - elapsed(classStartTime)); - System.out.println(); - } - } - - private void openCurrentTest(Description description) { - currentTest = description.getMethodName(); - testHadError = false; - testFailed = false; - testIgnored = false; - testStartTime = System.currentTimeMillis(); - } - - private void closeCurrentTest() { - if (testHadError) { - errorsCurrentClass++; - } - if (testFailed) { - failuresCurrentClass++; - } - if (testIgnored) { - ignoresCurrentClass++; - } - testsCurrentClass++; - } - - private boolean isError(Failure failure) { - Throwable throwable = failure.getException(); - return (throwable != null) && !(throwable instanceof AssertionError); - } - - private void reportError(Failure error) { - Description description = error.getDescription(); - String methodName = description.getMethodName(); - String className = description.getTestClass().getName(); - String message = error.getMessage(); - System.out.format("EXCEPTION: test %s() in %s: %s\n", - methodName, className, message); - System.out.println(formatStackTrace(error.getException())); - } - - private void reportFailure(Failure failure) { - Description description = failure.getDescription(); - String methodName = description.getMethodName(); - String className = description.getTestClass().getName(); - String message = failure.getMessage(); - System.out.format("TEST FAILED: test %s() in %s: %s\n", methodName, - className, message); - } - - private void reportCurrentTest() { - if (reportLevel == FULL) { - char passFlag = (testIgnored | testFailed | testHadError) ? ' ' - : '1'; - char errorFlag = testHadError ? '1' : ' '; - char failFlag = testFailed ? '1' : ' '; - char ignoreFlag = testIgnored ? '1' : ' '; - System.out.format( - " %c %c %c %c %6s %s()\n", - passFlag, errorFlag, failFlag, ignoreFlag, - elapsed(testStartTime), currentTest); - } - } - - // ------------------------------------------------------------------------- - // Formatting methods. - // ------------------------------------------------------------------------- - - private final SimpleDateFormat formatter = new SimpleDateFormat( - "HH:mm:ss 'on' MMM dd, yyyy"); - - private String time(long time) { - return formatter.format(new Date(time)); - } - - /** Show elapsed time in 6 columns. */ - private String elapsed(long start) { - long interval = System.currentTimeMillis() - start; - return String.format("%6.2f", ((float) interval) / 1000.0); - } - - /** - * Trim the stack trace: don't show the line saying "23 more", and don't - * show the lines about org.junit or java.lang.reflect or sun.reflect. - * - * Once we hit some "client code", we won't trim any futher lines even if - * they belong to org.junit, or the others. - * - * If we have nested exceptions, the process repeats for each "Caused by" - * section. - */ - private String formatStackTrace(Throwable throwable) { - StringWriter w = new StringWriter(); - throwable.printStackTrace(new PrintWriter(w)); - String[] lineArray = w.toString().split("\\n"); - List lines = new ArrayList(Arrays.asList(lineArray)); - - boolean removing = true; - for (int i = lines.size() - 1; i > 0; i--) { - String line = lines.get(i); - if (removing) { - if (line.matches("\\s*[\\.\\s\\d]+more\\s*") - || line.contains("at " - + VitroTestRunner.class.getName()) - || line.contains("at org.junit.") - || line.contains("at java.lang.reflect.") - || line.contains("at sun.reflect.")) { - lines.remove(line); - } else { - removing = false; - } - } else { - if (line.contains("Caused by: ")) { - removing = true; - } - } - } - - StringBuilder result = new StringBuilder(); - for (String line : lines) { - result.append(line).append('\n'); - } - return result.toString().trim(); - } -} + +/** + * Listen to events as they come from the JUnit test runner. The events from the + * lifecycle methods are broken down into semantic chunks and executed. Three + * levels of output are available. + * + * On the surface, JUnit treats "failures" (failed assertions) the same as + * "errors" (unexpected exceptions). We're going to distinguish between them. + * + * @author jeb228 + */ +public class VitroTestRunListener extends RunListener { + private final ReportLevel reportLevel; + + private int classCount; + private int testsTotal; + private int errorsTotal; + private int failuresTotal; + private int ignoresTotal; + private long overallStartTime; + + private Class currentClass; + private int testsCurrentClass; + private int errorsCurrentClass; + private int failuresCurrentClass; + private int ignoresCurrentClass; + private long classStartTime; + + private String currentTest; + private boolean testHadError; + private boolean testFailed; + private boolean testIgnored; + private long testStartTime; + + public VitroTestRunListener(ReportLevel reportLevel) { + this.reportLevel = reportLevel; + } + + /** Did any of the tests fail or have errors? */ + public boolean didEverythingPass() { + return (failuresTotal == 0) && (errorsTotal == 0); + } + + // ------------------------------------------------------------------------- + // Life-cycle methods that will be called by the test runner. + // ------------------------------------------------------------------------- + + @Override + public void testRunStarted(Description description) throws Exception { + openTestRun(); + reportTestRunStart(); + } + + @Override + public void testStarted(Description description) throws Exception { + if (currentClass != description.getTestClass()) { + if (currentClass != null) { + closeCurrentClass(); + reportCurrentClass(); + } + + openCurrentClass(description); + reportCurrentClassStart(); + } + + openCurrentTest(description); + } + + @Override + public void testAssumptionFailure(Failure failure) { + if (isError(failure)) { + testHadError = true; + reportError(failure); + } else { + testFailed = true; + reportFailure(failure); + } + } + + @Override + public void testFailure(Failure failure) throws Exception { + if (isError(failure)) { + testHadError = true; + reportError(failure); + } else { + testFailed = true; + reportFailure(failure); + } + } + + @Override + public void testFinished(Description description) throws Exception { + closeCurrentTest(); + reportCurrentTest(); + } + + @Override + public void testIgnored(Description description) throws Exception { + testStarted(description); + testIgnored = true; + testFinished(description); + } + + @Override + public void testRunFinished(Result result) throws Exception { + if (currentClass != null) { + closeCurrentClass(); + reportCurrentClass(); + } + closeTestRun(); + reportTestRun(); + System.out.println(); + } + + // ------------------------------------------------------------------------- + // Handling the logical events. + // ------------------------------------------------------------------------- + + private void openTestRun() { + overallStartTime = System.currentTimeMillis(); + } + + private void closeTestRun() { + // Nothing to close. + } + + private void reportTestRunStart() { + if (reportLevel == FULL) { + System.out + .println("Starting test run at " + time(overallStartTime)); + System.out.println(); + } + + if (reportLevel == MORE) { + System.out + .println("Starting test run at " + time(overallStartTime)); + System.out.println(); + System.out.println("Tests Pass Error Fail Ignore Seconds"); + } + } + + private void reportTestRun() { + int successes = testsTotal - errorsTotal - failuresTotal - ignoresTotal; + + if (reportLevel != BRIEF) { + System.out.println(); + } + + System.out.format( + "Tests Pass Error Fail Ignore Seconds TOTAL (%d classes)\n", + classCount); + System.out.format(" %4d %4d %4d %4d %4d %6s\n", testsTotal, + successes, errorsTotal, failuresTotal, ignoresTotal, + elapsed(overallStartTime)); + + if (reportLevel != BRIEF) { + System.out.println("Ending test run at " + + time(System.currentTimeMillis())); + } + } + + private void openCurrentClass(Description description) { + currentClass = description.getTestClass(); + classStartTime = System.currentTimeMillis(); + testsCurrentClass = 0; + errorsCurrentClass = 0; + failuresCurrentClass = 0; + ignoresCurrentClass = 0; + } + + private void closeCurrentClass() { + classCount++; + testsTotal += testsCurrentClass; + errorsTotal += errorsCurrentClass; + failuresTotal += failuresCurrentClass; + ignoresTotal += ignoresCurrentClass; + } + + private void reportCurrentClassStart() { + if (reportLevel == FULL) { + System.out.format("Tests Pass Error Fail Ignore Seconds %s\n", + currentClass.getName()); + } + } + + private void reportCurrentClass() { + int successes = testsCurrentClass - errorsCurrentClass + - failuresCurrentClass - ignoresCurrentClass; + if (reportLevel == MORE) { + System.out.format(" %4d %4d %4d %4d %4d %6s %s\n", + testsCurrentClass, successes, errorsCurrentClass, + failuresCurrentClass, ignoresCurrentClass, + elapsed(classStartTime), currentClass.getSimpleName()); + } + if (reportLevel == FULL) { + System.out.println("-----------------------------------"); + System.out.format(" %4d %4d %4d %4d %4d %6s\n", + testsCurrentClass, successes, errorsCurrentClass, + failuresCurrentClass, ignoresCurrentClass, + elapsed(classStartTime)); + System.out.println(); + } + } + + private void openCurrentTest(Description description) { + currentTest = description.getMethodName(); + testHadError = false; + testFailed = false; + testIgnored = false; + testStartTime = System.currentTimeMillis(); + } + + private void closeCurrentTest() { + if (testHadError) { + errorsCurrentClass++; + } + if (testFailed) { + failuresCurrentClass++; + } + if (testIgnored) { + ignoresCurrentClass++; + } + testsCurrentClass++; + } + + private boolean isError(Failure failure) { + Throwable throwable = failure.getException(); + return (throwable != null) && !(throwable instanceof AssertionError); + } + + private void reportError(Failure error) { + Description description = error.getDescription(); + String methodName = description.getMethodName(); + String className = description.getTestClass().getName(); + String message = error.getMessage(); + System.out.format("EXCEPTION: test %s() in %s: %s\n", + methodName, className, message); + System.out.println(formatStackTrace(error.getException())); + } + + private void reportFailure(Failure failure) { + Description description = failure.getDescription(); + String methodName = description.getMethodName(); + String className = description.getTestClass().getName(); + String message = failure.getMessage(); + System.out.format("TEST FAILED: test %s() in %s: %s\n", methodName, + className, message); + } + + private void reportCurrentTest() { + if (reportLevel == FULL) { + char passFlag = (testIgnored | testFailed | testHadError) ? ' ' + : '1'; + char errorFlag = testHadError ? '1' : ' '; + char failFlag = testFailed ? '1' : ' '; + char ignoreFlag = testIgnored ? '1' : ' '; + System.out.format( + " %c %c %c %c %6s %s()\n", + passFlag, errorFlag, failFlag, ignoreFlag, + elapsed(testStartTime), currentTest); + } + } + + // ------------------------------------------------------------------------- + // Formatting methods. + // ------------------------------------------------------------------------- + + private final SimpleDateFormat formatter = new SimpleDateFormat( + "HH:mm:ss 'on' MMM dd, yyyy"); + + private String time(long time) { + return formatter.format(new Date(time)); + } + + /** Show elapsed time in 6 columns. */ + private String elapsed(long start) { + long interval = System.currentTimeMillis() - start; + return String.format("%6.2f", ((float) interval) / 1000.0); + } + + /** + * Trim the stack trace: don't show the line saying "23 more", and don't + * show the lines about org.junit or java.lang.reflect or sun.reflect. + * + * Once we hit some "client code", we won't trim any futher lines even if + * they belong to org.junit, or the others. + * + * If we have nested exceptions, the process repeats for each "Caused by" + * section. + */ + private String formatStackTrace(Throwable throwable) { + StringWriter w = new StringWriter(); + throwable.printStackTrace(new PrintWriter(w)); + String[] lineArray = w.toString().split("\\n"); + List lines = new ArrayList(Arrays.asList(lineArray)); + + boolean removing = true; + for (int i = lines.size() - 1; i > 0; i--) { + String line = lines.get(i); + if (removing) { + if (line.matches("\\s*[\\.\\s\\d]+more\\s*") + || line.contains("at " + + VitroTestRunner.class.getName()) + || line.contains("at org.junit.") + || line.contains("at java.lang.reflect.") + || line.contains("at sun.reflect.")) { + lines.remove(line); + } else { + removing = false; + } + } else { + if (line.contains("Caused by: ")) { + removing = true; + } + } + } + + StringBuilder result = new StringBuilder(); + for (String line : lines) { + result.append(line).append('\n'); + } + return result.toString().trim(); + } +} diff --git a/webapp/languages/example/i18n/all_es.properties b/webapp/languages/example/i18n/all_es.properties index 0688a577f..0cfe0d066 100644 --- a/webapp/languages/example/i18n/all_es.properties +++ b/webapp/languages/example/i18n/all_es.properties @@ -9,9 +9,9 @@ cancel_title = cancelar required_fields = campos obligatorios or = o alt_error_alert = Icono de alerta con error -alt_confirmation = Icono de confirmación +alt_confirmation = Icono de confirmaci√≥n -email_address = Dirección de correo electrónico +email_address = Direcci√≥n de correo electr√≥nico first_name = Primer nombre last_name = Apellido roles = Roles @@ -21,10 +21,10 @@ ascending_order = orden ascendente descending_order = orden descendente select_one = Seleccione uno -type_more_characters = escribir más caracteres +type_more_characters = escribir m√°s caracteres no_match = No hay resultados -request_failed = Error en la solicitud. Por favor, póngase en contacto con el administrador del sistema. +request_failed = Error en la solicitud. Por favor, p√≥ngase en contacto con el administrador del sistema. # # Image upload pages @@ -43,11 +43,11 @@ current_photo = Foto actual upload_photo = Suba foto replace_photo = Reemplace foto photo_types = (JPEG, GIF, o PNG) -maximum_file_size = Tamaño máximo de archivo: {0} megabytes -minimum_image_dimensions = Dimensiones mínimas de imagen: {0} x {1} pixels +maximum_file_size = Tama√±o m√°ximo de archivo: {0} megabytes +minimum_image_dimensions = Dimensiones m√≠nimas de imagen: {0} x {1} pixels -cropping_caption = La foto de tu perfil se verá como la imagen de abajo. -cropping_note = Para realizar ajustes, arrastre alrededor y cambie el tamaño de la foto de la derecha. Cuando esté satisfecho con su foto, haga clic en el botón "Guardar foto". +cropping_caption = La foto de tu perfil se ver√° como la imagen de abajo. +cropping_note = Para realizar ajustes, arrastre alrededor y cambie el tama√±o de la foto de la derecha. Cuando est√© satisfecho con su foto, haga clic en el bot√≥n "Guardar foto". alt_thumbnail_photo = Foto de individuo alt_image_to_crop = Imagen que desea recortar @@ -57,14 +57,14 @@ delete_link = Borrar foto submit_upload = Subir foto submit_save = Guardar foto -confirm_delete = ¿Seguro que quiere borrar esta foto? +confirm_delete = ¬øSeguro que quiere borrar esta foto? -imageUpload.errorNoURI = No se proporcionó ninguna entidad URI +imageUpload.errorNoURI = No se proporcion√≥ ninguna entidad URI imageUpload.errorUnrecognizedURI = Este URI no se reconoce como perteneciente a cualquiera:'' {0}'' imageUpload.errorNoImageForCropping = No hay archivo de imagen que desea recortar. -imageUpload.errorImageTooSmall = La imagen cargada debe ser al menos {0} píxeles de alto y {1} píxeles de ancho. +imageUpload.errorImageTooSmall = La imagen cargada debe ser al menos {0} p√≠xeles de alto y {1} p√≠xeles de ancho. imageUpload.errorUnknown = Lo sentimos, no pudimos procesar la foto que nos ha facilitado. Por favor, intente otra foto. -imageUpload.errorFileTooBig = Por favor, sube una imagen más pequeña que {0} megabytes. +imageUpload.errorFileTooBig = Por favor, sube una imagen m√°s peque√±a que {0} megabytes. imageUpload.errorUnrecognizedFileType = '' {0}'' no es un tipo de archivo de imagen reconocida. Por favor, sube JPEG, GIF o PNG solamente. imageUpload.errorNoPhotoSelected = Por favor, busque y seleccione una foto. imageUpload.errorBadMultipartRequest = Error al analizar la solicitud de varias partes para subir una imagen. @@ -73,56 +73,56 @@ imageUpload.errorFormFieldMissing = El formulario no contiene a {0}'' campo'' ". # # User Accounts pages # -account_management = Gestión de cuentas +account_management = Gesti√≥n de cuentas user_accounts_link = Las cuentas de usuario user_accounts_title = cuentas de usuario login_count = Ingresa contar -last_login = Última sesión +last_login = √öltima sesi√≥n -add_new_account = Añadir nueva cuenta +add_new_account = A√±adir nueva cuenta edit_account = Edit cuenta external_auth_only = Externamente autenticados -reset_password = Restablecer contraseña -reset_password_note = Nota: Las instrucciones para restablecer la contraseña serán enviados por correo electrónico a la dirección indicada anteriormente. La contraseña no se restablecerá hasta que el usuario sigue el enlace que aparece en este correo electrónico. -new_password = Nueva contraseña -confirm_password = Confirmar nueva contraseña -minimum_password_length = Mínimo de {0} caracteres de longitud. -leave_password_unchanged = Dejando esto en blanco significa que no se puede cambiar la contraseña. -confirm_initial_password = Confirmar contraseña inicial +reset_password = Restablecer contrase√±a +reset_password_note = Nota: Las instrucciones para restablecer la contrase√±a ser√°n enviados por correo electr√≥nico a la direcci√≥n indicada anteriormente. La contrase√±a no se restablecer√° hasta que el usuario sigue el enlace que aparece en este correo electr√≥nico. +new_password = Nueva contrase√±a +confirm_password = Confirmar nueva contrase√±a +minimum_password_length = M√≠nimo de {0} caracteres de longitud. +leave_password_unchanged = Dejando esto en blanco significa que no se puede cambiar la contrase√±a. +confirm_initial_password = Confirmar contrase√±a inicial new_account_1 = Una nueva cuenta -new_account_2 = fue creado con éxito. +new_account_2 = fue creado con √©xito. new_account_title = nueva cuenta -new_account_notification = Un correo electrónico de notificación ha sido enviada a {0} con las instrucciones para activar la cuenta y una contraseña. +new_account_notification = Un correo electr√≥nico de notificaci√≥n ha sido enviada a {0} con las instrucciones para activar la cuenta y una contrase√±a. updated_account_1 = La cuenta para el updated_account_2 = se ha actualizado. -updated_account_title = descripción actualizada -updated_account_notification = Un correo electrónico de confirmación ha sido enviado a {0} con instrucciones para restablecer la contraseña. La contraseña no se restablecerá hasta que el usuario sigue el enlace que aparece en este correo electrónico. +updated_account_title = descripci√≥n actualizada +updated_account_notification = Un correo electr√≥nico de confirmaci√≥n ha sido enviado a {0} con instrucciones para restablecer la contrase√±a. La contrase√±a no se restablecer√° hasta que el usuario sigue el enlace que aparece en este correo electr√≥nico. deleted_accounts = Suprimido {0} {0, choice, 0#cuentas | 1#cuenta | 1 a owl:Class ; @@ -55,11 +55,11 @@ display:RequiredAction a owl:Class ; a owl:Class ; - rdfs:comment "A data getter for a VClassGroup page". + rdfs:comment "A data getter for a VClassGroup page" . a owl:Class ; - rdfs:comment "A data getter for a Fixed piece of HTML stored in RDF". + rdfs:comment "A data getter for a Fixed piece of HTML stored in RDF" . a owl:Class . diff --git a/webapp/src/edu/cornell/mannlib/vedit/validator/impl/UrlValidator.java b/webapp/src/edu/cornell/mannlib/vedit/validator/impl/UrlValidator.java index 5d580f58e..b2cb5a3bb 100644 --- a/webapp/src/edu/cornell/mannlib/vedit/validator/impl/UrlValidator.java +++ b/webapp/src/edu/cornell/mannlib/vedit/validator/impl/UrlValidator.java @@ -2,28 +2,37 @@ package edu.cornell.mannlib.vedit.validator.impl; -import edu.cornell.mannlib.vedit.validator.Validator; +import java.util.Iterator; + +import com.hp.hpl.jena.iri.IRI; +import com.hp.hpl.jena.iri.IRIFactory; +import com.hp.hpl.jena.iri.Violation; + import edu.cornell.mannlib.vedit.validator.ValidationObject; -import java.util.regex.*; +import edu.cornell.mannlib.vedit.validator.Validator; public class UrlValidator implements Validator { public ValidationObject validate (Object obj) throws IllegalArgumentException { ValidationObject vo = new ValidationObject(); - String theString = null; if (!(obj instanceof String)){ throw new IllegalArgumentException("Expected instance of String"); } - Pattern pat = Pattern.compile("[a-z]{3,5}*://.*\\.[a-z]{2,4}"); - Matcher mat = pat.matcher(theString); - if (mat.matches()){ - vo.setValid(true); - } else { + IRIFactory factory = IRIFactory.jenaImplementation(); + IRI iri = factory.create((String) obj); + if (iri.hasViolation(false) ) { + String errorStr = ""; + Iterator violIt = iri.violations(false); + while(violIt.hasNext()) { + errorStr += violIt.next().getShortMessage() + " "; + } vo.setValid(false); - vo.setMessage("Please enter a valid URL"); + vo.setMessage("Please enter a valid URL. " + errorStr); + } else { + vo.setValid(true); } vo.setValidatedObject(obj); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/permissions/DisplayByRolePermission.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/permissions/DisplayByRolePermission.java index 80aae91d2..19b9e141f 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/permissions/DisplayByRolePermission.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/permissions/DisplayByRolePermission.java @@ -16,6 +16,7 @@ import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestedAct import edu.cornell.mannlib.vitro.webapp.beans.BaseResourceBean.RoleLevel; import edu.cornell.mannlib.vitro.webapp.beans.DataPropertyStatement; import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatement; +import edu.cornell.mannlib.vitro.webapp.beans.Property; /** * Is the user authorized to display properties that are marked as restricted to @@ -82,7 +83,7 @@ public class DisplayByRolePermission extends Permission { */ private boolean isAuthorized(DisplayDataProperty action) { String predicateUri = action.getDataProperty().getURI(); - return canDisplayPredicate(predicateUri); + return canDisplayPredicate(new Property(predicateUri)); } /** @@ -90,8 +91,7 @@ public class DisplayByRolePermission extends Permission { * predicate. */ private boolean isAuthorized(DisplayObjectProperty action) { - String predicateUri = action.getObjectProperty().getURI(); - return canDisplayPredicate(predicateUri); + return canDisplayPredicate(action.getObjectProperty()); } /** @@ -103,7 +103,7 @@ public class DisplayByRolePermission extends Permission { String subjectUri = stmt.getIndividualURI(); String predicateUri = stmt.getDatapropURI(); return canDisplayResource(subjectUri) - && canDisplayPredicate(predicateUri); + && canDisplayPredicate(new Property(predicateUri)); } /** @@ -113,12 +113,10 @@ public class DisplayByRolePermission extends Permission { private boolean isAuthorized(DisplayObjectPropertyStatement action) { ObjectPropertyStatement stmt = action.getObjectPropertyStatement(); String subjectUri = stmt.getSubjectURI(); - String predicateUri = stmt.getPropertyURI(); - String rangeUri = (stmt.getProperty() == null) ? null - : stmt.getProperty().getRangeVClassURI(); + Property predicate = stmt.getProperty(); String objectUri = stmt.getObjectURI(); return canDisplayResource(subjectUri) - && canDisplayPredicate(predicateUri, rangeUri) + && canDisplayPredicate(predicate) && canDisplayResource(objectUri); } @@ -126,14 +124,10 @@ public class DisplayByRolePermission extends Permission { return PropertyRestrictionPolicyHelper.getBean(ctx).canDisplayResource( resourceUri, this.roleLevel); } - - private boolean canDisplayPredicate(String predicateUri) { - return canDisplayPredicate(predicateUri, null); - } - private boolean canDisplayPredicate(String predicateUri, String rangeUri) { + private boolean canDisplayPredicate(Property predicate) { return PropertyRestrictionPolicyHelper.getBean(ctx) - .canDisplayPredicate(predicateUri, rangeUri, this.roleLevel); + .canDisplayPredicate(predicate, this.roleLevel); } @Override diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/permissions/EditByRolePermission.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/permissions/EditByRolePermission.java index 6d5e64363..93c962015 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/permissions/EditByRolePermission.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/permissions/EditByRolePermission.java @@ -12,6 +12,7 @@ import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestedAct import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.AbstractDataPropertyStatementAction; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.AbstractObjectPropertyStatementAction; import edu.cornell.mannlib.vitro.webapp.beans.BaseResourceBean.RoleLevel; +import edu.cornell.mannlib.vitro.webapp.beans.Property; /** * Is the user authorized to edit properties that are marked as restricted to a @@ -78,9 +79,9 @@ public class EditByRolePermission extends Permission { */ private boolean isAuthorized(AbstractDataPropertyStatementAction action) { String subjectUri = action.getSubjectUri(); - String predicateUri = action.getPredicateUri(); + Property predicate = action.getPredicate(); return canModifyResource(subjectUri) - && canModifyPredicate(predicateUri); + && canModifyPredicate(predicate); } /** @@ -89,10 +90,10 @@ public class EditByRolePermission extends Permission { */ private boolean isAuthorized(AbstractObjectPropertyStatementAction action) { String subjectUri = action.getSubjectUri(); - String predicateUri = action.getPredicateUri(); + Property predicate = action.getPredicate(); String objectUri = action.getObjectUri(); return canModifyResource(subjectUri) - && canModifyPredicate(predicateUri) + && canModifyPredicate(predicate) && canModifyResource(objectUri); } @@ -101,9 +102,9 @@ public class EditByRolePermission extends Permission { resourceUri, roleLevel); } - private boolean canModifyPredicate(String predicateUri) { + private boolean canModifyPredicate(Property predicate) { return PropertyRestrictionPolicyHelper.getBean(ctx).canModifyPredicate( - predicateUri, roleLevel); + predicate, roleLevel); } @Override diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/BaseSelfEditingPolicy.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/BaseSelfEditingPolicy.java index 7d1563d0a..326ee93ef 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/BaseSelfEditingPolicy.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/BaseSelfEditingPolicy.java @@ -8,6 +8,7 @@ import edu.cornell.mannlib.vitro.webapp.auth.policy.bean.PropertyRestrictionPoli import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.Authorization; import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyDecision; import edu.cornell.mannlib.vitro.webapp.beans.BaseResourceBean.RoleLevel; +import edu.cornell.mannlib.vitro.webapp.beans.Property; /** * A base class with utility methods for policies involving self-editing. @@ -26,9 +27,9 @@ public abstract class BaseSelfEditingPolicy { uri, roleLevel); } - protected boolean canModifyPredicate(String uri) { + protected boolean canModifyPredicate(Property predicate) { return PropertyRestrictionPolicyHelper.getBean(ctx).canModifyPredicate( - uri, roleLevel); + predicate, roleLevel); } protected PolicyDecision cantModifyResource(String uri) { @@ -36,9 +37,9 @@ public abstract class BaseSelfEditingPolicy { + uri); } - protected PolicyDecision cantModifyPredicate(String uri) { + protected PolicyDecision cantModifyPredicate(Property predicate) { return inconclusiveDecision("No access to admin predicates; cannot modify " - + uri); + + predicate.getURI()); } protected PolicyDecision userNotAuthorizedToStatement() { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/DisplayRestrictedDataToSelfPolicy.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/DisplayRestrictedDataToSelfPolicy.java index 0f3e5e2bc..7ffbd627d 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/DisplayRestrictedDataToSelfPolicy.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/DisplayRestrictedDataToSelfPolicy.java @@ -23,6 +23,7 @@ import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestedAct import edu.cornell.mannlib.vitro.webapp.beans.BaseResourceBean.RoleLevel; import edu.cornell.mannlib.vitro.webapp.beans.DataPropertyStatement; import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatement; +import edu.cornell.mannlib.vitro.webapp.beans.Property; /** * Permit display of various data if it relates to the user's associated @@ -92,14 +93,14 @@ public class DisplayRestrictedDataToSelfPolicy implements PolicyIface { Collection individuals) { DataPropertyStatement stmt = action.getDataPropertyStatement(); String subjectUri = stmt.getIndividualURI(); - String predicateUri = stmt.getDatapropURI(); - if (canDisplayResource(subjectUri) && canDisplayPredicate(predicateUri) + Property predicate = new Property(stmt.getDatapropURI()); + if (canDisplayResource(subjectUri) && canDisplayPredicate(predicate) && isAboutAssociatedIndividual(individuals, stmt)) { return authorized("user may view DataPropertyStatement " - + subjectUri + " ==> " + predicateUri); + + subjectUri + " ==> " + predicate.getURI()); } else { return defaultDecision("user may not view DataPropertyStatement " - + subjectUri + " ==> " + predicateUri); + + subjectUri + " ==> " + predicate.getURI()); } } @@ -115,7 +116,8 @@ public class DisplayRestrictedDataToSelfPolicy implements PolicyIface { String subjectUri = stmt.getSubjectURI(); String predicateUri = stmt.getPropertyURI(); String objectUri = stmt.getObjectURI(); - if (canDisplayResource(subjectUri) && canDisplayPredicate(predicateUri) + if (canDisplayResource(subjectUri) && canDisplayPredicate(new Property + (predicateUri)) && canDisplayResource(objectUri) && isAboutAssociatedIndividual(individuals, stmt)) { return authorized("user may view ObjectPropertyStatement " @@ -143,9 +145,9 @@ public class DisplayRestrictedDataToSelfPolicy implements PolicyIface { uri, RoleLevel.SELF); } - private boolean canDisplayPredicate(String uri) { + private boolean canDisplayPredicate(Property predicate) { return PropertyRestrictionPolicyHelper.getBean(ctx) - .canDisplayPredicate(uri, RoleLevel.SELF); + .canDisplayPredicate(predicate, RoleLevel.SELF); } private boolean isAboutAssociatedIndividual(Collection selves, diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/PermissionsPolicy.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/PermissionsPolicy.java index 2bf85a628..c424ca355 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/PermissionsPolicy.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/PermissionsPolicy.java @@ -35,6 +35,8 @@ public class PermissionsPolicy implements PolicyIface { log.debug("Permission " + p + " approves request " + whatToAuth); return new BasicPolicyDecision(Authorization.AUTHORIZED, "PermissionsPolicy: approved by " + p); + } else { + log.trace("Permission " + p + " denies request " + whatToAuth); } } log.debug("No permission will approve " + whatToAuth); 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 b27a8de8a..11c351044 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 @@ -122,7 +122,8 @@ public class PolicyHelper { } Resource subject = stmt.getSubject(); - Property predicate = stmt.getPredicate(); + edu.cornell.mannlib.vitro.webapp.beans.Property predicate = + new edu.cornell.mannlib.vitro.webapp.beans.Property(stmt.getPredicate().getURI()); RDFNode objectNode = stmt.getObject(); if ((subject == null) || (predicate == null) || (objectNode == null)) { return false; @@ -131,7 +132,7 @@ public class PolicyHelper { RequestedAction action; if (objectNode.isResource()) { action = new AddObjectPropertyStatement(modelToBeModified, - subject.getURI(), predicate.getURI(), objectNode + subject.getURI(), predicate, objectNode .asResource().getURI()); } else { action = new AddDataPropertyStatement(modelToBeModified, @@ -153,7 +154,9 @@ public class PolicyHelper { } Resource subject = stmt.getSubject(); - Property predicate = stmt.getPredicate(); + edu.cornell.mannlib.vitro.webapp.beans.Property predicate = + new edu.cornell.mannlib.vitro.webapp.beans.Property(); + predicate.setURI(stmt.getPredicate().getURI()); RDFNode objectNode = stmt.getObject(); if ((subject == null) || (predicate == null) || (objectNode == null)) { return false; @@ -162,7 +165,7 @@ public class PolicyHelper { RequestedAction action; if (objectNode.isResource()) { action = new DropObjectPropertyStatement(modelToBeModified, - subject.getURI(), predicate.getURI(), objectNode + subject.getURI(), predicate, objectNode .asResource().getURI()); } else { action = new DropDataPropertyStatement(modelToBeModified, diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/SelfEditingPolicy.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/SelfEditingPolicy.java index e3a6b8dec..6ad28bfd2 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/SelfEditingPolicy.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/SelfEditingPolicy.java @@ -16,6 +16,7 @@ import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.AbstractDa import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.AbstractObjectPropertyStatementAction; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.resource.AbstractResourceAction; import edu.cornell.mannlib.vitro.webapp.beans.BaseResourceBean.RoleLevel; +import edu.cornell.mannlib.vitro.webapp.beans.Property; /** * Policy to use for Vivo Self-Editing based on NetId for use at Cornell. All @@ -69,7 +70,7 @@ public class SelfEditingPolicy extends BaseSelfEditingPolicy implements private PolicyDecision isAuthorizedForObjectPropertyAction( List userUris, AbstractObjectPropertyStatementAction action) { String subject = action.getSubjectUri(); - String predicate = action.getPredicateUri(); + Property predicate = action.getPredicate(); String object = action.getObjectUri(); if (!canModifyResource(subject)) { @@ -96,7 +97,7 @@ public class SelfEditingPolicy extends BaseSelfEditingPolicy implements private PolicyDecision isAuthorizedForDataPropertyAction( List userUris, AbstractDataPropertyStatementAction action) { String subject = action.getSubjectUri(); - String predicate = action.getPredicateUri(); + Property predicate = action.getPredicate(); if (!canModifyResource(subject)) { return cantModifyResource(subject); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/bean/PropertyRestrictionPolicyHelper.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/bean/PropertyRestrictionPolicyHelper.java index eb462b5df..e5163efd2 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/bean/PropertyRestrictionPolicyHelper.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/bean/PropertyRestrictionPolicyHelper.java @@ -7,6 +7,7 @@ import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import javax.servlet.ServletContext; @@ -17,6 +18,7 @@ import org.apache.commons.logging.Log; 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; @@ -24,18 +26,23 @@ 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.Model; -import com.hp.hpl.jena.rdf.model.Property; +import com.hp.hpl.jena.rdf.model.ModelFactory; import com.hp.hpl.jena.rdf.model.RDFNode; import com.hp.hpl.jena.rdf.model.Resource; import com.hp.hpl.jena.rdf.model.Statement; import com.hp.hpl.jena.rdf.model.StmtIterator; import com.hp.hpl.jena.rdf.model.impl.Util; +import com.hp.hpl.jena.sdb.util.Pair; import com.hp.hpl.jena.shared.Lock; +import com.hp.hpl.jena.vocabulary.OWL; import edu.cornell.mannlib.vitro.webapp.beans.BaseResourceBean.RoleLevel; +import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty; +import edu.cornell.mannlib.vitro.webapp.beans.Property; import edu.cornell.mannlib.vitro.webapp.dao.ModelAccess; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus; +import edu.cornell.mannlib.vitro.webapp.utils.ApplicationConfigurationOntologyUtils; /** * Assists the role-based policies in determining whether a property or resource @@ -108,17 +115,22 @@ public class PropertyRestrictionPolicyHelper { Model displayModel) { - Map displayThresholdMap = new HashMap(); - Map modifyThresholdMap = new HashMap(); + Map>, RoleLevel> displayThresholdMap = + new HashMap>, RoleLevel>(); + Map>, RoleLevel> modifyThresholdMap = + new HashMap>, RoleLevel>(); + + OntModel union = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM, + ModelFactory.createUnion(displayModel, model)); + + + populateThresholdMap(union, displayThresholdMap, + VitroVocabulary.HIDDEN_FROM_DISPLAY_BELOW_ROLE_LEVEL_ANNOT); + populateThresholdMap( + union, + modifyThresholdMap, + VitroVocabulary.PROHIBITED_FROM_UPDATE_BELOW_ROLE_LEVEL_ANNOT); - if (model != null) { - populateThresholdMap(model, displayThresholdMap, - VitroVocabulary.HIDDEN_FROM_DISPLAY_BELOW_ROLE_LEVEL_ANNOT); - populateThresholdMap( - model, - modifyThresholdMap, - VitroVocabulary.PROHIBITED_FROM_UPDATE_BELOW_ROLE_LEVEL_ANNOT); - } PropertyRestrictionPolicyHelper bean = new PropertyRestrictionPolicyHelper( PROHIBITED_NAMESPACES, PERMITTED_EXCEPTIONS, @@ -127,29 +139,85 @@ public class PropertyRestrictionPolicyHelper { return bean; } + private RoleLevel getModifyThreshold(Property property) { + return getThreshold(property, modifyThresholdMap); + } + + private RoleLevel getThreshold(Property property, + Map>, RoleLevel> + thresholdMap) { + if (property.getURI() == null) { + return RoleLevel.NOBODY; + } + RoleLevel roleLevel = getRoleLevelFromMap( + property.getDomainVClassURI(), property.getURI(), + property.getRangeVClassURI(), thresholdMap); + if (roleLevel == null) { + roleLevel = getRoleLevelFromMap( + OWL.Thing.getURI(), property.getURI(), OWL.Thing.getURI(), + thresholdMap); + } + return roleLevel; + } + + private RoleLevel getRoleLevelFromMap(String domainURI, + String predicateURI, + String rangeURI, + Map>, + RoleLevel> map) { + return map.get( + new Pair>( + domainURI, new Pair( + predicateURI, rangeURI))); + } + /** * Find all the resources that possess this property, and map the resource * URI to the required RoleLevel. */ private static void populateThresholdMap(OntModel model, - Map map, String propertyUri) { + Map>, RoleLevel> map, String propertyUri) { model.enterCriticalSection(Lock.READ); try { - Property property = model.getProperty(propertyUri); + com.hp.hpl.jena.rdf.model.Property property = model.getProperty(propertyUri); StmtIterator stmts = model.listStatements((Resource) null, property, (Resource) null); - while (stmts.hasNext()) { - Statement stmt = stmts.next(); - Resource subject = stmt.getSubject(); - RDFNode objectNode = stmt.getObject(); - if ((subject == null) || (!(objectNode instanceof Resource))) { - continue; - } - Resource object = (Resource) objectNode; - RoleLevel role = RoleLevel.getRoleByUri(object.getURI()); - map.put(subject.getURI(), role); + try { + while (stmts.hasNext()) { + Statement stmt = stmts.next(); + Resource subject = stmt.getSubject(); + RDFNode objectNode = stmt.getObject(); + if ((subject == null) || (!(objectNode instanceof Resource))) { + continue; + } + Resource object = (Resource) objectNode; + RoleLevel role = RoleLevel.getRoleByUri(object.getURI()); + map.put(new Pair>( + OWL.Thing.getURI(), new Pair( + subject.getURI(), OWL.Thing.getURI())), role); + } + } finally { + stmts.close(); } - stmts.close(); + List fauxOps = ApplicationConfigurationOntologyUtils + .getAdditionalFauxSubproperties(null, null, model, model); + for (ObjectProperty faux : fauxOps) { + RoleLevel role = null; + if(VitroVocabulary.PROHIBITED_FROM_UPDATE_BELOW_ROLE_LEVEL_ANNOT + .equals(propertyUri)) { + role = faux.getProhibitedFromUpdateBelowRoleLevel(); + } else if (VitroVocabulary.HIDDEN_FROM_DISPLAY_BELOW_ROLE_LEVEL_ANNOT + .equals(propertyUri)) { + role = faux.getHiddenFromDisplayBelowRoleLevel(); + } + if (role != null) { + log.debug("Putting D:" + faux.getDomainVClassURI() + " P:" + faux.getURI() + " R:" + faux.getRangeVClassURI() + " ==> L:" + role); + map.put(new Pair>( + faux.getDomainVClassURI(), new Pair( + faux.getURI(), faux.getRangeVClassURI())), role); + } + } + } finally { model.leaveCriticalSection(); } @@ -175,15 +243,14 @@ public class PropertyRestrictionPolicyHelper { * These URIs can be displayed only if the user's role is at least as high * as the threshold role. */ - private final Map displayThresholdMap; + private final Map>, RoleLevel> displayThresholdMap; /** * These URIs can be modified only if the user's role is at least as high as * the threshold role. */ - private final Map modifyThresholdMap; + private final Map>, RoleLevel> modifyThresholdMap; - private final Model displayModel; /** * Store unmodifiable versions of the inputs. @@ -194,14 +261,15 @@ public class PropertyRestrictionPolicyHelper { protected PropertyRestrictionPolicyHelper( Collection modifyProhibitedNamespaces, Collection modifyExceptionsAllowedUris, - Map displayThresholdMap, - Map modifyThresholdMap, + Map>, RoleLevel> displayThresholdMap, + Map>, RoleLevel> modifyThresholdMap, Model displayModel) { this.modifyProhibitedNamespaces = unmodifiable(modifyProhibitedNamespaces); this.modifyExceptionsAllowedUris = unmodifiable(modifyExceptionsAllowedUris); - this.displayThresholdMap = unmodifiable(displayThresholdMap); - this.modifyThresholdMap = unmodifiable(modifyThresholdMap); - this.displayModel = displayModel; + this.displayThresholdMap = displayThresholdMap; + this.modifyThresholdMap = modifyThresholdMap; +// this.displayThresholdMap = unmodifiable(displayThresholdMap); +// this.modifyThresholdMap = unmodifiable(modifyThresholdMap); if (log.isDebugEnabled()) { log.debug("prohibited: " + this.modifyProhibitedNamespaces); @@ -219,6 +287,7 @@ public class PropertyRestrictionPolicyHelper { } } + @SuppressWarnings("unused") private Map unmodifiable(Map raw) { if (raw == null) { return Collections.emptyMap(); @@ -271,83 +340,34 @@ public class PropertyRestrictionPolicyHelper { log.debug("can modify resource '" + resourceUri + "'"); return true; } - - public boolean canDisplayPredicate(String predicateUri, RoleLevel userRole) { - return canDisplayPredicate(predicateUri, null, userRole); - } /** * If display of a predicate is restricted, the user's role must be at least * as high as the restriction level. */ - public boolean canDisplayPredicate(String predicateUri, String rangeUri, RoleLevel userRole) { - if (predicateUri == null) { - log.debug("can't display predicate: predicateUri was null"); + public boolean canDisplayPredicate(Property predicate, RoleLevel userRole) { + if (predicate == null) { + log.debug("can't display predicate: predicate was null"); return false; } - RoleLevel displayThreshold = RoleLevel.NOBODY; - if (rangeUri == null) { - displayThreshold = displayThresholdMap.get(predicateUri); - } else { - log.debug("Getting display threshold for " + predicateUri + " " + rangeUri); - displayThreshold = getDisplayThreshold(predicateUri, rangeUri); - if (displayThreshold == null) { - displayThreshold = displayThresholdMap.get(predicateUri); - } - log.debug(displayThreshold); - } + RoleLevel displayThreshold = getThreshold(predicate, displayThresholdMap); if (isAuthorized(userRole, displayThreshold)) { - log.debug("can display predicate: '" + predicateUri - + "', userRole=" + userRole + ", thresholdRole=" - + displayThreshold); + log.debug("can display predicate: '" + predicate.getURI() + "', domain=" + + predicate.getDomainVClassURI() + ", range=" + + predicate.getRangeVClassURI() + ", userRole=" + + userRole + ", thresholdRole=" + displayThreshold); return true; } - log.debug("can't display predicate: '" + predicateUri + "', userRole=" - + userRole + ", thresholdRole=" + displayThreshold); + log.debug("can't display predicate: '" + predicate.getURI() + "', domain=" + + predicate.getDomainVClassURI() + ", range=" + + predicate.getRangeVClassURI() + ", userRole=" + + userRole + ", thresholdRole=" + displayThreshold); return false; } - /** - * Gets the role level threshold for displaying a predicate with a particular - * object class - * @param predicateUri - * @param rangeUri - * @return RoleLevel threshold - */ - private RoleLevel getDisplayThreshold(String predicateUri, String rangeUri) { - String query = "PREFIX rdfs: \n" + - "PREFIX config: \n" + - "PREFIX vitro: \n" + - "SELECT ?level WHERE { \n" + -// " ?p rdfs:subPropertyOf ?property . \n" + - " ?context config:configContextFor ?p . \n" + - " ?context config:qualifiedBy ?range . \n" + - " ?context config:hasConfiguration ?configuration . \n" + - " ?configuration vitro:hiddenFromDisplayBelowRoleLevelAnnot ?level \n" + - "}"; - Query q = QueryFactory.create(query); - QueryExecution qe = QueryExecutionFactory.create(q, displayModel); - try { - ResultSet rs = qe.execSelect(); - if (!rs.hasNext()) { - return null; - } - while(rs.hasNext()) { - QuerySolution qsoln = rs.nextSolution(); - Resource levelRes = qsoln.getResource("level"); - if (levelRes != null) { - return RoleLevel.getRoleByUri(levelRes.getURI()); - } - } - } finally { - qe.close(); - } - return null; - } - /** * A predicate cannot be modified if its namespace is in the prohibited list * (some exceptions are allowed). @@ -355,32 +375,36 @@ public class PropertyRestrictionPolicyHelper { * If modification of a predicate is restricted, the user's role must be at * least as high as the restriction level. */ - public boolean canModifyPredicate(String predicateUri, RoleLevel userRole) { - if (predicateUri == null) { - log.debug("can't modify predicate: predicateUri was null"); + public boolean canModifyPredicate(Property predicate, RoleLevel userRole) { + if (predicate == null || predicate.getURI() == null) { + log.debug("can't modify predicate: predicate was null"); return false; } - if (modifyProhibitedNamespaces.contains(namespace(predicateUri))) { - if (modifyExceptionsAllowedUris.contains(predicateUri)) { - log.debug("'" + predicateUri + "' is a permitted exception"); + if (modifyProhibitedNamespaces.contains(namespace(predicate.getURI()))) { + if (modifyExceptionsAllowedUris.contains(predicate.getURI())) { + log.debug("'" + predicate.getURI() + "' is a permitted exception"); } else { - log.debug("can't modify resource '" + predicateUri + log.debug("can't modify resource '" + predicate.getURI() + "': prohibited namespace: '" - + namespace(predicateUri) + "'"); + + namespace(predicate.getURI()) + "'"); return false; } } - RoleLevel modifyThreshold = modifyThresholdMap.get(predicateUri); + RoleLevel modifyThreshold = getModifyThreshold(predicate); if (isAuthorized(userRole, modifyThreshold)) { - log.debug("can modify predicate: '" + predicateUri + "', userRole=" + log.debug("can modify predicate: '" + predicate.getURI() + "', domain=" + + predicate.getDomainVClassURI() + ", range=" + + predicate.getRangeVClassURI() + ", userRole=" + userRole + ", thresholdRole=" + modifyThreshold); return true; } - log.debug("can't modify predicate: '" + predicateUri + "', userRole=" - + userRole + ", thresholdRole=" + modifyThreshold); + log.debug("can't modify predicate: '" + predicate.getURI() + "', domain=" + + predicate.getDomainVClassURI() + ", range=" + + predicate.getRangeVClassURI() + ", userRole=" + + userRole + ", thresholdRole=" + modifyThreshold); return false; } @@ -422,7 +446,7 @@ public class PropertyRestrictionPolicyHelper { throw new NullPointerException( "display model has not been initialized."); } - + PropertyRestrictionPolicyHelper bean = PropertyRestrictionPolicyHelper .createBean(model, displayModel); PropertyRestrictionPolicyHelper.setBean(ctx, bean); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/specialrelationships/AbstractRelationshipPolicy.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/specialrelationships/AbstractRelationshipPolicy.java index 02dd57f16..359c646b2 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/specialrelationships/AbstractRelationshipPolicy.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/specialrelationships/AbstractRelationshipPolicy.java @@ -13,6 +13,7 @@ import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.Authorization; import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyDecision; import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyIface; import edu.cornell.mannlib.vitro.webapp.beans.BaseResourceBean.RoleLevel; +import edu.cornell.mannlib.vitro.webapp.beans.Property; /** * A collection of building-block methods so we can code a policy based on the @@ -34,9 +35,9 @@ public abstract class AbstractRelationshipPolicy implements PolicyIface { uri, RoleLevel.SELF); } - protected boolean canModifyPredicate(String uri) { + protected boolean canModifyPredicate(Property predicate) { return PropertyRestrictionPolicyHelper.getBean(ctx).canModifyPredicate( - uri, RoleLevel.SELF); + predicate, RoleLevel.SELF); } protected PolicyDecision cantModifyResource(String uri) { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/ifaces/RequestActionConstants.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/ifaces/RequestActionConstants.java index 738814cbb..73b1c6785 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/ifaces/RequestActionConstants.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/ifaces/RequestActionConstants.java @@ -2,9 +2,12 @@ package edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces; +import edu.cornell.mannlib.vitro.webapp.beans.Property; + public class RequestActionConstants { public static String actionNamespace = "java:"; public static String SOME_URI = "?SOME_URI"; + public static Property SOME_PREDICATE = new Property(SOME_URI); public static String SOME_LITERAL = "?SOME_LITERAL"; } 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 024709878..bfcf98c2a 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 @@ -5,6 +5,7 @@ package edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt; import com.hp.hpl.jena.ontology.OntModel; import edu.cornell.mannlib.vitro.webapp.beans.DataPropertyStatement; +import edu.cornell.mannlib.vitro.webapp.beans.Property; /** * A base class for requested actions that involve adding, editing, or dropping @@ -14,12 +15,16 @@ public abstract class AbstractDataPropertyStatementAction extends AbstractPropertyStatementAction { private final String subjectUri; private final String predicateUri; + private final Property predicate; public AbstractDataPropertyStatementAction(OntModel ontModel, String subjectUri, String predicateUri) { super(ontModel); this.subjectUri = subjectUri; this.predicateUri = predicateUri; + Property dataProperty = new Property(); + dataProperty.setURI(predicateUri); + this.predicate = dataProperty; } public AbstractDataPropertyStatementAction(OntModel ontModel, @@ -28,12 +33,19 @@ public abstract class AbstractDataPropertyStatementAction extends this.subjectUri = (dps.getIndividual() == null) ? dps .getIndividualURI() : dps.getIndividual().getURI(); this.predicateUri = dps.getDatapropURI(); + Property dataProperty = new Property(); + dataProperty.setURI(predicateUri); + this.predicate = dataProperty; } public String getSubjectUri() { return subjectUri; } + public Property getPredicate() { + return predicate; + } + @Override public String getPredicateUri() { return predicateUri; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/propstmt/AbstractObjectPropertyStatementAction.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/propstmt/AbstractObjectPropertyStatementAction.java index da380c383..700b0bf24 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/propstmt/AbstractObjectPropertyStatementAction.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/propstmt/AbstractObjectPropertyStatementAction.java @@ -5,6 +5,7 @@ package edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt; import com.hp.hpl.jena.ontology.OntModel; import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatement; +import edu.cornell.mannlib.vitro.webapp.beans.Property; /** * A base class for requested actions that involve adding, editing, or deleting @@ -13,14 +14,14 @@ import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatement; public abstract class AbstractObjectPropertyStatementAction extends AbstractPropertyStatementAction { private final String subjectUri; - private final String predicateUri; + private final Property predicate; private final String objectUri; public AbstractObjectPropertyStatementAction(OntModel ontModel, String subjectUri, - String predicateUri, String objectUri) { + Property predicate, String objectUri) { super(ontModel); this.subjectUri = subjectUri; - this.predicateUri = predicateUri; + this.predicate = predicate; this.objectUri = objectUri; } @@ -28,8 +29,7 @@ public abstract class AbstractObjectPropertyStatementAction extends super(ontModel); this.subjectUri = (ops.getSubject() == null) ? ops.getSubjectURI() : ops.getSubject().getURI(); - this.predicateUri = (ops.getProperty() == null) ? ops.getPropertyURI() - : ops.getProperty().getURI(); + this.predicate = (ops.getProperty()); this.objectUri = (ops.getObject() == null) ? ops.getObjectURI() : ops .getObject().getURI(); } @@ -42,9 +42,13 @@ public abstract class AbstractObjectPropertyStatementAction extends return objectUri; } + public Property getPredicate() { + return predicate; + } + @Override public String getPredicateUri() { - return predicateUri; + return predicate.getURI(); } @Override @@ -55,6 +59,6 @@ public abstract class AbstractObjectPropertyStatementAction extends @Override public String toString() { return this.getClass().getSimpleName() + ": <" + subjectUri + "> <" - + predicateUri + "> <" + objectUri + ">"; + + predicate.getURI() + "> <" + objectUri + ">"; } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/propstmt/AbstractPropertyStatementAction.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/propstmt/AbstractPropertyStatementAction.java index 82434a2bd..6f5d95dae 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/propstmt/AbstractPropertyStatementAction.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/propstmt/AbstractPropertyStatementAction.java @@ -5,6 +5,7 @@ package edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt; import com.hp.hpl.jena.ontology.OntModel; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestedAction; +import edu.cornell.mannlib.vitro.webapp.beans.Property; /** * A base class for requested actions that involve adding, editing, or deleting @@ -27,5 +28,7 @@ public abstract class AbstractPropertyStatementAction extends RequestedAction { */ public abstract String[] getResourceUris(); + public abstract Property getPredicate(); + public abstract String getPredicateUri(); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/propstmt/AddObjectPropertyStatement.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/propstmt/AddObjectPropertyStatement.java index 423893328..286850787 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/propstmt/AddObjectPropertyStatement.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/propstmt/AddObjectPropertyStatement.java @@ -5,6 +5,7 @@ package edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt; import com.hp.hpl.jena.ontology.OntModel; import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatement; +import edu.cornell.mannlib.vitro.webapp.beans.Property; /** * Should we allow the user to add this ObjectPropertyStatement to this model? @@ -12,8 +13,8 @@ import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatement; public class AddObjectPropertyStatement extends AbstractObjectPropertyStatementAction { public AddObjectPropertyStatement(OntModel ontModel, String uriOfSub, - String uriOfPred, String uriOfObj) { - super(ontModel, uriOfSub, uriOfPred, uriOfObj); + Property predicate, String uriOfObj) { + super(ontModel, uriOfSub, predicate, uriOfObj); } public AddObjectPropertyStatement(OntModel ontModel, diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/propstmt/DropObjectPropertyStatement.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/propstmt/DropObjectPropertyStatement.java index c994a39e8..016dec38a 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/propstmt/DropObjectPropertyStatement.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/propstmt/DropObjectPropertyStatement.java @@ -5,6 +5,7 @@ package edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt; import com.hp.hpl.jena.ontology.OntModel; import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatement; +import edu.cornell.mannlib.vitro.webapp.beans.Property; /** * Should we allow the user to delete this ObjectPropertyStatement from this @@ -13,7 +14,7 @@ import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatement; public class DropObjectPropertyStatement extends AbstractObjectPropertyStatementAction { public DropObjectPropertyStatement(OntModel ontModel, String sub, - String pred, String obj) { + Property pred, String obj) { super(ontModel, sub, pred, obj); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/propstmt/EditObjectPropertyStatement.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/propstmt/EditObjectPropertyStatement.java index 732c3fa31..cb65eea0d 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/propstmt/EditObjectPropertyStatement.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/requestedAction/propstmt/EditObjectPropertyStatement.java @@ -5,6 +5,7 @@ package edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt; import com.hp.hpl.jena.ontology.OntModel; import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatement; +import edu.cornell.mannlib.vitro.webapp.beans.Property; /** * Should we allow the user to edit this ObjectPropertyStatement in this model? @@ -12,8 +13,8 @@ import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatement; public class EditObjectPropertyStatement extends AbstractObjectPropertyStatementAction { public EditObjectPropertyStatement(OntModel ontModel, String subjectUri, - String keywordPredUri, String objectUri) { - super(ontModel, subjectUri, keywordPredUri, objectUri); + Property keywordPred, String objectUri) { + super(ontModel, subjectUri, keywordPred, objectUri); } public EditObjectPropertyStatement(OntModel ontModel, 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 be5609495..61a195f12 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/beans/ObjectProperty.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/beans/ObjectProperty.java @@ -78,10 +78,12 @@ public class ObjectProperty extends Property implements Comparable public Float getSearchBoost() { return searchBoost; } public void setSearchBoost( Float boost ){ searchBoost = boost;} + public boolean isUnion() { return false; } + public List getUnionComponents() { return new ArrayList(); } + /** * Default constructor */ diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/SparqlQueryServlet.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/SparqlQueryServlet.java index ab6d52616..ec6d1d1eb 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/SparqlQueryServlet.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/SparqlQueryServlet.java @@ -9,9 +9,11 @@ import java.io.PrintWriter; import java.io.Writer; import java.net.URLDecoder; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; @@ -40,6 +42,7 @@ import com.hp.hpl.jena.vocabulary.XSD; import edu.cornell.mannlib.vedit.controller.BaseEditController; import edu.cornell.mannlib.vitro.webapp.auth.permissions.SimplePermission; import edu.cornell.mannlib.vitro.webapp.beans.Ontology; +import edu.cornell.mannlib.vitro.webapp.controller.individual.IndividualController; import edu.cornell.mannlib.vitro.webapp.dao.OntologyDao; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService.ModelSerializationFormat; @@ -47,45 +50,37 @@ import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService.ResultFormat; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException; import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils; import edu.cornell.mannlib.vitro.webapp.utils.SparqlQueryUtils; +import edu.cornell.mannlib.vitro.webapp.web.ContentType; /** - * Services a sparql query. This will return a simple error message and a 501 if + * Services a SPARQL query. This will return a simple error message and a 501 if * there is no Model. * + * * @author bdc34 * */ public class SparqlQueryServlet extends BaseEditController { private static final Log log = LogFactory.getLog(SparqlQueryServlet.class.getName()); - - private final static boolean CONVERT = true; /** * format configurations for SELECT queries. */ protected static HashMap rsFormats = new HashMap(); - - private static RSFormatConfig[] rsfs = { - new RSFormatConfig( "RS_XML", !CONVERT, ResultFormat.XML, null, "text/xml"), - new RSFormatConfig( "RS_TEXT", !CONVERT, ResultFormat.TEXT, null, "text/plain"), - new RSFormatConfig( "vitro:csv", !CONVERT, ResultFormat.CSV, null, "text/csv"), - new RSFormatConfig( "RS_JSON", !CONVERT, ResultFormat.JSON, null, "application/javascript") }; - + /** * format configurations for CONSTRUCT/DESCRIBE queries. */ protected static HashMap modelFormats = new HashMap(); - private static ModelFormatConfig[] fmts = { - new ModelFormatConfig("RDF/XML", !CONVERT, ModelSerializationFormat.RDFXML, null, "application/rdf+xml" ), - new ModelFormatConfig("RDF/XML-ABBREV", CONVERT, ModelSerializationFormat.N3, "RDF/XML-ABBREV", "application/rdf+xml" ), - new ModelFormatConfig("N3", !CONVERT, ModelSerializationFormat.N3, null, "text/n3" ), - new ModelFormatConfig("N-TRIPLE", !CONVERT, ModelSerializationFormat.NTRIPLE, null, "text/plain" ), - new ModelFormatConfig("TTL", CONVERT, ModelSerializationFormat.N3, "TTL", "application/x-turtle" ), - new ModelFormatConfig("JSON-LD", CONVERT, ModelSerializationFormat.N3, "JSON-LD", "application/javascript" ) }; + /** + * Use this map to decide which MIME type is suited for the "accept" header. + */ + public static final Map ACCEPTED_CONTENT_TYPES; + @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException @@ -113,100 +108,85 @@ public class SparqlQueryServlet extends BaseEditController { String queryParam = vreq.getParameter("query"); log.debug("queryParam was : " + queryParam); - String resultFormatParam = vreq.getParameter("resultFormat"); - log.debug("resultFormat was: " + resultFormatParam); - - String rdfResultFormatParam = vreq.getParameter("rdfResultFormat"); - if (rdfResultFormatParam == null) { - rdfResultFormatParam = "RDF/XML-ABBREV"; - } - log.debug("rdfResultFormat was: " + rdfResultFormatParam); - - if( queryParam == null || "".equals(queryParam) || - resultFormatParam == null || "".equals(resultFormatParam) || - !rsFormats.containsKey( resultFormatParam ) || - rdfResultFormatParam == null || "".equals(rdfResultFormatParam) || - !modelFormats.containsKey( rdfResultFormatParam ) ) { + if( queryParam == null || "".equals(queryParam) ){ doHelp(request,response); return; } - - executeQuery(response, resultFormatParam, rdfResultFormatParam, - queryParam, vreq.getUnfilteredRDFService()); + + String contentType = checkForContentType(vreq.getHeader("Accept")); + + Query query = SparqlQueryUtils.create(queryParam); + if( query.isSelectType() ){ + String format = contentType!=null ? contentType:vreq.getParameter("resultFormat"); + RSFormatConfig formatConf = rsFormats.get(format); + doSelect(response, queryParam, formatConf, vreq.getRDFService()); + }else if( query.isAskType()){ + doAsk( queryParam, vreq.getRDFService(), response ); + }else if( query.isConstructType() ){ + String format = contentType != null ? contentType : vreq.getParameter("rdfResultFormat"); + if (format== null) { + format= "RDF/XML-ABBREV"; + } + ModelFormatConfig formatConf = modelFormats.get(format); + doConstruct(response, query, formatConf, vreq.getRDFService()); + }else{ + doHelp(request,response); + } return; } - private void executeQuery(HttpServletResponse response, - String resultFormatParam, - String rdfResultFormatParam, - String queryParam, - RDFService rdfService ) throws IOException { - /* BJL23 2008-11-06 - * modified to support CSV output. - * Unfortunately, ARQ doesn't make it easy to - * do this by implementing a new ResultSetFormat, because - * ResultSetFormatter is hardwired with expected values. - * This slightly ugly approach will have to do for now. - */ -// if ( !("vitro:csv").equals(resultFormatParam) ) { -// rsf = selectFormatSymbols.get(resultFormatParam); -// } -// String mimeType = rdfFormatToMimeType.get(resultFormatParam); - - try{ - Query query = SparqlQueryUtils.create(queryParam); - if( query.isSelectType() ){ - doSelectQuery( queryParam, rdfService, resultFormatParam, response); - } else if(query.isAskType()){ - // Irrespective of the ResultFormatParam, - // this always prints a boolean to the default OutputStream. - String result = (rdfService.sparqlAskQuery(queryParam) == true) - ? "true" - : "false"; - PrintWriter p = response.getWriter(); - p.write(result); - return; - } else { - doModelResultQuery( query, rdfService, rdfResultFormatParam, response); - } - } catch (RDFServiceException e) { - throw new RuntimeException(e); - } - } + private void doAsk(String queryParam, RDFService rdfService, + HttpServletResponse response) throws ServletException, IOException { + + // Irrespective of the ResultFormatParam, + // this always prints a boolean to the default OutputStream. + String result; + try { + result = (rdfService.sparqlAskQuery(queryParam) == true) + ? "true" + : "false"; + } catch (RDFServiceException e) { + throw new ServletException( "Could not execute ask query ", e ); + } + PrintWriter p = response.getWriter(); + p.write(result); + return; + } + /** * Execute the query and send the result to out. Attempt to * send the RDFService the same format as the rdfResultFormatParam * so that the results from the RDFService can be directly piped to the client. - * @param rdfService - * @throws IOException - * @throws RDFServiceException */ - private void doSelectQuery( String queryParam, - RDFService rdfService, String resultFormatParam, - HttpServletResponse response) throws IOException, RDFServiceException{ - RSFormatConfig config = rsFormats.get( resultFormatParam ); + private void doSelect(HttpServletResponse response, + String queryParam, + RSFormatConfig formatConf, + RDFService rdfService + ) throws ServletException { + try { + if( ! formatConf.converstionFromWireFormat ){ + response.setContentType( formatConf.responseMimeType ); + InputStream results; + results = rdfService.sparqlSelectQuery(queryParam, formatConf.wireFormat ); + pipe( results, response.getOutputStream() ); + }else{ + //always use JSON when conversion is needed. + InputStream results = rdfService.sparqlSelectQuery(queryParam, ResultFormat.JSON ); - if( ! config.converstionFromWireFormat ){ - response.setContentType( config.responseMimeType ); - InputStream results = rdfService.sparqlSelectQuery(queryParam, config.wireFormat ); - pipe( results, response.getOutputStream() ); - }else{ - //always use JSON when conversion is needed. - InputStream results = rdfService.sparqlSelectQuery(queryParam, ResultFormat.JSON ); - - response.setContentType( config.responseMimeType ); - - ResultSet rs = ResultSetFactory.fromJSON( results ); - OutputStream out = response.getOutputStream(); - ResultSetFormatter.output(out, rs, config.jenaResponseFormat); - - // } else { - // Writer out = response.getWriter(); - // toCsv(out, results); - //} + response.setContentType( formatConf.responseMimeType ); + + ResultSet rs = ResultSetFactory.fromJSON( results ); + OutputStream out = response.getOutputStream(); + ResultSetFormatter.output(out, rs, formatConf.jenaResponseFormat); + } + } catch (RDFServiceException e) { + throw new ServletException("Cannot get result from the RDFService",e); + } catch (IOException e) { + throw new ServletException("Cannot perform SPARQL SELECT",e); } } + /** * Execute the query and send the result to out. Attempt to @@ -217,40 +197,44 @@ public class SparqlQueryServlet extends BaseEditController { * @throws RDFServiceException * @throws */ - private void doModelResultQuery( Query query, - RDFService rdfService, String rdfResultFormatParam, - HttpServletResponse response) throws IOException, RDFServiceException{ - - //config drives what formats and conversions to use - ModelFormatConfig config = modelFormats.get( rdfResultFormatParam ); - - InputStream rawResult = null; - if( query.isConstructType() ){ - rawResult= rdfService.sparqlConstructQuery( query.toString(), config.wireFormat ); - }else if ( query.isDescribeType() ){ - rawResult = rdfService.sparqlDescribeQuery( query.toString(), config.wireFormat ); - } - - response.setContentType( config.responseMimeType ); - - if( config.converstionFromWireFormat ){ - Model resultModel = RDFServiceUtils.parseModel( rawResult, config.wireFormat ); - if( "JSON-LD".equals( config.jenaResponseFormat )){ - //since jena 2.6.4 doesn't support JSON-LD we do it - try { - JenaRDFParser parser = new JenaRDFParser(); - Object json = JSONLD.fromRDF(resultModel, parser); - JSONUtils.write(response.getWriter(), json); - } catch (JSONLDProcessingError e) { - throw new RDFServiceException("Could not convert from Jena model to JSON-LD", e); + private void doConstruct( HttpServletResponse response, + Query query, + ModelFormatConfig formatConfig, + RDFService rdfService + ) throws ServletException{ + try{ + InputStream rawResult = null; + if( query.isConstructType() ){ + rawResult= rdfService.sparqlConstructQuery( query.toString(), formatConfig.wireFormat ); + }else if ( query.isDescribeType() ){ + rawResult = rdfService.sparqlDescribeQuery( query.toString(), formatConfig.wireFormat ); + } + + response.setContentType( formatConfig.responseMimeType ); + + if( formatConfig.converstionFromWireFormat ){ + Model resultModel = RDFServiceUtils.parseModel( rawResult, formatConfig.wireFormat ); + if( "JSON-LD".equals( formatConfig.jenaResponseFormat )){ + //since jena 2.6.4 doesn't support JSON-LD we do it + try { + JenaRDFParser parser = new JenaRDFParser(); + Object json = JSONLD.fromRDF(resultModel, parser); + JSONUtils.write(response.getWriter(), json); + } catch (JSONLDProcessingError e) { + throw new RDFServiceException("Could not convert from Jena model to JSON-LD", e); + } + }else{ + OutputStream out = response.getOutputStream(); + resultModel.write(out, formatConfig.jenaResponseFormat ); } }else{ OutputStream out = response.getOutputStream(); - resultModel.write(out, config.jenaResponseFormat ); + pipe( rawResult, out ); } - }else{ - OutputStream out = response.getOutputStream(); - pipe( rawResult, out ); + }catch( IOException ex){ + throw new ServletException("could not run SPARQL CONSTRUCT",ex); + } catch (RDFServiceException ex) { + throw new ServletException("could not run SPARQL CONSTRUCT",ex); } } @@ -362,13 +346,35 @@ public class SparqlQueryServlet extends BaseEditController { rd.forward(req,res); } + /** Simple boolean vaule to improve the legibility of confiugrations. */ + private final static boolean CONVERT = true; - public static class ModelFormatConfig{ + /** Simple vaule to improve the legibility of confiugrations. */ + private final static String NO_CONVERSION = null; + + public static class FormatConfig{ public String valueFromForm; public boolean converstionFromWireFormat; - public RDFService.ModelSerializationFormat wireFormat; - public String jenaResponseFormat; public String responseMimeType; + } + + private static ModelFormatConfig[] fmts = { + new ModelFormatConfig("RDF/XML", + !CONVERT, ModelSerializationFormat.RDFXML, NO_CONVERSION, "application/rdf+xml" ), + new ModelFormatConfig("RDF/XML-ABBREV", + CONVERT, ModelSerializationFormat.N3, "RDF/XML-ABBREV", "application/rdf+xml" ), + new ModelFormatConfig("N3", + !CONVERT, ModelSerializationFormat.N3, NO_CONVERSION, "text/n3" ), + new ModelFormatConfig("N-TRIPLE", + !CONVERT, ModelSerializationFormat.NTRIPLE, NO_CONVERSION, "text/plain" ), + new ModelFormatConfig("TTL", + CONVERT, ModelSerializationFormat.N3, "TTL", "application/x-turtle" ), + new ModelFormatConfig("JSON-LD", + CONVERT, ModelSerializationFormat.N3, "JSON-LD", "application/javascript" ) }; + + public static class ModelFormatConfig extends FormatConfig{ + public RDFService.ModelSerializationFormat wireFormat; + public String jenaResponseFormat; public ModelFormatConfig( String valueFromForm, boolean converstionFromWireFormat, @@ -383,12 +389,20 @@ public class SparqlQueryServlet extends BaseEditController { } } - public static class RSFormatConfig{ - public String valueFromForm; - public boolean converstionFromWireFormat; + + private static RSFormatConfig[] rsfs = { + new RSFormatConfig( "RS_XML", + !CONVERT, ResultFormat.XML, null, "text/xml"), + new RSFormatConfig( "RS_TEXT", + !CONVERT, ResultFormat.TEXT, null, "text/plain"), + new RSFormatConfig( "vitro:csv", + !CONVERT, ResultFormat.CSV, null, "text/csv"), + new RSFormatConfig( "RS_JSON", + !CONVERT, ResultFormat.JSON, null, "application/javascript") }; + + public static class RSFormatConfig extends FormatConfig{ public ResultFormat wireFormat; public ResultSetFormat jenaResponseFormat; - public String responseMimeType; public RSFormatConfig( String valueFromForm, boolean converstionFromWireFormat, @@ -403,14 +417,48 @@ public class SparqlQueryServlet extends BaseEditController { } } - static{ - /* move the lists of configs into maps for easy lookup */ + static{ + HashMap map = new HashMap(); + + /* move the lists of configurations into maps for easy lookup + * by both MIME content type and the parameters from the form */ for( RSFormatConfig rsfc : rsfs ){ rsFormats.put( rsfc.valueFromForm, rsfc ); + rsFormats.put( rsfc.responseMimeType, rsfc); + map.put(rsfc.responseMimeType, 1.0f); } for( ModelFormatConfig mfc : fmts ){ modelFormats.put( mfc.valueFromForm, mfc); - } + modelFormats.put(mfc.responseMimeType, mfc); + map.put(mfc.responseMimeType, 1.0f); + } + + ACCEPTED_CONTENT_TYPES = Collections.unmodifiableMap(map); } + + /** + * Get the content type based on content negotiation. + * Returns null of no content type can be agreed on or + * if there is no accept header. + */ + protected String checkForContentType( String acceptHeader ) { + if (acceptHeader == null) + return null; + + try { + Map typesAndQ = ContentType + .getTypesAndQ(acceptHeader); + + String ctStr = ContentType + .getBestContentType(typesAndQ,ACCEPTED_CONTENT_TYPES); + + if( ACCEPTED_CONTENT_TYPES.containsKey( ctStr )){ + return ctStr; + } + } catch (Throwable th) { + log.error("Problem while checking accept header ", th); + } + return null; + } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/admin/ShowAuthController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/admin/ShowAuthController.java index 7fcfaba38..fc57c4084 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/admin/ShowAuthController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/admin/ShowAuthController.java @@ -91,7 +91,7 @@ public class ShowAuthController extends FreemarkerHttpServlet { private boolean mayEditIndividual(VitroRequest vreq, String individualUri) { RequestedAction action = new EditObjectPropertyStatement( vreq.getJenaOntModel(), individualUri, - RequestActionConstants.SOME_URI, + RequestActionConstants.SOME_PREDICATE, RequestActionConstants.SOME_URI); return PolicyHelper.isAuthorizedForActions(vreq, action); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/Classes2ClassesRetryController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/Classes2ClassesRetryController.java index 262db6590..f724e82b1 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/Classes2ClassesRetryController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/Classes2ClassesRetryController.java @@ -19,6 +19,7 @@ import edu.cornell.mannlib.vitro.webapp.auth.permissions.SimplePermission; import edu.cornell.mannlib.vitro.webapp.beans.Classes2Classes; import edu.cornell.mannlib.vitro.webapp.controller.Controllers; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.dao.ModelAccess; import edu.cornell.mannlib.vitro.webapp.dao.VClassDao; public class Classes2ClassesRetryController extends BaseEditController { @@ -43,7 +44,7 @@ public class Classes2ClassesRetryController extends BaseEditController { action = epo.getAction(); } - VClassDao vcDao = request.getUnfilteredWebappDaoFactory().getVClassDao(); + VClassDao vcDao = ModelAccess.on(getServletContext()).getWebappDaoFactory().getVClassDao(); epo.setDataAccessObject(vcDao); Classes2Classes objectForEditing = new Classes2Classes(); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/OntologyRetryController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/OntologyRetryController.java index e9d5405ee..f9814d647 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/OntologyRetryController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/OntologyRetryController.java @@ -22,6 +22,7 @@ import edu.cornell.mannlib.vedit.forwarder.impl.UrlForwarder; import edu.cornell.mannlib.vedit.util.FormUtils; import edu.cornell.mannlib.vedit.validator.Validator; import edu.cornell.mannlib.vedit.validator.impl.RequiredFieldValidator; +import edu.cornell.mannlib.vedit.validator.impl.UrlValidator; import edu.cornell.mannlib.vitro.webapp.auth.permissions.SimplePermission; import edu.cornell.mannlib.vitro.webapp.beans.Ontology; import edu.cornell.mannlib.vitro.webapp.controller.Controllers; @@ -47,7 +48,13 @@ public class OntologyRetryController extends BaseEditController { epo.setBeanClass(Ontology.class); epo.setBeanMask(testMask); - String action = "insert"; + String action = null; + if (epo.getAction() == null) { + action = "insert"; + epo.setAction("insert"); + } else { + action = epo.getAction(); + } OntologyDao oDao = request.getUnfilteredWebappDaoFactory().getOntologyDao(); epo.setDataAccessObject(oDao); @@ -67,13 +74,12 @@ public class OntologyRetryController extends BaseEditController { epo.setOriginalBean(ontologyForEditing); } else { ontologyForEditing = (Ontology) epo.getNewBean(); - action = "update"; - log.error("using newBean"); } //validators List validatorList = new ArrayList(); validatorList.add(new RequiredFieldValidator()); + validatorList.add(new UrlValidator()); epo.getValidatorMap().put("URI", validatorList); //make a simple mask for the class's id diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/PropertyRetryController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/PropertyRetryController.java index 760c1905b..0c8781180 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/PropertyRetryController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/PropertyRetryController.java @@ -37,6 +37,7 @@ 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.edit.utils.RoleLevelOptionsSetup; +import edu.cornell.mannlib.vitro.webapp.dao.ModelAccess; import edu.cornell.mannlib.vitro.webapp.dao.ObjectPropertyDao; import edu.cornell.mannlib.vitro.webapp.dao.OntologyDao; import edu.cornell.mannlib.vitro.webapp.dao.VClassDao; @@ -69,7 +70,8 @@ public class PropertyRetryController extends BaseEditController { action = epo.getAction(); } - ObjectPropertyDao propDao = request.getUnfilteredWebappDaoFactory().getObjectPropertyDao(); + ObjectPropertyDao propDao = ModelAccess.on(getServletContext()).getWebappDaoFactory().getObjectPropertyDao(); + //getUnfilteredWebappDaoFactory().getObjectPropertyDao(); epo.setDataAccessObject(propDao); OntologyDao ontDao = request.getUnfilteredWebappDaoFactory().getOntologyDao(); VClassDao vclassDao = request.getUnfilteredWebappDaoFactory().getVClassDao(); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/VclassEditController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/VclassEditController.java index 19199f330..10e5debd1 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/VclassEditController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/VclassEditController.java @@ -24,6 +24,7 @@ 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.dao.ModelAccess; import edu.cornell.mannlib.vitro.webapp.dao.VClassDao; import edu.cornell.mannlib.vitro.webapp.dao.VClassGroupDao; import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; @@ -44,7 +45,7 @@ public class VclassEditController extends BaseEditController { EditProcessObject epo = super.createEpo(request, FORCE_NEW); request.setAttribute("epoKey", epo.getKey()); - VClassDao vcwDao = request.getUnfilteredWebappDaoFactory().getVClassDao(); + VClassDao vcwDao = ModelAccess.on(getServletContext()).getBaseWebappDaoFactory().getVClassDao(); VClass vcl = (VClass)vcwDao.getVClassByURI(request.getParameter("uri")); if (vcl == null) { @@ -140,8 +141,8 @@ public class VclassEditController extends BaseEditController { HashMap formSelect = new HashMap(); // tells the JSP what select lists are populated, and thus should be displayed request.setAttribute("formSelect",formSelect); - // if supported, we want to show only the asserted superclasses and subclasses. Don't want to see anonymous classes, restrictions, etc. - VClassDao vcDao = request.getUnfilteredAssertionsWebappDaoFactory().getVClassDao(); + // if supported, we want to show only the asserted superclasses and subclasses. + VClassDao vcDao = ModelAccess.on(getServletContext()).getBaseWebappDaoFactory().getVClassDao(); List superURIs = vcDao.getSuperClassURIs(vcl.getURI(),false); List superVClasses = new ArrayList(); Iterator superURIit = superURIs.iterator(); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ImageUploadController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ImageUploadController.java index 33f0ee2ec..b15b402ad 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ImageUploadController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ImageUploadController.java @@ -23,6 +23,7 @@ import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.AddObjectP import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.DropObjectPropertyStatement; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.EditObjectPropertyStatement; import edu.cornell.mannlib.vitro.webapp.beans.Individual; +import edu.cornell.mannlib.vitro.webapp.beans.Property; import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.ParamMap; @@ -146,20 +147,23 @@ public class ImageUploadController extends FreemarkerHttpServlet { String action = vreq.getParameter(PARAMETER_ACTION); Individual entity = validateEntityUri(vreq); String imageUri = entity.getMainImageUri(); + + Property indMainImage = new Property(); + indMainImage.setURI(VitroVocabulary.IND_MAIN_IMAGE); RequestedAction ra; if (ACTION_DELETE.equals(action) || ACTION_DELETE_EDIT.equals(action)) { ra = new DropObjectPropertyStatement(vreq.getJenaOntModel(), - entity.getURI(), VitroVocabulary.IND_MAIN_IMAGE, + entity.getURI(), indMainImage, imageUri); } else if (imageUri != null) { ra = new EditObjectPropertyStatement(vreq.getJenaOntModel(), - entity.getURI(), VitroVocabulary.IND_MAIN_IMAGE, + entity.getURI(), indMainImage, imageUri); } else { ra = new AddObjectPropertyStatement(vreq.getJenaOntModel(), - entity.getURI(), VitroVocabulary.IND_MAIN_IMAGE, + entity.getURI(), indMainImage, RequestActionConstants.SOME_URI); } return new Actions(ra); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/individual/IndividualRequestAnalyzer.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/individual/IndividualRequestAnalyzer.java index d89766164..c0e8561d9 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/individual/IndividualRequestAnalyzer.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/individual/IndividualRequestAnalyzer.java @@ -132,10 +132,11 @@ public class IndividualRequestAnalyzer { * only provide a set of bytes. */ protected ContentType checkAcceptHeaderForLinkedDataRequest() { - String acceptHeader = vreq.getHeader("accept"); - if (acceptHeader == null) { - return null; - } + String acceptHeader = vreq.getHeader("Accept"); + if (acceptHeader == null) + acceptHeader = vreq.getHeader("accept"); + if (acceptHeader == null) + return null; try { Map typesAndQ = ContentType diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/jena/RDFUploadController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/jena/RDFUploadController.java index 24fe90dce..a196d8d28 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/jena/RDFUploadController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/jena/RDFUploadController.java @@ -77,11 +77,16 @@ public class RDFUploadController extends JenaIngestController { VitroRequest request = new VitroRequest(req); LoginStatusBean loginBean = LoginStatusBean.getBean(request); - String modelName = req.getParameter("modelName"); - if(modelName!=null){ - loadRDF(req,request,response); - return; - } + try { + String modelName = req.getParameter("modelName"); + if(modelName!=null){ + loadRDF(req,request,response); + return; + } + } catch (Exception e) { + log.error(e,e); + throw new RuntimeException(e); + } boolean remove = "remove".equals(request.getParameter("mode")); String verb = remove?"Removed":"Added"; 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 7d70cfc52..6c120ee79 100755 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/ObjectPropertyDao.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/ObjectPropertyDao.java @@ -15,7 +15,7 @@ public interface ObjectPropertyDao extends PropertyDao { public ObjectProperty getObjectPropertyByURI(String objectPropertyURI); - public ObjectProperty getObjectPropertyByURIAndRangeURI(String objectPropertyURI, String rangeURI); + public ObjectProperty getObjectPropertyByURIs(String objectPropertyURI, String domainURI, String rangeURI); public List getObjectPropertiesForObjectPropertyStatements(List /*of ObjectPropertyStatement */ objectPropertyStatements); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/ObjectPropertyStatementDao.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/ObjectPropertyStatementDao.java index 34bd23d46..7f750e7f4 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/ObjectPropertyStatementDao.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/ObjectPropertyStatementDao.java @@ -41,8 +41,8 @@ public interface ObjectPropertyStatementDao { public Map getMostSpecificTypesInClassgroupsForIndividual(String subjectUri); List> getObjectPropertyStatementsForIndividualByProperty( - String subjectUri, String propertyUri, String objectKey, String rangeUri, - String queryString, Set constructQueryStrings, + String subjectUri, String propertyUri, String objectKey, String domainUri, + String rangeUri, String queryString, Set constructQueryStrings, String sortDirection); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/VitroVocabulary.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/VitroVocabulary.java index ae21af42d..d06f6ccab 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/VitroVocabulary.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/VitroVocabulary.java @@ -7,10 +7,13 @@ public class VitroVocabulary { public static final String vitroURI = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#"; + public static final String configURI= "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationConfiguration#"; public static final String VITRO_AUTH = "http://vitro.mannlib.cornell.edu/ns/vitro/authorization#"; public static final String VITRO_PUBLIC = "http://vitro.mannlib.cornell.edu/ns/vitro/public#"; public static final String VITRO_PUBLIC_ONTOLOGY = "http://vitro.mannlib.cornell.edu/ns/vitro/public"; + // TODO change the following before 1.6 release + public static final String PROPERTY_CONFIG_DATA = "http://example.org/appConfig/"; /** BJL23 2008-02-25: @@ -95,6 +98,9 @@ public class VitroVocabulary { public static final String PROPERTY_CUSTOM_LIST_VIEW_ANNOT = vitroURI + "customListViewAnnot"; public static final String PROPERTY_SELECTFROMEXISTINGANNOT = vitroURI+"selectFromExistingAnnot"; public static final String PROPERTY_OFFERCREATENEWOPTIONANNOT = vitroURI+"offerCreateNewOptionAnnot"; + public static final String PROPERTY_EDITLINKSUPPRESSED = configURI + "editLinkSuppressed"; + public static final String PROPERTY_ADDLINKSUPPRESSED = configURI + "addLinkSuppressed"; + public static final String PROPERTY_DELETELINKSUPPRESSED = configURI + "deleteLinkSuppressed"; public static final String PROPERTY_INPROPERTYGROUPANNOT = vitroURI+"inPropertyGroupAnnot"; public static final String PROPERTYGROUP = vitroURI + "PropertyGroup"; public static final String MASKS_PROPERTY = vitroURI + "masksProperty"; 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 7e8704582..525301c3b 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 @@ -49,8 +49,8 @@ class ObjectPropertyDaoFiltering extends BaseFiltering implements ObjectProperty return (newOprop == null) ? null : new ObjectPropertyFiltering(newOprop, filters); } - public ObjectProperty getObjectPropertyByURIAndRangeURI(String objectPropertyURI, String rangeURI) { - ObjectProperty newOprop=innerObjectPropertyDao.getObjectPropertyByURIAndRangeURI(objectPropertyURI, rangeURI); + public ObjectProperty getObjectPropertyByURIs(String objectPropertyURI, String domainURI, String rangeURI) { + ObjectProperty newOprop=innerObjectPropertyDao.getObjectPropertyByURIs(objectPropertyURI, domainURI, rangeURI); return (newOprop == null) ? null : new ObjectPropertyFiltering(newOprop, filters); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/ObjectPropertyFiltering.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/ObjectPropertyFiltering.java index bf711c970..0706ba42e 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/ObjectPropertyFiltering.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/ObjectPropertyFiltering.java @@ -523,6 +523,36 @@ public class ObjectPropertyFiltering extends ObjectProperty { public void setCollateBySubclass(boolean collate) { innerObjectProperty.setCollateBySubclass(collate); } + + @Override + public boolean isEditLinkSuppressed() { + return innerObjectProperty.isEditLinkSuppressed(); + } + + @Override + public boolean isAddLinkSuppressed() { + return innerObjectProperty.isAddLinkSuppressed(); + } + + @Override + public boolean isDeleteLinkSuppressed() { + return innerObjectProperty.isDeleteLinkSuppressed(); + } + + @Override + public void setEditLinkSuppressed(boolean editLinkSuppressed) { + innerObjectProperty.setEditLinkSuppressed(editLinkSuppressed); + } + + @Override + public void setAddLinkSuppressed(boolean addLinkSuppressed) { + innerObjectProperty.setAddLinkSuppressed(addLinkSuppressed); + } + + @Override + public void setDeleteLinkSuppressed(boolean deleteLinkSuppressed) { + innerObjectProperty.setDeleteLinkSuppressed(deleteLinkSuppressed); + } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/ObjectPropertyStatementDaoFiltering.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/ObjectPropertyStatementDaoFiltering.java index de7c93438..9c77892e5 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/ObjectPropertyStatementDaoFiltering.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/ObjectPropertyStatementDaoFiltering.java @@ -86,12 +86,13 @@ class ObjectPropertyStatementDaoFiltering extends BaseFiltering implements Objec @Override public List> getObjectPropertyStatementsForIndividualByProperty( - String subjectUri, String propertyUri, String objectKey, String rangeUri, - String query, Set queryStrings, String sortDirection) { + String subjectUri, String propertyUri, String objectKey, String domainUri, + String rangeUri, String query, Set queryStrings, String sortDirection) { List> data = innerObjectPropertyStatementDao.getObjectPropertyStatementsForIndividualByProperty( - subjectUri, propertyUri, objectKey, rangeUri, query, queryStrings,sortDirection); + subjectUri, propertyUri, objectKey, domainUri, rangeUri, query, + queryStrings,sortDirection); /* Filter the data * @@ -107,6 +108,7 @@ class ObjectPropertyStatementDaoFiltering extends BaseFiltering implements Objec ObjectPropertyStatement statement = new ObjectPropertyStatementImpl(subjectUri, propertyUri, objectUri); ObjectProperty op = new ObjectProperty(); op.setURI(propertyUri); + op.setDomainVClassURI(domainUri); op.setRangeVClassURI(rangeUri); statement.setProperty(op); stmtsToData.put(statement, map); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaBaseDao.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaBaseDao.java index 6e8fe09d1..38f6eb578 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaBaseDao.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaBaseDao.java @@ -834,7 +834,11 @@ public class JenaBaseDao extends JenaBaseDaoCon { try { String localName = r.getLocalName(); if (localName != null) { - label = localName; + if(localName.trim().length() > 0) { + label = localName; + } else { + label = r.getURI(); + } } else if (r.isAnon()) { label = r.getId().toString(); } else { @@ -925,8 +929,10 @@ public class JenaBaseDao extends JenaBaseDaoCon { return null; if (vitroURIStr.indexOf(PSEUDO_BNODE_NS)==0) { String idStr = vitroURIStr.split("#")[1]; + log.debug("Trying to get bnode " + idStr); RDFNode rdfNode = ontModel.getRDFNode(Node.createAnon(AnonId.create(idStr))); if ( (rdfNode != null) && (rdfNode.canAs(OntClass.class)) ) { + log.debug("found it"); cls = rdfNode.as(OntClass.class); } } else { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaBaseDaoCon.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaBaseDaoCon.java index c315b4856..f8eb9e0cf 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaBaseDaoCon.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/JenaBaseDaoCon.java @@ -75,6 +75,9 @@ public class JenaBaseDaoCon { protected AnnotationProperty PROPERTY_INPROPERTYGROUPANNOT = _constModel.createAnnotationProperty(VitroVocabulary.PROPERTY_INPROPERTYGROUPANNOT); protected AnnotationProperty PROPERTY_COLLATEBYSUBCLASSANNOT = _constModel.createAnnotationProperty(VitroVocabulary.PROPERTY_COLLATEBYSUBCLASSANNOT); protected AnnotationProperty PROPERTY_STUBOBJECTPROPERTYANNOT = _constModel.createAnnotationProperty(VitroVocabulary.PROPERTY_STUBOBJECTPROPERTYANNOT); + protected AnnotationProperty PROPERTY_EDITLINKSUPPRESSED = _constModel.createAnnotationProperty(VitroVocabulary.PROPERTY_EDITLINKSUPPRESSED); + protected AnnotationProperty PROPERTY_ADDLINKSUPPRESSED = _constModel.createAnnotationProperty(VitroVocabulary.PROPERTY_ADDLINKSUPPRESSED); + protected AnnotationProperty PROPERTY_DELETELINKSUPPRESSED = _constModel.createAnnotationProperty(VitroVocabulary.PROPERTY_DELETELINKSUPPRESSED); protected OntClass PROPERTYGROUP = _constModel.createClass(VitroVocabulary.PROPERTYGROUP); 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 351711cb9..487d2a116 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 @@ -37,6 +37,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.expr.NodeValue; import com.hp.hpl.jena.util.iterator.ClosableIterator; import com.hp.hpl.jena.vocabulary.OWL; import com.hp.hpl.jena.vocabulary.RDF; @@ -224,6 +225,13 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp Boolean collateBySubclass = getPropertyBooleanValue(op,PROPERTY_COLLATEBYSUBCLASSANNOT); p.setCollateBySubclass(collateBySubclass==null ? false : collateBySubclass); + Boolean editLinkSuppressed = getPropertyBooleanValue(op, PROPERTY_EDITLINKSUPPRESSED); + p.setEditLinkSuppressed(editLinkSuppressed == null ? false : editLinkSuppressed); + Boolean addLinkSuppressed = getPropertyBooleanValue(op, PROPERTY_ADDLINKSUPPRESSED); + p.setAddLinkSuppressed(addLinkSuppressed == null ? false : addLinkSuppressed); + Boolean deleteLinkSuppressed = getPropertyBooleanValue(op, PROPERTY_DELETELINKSUPPRESSED); + p.setDeleteLinkSuppressed(deleteLinkSuppressed == null ? false : deleteLinkSuppressed); + Resource groupRes = (Resource) op.getPropertyValue(PROPERTY_INPROPERTYGROUPANNOT); if (groupRes != null) { p.setGroupURI(groupRes.getURI()); @@ -284,21 +292,39 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp } } - public ObjectProperty getObjectPropertyByURIAndRangeURI(String propertyURI, String rangeURI) { + public ObjectProperty getObjectPropertyByURIs(String propertyURI, String domainURI, String rangeURI) { + if(log.isDebugEnabled()) { + log.debug("Getting " + propertyURI + " with domain " + domainURI + " and range " + rangeURI); + } ObjectProperty op = getObjectPropertyByURI(propertyURI); - if (op == null) { + if (op == null || rangeURI == null) { return op; } + op.setDomainVClassURI(domainURI); op.setRangeVClassURI(rangeURI); String propQuery = "PREFIX rdfs: \n" + "PREFIX config: \n" + "PREFIX vitro: \n" + - "SELECT ?range ?label ?group ?customForm ?displayLevel ?updateLevel WHERE { \n" + - " ?context config:configContextFor <" + propertyURI + "> . \n" + - " ?context config:qualifiedBy <" + rangeURI + "> . \n" + - " ?context config:hasConfiguration ?configuration . \n" + + "SELECT ?range ?label ?group ?customForm ?displayRank ?displayLevel " + + " ?updateLevel ?editLinkSuppressed ?addLinkSuppressed ?deleteLinkSuppressed \n" + + " WHERE { \n" + + " ?context config:configContextFor <" + propertyURI + "> . \n"; + if (domainURI != null) { + propQuery += " ?context config:qualifiedByDomain <" + domainURI + "> . \n"; + } else { + propQuery += " FILTER NOT EXISTS { ?context config:qualifiedByDomain ?domainURI } \n"; + } + if (rangeURI != null) { + propQuery += " ?context config:qualifiedBy <" + rangeURI + "> . \n"; + }; + propQuery += " ?context config:hasConfiguration ?configuration . \n" + + " ?configuration a config:ObjectPropertyDisplayConfig . \n" + " OPTIONAL { ?configuration config:propertyGroup ?group } \n" + " OPTIONAL { ?configuration config:displayName ?label } \n" + + " OPTIONAL { ?configuration config:editLinkSuppressed ?editLinkSuppressed } \n" + + " OPTIONAL { ?configuration config:addLinkSuppressed ?addLinkSuppressed } \n" + + " OPTIONAL { ?configuration config:deleteLinkSuppressed ?deleteLinkSuppressed } \n" + + " OPTIONAL { ?configuration vitro:displayRankAnnot ?displayRank } \n" + " OPTIONAL { ?configuration vitro:customEntryFormAnnot ?customForm } \n" + " OPTIONAL { ?configuration vitro:hiddenFromDisplayBelowRoleLevelAnnot ?displayLevel } \n" + " OPTIONAL { ?configuration vitro:prohibitedFromUpdateBelowRoleLevelAnnot ?updateLevel } \n" + @@ -314,6 +340,11 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp if (groupRes != null) { op.setGroupURI(groupRes.getURI()); } + Literal displayRankLit = qsoln.getLiteral("displayRank"); + if(displayRankLit != null) { + op.setDomainDisplayTier( + Integer.parseInt(displayRankLit.getLexicalForm())); + } Resource displayLevelRes = qsoln.getResource("displayLevel"); if (displayLevelRes != null) { op.setHiddenFromDisplayBelowRoleLevel( @@ -334,6 +365,18 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp if (customFormLit != null) { op.setCustomEntryForm(customFormLit.getLexicalForm()); } + Literal editLinkSuppressedLit = qsoln.getLiteral("editLinkSuppressed"); + if (editLinkSuppressedLit != null ) { + op.setEditLinkSuppressed(editLinkSuppressedLit.getBoolean()); + } + Literal addLinkSuppressedLit = qsoln.getLiteral("addLinkSuppressed"); + if (addLinkSuppressedLit != null ) { + op.setAddLinkSuppressed(addLinkSuppressedLit.getBoolean()); + } + Literal deleteLinkSuppressedLit = qsoln.getLiteral("deleteLinkSuppressed"); + if (deleteLinkSuppressedLit != null ) { + op.setDeleteLinkSuppressed(deleteLinkSuppressedLit.getBoolean()); + } } } finally { qe.close(); @@ -902,14 +945,14 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp protected static final String LIST_VIEW_CONFIG_FILE_QUERY_STRING = "PREFIX display: \n" + "PREFIX config: \n" + - "SELECT ?property ?range ?filename WHERE { \n" + + "SELECT ?property ?range ?domain ?filename WHERE { \n" + " { ?property display:listViewConfigFile ?filename \n" + " } UNION { \n" + - " ?lv config:listViewConfigFile ?filename . \n " + - " ?configuration config:hasListView ?lv . " + + " ?configuration config:listViewConfigFile ?filename . \n " + " ?context config:hasConfiguration ?configuration . \n" + " ?context config:configContextFor ?property . \n" + " ?context config:qualifiedBy ?range . \n" + + " OPTIONAL { ?context config:qualifiedByDomain ?domain } \n" + " } \n" + "}"; @@ -925,14 +968,15 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp //TODO private void addPropertyClassCombinationsToListViewMap(HashMap) - // Map key is pair of object property and range class URI - // If range is unspecified, OWL.Thing.getURI() is used in the key. - Map, String> customListViewConfigFileMap = null; + // 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; @Override public String getCustomListViewConfigFileName(ObjectProperty op) { if (customListViewConfigFileMap == null) { - customListViewConfigFileMap = new HashMap, String>(); + customListViewConfigFileMap = new HashMap>, String>(); OntModel displayModel = getOntModelSelector().getDisplayModel(); //Get all property to list view config file mappings in the system QueryExecution qexec = QueryExecutionFactory.create(listViewConfigFileQuery, displayModel); @@ -945,6 +989,10 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp String rangeUri = (rangeNode != null) ? ((Resource) rangeNode).getURI() : OWL.Thing.getURI(); + RDFNode domainNode = soln.get("domain"); + String domainUri = (domainNode != null) + ? ((Resource) domainNode).getURI() + : OWL.Thing.getURI(); ObjectProperty prop = getObjectPropertyByURI(propertyUri); if (prop == null) { //This is a warning only if this property is the one for which we're searching @@ -955,15 +1003,24 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp } } else { String filename = soln.getLiteral("filename").getLexicalForm(); - customListViewConfigFileMap.put(new Pair(prop, rangeUri), filename); + log.debug("putting " + domainUri + " " + prop.getURI() + " " + rangeUri + " " + filename + " into list view map"); + customListViewConfigFileMap.put( + new Pair>( + domainUri, new Pair( + prop, rangeUri)), filename); } } qexec.close(); } - String customListViewConfigFileName = customListViewConfigFileMap.get(new Pair(op, op.getRangeVClassURI())); + String customListViewConfigFileName = customListViewConfigFileMap.get(new Pair>(op.getDomainVClassURI(), new Pair(op, op.getRangeVClassURI()))); if (customListViewConfigFileName == null) { - customListViewConfigFileName = customListViewConfigFileMap.get(new Pair(op, OWL.Thing.getURI())); + log.debug("no list view found for " + op.getURI() + " qualified by range " + op.getRangeVClassURI() + " and domain " + op.getDomainVClassURI()); + customListViewConfigFileName = customListViewConfigFileMap.get(new Pair>(OWL.Thing.getURI(), new Pair(op, op.getRangeVClassURI()))); + } + if (customListViewConfigFileName == null) { + log.debug("no list view found for " + op.getURI() + " qualified by range " + op.getRangeVClassURI()); + customListViewConfigFileName = customListViewConfigFileMap.get(new Pair>(OWL.Thing.getURI(), new Pair(op, OWL.Thing.getURI()))); } return customListViewConfigFileName; 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 0d45ab9c6..45810e361 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 @@ -273,8 +273,7 @@ public class ObjectPropertyStatementDaoJena extends JenaBaseDao implements Objec public List> getObjectPropertyStatementsForIndividualByProperty( String subjectUri, String propertyUri, - String objectKey, - String rangeUri, + String objectKey, String domainUri, String rangeUri, String queryString, Set constructQueryStrings, String sortDirection) { @@ -282,11 +281,13 @@ public class ObjectPropertyStatementDaoJena extends JenaBaseDao implements Objec Model constructedModel = constructModelForSelectQueries( subjectUri, propertyUri, constructQueryStrings); + if(log.isDebugEnabled()) { + log.debug("Constructed model has " + constructedModel.size() + " statements."); + } + if("desc".equalsIgnoreCase( sortDirection ) ){ queryString = queryString.replaceAll(" ASC\\(", " DESC("); } - - log.debug("Query string for object property " + propertyUri + ": " + queryString); Query query = null; try { @@ -300,10 +301,15 @@ public class ObjectPropertyStatementDaoJena extends JenaBaseDao implements Objec QuerySolutionMap initialBindings = new QuerySolutionMap(); initialBindings.add("subject", ResourceFactory.createResource(subjectUri)); initialBindings.add("property", ResourceFactory.createResource(propertyUri)); - if (rangeUri != null) { + if (domainUri != null && !domainUri.startsWith(VitroVocabulary.PSEUDO_BNODE_NS)) { + initialBindings.add("subjectType", ResourceFactory.createResource(domainUri)); + } + if (rangeUri != null && !rangeUri.startsWith(VitroVocabulary.PSEUDO_BNODE_NS)) { initialBindings.add("objectType", ResourceFactory.createResource(rangeUri)); } + 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(); @@ -353,13 +359,13 @@ public class ObjectPropertyStatementDaoJena extends JenaBaseDao implements Objec Model constructedModel = ModelFactory.createDefaultModel(); for (String queryString : constructQueries) { + + queryString = queryString.replace("?subject", "<" + subjectUri + ">"); + queryString = queryString.replace("?property", "<" + propertyUri + ">"); log.debug("CONSTRUCT query string for object property " + propertyUri + ": " + queryString); - queryString = queryString.replace("?subject", "<" + subjectUri + ">"); - queryString = queryString.replace("?property", "<" + propertyUri + ">"); - // 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 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 a457b607c..a7a55f136 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 @@ -16,6 +16,7 @@ import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import com.hp.hpl.jena.ontology.IntersectionClass; import com.hp.hpl.jena.ontology.OntClass; import com.hp.hpl.jena.ontology.OntModel; import com.hp.hpl.jena.ontology.OntProperty; @@ -33,6 +34,7 @@ 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.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; @@ -51,7 +53,8 @@ import edu.cornell.mannlib.vitro.webapp.dao.jena.event.EditEvent; public class PropertyDaoJena extends JenaBaseDao implements PropertyDao { protected static final Log log = LogFactory.getLog(PropertyDaoJena.class.getName()); - + protected static final String FAUX_PROPERTY_FLAG = "FAUX"; + private static final Map NAMESPACES = new HashMap() {{ put("afn", VitroVocabulary.AFN); put("owl", VitroVocabulary.OWL); @@ -328,7 +331,7 @@ public class PropertyDaoJena extends JenaBaseDao implements PropertyDao { public List getClassesWithRestrictionOnProperty(String propertyURI) { if (propertyURI == null) { - log.info("getClassesWithRestrictionOnProperty: called with null propertyURI"); + log.warn("getClassesWithRestrictionOnProperty: called with null propertyURI"); return null; } @@ -348,7 +351,7 @@ public class PropertyDaoJena extends JenaBaseDao implements PropertyDao { Statement statement = stmtIter.next(); if ( statement.getSubject().canAs(OntClass.class) ) { - classURISet.addAll(getRelatedClasses(statement.getSubject().as(OntClass.class))); + classURISet.addAll(getRestrictedClasses(statement.getSubject().as(OntClass.class))); } else { log.warn("getClassesWithRestrictionOnProperty: Unexpected use of onProperty: it is not applied to a class"); } @@ -381,9 +384,7 @@ public class PropertyDaoJena extends JenaBaseDao implements PropertyDao { } /** - * Finds all named superclasses, subclasses and equivalent classes of - * the given class. - * + * Find named classes to which a restriction "applies" * @param resourceURI identifier of a class * @return set of class URIs * @@ -391,13 +392,12 @@ public class PropertyDaoJena extends JenaBaseDao implements PropertyDao { * the ontology model. */ - public HashSet getRelatedClasses(OntClass ontClass) { + public HashSet getRestrictedClasses(OntClass ontClass) { HashSet classSet = new HashSet(); List classList = ontClass.listEquivalentClasses().toList(); classList.addAll(ontClass.listSubClasses().toList()); - classList.addAll(ontClass.listSuperClasses().toList()); Iterator it = classList.iterator(); @@ -406,6 +406,8 @@ public class PropertyDaoJena extends JenaBaseDao implements PropertyDao { if (!oc.isAnon()) { classSet.add(oc.getURI()); + } else { + classSet.addAll(getRestrictedClasses(oc)); } } @@ -524,15 +526,8 @@ public class PropertyDaoJena extends JenaBaseDao implements PropertyDao { } } - List piList = getAllPropInstByVClasses(vclasses); + return getAllPropInstByVClasses(vclasses); - for (PropertyInstance pi : piList) { - pi.setDomainClassURI(ind.getVClassURI()); - // TODO: improve. This is so the DWR property editing passes the - // individual's VClass to get the right restrictions - } - - return piList; } /* @@ -621,6 +616,42 @@ public class PropertyDaoJena extends JenaBaseDao implements PropertyDao { return classes; } + private static final int DEPTH_LIMIT = 20; + + private List getRelatedRestrictions(OntClass ontClass) { + return getRelatedRestrictions(ontClass, new ArrayList(), DEPTH_LIMIT); + } + + private List getRelatedRestrictions(OntClass ontClass, + List relatedRestrictions, int limit) { + limit--; + if (ontClass.isRestriction()) { + relatedRestrictions.add(ontClass.as(Restriction.class)); + } else if (ontClass.isIntersectionClass()) { + IntersectionClass inter = ontClass.as(IntersectionClass.class); + Iterator operIt = inter.listOperands(); + while (operIt.hasNext()) { + OntClass operand = operIt.next(); + if (!relatedRestrictions.contains(operand) && limit > 0) { + relatedRestrictions.addAll( + getRelatedRestrictions( + operand, relatedRestrictions, limit)); + } + } + } else { + List superClasses = listSuperClasses(ontClass); + superClasses.addAll(listEquivalentClasses(ontClass)); + for (OntClass sup : superClasses) { + if (sup.isAnon() && !sup.equals(ontClass) + && !relatedRestrictions.contains(ontClass) && limit > 0) { + relatedRestrictions.addAll( + getRelatedRestrictions(sup, relatedRestrictions, limit)); + } + } + } + return relatedRestrictions; + } + public List getAllPropInstByVClasses(List vclasses) { List propInsts = new ArrayList(); @@ -651,55 +682,52 @@ public class PropertyDaoJena extends JenaBaseDao implements PropertyDao { String VClassURI = vclass.getURI(); OntClass ontClass = getOntClass(ontModel,VClassURI); - if (ontClass != null) { - List relatedClasses = new ArrayList(); - relatedClasses.addAll(listEquivalentClasses(ontClass)); - relatedClasses.addAll(listSuperClasses(ontClass)); - for (OntClass relatedClass : relatedClasses) { - // find properties in restrictions - if (relatedClass.isRestriction() && relatedClass.canAs(Restriction.class)) { - // TODO: check if restriction is something like - // maxCardinality 0 or allValuesFrom owl:Nothing, - // in which case the property is NOT applicable! - Restriction rest = relatedClass.as(Restriction.class); - OntProperty onProperty = rest.getOnProperty(); - if (onProperty != null) { - Resource[] ranges = new Resource[2]; - if (rest.isAllValuesFromRestriction()) { - ranges[0] = (rest.asAllValuesFromRestriction()).getAllValuesFrom(); - } else if (rest.isSomeValuesFromRestriction()) { - ranges[1] = (rest.asSomeValuesFromRestriction()).getSomeValuesFrom(); - } - updatePropertyRangeMap(applicableProperties, onProperty.getURI(), ranges); - } - } - } - - List propertyList = - getPropertiesWithAppropriateDomainFor(VClassURI); - for (Resource prop : propertyList) { - if (prop.getNameSpace() != null - && !NONUSER_NAMESPACES.contains( - prop.getNameSpace()) ) { - StmtIterator rangeSit = prop.listProperties( - RDFS.range); - Resource rangeRes = null; - while (rangeSit.hasNext()) { - Statement s = rangeSit.nextStatement(); - if (s.getObject().isURIResource()) { - rangeRes = (Resource) s.getObject(); - } - } - Resource[] ranges = new Resource[2]; - ranges[0] = rangeRes; - updatePropertyRangeMap( - applicableProperties, prop.getURI(), ranges); - - } - } - + if (ontClass == null) { + continue; } - } + List relatedRestrictions = getRelatedRestrictions(ontClass); + for (Restriction rest : relatedRestrictions) { + // find properties in restrictions + // TODO: check if restriction is something like + // maxCardinality 0 or allValuesFrom owl:Nothing, + // in which case the property is NOT applicable! + OntProperty onProperty = rest.getOnProperty(); + if (onProperty != null) { + Resource[] ranges = new Resource[2]; + if (rest.isAllValuesFromRestriction()) { + ranges[0] = (rest.asAllValuesFromRestriction()).getAllValuesFrom(); + } else if (rest.isSomeValuesFromRestriction()) { + ranges[1] = (rest.asSomeValuesFromRestriction()).getSomeValuesFrom(); + } + updatePropertyRangeMap(applicableProperties, onProperty.getURI(), ranges); + } + } + + List propertyList = + getPropertiesWithAppropriateDomainFor(VClassURI); + for (Resource prop : propertyList) { + if (prop.getNameSpace() != null + && !NONUSER_NAMESPACES.contains( + prop.getNameSpace()) ) { + StmtIterator rangeSit = prop.listProperties( + RDFS.range); + Resource rangeRes = null; + while (rangeSit.hasNext()) { + Statement s = rangeSit.nextStatement(); + if (s.getObject().isURIResource()) { + rangeRes = (Resource) s.getObject(); + } + } + Resource[] ranges = new Resource[2]; + ranges[0] = rangeRes; + updatePropertyRangeMap( + applicableProperties, prop.getURI(), ranges); + + } + } + + } + } catch (Exception e) { log.error("Unable to get applicable properties " + "by examining property restrictions and domains", e); @@ -718,12 +746,36 @@ public class PropertyDaoJena extends JenaBaseDao implements PropertyDao { : (op.getRange() == null && foundRanges[1] != null) ? foundRanges[1] : op.getRange(); - propInsts.add(getPropInstForPropertyAndRange(op, rangeRes, applicableProperties)); - List additionalFauxSubpropertyRangeURIs = getAdditionalFauxSubpropertyRangeURIsForPropertyURI(propertyURI); - for (String rangeURI : additionalFauxSubpropertyRangeURIs) { - if (getWebappDaoFactory().getVClassDao().isSubClassOf(rangeURI, rangeRes.getURI())) { - propInsts.add(getPropInstForPropertyAndRange( - op, ResourceFactory.createResource(rangeURI), applicableProperties)); + Resource domainRes = op.getDomain(); + propInsts.add(getPropInst( + op, domainRes, rangeRes, applicableProperties)); + List> additionalFauxSubpropertyDomainAndRangeURIs = + getAdditionalFauxSubpropertyDomainAndRangeURIsForPropertyURI( + propertyURI); + for (Pair domainAndRangeURIs : + additionalFauxSubpropertyDomainAndRangeURIs) { + boolean applicablePropInst = false; + if (rangeRes == null || + !getWebappDaoFactory().getVClassDao().isSubClassOf( + rangeRes.getURI(), domainAndRangeURIs.getRight())) { + if (domainAndRangeURIs.getLeft() == null) { + applicablePropInst = true; + } else { + for(VClass vclass : vclasses) { + if (vclass.getURI() != null && vclass.getURI().equals( + domainAndRangeURIs.getLeft())) { + applicablePropInst = true; + break; + } + } + } + if (applicablePropInst) { + propInsts.add(getPropInst( + op, + ResourceFactory.createResource(domainAndRangeURIs.getLeft()), + ResourceFactory.createResource(domainAndRangeURIs.getRight()), + applicableProperties)); + } } } } @@ -736,11 +788,19 @@ public class PropertyDaoJena extends JenaBaseDao implements PropertyDao { } - private PropertyInstance getPropInstForPropertyAndRange(OntProperty op, Resource rangeRes, - Map applicableProperties) { + private PropertyInstance getPropInst(OntProperty op, Resource domainRes, Resource rangeRes, + Map applicableProperties) { + if (log.isDebugEnabled() && domainRes != null && rangeRes != null) { + log.debug("getPropInst() op: " + op.getURI() + " domain: " + + domainRes.getURI() + " range: " + rangeRes.getURI()); + } PropertyInstance pi = new PropertyInstance(); - String domainURIStr = getURIStr(op.getDomain()); - if (rangeRes != null) { + String domainURIStr = (domainRes != null && !domainRes.isAnon()) ? + domainURIStr = domainRes.getURI() + : null; + if (rangeRes == null) { + pi.setRangeClassURI(OWL.Thing.getURI()); // TODO see above + } else { String rangeClassURI; if (rangeRes.isAnon()) { rangeClassURI = PSEUDO_BNODE_NS + rangeRes.getId() @@ -757,18 +817,18 @@ public class PropertyDaoJena extends JenaBaseDao implements PropertyDao { range.setName(range.getLocalName()); } pi.setRangeClassName(range.getName()); - } else { - pi.setRangeClassURI(OWL.Thing.getURI()); // TODO see above } pi.setDomainClassURI(domainURIStr); - VClass domain = getWebappDaoFactory().getVClassDao() - .getVClassByURI(domainURIStr); - if (domain == null) { - domain = new VClass(); - domain.setURI(domainURIStr); - domain.setName(domain.getLocalName()); + if (domainURIStr != null) { + VClass domain = getWebappDaoFactory().getVClassDao() + .getVClassByURI(domainURIStr); + if (domain == null) { + domain = new VClass(); + domain.setURI(domainURIStr); + domain.setName(domain.getLocalName()); + } + pi.setDomainClassName(domain.getName()); } - pi.setDomainClassName(domain.getName()); pi.setSubjectSide(true); pi.setPropertyURI(op.getURI()); pi.setPropertyName(getLabelOrId(op)); // TODO @@ -777,14 +837,15 @@ public class PropertyDaoJena extends JenaBaseDao implements PropertyDao { return pi; } - private List getAdditionalFauxSubpropertyRangeURIsForPropertyURI(String propertyURI) { - List rangeURIs = new ArrayList(); + private List> getAdditionalFauxSubpropertyDomainAndRangeURIsForPropertyURI(String propertyURI) { + List> domainAndRangeURIs = new ArrayList>(); String propQuery = "PREFIX rdfs: \n" + "PREFIX config: \n" + "PREFIX vitro: \n" + - "SELECT ?range WHERE { \n" + + "SELECT ?domain ?range WHERE { \n" + " ?context config:configContextFor <" + propertyURI + "> . \n" + " ?context config:qualifiedBy ?range . \n" + + " OPTIONAL { ?context config:qualifiedByDomain ?domain } \n" + "}"; Query q = QueryFactory.create(propQuery); @@ -794,12 +855,18 @@ public class PropertyDaoJena extends JenaBaseDao implements PropertyDao { while (rs.hasNext()) { QuerySolution qsoln = rs.nextSolution(); Resource rangeRes = qsoln.getResource("range"); - rangeURIs.add(rangeRes.getURI()); + String rangeURI = rangeRes.getURI(); + Resource domainRes = qsoln.getResource("domain"); + String domainURI = null; + if (domainRes != null && !domainRes.isAnon()) { + domainURI = domainRes.getURI(); + } + domainAndRangeURIs.add(new Pair(domainURI, rangeURI)); } } finally { qe.close(); } - return rangeURIs; + return domainAndRangeURIs; } private String getURIStr(Resource res) { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassDaoJena.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassDaoJena.java index 8c4a20e77..1d168eb63 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassDaoJena.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassDaoJena.java @@ -462,9 +462,11 @@ public class VClassDaoJena extends JenaBaseDao implements VClassDao { while (classIt.hasNext()) { try { Individual classInd = classIt.next(); - OntClass cls = classInd.as(OntClass.class); - if (!cls.isAnon() && !(NONUSER_NAMESPACES.contains(cls.getNameSpace()))) { - classes.add(new VClassJena(cls,getWebappDaoFactory())); + if(classInd.canAs(OntClass.class)) { + OntClass cls = classInd.as(OntClass.class); + if (!cls.isAnon() && !(NONUSER_NAMESPACES.contains(cls.getNameSpace()))) { + classes.add(new VClassJena(cls,getWebappDaoFactory())); + } } } catch (ClassCastException cce) { log.error(cce, cce); @@ -1091,11 +1093,8 @@ public class VClassDaoJena extends JenaBaseDao implements VClassDao { OntModel ontModel = getOntModel(); try { ontModel.enterCriticalSection(Lock.READ); - OntClass oc1 = getOntClass(ontModel, vclassURI1); - OntClass oc2 = getOntClass(ontModel, vclassURI2); - if (oc1 == null || oc2 == null) { - return false; - } + Resource oc1 = ontModel.getResource(vclassURI1); + Resource oc2 = ontModel.getResource(vclassURI2); return ontModel.contains(oc1, RDFS.subClassOf, oc2); } finally { ontModel.leaveCriticalSection(); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassJena.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassJena.java index c4db19dd2..436ae8bd9 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassJena.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/VClassJena.java @@ -2,10 +2,15 @@ package edu.cornell.mannlib.vitro.webapp.dao.jena; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.hp.hpl.jena.ontology.OntClass; +import com.hp.hpl.jena.ontology.UnionClass; import com.hp.hpl.jena.rdf.model.RDFNode; import com.hp.hpl.jena.rdf.model.Resource; import com.hp.hpl.jena.rdf.model.Statement; @@ -376,4 +381,27 @@ public class VClassJena extends VClass { } } } + + @Override + public boolean isUnion() { + return this.cls.isUnionClass(); + } + + //TODO consider anonymous components + @Override + public List getUnionComponents() { + List unionComponents = new ArrayList(); + if (isUnion()) { + UnionClass union = this.cls.as(UnionClass.class); + Iterator opIt = union.listOperands(); + while(opIt.hasNext()) { + OntClass component = opIt.next(); + if (!component.isAnon()) { + unionComponents.add(new VClassJena(component, this.webappDaoFactory)); + } + } + } + return unionComponents; + } + } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/PelletListener.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/PelletListener.java index 58be08c6d..47634ddba 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/PelletListener.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/PelletListener.java @@ -624,8 +624,10 @@ public class PelletListener implements ModelChangedListener { if ( (additionModel.size() > 0) || (removalModel.size()>0) ) { if (!isSynchronizing) { if (foreground) { + log.debug("Running Pellet in foreground."); (new PelletSynchronizer()).run(); } else { + log.debug("Running Pellet in background."); new Thread(new PelletSynchronizer(), "PelletListener.PelletSynchronizer").start(); } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/ReasonerConfiguration.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/ReasonerConfiguration.java index 5b833a1a4..970c14e4d 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/ReasonerConfiguration.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/pellet/ReasonerConfiguration.java @@ -30,8 +30,7 @@ public class ReasonerConfiguration { /** * The default reasoner configuration is designed to provide acceptable performance on larger knowledge bases. * It will classify and realize, and add inferred disjointWith statements. - * It ignores domain and range "axioms," on the assumption that they are not truly axioms but editing constraints. - * It also ignores "owl:inverseOf." + * It ignores domain and range "axioms," on the assumption that they are not truly axioms but editing constraints. */ public static ReasonerConfiguration DEFAULT; @@ -78,6 +77,7 @@ public class ReasonerConfiguration { defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,RDF.first,null)); defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,RDF.rest,null)); defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,OWL.disjointWith,null)); + defaultInferenceDrivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,OWL.inverseOf,null)); DEFAULT.setInferenceDrivingPatternAllowSet(defaultInferenceDrivingPatternAllowSet); Set defaultInferenceReceivingPatternAllowSet = new HashSet(); defaultInferenceReceivingPatternAllowSet.add(ObjectPropertyStatementPatternFactory.getPattern(null,RDF.type,null)); 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 a214814f7..3ecb8c289 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 @@ -53,12 +53,22 @@ public class EditConfigurationUtils { return vreq.getParameter("objectUri"); } + public static String getDomainUri(VitroRequest vreq) { + return vreq.getParameter("domainUri"); + } + public static String getRangeUri(VitroRequest vreq) { return vreq.getParameter("rangeUri"); } public static VClass getRangeVClass(VitroRequest vreq) { - return vreq.getWebappDaoFactory().getVClassDao().getVClassByURI(getRangeUri(vreq)); + // This needs a WebappDaoFactory with no filtering/RDFService + // funny business because it needs to be able to retrieve anonymous union + // classes by their "pseudo-bnode URIs". + // Someday we'll need to figure out a different way of doing this. + WebappDaoFactory ctxDaoFact = ModelAccess.on( + vreq.getSession().getServletContext()).getWebappDaoFactory(); + return ctxDaoFact.getVClassDao().getVClassByURI(getRangeUri(vreq)); } //get individual 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 39095ba3f..fdc1f008a 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 @@ -27,13 +27,13 @@ public class IndividualsViaObjectPropetyOptions implements FieldOptions { private static final String LEFT_BLANK = ""; private String subjectUri; private String predicateUri; - private String rangeUri; + private List rangeTypes; private String objectUri; private String defaultOptionLabel; public IndividualsViaObjectPropetyOptions(String subjectUri, - String predicateUri, String rangeUri, String objectUri) throws Exception { + String predicateUri, List rangeTypes, String objectUri) throws Exception { super(); if (subjectUri == null || subjectUri.equals("")) { @@ -45,7 +45,7 @@ public class IndividualsViaObjectPropetyOptions implements FieldOptions { this.subjectUri = subjectUri; this.predicateUri = predicateUri; - this.rangeUri = rangeUri; + this.rangeTypes = rangeTypes; this.objectUri = objectUri; } @@ -78,8 +78,8 @@ public class IndividualsViaObjectPropetyOptions implements FieldOptions { //get all vclasses applicable to the individual subject HashSet vclassesURIs = getApplicableVClassURIs(subject, wDaoFact); - if (rangeUri != null) { - vclassesURIs = filterToSubclassesOfRange(vclassesURIs, rangeUri, wDaoFact); + if (!rangeTypes.isEmpty()) { + vclassesURIs = filterToSubclassesOfRange(vclassesURIs, rangeTypes, wDaoFact); } if (vclassesURIs.size() == 0) { @@ -117,9 +117,13 @@ public class IndividualsViaObjectPropetyOptions implements FieldOptions { private HashSet getApplicableVClassURIs(Individual subject, WebappDaoFactory wDaoFact) { HashSet vclassesURIs = new HashSet(); - if (rangeUri != null) { - log.debug("individualsViaObjectProperty using rangeUri " + rangeUri); - vclassesURIs.add(rangeUri); + if (!rangeTypes.isEmpty()) { + StringBuffer rangeBuff = new StringBuffer(); + for (VClass rangeType : rangeTypes) { + vclassesURIs.add(rangeType.getURI()); + rangeBuff.append(rangeType.getURI()).append(", "); + } + log.debug("individualsViaObjectProperty using rangeUri " + rangeBuff.toString()); return vclassesURIs; } @@ -144,13 +148,15 @@ public class IndividualsViaObjectPropetyOptions implements FieldOptions { } private HashSet filterToSubclassesOfRange(HashSet vclassesURIs, - String rangeUri, + List rangeTypes, WebappDaoFactory wDaoFact) { HashSet filteredVClassesURIs = new HashSet(); VClassDao vcDao = wDaoFact.getVClassDao(); for (String vclass : vclassesURIs) { - if (vclass.equals(rangeUri) || vcDao.isSubClassOf(vclass, rangeUri)) { - filteredVClassesURIs.add(vclass); + for (VClass rangeType : rangeTypes) { + if (vclass.equals(rangeType.getURI()) || vcDao.isSubClassOf(vclass, rangeType.getURI())) { + filteredVClassesURIs.add(vclass); + } } } return filteredVClassesURIs; 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 8ffa4e04c..69ae7f40a 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 @@ -99,41 +99,60 @@ public class DefaultObjectPropertyFormGenerator implements EditConfigurationGene return getDefaultObjectEditConfiguration(vreq, session); } - protected List getRangeTypes(VitroRequest vreq) { - WebappDaoFactory wDaoFact = vreq.getWebappDaoFactory(); - List types = new ArrayList(); + protected List getRangeTypes(VitroRequest vreq) { + // This first part needs a WebappDaoFactory with no filtering/RDFService + // funny business because it needs to be able to retrieve anonymous union + // classes by their "pseudo-bnode URIs". + // Someday we'll need to figure out a different way of doing this. + WebappDaoFactory ctxDaoFact = ModelAccess.on( + vreq.getSession().getServletContext()).getWebappDaoFactory(); + List types = new ArrayList(); Individual subject = EditConfigurationUtils.getSubjectIndividual(vreq); String predicateUri = EditConfigurationUtils.getPredicateUri(vreq); String rangeUri = EditConfigurationUtils.getRangeUri(vreq); if (rangeUri != null) { - types.add(rangeUri); + VClass rangeVClass = ctxDaoFact.getVClassDao().getVClassByURI(rangeUri); + if (!rangeVClass.isUnion()) { + types.add(rangeVClass); + } else { + for (VClass unionComponent : rangeVClass.getUnionComponents()) { + types.add(unionComponent); + } + } return types; } + WebappDaoFactory wDaoFact = vreq.getWebappDaoFactory(); //Get all vclasses applicable to subject List vClasses = subject.getVClasses(); - HashSet typesHash = new HashSet(); + HashMap typesHash = new HashMap(); for(VClass vclass: vClasses) { List rangeVclasses = wDaoFact.getVClassDao().getVClassesForProperty(vclass.getURI(),predicateUri); if(rangeVclasses != null) { for(VClass range: rangeVclasses) { //a hash will keep a unique list of types and so prevent duplicates - typesHash.add(range.getURI()); + typesHash.put(range.getURI(), range); } } } - types.addAll(typesHash); + types.addAll(typesHash.values()); return types; } private boolean tooManyRangeOptions(VitroRequest vreq, HttpSession session ) throws SolrServerException { - List types = getRangeTypes(vreq); + List rangeTypes = getRangeTypes(vreq); SolrServer solrServer = SolrSetup.getSolrServer(session.getServletContext()); + List types = new ArrayList(); //empty list means the range is not set to anything, force Thing - if(types.size() == 0 ){ - types = new ArrayList(); - types.add(VitroVocabulary.OWL_THING); - } + if(types.size() == 0 ){ + types.add(VitroVocabulary.OWL_THING); + } else { + for (VClass vclass : rangeTypes) { + if (vclass.getURI() != null) { + types.add(vclass.getURI()); + } + } + } long count = 0; for( String type:types){ @@ -184,7 +203,7 @@ public class DefaultObjectPropertyFormGenerator implements EditConfigurationGene this.setSparqlQueries(editConfiguration); //set fields - setFields(editConfiguration, vreq, EditConfigurationUtils.getPredicateUri(vreq), EditConfigurationUtils.getRangeUri(vreq)); + setFields(editConfiguration, vreq, EditConfigurationUtils.getPredicateUri(vreq), getRangeTypes(vreq)); // No need to put in session here b/c put in session within edit request dispatch controller instead //placing in session depends on having edit key which is handled in edit request dispatch controller @@ -358,7 +377,7 @@ public class DefaultObjectPropertyFormGenerator implements EditConfigurationGene setFields(editConfiguration, vreq, predicateUri, null); } - protected void setFields(EditConfigurationVTwo editConfiguration, VitroRequest vreq, String predicateUri, String rangeUri) throws Exception { + protected void setFields(EditConfigurationVTwo editConfiguration, VitroRequest vreq, String predicateUri, List rangeTypes) throws Exception { FieldVTwo field = new FieldVTwo(); field.setName("objectVar"); @@ -370,7 +389,7 @@ public class DefaultObjectPropertyFormGenerator implements EditConfigurationGene field.setOptions( new IndividualsViaObjectPropetyOptions( subjectUri, predicateUri, - rangeUri, + rangeTypes, objectUri)); }else{ field.setOptions(null); @@ -441,14 +460,22 @@ public class DefaultObjectPropertyFormGenerator implements EditConfigurationGene formSpecificData.put("editMode", getEditMode(vreq).toString().toLowerCase()); //We also need the type of the object itself - List types = getRangeTypes(vreq); + List types = getRangeTypes(vreq); //if types array contains only owl:Thing, the search will not return any results //In this case, set an empty array - if(types.size() == 1 && types.get(0).equals(VitroVocabulary.OWL_THING) ){ - types = new ArrayList(); + if(types.size() == 1 && types.get(0).getURI().equals(VitroVocabulary.OWL_THING) ){ + types = new ArrayList(); } - formSpecificData.put("objectTypes", StringUtils.join(types, ",")); + StringBuffer typesBuff = new StringBuffer(); + for (VClass type : types) { + if (type.getURI() != null) { + typesBuff.append(type.getURI()).append(","); + } + } + + formSpecificData.put("objectTypes", typesBuff.toString()); + log.debug("autocomplete object types : " + formSpecificData.get("objectTypes")); //Get label for individual if it exists if(EditConfigurationUtils.getObjectIndividual(vreq) != null) { @@ -464,15 +491,15 @@ public class DefaultObjectPropertyFormGenerator implements EditConfigurationGene editConfiguration.setFormSpecificData(formSpecificData); } - private Object rangeIndividualsExist(HttpSession session, List types) throws SolrServerException { + private Object rangeIndividualsExist(HttpSession session, List types) throws SolrServerException { SolrServer solrServer = SolrSetup.getSolrServer(session.getServletContext()); boolean rangeIndividualsFound = false; - for( String type:types){ + for( VClass type:types){ //solr for type count. SolrQuery query = new SolrQuery(); - query.setQuery( VitroSearchTermNames.RDFTYPE + ":" + type); + query.setQuery( VitroSearchTermNames.RDFTYPE + ":" + type.getURI()); query.setRows(0); QueryResponse rsp = solrServer.query(query); 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 2645e638b..855a2d8ed 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 @@ -28,8 +28,10 @@ import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestActio 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; @@ -272,7 +274,7 @@ public class ManageLabelsForIndividualGenerator extends BaseEditConfigurationGen RequestActionConstants.SOME_URI); AddObjectPropertyStatement aops = new AddObjectPropertyStatement( vreq.getJenaOntModel(), individual.getURI(), - RequestActionConstants.SOME_URI, + RequestActionConstants.SOME_PREDICATE, RequestActionConstants.SOME_URI); return PolicyHelper.isAuthorizedForActions(vreq, new Actions(adps).or(aops)); } @@ -317,8 +319,8 @@ public class ManageLabelsForIndividualGenerator extends BaseEditConfigurationGen //This should put the label in the list //Create label information instance with the required information //To generate link - DataPropertyStatementTemplateModel dpstm = new DataPropertyStatementTemplateModel(subjectUri, propertyUri, l, - template, vreq); + DataPropertyStatementTemplateModel dpstm = new DataPropertyStatementTemplateModel( + subjectUri, new Property(propertyUri), l, template, vreq); labelsList.add(new LabelInformation( l, dpstm.getEditUrl(), dpstm.getDeleteUrl(), languageTag, languageName)); } 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 fba13b869..692f9212d 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 @@ -171,6 +171,9 @@ public class EditRequestDispatchController extends FreemarkerHttpServlet { makeEditConfigurationVTwo( editConfGeneratorName, vreq, session); } + if(editConfig == null) { + log.error("editConfig is null! How did this happen?"); + } String editKey = EditConfigurationUtils.getEditKey(vreq); editConfig.setEditKey(editKey); @@ -199,6 +202,7 @@ public class EditRequestDispatchController extends FreemarkerHttpServlet { String editConfGeneratorName = null; String predicateUri = getPredicateUri(vreq); + String domainUri = EditConfigurationUtils.getDomainUri(vreq); String rangeUri = EditConfigurationUtils.getRangeUri(vreq); // *** handle the case where the form is specified as a request parameter *** @@ -215,9 +219,9 @@ public class EditRequestDispatchController extends FreemarkerHttpServlet { // *** check for a predicate URI in the request }else if( predicateUri != null && !predicateUri.isEmpty() ){ - Property prop = getProperty( predicateUri, vreq); + Property prop = getProperty( predicateUri, domainUri, rangeUri, vreq); if (prop != null && rangeUri != null) { - editConfGeneratorName = getCustomEntryFormForPropertyAndRange(prop, rangeUri); + editConfGeneratorName = getCustomEntryForm(prop); } else if( prop != null && prop.getCustomEntryForm() != null ){ //there is a custom form, great! let's use it. editConfGeneratorName = prop.getCustomEntryForm(); @@ -247,25 +251,19 @@ public class EditRequestDispatchController extends FreemarkerHttpServlet { return editConfGeneratorName; } - private String getCustomEntryFormForPropertyAndRange(Property prop, String rangeUri){ - String entryFormName = null; - // = ApplicationConfigurationOntologyUtils.getEntryForm(prop.getURI(), rangeUri); - if (entryFormName == null) { - if (prop.getCustomEntryForm() != null) { - return prop.getCustomEntryForm(); - } else { - return DEFAULT_OBJ_FORM; - } + private String getCustomEntryForm(Property prop){ + if (prop.getCustomEntryForm() == null) { + return DEFAULT_OBJ_FORM; } else { - prop.setCustomEntryForm(entryFormName); - return entryFormName; + return prop.getCustomEntryForm(); } } - private Property getProperty(String predicateUri, VitroRequest vreq) { + private Property getProperty(String predicateUri, String domainUri, String rangeUri, VitroRequest vreq) { Property p = null; try{ - p = vreq.getWebappDaoFactory().getObjectPropertyDao().getObjectPropertyByURI(predicateUri); + p = vreq.getWebappDaoFactory().getObjectPropertyDao().getObjectPropertyByURIs( + predicateUri, domainUri, rangeUri); if(p == null) { p = vreq.getWebappDaoFactory().getDataPropertyDao().getDataPropertyByURI(predicateUri); } 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 29ab6a58a..74de6f79e 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 @@ -4,14 +4,17 @@ package edu.cornell.mannlib.vitro.webapp.ontology.update; import java.io.IOException; import java.util.ArrayList; -import java.util.HashSet; import java.util.Iterator; import java.util.List; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + import com.hp.hpl.jena.ontology.OntClass; 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.query.Dataset; import com.hp.hpl.jena.rdf.model.Literal; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.ModelFactory; @@ -24,9 +27,10 @@ import com.hp.hpl.jena.rdf.model.StmtIterator; import com.hp.hpl.jena.shared.Lock; import com.hp.hpl.jena.vocabulary.OWL; import com.hp.hpl.jena.vocabulary.RDF; -import com.hp.hpl.jena.vocabulary.RDFS; +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; /** * Performs knowledge base updates to the abox to align with a new ontology version @@ -34,10 +38,13 @@ import edu.cornell.mannlib.vitro.webapp.ontology.update.AtomicOntologyChange.Ato */ public class ABoxUpdater { + private final Log log = LogFactory.getLog(ABoxUpdater.class); private OntModel oldTboxModel; private OntModel newTboxModel; - private OntModel aboxModel; + private Dataset dataset; + private RDFService rdfService; private OntModel newTBoxAnnotationsModel; + private TBoxUpdater tboxUpdater; private ChangeLogger logger; private ChangeRecord record; private OntClass OWL_THING = (ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM)).createClass(OWL.Thing.getURI()); @@ -55,19 +62,19 @@ public class ABoxUpdater { * and the retractions model. * */ - public ABoxUpdater(OntModel oldTboxModel, - OntModel newTboxModel, - OntModel aboxModel, - OntModel newAnnotationsModel, + public ABoxUpdater(UpdateSettings settings, ChangeLogger logger, ChangeRecord record) { - this.oldTboxModel = oldTboxModel; - this.newTboxModel = newTboxModel; - this.aboxModel = aboxModel; - this.newTBoxAnnotationsModel = newAnnotationsModel; + this.oldTboxModel = settings.getOldTBoxModel(); + this.newTboxModel = settings.getNewTBoxModel(); + RDFService rdfService = settings.getRDFService(); + this.dataset = new RDFServiceDataset(rdfService); + this.rdfService = rdfService; + this.newTBoxAnnotationsModel = settings.getNewTBoxAnnotationsModel(); this.logger = logger; this.record = record; + this.tboxUpdater = new TBoxUpdater(settings, logger, record); } /** @@ -124,68 +131,75 @@ public class ABoxUpdater { public void renameClass(AtomicOntologyChange change) throws IOException { //logger.log("Processing a class rename from: " + change.getSourceURI() + " to " + change.getDestinationURI()); - aboxModel.enterCriticalSection(Lock.WRITE); - - try { - - Model additions = ModelFactory.createDefaultModel(); - Model retractions = ModelFactory.createDefaultModel(); - - //TODO - look for these in the models and log error if not found - Resource oldClass = ResourceFactory.createResource(change.getSourceURI()); - Resource newClass = ResourceFactory.createResource(change.getDestinationURI()); - - // Change class references in the subjects of statements - - // BJL 2010-04-09 : In future versions we need to keep track of - // the difference between true direct renamings and "use-insteads." - // For now, the best behavior is to remove any remaining statements - // where the old class is the subject, *unless* the statements - // is part of the new annotations file (see comment below) or the - // predicate is vitro:autolinkedToTab. In the latter case, - // the autolinking annotation should be rewritten using the - // new class name. - - StmtIterator iter = aboxModel.listStatements(oldClass, (Property) null, (RDFNode) null); - - int removeCount = 0; - while (iter.hasNext()) { - Statement oldStatement = iter.next(); - removeCount++; - retractions.add(oldStatement); - } - - //log summary of changes - if (removeCount > 0) { - logger.log("Removed " + removeCount + " subject reference" + ((removeCount > 1) ? "s" : "") + " to the " + oldClass.getURI() + " class"); - } - - // Change class references in the objects of rdf:type statements - iter = aboxModel.listStatements((Resource) null, RDF.type, oldClass); - - int renameCount = 0; - while (iter.hasNext()) { - renameCount++; - Statement oldStatement = iter.next(); - Statement newStatement = ResourceFactory.createStatement(oldStatement.getSubject(), RDF.type, newClass); - retractions.add(oldStatement); - additions.add(newStatement); - } - - //log summary of changes - if (renameCount > 0) { - logger.log("Retyped " + renameCount + " individual" + ((renameCount > 1) ? "s" : "") + " from type " + oldClass.getURI() + " to type " + newClass.getURI()); - } - - aboxModel.remove(retractions); - record.recordRetractions(retractions); - aboxModel.add(additions); - record.recordAdditions(additions); - - } finally { - aboxModel.leaveCriticalSection(); - } - + + Iterator graphIt = dataset.listNames(); + while(graphIt.hasNext()) { + String graph = graphIt.next(); + if(!KnowledgeBaseUpdater.isUpdatableABoxGraph(graph)){ + continue; + } + Model aboxModel = dataset.getNamedModel(graph); + aboxModel.enterCriticalSection(Lock.WRITE); + try { + + Model additions = ModelFactory.createDefaultModel(); + Model retractions = ModelFactory.createDefaultModel(); + + //TODO - look for these in the models and log error if not found + Resource oldClass = ResourceFactory.createResource(change.getSourceURI()); + Resource newClass = ResourceFactory.createResource(change.getDestinationURI()); + + // Change class references in the subjects of statements + + // BJL 2010-04-09 : In future versions we need to keep track of + // the difference between true direct renamings and "use-insteads." + // For now, the best behavior is to remove any remaining statements + // where the old class is the subject, *unless* the statements + // is part of the new annotations file (see comment below) or the + // predicate is vitro:autolinkedToTab. In the latter case, + // the autolinking annotation should be rewritten using the + // new class name. + + StmtIterator iter = aboxModel.listStatements(oldClass, (Property) null, (RDFNode) null); + + int removeCount = 0; + while (iter.hasNext()) { + Statement oldStatement = iter.next(); + removeCount++; + retractions.add(oldStatement); + } + + //log summary of changes + if (removeCount > 0) { + logger.log("Removed " + removeCount + " subject reference" + ((removeCount > 1) ? "s" : "") + " to the " + oldClass.getURI() + " class"); + } + + // Change class references in the objects of rdf:type statements + iter = aboxModel.listStatements((Resource) null, RDF.type, oldClass); + + int renameCount = 0; + while (iter.hasNext()) { + renameCount++; + Statement oldStatement = iter.next(); + Statement newStatement = ResourceFactory.createStatement(oldStatement.getSubject(), RDF.type, newClass); + retractions.add(oldStatement); + additions.add(newStatement); + } + + //log summary of changes + if (renameCount > 0) { + logger.log("Retyped " + renameCount + " individual" + ((renameCount > 1) ? "s" : "") + " from type " + oldClass.getURI() + " to type " + newClass.getURI()); + } + + aboxModel.remove(retractions); + record.recordRetractions(retractions); + aboxModel.add(additions); + record.recordAdditions(additions); + + } finally { + aboxModel.leaveCriticalSection(); + } + } } /** @@ -231,24 +245,26 @@ public class ABoxUpdater { if (!parentOfAddedClass.equals(OWL.Thing)) { - StmtIterator stmtIter = aboxModel.listStatements(null, RDF.type, parentOfAddedClass); - - int count = stmtIter.toList().size(); - if (count > 0) { - - String indList = ""; - while (stmtIter.hasNext()) { - Statement stmt = stmtIter.next(); - indList += "\n\t" + stmt.getSubject().getURI(); - } - + Iterator graphIt = dataset.listNames(); + while(graphIt.hasNext()) { + String graph = graphIt.next(); + if(!KnowledgeBaseUpdater.isUpdatableABoxGraph(graph)){ + continue; + } + Model aboxModel = dataset.getNamedModel(graph); + + StmtIterator stmtIter = aboxModel.listStatements(null, RDF.type, parentOfAddedClass); + + int count = stmtIter.toList().size(); + if (count > 0) { //TODO - take out the detailed logging after our internal testing is completed. logger.log("There " + ((count > 1) ? "are" : "is") + " " + count + " individual" + ((count > 1) ? "s" : "") + " in the model that " + ((count > 1) ? "are" : "is") + " of type " + parentOfAddedClass.getURI() + "," + " and a new subclass of that class has been added: " + addedClass.getURI() + ". " + "Please review " + ((count > 1) ? "these" : "this") + " individual" + ((count > 1) ? "s" : "") + " to see whether " + ((count > 1) ? "they" : "it") + " should be of type: " + addedClass.getURI() ); } - } + + } } } } @@ -330,25 +346,33 @@ public class ABoxUpdater { } // Remove instances of the deleted class - aboxModel.enterCriticalSection(Lock.WRITE); - try { - int count = 0; - int refCount = 0; - StmtIterator iter = aboxModel.listStatements((Resource) null, RDF.type, deletedClass); - - while (iter.hasNext()) { - count++; - Statement typeStmt = iter.next(); - refCount = deleteIndividual(typeStmt.getSubject()); - } - - if (count > 0) { - logger.log("Removed " + count + " individual" + (((count > 1) ? "s" : "") + " of type " + deletedClass.getURI()) + " (refs = " + refCount + ")"); - } - - } finally { - aboxModel.leaveCriticalSection(); - } + Iterator graphIt = dataset.listNames(); + while(graphIt.hasNext()) { + String graph = graphIt.next(); + if(!KnowledgeBaseUpdater.isUpdatableABoxGraph(graph)){ + continue; + } + Model aboxModel = dataset.getNamedModel(graph); + aboxModel.enterCriticalSection(Lock.WRITE); + try { + int count = 0; + int refCount = 0; + StmtIterator iter = aboxModel.listStatements((Resource) null, RDF.type, deletedClass); + + while (iter.hasNext()) { + count++; + Statement typeStmt = iter.next(); + refCount = deleteIndividual(typeStmt.getSubject()); + } + + if (count > 0) { + logger.log("Removed " + count + " individual" + (((count > 1) ? "s" : "") + " of type " + deletedClass.getURI()) + " (refs = " + refCount + ")"); + } + + } finally { + aboxModel.leaveCriticalSection(); + } + } } protected int deleteIndividual(Resource individual) throws IOException { @@ -356,29 +380,37 @@ public class ABoxUpdater { Model retractions = ModelFactory.createDefaultModel(); int refCount = 0; - aboxModel.enterCriticalSection(Lock.WRITE); - try { - StmtIterator iter = aboxModel.listStatements(individual, (Property) null, (RDFNode) null); - - while (iter.hasNext()) { - Statement subjstmt = iter.next(); - retractions.add(subjstmt); - } - - iter = aboxModel.listStatements((Resource) null, (Property) null, individual); - - while (iter.hasNext()) { - Statement objstmt = iter.next(); - retractions.add(objstmt); - refCount++; - } - - aboxModel.remove(retractions); - record.recordRetractions(retractions); - - } finally { - aboxModel.leaveCriticalSection(); - } + Iterator graphIt = dataset.listNames(); + while(graphIt.hasNext()) { + String graph = graphIt.next(); + if(!KnowledgeBaseUpdater.isUpdatableABoxGraph(graph)){ + continue; + } + Model aboxModel = dataset.getNamedModel(graph); + aboxModel.enterCriticalSection(Lock.WRITE); + try { + StmtIterator iter = aboxModel.listStatements(individual, (Property) null, (RDFNode) null); + + while (iter.hasNext()) { + Statement subjstmt = iter.next(); + retractions.add(subjstmt); + } + + iter = aboxModel.listStatements((Resource) null, (Property) null, individual); + + while (iter.hasNext()) { + Statement objstmt = iter.next(); + retractions.add(objstmt); + refCount++; + } + + aboxModel.remove(retractions); + record.recordRetractions(retractions); + + } finally { + aboxModel.leaveCriticalSection(); + } + } return refCount; } @@ -388,20 +420,33 @@ public class ABoxUpdater { Iterator propItr = changes.iterator(); while(propItr.hasNext()){ AtomicOntologyChange propChangeObj = propItr.next(); - switch (propChangeObj.getAtomicChangeType()){ - case ADD: - addProperty(propChangeObj); - break; - case DELETE: - deleteProperty(propChangeObj); - break; - case RENAME: - renameProperty(propChangeObj); - break; - default: - logger.logError("unexpected change type indicator: " + propChangeObj.getAtomicChangeType()); - break; - } + log.debug("processing " + propChangeObj); + try { + if (propChangeObj.getAtomicChangeType() == null) { + log.error("Missing change type; skipping " + propChangeObj); + continue; + } + switch (propChangeObj.getAtomicChangeType()){ + case ADD: + log.debug("add"); + addProperty(propChangeObj); + break; + case DELETE: + log.debug("delete"); + deleteProperty(propChangeObj); + break; + case RENAME: + log.debug("rename"); + renameProperty(propChangeObj); + break; + default: + log.debug("unknown"); + logger.logError("unexpected change type indicator: " + propChangeObj.getAtomicChangeType()); + break; + } + } catch (Exception e) { + log.error(e,e); + } } } @@ -424,37 +469,45 @@ public class ABoxUpdater { if (inverseOfAddedProperty != null) { Model additions = ModelFactory.createDefaultModel(); - aboxModel.enterCriticalSection(Lock.WRITE); - - try { - StmtIterator iter = aboxModel.listStatements((Resource) null, inverseOfAddedProperty, (RDFNode) null); - - while (iter.hasNext()) { - - Statement stmt = iter.next(); - - if (stmt.getObject().isResource()) { - Statement newStmt = ResourceFactory.createStatement(stmt.getObject().asResource(), addedProperty, stmt.getSubject()); - additions.add(newStmt); - } else { - logger.log("WARNING: expected the object of this statement to be a Resource but it is not. No inverse has been asserted: " + stmtString(stmt)); - } - } - - aboxModel.add(additions); - record.recordAdditions(additions); - - if (additions.size() > 0) { - logger.log("Added " + additions.size() + " statement" + - ((additions.size() > 1) ? "s" : "") + - " with predicate " + addedProperty.getURI() + - " (as an inverse to existing " + inverseOfAddedProperty.getURI() + - " statement" + ((additions.size() > 1) ? "s" : "") + ")"); - } - - } finally { - aboxModel.leaveCriticalSection(); - } + Iterator graphIt = dataset.listNames(); + while(graphIt.hasNext()) { + String graph = graphIt.next(); + if(!KnowledgeBaseUpdater.isUpdatableABoxGraph(graph)){ + continue; + } + Model aboxModel = dataset.getNamedModel(graph); + aboxModel.enterCriticalSection(Lock.WRITE); + + try { + StmtIterator iter = aboxModel.listStatements((Resource) null, inverseOfAddedProperty, (RDFNode) null); + + while (iter.hasNext()) { + + Statement stmt = iter.next(); + + if (stmt.getObject().isResource()) { + Statement newStmt = ResourceFactory.createStatement(stmt.getObject().asResource(), addedProperty, stmt.getSubject()); + additions.add(newStmt); + } else { + logger.log("WARNING: expected the object of this statement to be a Resource but it is not. No inverse has been asserted: " + stmtString(stmt)); + } + } + + aboxModel.add(additions); + record.recordAdditions(additions); + + if (additions.size() > 0) { + logger.log("Added " + additions.size() + " statement" + + ((additions.size() > 1) ? "s" : "") + + " with predicate " + addedProperty.getURI() + + " (as an inverse to existing " + inverseOfAddedProperty.getURI() + + " statement" + ((additions.size() > 1) ? "s" : "") + ")"); + } + + } finally { + aboxModel.leaveCriticalSection(); + } + } } } @@ -492,33 +545,41 @@ public class ABoxUpdater { } } - Model deletePropModel = ModelFactory.createDefaultModel(); - - if (replacementProperty == null) { - - aboxModel.enterCriticalSection(Lock.WRITE); - try { - deletePropModel.add(aboxModel.listStatements((Resource) null, deletedProperty, (RDFNode) null)); - aboxModel.remove(deletePropModel); - } finally { - aboxModel.leaveCriticalSection(); - } - record.recordRetractions(deletePropModel); - boolean plural = (deletePropModel.size() > 1); - if (deletePropModel.size() > 0) { - logger.log("Removed " + deletePropModel.size() + " statement" + (plural ? "s" : "") + " with predicate " + - propObj.getSourceURI()); - } - } else { - AtomicOntologyChange chg = new AtomicOntologyChange(deletedProperty.getURI(), replacementProperty.getURI(), AtomicChangeType.RENAME, propObj.getNotes()); - renameProperty(chg); - } + Iterator graphIt = dataset.listNames(); + while(graphIt.hasNext()) { + String graph = graphIt.next(); + if(!KnowledgeBaseUpdater.isUpdatableABoxGraph(graph)){ + continue; + } + Model aboxModel = dataset.getNamedModel(graph); + Model deletePropModel = ModelFactory.createDefaultModel(); + + if (replacementProperty == null) { + + aboxModel.enterCriticalSection(Lock.WRITE); + try { + deletePropModel.add(aboxModel.listStatements((Resource) null, deletedProperty, (RDFNode) null)); + aboxModel.remove(deletePropModel); + } finally { + aboxModel.leaveCriticalSection(); + } + record.recordRetractions(deletePropModel); + boolean plural = (deletePropModel.size() > 1); + if (deletePropModel.size() > 0) { + logger.log("Removed " + deletePropModel.size() + " statement" + (plural ? "s" : "") + " with predicate " + + propObj.getSourceURI()); + } + } else { + AtomicOntologyChange chg = new AtomicOntologyChange(deletedProperty.getURI(), replacementProperty.getURI(), AtomicChangeType.RENAME, propObj.getNotes()); + renameProperty(chg); + } + } } private void renameProperty(AtomicOntologyChange propObj) throws IOException { - //logger.log("Processing a property rename from: " + propObj.getSourceURI() + " to " + propObj.getDestinationURI()); + logger.log("Processing a property rename from: " + propObj.getSourceURI() + " to " + propObj.getDestinationURI()); OntProperty oldProperty = oldTboxModel.getOntProperty(propObj.getSourceURI()); OntProperty newProperty = newTboxModel.getOntProperty(propObj.getDestinationURI()); @@ -533,35 +594,46 @@ public class ABoxUpdater { return; } - Model renamePropAddModel = ModelFactory.createDefaultModel(); - Model renamePropRetractModel = ModelFactory.createDefaultModel(); + Iterator graphIt = dataset.listNames(); + while(graphIt.hasNext()) { + String graph = graphIt.next(); + if(!KnowledgeBaseUpdater.isUpdatableABoxGraph(graph)){ + continue; + } + Model aboxModel = dataset.getNamedModel(graph); - aboxModel.enterCriticalSection(Lock.WRITE); - try { - renamePropRetractModel.add( aboxModel.listStatements( - (Resource) null, oldProperty, (RDFNode) null)); - StmtIterator stmItr = renamePropRetractModel.listStatements(); - while(stmItr.hasNext()) { - Statement tempStatement = stmItr.nextStatement(); - renamePropAddModel.add( tempStatement.getSubject(), - newProperty, - tempStatement.getObject() ); - } - aboxModel.remove(renamePropRetractModel); - aboxModel.add(renamePropAddModel); - } finally { - aboxModel.leaveCriticalSection(); - } - - record.recordAdditions(renamePropAddModel); - record.recordRetractions(renamePropRetractModel); - - if (renamePropRetractModel.size() > 0) { - logger.log("Changed " + renamePropRetractModel.size() + " statement" + - ((renamePropRetractModel.size() > 1) ? "s" : "") + - " with predicate " + propObj.getSourceURI() + " to use " + - propObj.getDestinationURI() + " instead"); - } + Model renamePropAddModel = ModelFactory.createDefaultModel(); + Model renamePropRetractModel = ModelFactory.createDefaultModel(); + + aboxModel.enterCriticalSection(Lock.WRITE); + try { + renamePropRetractModel.add( aboxModel.listStatements( + (Resource) null, oldProperty, (RDFNode) null)); + StmtIterator stmItr = renamePropRetractModel.listStatements(); + while(stmItr.hasNext()) { + Statement tempStatement = stmItr.nextStatement(); + renamePropAddModel.add( tempStatement.getSubject(), + newProperty, + tempStatement.getObject() ); + } + aboxModel.remove(renamePropRetractModel); + aboxModel.add(renamePropAddModel); + } finally { + aboxModel.leaveCriticalSection(); + } + + record.recordAdditions(renamePropAddModel); + record.recordRetractions(renamePropRetractModel); + + if (renamePropRetractModel.size() > 0) { + logger.log("Changed " + renamePropRetractModel.size() + " statement" + + ((renamePropRetractModel.size() > 1) ? "s" : "") + + " with predicate " + propObj.getSourceURI() + " to use " + + propObj.getDestinationURI() + " instead"); + } + } + + tboxUpdater.renameProperty(propObj); } public void logChanges(Statement oldStatement, Statement newStatement) throws IOException { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/AtomicOntologyChange.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/AtomicOntologyChange.java index e19b095ff..4fbab936d 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/AtomicOntologyChange.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/AtomicOntologyChange.java @@ -30,6 +30,11 @@ public class AtomicOntologyChange { this.notes = notes; } + @Override + public String toString() { + return "Source: " + sourceURI + "; Destination: " + destinationURI + + "; Type: " + atomicChangeType + "; Notes:" + notes; + } /** * Contains the URI of a class or property in the previous version of diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/ChangeRecord.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/ChangeRecord.java index 8845e1f43..3c9029839 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/ChangeRecord.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/ChangeRecord.java @@ -12,4 +12,6 @@ public interface ChangeRecord { public void writeChanges(); + public boolean hasRecordedChanges(); + } 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 62aab4416..6f46af050 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 @@ -11,6 +11,8 @@ import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -22,19 +24,16 @@ 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.Syntax; +import com.hp.hpl.jena.query.Dataset; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.ModelFactory; import com.hp.hpl.jena.rdf.model.Statement; import com.hp.hpl.jena.rdf.model.StmtIterator; -import com.hp.hpl.jena.shared.Lock; +import edu.cornell.mannlib.vitro.webapp.dao.jena.RDFServiceDataset; import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeSet; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService.ModelSerializationFormat; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException; import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils; import edu.cornell.mannlib.vitro.webapp.servlet.setup.JenaDataSourceSetupBase; @@ -58,14 +57,13 @@ public class KnowledgeBaseUpdater { this.record = new SimpleChangeRecord(settings.getAddedDataFile(), settings.getRemovedDataFile()); } - public void update(ServletContext servletContext) throws IOException { + public boolean update(ServletContext servletContext) throws IOException { if (this.logger == null) { this.logger = new SimpleChangeLogger(settings.getLogFile(), settings.getErrorLogFile()); } long startTime = System.currentTimeMillis(); - System.out.println("Migrating the knowledge base"); log.info("Migrating the knowledge base"); logger.log("Started knowledge base migration"); @@ -73,7 +71,7 @@ public class KnowledgeBaseUpdater { performUpdate(servletContext); } catch (Exception e) { logger.logError(e.getMessage()); - e.printStackTrace(); + log.error(e,e); } if (!logger.errorsWritten()) { @@ -85,10 +83,9 @@ public class KnowledgeBaseUpdater { logger.closeLogs(); long elapsedSecs = (System.currentTimeMillis() - startTime)/1000; - System.out.println("Finished knowledge base migration in " + elapsedSecs + " second" + (elapsedSecs != 1 ? "s" : "")); log.info("Finished knowledge base migration in " + elapsedSecs + " second" + (elapsedSecs != 1 ? "s" : "")); - return; + return record.hasRecordedChanges(); } private void performUpdate(ServletContext servletContext) throws Exception { @@ -98,136 +95,153 @@ public class KnowledgeBaseUpdater { AtomicOntologyChangeLists changes = new AtomicOntologyChangeLists(rawChanges,settings.getNewTBoxModel(),settings.getOldTBoxModel()); //process the TBox before the ABox - log.info("\tupdating tbox annotations"); - updateTBoxAnnotations(); - + try { + log.debug("\tupdating tbox annotations"); + updateTBoxAnnotations(); + } catch (Exception e) { + log.error(e,e); + } + try { migrateMigrationMetadata(servletContext); logger.log("Migrated migration metadata"); } catch (Exception e) { - log.debug("unable to migrate migration metadata " + e.getMessage()); + log.error("unable to migrate migration metadata " + e.getMessage()); } - - log.info("\tupdating the abox"); - updateABox(changes); - } - - private void performSparqlConstructAdditions(String sparqlConstructDir, OntModel readModel, OntModel writeModel) throws IOException { - - Model anonModel = performSparqlConstructs(sparqlConstructDir, readModel, true); - - if (anonModel == null) { - return; - } - - writeModel.enterCriticalSection(Lock.WRITE); - try { - JenaIngestUtils jiu = new JenaIngestUtils(); - Model additions = jiu.renameBNodes(anonModel, settings.getDefaultNamespace() + "n", writeModel); - Model actualAdditions = ModelFactory.createDefaultModel(); - StmtIterator stmtIt = additions.listStatements(); - - while (stmtIt.hasNext()) { - Statement stmt = stmtIt.nextStatement(); - if (!writeModel.contains(stmt)) { - actualAdditions.add(stmt); - } - } - - writeModel.add(actualAdditions); - record.recordAdditions(actualAdditions); - } finally { - writeModel.leaveCriticalSection(); - } + + log.info("performing SPARQL CONSTRUCT additions"); + performSparqlConstructs(settings.getSparqlConstructAdditionsDir(), settings.getRDFService(), ADD); + + log.info("performing SPARQL CONSTRUCT retractions"); + performSparqlConstructs(settings.getSparqlConstructDeletionsDir(), settings.getRDFService(), RETRACT); + + log.info("\tupdating the abox"); + updateABox(changes); + + log.info("performing post-processing SPARQL CONSTRUCT additions"); + performSparqlConstructs(settings.getSparqlConstructAdditionsDir() + "/post/", + settings.getRDFService(), ADD); + + log.info("performing post-processing SPARQL CONSTRUCT retractions"); + performSparqlConstructs(settings.getSparqlConstructDeletionsDir() + "/post/", + settings.getRDFService(), RETRACT); + + } - private void performSparqlConstructRetractions(String sparqlConstructDir, OntModel readModel, OntModel writeModel) throws IOException { - - Model retractions = performSparqlConstructs(sparqlConstructDir, readModel, false); - - if (retractions == null) { - return; - } - - writeModel.enterCriticalSection(Lock.WRITE); - - try { - writeModel.remove(retractions); - record.recordRetractions(retractions); - } finally { - writeModel.leaveCriticalSection(); - } - - } + private static final boolean ADD = true; + private static final boolean RETRACT = !ADD; - /** - * Performs a set of arbitrary SPARQL CONSTRUCT queries on the - * data, for changes that cannot be expressed as simple property - * or class additions, deletions, or renamings. - * Blank nodes created by the queries are given random URIs. - * @param sparqlConstructDir - * @param aboxModel - */ - private Model performSparqlConstructs(String sparqlConstructDir, - OntModel readModel, - boolean add) throws IOException { - - Model anonModel = ModelFactory.createDefaultModel(); - File sparqlConstructDirectory = new File(sparqlConstructDir); - - if (!sparqlConstructDirectory.isDirectory()) { - logger.logError(this.getClass().getName() + - "performSparqlConstructs() expected to find a directory " + - " at " + sparqlConstructDir + ". Unable to execute " + - " SPARQL CONSTRUCTS."); - return null; - } - - File[] sparqlFiles = sparqlConstructDirectory.listFiles(); - for (int i = 0; i < sparqlFiles.length; i ++) { - File sparqlFile = sparqlFiles[i]; - try { - BufferedReader reader = new BufferedReader(new FileReader(sparqlFile)); - StringBuffer fileContents = new StringBuffer(); - String ln; - - while ( (ln = reader.readLine()) != null) { - fileContents.append(ln).append('\n'); - } - - try { - log.debug("\t\tprocessing SPARQL construct query from file " + sparqlFiles[i].getName()); - Query q = QueryFactory.create(fileContents.toString(), Syntax.syntaxARQ); - readModel.enterCriticalSection(Lock.READ); - try { - QueryExecution qe = QueryExecutionFactory.create(q, readModel); - long numBefore = anonModel.size(); - qe.execConstruct(anonModel); - long numAfter = anonModel.size(); - long num = numAfter - numBefore; - - if (num > 0) { - logger.log((add ? "Added " : "Removed ") + num + - " statement" + ((num > 1) ? "s" : "") + - " using the SPARQL construct query from file " + sparqlFiles[i].getParentFile().getName() + "/" + sparqlFiles[i].getName()); + /** + * Performs a set of arbitrary SPARQL CONSTRUCT queries on the + * data, for changes that cannot be expressed as simple property + * or class additions, deletions, or renamings. + * Blank nodes created by the queries are given random URIs. + * @param sparqlConstructDir + * @param readModel + * @param writeModel + * @param add (add = true; retract = false) + */ + private void performSparqlConstructs(String sparqlConstructDir, + RDFService rdfService, + boolean add) throws IOException { + Dataset dataset = new RDFServiceDataset(rdfService); + File sparqlConstructDirectory = new File(sparqlConstructDir); + log.info("Using SPARQL CONSTRUCT directory " + sparqlConstructDirectory); + if (!sparqlConstructDirectory.isDirectory()) { + String logMsg = this.getClass().getName() + + "performSparqlConstructs() expected to find a directory " + + " at " + sparqlConstructDir + ". Unable to execute " + + " SPARQL CONSTRUCTS."; + logger.logError(logMsg); + log.error(logMsg); + return; + } + List sparqlFiles = Arrays.asList(sparqlConstructDirectory.listFiles()); + Collections.sort(sparqlFiles); // queries may depend on being run in a certain order + JenaIngestUtils jiu = new JenaIngestUtils(); + for (File sparqlFile : sparqlFiles) { + if(sparqlFile.isDirectory()) { + continue; + } + StringBuffer fileContents = new StringBuffer(); + try { + BufferedReader reader = new BufferedReader(new FileReader(sparqlFile)); + String ln; + while ( (ln = reader.readLine()) != null) { + fileContents.append(ln).append('\n'); + } + } catch (FileNotFoundException fnfe) { + String logMsg = "WARNING: performSparqlConstructs() could not find " + + " SPARQL CONSTRUCT file " + sparqlFile + ". Skipping."; + logger.log(logMsg); + log.info(logMsg); + continue; + } + Model anonModel = ModelFactory.createDefaultModel(); + try { + log.info("\t\tprocessing SPARQL construct query from file " + sparqlFile.getName()); + + anonModel = RDFServiceUtils.parseModel( + rdfService.sparqlConstructQuery(fileContents.toString(), + RDFService.ModelSerializationFormat.NTRIPLE), + ModelSerializationFormat.NTRIPLE); + + long num = anonModel.size(); + if (num > 0) { + String logMsg = (add ? "Added " : "Removed ") + num + + " statement" + ((num > 1) ? "s" : "") + + " using the SPARQL construct query from file " + + sparqlFile.getParentFile().getName() + + "/" + sparqlFile.getName(); + logger.log(logMsg); + log.info(logMsg); + } + + } catch (Exception e) { + logger.logError(this.getClass().getName() + + ".performSparqlConstructs() unable to execute " + + "query at " + sparqlFile + ". Error message is: " + e.getMessage()); + log.error(e,e); + } + + if(!add) { + StmtIterator sit = anonModel.listStatements(); + while (sit.hasNext()) { + Statement stmt = sit.nextStatement(); + Iterator graphIt = dataset.listNames(); + while(graphIt.hasNext()) { + String graph = graphIt.next(); + if(!isUpdatableABoxGraph(graph)) { + continue; } - qe.close(); - } finally { - readModel.leaveCriticalSection(); - } - } catch (Exception e) { - logger.logError(this.getClass().getName() + - ".performSparqlConstructs() unable to execute " + - "query at " + sparqlFile + ". Error message is: " + e.getMessage()); - } - } catch (FileNotFoundException fnfe) { - logger.log("WARNING: performSparqlConstructs() could not find " + - " SPARQL CONSTRUCT file " + sparqlFile + ". Skipping."); - } - } - - return anonModel; - } + Model writeModel = dataset.getNamedModel(graph); + if (writeModel.contains(stmt)) { + writeModel.remove(stmt); + } + } + } + record.recordRetractions(anonModel); + //log.info("removed " + anonModel.size() + " statements from SPARQL CONSTRUCTs"); + } else { + Model writeModel = dataset.getNamedModel(JenaDataSourceSetupBase.JENA_DB_MODEL); + Model additions = jiu.renameBNodes( + anonModel, settings.getDefaultNamespace() + "n", writeModel); + Model actualAdditions = ModelFactory.createDefaultModel(); + StmtIterator stmtIt = additions.listStatements(); + while (stmtIt.hasNext()) { + Statement stmt = stmtIt.nextStatement(); + if (!writeModel.contains(stmt)) { + actualAdditions.add(stmt); + } + } + writeModel.add(actualAdditions); + //log.info("added " + actualAdditions.size() + " statements from SPARQL CONSTRUCTs"); + record.recordAdditions(actualAdditions); + } + + } + } private List getAtomicOntologyChanges() @@ -240,10 +254,8 @@ public class KnowledgeBaseUpdater { private void updateABox(AtomicOntologyChangeLists changes) throws IOException { - OntModel oldTBoxModel = settings.getOldTBoxModel(); - OntModel newTBoxModel = settings.getNewTBoxModel(); - OntModel ABoxModel = settings.getAssertionOntModelSelector().getABoxModel(); - ABoxUpdater aboxUpdater = new ABoxUpdater(oldTBoxModel, newTBoxModel, ABoxModel,settings.getNewTBoxAnnotationsModel(), logger, record); + + ABoxUpdater aboxUpdater = new ABoxUpdater(settings, logger, record); aboxUpdater.processPropertyChanges(changes.getAtomicPropertyChanges()); aboxUpdater.processClassChanges(changes.getAtomicClassChanges()); } @@ -281,14 +293,18 @@ public class KnowledgeBaseUpdater { rdfService.changeSetUpdate(removeChangeSet); } - private void updateTBoxAnnotations() throws IOException { - - TBoxUpdater tboxUpdater = new TBoxUpdater(settings.getOldTBoxAnnotationsModel(), - settings.getNewTBoxAnnotationsModel(), - settings.getAssertionOntModelSelector().getTBoxModel(), logger, record); - - tboxUpdater.updateDefaultAnnotationValues(); - //tboxUpdater.updateAnnotationModel(); + private void updateTBoxAnnotations() { + TBoxUpdater tboxUpdater = new TBoxUpdater(settings, logger, record); + try { + tboxUpdater.modifyPropertyQualifications(); + } catch (Exception e) { + log.error("Unable to modify qualified property config file ", e); + } + try { + tboxUpdater.updateDefaultAnnotationValues(); + } catch (Exception e) { + log.error("Unable to update default annotation values ", e); + } } /** @@ -296,7 +312,7 @@ public class KnowledgeBaseUpdater { * needs to be updated to conform to a new ontology version */ public boolean updateRequired(ServletContext servletContext) throws IOException { - boolean required = false; + boolean required = true; String sparqlQueryStr = loadSparqlQuery(settings.getAskUpdatedQueryFile()); if (sparqlQueryStr == null) { @@ -338,7 +354,7 @@ public class KnowledgeBaseUpdater { File file = new File(filePath); if (!file.exists()) { - return null; + throw new RuntimeException("SPARQL file not found at " + filePath); } BufferedReader reader = new BufferedReader(new FileReader(file)); StringBuffer fileContents = new StringBuffer(); @@ -363,8 +379,10 @@ public class KnowledgeBaseUpdater { " update to new ontology version: ", e); } } - - + + public static boolean isUpdatableABoxGraph(String graphName) { + return (!graphName.contains("tbox") && !graphName.contains("filegraph")); + } /** * A class that allows to access two different ontology change lists, @@ -390,11 +408,13 @@ public class KnowledgeBaseUpdater { while(listItr.hasNext()) { AtomicOntologyChange changeObj = listItr.next(); if (changeObj.getSourceURI() != null){ - + log.debug("triaging " + changeObj); if (oldTboxModel.getOntProperty(changeObj.getSourceURI()) != null){ atomicPropertyChanges.add(changeObj); + log.debug("added to property changes"); } else if (oldTboxModel.getOntClass(changeObj.getSourceURI()) != null) { atomicClassChanges.add(changeObj); + log.debug("added to class changes"); } else if ("Prop".equals(changeObj.getNotes())) { atomicPropertyChanges.add(changeObj); } else if ("Class".equals(changeObj.getNotes())) { @@ -429,5 +449,6 @@ public class KnowledgeBaseUpdater { public List getAtomicPropertyChanges() { return atomicPropertyChanges; } + } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/OntologyChangeParser.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/OntologyChangeParser.java index 6ef0467ea..6a92b213c 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/OntologyChangeParser.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/OntologyChangeParser.java @@ -9,6 +9,8 @@ import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.skife.csv.CSVReader; import org.skife.csv.SimpleReader; @@ -23,6 +25,8 @@ import edu.cornell.mannlib.vitro.webapp.ontology.update.AtomicOntologyChange.Ato public class OntologyChangeParser { + private final Log log = LogFactory.getLog(OntologyChangeParser.class); + private ChangeLogger logger; public OntologyChangeParser(ChangeLogger logger) { @@ -85,6 +89,8 @@ public class OntologyChangeParser { } + log.debug(changeObj); + changeObjects.add(changeObj); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/SimpleChangeRecord.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/SimpleChangeRecord.java index d0ca316e0..78a5c6ba7 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/SimpleChangeRecord.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/SimpleChangeRecord.java @@ -26,6 +26,9 @@ public class SimpleChangeRecord implements ChangeRecord { private File additionsFile; private File retractionsFile; + private int additionsCount = 0; + private int retractionsCount = 0; + public SimpleChangeRecord( String additionsFile, String retractionsFile) { this.additionsFile = new File(additionsFile); @@ -46,11 +49,12 @@ public class SimpleChangeRecord implements ChangeRecord { public void recordAdditions(Model incrementalAdditions) { additionsModel.add(incrementalAdditions); - + additionsCount += incrementalAdditions.size(); } public void recordRetractions(Model incrementalRetractions) { retractionsModel.add(incrementalRetractions); + retractionsCount += incrementalRetractions.size(); } private void write(Model model, File file) { @@ -71,5 +75,9 @@ public class SimpleChangeRecord implements ChangeRecord { write(retractionsModel, retractionsFile); } } + + public boolean hasRecordedChanges() { + return additionsCount > 0 || retractionsCount > 0; + } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/TBoxUpdater.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/TBoxUpdater.java index b5d66613a..a9616cefa 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/TBoxUpdater.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/TBoxUpdater.java @@ -2,11 +2,22 @@ package edu.cornell.mannlib.vitro.webapp.ontology.update; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; import java.util.List; +import org.apache.commons.logging.Log; +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.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.rdf.model.Literal; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.ModelFactory; @@ -14,6 +25,7 @@ import com.hp.hpl.jena.rdf.model.NodeIterator; 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.ResourceFactory; import com.hp.hpl.jena.rdf.model.Statement; import com.hp.hpl.jena.rdf.model.StmtIterator; import com.hp.hpl.jena.shared.Lock; @@ -21,398 +33,542 @@ import com.hp.hpl.jena.vocabulary.RDF; import com.hp.hpl.jena.vocabulary.RDFS; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; +import edu.cornell.mannlib.vitro.webapp.dao.jena.RDFServiceDataset; +import edu.cornell.mannlib.vitro.webapp.servlet.setup.JenaDataSourceSetupBase; /** -* Performs knowledge base updates to the tbox to align with a new ontology version -* -*/ + * Performs knowledge base updates to the tbox to align with a new ontology version + * + */ public class TBoxUpdater { - private OntModel oldTboxAnnotationsModel; - private OntModel newTboxAnnotationsModel; - private OntModel siteModel; - private ChangeLogger logger; - private ChangeRecord record; - private boolean detailLogs = false; - - private static final String classGroupURI = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#ClassGroup"; - private Resource classGroupClass = (ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM)).createResource(classGroupURI); - private static final String inClassGroupURI = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#inClassGroup"; - private Property inClassGroupProp = (ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM)).createProperty(inClassGroupURI); + private static final Log log = LogFactory.getLog(TBoxUpdater.class); - /** - * - * Constructor - * - * @param oldTboxAnnotationsModel - previous version of the annotations in the ontology - * @param newTboxAnnotationsModel - new version of the annotations in the ontology - * @param siteModel - the knowledge base to be updated - * @param logger - for writing to the change log - * and the error log. - * @param record - for writing to the additions model - * and the retractions model. - * - */ - public TBoxUpdater(OntModel oldTboxAnnotationsModel, - OntModel newTboxAnnotationsModel, - OntModel siteModel, - ChangeLogger logger, - ChangeRecord record) { - - this.oldTboxAnnotationsModel = oldTboxAnnotationsModel; - this.newTboxAnnotationsModel = newTboxAnnotationsModel; - this.siteModel = siteModel; - this.logger = logger; - this.record = record; - } - - /** - * - * Update a knowledge base to align with changes to vitro annotation property default - * values in a new version of the ontology. The two versions of the ontology and the - * knowledge base to be updated are provided in the class constructor and are - * referenced via class level variables. - * - * If the default value (i.e. the value that is provided in the vivo-core - * annotations files) of a vitro annotation property has been changed for a vivo - * core class, and that default value has not been changed in the site knowledge - * base, then update the value in the site knowledge base to be the new default. - * Also, if a new vitro annotation property setting (i.e. either an existing - * setting applied to an existing class where it wasn't applied before, or - * an existing setting applied to a new class) has been applied to a vivo - * core class then copy that new property statement into the site model. - * If a property setting for a class exists in the old ontology but - * not in the new one, then that statement will be removed from the - * site knowledge base. - * - * Writes to the change log file, the error log file, and the incremental change - * knowledge base. - * - * Note: as specified, this method for now assumes that no new vitro annotation - * properties have been introduced. This should be updated for future versions. - */ - public void updateDefaultAnnotationValues() throws IOException { - - siteModel.enterCriticalSection(Lock.WRITE); - - try { - - Model additions = ModelFactory.createDefaultModel(); - Model retractions = ModelFactory.createDefaultModel(); - - // Update defaults values for vitro annotation properties in the site model - // if the default has changed in the new version of the ontology AND if - // the site hasn't overidden the previous default in their knowledge base. - - StmtIterator iter = oldTboxAnnotationsModel.listStatements(); - - while (iter.hasNext()) { - - Statement stmt = iter.next(); - Resource subject = stmt.getSubject(); - Property predicate = stmt.getPredicate(); - RDFNode oldObject = stmt.getObject(); - - if (! ( (RDFS.getURI().equals(predicate.getNameSpace())) || - (VitroVocabulary.vitroURI.equals(predicate.getNameSpace())) - ) ) { - // this annotation updater is only concerned with properties - // such as rdfs:comment and properties in the vitro application - // namespace - continue; - } - - NodeIterator newObjects = newTboxAnnotationsModel.listObjectsOfProperty(subject, predicate); - - if ((newObjects == null) || (!newObjects.hasNext()) ) { - // first check to see if the site has a local value change - // that should override the deletion - List siteObjects = siteModel.listObjectsOfProperty(subject, predicate).toList(); - - if (siteObjects.size() > 1) { - /* + private UpdateSettings settings; + private OntModel oldTboxAnnotationsModel; + private OntModel newTboxAnnotationsModel; + private OntModel siteModel; + private ChangeLogger logger; + private ChangeRecord record; + private boolean detailLogs = false; + + private static final String classGroupURI = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#ClassGroup"; + private Resource classGroupClass = (ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM)).createResource(classGroupURI); + private static final String inClassGroupURI = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#inClassGroup"; + private Property inClassGroupProp = (ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM)).createProperty(inClassGroupURI); + + /** + * + * Constructor + * + * @param oldTboxAnnotationsModel - previous version of the annotations in the ontology + * @param newTboxAnnotationsModel - new version of the annotations in the ontology + * @param siteModel - the knowledge base to be updated + * @param logger - for writing to the change log + * and the error log. + * @param record - for writing to the additions model + * and the retractions model. + * + */ + public TBoxUpdater(UpdateSettings settings, + ChangeLogger logger, + ChangeRecord record) { + this.settings = settings; + this.oldTboxAnnotationsModel = settings.getOldTBoxAnnotationsModel(); + this.newTboxAnnotationsModel = settings.getNewTBoxAnnotationsModel(); + this.siteModel = settings.getAssertionOntModelSelector().getTBoxModel(); + this.logger = logger; + this.record = record; + } + + /** + * Update application ontology data for domain and range-qualified properties + * to use any applicable settings from obsolete subproperties + */ + public void modifyPropertyQualifications() throws IOException { + + } + + private Model mergeConfigurations(Model oldConfig, Model newConfig) { + return null; + } + + public void updateDefaultAnnotationValues() throws IOException { + updateDefaultAnnotationValues(null); + } + + /** + * + * Update a knowledge base to align with changes to vitro annotation property default + * values in a new version of the ontology. The two versions of the ontology and the + * knowledge base to be updated are provided in the class constructor and are + * referenced via class level variables. + * + * If the default value (i.e. the value that is provided in the vivo-core + * annotations files) of a vitro annotation property has been changed for a vivo + * core class, and that default value has not been changed in the site knowledge + * base, then update the value in the site knowledge base to be the new default. + * Also, if a new vitro annotation property setting (i.e. either an existing + * setting applied to an existing class where it wasn't applied before, or + * an existing setting applied to a new class) has been applied to a vivo + * core class then copy that new property statement into the site model. + * If a property setting for a class exists in the old ontology but + * not in the new one, then that statement will be removed from the + * site knowledge base. + * + * Writes to the change log file, the error log file, and the incremental change + * knowledge base. + * + * Note: as specified, this method for now assumes that no new vitro annotation + * properties have been introduced. This should be updated for future versions. + */ + public void updateDefaultAnnotationValues(String subjectURI) throws IOException { + + siteModel.enterCriticalSection(Lock.WRITE); + + try { + + Model additions = ModelFactory.createDefaultModel(); + Model retractions = ModelFactory.createDefaultModel(); + + // Update defaults values for vitro annotation properties in the site model + // if the default has changed in the new version of the ontology AND if + // the site hasn't overidden the previous default in their knowledge base. + + if(oldTboxAnnotationsModel == null) { + logger.log("oldTboxAnnotationModel is null; aborting update of annotation values"); + return; + } + + Resource subj = (subjectURI == null) ? null : ResourceFactory.createResource(subjectURI); + + StmtIterator iter = oldTboxAnnotationsModel.listStatements(subj, null, (RDFNode) null); + + while (iter.hasNext()) { + + Statement stmt = iter.next(); + Resource subject = stmt.getSubject(); + Property predicate = stmt.getPredicate(); + RDFNode oldObject = stmt.getObject(); + + if (! ( (RDFS.getURI().equals(predicate.getNameSpace())) || + (VitroVocabulary.vitroURI.equals(predicate.getNameSpace())) + ) ) { + // this annotation updater is only concerned with properties + // such as rdfs:comment and properties in the vitro application + // namespace + continue; + } + + NodeIterator newObjects = newTboxAnnotationsModel.listObjectsOfProperty(subject, predicate); + + if ((newObjects == null) || (!newObjects.hasNext()) ) { + // first check to see if the site has a local value change + // that should override the deletion + List siteObjects = siteModel.listObjectsOfProperty(subject, predicate).toList(); + + if (siteObjects.size() > 1) { + /* logger.log("WARNING: found " + siteObjects.size() + " statements with subject = " + subject.getURI() + " and property = " + predicate.getURI() + " in the site database (maximum of one is expected)"); - */ - } - - if (siteObjects.size() > 0) { - RDFNode siteNode = siteObjects.get(0); - if (siteNode.equals(oldObject)) { - retractions.add(siteModel.listStatements(subject, predicate, (RDFNode) null)); - } - } - - continue; - } - - RDFNode newObject = newObjects.next(); - - int i = 1; - while (newObjects.hasNext()) { - i++; - newObjects.next(); - } - - if (i > 1) { - /* + */ + } + + if (siteObjects.size() > 0) { + RDFNode siteNode = siteObjects.get(0); + if (siteNode.equals(oldObject)) { + retractions.add(siteModel.listStatements(subject, predicate, (RDFNode) null)); + } + } + + continue; + } + + RDFNode newObject = newObjects.next(); + + int i = 1; + while (newObjects.hasNext()) { + i++; + newObjects.next(); + } + + if (i > 1) { + /* logger.log("WARNING: found " + i + " statements with subject = " + subject.getURI() + " and property = " + predicate.getURI() + " in the new version of the annotations ontology (maximum of one is expected)"); - */ - continue; - } - - // If a subject-property pair occurs in the old annotation TBox and the new annotations - // TBox, but not in the site model, then it is considered an erroneous deletion and - // the value from the new TBox is added into the site model. - // sjm: 7-16-2010. We want this here now to add back in annotations mistakenly dropped - // in the .9 to 1.0 migration, but I'm not sure we would want this here permanently. - // Shouldn't a site be allowed to delete annotations if they want to? - - NodeIterator siteObjects = siteModel.listObjectsOfProperty(subject,predicate); - - if (siteObjects == null || !siteObjects.hasNext()) { - try { - additions.add(subject, predicate, newObject); - - if (detailLogs) { - logger.log( "adding Statement: subject = " + subject.getURI() + - " property = " + predicate.getURI() + - " object = " + (newObject.isLiteral() ? ((Literal)newObject).getLexicalForm() - : ((Resource)newObject).getURI())); - } - } catch (Exception e) { - logger.logError("Error trying to add statement with property " + predicate.getURI() + - " of class = " + subject.getURI() + " in the knowledge base:\n" + e.getMessage()); - } - - continue; - } - - - if (!newObject.equals(oldObject)) { + */ + continue; + } - RDFNode siteObject = siteObjects.next(); + // If a subject-property pair occurs in the old annotation TBox and the new annotations + // TBox, but not in the site model, then it is considered an erroneous deletion and + // the value from the new TBox is added into the site model. + // sjm: 7-16-2010. We want this here now to add back in annotations mistakenly dropped + // in the .9 to 1.0 migration, but I'm not sure we would want this here permanently. + // Shouldn't a site be allowed to delete annotations if they want to? - i = 1; - while (siteObjects.hasNext()) { - i++; - siteObjects.next(); - } + NodeIterator siteObjects = siteModel.listObjectsOfProperty(subject,predicate); - if (i > 1) { - /* + if (siteObjects == null || !siteObjects.hasNext()) { + try { + additions.add(subject, predicate, newObject); + + if (detailLogs) { + logger.log( "adding Statement: subject = " + subject.getURI() + + " property = " + predicate.getURI() + + " object = " + (newObject.isLiteral() ? ((Literal)newObject).getLexicalForm() + : ((Resource)newObject).getURI())); + } + } catch (Exception e) { + logger.logError("Error trying to add statement with property " + predicate.getURI() + + " of class = " + subject.getURI() + " in the knowledge base:\n" + e.getMessage()); + } + + continue; + } + + + if (!newObject.equals(oldObject)) { + + RDFNode siteObject = siteObjects.next(); + + i = 1; + while (siteObjects.hasNext()) { + i++; + siteObjects.next(); + } + + if (i > 1) { + /* logger.log("WARNING: found " + i + " statements with subject = " + subject.getURI() + " and property = " + predicate.getURI() + " in the site annotations model (maximum of one is expected) "); - */ - continue; - } - - if (siteObject.equals(oldObject)) { - try { - StmtIterator it = siteModel.listStatements(subject, predicate, (RDFNode)null); - while (it.hasNext()) { - retractions.add(it.next()); - } - } catch (Exception e) { - logger.logError("Error removing statement for subject = " + subject.getURI() + - "and property = " + predicate.getURI() + - "from the knowledge base:\n" + e.getMessage()); - } + */ + continue; + } - try { - additions.add(subject, predicate, newObject); - - if (detailLogs) { - logger.log("Changed the value of property " + predicate.getURI() + - " of subject = " + subject.getURI() + - " from " + - (oldObject.isResource() ? ((Resource)oldObject).getURI() : ((Literal)oldObject).getLexicalForm()) + - " to " + - (newObject.isResource() ? ((Resource)newObject).getURI() : ((Literal)newObject).getLexicalForm()) + - " in the knowledge base:\n"); - } - } catch (Exception e) { - logger.logError("Error trying to change the value of property " + predicate.getURI() + - " of class = " + subject.getURI() + " in the knowledge base:\n" + e.getMessage()); - } - } - } - } - - Model actualAdditions = additions.difference(retractions); - siteModel.add(actualAdditions); - record.recordAdditions(actualAdditions); - Model actualRetractions = retractions.difference(additions); - siteModel.remove(actualRetractions); - record.recordRetractions(actualRetractions); - - long numAdded = actualAdditions.size(); - long numRemoved = actualRetractions.size(); - - // log summary of changes - if (numAdded > 0) { - logger.log("Updated the default vitro annotation value for " + - numAdded + " statements in the knowledge base"); - } - - if (numRemoved > 0) { - logger.log("Removed " + numRemoved + - " outdated vitro annotation property setting" + ((numRemoved > 1) ? "s" : "") + " from the knowledge base"); - } - - // Copy annotation property settings that were introduced in the new ontology - // into the site model. - // + if (siteObject.equals(oldObject)) { + try { + StmtIterator it = siteModel.listStatements(subject, predicate, (RDFNode)null); + while (it.hasNext()) { + retractions.add(it.next()); + } + } catch (Exception e) { + logger.logError("Error removing statement for subject = " + subject.getURI() + + "and property = " + predicate.getURI() + + "from the knowledge base:\n" + e.getMessage()); + } - Model newAnnotationSettings = newTboxAnnotationsModel.difference(oldTboxAnnotationsModel); - Model newAnnotationSettingsToAdd = ModelFactory.createDefaultModel(); - StmtIterator newStmtIt = newAnnotationSettings.listStatements(); - while (newStmtIt.hasNext()) { - Statement stmt = newStmtIt.next(); - if (!siteModel.contains(stmt)) { - newAnnotationSettingsToAdd.add(stmt); - - if (detailLogs) { - logger.log( "adding Statement: subject = " + stmt.getSubject().getURI() + - " property = " + stmt.getPredicate().getURI() + - " object = " + (stmt.getObject().isLiteral() ? ((Literal)stmt.getObject()).getLexicalForm() - : ((Resource)stmt.getObject()).getURI())); - } - } - } - - siteModel.add(newAnnotationSettingsToAdd); - record.recordAdditions(newAnnotationSettingsToAdd); - - // log the additions - summary - if (newAnnotationSettingsToAdd.size() > 0) { - boolean plural = (newAnnotationSettingsToAdd.size() > 1); - logger.log("Added " + newAnnotationSettingsToAdd.size() + " new annotation property setting" + (plural ? "s" : "") + " to the knowledge base. This includes only " + - "existing annotation properties applied to existing classes where they weren't applied before, or existing " + - "properties applied to new classes."); - } - - } finally { - siteModel.leaveCriticalSection(); - } -} - -/** - * - * Update a knowledge base to align with changes to the vitro annotation model - * in a new version of the ontology. The two versions of the ontology and the - * knowledge base to be updated are provided in the class constructor and are - * referenced via class level variables. - * - * Currently, this method only handles deletions of a ClassGroup - * - * Writes to the change log file, the error log file, and the incremental change - * knowledge base. - * - */ -public void updateAnnotationModel() throws IOException { - - // for each ClassGroup in the old vitro annotations model: if it is not in - // the new vitro annotations model and the site has no classes asserted to - // be in that class group then delete it. - - removeObsoleteAnnotations(); - - siteModel.enterCriticalSection(Lock.WRITE); - - try { - Model retractions = ModelFactory.createDefaultModel(); - - StmtIterator iter = oldTboxAnnotationsModel.listStatements((Resource) null, RDF.type, classGroupClass); - - while (iter.hasNext()) { - Statement stmt = iter.next(); - - if (!newTboxAnnotationsModel.contains(stmt) && !usesGroup(siteModel, stmt.getSubject())) { - long pre = retractions.size(); - retractions.add(siteModel.listStatements(stmt.getSubject(),(Property) null,(RDFNode)null)); - long post = retractions.size(); - if ((post - pre) > 0) { - logger.log("Removed the " + stmt.getSubject().getURI() + " ClassGroup from the annotations model"); - } - } - } - - if (retractions.size() > 0) { - siteModel.remove(retractions); - record.recordRetractions(retractions); - } - - } finally { - siteModel.leaveCriticalSection(); - } + try { + additions.add(subject, predicate, newObject); - // If we were going to handle add, this is the logic: - // for each ClassGroup in new old vitro annotations model: if it is not in - // the old vitro annotations and it is not in the site model, then - // add it. - -} + if (detailLogs) { + logger.log("Changed the value of property " + predicate.getURI() + + " of subject = " + subject.getURI() + + " from " + + (oldObject.isResource() ? ((Resource)oldObject).getURI() : ((Literal)oldObject).getLexicalForm()) + + " to " + + (newObject.isResource() ? ((Resource)newObject).getURI() : ((Literal)newObject).getLexicalForm()) + + " in the knowledge base:\n"); + } + } catch (Exception e) { + logger.logError("Error trying to change the value of property " + predicate.getURI() + + " of class = " + subject.getURI() + " in the knowledge base:\n" + e.getMessage()); + } + } + } + } -public boolean usesGroup(Model model, Resource theClassGroup) throws IOException { - - model.enterCriticalSection(Lock.READ); - - try { - return (model.contains((Resource) null, inClassGroupProp, theClassGroup) ? true : false); - } finally { - model.leaveCriticalSection(); - } -} + Model actualAdditions = additions.difference(retractions); + siteModel.add(actualAdditions); + record.recordAdditions(actualAdditions); + Model actualRetractions = retractions.difference(additions); + siteModel.remove(actualRetractions); + record.recordRetractions(actualRetractions); -public void removeObsoleteAnnotations() throws IOException { - - Resource subj1 = (ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM)).createResource("http://vivoweb.org/ontology/florida#StatewideGoalAndFocusArea"); - Resource obj1 = (ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM)).createResource("http://vivoweb.org/ontology#vitroClassGrouptopics"); - - Property subj2 = (ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM)).createProperty("http://vivoweb.org/ontology/florida#divisionOfSponsoredResearchNumber"); - Resource obj2 = (ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM)).createResource("http://vivoweb.org/ontology#vitroPropertyGroupidentifiers"); - - Property subj3 = (ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM)).createProperty("http://vivoweb.org/ontology/florida#statewideGoalAndFocusArea"); - Resource obj3 = (ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM)).createResource("http://vivoweb.org/ontology#vitroPropertyGroupoutreach"); - - Property inPropertyGroupProp = (ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM)).createProperty("http://vitro.mannlib.cornell.edu/ns/vitro/0.7#inPropertyGroup"); - - siteModel.enterCriticalSection(Lock.WRITE); - - try { - Model retractions = ModelFactory.createDefaultModel(); - - if (siteModel.contains(subj1, inClassGroupProp, obj1) ) { - retractions.add(subj1, inClassGroupProp, obj1); - logger.log("Removed statement " + ABoxUpdater.stmtString(subj1, inClassGroupProp, obj1) + " from the knowledge base (assumed to be obsolete)"); + long numAdded = actualAdditions.size(); + long numRemoved = actualRetractions.size(); + + // log summary of changes + if (numAdded > 0) { + logger.log("Updated the default vitro annotation value for " + + numAdded + " statements in the knowledge base"); + } + + if (numRemoved > 0) { + logger.log("Removed " + numRemoved + + " outdated vitro annotation property setting" + ((numRemoved > 1) ? "s" : "") + " from the knowledge base"); + } + + // Copy annotation property settings that were introduced in the new ontology + // into the site model. + // + + Model newAnnotationSettings = newTboxAnnotationsModel.difference(oldTboxAnnotationsModel); + Model newAnnotationSettingsToAdd = ModelFactory.createDefaultModel(); + StmtIterator newStmtIt = newAnnotationSettings.listStatements(); + while (newStmtIt.hasNext()) { + Statement stmt = newStmtIt.next(); + if (!siteModel.contains(stmt)) { + newAnnotationSettingsToAdd.add(stmt); + + if (detailLogs) { + logger.log( "adding Statement: subject = " + stmt.getSubject().getURI() + + " property = " + stmt.getPredicate().getURI() + + " object = " + (stmt.getObject().isLiteral() ? ((Literal)stmt.getObject()).getLexicalForm() + : ((Resource)stmt.getObject()).getURI())); + } + } + } + + siteModel.add(newAnnotationSettingsToAdd); + record.recordAdditions(newAnnotationSettingsToAdd); + + // log the additions - summary + if (newAnnotationSettingsToAdd.size() > 0) { + boolean plural = (newAnnotationSettingsToAdd.size() > 1); + logger.log("Added " + newAnnotationSettingsToAdd.size() + " new annotation property setting" + (plural ? "s" : "") + " to the knowledge base. This includes only " + + "existing annotation properties applied to existing classes where they weren't applied before, or existing " + + "properties applied to new classes."); + } + + } finally { + siteModel.leaveCriticalSection(); + } + } + + /** + * + * Update a knowledge base to align with changes to the vitro annotation model + * in a new version of the ontology. The two versions of the ontology and the + * knowledge base to be updated are provided in the class constructor and are + * referenced via class level variables. + * + * Currently, this method only handles deletions of a ClassGroup + * + * Writes to the change log file, the error log file, and the incremental change + * knowledge base. + * + */ + public void updateAnnotationModel() throws IOException { + + // for each ClassGroup in the old vitro annotations model: if it is not in + // the new vitro annotations model and the site has no classes asserted to + // be in that class group then delete it. + + removeObsoleteAnnotations(); + + siteModel.enterCriticalSection(Lock.WRITE); + + try { + Model retractions = ModelFactory.createDefaultModel(); + + StmtIterator iter = oldTboxAnnotationsModel.listStatements((Resource) null, RDF.type, classGroupClass); + + while (iter.hasNext()) { + Statement stmt = iter.next(); + + if (!newTboxAnnotationsModel.contains(stmt) && !usesGroup(siteModel, stmt.getSubject())) { + long pre = retractions.size(); + retractions.add(siteModel.listStatements(stmt.getSubject(),(Property) null,(RDFNode)null)); + long post = retractions.size(); + if ((post - pre) > 0) { + logger.log("Removed the " + stmt.getSubject().getURI() + " ClassGroup from the annotations model"); + } + } + } + + if (retractions.size() > 0) { + siteModel.remove(retractions); + record.recordRetractions(retractions); + } + + } finally { + siteModel.leaveCriticalSection(); } - if (siteModel.contains(subj2, inPropertyGroupProp, obj2) ) { - retractions.add(subj2, inPropertyGroupProp, obj2); - logger.log("Removed statement " + ABoxUpdater.stmtString(subj2, inPropertyGroupProp, obj2) + " from the knowledge base (assumed to be obsolete)"); - } + // If we were going to handle add, this is the logic: + // for each ClassGroup in new old vitro annotations model: if it is not in + // the old vitro annotations and it is not in the site model, then + // add it. - if (siteModel.contains(subj3, inPropertyGroupProp, obj3) ) { - retractions.add(subj3, inPropertyGroupProp, obj3); - logger.log("Removed statement " + ABoxUpdater.stmtString(subj3, inPropertyGroupProp, obj3) + " from the knowledge base (assumed to be obsolete)"); + } + + public boolean usesGroup(Model model, Resource theClassGroup) throws IOException { + + model.enterCriticalSection(Lock.READ); + + try { + return (model.contains((Resource) null, inClassGroupProp, theClassGroup) ? true : false); + } finally { + model.leaveCriticalSection(); } - - if (retractions.size() > 0) { - siteModel.remove(retractions); - record.recordRetractions(retractions); - } - - } finally { - siteModel.leaveCriticalSection(); - } -} + } + + public void removeObsoleteAnnotations() throws IOException { + + Resource subj1 = (ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM)).createResource("http://vivoweb.org/ontology/florida#StatewideGoalAndFocusArea"); + Resource obj1 = (ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM)).createResource("http://vivoweb.org/ontology#vitroClassGrouptopics"); + + Property subj2 = (ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM)).createProperty("http://vivoweb.org/ontology/florida#divisionOfSponsoredResearchNumber"); + Resource obj2 = (ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM)).createResource("http://vivoweb.org/ontology#vitroPropertyGroupidentifiers"); + + Property subj3 = (ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM)).createProperty("http://vivoweb.org/ontology/florida#statewideGoalAndFocusArea"); + Resource obj3 = (ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM)).createResource("http://vivoweb.org/ontology#vitroPropertyGroupoutreach"); + + Property inPropertyGroupProp = (ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM)).createProperty("http://vitro.mannlib.cornell.edu/ns/vitro/0.7#inPropertyGroup"); + + siteModel.enterCriticalSection(Lock.WRITE); + + try { + Model retractions = ModelFactory.createDefaultModel(); + + if (siteModel.contains(subj1, inClassGroupProp, obj1) ) { + retractions.add(subj1, inClassGroupProp, obj1); + logger.log("Removed statement " + ABoxUpdater.stmtString(subj1, inClassGroupProp, obj1) + " from the knowledge base (assumed to be obsolete)"); + } + + if (siteModel.contains(subj2, inPropertyGroupProp, obj2) ) { + retractions.add(subj2, inPropertyGroupProp, obj2); + logger.log("Removed statement " + ABoxUpdater.stmtString(subj2, inPropertyGroupProp, obj2) + " from the knowledge base (assumed to be obsolete)"); + } + + if (siteModel.contains(subj3, inPropertyGroupProp, obj3) ) { + retractions.add(subj3, inPropertyGroupProp, obj3); + logger.log("Removed statement " + ABoxUpdater.stmtString(subj3, inPropertyGroupProp, obj3) + " from the knowledge base (assumed to be obsolete)"); + } + + if (retractions.size() > 0) { + siteModel.remove(retractions); + record.recordRetractions(retractions); + } + + } finally { + siteModel.leaveCriticalSection(); + } + } + + public void renameProperty(AtomicOntologyChange changeObj) throws IOException { + Dataset dataset = new RDFServiceDataset(settings.getRDFService()); + Model userAnnotationsModel = dataset.getNamedModel( + JenaDataSourceSetupBase.JENA_TBOX_ASSERTIONS_MODEL); + if(changeObj.getNotes() != null && changeObj.getNotes().startsWith("cc:")) { + mergePropertyAnnotationsToPropertyConfig(changeObj, userAnnotationsModel); + } + Resource renamedProperty = userAnnotationsModel.getResource(changeObj.getSourceURI()); + userAnnotationsModel.removeAll(renamedProperty, null, (RDFNode) null); + userAnnotationsModel.removeAll(null, null, renamedProperty); + } + + private void mergePropertyAnnotationsToPropertyConfig(AtomicOntologyChange changeObj, + Model userAnnotationsModel) throws IOException { + String contextURI = VitroVocabulary.PROPERTY_CONFIG_DATA + changeObj.getNotes().substring(3); + String oldPropertyURI = changeObj.getSourceURI(); + + Model oldAnnotationsModel = settings.getOldTBoxAnnotationsModel(); + + String propertyAnnotationsQuery = + "PREFIX config: <" + VitroVocabulary.configURI + "> \n" + + "PREFIX vitro: <" + VitroVocabulary.vitroURI + "> \n" + + "CONSTRUCT { \n" + + " <" + oldPropertyURI + "> vitro:inPropertyGroupAnnot ?group . \n" + + " <" + oldPropertyURI + "> <" + RDFS.label.getURI() + "> ?label . \n" + + " <" + oldPropertyURI + "> vitro:displayRankAnnot ?displayRank . \n" + + " <" + oldPropertyURI + "> vitro:customEntryFormAnnot ?customForm . \n" + + " <" + oldPropertyURI + "> vitro:hiddenFromDisplayBelowRoleLevelAnnot ?displayLevel . \n" + + " <" + oldPropertyURI + "> vitro:prohibitedFromUpdateBelowRoleLevelAnnot ?updateLevel . \n " + + "} WHERE { \n" + + " { <" + oldPropertyURI + "> vitro:inPropertyGroupAnnot ?group } \n" + + " UNION { <" + oldPropertyURI + "> <" + RDFS.label.getURI() + "> ?label } \n" + + " UNION { <" + oldPropertyURI + "> vitro:displayRankAnnot ?displayRank } \n" + + " UNION { <" + oldPropertyURI + "> vitro:customEntryFormAnnot ?customForm } \n" + + " UNION { <" + oldPropertyURI + "> vitro:hiddenFromDisplayBelowRoleLevelAnnot ?displayLevel } \n" + + " UNION { <" + oldPropertyURI + "> vitro:prohibitedFromUpdateBelowRoleLevelAnnot ?updateLevel } \n " + + "} \n" ; + + Model userChangesModel = construct( + propertyAnnotationsQuery, userAnnotationsModel).difference( + construct(propertyAnnotationsQuery, oldAnnotationsModel)); + + String addQuery = "PREFIX config: <" + VitroVocabulary.configURI + "> \n" + + "PREFIX vitro: <" + VitroVocabulary.vitroURI + "> \n" + + "CONSTRUCT { \n" + + " ?configuration config:propertyGroup ?group . \n" + + " ?configuration config:displayName ?label . \n" + + " ?configuration vitro:displayRankAnnot ?displayRank . \n" + + " ?configuration vitro:customEntryFormAnnot ?customForm . \n" + + " ?configuration vitro:hiddenFromDisplayBelowRoleLevelAnnot ?displayLevel . \n" + + " ?configuration vitro:prohibitedFromUpdateBelowRoleLevelAnnot ?updateLevel . \n " + + "} WHERE { \n" + + " <" + contextURI + "> config:hasConfiguration ?configuration . \n" + + " OPTIONAL { <" + oldPropertyURI + "> vitro:inPropertyGroupAnnot ?group } \n" + + " OPTIONAL { <" + oldPropertyURI + "> <" + RDFS.label.getURI() + "> ?label } \n" + + " OPTIONAL { <" + oldPropertyURI + "> vitro:displayRankAnnot ?displayRank } \n" + + " OPTIONAL { <" + oldPropertyURI + "> vitro:customEntryFormAnnot ?customForm } \n" + + " OPTIONAL { <" + oldPropertyURI + "> vitro:hiddenFromDisplayBelowRoleLevelAnnot ?displayLevel } \n" + + " OPTIONAL { <" + oldPropertyURI + "> vitro:prohibitedFromUpdateBelowRoleLevelAnnot ?updateLevel } \n " + + "} \n" ; + + String retractQuery = "PREFIX config: <" + VitroVocabulary.configURI + "> \n" + + "PREFIX vitro: <" + VitroVocabulary.vitroURI + "> \n" + + "CONSTRUCT { \n" + + " <" + oldPropertyURI + "> config:propertyGroup ?rgroup . \n" + + " ?configuration config:displayName ?rlabel . \n" + + " ?configuration vitro:displayRankAnnot ?rdisplayRank . \n" + + " ?configuration vitro:customEntryFormAnnot ?rcustomForm . \n" + + " ?configuration vitro:hiddenFromDisplayBelowRoleLevelAnnot ?rdisplayLevel . \n" + + " ?configuration vitro:prohibitedFromUpdateBelowRoleLevelAnnot ?rupdateLevel . \n " + + "} WHERE { \n" + + " <" + contextURI + "> config:hasConfiguration ?configuration . \n" + + " OPTIONAL { <" + oldPropertyURI + "> vitro:inPropertyGroupAnnot ?group . \n" + + " ?configuration config:propertyGroup ?rgroup } \n" + + " OPTIONAL { <" + oldPropertyURI + "> <" + RDFS.label.getURI() + "> ?label . \n" + + " ?configuration config:displayName ?rlabel } \n " + + " OPTIONAL { <" + oldPropertyURI + "> vitro:displayRankAnnot ?displayRank . \n" + + " ?configuration vitro:displayRantAnnot ?rdisplayRank } \n " + + " OPTIONAL { <" + oldPropertyURI + "> vitro:customEntryFormAnnot ?customForm . \n" + + " ?configuration vitro:customEntryFormAnnot ?rcustomForm } \n" + + " OPTIONAL { <" + oldPropertyURI + "> vitro:hiddenFromDisplayBelowRoleLevelAnnot ?displayLevel . \n" + + " ?configuration vitro:hiddenFromDisplayBelowRoleLevelAnnot ?rdisplayLevel } \n" + + " OPTIONAL { <" + oldPropertyURI + "> vitro:prohibitedFromUpdateBelowRoleLevelAnnot ?updateLevel . \n " + + " ?configuration vitro:prohibitedFromUpdateBelowRoleLevelAnnot ?updateLevel } " + + "} \n" ; + + Model configModel = ModelFactory.createDefaultModel(); + String configFileName = settings.getQualifiedPropertyConfigFile(); + File file = new File(configFileName); + FileInputStream fis = new FileInputStream(file); + configModel.read(fis, null, "N3"); + + Model union = ModelFactory.createUnion(configModel, + userChangesModel); + + Model additions = construct(addQuery, union); + Model retractions = construct(retractQuery, union); + + if (additions.size() > 0 || retractions.size() > 0) { + configModel.remove(retractions); + log.info("Removing " + retractions.size() + " statements from " + contextURI); + configModel.add(additions); + log.info("Adding " + additions.size() + " statements from " + contextURI); + FileOutputStream fos = new FileOutputStream(file); + configModel.write(fos, "N3"); + } + } + + private Model construct(String queryStr, Model model) { + Query query = QueryFactory.create(queryStr); + QueryExecution qe = QueryExecutionFactory.create(query, model); + try { + return qe.execConstruct(); + } finally { + qe.close(); + } + } } \ No newline at end of file diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/UpdateSettings.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/UpdateSettings.java index f6e9cf9da..1e37ded8f 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/UpdateSettings.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/ontology/update/UpdateSettings.java @@ -5,6 +5,7 @@ package edu.cornell.mannlib.vitro.webapp.ontology.update; import com.hp.hpl.jena.ontology.OntModel; import edu.cornell.mannlib.vitro.webapp.dao.jena.OntModelSelector; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; public class UpdateSettings { @@ -20,6 +21,7 @@ public class UpdateSettings { private String errorLogFile; private String addedDataFile; private String removedDataFile; + private String qualifiedPropertyConfigFile; private String defaultNamespace; private OntModelSelector assertionOntModelSelector; private OntModelSelector inferenceOntModelSelector; @@ -37,6 +39,8 @@ public class UpdateSettings { private OntModel newDisplayModelFromFile; private OntModel loadedAtStartupDisplayModel; private OntModel oldDisplayModelVivoListViewConfig; + private RDFService rdfService; + public String getDataDir() { return dataDir; } @@ -118,7 +122,13 @@ public class UpdateSettings { public void setRemovedDataFile(String removedDataFile) { this.removedDataFile = removedDataFile; } - public String getDefaultNamespace() { + public String getQualifiedPropertyConfigFile() { + return qualifiedPropertyConfigFile; + } + public void setQualifiedPropertyConfigFile(String qualifiedPropertyConfigFile) { + this.qualifiedPropertyConfigFile = qualifiedPropertyConfigFile; + } + public String getDefaultNamespace() { return defaultNamespace; } public void setDefaultNamespace(String defaultNamespace) { @@ -223,6 +233,13 @@ public class UpdateSettings { return this.oldDisplayModelVivoListViewConfig; } + public RDFService getRDFService() { + return this.rdfService; + } + + public void setRDFService(RDFService rdfService) { + this.rdfService = rdfService; + } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/jena/RDFServiceJena.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/jena/RDFServiceJena.java index ddf192b84..b851fab9b 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/jena/RDFServiceJena.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/jena/RDFServiceJena.java @@ -6,13 +6,16 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.util.ArrayList; -import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; import java.util.Iterator; import java.util.List; +import java.util.concurrent.ConcurrentLinkedQueue; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import com.hp.hpl.jena.graph.Node; import com.hp.hpl.jena.graph.Triple; import com.hp.hpl.jena.query.DataSource; import com.hp.hpl.jena.query.Dataset; @@ -21,11 +24,9 @@ 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.QueryParseException; import com.hp.hpl.jena.query.QuerySolution; import com.hp.hpl.jena.query.ResultSet; import com.hp.hpl.jena.query.ResultSetFormatter; -import com.hp.hpl.jena.query.Syntax; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.ModelFactory; import com.hp.hpl.jena.rdf.model.RDFNode; @@ -129,6 +130,7 @@ public abstract class RDFServiceJena extends RDFServiceImpl implements RDFServic Resource s2 = (Resource) n; // now run yet another describe query String smallerTree = makeDescribe(s2); + log.debug(smallerTree); Query smallerTreeQuery = QueryFactory.create(smallerTree); QueryExecution qe3 = QueryExecutionFactory.create( smallerTreeQuery, tree); @@ -172,13 +174,17 @@ public abstract class RDFServiceJena extends RDFServiceImpl implements RDFServic StringBuffer queryBuff = new StringBuffer(); queryBuff.append("CONSTRUCT { \n"); - addStatementPatterns(stmtIt, queryBuff, !WHERE_CLAUSE); + List stmts = stmtIt.toList(); + stmts = sort(stmts); + addStatementPatterns(stmts, queryBuff, !WHERE_CLAUSE); queryBuff.append("} WHERE { \n"); if (graphURI != null) { queryBuff.append(" GRAPH <" + graphURI + "> { \n"); } stmtIt = model.listStatements(); - addStatementPatterns(stmtIt, queryBuff, WHERE_CLAUSE); + stmts = stmtIt.toList(); + stmts = sort(stmts); + addStatementPatterns(stmts, queryBuff, WHERE_CLAUSE); if (graphURI != null) { queryBuff.append(" } \n"); } @@ -208,11 +214,61 @@ public abstract class RDFServiceJena extends RDFServiceImpl implements RDFServic } } + private List sort(List stmts) { + List output = new ArrayList(); + int originalSize = stmts.size(); + List remaining = stmts; + ConcurrentLinkedQueue subjQueue = new ConcurrentLinkedQueue(); + for(Statement stmt : remaining) { + if(stmt.getSubject().isURIResource()) { + subjQueue.add(stmt.getSubject()); + break; + } + } + if (subjQueue.isEmpty()) { + throw new RuntimeException("No named subject in statement patterns"); + } + while(remaining.size() > 0) { + if(subjQueue.isEmpty()) { + subjQueue.add(remaining.get(0).getSubject()); + } + while(!subjQueue.isEmpty()) { + Resource subj = subjQueue.poll(); + List temp = new ArrayList(); + for (Statement stmt : remaining) { + if(stmt.getSubject().equals(subj)) { + output.add(stmt); + if (stmt.getObject().isResource()) { + subjQueue.add((Resource) stmt.getObject()); + } + } else { + temp.add(stmt); + } + } + remaining = temp; + } + } + if(output.size() != originalSize) { + throw new RuntimeException("original list size was " + originalSize + + " but sorted size is " + output.size()); + } + return output; + } + + private String getHexString(Node node) { + String label = node.getBlankNodeLabel().replaceAll("\\W", "").toUpperCase(); + if (label.length() > 7) { + return label.substring(label.length() - 7); + } else { + return label; + } + } + private static final boolean WHERE_CLAUSE = true; - private void addStatementPatterns(StmtIterator stmtIt, StringBuffer patternBuff, boolean whereClause) { - while(stmtIt.hasNext()) { - Triple t = stmtIt.next().asTriple(); + private void addStatementPatterns(List stmts, StringBuffer patternBuff, boolean whereClause) { + for(Statement stmt : stmts) { + Triple t = stmt.asTriple(); patternBuff.append(SparqlGraph.sparqlNodeDelete(t.getSubject(), null)); patternBuff.append(" "); patternBuff.append(SparqlGraph.sparqlNodeDelete(t.getPredicate(), null)); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sparql/RDFServiceSparql.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sparql/RDFServiceSparql.java index 929303d4a..d890a1625 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sparql/RDFServiceSparql.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sparql/RDFServiceSparql.java @@ -9,6 +9,7 @@ import java.io.StringWriter; import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.concurrent.ConcurrentLinkedQueue; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager; @@ -715,7 +716,9 @@ public class RDFServiceSparql extends RDFServiceImpl implements RDFService { if (graphURI != null) { queryBuff.append(" GRAPH <" + graphURI + "> { \n"); } - addStatementPatterns(stmtIt, queryBuff, !WHERE_CLAUSE); + List stmts = stmtIt.toList(); + sort(stmts); + addStatementPatterns(stmts, queryBuff, !WHERE_CLAUSE); if (graphURI != null) { queryBuff.append(" } \n"); } @@ -724,7 +727,9 @@ public class RDFServiceSparql extends RDFServiceImpl implements RDFService { queryBuff.append(" GRAPH <" + graphURI + "> { \n"); } stmtIt = model.listStatements(); - addStatementPatterns(stmtIt, queryBuff, WHERE_CLAUSE); + stmts = stmtIt.toList(); + sort(stmts); + addStatementPatterns(stmts, queryBuff, WHERE_CLAUSE); if (graphURI != null) { queryBuff.append(" } \n"); } @@ -736,11 +741,53 @@ public class RDFServiceSparql extends RDFServiceImpl implements RDFService { executeUpdate(queryBuff.toString()); } + private List sort(List stmts) { + List output = new ArrayList(); + int originalSize = stmts.size(); + List remaining = stmts; + ConcurrentLinkedQueue subjQueue = + new ConcurrentLinkedQueue(); + for(Statement stmt : remaining) { + if(stmt.getSubject().isURIResource()) { + subjQueue.add(stmt.getSubject()); + break; + } + } + if (subjQueue.isEmpty()) { + throw new RuntimeException("No named subject in statement patterns"); + } + while(remaining.size() > 0) { + if(subjQueue.isEmpty()) { + subjQueue.add(remaining.get(0).getSubject()); + } + while(!subjQueue.isEmpty()) { + com.hp.hpl.jena.rdf.model.Resource subj = subjQueue.poll(); + List temp = new ArrayList(); + for (Statement stmt : remaining) { + if(stmt.getSubject().equals(subj)) { + output.add(stmt); + if (stmt.getObject().isResource()) { + subjQueue.add((com.hp.hpl.jena.rdf.model.Resource) stmt.getObject()); + } + } else { + temp.add(stmt); + } + } + remaining = temp; + } + } + if(output.size() != originalSize) { + throw new RuntimeException("original list size was " + originalSize + + " but sorted size is " + output.size()); + } + return output; + } + private static final boolean WHERE_CLAUSE = true; - private void addStatementPatterns(StmtIterator stmtIt, StringBuffer patternBuff, boolean whereClause) { - while(stmtIt.hasNext()) { - Triple t = stmtIt.next().asTriple(); + private void addStatementPatterns(List stmts, StringBuffer patternBuff, boolean whereClause) { + for(Statement stmt : stmts) { + Triple t = stmt.asTriple(); patternBuff.append(SparqlGraph.sparqlNodeDelete(t.getSubject(), null)); patternBuff.append(" "); patternBuff.append(SparqlGraph.sparqlNodeDelete(t.getPredicate(), null)); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasoner.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasoner.java index b0cb19d29..4374f0b58 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasoner.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasoner.java @@ -251,18 +251,24 @@ public class SimpleReasoner extends StatementListener { return; } - OntClass subject = tboxModel.getOntClass((stmt.getSubject()).getURI()); - if (subject == null) { - log.debug("didn't find subject class in the tbox: " - + (stmt.getSubject()).getURI()); - return; - } - - OntClass object = tboxModel.getOntClass(((Resource)stmt.getObject()).getURI()); - if (object == null) { - log.debug("didn't find object class in the tbox: " - + ((Resource)stmt.getObject()).getURI()); - return; + OntClass subject, object; + tboxModel.enterCriticalSection(Lock.READ); + try { + subject = tboxModel.getOntClass((stmt.getSubject()).getURI()); + if (subject == null) { + log.debug("didn't find subject class in the tbox: " + + (stmt.getSubject()).getURI()); + return; + } + + object = tboxModel.getOntClass(((Resource)stmt.getObject()).getURI()); + if (object == null) { + log.debug("didn't find object class in the tbox: " + + ((Resource)stmt.getObject()).getURI()); + return; + } + } finally { + tboxModel.leaveCriticalSection(); } if (stmt.getPredicate().equals(RDFS.subClassOf)) { @@ -1672,6 +1678,10 @@ public class SimpleReasoner extends StatementListener { typeURIs = getRemainingAssertedTypeURIs(stmt.getSubject()); } removedABoxTypeAssertion(stmt, inferenceModel, typeURIs); + } else if (doSameAs && stmt.getPredicate().equals(OWL.sameAs)) { + removedABoxSameAsAssertion(stmt, inferenceModel); + } else { + removedABoxAssertion(stmt, inferenceModel); } doPlugins(ModelUpdate.Operation.RETRACT,stmt); } catch (NullPointerException npe) { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/AssembleModelsSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/AssembleModelsSetup.java deleted file mode 100644 index d95c4fc68..000000000 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/AssembleModelsSetup.java +++ /dev/null @@ -1,85 +0,0 @@ -/* $This file is distributed under the terms of the license in /doc/license.txt$ */ - -package edu.cornell.mannlib.vitro.webapp.servlet.setup; - -import java.io.InputStream; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; - -import javax.servlet.ServletContextEvent; -import javax.servlet.ServletContextListener; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import com.hp.hpl.jena.assembler.Assembler; -import com.hp.hpl.jena.ontology.OntModel; -import com.hp.hpl.jena.rdf.model.Model; -import com.hp.hpl.jena.rdf.model.ModelFactory; -import com.hp.hpl.jena.rdf.model.Resource; -import com.hp.hpl.jena.rdf.model.ResourceFactory; -import com.hp.hpl.jena.util.iterator.ExtendedIterator; -import com.hp.hpl.jena.vocabulary.RDF; - -import edu.cornell.mannlib.vitro.webapp.dao.ModelAccess; -import edu.cornell.mannlib.vitro.webapp.dao.jena.ModelSynchronizer; - -/** - * This is the beginning of a more sane and flexible model management system, - * especially necessary for DataStaR. - * Don't use it yet; it's going to change. - * (That part is still insane, I know.) - * @author bjl23 - */ -public class AssembleModelsSetup implements ServletContextListener { - - private static final Log log = LogFactory.getLog(AssembleModelsSetup.class); - - private List assembledModels = new LinkedList(); - - private String ASSEMBLERS_DIR_PATH = "/WEB-INF/assemblers/"; - private Resource ASSEMBLER_OBJECT = ResourceFactory.createProperty("http://jena.hpl.hp.com/2005/11/Assembler#Object"); - private String SYNTAX = "N3"; - - public void contextInitialized(ServletContextEvent sce) { - OntModel jenaOntModel = ModelAccess.on(sce.getServletContext()).getBaseOntModel(); - // read assemblers out of assemblers directory - Set pathSet = sce.getServletContext().getResourcePaths(ASSEMBLERS_DIR_PATH); - for (String path : (Set)pathSet) { - InputStream assemblerInputStream = sce.getServletContext().getResourceAsStream(path); - Model assemblerModel = ModelFactory.createDefaultModel(); - try { - assemblerModel.read(assemblerInputStream, null, SYNTAX); - ExtendedIterator assemblerIt = assemblerModel.listResourcesWithProperty(RDF.type,ASSEMBLER_OBJECT); - while (assemblerIt.hasNext()) { - Resource assemblerObj = (Resource) assemblerIt.next(); - Model assembledModel = Assembler.general.openModel(assemblerObj); - /* special stuff here */ - Model memModel = ModelFactory.createDefaultModel(); - memModel.add(assembledModel); - memModel.register(new ModelSynchronizer(assembledModel)); - /* end special stuff */ - if (assembledModel != null) { - jenaOntModel.addSubModel(memModel); - } - } - if (assemblerIt != null) { - assemblerIt.close(); - } - } catch (Exception e) { - log.error("Unable to use assembler at "+path); - } - } - System.out.println("ContextListener AssembleModelsSetup done"); - } - - public void contextDestroyed(ServletContextEvent sce) { - for (Model model : assembledModels) { - if (model != null) { - model.close(); - } - } - } - -} 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 b84913c54..c5b6cbf3d 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 @@ -56,7 +56,7 @@ public class SimpleReasonerSetup implements ServletContextListener { OntModelSelector inferencesOms = ModelAccess.on(ctx).getInferenceOntModelSelector(); OntModelSelector unionOms = ModelAccess.on(ctx).getUnionOntModelSelector(); - WebappDaoFactoryJena wadf = (WebappDaoFactoryJena) ModelAccess.on(ctx).getWebappDaoFactory(); + WebappDaoFactory wadf = ModelAccess.on(ctx).getWebappDaoFactory(); if (!assertionsOms.getTBoxModel().getProfile().NAMESPACE().equals(OWL.NAMESPACE.getNameSpace())) { log.error("Not connecting Pellet reasoner - the TBox assertions model is not an OWL model"); @@ -75,28 +75,24 @@ public class SimpleReasonerSetup implements ServletContextListener { sce.getServletContext().setAttribute("pelletListener",pelletListener); sce.getServletContext().setAttribute("pelletOntModel", pelletListener.getPelletModel()); - if (wadf != null) { - wadf.setPelletListener(pelletListener); + if (wadf instanceof WebappDaoFactoryJena) { + ((WebappDaoFactoryJena) wadf).setPelletListener(pelletListener); } log.info("Pellet reasoner connected for the TBox"); - // set up simple reasoning for the ABox - - DataSource bds = JenaDataSourceSetupBase - .getApplicationDataSource(ctx); - String dbType = ConfigurationProperties.getBean(ctx).getProperty( // database type - "VitroConnection.DataSource.dbtype","MySQL"); - + // set up simple reasoning for the ABox + RDFService rdfService = RDFServiceUtils.getRDFServiceFactory(ctx).getRDFService(); Dataset dataset = new RDFServiceDataset(rdfService); Model rebuildModel = dataset.getNamedModel(JENA_INF_MODEL_REBUILD); - Model scratchModel = dataset.getNamedModel(JENA_INF_MODEL_SCRATCHPAD); + Model scratchModel = dataset.getNamedModel(JENA_INF_MODEL_SCRATCHPAD); + Model inferenceModel = dataset.getNamedModel(JenaDataSourceSetupBase.JENA_INF_MODEL); // the simple reasoner will register itself as a listener to the ABox assertions SimpleReasoner simpleReasoner = new SimpleReasoner( - unionOms.getTBoxModel(), rdfService, inferencesOms.getABoxModel(), rebuildModel, scratchModel); + unionOms.getTBoxModel(), rdfService, inferenceModel, rebuildModel, scratchModel); sce.getServletContext().setAttribute(SimpleReasoner.class.getName(),simpleReasoner); StartupStatus ss = StartupStatus.getBean(ctx); @@ -114,19 +110,6 @@ public class SimpleReasonerSetup implements ServletContextListener { } simpleReasoner.setPluginList(pluginList); - - if (isRecomputeRequired(sce.getServletContext())) { - log.info("ABox inference recompute required."); - waitForTBoxReasoning(pelletListener); - if (JenaDataSourceSetupBase.isFirstStartup()) { - simpleReasoner.recompute(); - } else { - log.info("starting ABox inference recompute in a separate thread."); - new Thread(new ABoxRecomputer(simpleReasoner),"ABoxRecomputer").start(); - } - - } - SimpleReasonerTBoxListener simpleReasonerTBoxListener = new SimpleReasonerTBoxListener(simpleReasoner); sce.getServletContext().setAttribute(SimpleReasonerTBoxListener.class.getName(),simpleReasonerTBoxListener); assertionsOms.getTBoxModel().register(simpleReasonerTBoxListener); @@ -139,16 +122,21 @@ public class SimpleReasonerSetup implements ServletContextListener { } } - private void waitForTBoxReasoning(PelletListener pelletListener) + public static void waitForTBoxReasoning(ServletContextEvent sce) throws InterruptedException { - int sleeps = 0; - while (sleeps < 1000 && pelletListener.isReasoning()) { - if ((sleeps % 10) == 0) { // print message at 10 second intervals - log.info("Waiting for initial TBox reasoning to complete"); - } - Thread.sleep(1000); - sleeps++; - } + PelletListener pelletListener = (PelletListener) sce.getServletContext().getAttribute("pelletListener"); + if (pelletListener == null) { + return ; + } + int sleeps = 0; + // sleep at least once to make sure the TBox reasoning gets started + while ((0 == sleeps) || ((sleeps < 1000) && pelletListener.isReasoning())) { + if ((sleeps % 10) == 0) { // print message at 10 second intervals + log.info("Waiting for initial TBox reasoning to complete"); + } + Thread.sleep(1000); + sleeps++; + } } @Override @@ -196,7 +184,7 @@ public class SimpleReasonerSetup implements ServletContextListener { ctx.setAttribute(RECOMPUTE_REQUIRED_ATTR, true); } - private static boolean isRecomputeRequired(ServletContext ctx) { + public static boolean isRecomputeRequired(ServletContext ctx) { return (ctx.getAttribute(RECOMPUTE_REQUIRED_ATTR) != null); } @@ -210,19 +198,6 @@ public class SimpleReasonerSetup implements ServletContextListener { private static boolean isMSTComputeRequired(ServletContext ctx) { return (ctx.getAttribute(MSTCOMPUTE_REQUIRED_ATTR) != null); } - - private class ABoxRecomputer implements Runnable { - - private SimpleReasoner simpleReasoner; - - public ABoxRecomputer(SimpleReasoner simpleReasoner) { - this.simpleReasoner = simpleReasoner; - } - - public void run() { - simpleReasoner.recompute(); - } - } /** * Read the names of the plugin classes classes. 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 6dda504f2..d02bbeceb 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 @@ -41,6 +41,9 @@ import edu.cornell.mannlib.vitro.webapp.dao.ModelAccess; 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; /** @@ -54,10 +57,11 @@ public class UpdateKnowledgeBase implements ServletContextListener { private final static Log log = LogFactory.getLog(UpdateKnowledgeBase.class); private static final String DATA_DIR = "/WEB-INF/ontologies/update/"; + private static final String DIFF_FILE = DATA_DIR + "diff.tab.txt"; + private static final String ASK_QUERY_FILE = DATA_DIR + "askUpdated.sparql"; + private static final String SUCCESS_ASSERTIONS_FILE = DATA_DIR + "success.n3"; private static final String OLD_TBOX_MODEL_DIR = DATA_DIR + "oldVersion/"; - private static final String NEW_TBOX_MODEL_DIR = "/WEB-INF/filegraph/tbox/"; private static final String OLD_TBOX_ANNOTATIONS_DIR = DATA_DIR + "oldAnnotations/"; - private static final String NEW_TBOX_ANNOTATIONS_DIR = "/WEB-INF/ontologies/user/tbox/"; //For display model migration private static final String OLD_DISPLAYMODEL_TBOX_PATH = DATA_DIR + "oldDisplayModel/displayTBOX.n3"; private static final String NEW_DISPLAYMODEL_TBOX_PATH = "/WEB-INF/ontologies/app/menuload/displayTBOX.n3"; @@ -72,78 +76,136 @@ public class UpdateKnowledgeBase implements ServletContextListener { ServletContext ctx = sce.getServletContext(); StartupStatus ss = StartupStatus.getBean(ctx); + boolean migrationChangesMade = false; + try { UpdateSettings settings = new UpdateSettings(); putReportingPathsIntoSettings(ctx, settings); + putNonReportingPathsIntoSettings(ctx, settings); + SimpleReasonerSetup.waitForTBoxReasoning(sce); + WebappDaoFactory wadf = ModelAccess.on(ctx).getWebappDaoFactory(); settings.setDefaultNamespace(wadf.getDefaultNamespace()); settings.setAssertionOntModelSelector(ModelAccess.on(ctx).getBaseOntModelSelector()); settings.setInferenceOntModelSelector(ModelAccess.on(ctx).getInferenceOntModelSelector()); settings.setUnionOntModelSelector(ModelAccess.on(ctx).getUnionOntModelSelector()); + + ConfigurationProperties props = ConfigurationProperties.getBean(ctx); + Path homeDir = Paths.get(props.getProperty("vitro.home")); + settings.setDisplayModel(ModelAccess.on(ctx).getDisplayModel()); + OntModel oldTBoxModel = loadModelFromDirectory(ctx.getRealPath(OLD_TBOX_MODEL_DIR)); + settings.setOldTBoxModel(oldTBoxModel); + OntModel newTBoxModel = loadModelFromDirectory(createDirectory(homeDir, "rdf", "tbox", "filegraph").toString()); + settings.setNewTBoxModel(newTBoxModel); + OntModel oldTBoxAnnotationsModel = loadModelFromDirectory(ctx.getRealPath(OLD_TBOX_ANNOTATIONS_DIR)); + settings.setOldTBoxAnnotationsModel(oldTBoxAnnotationsModel); + OntModel newTBoxAnnotationsModel = loadModelFromDirectory(createDirectory(homeDir, "rdf", "tbox", "firsttime").toString()); + settings.setNewTBoxAnnotationsModel(newTBoxAnnotationsModel); + settings.setRDFService(RDFServiceUtils.getRDFServiceFactory(ctx).getRDFService()); + boolean tryMigrateDisplay = true; try { - settings.setDisplayModel(ModelAccess.on(ctx).getDisplayModel()); - OntModel oldTBoxModel = loadModelFromDirectory(ctx.getRealPath(OLD_TBOX_MODEL_DIR)); - settings.setOldTBoxModel(oldTBoxModel); - OntModel newTBoxModel = loadModelFromDirectory(ctx.getRealPath(NEW_TBOX_MODEL_DIR)); - settings.setNewTBoxModel(newTBoxModel); - OntModel oldTBoxAnnotationsModel = loadModelFromDirectory(ctx.getRealPath(OLD_TBOX_ANNOTATIONS_DIR)); - settings.setOldTBoxAnnotationsModel(oldTBoxAnnotationsModel); - OntModel newTBoxAnnotationsModel = loadModelFromDirectory(ctx.getRealPath(NEW_TBOX_ANNOTATIONS_DIR)); - settings.setNewTBoxAnnotationsModel(newTBoxAnnotationsModel); - //Display model tbox and display metadata - //old display model tbox model - OntModel oldDisplayModelTboxModel = loadModelFromFile(ctx.getRealPath(OLD_DISPLAYMODEL_TBOX_PATH)); - settings.setOldDisplayModelTboxModel(oldDisplayModelTboxModel); - //new display model tbox model - OntModel newDisplayModelTboxModel = loadModelFromFile(ctx.getRealPath(NEW_DISPLAYMODEL_TBOX_PATH)); - settings.setNewDisplayModelTboxModel(newDisplayModelTboxModel); - //old display model display model metadata - OntModel oldDisplayModelDisplayMetadataModel = loadModelFromFile(ctx.getRealPath(OLD_DISPLAYMODEL_DISPLAYMETADATA_PATH)); - settings.setOldDisplayModelDisplayMetadataModel(oldDisplayModelDisplayMetadataModel); - //new display model display model metadata - OntModel newDisplayModelDisplayMetadataModel = loadModelFromFile(ctx.getRealPath(NEW_DISPLAYMODEL_DISPLAYMETADATA_PATH)); - settings.setNewDisplayModelDisplayMetadataModel(newDisplayModelDisplayMetadataModel); - //Get new display model - OntModel newDisplayModelFromFile = loadModelFromFile(ctx.getRealPath(NEW_DISPLAYMODEL_PATH)); - settings.setNewDisplayModelFromFile(newDisplayModelFromFile); - OntModel loadedAtStartupFiles = loadModelFromDirectory(ctx.getRealPath(LOADED_STARTUPT_DISPLAYMODEL_DIR)); - settings.setLoadedAtStartupDisplayModel(loadedAtStartupFiles); - OntModel oldDisplayModelVivoListView = loadModelFromFile(ctx.getRealPath(OLD_DISPLAYMODEL_VIVOLISTVIEW_PATH)); - settings.setVivoListViewConfigDisplayModel(oldDisplayModelVivoListView); + //Display model tbox and display metadata + //old display model tbox model + OntModel oldDisplayModelTboxModel = loadModelFromFile(ctx.getRealPath(OLD_DISPLAYMODEL_TBOX_PATH)); + settings.setOldDisplayModelTboxModel(oldDisplayModelTboxModel); + //new display model tbox model + OntModel newDisplayModelTboxModel = loadModelFromFile(ctx.getRealPath(NEW_DISPLAYMODEL_TBOX_PATH)); + settings.setNewDisplayModelTboxModel(newDisplayModelTboxModel); + //old display model display model metadata + OntModel oldDisplayModelDisplayMetadataModel = loadModelFromFile(ctx.getRealPath(OLD_DISPLAYMODEL_DISPLAYMETADATA_PATH)); + settings.setOldDisplayModelDisplayMetadataModel(oldDisplayModelDisplayMetadataModel); + //new display model display model metadata + OntModel newDisplayModelDisplayMetadataModel = loadModelFromFile(ctx.getRealPath(NEW_DISPLAYMODEL_DISPLAYMETADATA_PATH)); + settings.setNewDisplayModelDisplayMetadataModel(newDisplayModelDisplayMetadataModel); + //Get new display model + OntModel newDisplayModelFromFile = loadModelFromFile(ctx.getRealPath(NEW_DISPLAYMODEL_PATH)); + settings.setNewDisplayModelFromFile(newDisplayModelFromFile); + OntModel loadedAtStartupFiles = loadModelFromDirectory(ctx.getRealPath(LOADED_STARTUPT_DISPLAYMODEL_DIR)); + settings.setLoadedAtStartupDisplayModel(loadedAtStartupFiles); + OntModel oldDisplayModelVivoListView = loadModelFromFile(ctx.getRealPath(OLD_DISPLAYMODEL_VIVOLISTVIEW_PATH)); + settings.setVivoListViewConfigDisplayModel(oldDisplayModelVivoListView); + } catch (ModelFileNotFoundException e) { + // expected if no display migration was intended + tryMigrateDisplay = false; } catch (Exception e) { - log.info("unable to read display model migration files, display model not migrated. " + e.getMessage()); - tryMigrateDisplay = false; + log.info("Unable to read display model migration files. ", e); + tryMigrateDisplay = false; } - - try { - KnowledgeBaseUpdater ontologyUpdater = new KnowledgeBaseUpdater(settings); - - try { - if (ontologyUpdater.updateRequired(ctx)) { - ctx.setAttribute(KBM_REQURIED_AT_STARTUP, Boolean.TRUE); - ontologyUpdater.update(ctx); - if (tryMigrateDisplay) { - try { - migrateDisplayModel(settings); - log.info("Migrated display model"); - } catch (Exception e) { - log.warn("unable to successfully update display model: " + e.getMessage()); - } - } - } - } catch (Exception ioe) { - ss.fatal(this, "Exception updating knowledge base for ontology changes: ", ioe); - } - } catch (Throwable t){ - ss.fatal(this, "Exception updating knowledge base for ontology changes: ", t); - } - } catch (Throwable t) { - ss.fatal(this, "Exception updating knowledge base for ontology changes: ", t); + + + KnowledgeBaseUpdater ontologyUpdater = new KnowledgeBaseUpdater(settings); + boolean requiredUpdate = ontologyUpdater.updateRequired(ctx); + + try { + ctx.setAttribute(KBM_REQURIED_AT_STARTUP, Boolean.TRUE); + log.info("Data migration required"); + migrationChangesMade = ontologyUpdater.update(ctx); + if (tryMigrateDisplay) { + try { + migrateDisplayModel(settings); + log.info("Migrated display model"); + } catch (Exception e) { + log.warn("unable to successfully update display model: " + e.getMessage()); + } + } + // reload the display model since the TBoxUpdater may have + // modified it + new ApplicationModelSetup().contextInitialized(sce); + } catch (Exception ioe) { + 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(); + } + } + + } 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(); + } + } + + + /** + * Set the paths for the files that specify how to perform the update + */ + private void putNonReportingPathsIntoSettings(ServletContext ctx, UpdateSettings settings) { + settings.setAskUpdatedQueryFile(ctx.getRealPath(ASK_QUERY_FILE)); + settings.setDiffFile(ctx.getRealPath(DIFF_FILE)); + settings.setSparqlConstructAdditionsDir(ctx.getRealPath(DATA_DIR + "sparqlConstructs/additions")); + settings.setSparqlConstructDeletionsDir(ctx.getRealPath(DATA_DIR + "sparqlConstructs/deletions")); + settings.setSuccessAssertionsFile(ctx.getRealPath(SUCCESS_ASSERTIONS_FILE)); + settings.setSuccessRDFFormat("N3"); + } + /** * Create the directories where we will report on the update. * Put the paths for the directories and files into the settings object. @@ -156,14 +218,6 @@ public class UpdateKnowledgeBase implements ServletContextListener { settings.setDataDir(dataDir.toString()); StartupStatus.getBean(ctx).info(this, "Updating knowledge base: reports are in '" + dataDir + "'"); - settings.setAskUpdatedQueryFile(dataDir.resolve("askUpdated.sparql").toString()); - settings.setDiffFile(dataDir.resolve("diff.tab.txt").toString()); - settings.setSuccessAssertionsFile(dataDir.resolve("success.n3").toString()); - settings.setSuccessRDFFormat("N3"); - - settings.setSparqlConstructAdditionsDir(createDirectory(dataDir, "sparqlConstructs", "additions").toString()); - settings.setSparqlConstructDeletionsDir(createDirectory(dataDir, "sparqlConstructs", "deletions").toString()); - Path changedDir = createDirectory(dataDir, "changedData"); settings.setAddedDataFile(changedDir.resolve("addedData.n3").toString()); settings.setRemovedDataFile(changedDir.resolve("removedData.n3").toString()); @@ -171,8 +225,19 @@ public class UpdateKnowledgeBase implements ServletContextListener { Path logDir = createDirectory(dataDir, "logs"); settings.setLogFile(logDir.resolve(timestampedFileName("knowledgeBaseUpdate", "log")).toString()); settings.setErrorLogFile(logDir.resolve(timestampedFileName("knowledgeBaseUpdate.error", "log")).toString()); + + Path qualifiedPropertyConfigFile = getFilePath(homeDir, "rdf", "display", "everytime", "PropertyConfig.n3"); + settings.setQualifiedPropertyConfigFile(qualifiedPropertyConfigFile.toString()); } + private Path getFilePath(Path parent, String... children) throws IOException { + Path path = parent; + for (String child : children) { + path = path.resolve(child); + } + return path; + } + private Path createDirectory(Path parent, String... children) throws IOException { Path dir = parent; for (String child : children) { 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 9aab09eab..ee25e2c07 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/ApplicationConfigurationOntologyUtils.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/ApplicationConfigurationOntologyUtils.java @@ -10,100 +10,119 @@ import javax.servlet.ServletContext; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +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.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.Resource; +import com.hp.hpl.jena.rdf.model.ResourceFactory; +import com.hp.hpl.jena.vocabulary.RDFS; +import edu.cornell.mannlib.vitro.webapp.beans.Individual; import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty; +import edu.cornell.mannlib.vitro.webapp.beans.VClass; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.dao.ModelAccess; import edu.cornell.mannlib.vitro.webapp.dao.ModelAccess.ModelID; +import edu.cornell.mannlib.vitro.webapp.dao.ObjectPropertyDao; +import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; +import edu.cornell.mannlib.vitro.webapp.dao.jena.WebappDaoFactoryJena; public class ApplicationConfigurationOntologyUtils { private static final Log log = LogFactory.getLog(ApplicationConfigurationOntologyUtils.class); - public static List getAdditionalFauxSubpropertiesForList(List propList, VitroRequest vreq) { + public static List getAdditionalFauxSubpropertiesForList(List propList, Individual subject, VitroRequest vreq) { ServletContext ctx = vreq.getSession().getServletContext(); Model displayModel = ModelAccess.on(ctx).getDisplayModel(); Model tboxModel = ModelAccess.on(ctx).getOntModel(ModelID.UNION_TBOX); - return getAdditionalFauxSubpropertiesForList(propList, displayModel, tboxModel); + return getAdditionalFauxSubpropertiesForList(propList, subject, displayModel, tboxModel); } + public static List getAdditionalFauxSubproperties(ObjectProperty prop, + Individual subject, + Model tboxModel, + Model union) { + + List additionalProps = new ArrayList(); + String queryStr = "PREFIX rdfs: \n" + + "PREFIX config: \n" + + "PREFIX vitro: \n" + + "SELECT DISTINCT ?range ?domain ?property WHERE { \n" + + " ?context config:configContextFor ?property . \n" + + " ?context config:qualifiedBy ?range . \n" + + " ?context config:hasConfiguration ?configuration . \n" + + " ?configuration a config:ObjectPropertyDisplayConfig . \n" + + " OPTIONAL { ?context config:qualifiedByDomain ?domain } \n" + + "}"; + + if(prop != null) { + log.debug("Checking " + prop.getURI() + " for additional properties"); + queryStr = queryStr.replaceAll("For \\?property", "For <" + prop.getURI() + ">"); + } + log.debug(queryStr); + Query q = QueryFactory.create(queryStr); + QueryExecution qe = QueryExecutionFactory.create(q, union); + WebappDaoFactory wadf = new WebappDaoFactoryJena( + ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM, union)); + ObjectPropertyDao opDao = wadf.getObjectPropertyDao(); + try { + ResultSet rs = qe.execSelect(); + while (rs.hasNext()) { + QuerySolution qsoln = rs.nextSolution(); + log.debug(qsoln); + String opURI = (prop != null) ? prop.getURI() : qsoln.getResource( + "property").getURI(); + Resource domainRes = qsoln.getResource("domain"); + String domainURI = (domainRes != null) ? domainRes.getURI() : null; + String rangeURI = qsoln.getResource("range").getURI(); + if (appropriateDomain(domainRes, subject, tboxModel)) { + additionalProps.add(opDao.getObjectPropertyByURIs( + opURI, domainURI, rangeURI)); + } + } + } finally { + qe.close(); + } + return additionalProps; + } + public static List getAdditionalFauxSubpropertiesForList(List propList, + Individual subject, Model displayModel, Model tboxModel) { + List additionalProps = new ArrayList(); Model union = ModelFactory.createUnion(displayModel, tboxModel); - String propQuery = "PREFIX rdfs: \n" + - "PREFIX config: \n" + - "PREFIX vitro: \n" + - "SELECT ?range ?label ?group ?customForm WHERE { \n" + - " ?p rdfs:subPropertyOf ?property . \n" + - " ?context config:configContextFor ?p . \n" + - " ?context config:qualifiedBy ?range . \n" + - " ?context config:hasConfiguration ?configuration . \n" + - " OPTIONAL { ?configuration config:propertyGroup ?group } \n" + - " OPTIONAL { ?configuration config:displayName ?label } \n" + - " OPTIONAL { ?configuration vitro:customEntryFormAnnot ?customForm } \n" + - "}"; - - for (ObjectProperty op : propList) { - log.debug("Checking " + op.getURI() + " for additional properties"); - String queryStr = propQuery.replaceAll("\\?property", "<" + op.getURI() + ">"); - log.debug(queryStr); - Query q = QueryFactory.create(queryStr); - QueryExecution qe = QueryExecutionFactory.create(q, union); - try { - ResultSet rs = qe.execSelect(); - while (rs.hasNext()) { - ObjectProperty newProp = new ObjectProperty(); - newProp.setURI(op.getURI()); - QuerySolution qsoln = rs.nextSolution(); - log.debug(qsoln); - Resource rangeRes = qsoln.getResource("range"); - if (rangeRes != null) { - newProp.setRangeVClassURI(rangeRes.getURI()); - } else { - newProp.setRangeVClassURI(op.getRangeVClassURI()); - } - Resource groupRes = qsoln.getResource("group"); - if (groupRes != null) { - newProp.setGroupURI(groupRes.getURI()); - } else { - newProp.setGroupURI(op.getURI()); - } - Literal labelLit = qsoln.getLiteral("label"); - if (labelLit != null) { - newProp.setDomainPublic(labelLit.getLexicalForm()); - } else { - newProp.setDomainPublic(op.getDomainPublic()); - } - Literal customFormLit = qsoln.getLiteral("customForm"); - if (customFormLit != null) { - newProp.setCustomEntryForm(customFormLit.getLexicalForm()); - } else { - newProp.setCustomEntryForm(op.getCustomEntryForm()); - } - additionalProps.add(newProp); - } - } finally { - qe.close(); - } - } + for (ObjectProperty op : propList) { + additionalProps.addAll(getAdditionalFauxSubproperties(op, subject, tboxModel, union)); + } + return additionalProps; } - + private static boolean appropriateDomain(Resource domainRes, Individual subject, Model tboxModel) { + if (subject == null || domainRes == null) { + return true; + } + for (VClass vclass : subject.getVClasses()) { + if ((vclass.getURI() != null) && + ((vclass.getURI().equals(domainRes.getURI()) || + (tboxModel.contains( + ResourceFactory.createResource( + vclass.getURI()), RDFS.subClassOf, domainRes))))) { + return true; + } + } + return false; + } } 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 f4306cb17..50ab7a098 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 @@ -453,10 +453,13 @@ public class EditConfigurationTemplateModel extends BaseTemplateModel { String objectKey = vreq.getParameter("objectKey"); statementDisplay.put(objectKey, objectUri); + ObjectProperty predicate = new ObjectProperty(); + predicate.setURI(predicateUri); + //Using object property statement template model here ObjectPropertyStatementTemplateModel osm = new ObjectPropertyStatementTemplateModel( subjectUri, - predicateUri, + predicate, objectKey, statementDisplay, null, vreq); @@ -524,15 +527,23 @@ public class EditConfigurationTemplateModel extends BaseTemplateModel { if( subjectVClasses == null ) { vclasses = wdf.getVClassDao().getAllVclasses(); } else if (rangeClass != null) { + List rangeVClasses = new ArrayList(); vclasses = new ArrayList(); - vclasses.add(rangeClass); - List subURIs = wdf.getVClassDao().getSubClassURIs(rangeClass.getURI()); - for (String subClassURI : subURIs) { - VClass subClass = wdf.getVClassDao().getVClassByURI(subClassURI); - if (subClass != null) { - vclasses.add(subClass); - } - } + if (!rangeClass.isUnion()) { + rangeVClasses.add(rangeClass); + } else { + rangeVClasses.addAll(rangeClass.getUnionComponents()); + } + for(VClass rangeVClass : rangeVClasses) { + vclasses.add(rangeVClass); + List subURIs = wdf.getVClassDao().getSubClassURIs(rangeVClass.getURI()); + for (String subClassURI : subURIs) { + VClass subClass = wdf.getVClassDao().getVClassByURI(subClassURI); + if (subClass != null) { + vclasses.add(subClass); + } + } + } } else { //this hash is used to make sure there are no duplicates in the vclasses //a more elegant method may look at overriding equals/hashcode to enable a single hashset of VClass objects 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 0c4b09e72..f35e0d17d 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 @@ -117,7 +117,7 @@ public abstract class BaseIndividualTemplateModel extends BaseTemplateModel { RequestActionConstants.SOME_URI); AddObjectPropertyStatement aops = new AddObjectPropertyStatement( vreq.getJenaOntModel(), individual.getURI(), - RequestActionConstants.SOME_URI, + RequestActionConstants.SOME_PREDICATE, RequestActionConstants.SOME_URI); return PolicyHelper.isAuthorizedForActions(vreq, new Actions(adps).or(aops)); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/CollatedObjectPropertyTemplateModel.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/CollatedObjectPropertyTemplateModel.java index fd634595e..5dcbce7ea 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/CollatedObjectPropertyTemplateModel.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/CollatedObjectPropertyTemplateModel.java @@ -18,6 +18,7 @@ import org.apache.commons.logging.LogFactory; import edu.cornell.mannlib.vitro.webapp.beans.Individual; import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty; +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.VClassDao; @@ -58,7 +59,7 @@ public class CollatedObjectPropertyTemplateModel extends ObjectPropertyTemplateM postprocess(statementData); /* Collate the data */ - subclasses = collate(subjectUri, propertyUri, statementData, editing); + subclasses = collate(subjectUri, op, statementData, editing); for (SubclassTemplateModel subclass : subclasses) { List list = subclass.getStatements(); @@ -188,7 +189,7 @@ public class CollatedObjectPropertyTemplateModel extends ObjectPropertyTemplateM } // Collate the statements by subclass. - private List collate(String subjectUri, String propertyUri, + private List collate(String subjectUri, ObjectProperty property, List> statementData, boolean editing) { String objectKey = getObjectKey(); @@ -218,7 +219,7 @@ public class CollatedObjectPropertyTemplateModel extends ObjectPropertyTemplateM } listForThisSubclass.add(new ObjectPropertyStatementTemplateModel(subjectUri, - propertyUri, objectKey, map, getTemplateName(), vreq)); + property, objectKey, map, getTemplateName(), vreq)); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/DataPropertyStatementTemplateModel.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/DataPropertyStatementTemplateModel.java index a7209741a..87a17167d 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/DataPropertyStatementTemplateModel.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/DataPropertyStatementTemplateModel.java @@ -13,12 +13,14 @@ import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.DropDataPr import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.EditDataPropertyStatement; import edu.cornell.mannlib.vitro.webapp.beans.DataPropertyStatement; import edu.cornell.mannlib.vitro.webapp.beans.DataPropertyStatementImpl; +import edu.cornell.mannlib.vitro.webapp.beans.Property; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.ParamMap; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.RdfLiteralHash; + public class DataPropertyStatementTemplateModel extends PropertyStatementTemplateModel { private static final Log log = LogFactory.getLog(DataPropertyStatementTemplateModel.class); @@ -28,9 +30,10 @@ public class DataPropertyStatementTemplateModel extends PropertyStatementTemplat private final String templateName; //Extended to include vitro request to check for special parameters - public DataPropertyStatementTemplateModel(String subjectUri, String propertyUri, Literal literal, + public DataPropertyStatementTemplateModel(String subjectUri, Property property, Literal literal, String templateName, VitroRequest vreq) { - super(subjectUri, propertyUri, vreq); + + super(subjectUri, property, vreq); this.literalValue = literal; this.templateName = templateName; @@ -50,7 +53,7 @@ public class DataPropertyStatementTemplateModel extends PropertyStatementTemplat ParamMap params = new ParamMap( "subjectUri", subjectUri, - "predicateUri", propertyUri, + "predicateUri", property.getURI(), "datapropKey", makeHash(dps), "cmd", "delete"); @@ -63,7 +66,7 @@ public class DataPropertyStatementTemplateModel extends PropertyStatementTemplat private String makeEditUrl() { // vitro:moniker is deprecated. We display existing data values so editors can // move them to other properties and delete, but don't allow editing. - if ( propertyUri.equals(VitroVocabulary.MONIKER) ) { + if ( VitroVocabulary.MONIKER.equals(property.getURI()) ) { return ""; } @@ -76,7 +79,7 @@ public class DataPropertyStatementTemplateModel extends PropertyStatementTemplat ParamMap params = new ParamMap( "subjectUri", subjectUri, - "predicateUri", propertyUri, + "predicateUri", property.getURI(), "datapropKey", makeHash(dps)); if ( deleteUrl.isEmpty() ) { @@ -89,7 +92,7 @@ public class DataPropertyStatementTemplateModel extends PropertyStatementTemplat } private DataPropertyStatement makeStatement() { - DataPropertyStatement dps = new DataPropertyStatementImpl(subjectUri, propertyUri, literalValue.getLexicalForm()); + DataPropertyStatement dps = new DataPropertyStatementImpl(subjectUri, property.getURI(), literalValue.getLexicalForm()); // Language and datatype are needed to get the correct hash value dps.setLanguage(literalValue.getLanguage()); dps.setDatatypeURI(literalValue.getDatatypeURI()); 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 b70c24818..621c35998 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 @@ -88,7 +88,7 @@ public class DataPropertyTemplateModel extends PropertyTemplateModel { DataPropertyStatementDao dpDao = vreq.getWebappDaoFactory().getDataPropertyStatementDao(); List values = dpDao.getDataPropertyValuesForIndividualByProperty(subject, dp, queryString, constructQueries); for (Literal value : values) { - statements.add(new DataPropertyStatementTemplateModel(subjectUri, propertyUri, value, getTemplateName(), vreq)); + statements.add(new DataPropertyStatementTemplateModel(subjectUri, dp, value, getTemplateName(), vreq)); } } else { log.debug("Data property " + getUri() + " is unpopulated."); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/EditLinkSuppressor.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/EditLinkSuppressor.java deleted file mode 100644 index 87682ba6b..000000000 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/EditLinkSuppressor.java +++ /dev/null @@ -1,94 +0,0 @@ -/* $This file is distributed under the terms of the license in /doc/license.txt$ */ - -package edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual; - -import java.util.Arrays; -import java.util.List; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; - -/** - * Sometimes we don't want to show an Add, Edit, or Delete link for a particular - * property, no matter who the user is. - * - * TODO These are hard-coded while we wait for the Application Ontology to be - * implemented. - */ -public class EditLinkSuppressor { - private static final Log log = LogFactory.getLog(EditLinkSuppressor.class); - - private static final String CORE = "http://vivoweb.org/ontology/core#"; - private static final String PUB_TO_AUTHORSHIP = core("informationResourceInAuthorship"); - private static final String PERSON_TO_AUTHORSHIP = core("authorInAuthorship"); - private static final String AUTHORSHIP_TO_PERSON = core("linkedAuthor"); - private static final String AUTHORSHIP_TO_PUB = core("linkedInformationResource"); - private static final String INDIVIDUAL_TO_WEBPAGE = core("webpage"); - private static final String WEBPAGE_TO_INDIVIDUAL = core("webpageOf"); - private static final String HAS_RESEARCH_AREA = core("hasResearchArea"); - private static final String HAS_SUBJECT_AREA = core("hasSubjectArea"); - private static final String RESEARCH_AREA_OF = core("researchAreaOf"); - private static final String SUBJECT_AREA_FOR = core("subjectAreaFor"); - - private static String core(String localName) { - return CORE + localName; - } - - private static final List suppressAddLinksForThese = Arrays - .asList(new String[] { AUTHORSHIP_TO_PERSON, AUTHORSHIP_TO_PUB, - WEBPAGE_TO_INDIVIDUAL }); - - private static final List suppressEditLinksForThese = Arrays - .asList(new String[] { WEBPAGE_TO_INDIVIDUAL }); - - private static final List suppressDeleteLinksForThese = Arrays - .asList(new String[] { PUB_TO_AUTHORSHIP, PERSON_TO_AUTHORSHIP, - AUTHORSHIP_TO_PERSON, AUTHORSHIP_TO_PUB, - INDIVIDUAL_TO_WEBPAGE, WEBPAGE_TO_INDIVIDUAL, - HAS_RESEARCH_AREA, RESEARCH_AREA_OF, HAS_SUBJECT_AREA, - SUBJECT_AREA_FOR }); - - // TODO When we remove the hard-coding, vreq will allow us to find the - // application ontology model. - @SuppressWarnings("unused") - private final VitroRequest vreq; - - public EditLinkSuppressor(VitroRequest vreq) { - this.vreq = vreq; - } - - /** - * Should we suppress the Add link on this property? - */ - public boolean isAddLinkSuppressed(String propertyUri) { - if (propertyUri == null) { - log.error("Suppressing the add link on a null property."); - return true; - } - return suppressAddLinksForThese.contains(propertyUri); - } - - /** - * Should we suppress the Edit link on this property? - */ - public boolean isEditLinkSuppressed(String propertyUri) { - if (propertyUri == null) { - log.error("Suppressing the edit link on a null property."); - return true; - } - return suppressEditLinksForThese.contains(propertyUri); - } - - /** - * Should we suppress the Delete link on this property? - */ - public boolean isDeleteLinkSuppressed(String propertyUri) { - if (propertyUri == null) { - log.error("Suppressing the delete link on a null property."); - return true; - } - return suppressDeleteLinksForThese.contains(propertyUri); - } -} 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 e7498e668..7c023e022 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 @@ -20,6 +20,7 @@ import edu.cornell.mannlib.vitro.webapp.beans.PropertyGroup; import edu.cornell.mannlib.vitro.webapp.beans.PropertyInstance; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.dao.DataPropertyDao; +import edu.cornell.mannlib.vitro.webapp.dao.ModelAccess; import edu.cornell.mannlib.vitro.webapp.dao.ObjectPropertyDao; import edu.cornell.mannlib.vitro.webapp.dao.PropertyGroupDao; import edu.cornell.mannlib.vitro.webapp.dao.PropertyInstanceDao; @@ -74,12 +75,12 @@ public class GroupedPropertyList extends BaseTemplateModel { List populatedObjectPropertyList = subject .getPopulatedObjectPropertyList(); - List additions = ApplicationConfigurationOntologyUtils + Collection additions = ApplicationConfigurationOntologyUtils .getAdditionalFauxSubpropertiesForList( - populatedObjectPropertyList, vreq); + populatedObjectPropertyList, subject, vreq); if (log.isDebugEnabled()) { for (ObjectProperty t : additions) { - log.debug(t.getDomainPublic() + " " + t.getGroupURI()); + log.debug(t.getDomainPublic() + " " + t.getGroupURI() + " domain " + t.getDomainVClassURI()); } log.debug("Added " + additions.size() + " properties due to application configuration ontology"); @@ -88,7 +89,7 @@ public class GroupedPropertyList extends BaseTemplateModel { populatedObjectPropertyList.addAll(additions); propertyList.addAll(populatedObjectPropertyList); - + // If editing this page, merge in object properties applicable to the individual that are currently // 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. @@ -175,7 +176,13 @@ public class GroupedPropertyList extends BaseTemplateModel { // There is no ObjectPropertyDao.getAllPossibleObjectPropertiesForIndividual() parallel to // DataPropertyDao.getAllPossibleDatapropsForIndividual(). The comparable method for object properties // is defined using PropertyInstance rather than ObjectProperty. - PropertyInstanceDao piDao = wdf.getPropertyInstanceDao(); + + // Getting WebappDaoFactory from the session because we can't have the filtering + // that gets applied to the request. This breaks blank node structures in the + // restrictions that determine applicable properties. + WebappDaoFactory wadf = ModelAccess.on(vreq.getSession().getServletContext()).getWebappDaoFactory(); + PropertyInstanceDao piDao = wadf.getPropertyInstanceDao(); + Collection allPropInstColl = piDao .getAllPossiblePropInstForIndividual(subject.getURI()); if (allPropInstColl != null) { @@ -183,7 +190,7 @@ public class GroupedPropertyList extends BaseTemplateModel { if (pi != null) { if (!alreadyOnObjectPropertyList( populatedObjectPropertyList, pi)) { - addObjectPropertyToPropertyList(pi.getPropertyURI(), pi.getRangeClassURI(), + addObjectPropertyToPropertyList(pi.getPropertyURI(), pi.getDomainClassURI(), pi.getRangeClassURI(), propertyList); } } else { @@ -199,7 +206,7 @@ public class GroupedPropertyList extends BaseTemplateModel { // constitute a special case (i.e., included in piDao.getAllPossiblePropInstForIndividual()). for (String propertyUri : VITRO_PROPS_TO_ADD_TO_LIST) { if (!alreadyOnPropertyList(propertyList, propertyUri)) { - addObjectPropertyToPropertyList(propertyUri, null, propertyList); + addObjectPropertyToPropertyList(propertyUri, null, null, propertyList); } } } @@ -211,16 +218,29 @@ public class GroupedPropertyList extends BaseTemplateModel { } for (ObjectProperty op : opList) { if (op.getURI() != null && op.getURI().equals(pi.getPropertyURI())) { - return true; + 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; + } } } return false; } - private void addObjectPropertyToPropertyList(String propertyUri, String rangeUri, + private void addObjectPropertyToPropertyList(String propertyUri, String domainUri, String rangeUri, List propertyList) { ObjectPropertyDao opDao = wdf.getObjectPropertyDao(); - ObjectProperty op = opDao.getObjectPropertyByURIAndRangeURI(propertyUri, rangeUri); + ObjectProperty op = opDao.getObjectPropertyByURIs(propertyUri, domainUri, rangeUri); if (op == null) { log.error("ObjectProperty op returned null from opDao.getObjectPropertyByURI(" + propertyUri + ")"); } else if (op.getURI() == null) { @@ -457,11 +477,16 @@ public class GroupedPropertyList extends BaseTemplateModel { } public PropertyTemplateModel pullProperty(String propertyUri) { + return pullProperty(propertyUri, null); + } + + public PropertyTemplateModel pullProperty(String propertyUri, String rangeUri) { for (PropertyGroupTemplateModel pgtm : groups) { List properties = pgtm.getProperties(); for (PropertyTemplateModel ptm : properties) { - if (propertyUri.equals(ptm.getUri())) { + if (propertyUri.equals(ptm.getUri()) && + (rangeUri == null || rangeUri.equals(ptm.getRangeUri()))) { // Remove the property from the group. // NB Works with a for-each loop instead of an iterator, // since iteration doesn't continue after the remove. diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/NameStatementTemplateModel.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/NameStatementTemplateModel.java index b8a752dc4..cd30bdf40 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/NameStatementTemplateModel.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/NameStatementTemplateModel.java @@ -14,6 +14,7 @@ import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestedAct import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.EditDataPropertyStatement; import edu.cornell.mannlib.vitro.webapp.beans.DataPropertyStatement; import edu.cornell.mannlib.vitro.webapp.beans.DataPropertyStatementImpl; +import edu.cornell.mannlib.vitro.webapp.beans.Property; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.ParamMap; @@ -37,7 +38,7 @@ public class NameStatementTemplateModel extends PropertyStatementTemplateModel { private final String editUrl; NameStatementTemplateModel(String subjectUri, VitroRequest vreq) { - super(subjectUri, VitroVocabulary.LABEL, vreq); + super(subjectUri, new Property(VitroVocabulary.LABEL), vreq); // NIHVIVO-2466 Use the same methods to get the label that are used elsewhere in the // application, to guarantee consistent results for individuals with multiple labels @@ -69,7 +70,7 @@ public class NameStatementTemplateModel extends PropertyStatementTemplateModel { ParamMap params = new ParamMap( "subjectUri", subjectUri, - "predicateUri", propertyUri, + "predicateUri", property.getURI(), "datapropKey", makeHash(dps), "deleteProhibited", "prohibited"); @@ -80,7 +81,7 @@ public class NameStatementTemplateModel extends PropertyStatementTemplateModel { private DataPropertyStatement makeStatement(Literal literalValue) { DataPropertyStatement dps = new DataPropertyStatementImpl(subjectUri, - propertyUri, literalValue.getLexicalForm()); + property.getURI(), literalValue.getLexicalForm()); // Language and datatype are needed to get the correct hash value dps.setLanguage(literalValue.getLanguage()); dps.setDatatypeURI(literalValue.getDatatypeURI()); 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 f68441b96..c9da36ce8 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 @@ -13,8 +13,10 @@ import edu.cornell.mannlib.vitro.webapp.auth.policy.PolicyHelper; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestedAction; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.DropObjectPropertyStatement; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.EditObjectPropertyStatement; +import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty; import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatement; import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatementImpl; +import edu.cornell.mannlib.vitro.webapp.beans.Property; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.ParamMap; @@ -31,9 +33,9 @@ public class ObjectPropertyStatementTemplateModel extends PropertyStatementTempl private final String editUrl; private final String deleteUrl; - public ObjectPropertyStatementTemplateModel(String subjectUri, String propertyUri, String objectKey, + public ObjectPropertyStatementTemplateModel(String subjectUri, ObjectProperty predicate, String objectKey, Map data, String templateName, VitroRequest vreq) { - super(subjectUri, propertyUri, vreq); + super(subjectUri, predicate, vreq); this.data = Collections.unmodifiableMap(new HashMap(data)); this.objectUri = data.get(objectKey); @@ -41,7 +43,8 @@ public class ObjectPropertyStatementTemplateModel extends PropertyStatementTempl //to keep track of later this.objectKey = objectKey; - ObjectPropertyStatement ops = new ObjectPropertyStatementImpl(subjectUri, propertyUri, objectUri); + ObjectPropertyStatement ops = new ObjectPropertyStatementImpl(subjectUri, property.getURI(), objectUri); + ops.setProperty(predicate); // Do delete url first, since it is used in building edit url this.deleteUrl = makeDeleteUrl(); @@ -50,24 +53,24 @@ public class ObjectPropertyStatementTemplateModel extends PropertyStatementTempl private String makeDeleteUrl() { // Is the delete link suppressed for this property? - if (new EditLinkSuppressor(vreq).isDeleteLinkSuppressed(propertyUri)) { + if (property.isDeleteLinkSuppressed()) { return ""; } // Determine whether the statement can be deleted RequestedAction action = new DropObjectPropertyStatement( - vreq.getJenaOntModel(), subjectUri, propertyUri, objectUri); + vreq.getJenaOntModel(), subjectUri, property, objectUri); if ( ! PolicyHelper.isAuthorizedForActions(vreq, action) ) { return ""; } - if (propertyUri.equals(VitroVocabulary.IND_MAIN_IMAGE)) { + if (VitroVocabulary.IND_MAIN_IMAGE.equals(property.getURI())) { return ObjectPropertyTemplateModel.getImageUploadUrl(subjectUri, "delete"); } ParamMap params = new ParamMap( "subjectUri", subjectUri, - "predicateUri", propertyUri, + "predicateUri", property.getURI(), "objectUri", objectUri, "cmd", "delete", "objectKey", objectKey); @@ -92,7 +95,7 @@ public class ObjectPropertyStatementTemplateModel extends PropertyStatementTempl private String makeEditUrl(ObjectPropertyStatement ops) { // Is the edit link suppressed for this property? - if (new EditLinkSuppressor(vreq).isEditLinkSuppressed(propertyUri)) { + if (property.isEditLinkSuppressed()) { return ""; } @@ -102,19 +105,26 @@ public class ObjectPropertyStatementTemplateModel extends PropertyStatementTempl return ""; } - if (propertyUri.equals(VitroVocabulary.IND_MAIN_IMAGE)) { + if (VitroVocabulary.IND_MAIN_IMAGE.equals(property.getURI())) { return ObjectPropertyTemplateModel.getImageUploadUrl(subjectUri, "edit"); } ParamMap params = new ParamMap( "subjectUri", subjectUri, - "predicateUri", propertyUri, + "predicateUri", property.getURI(), "objectUri", objectUri); if ( deleteUrl.isEmpty() ) { params.put("deleteProhibited", "prohibited"); } + 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.putAll(UrlBuilder.getModelParams(vreq)); return UrlBuilder.getUrl(EDIT_PATH, params); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/ObjectPropertyTemplateModel.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/ObjectPropertyTemplateModel.java index 701ad0320..5257c3dbb 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/ObjectPropertyTemplateModel.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/ObjectPropertyTemplateModel.java @@ -80,7 +80,6 @@ public abstract class ObjectPropertyTemplateModel extends PropertyTemplateModel private PropertyListConfig config; private String objectKey; private String sortDirection; - private String rangeURI; ObjectPropertyTemplateModel(ObjectProperty op, Individual subject, VitroRequest vreq, boolean editing) @@ -90,7 +89,8 @@ public abstract class ObjectPropertyTemplateModel extends PropertyTemplateModel setName(op.getDomainPublic()); sortDirection = op.getDomainEntitySortDirection(); - rangeURI = op.getRangeVClassURI(); + domainUri = op.getDomainVClassURI(); + rangeUri = op.getRangeVClassURI(); // Get the config for this object property try { @@ -110,13 +110,13 @@ public abstract class ObjectPropertyTemplateModel extends PropertyTemplateModel protected void setAddUrl(Property property) { // Is the add link suppressed for this property? - if (new EditLinkSuppressor(vreq).isAddLinkSuppressed(propertyUri)) { + if (property.isAddLinkSuppressed()) { return; } // Determine whether a new statement can be added RequestedAction action = new AddObjectPropertyStatement( - vreq.getJenaOntModel(), subjectUri, propertyUri, + vreq.getJenaOntModel(), subjectUri, property, RequestActionConstants.SOME_URI); if ( ! PolicyHelper.isAuthorizedForActions(vreq, action) ) { return; @@ -133,6 +133,9 @@ public abstract class ObjectPropertyTemplateModel extends PropertyTemplateModel "subjectUri", subjectUri, "predicateUri", propertyUri); + if (domainUri != null) { + params.put("domainUri", domainUri); + } if (rangeUri != null) { params.put("rangeUri", rangeUri); } @@ -157,7 +160,7 @@ public abstract class ObjectPropertyTemplateModel extends PropertyTemplateModel protected List> getStatementData() { ObjectPropertyStatementDao opDao = vreq.getWebappDaoFactory().getObjectPropertyStatementDao(); - return opDao.getObjectPropertyStatementsForIndividualByProperty(subjectUri, propertyUri, objectKey, rangeURI, getSelectQuery(), getConstructQueries(), sortDirection); + return opDao.getObjectPropertyStatementsForIndividualByProperty(subjectUri, propertyUri, objectKey, domainUri, rangeUri, getSelectQuery(), getConstructQueries(), sortDirection); } protected abstract boolean isEmpty(); 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 0b285fb6e..10b5ce4d9 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 @@ -36,8 +36,13 @@ public class PropertyGroupTemplateModel extends BaseTemplateModel { properties = new ArrayList(propertyList.size()); for (Property p : propertyList) { if (p instanceof ObjectProperty) { - ObjectProperty op = (ObjectProperty)p; - properties.add(ObjectPropertyTemplateModel.getObjectPropertyTemplateModel(op, subject, vreq, editing, populatedObjectPropertyList)); + ObjectProperty op = (ObjectProperty) p; + ObjectPropertyTemplateModel tm = ObjectPropertyTemplateModel.getObjectPropertyTemplateModel( + op, subject, vreq, editing, populatedObjectPropertyList); + if (!tm.isEmpty() || (editing && !tm.getAddUrl().isEmpty())) { + properties.add(tm); + } + } else { properties.add(new DataPropertyTemplateModel((DataProperty)p, subject, vreq, editing, populatedDataPropertyList)); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/PropertyStatementTemplateModel.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/PropertyStatementTemplateModel.java index 1dfc9d2db..6074a7007 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/PropertyStatementTemplateModel.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/PropertyStatementTemplateModel.java @@ -2,6 +2,7 @@ package edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual; +import edu.cornell.mannlib.vitro.webapp.beans.Property; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.web.templatemodels.BaseTemplateModel; @@ -10,12 +11,12 @@ public abstract class PropertyStatementTemplateModel extends BaseTemplateModel { protected final VitroRequest vreq; protected final String subjectUri; - protected final String propertyUri; + protected final Property property; - PropertyStatementTemplateModel(String subjectUri, String propertyUri, VitroRequest vreq) { + PropertyStatementTemplateModel(String subjectUri, Property property, VitroRequest vreq) { this.vreq = vreq; this.subjectUri = subjectUri; - this.propertyUri = propertyUri; + this.property = property; } /* Template properties */ diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/PropertyTemplateModel.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/PropertyTemplateModel.java index 496e80a1a..43240e66f 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/PropertyTemplateModel.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/PropertyTemplateModel.java @@ -28,7 +28,10 @@ public abstract class PropertyTemplateModel extends BaseTemplateModel { protected final VitroRequest vreq; protected final String subjectUri; + protected final Property property; protected final String propertyUri; + protected String domainUri; + protected String rangeUri; private final String localName; protected Map verboseDisplay; @@ -41,6 +44,7 @@ public abstract class PropertyTemplateModel extends BaseTemplateModel { PropertyTemplateModel(Property property, Individual subject, VitroRequest vreq) { this.vreq = vreq; subjectUri = subject.getURI(); + this.property = property; propertyUri = property.getURI(); localName = property.getLocalName(); setVerboseDisplayValues(property); @@ -121,6 +125,10 @@ public abstract class PropertyTemplateModel extends BaseTemplateModel { return propertyUri; } + public String getRangeUri() { + return rangeUri; + } + public String getAddUrl() { //log.info("addUrl=" + addUrl); return (addUrl != null) ? addUrl : ""; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/UncollatedObjectPropertyTemplateModel.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/UncollatedObjectPropertyTemplateModel.java index 15f53b4c4..f4295118f 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/UncollatedObjectPropertyTemplateModel.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/UncollatedObjectPropertyTemplateModel.java @@ -41,7 +41,7 @@ public class UncollatedObjectPropertyTemplateModel extends ObjectPropertyTemplat String objectKey = getObjectKey(); for (Map map : statementData) { statements.add(new ObjectPropertyStatementTemplateModel(subjectUri, - propertyUri, objectKey, map, getTemplateName(), vreq)); + op, objectKey, map, getTemplateName(), vreq)); } postprocessStatementList(statements); 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 08da1960d..9459e6ca5 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 @@ -42,6 +42,7 @@ import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.DropObject import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.EditDataPropertyStatement; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.EditObjectPropertyStatement; import edu.cornell.mannlib.vitro.webapp.beans.IndividualImpl; +import edu.cornell.mannlib.vitro.webapp.beans.Property; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; public class SelfEditingPolicyTest extends AbstractTestClass { @@ -55,8 +56,8 @@ public class SelfEditingPolicyTest extends AbstractTestClass { private static final String UNSAFE_RESOURCE = UNSAFE_NS + "otherIndividual99999"; - private static final String SAFE_PREDICATE = SAFE_NS + "hasHairStyle"; - private static final String UNSAFE_PREDICATE = UNSAFE_NS + "hasSuperPowers"; + private static final Property SAFE_PREDICATE = new Property(SAFE_NS + "hasHairStyle"); + private static final Property UNSAFE_PREDICATE = new Property(UNSAFE_NS + "hasSuperPowers"); private ServletContextStub ctx; @@ -95,19 +96,19 @@ public class SelfEditingPolicyTest extends AbstractTestClass { PropertyRestrictionPolicyHelper.setBean(ctx, prph); whatToAuth = new AddObjectPropertyStatement(ontModel, SELFEDITOR_URI, - "http://mannlib.cornell.edu/bad#prp234", SAFE_RESOURCE); + new Property("http://mannlib.cornell.edu/bad#prp234"), SAFE_RESOURCE); assertDecision(INCONCLUSIVE, policy.isAuthorized(ids, whatToAuth)); whatToAuth = new AddObjectPropertyStatement(ontModel, SAFE_RESOURCE, - "http://mannlib.cornell.edu/bad#prp234", SELFEDITOR_URI); + new Property("http://mannlib.cornell.edu/bad#prp234"), SELFEDITOR_URI); assertDecision(INCONCLUSIVE, policy.isAuthorized(ids, whatToAuth)); whatToAuth = new AddObjectPropertyStatement(ontModel, SELFEDITOR_URI, - "http://mannlib.cornell.edu/bad#prp999", SAFE_RESOURCE); + new Property("http://mannlib.cornell.edu/bad#prp999"), SAFE_RESOURCE); assertDecision(INCONCLUSIVE, policy.isAuthorized(ids, whatToAuth)); whatToAuth = new AddObjectPropertyStatement(ontModel, SAFE_RESOURCE, - "http://mannlib.cornell.edu/bad#prp999", SELFEDITOR_URI); + new Property("http://mannlib.cornell.edu/bad#prp999"), SELFEDITOR_URI); assertDecision(INCONCLUSIVE, policy.isAuthorized(ids, whatToAuth)); whatToAuth = new AddObjectPropertyStatement(ontModel, SAFE_RESOURCE, @@ -132,11 +133,11 @@ public class SelfEditingPolicyTest extends AbstractTestClass { assertDecision(INCONCLUSIVE, policy.isAuthorized(ids, whatToAuth)); whatToAuth = new AddDataPropertyStatement(ontModel, SELFEDITOR_URI, - SAFE_PREDICATE); + SAFE_PREDICATE.getURI()); assertDecision(AUTHORIZED, policy.isAuthorized(ids, whatToAuth)); whatToAuth = new AddDataPropertyStatement(ontModel, SELFEDITOR_URI, - UNSAFE_PREDICATE); + UNSAFE_PREDICATE.getURI()); assertDecision(INCONCLUSIVE, policy.isAuthorized(ids, whatToAuth)); } @@ -218,16 +219,16 @@ public class SelfEditingPolicyTest extends AbstractTestClass { // @Test public void testVisitIdentifierBundleEditDataPropStmt() { - whatToAuth = new EditDataPropertyStatement(ontModel, SELFEDITOR_URI,SAFE_PREDICATE); + whatToAuth = new EditDataPropertyStatement(ontModel, SELFEDITOR_URI,SAFE_PREDICATE.getURI()); assertDecision(AUTHORIZED, policy.isAuthorized(ids, whatToAuth)); - whatToAuth = new EditDataPropertyStatement(ontModel, SELFEDITOR_URI, UNSAFE_PREDICATE); + whatToAuth = new EditDataPropertyStatement(ontModel, SELFEDITOR_URI, UNSAFE_PREDICATE.getURI()); assertDecision(INCONCLUSIVE, policy.isAuthorized(ids, whatToAuth)); - whatToAuth = new EditDataPropertyStatement(ontModel, UNSAFE_RESOURCE, SAFE_PREDICATE); + whatToAuth = new EditDataPropertyStatement(ontModel, UNSAFE_RESOURCE, SAFE_PREDICATE.getURI()); assertDecision(INCONCLUSIVE, policy.isAuthorized(ids, whatToAuth)); - whatToAuth = new EditDataPropertyStatement(ontModel, SAFE_RESOURCE, SAFE_PREDICATE); + whatToAuth = new EditDataPropertyStatement(ontModel, SAFE_RESOURCE, SAFE_PREDICATE.getURI()); assertDecision(INCONCLUSIVE, policy.isAuthorized(ids, whatToAuth)); } @@ -287,7 +288,7 @@ public class SelfEditingPolicyTest extends AbstractTestClass { public void twoSEIsFindDataPropertySubject() { setUpTwoSEIs(); - whatToAuth = new EditDataPropertyStatement(ontModel, SELFEDITOR_URI, SAFE_PREDICATE); + whatToAuth = new EditDataPropertyStatement(ontModel, SELFEDITOR_URI, SAFE_PREDICATE.getURI()); assertDecision(AUTHORIZED, policy.isAuthorized(ids, whatToAuth)); } @@ -295,7 +296,7 @@ public class SelfEditingPolicyTest extends AbstractTestClass { public void twoSEIsDontFindInDataProperty() { setUpTwoSEIs(); - whatToAuth = new EditDataPropertyStatement(ontModel, SAFE_RESOURCE, SAFE_PREDICATE); + whatToAuth = new EditDataPropertyStatement(ontModel, SAFE_RESOURCE, SAFE_PREDICATE.getURI()); 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 0e0ebfef6..aa5aa6ac0 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 @@ -32,6 +32,7 @@ import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.EditDataPr import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.EditObjectPropertyStatement; import edu.cornell.mannlib.vitro.webapp.beans.Individual; import edu.cornell.mannlib.vitro.webapp.beans.IndividualImpl; +import edu.cornell.mannlib.vitro.webapp.beans.Property; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; public class SelfEditingPolicy_2_Test extends AbstractTestClass { @@ -123,7 +124,7 @@ public class SelfEditingPolicy_2_Test extends AbstractTestClass { @Test public void nullIdentifierBundle() { AddObjectPropertyStatement whatToAuth = new AddObjectPropertyStatement( - ontModel, SELFEDITOR_URI, SAFE_PREDICATE, SAFE_RESOURCE); + ontModel, SELFEDITOR_URI, new Property(SAFE_PREDICATE), SAFE_RESOURCE); PolicyDecision dec = policy.isAuthorized(null, whatToAuth); Assert.assertNotNull(dec); Assert.assertEquals(Authorization.INCONCLUSIVE, dec.getAuthorized()); @@ -277,7 +278,7 @@ public class SelfEditingPolicy_2_Test extends AbstractTestClass { private void assertAddObjectPropStmt(String uriOfSub, String uriOfPred, String uriOfObj, Authorization expectedAuthorization) { AddObjectPropertyStatement whatToAuth = new AddObjectPropertyStatement( - ontModel, uriOfSub, uriOfPred, uriOfObj); + ontModel, uriOfSub, new Property(uriOfPred), uriOfObj); PolicyDecision dec = policy.isAuthorized(ids, whatToAuth); log.debug(dec); Assert.assertNotNull(dec); @@ -291,7 +292,7 @@ public class SelfEditingPolicy_2_Test extends AbstractTestClass { private void assertEditObjPropStmt(String uriOfSub, String uriOfPred, String uriOfObj, Authorization expectedAuthorization) { EditObjectPropertyStatement whatToAuth = new EditObjectPropertyStatement( - ontModel, uriOfSub, uriOfPred, uriOfObj); + ontModel, uriOfSub, new Property(uriOfPred), uriOfObj); PolicyDecision dec = policy.isAuthorized(ids, whatToAuth); log.debug(dec); Assert.assertNotNull(dec); diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/auth/policy/bean/PropertyRestrictionPolicyHelperTest.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/auth/policy/bean/PropertyRestrictionPolicyHelperTest.java index a00f136a2..030139d8c 100644 --- a/webapp/test/edu/cornell/mannlib/vitro/webapp/auth/policy/bean/PropertyRestrictionPolicyHelperTest.java +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/auth/policy/bean/PropertyRestrictionPolicyHelperTest.java @@ -18,7 +18,6 @@ import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.log4j.Level; import org.junit.Before; import org.junit.Test; @@ -27,6 +26,8 @@ import com.hp.hpl.jena.ontology.OntModelSpec; import com.hp.hpl.jena.rdf.model.ModelFactory; import com.hp.hpl.jena.rdf.model.Property; import com.hp.hpl.jena.rdf.model.Resource; +import com.hp.hpl.jena.sdb.util.Pair; +import com.hp.hpl.jena.vocabulary.OWL; import edu.cornell.mannlib.vitro.testing.AbstractTestClass; import edu.cornell.mannlib.vitro.webapp.beans.BaseResourceBean; @@ -58,17 +59,25 @@ public class PropertyRestrictionPolicyHelperTest extends AbstractTestClass { // setLoggerLevel(PropertyRestrictionPolicyHelper.class, Level.DEBUG); } + private void mapPut(String predicateURI, RoleLevel roleLevel, + Map>, RoleLevel> map) { + map.put(new Pair>( + OWL.Thing.getURI(), new Pair( + predicateURI, OWL.Thing.getURI())), roleLevel); + } + @Before public void createTheBean() { - Map displayLevels = new HashMap(); - displayLevels.put("http://predicates#display_self", SELF); - displayLevels.put("http://predicates#display_curator", CURATOR); - displayLevels.put("http://predicates#display_hidden", NOBODY); + Map>, RoleLevel> displayLevels = + new HashMap>, RoleLevel>(); + mapPut("http://predicates#display_curator", CURATOR, displayLevels); + mapPut("http://predicates#display_hidden", NOBODY, displayLevels); - Map modifyLevels = new HashMap(); - modifyLevels.put("http://predicates#modify_self", SELF); - modifyLevels.put("http://predicates#modify_curator", CURATOR); - modifyLevels.put("http://predicates#modify_hidden", NOBODY); + Map>, RoleLevel> modifyLevels = + new HashMap>, RoleLevel>(); + mapPut("http://predicates#modify_self", SELF, modifyLevels); + mapPut("http://predicates#modify_curator", CURATOR, modifyLevels); + mapPut("http://predicates#modify_hidden", NOBODY, modifyLevels); bean = new PropertyRestrictionPolicyHelper( Arrays.asList(PROHIBITED_NAMESPACES), @@ -125,68 +134,75 @@ public class PropertyRestrictionPolicyHelperTest extends AbstractTestClass { @Test public void displayPredicateNoRestriction() { assertEquals("displayPredicate: open", true, - bean.canDisplayPredicate("http://predicates#open", PUBLIC)); + bean.canDisplayPredicate(createVitroProperty( + "http://predicates#open"), PUBLIC)); } @Test public void displayPredicateRestrictionLower() { assertEquals("displayPredicate: lower restriction", true, - bean.canDisplayPredicate("http://predicates#display_self", - CURATOR)); + bean.canDisplayPredicate(createVitroProperty( + "http://predicates#display_self"), CURATOR)); } @Test public void displayPredicateRestrictionEqual() { assertEquals("displayPredicate: equal restriction", true, - bean.canDisplayPredicate("http://predicates#display_curator", - CURATOR)); + bean.canDisplayPredicate(createVitroProperty( + "http://predicates#display_curator"), CURATOR)); } @Test public void displayPredicateRestrictionHigher() { assertEquals("displayPredicate: higher restriction", false, - bean.canDisplayPredicate("http://predicates#display_hidden", - CURATOR)); + bean.canDisplayPredicate(createVitroProperty( + "http://predicates#display_hidden"), CURATOR)); } @Test public void modifyPredicateNoRestriction() { assertEquals("modifyPredicate: open", true, - bean.canModifyPredicate("http://predicates#open", PUBLIC)); + bean.canModifyPredicate(new edu.cornell.mannlib.vitro.webapp.beans.Property( + "http://predicates#open"), PUBLIC)); } @Test public void modifyPredicateRestrictionLower() { assertEquals("modifyPredicate: lower restriction", true, - bean.canModifyPredicate("http://predicates#modify_self", + bean.canModifyPredicate(new edu.cornell.mannlib.vitro.webapp.beans.Property( + "http://predicates#modify_self"), CURATOR)); } @Test public void modifyPredicateRestrictionEqual() { assertEquals("modifyPredicate: equal restriction", true, - bean.canModifyPredicate("http://predicates#modify_curator", + bean.canModifyPredicate(new edu.cornell.mannlib.vitro.webapp.beans.Property( + "http://predicates#modify_curator"), CURATOR)); } @Test public void modifyPredicateRestrictionHigher() { assertEquals("modifyPredicate: higher restriction", false, - bean.canModifyPredicate("http://predicates#modify_hidden", + bean.canModifyPredicate(new edu.cornell.mannlib.vitro.webapp.beans.Property( + "http://predicates#modify_hidden"), CURATOR)); } @Test public void modifyPredicateProhibitedNamespace() { assertEquals("modifyPredicate: prohibited namespace", false, - bean.canModifyPredicate(PROHIBITED_NAMESPACES[0] + "randoom", + bean.canModifyPredicate(new edu.cornell.mannlib.vitro.webapp.beans.Property( + PROHIBITED_NAMESPACES[0] + "randoom"), DB_ADMIN)); } @Test public void modifyPredicatePermittedException() { assertEquals("modifyPredicate: permitted exception", true, - bean.canModifyPredicate(PERMITTED_EXCEPTIONS[0], DB_ADMIN)); + bean.canModifyPredicate(new edu.cornell.mannlib.vitro.webapp.beans.Property( + PERMITTED_EXCEPTIONS[0]), DB_ADMIN)); } // ---------------------------------------------------------------------- @@ -195,9 +211,10 @@ public class PropertyRestrictionPolicyHelperTest extends AbstractTestClass { @Test public void buildDisplayThresholds() { - Map expectedMap = new HashMap(); - expectedMap.put("http://thresholds#display_public", PUBLIC); - expectedMap.put("http://thresholds#display_hidden", NOBODY); + Map>, BaseResourceBean.RoleLevel> expectedMap = + new HashMap>, BaseResourceBean.RoleLevel>(); + mapPut("http://thresholds#display_public", PUBLIC, expectedMap); + mapPut("http://thresholds#display_hidden", NOBODY, expectedMap); Map actualMap = populateThresholdMap(PROPERTY_DISPLAY_THRESHOLD); assertEquals("display thresholds", expectedMap, actualMap); @@ -205,9 +222,10 @@ public class PropertyRestrictionPolicyHelperTest extends AbstractTestClass { @Test public void buildModifyThresholds() { - Map expectedMap = new HashMap(); - expectedMap.put("http://thresholds#modify_editor", EDITOR); - expectedMap.put("http://thresholds#modify_curator", CURATOR); + Map>, BaseResourceBean.RoleLevel> expectedMap = + new HashMap>, BaseResourceBean.RoleLevel>(); + mapPut("http://thresholds#modify_editor", EDITOR, expectedMap); + mapPut("http://thresholds#modify_curator", CURATOR, expectedMap); Map actualMap = populateThresholdMap(PROPERTY_MODIFY_THRESHOLD); assertEquals("modify thresholds", expectedMap, actualMap); @@ -244,4 +262,9 @@ public class PropertyRestrictionPolicyHelperTest extends AbstractTestClass { model.add(subject, property, object); } } + + private edu.cornell.mannlib.vitro.webapp.beans.Property createVitroProperty( + String propertyURI) { + return new edu.cornell.mannlib.vitro.webapp.beans.Property(propertyURI); + } } diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerInversePropertyTest.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerInversePropertyTest.java index e0f81bb74..0003d576a 100644 --- a/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerInversePropertyTest.java +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerInversePropertyTest.java @@ -81,7 +81,14 @@ public class SimpleReasonerInversePropertyTest extends AbstractTestClass { aBox.add(a,P,b); Assert.assertTrue(inf.contains(b,Q,a)); aBox.add(c,Q,d); - Assert.assertTrue(inf.contains(d,P,c)); + Assert.assertTrue(inf.contains(d,P,c)); + + // delete assertions and verify that inferences go away + aBox.remove(c,Q,d); + Assert.assertFalse(inf.contains(d,P,c)); + aBox.remove(a,P,b); + Assert.assertFalse(inf.contains(b,Q,a)); + } @Test diff --git a/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/auth/policy/bean/PropertyRestrictionPolicyHelperStub.java b/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/auth/policy/bean/PropertyRestrictionPolicyHelperStub.java index 365ef82d0..bc441e5ad 100644 --- a/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/auth/policy/bean/PropertyRestrictionPolicyHelperStub.java +++ b/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/auth/policy/bean/PropertyRestrictionPolicyHelperStub.java @@ -10,6 +10,8 @@ import java.util.Set; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.ModelFactory; +import com.hp.hpl.jena.sdb.util.Pair; +import com.hp.hpl.jena.vocabulary.OWL; import edu.cornell.mannlib.vitro.webapp.auth.policy.bean.PropertyRestrictionPolicyHelper; import edu.cornell.mannlib.vitro.webapp.beans.BaseResourceBean.RoleLevel; @@ -43,10 +45,15 @@ public class PropertyRestrictionPolicyHelperStub extends namespaceSet.addAll(Arrays.asList(restrictedNamespaces)); } - Map thresholdMap = new HashMap(); + Map>, RoleLevel> thresholdMap = new HashMap< + Pair>, RoleLevel>(); if (restrictedProperties != null) { for (String prop : restrictedProperties) { - thresholdMap.put(prop, RoleLevel.NOBODY); + thresholdMap.put( + new Pair>( + OWL.Thing.getURI(), new Pair( + prop, OWL.Thing.getURI())), + RoleLevel.NOBODY); } } @@ -57,8 +64,8 @@ public class PropertyRestrictionPolicyHelperStub extends private PropertyRestrictionPolicyHelperStub( Set modifyRestrictedNamespaces, Set modifyPermittedExceptions, - Map displayThresholds, - Map modifyThresholds) { + Map>, RoleLevel> displayThresholds, + Map>, RoleLevel> modifyThresholds) { super(modifyRestrictedNamespaces, modifyPermittedExceptions, displayThresholds, modifyThresholds, ModelFactory.createDefaultModel()); } 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 0017b9291..54ba17477 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,7 @@ public class ObjectPropertyDaoStub implements ObjectPropertyDao { } @Override - public ObjectProperty getObjectPropertyByURIAndRangeURI(String objectPropertyURI, String rangeURI) { + public ObjectProperty getObjectPropertyByURIs(String objectPropertyURI, String domainURI, String rangeURI) { return getObjectPropertyByURI(objectPropertyURI); } diff --git a/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/dao/ObjectPropertyStatementDaoStub.java b/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/dao/ObjectPropertyStatementDaoStub.java index d5913a557..4144631e9 100644 --- a/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/dao/ObjectPropertyStatementDaoStub.java +++ b/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/dao/ObjectPropertyStatementDaoStub.java @@ -216,7 +216,7 @@ public class ObjectPropertyStatementDaoStub implements @Override public List> getObjectPropertyStatementsForIndividualByProperty( - String subjectUri, String propertyUri, String objectKey, String rangeUri, + String subjectUri, String propertyUri, String objectKey, String domainUri, String rangeUri, String query, Set constructQueries, String sortDir) { throw new RuntimeException( "ObjectPropertyStatementDaoStub.getObjectPropertyStatementsForIndividualByProperty() not implemented."); diff --git a/webapp/web/WEB-INF/resources/startup_listeners.txt b/webapp/web/WEB-INF/resources/startup_listeners.txt index 98a3fac21..657915abc 100644 --- a/webapp/web/WEB-INF/resources/startup_listeners.txt +++ b/webapp/web/WEB-INF/resources/startup_listeners.txt @@ -25,8 +25,6 @@ edu.cornell.mannlib.vitro.webapp.servlet.setup.UserModelSetup edu.cornell.mannlib.vitro.webapp.servlet.setup.ContentModelSetup edu.cornell.mannlib.vitro.webapp.servlet.setup.ModelMakerSetup -edu.cornell.mannlib.vitro.webapp.servlet.setup.UpdateKnowledgeBase - edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorageSetup edu.cornell.mannlib.vitro.webapp.web.images.PlaceholderUtil$Setup @@ -38,6 +36,8 @@ edu.cornell.mannlib.vitro.webapp.servlet.setup.FileGraphSetup edu.cornell.mannlib.vitro.webapp.servlet.setup.SimpleReasonerSetup +edu.cornell.mannlib.vitro.webapp.servlet.setup.UpdateKnowledgeBase + # Must run after JenaDataSourceSetup edu.cornell.mannlib.vitro.webapp.servlet.setup.ThemeInfoSetup diff --git a/webapp/web/i18n/all.properties b/webapp/web/i18n/all.properties index ce2217ce1..2817af838 100644 --- a/webapp/web/i18n/all.properties +++ b/webapp/web/i18n/all.properties @@ -42,13 +42,13 @@ crop_page_title_with_name = Crop image for {0} current_photo = Current Photo upload_photo = Upload a photo replace_photo = Replace Photo -photo_types = (JPEG, GIF or PNG) +photo_types = (JPEG, GIF or PNG) maximum_file_size = Maximum file size: {0} megabytes minimum_image_dimensions = Minimum image dimensions: {0} x {1} pixels cropping_caption = Your profile photo will look like the image below. cropping_note = To make adjustments, you can drag around and resize the photo to the right. \ - When you are happy with your photo click the "Save Photo" button. +When you are happy with your photo click the "Save Photo" button. alt_thumbnail_photo = Individual photo alt_image_to_crop = Image to be cropped @@ -69,7 +69,7 @@ imageUpload.errorFileTooBig = Please upload an image smaller than {0} megabytes. imageUpload.errorUnrecognizedFileType = ''{0}'' is not a recognized image file type. Please upload JPEG, GIF, or PNG files only. imageUpload.errorNoPhotoSelected = Please browse and select a photo. imageUpload.errorBadMultipartRequest = Failed to parse the multi-part request for uploading an image. -imageUpload.errorFormFieldMissing = The form did not contain a ''{0}'' field." +imageUpload.errorFormFieldMissing = The form did not contain a ''{0}'' field." # # User Accounts pages @@ -84,27 +84,27 @@ last_login = Last Login add_new_account = Add new account edit_account = Edit account external_auth_only = Externally Authenticated Only -reset_password = Reset password +reset_password = Reset password reset_password_note = Note: Instructions for resetting the password will \ - be emailed to the address entered above. The password will not \ - be reset until the user follows the link provided in this email. +be emailed to the address entered above. The password will not \ +be reset until the user follows the link provided in this email. new_password = New password confirm_password = Confirm new password minimum_password_length = Minimum of {0} characters in length. leave_password_unchanged = Leaving this blank means that the password will not be changed. confirm_initial_password = Confirm initial password -new_account_1 = A new account for +new_account_1 = A new account for new_account_2 = was successfully created. new_account_title = new account new_account_notification = A notification email has been sent to {0} \ - with instructions for activating the account and creating a password. +with instructions for activating the account and creating a password. updated_account_1 = The account for updated_account_2 = has been updated. updated_account_title = updated account updated_account_notification = A confirmation email has been sent to {0} \ - with instructions for resetting a password. \ - The password will not be reset until the user follows the link provided in this email. +with instructions for resetting a password. \ +The password will not be reset until the user follows the link provided in this email. deleted_accounts = Deleted {0} {0, choice, 0#accounts|1#account|1 diff --git a/webapp/web/templates/freemarker/body/siteAdmin/siteAdmin-siteConfiguration.ftl b/webapp/web/templates/freemarker/body/siteAdmin/siteAdmin-siteConfiguration.ftl index b5129203d..eb9a38c76 100644 --- a/webapp/web/templates/freemarker/body/siteAdmin/siteAdmin-siteConfiguration.ftl +++ b/webapp/web/templates/freemarker/body/siteAdmin/siteAdmin-siteConfiguration.ftl @@ -8,7 +8,7 @@
    <#if siteConfig.internalClass?has_content> -
  • ${i18n().internal_class}
  • +
  • ${i18n().internal_class_i_capped}
  • <#if siteConfig.manageProxies?has_content> diff --git a/webapp/web/templates/freemarker/edit/forms/js/customFormWithAutocomplete.js b/webapp/web/templates/freemarker/edit/forms/js/customFormWithAutocomplete.js index d02e8e8d0..8ef3746b0 100644 --- a/webapp/web/templates/freemarker/edit/forms/js/customFormWithAutocomplete.js +++ b/webapp/web/templates/freemarker/edit/forms/js/customFormWithAutocomplete.js @@ -144,7 +144,7 @@ var customForm = { // Put this case first, because in edit mode with // validation errors we just want initFormFullView. // if ((!this.supportEdit) && (this.editMode == 'edit' || this.editMode == 'repair')) { - if (this.editMode == 'edit' || this.editMode == 'repair') { + if (this.editMode == 'edit' || this.editMode == 'repair' || this.editMode == 'error') { this.initFormWithValidationErrors(); } else if (this.findValidationErrors()) { @@ -321,8 +321,12 @@ var customForm = { }, complete: function(xhr, status) { // Not sure why, but we need an explicit json parse here. - var results = $.parseJSON(xhr.responseText), - filteredResults = customForm.filterAcResults(results); + var results = $.parseJSON(xhr.responseText); + var filteredResults = customForm.filterAcResults(results); + + if ( customForm.acTypes[$(selectedObj).attr('acGroupName')] == "http://www.w3.org/2004/02/skos/core#Concept" ) { + filteredResults = customForm.removeConceptSubclasses(filteredResults); + } customForm.acCache[request.term] = filteredResults; response(filteredResults); @@ -423,6 +427,16 @@ var customForm = { }, + removeConceptSubclasses: function(array) { + $(array).each(function(i) { + if(this["msType"] != "http://www.w3.org/2004/02/skos/core#Concept") { + //Remove from array + array.splice(i, 1); + } + }); + return array; + }, + showAutocompleteSelection: function(label, uri, selectedObj) { // hide the acSelector field and set it's value to the selected ac item this.hideFields($(selectedObj).parent()); diff --git a/webapp/web/templates/freemarker/lib/lib-properties.ftl b/webapp/web/templates/freemarker/lib/lib-properties.ftl index 3f1a37dc1..3ba46792b 100644 --- a/webapp/web/templates/freemarker/lib/lib-properties.ftl +++ b/webapp/web/templates/freemarker/lib/lib-properties.ftl @@ -108,13 +108,13 @@ name will be used as the label. --> <#if editable> <#local url = property.addUrl> <#if url?has_content> - <@showAddLink property.localName label url /> + <@showAddLink property.localName property.name label url /> -<#macro showAddLink propertyLocalName label url> - <#if propertyLocalName == "informationResourceInAuthorship" || propertyLocalName == "webpage" || propertyLocalName == "hasResearchArea"> +<#macro showAddLink propertyLocalName propertyName label url> + <#if propertyName == "informationResourceInAuthorship" || propertyName == "webpage" || propertyLocalName == "hasResearchArea"> ${i18n().manage} <#else> @@ -131,30 +131,42 @@ name will be used as the label. --> <#macro propertyListItem property statement editable >
  • <#nested> - <@editingLinks "${property.localName}" statement editable/> + <@editingLinks "${property.localName}" "${property.name}" statement editable/>
  • -<#macro editingLinks propertyLocalName statement editable> - <#if editable && (propertyLocalName != "informationResourceInAuthorship" && propertyLocalName != "webpage" && propertyLocalName != "hasResearchArea")> - <@editLink propertyLocalName statement /> - <@deleteLink propertyLocalName statement /> +<#macro editingLinks propertyLocalName propertyName statement editable> + <#if editable && (propertyName != "authors" && propertyName != "webpage" && propertyLocalName != "hasResearchArea")> + <@editLink propertyLocalName propertyName statement /> + <@deleteLink propertyLocalName propertyName statement /> - -<#macro editLink propertyLocalName statement> +<#macro editLink propertyLocalName propertyName statement> +<#if propertyLocalName?contains("ARG_2000028")> + <#if propertyName?contains("mailing address")> + <#local url = statement.editUrl + "&addressUri=" + "${statement.address!}"> + <#elseif propertyName?contains("phone")> + <#local url = statement.editUrl + "&phoneUri=" + "${statement.phone!}"> + <#elseif propertyName?contains("primary email") || propertyName?contains("additional emails")> + <#local url = statement.editUrl + "&emailUri=" + "${statement.email!}"> + <#elseif propertyName?contains("full name")> + <#local url = statement.editUrl + "&fullNameUri=" + "${statement.fullName!}"> + +<#else> <#local url = statement.editUrl> + <#if url?has_content> <@showEditLink propertyLocalName url /> + <#macro showEditLink propertyLocalName url> ${i18n().edit_entry} -<#macro deleteLink propertyLocalName statement> +<#macro deleteLink propertyLocalName propertyName statement> <#local url = statement.deleteUrl> <#if url?has_content> <@showDeleteLink propertyLocalName url /> @@ -197,7 +209,7 @@ name will be used as the label. --> ${individual.name} - <@editingLinks "${mainImage.localName}" mainImage.first() editable /> + <@editingLinks "${mainImage.localName}" "" mainImage.first() editable /> <#else> <#local imageLabel><@addLinkWithLabel mainImage editable "${i18n().photo}" /> ${imageLabel} @@ -218,7 +230,7 @@ name will be used as the label. --> <#local label = individual.nameStatement> ${label.value} <#if useEditLink> - <@editingLinks "label" label editable /> + <@editingLinks "label" "" label editable /> <#elseif editable || (labelCount > 1)> <#--We display the link even when the user is not logged in case of multiple labels--> <#if editable>