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 a0e47c20d..14d20d618 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 @@ -47,41 +47,59 @@ public class EditConfigurationUtils { public static Individual getSubjectIndividual(VitroRequest vreq) { Individual subject = null; String subjectUri = getSubjectUri(vreq); - WebappDaoFactory wdf = vreq.getWebappDaoFactory(); - - if( subjectUri != null ){ - subject = wdf.getIndividualDao().getIndividualByURI(subjectUri); - if( subject != null ) - vreq.setAttribute("subject", subject); - } + subject = getIndividual(vreq, subjectUri); + + if( subject!= null ){ + vreq.setAttribute("subject", subject); + } return subject; } + public static Individual getIndividual(VitroRequest vreq, String uri) { + Individual individual = null; + WebappDaoFactory wdf = vreq.getWebappDaoFactory(); + + if( uri != null ){ + individual = wdf.getIndividualDao().getIndividualByURI(uri); + } + return individual; + } + public static Individual getObjectIndividual(VitroRequest vreq) { String objectUri = getObjectUri(vreq); - Individual object = null; - WebappDaoFactory wdf = vreq.getWebappDaoFactory(); - - if( objectUri != null ){ - object = wdf.getIndividualDao().getIndividualByURI(objectUri); - if( object != null ) - vreq.setAttribute("subject", object); - } + Individual object = getIndividual(vreq, objectUri); + if( object != null ) { + vreq.setAttribute("subject", object); + } return object; } public static ObjectProperty getObjectProperty(VitroRequest vreq) { - WebappDaoFactory wdf = vreq.getWebappDaoFactory(); + //gets the predicate uri from the request String predicateUri = getPredicateUri(vreq); + return getObjectPropertyForPredicate(vreq, predicateUri); + } + + public static DataProperty getDataProperty(VitroRequest vreq) { + String predicateUri = getPredicateUri(vreq); + return getDataPropertyForPredicate(vreq, predicateUri); + } + + public static ObjectProperty getObjectPropertyForPredicate(VitroRequest vreq, String predicateUri) { + WebappDaoFactory wdf = vreq.getWebappDaoFactory(); ObjectProperty objectProp = wdf.getObjectPropertyDao().getObjectPropertyByURI(predicateUri); return objectProp; } - public static DataProperty getDataProperty(VitroRequest vreq) { + public static DataProperty getDataPropertyForPredicate(VitroRequest vreq, String predicateUri) { WebappDaoFactory wdf = vreq.getWebappDaoFactory(); - String predicateUri = getPredicateUri(vreq); - DataProperty dataProp = wdf.getDataPropertyDao().getDataPropertyByURI(predicateUri); + //TODO: Check reason for employing unfiltered webapp dao factory and note if using a different version + //would change the results + //For some reason, note that edit data prop statement request dispatch utilizes unfiltered webapp dao facotry + //DataProperty dataProp = wdf.getDataPropertyDao().getDataPropertyByURI(predicateUri); + WebappDaoFactory unfilteredWdf = vreq.getUnfilteredWebappDaoFactory(); + DataProperty dataProp = unfilteredWdf.getDataPropertyDao().getDataPropertyByURI( predicateUri ); return dataProp; } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditConfigurationVTwo.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditConfigurationVTwo.java index f23974bec..26c61d8ff 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditConfigurationVTwo.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditConfigurationVTwo.java @@ -10,7 +10,7 @@ import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; - +import java.util.Set; import javax.servlet.ServletContext; import javax.servlet.ServletRequest; import javax.servlet.http.HttpServletRequest; @@ -159,7 +159,98 @@ public class EditConfigurationVTwo { wdfSelectorForOptons = StandardWDFSelector.selector; } + //Make copy of edit configuration object + public EditConfigurationVTwo copy() { + EditConfigurationVTwo editConfig = new EditConfigurationVTwo(); + //Copy n3generator - make copy of n3generator or get something else? + editConfig.setN3Generator(new EditN3GeneratorVTwo(this)); + //For remaining ensure we make copies of all the objects and we don't use refererences + //Set form url + editConfig.setFormUrl(this.getFormUrl()); + //Set edit key + editConfig.setEditKey(this.getEditKey()); + //subject, predicate + editConfig.setUrlPatternToReturnTo(this.getUrlPatternToReturnTo()); + editConfig.setVarNameForSubject(this.getVarNameForSubject()); + editConfig.setSubjectUri(this.getSubjectUri()); + editConfig.setEntityToReturnTo(this.getEntityToReturnTo()); + editConfig.setVarNameForPredicate(this.getVarNameForPredicate()); + editConfig.setPredicateUri(this.getPredicateUri()); + //object or data parameters based on whether object or data property + if(this.getObject() != null) { + editConfig.setObject(this.getObject()); + } + editConfig.setVarNameForObject(this.getVarNameForObject()); + editConfig.setObjectResource(this.isObjectResource()); + editConfig.setDatapropKey(this.getDatapropKey()); + //original set datapropValue, which in this case would be empty string but no way here + editConfig.setDatapropValue(this.datapropValue); + editConfig.setUrlPatternToReturnTo(this.getUrlPatternToReturnTo()); + + //n3 required + editConfig.setN3Required(this.copy(this.getN3Required())); + //n3 optional + editConfig.setN3Optional(this.copy(this.getN3Optional())); + //uris on form + editConfig.setUrisOnform(this.copy(this.getUrisOnform())); + //literals on form + editConfig.setLiteralsOnForm(this.copy(this.getLiteralsOnForm())); + //files on form + editConfig.setFilesOnForm(this.copy(this.getFilesOnForm())); + //new resources + Map copyNewResources = new HashMap(); + editConfig.setNewResources(this.copy(this.getNewResources(), copyNewResources)); + //uris in scope + editConfig.setUrisInScope(this.copy(this.getUrisInScope())); + //TODO: ensure this is not a shallow copy of literals but makes entirely new literal objects + editConfig.setLiteralsInScope(this.getLiteralsInScope()); + //editConfig.setLiteralsInScope(this.copy(this.getLiteralsInScope())); + //sparql for additional uris in scope + editConfig.setSparqlForAdditionalUrisInScope( + this.copy(this.getSparqlForAdditionalUrisInScope(), + (Map) new HashMap())); + //sparql for additional literals in scope + editConfig.setSparqlForAdditionalLiteralsInScope( + this.copy(this.getSparqlForAdditionalLiteralsInScope(), + (Map) new HashMap())); + //sparql for existing literals + editConfig.setSparqlForExistingLiterals( + this.copy(this.getSparqlForExistingLiterals(), + (Map) new HashMap())); + //sparql for existing uris + editConfig.setSparqlForExistingUris( + this.copy(this.getSparqlForExistingUris(), + (Map) new HashMap())); + //TODO: Ensure this is true copy of field and not just shallow copy with same references + Map fields = this.getFields(); + editConfig.setFields(fields); + + return editConfig; + } + + //make copy of list of strings + public List copy(List list) { + List copyList = new ArrayList(); + for(String l: list) { + copyList.add(l); + } + return copyList; + } + + public Map> copy(Map> source) { + HashMap> map = new HashMap>(); + Set keys = map.keySet(); + for(String key: keys) { + List vals = map.get(key); + map.put(key, this.copy(vals)); + } + return map; + } + + + + /** * Add symbols for things like currentTime and editingUser to * editConfig.urisInScope and editConfig.literalsInScope. @@ -823,7 +914,11 @@ public class EditConfigurationVTwo { this.submitToUrl = submitToUrl; } - public boolean isUpdate(){ + public boolean isObjectPropertyUpdate(){ return this.getObject() != null && this.getObject().trim().length() > 0; } + + public boolean isDataPropertyUpdate() { + return this.getDatapropKey() != null && this.getDatapropKey().length() > 0; + } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditN3GeneratorVTwo.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditN3GeneratorVTwo.java index 0053b9b2a..b6594fbff 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditN3GeneratorVTwo.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditN3GeneratorVTwo.java @@ -151,9 +151,10 @@ public class EditN3GeneratorVTwo { String tmp = n3; for( String key : varsToVals.keySet()){ tmp = subInMultiLiterals( key, varsToVals.get(key),tmp); - } + } + outv.add(tmp); } - return n3targets; + return outv; } protected static String subInMultiLiterals(String var, Listvalues, String n3){ diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/ProcessRdfForm.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/ProcessRdfForm.java index f7d71e697..7dce8cf83 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/ProcessRdfForm.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/ProcessRdfForm.java @@ -7,6 +7,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.HashMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -15,6 +16,7 @@ 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.shared.Lock; +import com.hp.hpl.jena.rdf.model.Literal; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.dao.jena.DependentResourceDeleteJena; @@ -22,11 +24,19 @@ import edu.cornell.mannlib.vitro.webapp.dao.jena.event.EditEvent; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.preprocessors.ModelChangePreprocessor; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.controller.ProcessRdfFormController.Utilities; - +import edu.cornell.mannlib.vitro.webapp.beans.DataPropertyStatement; +import edu.cornell.mannlib.vitro.webapp.beans.DataPropertyStatementImpl; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.processEdit.RdfLiteralHash; public class ProcessRdfForm { - private static Log log = LogFactory.getLog(ProcessRdfForm.class); + private static Log log = LogFactory.getLog(ProcessRdfForm.class); + //Making this a global variable because this may be referenced in multiple places + //Alternatively we could handle all new resource related information separately in its own method + private static Map> varToNewResource = null; + + + /** * Execute any modelChangePreprocessors in the editConfiguration; * @@ -83,186 +93,374 @@ public class ProcessRdfForm { } } - + //Create new resource + // @SuppressWarnings("static-access") - public static AdditionsAndRetractions createNewResource(EditConfigurationVTwo editConfiguration , MultiValueEditSubmission submission){ - List errorMessages = new ArrayList(); - - EditN3GeneratorVTwo n3Subber = editConfiguration.getN3Generator(); - - if(log.isDebugEnabled()){ - log.debug("creating a new relation " + editConfiguration.getPredicateUri()); - } - - //handle creation of a new object property and maybe a resource - List n3Required = editConfiguration.getN3Required(); - List n3Optional = editConfiguration.getN3Optional(); - - /* ********** URIs and Literals on Form/Parameters *********** */ - //sub in resource uris off form - n3Required = n3Subber.subInMultiUris(submission.getUrisFromForm(), n3Required); - n3Optional = n3Subber.subInMultiUris(submission.getUrisFromForm(), n3Optional); - if(log.isDebugEnabled()) { - logRequiredOpt("substituted in URIs off from ",n3Required,n3Optional); - } - - //sub in literals from form - n3Required = n3Subber.subInMultiLiterals(submission.getLiteralsFromForm(), n3Required); - n3Optional = n3Subber.subInMultiLiterals(submission.getLiteralsFromForm(), n3Optional); - if(log.isDebugEnabled()) { - logRequiredOpt("substituted in literals off from ",n3Required,n3Optional); - } - - /* ****************** URIs and Literals in Scope ************** */ - n3Required = n3Subber.subInMultiUris( editConfiguration.getUrisInScope(), n3Required); - n3Optional = n3Subber.subInMultiUris( editConfiguration.getUrisInScope(), n3Optional); - if(log.isDebugEnabled()) { - logRequiredOpt("substituted in URIs from scope ",n3Required,n3Optional); - } - - n3Required = n3Subber.subInMultiLiterals( editConfiguration.getLiteralsInScope(), n3Required); - n3Optional = n3Subber.subInMultiLiterals( editConfiguration.getLiteralsInScope(), n3Optional); - if(log.isDebugEnabled()) { - logRequiredOpt("substituted in Literals from scope ",n3Required,n3Optional); - } - - //deal with required N3 - List requiredNewModels = new ArrayList(); - for(String n3 : n3Required){ - try{ - Model model = ModelFactory.createDefaultModel(); - StringReader reader = new StringReader(n3); - model.read(reader, "", "N3"); - requiredNewModels.add(model); - } catch(Throwable t){ - errorMessages.add("error processing required n3 string \n" + t.getMessage() + '\n' + "n3: \n" + n3); - } - } - - if(!errorMessages.isEmpty()){ - String error = "problems processing required n3: \n"; - for(String errorMsg: errorMessages){ - error += errorMsg + '\n'; - } - if(log.isDebugEnabled()){ - log.debug(error); - } - } - List requiredAssertions = requiredNewModels; - - //deal with optional N3 - List optionalNewModels = new ArrayList(); - for(String n3 : n3Optional){ - try{ - Model model = ModelFactory.createDefaultModel(); - StringReader reader = new StringReader(n3); - model.read(reader, "", "N3"); - optionalNewModels.add(model); - }catch(Throwable t){ - //if an optional N3 block fails to parse it will be ignored - //this is what is meant by optional. - } - } - requiredAssertions.addAll( optionalNewModels ); - - return getMinimalChanges(new AdditionsAndRetractions(requiredAssertions, Collections.emptyList())); - } + public static AdditionsAndRetractions createNewStatement(EditConfigurationVTwo editConfiguration , MultiValueEditSubmission submission, VitroRequest vreq){ + //Get all assertions + List assertions = populateAssertions(editConfiguration, submission, vreq); + //Retractions should be empty anyway but the method should take care of that + List retractions = new ArrayList(); + return getMinimalChanges(new AdditionsAndRetractions(assertions, retractions)); - @SuppressWarnings("static-access") - public static AdditionsAndRetractions editExistingResource(EditConfigurationVTwo editConfiguration, MultiValueEditSubmission submission) { - - Map> fieldAssertions = Utilities.fieldsToAssertionMap(editConfiguration.getFields()); - Map> fieldRetractions = Utilities.fieldsToRetractionMap(editConfiguration.getFields()); - EditN3GeneratorVTwo n3Subber = editConfiguration.getN3Generator(); - - /* ********** URIs and Literals on Form/Parameters *********** */ - fieldAssertions = n3Subber.substituteIntoValues(submission.getUrisFromForm(), submission.getLiteralsFromForm(), fieldAssertions); - if(log.isDebugEnabled()) { - logAddRetract("substituted in literals from form",fieldAssertions,fieldRetractions); - } - - /* ****************** URIs and Literals in Scope ************** */ - fieldAssertions = n3Subber.substituteIntoValues(editConfiguration.getUrisInScope(), editConfiguration.getLiteralsInScope(), fieldAssertions ); - fieldRetractions = n3Subber.substituteIntoValues(editConfiguration.getUrisInScope(), editConfiguration.getLiteralsInScope(), fieldRetractions); - if(log.isDebugEnabled()) { - logAddRetract("substituted in URIs and Literals from scope",fieldAssertions,fieldRetractions); - } - - //do edits ever need new resources? (YES) -/* Map varToNewResource = newToUriMap(editConfiguration.getNewResources(),wdf); - fieldAssertions = n3Subber.substituteIntoValues(varToNewResource, null, fieldAssertions); - if(log.isDebugEnabled()) { - Utilities.logAddRetract("substituted in URIs for new resources",fieldAssertions,fieldRetractions); - } - entToReturnTo = n3Subber.subInUris(varToNewResource,entToReturnTo); -*/ - //editing an existing statement - List requiredFieldAssertions = new ArrayList(); - List requiredFieldRetractions = new ArrayList(); - - List errorMessages = new ArrayList(); - - for(String fieldName : fieldAssertions.keySet()){ - List assertions = fieldAssertions.get(fieldName); - List retractions = fieldRetractions.get(fieldName); - - for(String n3: assertions){ - try{ - Model model = ModelFactory.createDefaultModel(); - StringReader reader = new StringReader(n3); - model.read(reader, "", "N3"); - requiredFieldAssertions.add(model); - }catch(Throwable t){ - String errMsg = "error processing N3 assertion string from field " + fieldName + "\n" + - t.getMessage() + '\n' + "n3: \n" + n3; - errorMessages.add(errMsg); - if(log.isDebugEnabled()){ - log.debug(errMsg); - } - } - } - - for(String n3 : retractions){ - try{ - Model model = ModelFactory.createDefaultModel(); - StringReader reader = new StringReader(n3); - model.read(reader, "", "N3"); - requiredFieldRetractions.add(model); - }catch(Throwable t){ - String errMsg = "error processing N3 retraction string from field " + fieldName + "\n"+ - t.getMessage() + '\n' + "n3: \n" + n3; - errorMessages.add(errMsg); - if(log.isDebugEnabled()){ - log.debug(errMsg); - } - } - } - } - - return getMinimalChanges(new AdditionsAndRetractions(requiredFieldAssertions, requiredFieldRetractions)); } - - /** - * This is intended to substitute vars from the EditConfiguration and - * EditSubmission into the URL to return to. - */ - public static String substitueForURL(EditConfigurationVTwo configuration, MultiValueEditSubmission submission){ - - List entToReturnTo = new ArrayList(1); - entToReturnTo.add(configuration.getEntityToReturnTo()); - - EditN3GeneratorVTwo n3Subber = configuration.getN3Generator(); - // Substitute in URIs from the submission - entToReturnTo = n3Subber.subInMultiUris(submission.getUrisFromForm(), entToReturnTo); - - // Substitute in URIs from the scope of the EditConfiguration - entToReturnTo = n3Subber.subInMultiUris(configuration.getUrisInScope(), entToReturnTo); - - //The problem is that subInURI will add < and > around URIs for the N3 syntax. - //for the URL to return to, replace < and > from URI additions. - return entToReturnTo.get(0).trim().replaceAll("<","").replaceAll(">",""); + public static AdditionsAndRetractions editExistingStatement(EditConfigurationVTwo editConfiguration, MultiValueEditSubmission submission, VitroRequest vreq) { + List fieldAssertions = populateAssertions(editConfiguration, submission, vreq); + List fieldRetractions = populateRetractions(editConfiguration, submission, vreq); + return getMinimalChanges(new AdditionsAndRetractions(fieldAssertions, fieldRetractions)); } + + + /** + * Certain methods/mechanisms overlap across type of property (object or data) and whether or not + * the updates are for existing or new resource or value + */ + //This should be a separate method because varToNewResources is referred to in multiple places + + + //get field assertions - so these appear to be employed when editing an EXISTING literal or resource + //Also note this depends on field assertions + public static List getRequiredFieldAssertions(EditConfigurationVTwo configuration, MultiValueEditSubmission submission, VitroRequest vreq) { + + List requiredFieldAssertions = new ArrayList(); + //Get the original assertions from the edit configuration field + Map> fieldAssertions = Utilities.fieldsToN3Map(configuration.getFields(), Utilities.assertionsType); + fieldAssertions = subUrisAndLiteralsInFieldAssertions(configuration, submission, vreq, fieldAssertions); + //process assertions + requiredFieldAssertions = processFieldAssertions(configuration, submission, vreq, fieldAssertions); + return requiredFieldAssertions; + } + + private static Map> subUrisAndLiteralsInFieldRetractions( + EditConfigurationVTwo configuration, + MultiValueEditSubmission submission, + VitroRequest vreq, Map> fieldRetractions) { + return subUrisAndLiteralsForField(configuration, submission, vreq, fieldRetractions); + } + + + //substitute uris and literals and also handle new resource + private static Map> subUrisAndLiteralsInFieldAssertions( + EditConfigurationVTwo configuration, + MultiValueEditSubmission submission, + VitroRequest vreq, Map> fieldAssertions) { + //Substitute URIs and literals from form and from scope + fieldAssertions = subUrisAndLiteralsForField(configuration, submission, vreq, fieldAssertions); + fieldAssertions = subNewResourceForField(configuration, vreq, fieldAssertions); + return fieldAssertions; + } + + //For both new and existing statement, need to incorporate varToNewResource + //Check whether data or not, to be consistent + //Map varToNewResource = newToUriMap + //TODO: Check if this still needs to differentiate between object and data property + private static Map> subNewResourceForField( + EditConfigurationVTwo configuration, VitroRequest vreq, + Map> fieldAssertions) { + EditN3GeneratorVTwo n3Subber = configuration.getN3Generator(); + setVarToNewResource(configuration, vreq); + fieldAssertions = n3Subber.substituteIntoValues(varToNewResource, null, fieldAssertions ); + return fieldAssertions; + } + + //Substitue for uris and literals from both form and scope for field + private static Map> subUrisAndLiteralsForField( + EditConfigurationVTwo configuration, + MultiValueEditSubmission submission, + VitroRequest vreq, Map> fieldN3) { + EditN3GeneratorVTwo n3Subber = configuration.getN3Generator(); + //Substitute URIs and literals from form + fieldN3 = n3Subber.substituteIntoValues(submission.getUrisFromForm(), submission.getLiteralsFromForm(), fieldN3); + //Substitute URIS and literals from scope + fieldN3 = n3Subber.substituteIntoValues(configuration.getUrisInScope(), configuration.getLiteralsInScope(), fieldN3 ); + return fieldN3; + } + + //Substitute for uris and literals for n3 required or n3Optional + private static List subUrisAndLiteralsForN3( + EditConfigurationVTwo configuration, + MultiValueEditSubmission submission, + VitroRequest vreq, List n3Statements) { + EditN3GeneratorVTwo n3Subber = configuration.getN3Generator(); + + //Substitute URIs and literals from form + n3Statements = n3Subber.subInMultiUris(submission.getUrisFromForm(), n3Statements); + n3Statements = n3Subber.subInMultiLiterals(submission.getLiteralsFromForm(), n3Statements); + //Substitute URIS and literals in scope + n3Statements = n3Subber.subInMultiUris(configuration.getUrisInScope(), n3Statements); + n3Statements = n3Subber.subInMultiLiterals(configuration.getLiteralsInScope(), n3Statements); + //for new resource + setVarToNewResource(configuration, vreq); + n3Statements = n3Subber.subInMultiUris(varToNewResource, n3Statements); + return n3Statements; + } + + public static void setVarToNewResource(EditConfigurationVTwo configuration, VitroRequest vreq) { + if(varToNewResource == null) { + //No longer using the data poperty method but just using the object processing form version + // if(Utilities.isDataProperty(configuration, vreq)) { + // OntModel resourcesModel = configuration.getResourceModelSelector().getModel(vreq,vreq.getSession().getServletContext()); + // varToNewResource = Utilities.newToUriMap(configuration.getNewResources(),resourcesModel); + // } else { + varToNewResource = Utilities.newToUriMap(configuration.getNewResources(),vreq.getWebappDaoFactory()); + /* + if(log.isDebugEnabled()) { + Utilities.logAddRetract("substituted in URIs for new resources",fieldAssertions,fieldRetractions); + }*/ + // } + } + } + + //this occurs for edits of existing statements whether object resource or literal + //In data form, not only is the condition for edit check but an additional check regarding + //has field changed is included, whereas object form depends only on whether or not this is an edit + //Here we take care of both conditions but including a method that checks whether or not to populate the assertions + //model + private static List processFieldAssertions( + EditConfigurationVTwo configuration, + MultiValueEditSubmission submission, + VitroRequest vreq, + Map> fieldAssertions) { + List requiredFieldAssertions = new ArrayList(); + + //Loop through field assertions + for(String fieldName : fieldAssertions.keySet()){ + //this checks whether or not proceed with populating the model based on the field + if(isGenerateModelFromField(fieldName, configuration, submission, vreq)) { + List assertions = fieldAssertions.get(fieldName); + for(String n3: assertions){ + try{ + Model model = ModelFactory.createDefaultModel(); + StringReader reader = new StringReader(n3); + model.read(reader, "", "N3"); + requiredFieldAssertions.add(model); + }catch(Throwable t){ + String errMsg = "error processing N3 assertion string from field " + fieldName + "\n" + + t.getMessage() + '\n' + "n3: \n" + n3; + //errorMessages.add(errMsg); + log.error(errMsg); + //TODO:Check whether need to throw exception here + } + } + } + } + + //if data property - since only see that there - then check for empty string condition + //which means only one value and it is an empty string + if(Utilities.checkForEmptyString(submission, configuration, vreq)) { + requiredFieldAssertions.clear(); + } + return requiredFieldAssertions; + } + + //Process Entity to Return to - substituting uris etc. + public static String processEntityToReturnTo(EditConfigurationVTwo configuration, MultiValueEditSubmission submission, VitroRequest vreq) { + List entityToReturnTo = new ArrayList(); + String entity = configuration.getEntityToReturnTo(); + entityToReturnTo.add(entity); + //Substitute uris and literals on form + //Substitute uris and literals in scope + //Substite var to new resource + EditN3GeneratorVTwo n3Subber = configuration.getN3Generator(); + + //Substitute URIs and literals from form + entityToReturnTo = n3Subber.subInMultiUris(submission.getUrisFromForm(), entityToReturnTo); + entityToReturnTo = n3Subber.subInMultiLiterals(submission.getLiteralsFromForm(), entityToReturnTo); + setVarToNewResource(configuration, vreq); + entityToReturnTo = n3Subber.subInMultiUris(varToNewResource, entityToReturnTo); + + String processedEntity = entityToReturnTo.get(0); + if(processedEntity != null) { + + processedEntity = processedEntity.trim().replaceAll("<","").replaceAll(">",""); + } + return processedEntity; + + } + + public static boolean isGenerateModelFromField(String fieldName, EditConfigurationVTwo configuration, MultiValueEditSubmission submission, VitroRequest vreq) { + if(Utilities.isObjectProperty(configuration, vreq)) { + return true; + } + if(Utilities.isDataProperty(configuration, vreq)) { + if(Utilities.hasFieldChanged(fieldName, configuration, submission)) { + return true; + } + } + return false; + } + + + public static List getRequiredFieldRetractions(EditConfigurationVTwo configuration, MultiValueEditSubmission submission, VitroRequest vreq) { + List requiredFieldRetractions = new ArrayList(); + //TODO: Check if need to check twice or if once is sufficient? + //if adding new object no retractions, although this should be empty if adding new literal too? + if(!configuration.isDataPropertyUpdate() && !configuration.isObjectPropertyUpdate()) { + return new ArrayList(); + } + //else populate + //If data property, field retractions based on field alone and if object property additional + //retraction processing required + if(configuration.isObjectPropertyUpdate()){ + Map> fieldRetractions = Utilities.fieldsToN3Map(configuration.getFields(), Utilities.retractionsType); + //sub in uris and literals for field + fieldRetractions = subUrisAndLiteralsInFieldRetractions(configuration, submission, vreq, fieldRetractions); + requiredFieldRetractions = processFieldRetractions(configuration, submission, vreq, fieldRetractions); + } + if(configuration.isDataPropertyUpdate()) { + //this simply goes through each field and checks if it has retractions + requiredFieldRetractions = processFieldRetractions(configuration, submission, vreq); + } + return requiredFieldRetractions; + } + + //this expects an input map with retractions populated and and with uris/literals subbed + private static List processFieldRetractions( + EditConfigurationVTwo configuration, + MultiValueEditSubmission submission, VitroRequest vreq, + Map> fieldRetractions) { + List requiredFieldRetractions = new ArrayList(); + //Get key set for fields + Map fields = configuration.getFields(); + for(String fieldName: fields.keySet()) { + //get retractions from field retractions for this field - post uri substitution etc. + List retractions = fieldRetractions.get(fieldName); + for( String n3 : retractions ){ + try{ + Model model = ModelFactory.createDefaultModel(); + StringReader reader = new StringReader(n3); + model.read(reader, "", "N3"); + requiredFieldRetractions.add(model); + }catch(Throwable t){ + String errMsg = "error processing N3 retraction string from field " + fieldName + "\n"+ + t.getMessage() + '\n' + + "n3: \n" + n3; + //errorMessages.add(errMsg); + log.error(errMsg); + } + } + } + return requiredFieldRetractions; + } + + //data property version , gets retractions from each field + private static List processFieldRetractions( + EditConfigurationVTwo configuration, + MultiValueEditSubmission submission, VitroRequest vreq) { + List requiredFieldRetractions = new ArrayList(); + //Get key set for fields + Map fields = configuration.getFields(); + for(String fieldName: fields.keySet()) { + //get retractions from field retractions for this field - post uri substitution etc. + FieldVTwo field = fields.get(fieldName); + if(Utilities.hasFieldChanged(fieldName, configuration, submission)) { + List retractions = field.getRetractions(); + if(retractions != null) { + for( String n3 : retractions ){ + try{ + Model model = ModelFactory.createDefaultModel(); + StringReader reader = new StringReader(n3); + model.read(reader, "", "N3"); + requiredFieldRetractions.add(model); + }catch(Throwable t){ + String errMsg = "error processing N3 retraction string from field " + fieldName + "\n"+ + t.getMessage() + '\n' + + "n3: \n" + n3; + //errorMessages.add(errMsg); + log.error(errMsg); + } + } + + } + } + } + return requiredFieldRetractions; + } + + //required assertions based on N3 + public static List getRequiredN3Assertions(EditConfigurationVTwo configuration, MultiValueEditSubmission submission, VitroRequest vreq) { + List requiredN3Assertions = new ArrayList(); + List n3Required = configuration.getN3Required(); + //Substitute uris and literals, including for + n3Required = subUrisAndLiteralsForN3(configuration, submission, vreq, n3Required); + requiredN3Assertions = processN3Assertions(configuration, submission, vreq, n3Required); + return requiredN3Assertions; + } + +private static List processN3Assertions( + EditConfigurationVTwo configuration, + MultiValueEditSubmission submission, VitroRequest vreq, + List n3Statements) { + //deal with required N3 + List n3Models = new ArrayList(); + for(String n3 : n3Statements){ + try{ + Model model = ModelFactory.createDefaultModel(); + StringReader reader = new StringReader(n3); + model.read(reader, "", "N3"); + n3Models.add( model ); + }catch(Throwable t){ + log.error("error processing required n3 string \n"+ + t.getMessage() + '\n' + + "n3: \n" + n3 ); + } + } + return n3Models; + } + +//there are no retractions based on N3 since N3 is only employed when new literal or resource being processed + + //optional field assertions + //if data property, then this would be empty + public static List getOptionalN3Assertions(EditConfigurationVTwo configuration, MultiValueEditSubmission submission, VitroRequest vreq) { + + if(Utilities.isDataProperty(configuration, vreq)) { + return new ArrayList(); + } + //if object property and existing prop update then return null + //otherwise this needs to be populated + if(Utilities.isObjectProperty(configuration, vreq) && configuration.isObjectPropertyUpdate()) { + return new ArrayList(); + } + + //populate + List optionalN3Assertions = new ArrayList(); + List n3Optional = configuration.getN3Optional(); + //Substitute uris and literals, including for + n3Optional = subUrisAndLiteralsForN3(configuration, submission, vreq, n3Optional); + optionalN3Assertions = processN3Assertions(configuration, submission, vreq, n3Optional); + return optionalN3Assertions; + } + + //"final" or general methods- get the assertions and retractions + public static List populateRetractions(EditConfigurationVTwo configuration, MultiValueEditSubmission submission, VitroRequest vreq) { + List retractions = new ArrayList(); + //if adding new object no retractions, although this should be empty if adding new literal too? + if(!configuration.isDataPropertyUpdate() && !configuration.isObjectPropertyUpdate()) { + return new ArrayList(); + } + + retractions = getRequiredFieldRetractions(configuration, submission, vreq); + + return retractions; + } + + //generally should always have assertions + public static List populateAssertions(EditConfigurationVTwo configuration, MultiValueEditSubmission submission, VitroRequest vreq) { + List assertions = new ArrayList(); + //if editing existing statement, then assertions based on field + if(configuration.isDataPropertyUpdate() || configuration.isObjectPropertyUpdate()) { + assertions = getRequiredFieldAssertions(configuration, submission, vreq); + } + //otherwise, if new literal or value, assertions generated from n3 required or n3 optional statements + else { + assertions = getRequiredN3Assertions(configuration, submission, vreq); + assertions.addAll(getOptionalN3Assertions(configuration, submission, vreq)); + } + return assertions; + } + private static boolean logAddRetract(String msg, Map>add, Map>retract){ log.debug(msg); @@ -276,5 +474,42 @@ public class ProcessRdfForm { if( required != null ) log.debug( "required: " + required.toString() ); if( optional != null ) log.debug( "optional: " + optional.toString() ); return true; - } + } + + public static void updateEditConfigurationForBackButton( + EditConfigurationVTwo editConfig, + MultiValueEditSubmission submission, VitroRequest vreq, OntModel writeModel) { + + //now setup an EditConfiguration so a single back button submissions can be handled + //Do this if data property + if(EditConfigurationUtils.isDataProperty(editConfig.getPredicateUri(), vreq)) { + EditConfigurationVTwo copy = editConfig.copy(); + + //need a new DataPropHash and a new editConfig that uses that, and replace + //the editConfig used for this submission in the session. The same thing + //is done for an update or a new insert since it will convert the insert + //EditConfig into an update EditConfig. + log.debug("attempting to make an updated copy of the editConfig for browser back button support"); + FieldVTwo dataField = copy.getField(copy.getVarNameForObject()); + + DataPropertyStatement dps = new DataPropertyStatementImpl(); + List submitted = submission.getLiteralsFromForm().get(copy.getVarNameForObject()); + if( submitted != null && submitted.size() > 0){ + for(Literal submittedLiteral: submitted) { + dps.setIndividualURI( copy.getSubjectUri() ); + dps.setDatapropURI( copy.getPredicateUri() ); + dps.setDatatypeURI( submittedLiteral.getDatatypeURI()); + dps.setLanguage( submittedLiteral.getLanguage() ); + dps.setData( submittedLiteral.getLexicalForm() ); + + copy.prepareForDataPropUpdate(writeModel, dps); + copy.setDatapropKey( Integer.toString(RdfLiteralHash.makeRdfLiteralHash(dps)) ); + } + EditConfigurationVTwo.putConfigInSession(copy,vreq.getSession()); + } + } + + } + + } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DefaultAddMissingIndividualFormGenerator.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DefaultAddMissingIndividualFormGenerator.java new file mode 100644 index 000000000..8033a1555 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DefaultAddMissingIndividualFormGenerator.java @@ -0,0 +1,488 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators; + +import java.util.Arrays; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpSession; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationUtils; + + +import com.hp.hpl.jena.rdf.model.Literal; +import com.hp.hpl.jena.rdf.model.Model; + +import edu.cornell.mannlib.vitro.webapp.beans.DataProperty; +import edu.cornell.mannlib.vitro.webapp.beans.DataPropertyStatement; +import edu.cornell.mannlib.vitro.webapp.beans.Individual; +import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty; +import edu.cornell.mannlib.vitro.webapp.beans.VClass; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues; +import edu.cornell.mannlib.vitro.webapp.dao.DisplayVocabulary; +import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.Field; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.processEdit.RdfLiteralHash; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditN3GeneratorVTwo; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.SelectListGeneratorVTwo; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.FieldVTwo; +import edu.cornell.mannlib.vitro.webapp.web.MiscWebUtils; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.preprocessors.DefaultAddMissingIndividualFormModelPreprocessor; + +/** + * Generates the edit configuration for a default property form. + * + */ +public class DefaultAddMissingIndividualFormGenerator implements EditConfigurationGenerator { + + private Log log = LogFactory.getLog(DefaultAddMissingIndividualFormGenerator.class); + private boolean isObjectPropForm = false; + private String subjectUri = null; + private String predicateUri = null; + private String objectUri = null; + + private String template = "defaultAddMissingIndividualForm.ftl"; + private static String createCommand = "create"; + private static String objectVarName = "newIndividual"; + private static HashMap defaultsForXSDtypes ; + static { + defaultsForXSDtypes = new HashMap(); + //defaultsForXSDtypes.put("http://www.w3.org/2001/XMLSchema#dateTime","2001-01-01T12:00:00"); + defaultsForXSDtypes.put("http://www.w3.org/2001/XMLSchema#dateTime","#Unparseable datetime defaults to now"); + } + + //Method which checks whether this particular generator should be employed + public static boolean isCreateNewIndividual(VitroRequest vreq, HttpSession session) { + String command = vreq.getParameter("cmd"); + String predicateUri = EditConfigurationUtils.getPredicateUri(vreq); + ObjectProperty objProp = vreq.getWebappDaoFactory().getObjectPropertyDao().getObjectPropertyByURI(predicateUri); + if(objProp != null) { + return(objProp.getOfferCreateNewOption() && + ( + (command != null && command.equals(createCommand)) || + objProp.getSelectFromExisting() == false + ) + ); + } + return false; + } + @Override + public EditConfigurationVTwo getEditConfiguration(VitroRequest vreq, HttpSession session) { + EditConfigurationVTwo editConfiguration = new EditConfigurationVTwo(); + //Set n3 generator + editConfiguration.setN3Generator(new EditN3GeneratorVTwo(editConfiguration)); + + //process subject, predicate, object parameters + this.initProcessParameters(vreq, session, editConfiguration); + + //Assumes this is a simple case of subject predicate var + editConfiguration.setN3Required(this.generateN3Required(vreq)); + + //n3 optional + editConfiguration.setN3Optional(this.generateN3Optional(vreq)); + + + editConfiguration.setNewResources(this.generateNewResources(vreq)); + //In scope + this.setUrisAndLiteralsInScope(editConfiguration); + + //on Form + this.setUrisAndLiteralsOnForm(editConfiguration, vreq); + + editConfiguration.setFilesOnForm(new ArrayList()); + + //Sparql queries + this.setSparqlQueries(editConfiguration); + + //set fields + setFields(editConfiguration, vreq, EditConfigurationUtils.getPredicateUri(vreq)); + + //add preprocesoors + addPreprocessors(vreq, editConfiguration); + + prepareForUpdate(vreq, session, editConfiguration); + + //Form title and submit label now moved to edit configuration template + //TODO: check if edit configuration template correct place to set those or whether + //additional methods here should be used and reference instead, e.g. edit configuration template could call + //default obj property form.populateTemplate or some such method + //Select from existing also set within template itself + setTemplate(editConfiguration, vreq); + //Set edit key + setEditKey(session, editConfiguration, vreq); + return editConfiguration; + } + + private Map generateNewResources(VitroRequest vreq) { + HashMap newResources = new HashMap(); + //TODO: Get default namespace + String defaultNamespace = ""; + newResources.put(objectVarName, defaultNamespace + "individual"); + return newResources; + } + //Need to replace edit key + //TODO:Check if we need to recheck forward to create new or assume that is the case since + //we're using this generator + //In this case we always set a new edit key as the original jsp checked 'isForwardToCreateNew' + //which condition would require that an entirely new edit key be created + private void setEditKey(HttpSession session, EditConfigurationVTwo editConfiguration, VitroRequest vreq) { + String editKey = EditConfigurationVTwo.newEditKey(session); + editConfiguration.setEditKey(editKey); + } + + private void setTemplate(EditConfigurationVTwo editConfiguration, + VitroRequest vreq) { + editConfiguration.setTemplate(template); + + } + + //Initialize setup: process parameters + //Doesn't look like we need to set up separate processing for data property form + private void initProcessParameters(VitroRequest vreq, HttpSession session, EditConfigurationVTwo editConfiguration) { + String formUrl = EditConfigurationUtils.getFormUrl(vreq); + + subjectUri = EditConfigurationUtils.getSubjectUri(vreq); + predicateUri = EditConfigurationUtils.getPredicateUri(vreq); + + editConfiguration.setFormUrl(formUrl); + + + editConfiguration.setUrlPatternToReturnTo("/individual"); + + editConfiguration.setVarNameForSubject("subject"); + editConfiguration.setSubjectUri(subjectUri); + editConfiguration.setEntityToReturnTo(subjectUri); + editConfiguration.setVarNameForPredicate("predicate"); + editConfiguration.setPredicateUri(predicateUri); + + + //this needs to be set for the editing to be triggered properly, otherwise the 'prepare' method + //pretends this is a data property editing statement and throws an error + //"object" : [ "newIndividual" , "${objectUriJson}" , "URI"], + if(EditConfigurationUtils.isObjectProperty(predicateUri, vreq)) { + //not concerned about remainder, can move into default obj prop form if required + this.isObjectPropForm = true; + this.initObjectParameters(vreq); + this.processObjectPropForm(vreq, editConfiguration); + } else { + log.error("Add missing individual called for a data property instead of object property"); + } + } + + + + + + private void initObjectParameters(VitroRequest vreq) { + //in case of object property + objectUri = EditConfigurationUtils.getObjectUri(vreq); + } + + //this particular form uses a different var name for object "newIndividual" + private void processObjectPropForm(VitroRequest vreq, EditConfigurationVTwo editConfiguration) { + editConfiguration.setVarNameForObject(objectVarName); + //If is replace with new, set Object resource to null + if(isReplaceWithNew(vreq)) { + editConfiguration.setObject(null); + } else { + editConfiguration.setObject(objectUri); + } + //this needs to be set for the editing to be triggered properly, otherwise the 'prepare' method + //pretends this is a data property editing statement and throws an error + //TODO: Check if null in case no object uri exists but this is still an object property + if(objectUri != null) { + editConfiguration.setObjectResource(true); + } + } + + + + //Get N3 required + //Handles both object and data property + private List generateN3Required(VitroRequest vreq) { + List n3ForEdit = new ArrayList(); + n3ForEdit.addAll(getN3Prefixes()); + n3ForEdit.add(getN3ForName()); + n3ForEdit.add("?subject ?predicate ?" + objectVarName + " ."); + n3ForEdit.add("?" + objectVarName + " rdf:type " + getRangeClassUri(vreq) + " . "); + return n3ForEdit; + } + + private List getN3Prefixes() { + List prefixStrings = new ArrayList(); + prefixStrings.add("@prefix rdf: ."); + prefixStrings.add("@prefix rdfs: ."); + return prefixStrings; + } + + private String getN3ForName() { + return "?" + objectVarName + " rdfs:label ?name"; + } + + private List generateN3Optional(VitroRequest vreq) { + //flag uri and asserted types need to be added here + List n3Optional = new ArrayList(); + n3Optional.addAll(getN3Prefixes()); + n3Optional.add("?" + objectVarName + " ?inverseProp ?subject ."); + //asserted types string buffer is empty in the original jsp + //TODO: Review original comments in jsp to see what could go here + //n3Optional.add(getN3AssertedTypes(vreq)); + n3Optional.add(getFlagURI(vreq)); + return n3Optional; + + } + + private String getFlagURI(VitroRequest vreq) { + WebappDaoFactory wdf = vreq.getWebappDaoFactory(); + String flagURI = wdf.getVClassDao().getTopConcept().getURI(); + return flagURI; + } + private String getN3AssertedTypes(VitroRequest vreq) { + return null; + } + //Set queries + private String retrieveQueryForInverse () { + String queryForInverse = "PREFIX owl: " + + " SELECT ?inverse_property " + + " WHERE { ?inverse_property owl:inverseOf ?predicate } "; + return queryForInverse; + } + + private void setUrisAndLiteralsInScope(EditConfigurationVTwo editConfiguration) { + HashMap> urisInScope = new HashMap>(); + editConfiguration.setUrisInScope(urisInScope); + editConfiguration.setLiteralsInScope(new HashMap>()); + } + + //n3 should look as follows + //?subject ?predicate ?objectVar + + private void setUrisAndLiteralsOnForm(EditConfigurationVTwo editConfiguration, VitroRequest vreq) { + List urisOnForm = new ArrayList(); + List literalsOnForm = new ArrayList(); + literalsOnForm.add("name"); + editConfiguration.setUrisOnform(urisOnForm); + editConfiguration.setLiteralsOnForm(literalsOnForm); + } + + + //This is for various items + private void setSparqlQueries(EditConfigurationVTwo editConfiguration) { + //Sparql queries defining retrieval of literals etc. + editConfiguration.setSparqlForAdditionalLiteralsInScope(new HashMap()); + + Map urisInScope = new HashMap(); + urisInScope.put("inverseProp", this.retrieveQueryForInverse()); + editConfiguration.setSparqlForAdditionalUrisInScope(urisInScope); + + editConfiguration.setSparqlForExistingLiterals(generateSparqlForExistingLiterals()); + editConfiguration.setSparqlForExistingUris(generateSparqlForExistingUris()); + } + + + //Sparql queries + + + private HashMap generateSparqlForExistingUris() { + HashMap map = new HashMap(); + return map; + } + + private HashMap generateSparqlForExistingLiterals() { + HashMap map = new HashMap(); + String query = StringUtils.join(getN3Prefixes(), ""); + query += "SELECT ?existingName WHERE { ?" + objectVarName + " rdfs:label ?existingName }"; + map.put("name", query); + return map; + } + + + private void setFields(EditConfigurationVTwo editConfiguration, VitroRequest vreq, String predicateUri) { + Map fields = new HashMap(); + if(EditConfigurationUtils.isObjectProperty(EditConfigurationUtils.getPredicateUri(vreq), vreq)) { + fields = getObjectPropertyField(editConfiguration, vreq); + } else { + log.error("Is not object property so fields not set"); + } + + editConfiguration.setFields(fields); + } + + + + + + + private String getRangeClassUri(VitroRequest vreq) { + Individual subject = EditConfigurationUtils.getSubjectIndividual(vreq); + ObjectProperty prop = EditConfigurationUtils.getObjectProperty(vreq); + + WebappDaoFactory wdf = vreq.getWebappDaoFactory(); + if( prop.getRangeVClassURI() == null ) { + // If property has no explicit range, we will use e.g. owl:Thing. + // Typically an allValuesFrom restriction will come into play later. + VClass top = wdf.getVClassDao().getTopConcept(); + prop.setRangeVClassURI(top.getURI()); + } + + VClass rangeClass = null; + String typeOfNew = getTypeOfNew(vreq); + if(typeOfNew != null ) + rangeClass = wdf.getVClassDao().getVClassByURI( typeOfNew ); + if( rangeClass == null ){ + rangeClass = wdf.getVClassDao().getVClassByURI(prop.getRangeVClassURI()); + if( rangeClass == null ) throw new Error ("Cannot find class for range for property. Looking for " + prop.getRangeVClassURI() ); + } + return rangeClass.getURI(); + } + + private Map getObjectPropertyField( + EditConfigurationVTwo editConfiguration, VitroRequest vreq) { + Map fields = new HashMap(); + FieldVTwo field = new FieldVTwo(); + field.setName("name"); + field.setNewResource(false); + //queryForExisting is not being used anywhere in Field + + List validators = new ArrayList(); + validators.add("nonempty"); + field.setValidators(validators); + + //subjectUri and subjectClassUri are not being used in Field + + field.setOptionsType("UNDEFINED"); + //TODO:check why predicate uri is empty on original jsp + field.setPredicateUri(""); + + field.setObjectClassUri(""); + field.setRangeDatatypeUri(null); + + field.setRangeLang(null); + field.setLiteralOptions(new ArrayList>()); + + List assertions = new ArrayList(); + assertions.add(getN3ForName()); + field.setAssertions(assertions); + fields.put(field.getName(), field); + + return fields; + + + } + + private void prepareForUpdate(VitroRequest vreq, HttpSession session, EditConfigurationVTwo editConfiguration) { + //Here, retrieve model from + Model model = (Model) session.getServletContext().getAttribute("jenaOntModel"); + //if object property + if(EditConfigurationUtils.isObjectProperty(EditConfigurationUtils.getPredicateUri(vreq), vreq)){ + Individual objectIndividual = EditConfigurationUtils.getObjectIndividual(vreq); + if(isForwardToCreateButEdit(vreq) || + objectIndividual != null) { + editConfiguration.prepareForObjPropUpdate(model); + } else { + //new object to be created + editConfiguration.prepareForNonUpdate( model ); + } + } else { + log.error("Data property not object property so update can't be done correctly"); + + } + } + + private void addPreprocessors(VitroRequest vreq, EditConfigurationVTwo editConfiguration) { + if(isReplaceWithNew(vreq)) { + //String subjectUri = EditConfigurationUtils.getSubjectUri(vreq); + //String predicateUri = EditConfigurationUtils.getPredicateUri(vreq); + //String objectUri = EditConfigurationUtils.getObjectUri(vreq); + editConfiguration.addModelChangePreprocessor( + new DefaultAddMissingIndividualFormModelPreprocessor( + subjectUri, predicateUri, objectUri)); + + } + } + + //Command processing + private boolean isTypeOfNew(VitroRequest vreq) { + String typeOfNew = getTypeOfNew(vreq); + return (typeOfNew != null && !typeOfNew.isEmpty()); + } + + private String getTypeOfNew(VitroRequest vreq) { + return vreq.getParameter("typeOfNew"); + } + // The default object proepty form offers the option to create a new item + // instead of selecting from existing individuals in the system. + // This is where the request to create a new indivdiual is handled. + //We don't really need this again b/c we wouldn't be using this generator unless we want + //to create a new individual so commenting out for now + /* + private boolean isForwardToCreateNew(VitroRequest vreq) { + String command = vreq.getParameter("cmd"); + ObjectProperty objectProp = EditConfigurationUtils.getObjectProperty(vreq); + if(hasCustomForm(objectProp)) { + return false; + } + + boolean isForwardToCreateNew = + ( objectProp != null && objectProp.getOfferCreateNewOption() ) + && ( objectProp.getSelectFromExisting() == false + || "create".equals(command)); + + return isForwardToCreateNew; + + } + + private boolean hasCustomForm(ObjectProperty objectProp) { + return( objectProp != null && + objectProp.getCustomEntryForm() != null && + !objectProp.getCustomEntryForm().isEmpty()); + + }*/ + + private boolean isReplaceWithNew(VitroRequest vreq) { + ObjectProperty objectProp = EditConfigurationUtils.getObjectProperty(vreq); + boolean isEditOfExistingStmt = isEditOfExistingStatement(vreq); + String command = vreq.getParameter("cmd"); + return (isEditOfExistingStmt + && "create".equals(command)) + && (objectProp != null) + && (objectProp.getOfferCreateNewOption() == true); + } + + private boolean isForwardToCreateButEdit(VitroRequest vreq) { + boolean isEditOfExistingStmt = isEditOfExistingStatement(vreq); + ObjectProperty objectProp = EditConfigurationUtils.getObjectProperty(vreq); + String command = vreq.getParameter("cmd"); + return (isEditOfExistingStmt + && (! "create".equals(command)) + && (objectProp != null) + && (objectProp.getOfferCreateNewOption() == true) + && (objectProp.getSelectFromExisting() == false) + ); + } + + //Is edit of existing statement only applicable to object properties + private boolean isEditOfExistingStatement(VitroRequest vreq) { + //TODO: Check if also applicable to data property, currently returning false + if(EditConfigurationUtils.isDataProperty(EditConfigurationUtils.getPredicateUri(vreq), vreq)) { + return false; + } + Individual object = EditConfigurationUtils.getObjectIndividual(vreq); + return (object != null); + + } + + + + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DefaultDeleteGenerator.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DefaultDeleteGenerator.java new file mode 100644 index 000000000..a93e1cd32 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/DefaultDeleteGenerator.java @@ -0,0 +1,75 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators; + +import java.util.Arrays; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpSession; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationUtils; + + +import com.hp.hpl.jena.rdf.model.Literal; +import com.hp.hpl.jena.rdf.model.Model; +import com.hp.hpl.jena.ontology.OntModel; +import edu.cornell.mannlib.vitro.webapp.beans.DataProperty; +import edu.cornell.mannlib.vitro.webapp.beans.DataPropertyStatement; +import edu.cornell.mannlib.vitro.webapp.beans.Individual; +import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty; +import edu.cornell.mannlib.vitro.webapp.beans.VClass; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues; +import edu.cornell.mannlib.vitro.webapp.dao.DisplayVocabulary; +import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.Field; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.processEdit.RdfLiteralHash; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditN3GeneratorVTwo; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.SelectListGeneratorVTwo; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.FieldVTwo; +import edu.cornell.mannlib.vitro.webapp.web.MiscWebUtils; +import edu.cornell.mannlib.vitro.webapp.search.beans.ProhibitedFromSearch; + +/** + * Generates delete form which submits the deletion request to the deletion controller. + * This is the page to which the user is redirected if they select Delete on the default property form. + * + */ +public class DefaultDeleteGenerator implements EditConfigurationGenerator { + + private Log log = LogFactory.getLog(DefaultObjectPropertyFormGenerator.class); + private String subjectUri = null; + private String predicateUri = null; + private String objectUri = null; + private String datapropKeyStr= null; + private int dataHash = 0; + private DataPropertyStatement dps = null; + private String dataLiteral = null; + private String template = "confirmDeletePropertyForm.ftl"; + private static HashMap defaultsForXSDtypes ; + static { + defaultsForXSDtypes = new HashMap(); + //defaultsForXSDtypes.put("http://www.w3.org/2001/XMLSchema#dateTime","2001-01-01T12:00:00"); + defaultsForXSDtypes.put("http://www.w3.org/2001/XMLSchema#dateTime","#Unparseable datetime defaults to now"); + } + + //In this case, simply return the edit configuration currently saved in session + //Since this is forwarding from another form, an edit configuration should already exist in session + @Override + public EditConfigurationVTwo getEditConfiguration(VitroRequest vreq, + HttpSession session) { + EditConfigurationVTwo editConfiguration = EditConfigurationVTwo.getConfigFromSession(session, vreq); + //Set template to be confirm delete + editConfiguration.setTemplate(template); + return editConfiguration; + } + +} 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 c7e407011..fd7899d8e 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 @@ -18,7 +18,7 @@ import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationUti import com.hp.hpl.jena.rdf.model.Literal; import com.hp.hpl.jena.rdf.model.Model; - +import com.hp.hpl.jena.ontology.OntModel; import edu.cornell.mannlib.vitro.webapp.beans.DataProperty; import edu.cornell.mannlib.vitro.webapp.beans.DataPropertyStatement; import edu.cornell.mannlib.vitro.webapp.beans.Individual; @@ -36,6 +36,7 @@ import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditN3GeneratorVTwo; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.SelectListGeneratorVTwo; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.FieldVTwo; import edu.cornell.mannlib.vitro.webapp.web.MiscWebUtils; +import edu.cornell.mannlib.vitro.webapp.search.beans.ProhibitedFromSearch; /** * Generates the edit configuration for a default property form. @@ -63,7 +64,18 @@ public class DefaultObjectPropertyFormGenerator implements EditConfigurationGene @Override public EditConfigurationVTwo getEditConfiguration(VitroRequest vreq, HttpSession session) { + + //Check if create new and return specific edit configuration from that generator. + if(DefaultAddMissingIndividualFormGenerator.isCreateNewIndividual(vreq, session)) { + DefaultAddMissingIndividualFormGenerator generator = new DefaultAddMissingIndividualFormGenerator(); + return generator.getEditConfiguration(vreq, session); + } + //TODO: Add a generator for delete: based on command being delete - propDelete.jsp //Generate a edit conf for the default object property form and return it. + return getDefaultObjectEditConfiguration(vreq, session); + } + + private EditConfigurationVTwo getDefaultObjectEditConfiguration(VitroRequest vreq, HttpSession session) { EditConfigurationVTwo editConfiguration = new EditConfigurationVTwo(); //Set n3 generator editConfiguration.setN3Generator(new EditN3GeneratorVTwo(editConfiguration)); @@ -100,19 +112,30 @@ public class DefaultObjectPropertyFormGenerator implements EditConfigurationGene prepareForUpdate(vreq, session, editConfiguration); + //After the main processing is done, check if select from existing process + processProhibitedFromSearch(vreq, session, editConfiguration); + //Form title and submit label now moved to edit configuration template //TODO: check if edit configuration template correct place to set those or whether //additional methods here should be used and reference instead, e.g. edit configuration template could call //default obj property form.populateTemplate or some such method //Select from existing also set within template itself setTemplate(editConfiguration, vreq); + //Set edit key + setEditKey(editConfiguration, vreq); return editConfiguration; } + private void setEditKey(EditConfigurationVTwo editConfiguration, VitroRequest vreq) { + String editKey = EditConfigurationUtils.getEditKey(vreq); + editConfiguration.setEditKey(editKey); + } + private void setTemplate(EditConfigurationVTwo editConfiguration, VitroRequest vreq) { String template = objectPropertyTemplate; - if(EditConfigurationUtils.isDataProperty(editConfiguration.getPredicateUri(), vreq)){ + + if(EditConfigurationUtils.isDataProperty(editConfiguration.getPredicateUri(), vreq)){ template = dataPropertyTemplate; } editConfiguration.setTemplate(template); @@ -137,7 +160,6 @@ public class DefaultObjectPropertyFormGenerator implements EditConfigurationGene editConfiguration.setPredicateUri(predicateUri); - //this needs to be set for the editing to be triggered properly, otherwise the 'prepare' method //pretends this is a data property editing statement and throws an error //"object" : [ "objectVar" , "${objectUriJson}" , "URI"], @@ -189,7 +211,6 @@ public class DefaultObjectPropertyFormGenerator implements EditConfigurationGene editConfiguration.setObjectResource(false); //set data prop value, data prop key str, editConfiguration.setDatapropKey((datapropKeyStr==null)?"":datapropKeyStr); - DataProperty prop = EditConfigurationUtils.getDataProperty(vreq); editConfiguration.setVarNameForObject(dataLiteral); //original set datapropValue, which in this case would be empty string but no way here editConfiguration.setDatapropValue(""); @@ -218,14 +239,17 @@ public class DefaultObjectPropertyFormGenerator implements EditConfigurationGene List n3Inverse = new ArrayList(); //Note that for proper substitution, spaces expected between variables, i.e. string //of n3 format - n3Inverse.add("?objectVar ?inverseProp ?subject ."); + //Set only if object property form + if(this.isObjectPropForm) { + n3Inverse.add("?objectVar ?inverseProp ?subject ."); + } return n3Inverse; } //Set queries private String retrieveQueryForInverse () { - String queryForInverse = "PREFIX owl: " + String queryForInverse = "PREFIX owl: " + " SELECT ?inverse_property " + " WHERE { ?inverse_property owl:inverseOf ?predicate } "; return queryForInverse; @@ -253,13 +277,15 @@ public class DefaultObjectPropertyFormGenerator implements EditConfigurationGene private void setUrisAndLiteralsOnForm(EditConfigurationVTwo editConfiguration, VitroRequest vreq) { List urisOnForm = new ArrayList(); - urisOnForm.add("objectVar"); - editConfiguration.setUrisOnform(urisOnForm); List literalsOnForm = new ArrayList(); if(EditConfigurationUtils.isDataProperty(EditConfigurationUtils.getPredicateUri(vreq), vreq)) { //if data property set to data literal literalsOnForm.add(dataLiteral); + } else { + //uris on form should be empty if data property + urisOnForm.add("objectVar"); } + editConfiguration.setUrisOnform(urisOnForm); editConfiguration.setLiteralsOnForm(literalsOnForm); } @@ -313,6 +339,7 @@ public class DefaultObjectPropertyFormGenerator implements EditConfigurationGene field.setNewResource(false); //queryForExisting is not being used anywhere in Field String rangeDatatypeUri = getRangeDatatypeUri(editConfiguration, vreq); + String rangeLang = getRangeLang(editConfiguration, vreq); List validators = new ArrayList(); validators.add("datatype:" + rangeDatatypeUri); @@ -325,8 +352,10 @@ public class DefaultObjectPropertyFormGenerator implements EditConfigurationGene field.setPredicateUri(null); field.setObjectClassUri(null); field.setRangeDatatypeUri(rangeDatatypeUri); - - field.setRangeLang(getRangeLang(editConfiguration, vreq)); + //have either range datatype uri or range lang + if(rangeDatatypeUri == null) { + field.setRangeLang(rangeLang); + } field.setLiteralOptions(getLiteralOptions(editConfiguration, vreq)); //set assertions @@ -368,6 +397,8 @@ public class DefaultObjectPropertyFormGenerator implements EditConfigurationGene log.debug("language attribute of ["+rangeLang+"] on data property statement in DefaultDataPropertyFormGenerator"); } } + if( rangeLang != null && rangeLang.trim().length() == 0) + rangeLang = null; return rangeLang; } @@ -393,7 +424,9 @@ public class DefaultObjectPropertyFormGenerator implements EditConfigurationGene } else { log.debug("No incoming dataproperty statement attribute for property "+prop.getPublicName()+"; adding a new statement"); } - + if( rangeDatatypeUri != null && rangeDatatypeUri.trim().length() == 0) + rangeDatatypeUri = null; + return rangeDatatypeUri; } @@ -461,91 +494,35 @@ public class DefaultObjectPropertyFormGenerator implements EditConfigurationGene String typeOfNew = vreq.getParameter("typeOfNew"); return (typeOfNew != null && !typeOfNew.isEmpty()); } - //orignal code for process to forward new is below - /* - private ResponseValues processForwardToCreateNew(VitroRequest vreq) { - String command = vreq.getParameter("cmd"); - ObjectProperty objectProp = (ObjectProperty) vreq.getAttribute("predicate"); - - // TODO Auto-generated method stub - // The default object proepty form offers the option to create a new item - // instead of selecting from existing individuals in the system. - // This is where the request to create a new indivdiual is handled. - // - // Forward to create new is part of the default object property form - // it should be handled in that form's EditConfigurationVTwo, not here. - // The code that sets up the EditConfigurationVTwo should decide on - // different configurations and templates to use based on isForwardToCreateNew. - //TODO: make sure that forward to create new works on the default object property form - - - if( isFowardToCreateNew(vreq, objectProp, command)){ - return handleForwardToCreateNew(vreq, command, objectProp, isEditOfExistingStmt(vreq)); - } - //what should this return otherwise and should this in fact redirect - return null; - - }*/ - /* - Forward to create new is part of the default object property form - it should be handled in that form's EditConfigurationVTwo, not here. - The code that sets up the EditConfigurationVTwo should decide on - different configurations and templates to use based on isForwardToCreateNew. -*//* -boolean isFowardToCreateNew(VitroRequest vreq, ObjectProperty objectProp, String command){ - //Offer create new and select from existing are ignored if there is a custom form - if( objectProp != null && objectProp.getCustomEntryForm() != null && !objectProp.getCustomEntryForm().isEmpty()){ - return false; - } else { - - boolean isForwardToCreateNew = - ( objectProp != null && objectProp.getOfferCreateNewOption() && objectProp.getSelectFromExisting() == false) - || ( objectProp != null && objectProp.getOfferCreateNewOption() && "create".equals(command)); - - return isForwardToCreateNew; - } -} - -ResponseValues handleForwardToCreateNew(VitroRequest vreq, String command, ObjectProperty objectProp, boolean isEditOfExistingStmt){ - vreq.setAttribute("isForwardToCreateNew", new Boolean(true)); - - //If a objectProperty is both provideSelect and offerCreateNewOption - // and a user goes to a defaultObjectProperty.jsp form then the user is - // offered the option to create a new Individual and replace the - // object in the existing objectPropertyStatement with this new individual. - boolean isReplaceWithNew = - isEditOfExistingStmt && "create".equals(command) - && objectProp != null && objectProp.getOfferCreateNewOption() == true; - - // If an objectProperty is selectFromExisitng==false and offerCreateNewOption == true - // the we want to forward to the create new form but edit the existing object - // of the objPropStmt. - boolean isForwardToCreateButEdit = - isEditOfExistingStmt && objectProp != null - && objectProp.getOfferCreateNewOption() == true - && objectProp.getSelectFromExisting() == false - && ! "create".equals(command); - - //bdc34: maybe when doing a create new, the custom form should be on the class, not the property? - String form; - if( isReplaceWithNew ){ - vreq.setAttribute("isReplaceWithNew", new Boolean(true)); - form = DEFAULT_ADD_INDIVIDUAL; - }else if( isForwardToCreateButEdit ){ - vreq.setAttribute("isForwardToCreateButEdit", new Boolean(true)); - form = DEFAULT_ADD_INDIVIDUAL; - }else { - form = DEFAULT_ADD_INDIVIDUAL; - } - - //forward to form? - //There should be no error message here - //TODO: Return redirect response values or find out to process this here - HashMap map = new HashMap(); - map.put("errorMessage", "forweard to create new is not yet implemented"); - return new TemplateResponseValues("error-message.ftl", map); -} -*/ + private boolean isSelectFromExisting(VitroRequest vreq) { + String predicateUri = EditConfigurationUtils.getPredicateUri(vreq); + if(EditConfigurationUtils.isDataProperty(predicateUri, vreq)) { + return false; + } + ObjectProperty objProp = EditConfigurationUtils.getObjectPropertyForPredicate(vreq, EditConfigurationUtils.getPredicateUri(vreq)); + return objProp.getSelectFromExisting(); + } + + //Additional processing, eg. select from existing + //This is really process prohibited from search + private void processProhibitedFromSearch(VitroRequest vreq, HttpSession session, EditConfigurationVTwo editConfig) { + if(isSelectFromExisting(vreq)) { + // set ProhibitedFromSearch object so picklist doesn't show + // individuals from classes that should be hidden from list views + //TODO: Check how model is retrieved + OntModel displayOntModel = + (OntModel) session.getServletContext() + .getAttribute("displayOntModel"); + if (displayOntModel != null) { + ProhibitedFromSearch pfs = new ProhibitedFromSearch( + DisplayVocabulary.SEARCH_INDEX_URI, displayOntModel); + if( editConfig != null ) + editConfig.setProhibitedFromSearch(pfs); + } + } + } + + } 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 63c84f0fb..8b053c2be 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 @@ -2,9 +2,12 @@ package edu.cornell.mannlib.vitro.webapp.edit.n3editing.controller; +import static edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationUtils.getPredicateUri; + +import java.net.URLEncoder; import java.util.HashMap; import java.util.Map; -import java.net.URLEncoder; + import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @@ -12,24 +15,22 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.hp.hpl.jena.rdf.model.Model; + +import edu.cornell.mannlib.vitro.webapp.beans.DataPropertyStatement; import edu.cornell.mannlib.vitro.webapp.beans.Individual; import edu.cornell.mannlib.vitro.webapp.beans.Property; -import edu.cornell.mannlib.vitro.webapp.beans.DataProperty; -import edu.cornell.mannlib.vitro.webapp.beans.DataPropertyStatement; -import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerHttpServlet; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.RedirectResponseValues; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues; -import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; +import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationUtils; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators.EditConfigurationGenerator; -import edu.cornell.mannlib.vitro.webapp.web.MiscWebUtils; -import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationUtils; -import edu.cornell.mannlib.vitro.webapp.web.templatemodels.edit.EditConfigurationTemplateModel; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.processEdit.RdfLiteralHash; +import edu.cornell.mannlib.vitro.webapp.web.templatemodels.edit.EditConfigurationTemplateModel; /** * This servlet is intended to handle all requests to create a form for use * by the N3 editing system. It will examine the request parameters, determine @@ -60,25 +61,19 @@ public class EditRequestDispatchController extends FreemarkerHttpServlet { if(isErrorCondition(vreq)){ return doHelp(vreq, getErrorMessage(vreq)); } - - //if delete, originally forwarded but here would have to do something else - // processDelete(vreq); - + //TODO: Check if skip edit form needs to go here or elsewhere //in case form needs to be redirected b/c of special individuals // processSkipEditForm(vreq); //Get the edit generator name String editConfGeneratorName = processEditConfGeneratorName(vreq); - //if need to forward to create new object, handle that - //why is this not done earlier? why aren't forwards handled in the same place? - // processForwardToCreateNew(vreq); + //forward to create new handled in default object property form generator //session attribute setSessionRequestFromEntity(vreq); //Test - boolean isObjectProp = EditConfigurationUtils.isObjectProperty(EditConfigurationUtils.getPredicateUri(vreq), vreq); - boolean isDataProp = EditConfigurationUtils.isDataProperty(EditConfigurationUtils.getPredicateUri(vreq), vreq); + /**** make new or get an existing edit configuration ***/ EditConfigurationVTwo editConfig = setupEditConfiguration(editConfGeneratorName, vreq); @@ -109,12 +104,10 @@ public class EditRequestDispatchController extends FreemarkerHttpServlet { private EditConfigurationVTwo setupEditConfiguration(String editConfGeneratorName, VitroRequest vreq) { - //Still based on request attribute, if edit key exists on request, then use otherwise generate new edit key - String editKey = EditConfigurationUtils.getEditKey(vreq); + HttpSession session = vreq.getSession(); EditConfigurationVTwo editConfig = makeEditConfigurationVTwo( editConfGeneratorName, vreq, session); - //Set edit key for edit configuration here - editConfig.setEditKey(editKey); + //edit key should now always be set in the generator class //put edit configuration in session EditConfigurationVTwo.putConfigInSession(editConfig, session); @@ -137,7 +130,7 @@ public class EditRequestDispatchController extends FreemarkerHttpServlet { WebappDaoFactory wdf = vreq.getWebappDaoFactory(); //use default object property form if nothing else works String editConfGeneratorName = DEFAULT_OBJ_FORM; - String predicateUri = EditConfigurationUtils.getPredicateUri(vreq); + String predicateUri = getPredicateUri(vreq); String formParam = getFormParam(vreq); // *** handle the case where the form is specified as a request parameter *** if( predicateUri == null && ( formParam != null && !formParam.isEmpty()) ){ @@ -250,63 +243,6 @@ public class EditRequestDispatchController extends FreemarkerHttpServlet { return errorMessage; } - - //Based on subject, predicate, object and command, set the appropriate attributes - //TODO: Check if setting attributes the way to go or alternative - //Leaving these in for now but shouldn't depending on vreq attributes at all - //Generators should process them - //leaving here for reference, delete later - private void processStoreParameters(VitroRequest vreq) { - - //TODO: Check if json version required any longer - //subject - /* - processSubject(vreq); - processPredicate(vreq); - processObject(vreq); - processFormParam(vreq); - processTypeOfNew(vreq); - processUrlPatternReturn(vreq); - saveCurrentUrl(vreq); - - //if data propety - if(isDataProperty(vreq.getParameter("predicateUri"), vreq)) { - processDataProperty(vreq); - }*/ - } - - private void processDataProperty(VitroRequest vreq) { - String datapropKeyStr = vreq.getParameter("datapropKey"); - String predicateUri = vreq.getParameter("predicateUri"); - String subjectUri = vreq.getParameter("subjectUri"); - WebappDaoFactory wdf = vreq.getWebappDaoFactory(); - HttpSession session = vreq.getSession(); - Individual subject = wdf.getIndividualDao().getIndividualByURI(subjectUri); - int dataHash = 0; - if( datapropKeyStr != null ){ - try { - dataHash = Integer.parseInt(datapropKeyStr); - vreq.setAttribute("datahash", dataHash); - log.debug("Found a datapropKey in parameters and parsed it to int: " + dataHash); - } catch (NumberFormatException ex) { - //return doHelp(vreq, "Cannot decode incoming datapropKey value "+datapropKeyStr+" as an integer hash in EditDataPropStmtRequestDispatchController"); - } - } - - DataPropertyStatement dps = null; - if( dataHash != 0) { - Model model = (Model)session.getServletContext().getAttribute("jenaOntModel"); - dps = RdfLiteralHash.getPropertyStmtByHash(subject, predicateUri, dataHash, model); - - if (dps==null) { - log.error("No match to existing data property \""+predicateUri+"\" statement for subject \""+subjectUri+"\" via key "+datapropKeyStr); - //TODO: Needs to forward to dataPropMissingStatement.jsp - //return null; - } - vreq.setAttribute("dataprop", dps ); - } - } - //should return null private String getFormParam(VitroRequest vreq) { String formParam = (String) vreq.getAttribute("editForm"); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/ProcessRdfFormController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/ProcessRdfFormController.java index 11ed6ba43..e448155f1 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/ProcessRdfFormController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/controller/ProcessRdfFormController.java @@ -3,6 +3,7 @@ package edu.cornell.mannlib.vitro.webapp.edit.n3editing.controller; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -16,12 +17,21 @@ import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationUtils; + import com.hp.hpl.jena.ontology.OntModel; +import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.Property; + +import com.hp.hpl.jena.rdf.model.Resource; import com.hp.hpl.jena.rdf.model.ResourceFactory; +import com.hp.hpl.jena.rdf.model.Literal; import edu.cornell.mannlib.vitro.webapp.beans.Individual; import edu.cornell.mannlib.vitro.webapp.beans.IndividualImpl; +import edu.cornell.mannlib.vitro.webapp.beans.DataPropertyStatement; +import edu.cornell.mannlib.vitro.webapp.beans.DataProperty; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.processEdit.RdfLiteralHash; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerHttpServlet; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; @@ -29,6 +39,7 @@ import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.ParamMa import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Route; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.RedirectResponseValues; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues; import edu.cornell.mannlib.vitro.webapp.dao.InsertException; import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.AdditionsAndRetractions; @@ -39,6 +50,7 @@ import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.MultiValueEditSubmis import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.ProcessRdfForm; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.processEdit.EditN3Utils; +import edu.cornell.mannlib.vitro.webapp.edit.EditLiteral; /** * This servlet will process EditConfigurations with query parameters * to perform an edit. @@ -54,10 +66,9 @@ public class ProcessRdfFormController extends FreemarkerHttpServlet{ // You can get a reference to the servlet from the context. // this will need to be converted from a jsp to something else public static final String POST_EDIT_CLEANUP_JSP = "postEditCleanUp.jsp"; - @Override - protected ResponseValues processRequest(VitroRequest vreq) { + protected ResponseValues processRequest(VitroRequest vreq) { //get the EditConfiguration EditConfigurationVTwo configuration = getEditConfiguration(vreq); if(configuration == null) @@ -67,6 +78,7 @@ public class ProcessRdfFormController extends FreemarkerHttpServlet{ MultiValueEditSubmission submission = new MultiValueEditSubmission(vreq.getParameterMap(), configuration); EditSubmissionUtils.putEditSubmissionInSession(vreq.getSession(), submission); + //if errors, return error response ResponseValues errorResponse = doValidationErrors(vreq, configuration, submission); if( errorResponse != null ) return errorResponse; @@ -75,12 +87,15 @@ public class ProcessRdfFormController extends FreemarkerHttpServlet{ OntModel queryModel = configuration.getQueryModelSelector().getModel(vreq, getServletContext()); OntModel writeModel = configuration.getWriteModelSelector().getModel(vreq,getServletContext()); - AdditionsAndRetractions changes; - if(configuration.isUpdate()){ - changes = ProcessRdfForm.editExistingResource(configuration, submission); - }else{ - changes = ProcessRdfForm.createNewResource(configuration, submission); - } + //If data property check for back button confusion + boolean isBackButton = checkForBackButtonConfusion(configuration, vreq, queryModel); + if(isBackButton) { + //Process back button issues and do a return here + return doProcessBackButton(configuration, submission, vreq); + } + + //Otherwise, process as usual + AdditionsAndRetractions changes = getAdditionsAndRetractions(configuration, submission, vreq); if( configuration.isUseDependentResourceDelete() ) changes = ProcessRdfForm.addDependentDeletes(changes, queryModel); @@ -90,19 +105,84 @@ public class ProcessRdfFormController extends FreemarkerHttpServlet{ ProcessRdfForm.applyChangesToWriteModel(changes, queryModel, writeModel, EditN3Utils.getEditorUri(vreq) ); //Here we are trying to get the entity to return to URL, - if( configuration.getEntityToReturnTo() != null ){ - vreq.setAttribute("entityToReturnTo", ProcessRdfForm.substitueForURL( configuration, submission)); - } - - return doPostEdit(vreq); + //More involved processing for data property apparently + //Also what do we actually DO with the vreq attribute: Answer: Use it for redirection + //And no where else so we could technically calculate and send that here + String entityToReturnTo = ProcessRdfForm.processEntityToReturnTo(configuration, submission, vreq); + //For data property processing, need to update edit configuration for back button + ProcessRdfForm.updateEditConfigurationForBackButton(configuration, submission, vreq, writeModel); + return doPostEdit(vreq, entityToReturnTo); + } + + //In case of back button confusion + //Currently returning an error message: + //Later TODO: Per Brian Caruso's instructions, replicate + //the logic in the original datapropertyBackButtonProblems.jsp + private ResponseValues doProcessBackButton(EditConfigurationVTwo configuration, + MultiValueEditSubmission submission, VitroRequest vreq) { + + //The bulk of the processing should probably/already sits in ProcessRdfForm so that should remain there + //The issue is what then to do with the actual redirect? What do we redirect to? + HashMap map = new HashMap(); + map.put("errorMessage", "Back button confusion has occurred"); + ResponseValues values = new TemplateResponseValues("error-message.ftl", map); + return values; + } + + //Check for "back button" confusion specifically for data property editing although need to check if this applies to object property editing? + //TODO: Check if only applicable to data property editing + private boolean checkForBackButtonConfusion(EditConfigurationVTwo editConfig, VitroRequest vreq, Model model) { + //back button confusion limited to data property + if(EditConfigurationUtils.isObjectProperty(editConfig.getPredicateUri(), vreq)) { + return false; + } + Individual subject = EditConfigurationUtils.getSubjectIndividual(vreq); + WebappDaoFactory wdf = vreq.getWebappDaoFactory(); + if (editConfig.getDatapropKey() == null + || editConfig.getDatapropKey().length() == 0) + return false; + + int dpropHash = Integer.parseInt(editConfig.getDatapropKey()); + DataPropertyStatement dps = RdfLiteralHash.getPropertyStmtByHash(subject, editConfig.getPredicateUri(), dpropHash, model); + + if (dps != null) + return false; + DataProperty dp = wdf.getDataPropertyDao().getDataPropertyByURI( + editConfig.getPredicateUri()); + if (dp != null) { + if (dp.getDisplayLimit() == 1 /* || dp.isFunctional() */) + return false; + else + return true; + } + return false; + } + + private AdditionsAndRetractions getAdditionsAndRetractions( + EditConfigurationVTwo configuration, + MultiValueEditSubmission submission, VitroRequest vreq) { + + AdditionsAndRetractions changes = null; + //if editing existing resource or literal + if(configuration.isObjectPropertyUpdate() || configuration.isDataPropertyUpdate()) { + changes = ProcessRdfForm.editExistingStatement(configuration, submission, vreq); + } else { + changes = ProcessRdfForm.createNewStatement(configuration, submission, vreq); + } + + return changes; + } + + private EditConfigurationVTwo getEditConfiguration(HttpServletRequest request) { HttpSession session = request.getSession(); EditConfigurationVTwo editConfiguration = EditConfigurationVTwo.getConfigFromSession(session, request); return editConfiguration; } + // private ResponseValues doEditConfigNotFound(VitroRequest request) { // HashMapmap = new HashMap(); // map.put("message", "No editing configuration found, cannot process edit."); @@ -128,11 +208,12 @@ public class ProcessRdfFormController extends FreemarkerHttpServlet{ } return null; //no errors } + + //TODO: Is this the equivalent of post Edit Cleanup + //Also do we wish to continue setting attributes on the request? - private RedirectResponseValues doPostEdit(VitroRequest vreq ) { - String resourceToRedirectTo = null; + private RedirectResponseValues doPostEdit(VitroRequest vreq, String resourceToRedirectTo ) { String urlPattern = null; - String predicateLocalName = null; String predicateAnchor = ""; HttpSession session = vreq.getSession(false); if( session != null ) { @@ -143,54 +224,20 @@ public class ProcessRdfFormController extends FreemarkerHttpServlet{ MultiValueEditSubmission editSub = EditSubmissionUtils.getEditSubmissionFromSession(session,editConfig); EditSubmissionUtils.clearEditSubmissionInSession(session, editSub); - if( editConfig != null ){ - String predicateUri = editConfig.getPredicateUri(); - if( predicateUri != null ){ - try{ - Property prop = ResourceFactory.createProperty(predicateUri); - predicateLocalName = prop.getLocalName(); - }catch (com.hp.hpl.jena.shared.InvalidPropertyURIException e){ - log.debug("could not convert predicateUri into a valid URI",e); - } - } - - if( editConfig.getEntityToReturnTo() != null && editConfig.getEntityToReturnTo().startsWith("?") ){ - resourceToRedirectTo = (String)vreq.getAttribute("entityToReturnTo"); - }else{ - resourceToRedirectTo = editConfig.getEntityToReturnTo(); - } - - //if there is no entity to return to it is likely a cancel - if( resourceToRedirectTo == null || resourceToRedirectTo.length() == 0 ) - resourceToRedirectTo = editConfig.getSubjectUri(); + //Get prop local name if it exists + String predicateLocalName = Utilities.getPredicateLocalName(editConfig); + + //Get url pattern + urlPattern = Utilities.getPostEditUrlPattern(vreq, editConfig); + predicateAnchor = Utilities.getPredicateAnchorPostEdit(urlPattern, predicateLocalName); + if(predicateAnchor != null && !predicateAnchor.isEmpty()) { + vreq.setAttribute("predicateAnchor", predicateAnchor); + } - //set up base URL - String cancel = vreq.getParameter("cancel"); - String urlPatternToReturnTo = null; - String urlPatternToCancelTo = null; - if (editConfig != null) { - urlPatternToReturnTo = editConfig.getUrlPatternToReturnTo(); - urlPatternToCancelTo = vreq.getParameter("url"); - } - // If a different cancel return path has been designated, use it. Otherwise, use the regular return path. - if (cancel != null && cancel.equals("true") && !StringUtils.isEmpty(urlPatternToCancelTo)) { - urlPattern = urlPatternToCancelTo; - } else if (!StringUtils.isEmpty(urlPatternToReturnTo)) { - urlPattern = urlPatternToReturnTo; - } else { - urlPattern = "/individual"; - } - - //looks like a redirect to a profile page, try to add anchor for property that was just edited. - if( urlPattern.endsWith("individual") || urlPattern.endsWith("entity") ){ - if( predicateLocalName != null && predicateLocalName.length() > 0){ - predicateAnchor = "#" + predicateLocalName; - vreq.setAttribute("predicateAnchor", predicateAnchor); - } - } } + //Redirect appropriately if( resourceToRedirectTo != null ){ ParamMap paramMap = new ParamMap(); paramMap.put("uri", resourceToRedirectTo); @@ -210,37 +257,59 @@ public class ProcessRdfFormController extends FreemarkerHttpServlet{ private static Log log = LogFactory.getLog(ProcessRdfFormController.class); static Random random = new Random(); + public static String assertionsType = "assertions"; + public static String retractionsType = "retractions"; - public static Map> fieldsToAssertionMap( Map fields){ - Map> out = new HashMap>(); + public static boolean isDataProperty(EditConfigurationVTwo configuration, VitroRequest vreq) { + return EditConfigurationUtils.isDataProperty(configuration.getPredicateUri(), vreq); + } + + public static boolean isObjectProperty(EditConfigurationVTwo configuration, VitroRequest vreq) { + + return EditConfigurationUtils.isObjectProperty(configuration.getPredicateUri(), vreq); + } + + public static List makeListCopy(List list) { + List copyOfN3 = new ArrayList(); + for( String str : list){ + copyOfN3.add(str); + } + return copyOfN3; + } + + public static List getFieldStmts(FieldVTwo field, String stmtType) { + if(stmtType.equals(assertionsType)) { + return field.getAssertions(); + } else { + return field.getRetractions(); + } + } + + public static Map> fieldsToN3Map(Map fields, String stmtType) { + Map> out = new HashMap>(); for( String fieldName : fields.keySet()){ FieldVTwo field = fields.get(fieldName); - - List copyOfN3 = new ArrayList(); - for( String str : field.getAssertions()){ - copyOfN3.add(str); - } + List n3Stmts = getFieldStmts(field, stmtType); + List copyOfN3 = makeListCopy(n3Stmts); out.put( fieldName, copyOfN3 ); } return out; } + + public static Map> fieldsToAssertionMap( Map fields){ + return fieldsToN3Map(fields, assertionsType); + } public static Map> fieldsToRetractionMap( Map fields){ - Map> out = new HashMap>(); - for( String fieldName : fields.keySet()){ - FieldVTwo field = fields.get(fieldName); - - List copyOfN3 = new ArrayList(); - for( String str : field.getRetractions()){ - copyOfN3.add(str); - } - out.put( fieldName, copyOfN3 ); - } - return out; + return fieldsToN3Map(fields, retractionsType); } - public static Map newToUriMap(Map newResources, WebappDaoFactory wdf){ - HashMap newVarsToUris = new HashMap(); + //this works differently based on whether this is object property editing or data property editing + //Object prop version below + //Also updating to allow an array to be returned with the uri instead of a single uri + //Note this would require more analysis in context of multiple uris possible for a field + public static Map> newToUriMap(Map newResources, WebappDaoFactory wdf){ + HashMap> newVarsToUris = new HashMap>(); HashSet newUris = new HashSet(); for( String key : newResources.keySet()){ String prefix = newResources.get(key); @@ -248,7 +317,9 @@ public class ProcessRdfFormController extends FreemarkerHttpServlet{ while( newUris.contains(uri) ){ uri = makeNewUri(prefix,wdf); } - newVarsToUris.put(key,uri); + List urisList = new ArrayList(); + urisList.add(uri); + newVarsToUris.put(key,urisList); newUris.add(uri); } return newVarsToUris; @@ -283,8 +354,178 @@ public class ProcessRdfFormController extends FreemarkerHttpServlet{ return goodURI; } - - - } + //Data prop version, from processDatapropRdfForm.jsp + //TODO: Should this even be set this way as this needs to be changed somehow? + public static String defaultUriPrefix = "http://vivo.library.cornell.edu/ns/0.1#individual"; + public static Map> newToUriMap(Map newResources, + Model model) { + HashMap> newUris = new HashMap>(); + for (String key : newResources.keySet()) { + List urisList = new ArrayList(); + urisList.add(makeNewUri(newResources.get(key), model)); + newUris.put(key, urisList); + } + return newUris; + } + + //This is the data property method, this is to be removed + //TODO: Remove this method and ensure this is not called + public static String makeNewUri(String prefix, Model model) { + if (prefix == null || prefix.length() == 0) + prefix = defaultUriPrefix; + + String uri = prefix + random.nextInt(); + Resource r = ResourceFactory.createResource(uri); + while (model.containsResource(r)) { + uri = prefix + random.nextInt(); + r = ResourceFactory.createResource(uri); + } + return uri; + } + + //TODO: Check if this would be correct with multiple values and uris being passed back + //First, need to order by uris in original and new values probably and + //for literals, order by? Alphabetical or numeric value? Hard to say + public static boolean hasFieldChanged(String fieldName, + EditConfigurationVTwo editConfig, MultiValueEditSubmission submission) { + List orgValue = editConfig.getUrisInScope().get(fieldName); + List newValue = submission.getUrisFromForm().get(fieldName); + //Sort both just in case + if(orgValue != null) { + Collections.sort(orgValue); + } + if(newValue != null) { + Collections.sort(newValue); + } + if (orgValue != null && newValue != null) { + if (orgValue.equals(newValue)) + return false; + else + return true; + } + + List orgLit = editConfig.getLiteralsInScope().get(fieldName); + List newLit = submission.getLiteralsFromForm().get(fieldName); + //TODO: Sort ? Need custom comparator + //Collections.sort(orgLit); + //Collections.sort(newLit); + //for(Literal l: orgLit) + //boolean fieldChanged = !EditLiteral.equalLiterals(orgLit, newLit); + //TODO:Check if below acts as expected + boolean fieldChanged = !orgLit.equals(newLit); + if(!fieldChanged) { + int orgLen = orgLit.size(); + int newLen = newLit.size(); + if(orgLen != newLen) { + fieldChanged = true; + } else { + int i; + for(i = 0; i < orgLen; i++) { + if(!EditLiteral.equalLiterals(orgLit.get(i), newLit.get(i))) { + fieldChanged = true; + break; + } + } + } + } + log.debug("field " + fieldName + " " + + (fieldChanged ? "did Change" : "did NOT change")); + return fieldChanged; + } + public static boolean checkForEmptyString( + MultiValueEditSubmission submission, + EditConfigurationVTwo configuration, VitroRequest vreq) { + // TODO Auto-generated method stub + if(isDataProperty(configuration, vreq)) { + // Our editors have gotten into the habbit of clearing the text from the + // textarea and saving it to invoke a delete. see Issue VITRO-432 + if (configuration.getFields().size() == 1) { + String onlyField = configuration.getFields().keySet().iterator() + .next(); + List value = submission.getLiteralsFromForm().get(onlyField); + if( value == null || value.size() == 0){ + log.debug("No parameters found in submission for field \"" + onlyField +"\""); + return true; + }else { + if(value.size() == 1) { + if( "".equals(value.get(0).getLexicalForm())) { + log.debug("Submission was a single field named \"" + onlyField + "\" with an empty string"); + return true; + } + } + } + } + } + return false; + } + + //Get predicate local anchor + public static String getPredicateLocalName(EditConfigurationVTwo editConfig) { + String predicateLocalName = null; + if( editConfig != null ){ + String predicateUri = editConfig.getPredicateUri(); + if( predicateUri != null ){ + try{ + Property prop = ResourceFactory.createProperty(predicateUri); + predicateLocalName = prop.getLocalName(); + + }catch (com.hp.hpl.jena.shared.InvalidPropertyURIException e){ + log.debug("could not convert predicateUri into a valid URI",e); + } + } + } + return predicateLocalName; + } + //Get URL pattern for return + public static String getPostEditUrlPattern(VitroRequest vreq, EditConfigurationVTwo editConfig) { + String cancel = vreq.getParameter("cancel"); + String urlPattern = null; + + String urlPatternToReturnTo = null; + String urlPatternToCancelTo = null; + if (editConfig != null) { + urlPatternToReturnTo = editConfig.getUrlPatternToReturnTo(); + urlPatternToCancelTo = vreq.getParameter("url"); + } + // If a different cancel return path has been designated, use it. Otherwise, use the regular return path. + if (cancel != null && cancel.equals("true") && !StringUtils.isEmpty(urlPatternToCancelTo)) { + urlPattern = urlPatternToCancelTo; + } else if (!StringUtils.isEmpty(urlPatternToReturnTo)) { + urlPattern = urlPatternToReturnTo; + } else { + urlPattern = "/individual"; + } + return urlPattern; + } + + //Get resource to redirect to + public static String getResourceToRedirect(VitroRequest vreq, EditConfigurationVTwo editConfig, String entityToReturnTo ) { + String resourceToRedirectTo = null; + if( editConfig != null ){ + + if( editConfig.getEntityToReturnTo() != null && editConfig.getEntityToReturnTo().startsWith("?") ){ + resourceToRedirectTo = entityToReturnTo; + }else{ + resourceToRedirectTo = editConfig.getEntityToReturnTo(); + } + + //if there is no entity to return to it is likely a cancel + if( resourceToRedirectTo == null || resourceToRedirectTo.length() == 0 ) + resourceToRedirectTo = editConfig.getSubjectUri(); + } + return resourceToRedirectTo; + } + + public static String getPredicateAnchorPostEdit(String urlPattern, + String predicateLocalName) { + String predicateAnchor = null; + if( urlPattern.endsWith("individual") || urlPattern.endsWith("entity") ){ + if( predicateLocalName != null && predicateLocalName.length() > 0){ + predicateAnchor = "#" + predicateLocalName; + } + } + return predicateAnchor; + } + } } 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 c73e11ca8..3b217f519 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 @@ -7,13 +7,18 @@ import edu.cornell.mannlib.vitro.webapp.beans.DataPropertyStatement; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationUtils; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.SelectListGeneratorVTwo; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.EditConfiguration; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators.DefaultObjectPropertyFormGenerator; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.web.templatemodels.BaseTemplateModel; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; +import java.text.Collator; +import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; import java.util.List; import java.util.ArrayList; @@ -43,12 +48,17 @@ public class EditConfigurationTemplateModel extends BaseTemplateModel { this.retrieveEditData(); } + //Seeing if returning edit config object might work + public EditConfigurationVTwo getEditConfigObject() { + return editConfig; + } + public String getEditKey(){ return editConfig.getEditKey(); } public boolean isUpdate(){ - return editConfig.isUpdate(); + return editConfig.isObjectPropertyUpdate(); } public String getSubmitToUrl(){ @@ -75,10 +85,7 @@ public class EditConfigurationTemplateModel extends BaseTemplateModel { } - //TODO: remove - private void setRangeDatatype() { - - } + private boolean isRangeOptionsExist() { boolean rangeOptionsExist = (pageData.get("rangeOptionsExist") != null && (Boolean) pageData.get("rangeOptionsExist") == true); @@ -86,7 +93,8 @@ public class EditConfigurationTemplateModel extends BaseTemplateModel { } private void setFormTitle() { - if(editConfig.isObjectResource()) { + //if(editConfig.isObjectResource()) { + if(EditConfigurationUtils.isObjectProperty(editConfig.getPredicateUri(), vreq)) { setObjectFormTitle(); } else { setDataFormTitle(); @@ -107,6 +115,8 @@ public class EditConfigurationTemplateModel extends BaseTemplateModel { } //Process and set data + //Both form title and submit label would depend on whether this is data property + //or object property private void setObjectFormTitle() { String formTitle = null; Individual objectIndividual = EditConfigurationUtils.getObjectIndividual(vreq); @@ -147,20 +157,29 @@ public class EditConfigurationTemplateModel extends BaseTemplateModel { pageData.put("formTitle", formTitle); } + private void setSubmitLabel() { String submitLabel = null; - Individual objectIndividual = EditConfigurationUtils.getObjectIndividual(vreq); - ObjectProperty prop = EditConfigurationUtils.getObjectProperty(vreq); - - if(objectIndividual != null) { - submitLabel = "save change"; - } else { - if ( prop.getOfferCreateNewOption() ) { - submitLabel = "select existing"; - } else { - submitLabel = "save entry"; - } - } + if(EditConfigurationUtils.isObjectProperty(editConfig.getPredicateUri(), vreq)) { + Individual objectIndividual = EditConfigurationUtils.getObjectIndividual(vreq); + ObjectProperty prop = EditConfigurationUtils.getObjectProperty(vreq); + + if(objectIndividual != null) { + submitLabel = "Save change"; + } else { + if ( prop.getOfferCreateNewOption() ) { + submitLabel = "Select existing"; + } else { + submitLabel = "Save entry"; + } + } + } else { + if(editConfig.isDataPropertyUpdate()) { + submitLabel = "Save change"; + } else { + submitLabel = "Save entry"; + } + } pageData.put("submitLabel", submitLabel); } @@ -169,19 +188,7 @@ public class EditConfigurationTemplateModel extends BaseTemplateModel { if( prop.getSelectFromExisting() ){ WebappDaoFactory wdf = vreq.getWebappDaoFactory(); - // set ProhibitedFromSearch object so picklist doesn't show - // individuals from classes that should be hidden from list views - //uncomment out when we know what to do here - /* - OntModel displayOntModel = - (OntModel) session.getServletContext() - .getAttribute("displayOntModel"); - if (displayOntModel != null) { - ProhibitedFromSearch pfs = new ProhibitedFromSearch( - DisplayVocabulary.PRIMARY_SEARCH_INDEX_URI, displayOntModel); - if( editConfiguration != null ) - editConfiguration.setProhibitedFromSearch(pfs); - }*/ + Map rangeOptions = SelectListGeneratorVTwo.getOptions(editConfig, "objectVar" , wdf); if( rangeOptions != null && rangeOptions.size() > 0 ) { pageData.put("rangeOptionsExist", true); @@ -223,10 +230,13 @@ public class EditConfigurationTemplateModel extends BaseTemplateModel { } public List getLiteralStringValue(String key) { - List ls = editConfig.getLiteralsInScope().get(key); List literalValues = new ArrayList(); - for(Literal l: ls) { - literalValues.add(l.getString()); + Map> literalsInScope = editConfig.getLiteralsInScope(); + if(literalsInScope.containsKey(key)) { + List ls = literalsInScope.get(key); + for(Literal l: ls) { + literalValues.add(l.getString()); + } } return literalValues; } @@ -262,21 +272,26 @@ public class EditConfigurationTemplateModel extends BaseTemplateModel { String predicateUri = getPredicateUri(); //If predicate uri corresponds to object property, return that if(EditConfigurationUtils.isObjectProperty(predicateUri, vreq)){ - return this.vreq.getWebappDaoFactory().getObjectPropertyDao().getObjectPropertyByURI(predicateUri); + return EditConfigurationUtils.getObjectPropertyForPredicate(this.vreq, predicateUri); } //otherwise return Data property - return this.vreq.getWebappDaoFactory().getDataPropertyDao().getDataPropertyByURI(predicateUri); + return EditConfigurationUtils.getDataPropertyForPredicate(this.vreq, predicateUri); } public ObjectProperty getObjectPredicateProperty() { - return this.vreq.getWebappDaoFactory().getObjectPropertyDao().getObjectPropertyByURI(getPredicateUri()); + //explore usuing EditConfigurationUtils.getObjectProperty(this.vreq) + //return this.vreq.getWebappDaoFactory().getObjectPropertyDao().getObjectPropertyByURI(getPredicateUri()); + return EditConfigurationUtils.getObjectPropertyForPredicate(this.vreq, getPredicateUri()); } public DataProperty getDataPredicateProperty() { - return this.vreq.getWebappDaoFactory().getDataPropertyDao().getDataPropertyByURI(getPredicateUri()); - + return EditConfigurationUtils.getDataPropertyForPredicate(this.vreq, getPredicateUri()); } + public String getDataPredicatePublicDescription() { + DataProperty dp = getDataPredicateProperty(); + return dp.getPublicDescription(); + } public String getPredicateUri() { return editConfig.getPredicateUri(); } @@ -285,24 +300,129 @@ public class EditConfigurationTemplateModel extends BaseTemplateModel { return editConfig.getSubjectUri(); } + public String getSubjectName() { + + Individual subject = EditConfigurationUtils.getIndividual(vreq, getSubjectUri()); + return subject.getName(); + } + public String getObjectUri() { return editConfig.getObject(); } + //data literal public String getDataLiteral() { return getDataPredicateProperty().getLocalName() + "Edited"; } + //Get data property key + //public description only appears visible for object property public String getPropertyPublicDescription() { return getObjectPredicateProperty().getPublicDescription(); } + //properties queried on the main object property public boolean getPropertySelectFromExisting() { return getObjectPredicateProperty().getSelectFromExisting(); } + //used for form title for object properties + //TODO: update because assumes domain public + public String getPropertyPublicDomainTitle() { + ObjectProperty prop = EditConfigurationUtils.getObjectProperty(vreq); + return prop.getDomainPublic(); + } + + //used for form title for data properties + //TODO: Update b/c assumes data property + public String getPropertyPublicName() { + DataProperty prop = EditConfigurationUtils.getDataProperty(vreq); + return prop.getPublicName(); + } + + public boolean getPropertyOfferCreateNewOption() { + return getObjectPredicateProperty().getOfferCreateNewOption(); + } + + //TODO:Check where this logic should actually go, copied from input element formatting tag + public Map getOfferTypesCreateNew() { + WebappDaoFactory wdf = vreq.getWebappDaoFactory(); + ObjectProperty op = + wdf.getObjectPropertyDao().getObjectPropertyByURI(editConfig.getPredicateUri()); + + Individual sub = + wdf.getIndividualDao().getIndividualByURI(editConfig.getSubjectUri()); + + List vclasses = null; + vclasses = wdf.getVClassDao().getVClassesForProperty(sub.getVClassURI(), op.getURI()); + if( vclasses == null ) + vclasses = wdf.getVClassDao().getAllVclasses(); + + HashMap types = new HashMap(); + for( VClass vclass : vclasses ){ + + String name = null; + if( vclass.getPickListName() != null && vclass.getPickListName().length() > 0){ + name = vclass.getPickListName(); + }else if( vclass.getName() != null && vclass.getName().length() > 0){ + name = vclass.getName(); + }else if (vclass.getLocalNameWithPrefix() != null && vclass.getLocalNameWithPrefix().length() > 0){ + name = vclass.getLocalNameWithPrefix(); + } + if( name != null && name.length() > 0) + types.put(vclass.getURI(),name); + } + + //Unlike input element formatting tag, including sorting logic here + return getSortedMap(types); + } + + public Map getSortedMap(Map hmap){ + // first make temporary list of String arrays holding both the key and its corresponding value, so that the list can be sorted with a decent comparator + List objectsToSort = new ArrayList(hmap.size()); + for (String key:hmap.keySet()) { + String[] x = new String[2]; + x[0] = key; + x[1] = hmap.get(key); + objectsToSort.add(x); + } + Collections.sort(objectsToSort, new MapComparator()); + + HashMap map = new LinkedHashMap(objectsToSort.size()); + for (String[] pair:objectsToSort) { + map.put(pair[0],pair[1]); + } + return map; + } + + private class MapComparator implements Comparator { + public int compare (String[] s1, String[] s2) { + Collator collator = Collator.getInstance(); + if (s2 == null) { + return 1; + } else if (s1 == null) { + return -1; + } else { + if ("".equals(s1[0])) { + return -1; + } else if ("".equals(s2[0])) { + return 1; + } + if (s2[1]==null) { + return 1; + } else if (s1[1] == null){ + return -1; + } else { + return collator.compare(s1[1],s2[1]); + } + } + } + } + + + //booleans for checking whether predicate is data or object public boolean isDataProperty() { return EditConfigurationUtils.isDataProperty(getPredicateUri(), vreq); @@ -321,7 +441,34 @@ public class EditConfigurationTemplateModel extends BaseTemplateModel { } public String getCurrentUrl() { - return "/edit/editRequestDispatch?" + vreq.getQueryString(); + return getMainEditUrl() + "?" + vreq.getQueryString(); } + public String getMainEditUrl() { + return "/edit/editRequestDispatch"; + } + + //TODO: Check if this logic is correct and delete prohibited does not expect a specific value + public boolean isDeleteProhibited() { + String deleteProhibited = vreq.getParameter("deleteProhibited"); + return (deleteProhibited != null && !deleteProhibited.isEmpty()); + } + + public String getDatapropKey() { + return editConfig.getDatapropKey(); + } + + //Check whether deletion form should be included for default object property + public boolean getIncludeDeletionForm() { + if(isDeleteProhibited()) + return false; + if(isObjectProperty()) { + return (getObjectUri() != null && !getObjectUri().isEmpty()); + } + else { + String datapropKey = editConfig.getDatapropKey(); + return (datapropKey != null && !datapropKey.isEmpty()); + } + } + } diff --git a/webapp/web/templates/freemarker/edit/forms/defaultAddMissingIndividualForm.ftl b/webapp/web/templates/freemarker/edit/forms/defaultAddMissingIndividualForm.ftl new file mode 100644 index 000000000..33dbeb5e6 --- /dev/null +++ b/webapp/web/templates/freemarker/edit/forms/defaultAddMissingIndividualForm.ftl @@ -0,0 +1,24 @@ +<#-- $This file is distributed under the terms of the license in /doc/license.txt$ --> + +<#assign formTitle> + ${editConfiguration.propertyPublicDomainTitle} entry for ${editConfiguration.subjectName} + +<#if editConfiguration.objectUri?has_content> + <#assign formTitle>Edit ${formTitle} +<#else> + <#assign formTitle>Create ${formTitle} + + +

${formTitle}

+ +
+ + +
+
+ +
+
+ + + diff --git a/webapp/web/templates/freemarker/edit/forms/defaultDataPropertyForm.ftl b/webapp/web/templates/freemarker/edit/forms/defaultDataPropertyForm.ftl index 5f43ae908..6c4d542c9 100644 --- a/webapp/web/templates/freemarker/edit/forms/defaultDataPropertyForm.ftl +++ b/webapp/web/templates/freemarker/edit/forms/defaultDataPropertyForm.ftl @@ -2,26 +2,27 @@

${editConfiguration.formTitle}

-<#assign predicateProperty = "${editConfiguration.predicateProperty}" /> <#assign literalValues = "${editConfiguration.dataLiteralValuesAsString}" /> -
- - <#if editConfiguration.propertyPublicDescription?has_content> - - -

${editConfiguration.propertyPublicDescription}

- - - -
- -
- -
- -<#--ToDo: Include delete portion--> - +
+ + <#if editConfiguration.dataPredicatePublicDescription?has_content> + + + + + +
+ +
+
+ + +<#if editConfiguration.includeDeletionForm = true> +<#include "defaultDeletePropertyForm.ftl"> + + +<#include "defaultFormScripts.ftl"> diff --git a/webapp/web/templates/freemarker/edit/forms/defaultDeletePropertyForm.ftl b/webapp/web/templates/freemarker/edit/forms/defaultDeletePropertyForm.ftl new file mode 100644 index 000000000..429285bb4 --- /dev/null +++ b/webapp/web/templates/freemarker/edit/forms/defaultDeletePropertyForm.ftl @@ -0,0 +1,32 @@ +
+ + + + + + <#if editConfiguration.dataProperty = true> + + + Cancel + + + <#--The original jsp included vinput tag with cancel=empty string for case where both select from existing + and offer create new option are true below + so leaving as Cancel for now but unclear as to what the result would have been--> + <#if editConfiguration.objectProperty = true> + + + <#if editConfiguration.propertySelectFromExisting = false + && editConfiguration.propertyOfferCreateNewOption = false> + + Cancel + + + <#if editConfiguration.propertySelectFromExisting = true + && editConfiguration.propertyOfferCreateNewOption = true> + + Cancel + + + +
diff --git a/webapp/web/templates/freemarker/edit/forms/defaultFormScripts.ftl b/webapp/web/templates/freemarker/edit/forms/defaultFormScripts.ftl new file mode 100644 index 000000000..af4fd770a --- /dev/null +++ b/webapp/web/templates/freemarker/edit/forms/defaultFormScripts.ftl @@ -0,0 +1,69 @@ +<#-- $This file is distributed under the terms of the license in /doc/license.txt$ --> + +<#-- Template to setup and call scripts for form editing --> + +<#-- Like original jsp, allow the passing of variables --> +<#assign defaultHeight="200" /> +<#assign defaultWidth="75%" /> +<#assign defaultButton="bold,italic,underline,separator,link,bullist,numlist,separator,sub,sup,charmap,separator,undo,redo,separator,code"/> +<#assign defaultToolbarLocation = "top" /> +<#if !height?has_content> + <#assign height=defaultHeight/> + + +<#if !width?has_content> + <#assign width=defaultWidth /> + + +<#if !buttons?has_content> + <#assign buttons = defaultButton /> + + +<#if !toolbarLocation?has_content> + <#assign toolbarLocation = defaultToolbarLocation /> + + +<#-- Set up data --> + + +<#-- Script to enable browsing individuals within a class --> +<#--'',--> +${scripts.add('', +'', + '')} \ No newline at end of file diff --git a/webapp/web/templates/freemarker/edit/forms/defaultOfferCreateNewOptionForm.ftl b/webapp/web/templates/freemarker/edit/forms/defaultOfferCreateNewOptionForm.ftl new file mode 100644 index 000000000..2287fc6f1 --- /dev/null +++ b/webapp/web/templates/freemarker/edit/forms/defaultOfferCreateNewOptionForm.ftl @@ -0,0 +1,22 @@ + <#if editConfiguration.rangeOptionsExist = true > +

If you don't find the appropriate entry on the selection list above:

+ <#else> +

Please create a new entry.

+ + +<#assign typesList = editConfiguration.offerTypesCreateNew /> +
+ + + + + + + + Cancel +
\ No newline at end of file diff --git a/webapp/web/templates/freemarker/edit/forms/defaultPropertyForm.ftl b/webapp/web/templates/freemarker/edit/forms/defaultPropertyForm.ftl index 607f47bff..c609a3eaf 100644 --- a/webapp/web/templates/freemarker/edit/forms/defaultPropertyForm.ftl +++ b/webapp/web/templates/freemarker/edit/forms/defaultPropertyForm.ftl @@ -2,8 +2,6 @@

${editConfiguration.formTitle}

-<#assign predicateProperty = "${editConfiguration.predicateProperty}" /> - <#if editConfiguration.propertySelectFromExisting = true> <#if editConfiguration.rangeOptionsExist = true > <#assign rangeOptionKeys = editConfiguration.rangeOptions?keys /> @@ -30,3 +28,18 @@

There are no entries in the system from which to select.

+ +<#if editConfiguration.propertyOfferCreateNewOption = true> +<#include "defaultOfferCreateNewOptionForm.ftl"> + + + +<#if editConfiguration.propertySelectFromExisting = false && editConfiguration.propertyOfferCreateNewOption = false> +

This property is currently configured to prohibit editing.

+ + + +<#if editConfiguration.includeDeletionForm = true> +<#include "defaultDeletePropertyForm.ftl"> + +