diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/BaseEditElementVTwo.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/BaseEditElementVTwo.java new file mode 100644 index 000000000..d5e6a410e --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/BaseEditElementVTwo.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.VTwo; + +import java.io.IOException; +import java.io.StringWriter; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import freemarker.template.Configuration; +import freemarker.template.Template; +import freemarker.template.TemplateException; + +public abstract class BaseEditElementVTwo implements EditElementVTwo { + private static final Log log = LogFactory.getLog(BaseEditElementVTwo.class); + + protected FieldVTwo field; + + public BaseEditElementVTwo(FieldVTwo field){ + this.field = field; + } + + /** + * Utility method for use in EditElements to merge a freemarker template. + */ + protected String merge(Configuration fmConfig, String templateName, Map map){ + Template template = null; + try { + template = fmConfig.getTemplate(templateName); + } catch (IOException e) { + log.error("Cannot get template " + templateName); + } + + StringWriter writer = new StringWriter(); + try { + template.process(map, writer); + } catch (TemplateException e) { + log.error(e,e); + } catch (IOException e) { + log.error(e,e); + } + return writer.toString(); + } + + /** + * Utility method to check if a value from the query parameters is none or a single value. + * This returns true if the key is there and the value is null. + * This does not check if the value is the empty string. + */ + protected boolean hasNoneOrSingle(String key, Map queryParameters){ + if( queryParameters != null ){ + if( ! queryParameters.containsKey(key) ) + return true; //none + String[] vt = queryParameters.get(key); + return vt == null || vt.length == 0 || vt.length==1; + }else{ + log.error("passed null queryParameters"); + return false; + } + } + + protected boolean hasSingleNonNullNonEmptyValueForKey(String key, Map queryParameters){ + if( queryParameters != null ){ + if( ! queryParameters.containsKey(key) ) + return true; //none + String[] vt = queryParameters.get(key); + return vt != null && vt.length == 1 && vt[0] != null && ! vt[0].isEmpty() ; + }else{ + log.error("passed null queryParameters"); + return false; + } + } +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/DateTimeIntervalValidationVTwo.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/DateTimeIntervalValidationVTwo.java new file mode 100644 index 000000000..f01779260 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/DateTimeIntervalValidationVTwo.java @@ -0,0 +1,216 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo; + +import java.util.Calendar; +import java.util.HashMap; +import java.util.Map; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import com.hp.hpl.jena.datatypes.xsd.XSDDateTime; +import com.hp.hpl.jena.rdf.model.Literal; + +import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; +import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary.Precision; +import edu.cornell.mannlib.vitro.webapp.edit.elements.DateTimeWithPrecision; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.EditConfiguration; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.processEdit.EditSubmission; + +/* + * Assumption for date time interval validation: Only one start field/end field/and precision. + * We are currently not accepting multiple values for start time, end time, or precision. + */ + + +public class DateTimeIntervalValidationVTwo implements N3ValidatorVTwo { + private static Log log = LogFactory.getLog(DateTimeIntervalValidationVTwo.class); + + private String startFieldName; + private String endFieldName; + + private String startValueName; + private String endValueName; + + private String startPrecisionName; + private String endPrecisionName; + + public DateTimeIntervalValidationVTwo(String startFieldName, String endFieldName){ + this.startFieldName = startFieldName; + this.endFieldName = endFieldName; + startValueName = startFieldName + "-value"; + endValueName = endFieldName + "-value"; + startPrecisionName = startFieldName + "-precision"; + endPrecisionName = endFieldName + "-precision"; + } + + public Map validate(EditConfigurationVTwo editConfig, + MultiValueEditSubmission editSub) { + Map> existingLiterals = editConfig.getLiteralsInScope(); + List existingStartYear = existingLiterals.get(startValueName); + List existingEndYear = existingLiterals.get(endValueName); + + Map> literalsFromForm = editSub.getLiteralsFromForm(); + List formStartYear = literalsFromForm.get(startValueName); + List formEndYear = literalsFromForm.get(endValueName); + + VitroVocabulary.Precision startPrecision = getPrecision(startPrecisionName, editConfig, editSub); + VitroVocabulary.Precision endPrecision = getPrecision(endPrecisionName, editConfig, editSub); + + Map errors = new HashMap(); + + // NIHVIVO-2541 Commented out to allow end date with no start date +// if( formStartYear == null && formEndYear != null ){ +// errors.put(startFieldName, "If there is an end date, there should be a start date"); +// return errors; +// } + + + //Assuming form start year and form end year are working in conjunction with multiple values + int index; + if (formStartYear != null && formEndYear != null) { + int numberStartYears = formStartYear.size(); + int numberEndYears = formEndYear.size(); + if(numberStartYears > 1 && numberEndYears > 1) { + errors.put(startFieldName, "DateTimeIntervalValidationVTwo does not support multiple start years or end years"); + return errors; + } + + if(numberStartYears > 0 && numberEndYears > 0) { + errors.putAll(checkDateLiterals(formStartYear.get(0), formEndYear.get(0), startPrecision, endPrecision)); + } + } else if (formStartYear != null && existingEndYear != null) { + int numberStartYears = formStartYear.size(); + int numberEndYears = existingEndYear.size(); + if(numberStartYears > 1 && numberEndYears > 1) { + errors.put(startFieldName, "DateTimeIntervalValidationVTwo does not support multiple start years or end years"); + return errors; + } + + if(numberStartYears > 0 && numberEndYears > 0) { + errors.putAll(checkDateLiterals(formStartYear.get(0), existingEndYear.get(0), startPrecision, endPrecision)); + } + } else if (existingStartYear != null && formEndYear != null) { + int numberStartYears = existingStartYear.size(); + int numberEndYears = formEndYear.size(); + if(numberStartYears > 1 && numberEndYears > 1) { + errors.put(startFieldName, "DateTimeIntervalValidationVTwo does not support multiple start years or end years"); + return errors; + } + + if(numberStartYears > 0 && numberEndYears > 0) { + errors.putAll(checkDateLiterals(existingStartYear.get(0), formEndYear.get(0), startPrecision, endPrecision)); + } + } else if (existingStartYear != null && existingEndYear != null) { + int numberStartYears = existingStartYear.size(); + int numberEndYears = existingEndYear.size(); + if(numberStartYears > 1 && numberEndYears > 1) { + errors.put(startFieldName, "DateTimeIntervalValidationVTwo does not support multiple start years or end years"); + return errors; + } + + if(numberStartYears > 0 && numberEndYears > 0) { + errors.putAll(checkDateLiterals(existingStartYear.get(0), existingEndYear.get(0), startPrecision, endPrecision)); + } + } + + if (errors.size() != 0) + return errors; + else + return null; + } + + private Precision getPrecision(String precisionVarName, + EditConfigurationVTwo editConfig, MultiValueEditSubmission editSub) { + if( editSub != null + && editSub.getUrisFromForm() != null + && editSub.getUrisFromForm().containsKey(precisionVarName)){ + List precisionStr = editSub.getUrisFromForm().get(precisionVarName); + //TODO: Check if we need to handle multiple precision strings and what to do then + //Currently checks first precision str and then returns response + if(precisionStr.size() > 0) { + String precisionString = precisionStr.get(0); + VitroVocabulary.Precision precision = DateTimeWithPrecision.toPrecision( precisionString ); + if( precision == null ) + log.warn("cannot convert " + precisionStr + " to a precision"); + else + return precision; + } else { + log.error("No precision strings returned"); + } + + }else if( editConfig != null + && editConfig.getUrisInScope() != null + && editConfig.getUrisInScope().containsKey(precisionVarName)){ + List precisionStr = editConfig.getUrisInScope().get(precisionVarName); + //TODO: Check if we need to handle multiple precision strings and what to do then + //Currently checks first precision str and then returns response + if(precisionStr.size() > 0) { + String precisionString = precisionStr.get(0); + VitroVocabulary.Precision precision = DateTimeWithPrecisionVTwo.toPrecision( precisionString ); + if( precision == null ) + log.warn("cannot convert " + precisionString + " to a precision"); + else + return precision; + } else { + log.error("No precision strings returned"); + } + + } + //this is what is returned if a precision was not found in the config or submission + return null; + } + + private Map checkDateLiterals( + Literal startLit, Literal endLit, + VitroVocabulary.Precision startPrecision, VitroVocabulary.Precision endPrecision) { + Map errors = new HashMap(); + + if( endPrecision == null ){ + //there is no end date, nothing to check + return errors; + } + + try{ + XSDDateTime startDate = (XSDDateTime)startLit.getValue(); + XSDDateTime endDate = (XSDDateTime)endLit.getValue(); + if( startDate != null && endDate!= null ){ + Calendar startCal = startDate.asCalendar(); + Calendar endCal = endDate.asCalendar(); + + if( endCal != null ){ + if( !startCal.before( endCal ) ){ + if( startPrecision == VitroVocabulary.Precision.YEAR + && endPrecision == VitroVocabulary.Precision.YEAR ){ + errors.putAll( checkYears(startCal,endCal)); + }else{ + errors.put(startFieldName, "Start must be before end"); + errors.put(endFieldName, "End must be after start"); + } + } + } + } + }catch(ClassCastException cce){ + errors.put(startFieldName, "could not format start or end date"); + errors.put(endFieldName, "could not format start or end date"); + log.debug("could not format dates " + cce); + } + + return errors; + } + + private Map checkYears( + Calendar startCal, Calendar endCal) { + + Map errors = new HashMap(); + + if( ! (endCal.get(Calendar.YEAR) >= startCal.get(Calendar.YEAR) )){ + errors.put(startFieldName, "Start must be before end"); + errors.put(endFieldName, "End must be after start"); + } + + return errors; + } +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/DateTimeWithPrecisionVTwo.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/DateTimeWithPrecisionVTwo.java new file mode 100644 index 000000000..728cd75b7 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/DateTimeWithPrecisionVTwo.java @@ -0,0 +1,620 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.List; +import java.util.ArrayList; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.joda.time.DateTime; +import org.joda.time.format.ISODateTimeFormat; + +import com.hp.hpl.jena.datatypes.xsd.XSDDatatype; +import com.hp.hpl.jena.rdf.model.Literal; +import com.hp.hpl.jena.rdf.model.ResourceFactory; + +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerConfiguration; +import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.EditConfiguration; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.Field; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.processEdit.EditSubmission; +import freemarker.template.Configuration; + +/** + * This is intended to work in conjunction with a template to create the HTML for a + * datetime with precision and to convert the submitted parameters into + * varname -> Literal and varname -> URI maps. + * + * The variables that get passed to the template are defined in: + * DateTimeWithPrecision.getMapForTemplate() + * + * Two variables will be defined for the N3 edit graphs (These are NOT variables passed to FM templates): + * $fieldname.precision - URI of datetime precision + * $fieldname.value - DateTime literal + * + */ +public class DateTimeWithPrecisionVTwo extends BaseEditElementVTwo { + + String fieldName; + + /** + * This is the minimum datetime precision that this element + * will accept. If the parameters submitted do not meet this + * requirement, then a validation error will be created. + */ + VitroVocabulary.Precision minimumPrecision; + + /** + * This is the maximum precision that the form should + * allow the user to enter. This value is not used by + * DateTimeWithPrecision for validation, it is only passed + * to the template. This should be removed when it can be + * specified in a ftl file. + * + * This could be thought of as the maximum precision to display. + */ + VitroVocabulary.Precision displayRequiredLevel; + + + VitroVocabulary.Precision DEFAULT_MIN_PRECISION = VitroVocabulary.Precision.DAY; + VitroVocabulary.Precision DEFAULT_DISPLAY_LEVEL = VitroVocabulary.Precision.DAY; + VitroVocabulary.Precision[] precisions = VitroVocabulary.Precision.values(); + + protected static final String BLANK_SENTINEL = ">SUBMITTED VALUE WAS BLANK<"; + + public DateTimeWithPrecisionVTwo(FieldVTwo field) { + super(field); + fieldName = field.getName(); + minimumPrecision = DEFAULT_MIN_PRECISION; + displayRequiredLevel = DEFAULT_DISPLAY_LEVEL; + } + + public DateTimeWithPrecisionVTwo(FieldVTwo field, VitroVocabulary.Precision minimumPrecision){ + this(field); + if( minimumPrecision != null ) + this.minimumPrecision = minimumPrecision; + else + this.minimumPrecision = DEFAULT_MIN_PRECISION; + this.displayRequiredLevel = this.minimumPrecision; + } + + //it would be nice to have only the version of the constructor that takes the enum + //but this is to quickly get the JSP configuration working. + public DateTimeWithPrecisionVTwo(FieldVTwo field, String minimumPrecisionURI, String displayRequiredLevelUri){ + this(field); + + this.minimumPrecision = toPrecision( minimumPrecisionURI); + if( this.minimumPrecision == null ) + throw new IllegalArgumentException(minimumPrecisionURI + +" is not a valid precision for minimumPrecision, see VitroVocabulary.Precision"); + + this.displayRequiredLevel = toPrecision( displayRequiredLevelUri ); + if( this.displayRequiredLevel == null ) + throw new IllegalArgumentException(displayRequiredLevelUri + +" is not a valid precision for displayRequiredLevel, see VitroVocabulary.Precision"); + +// if( this.displayRequiredLevel.ordinal() < this.minimumPrecision.ordinal() ){ +// throw new IllegalArgumentException("the display precision level " + this.displayRequiredLevel +// + " is less precise than the required minimum precision of " + this.minimumPrecision); +// } + } + + private static final Log log = LogFactory.getLog(DateTimeWithPrecisionVTwo.class); + protected String TEMPLATE_NAME = "dateTimeWithPrecision.ftl"; + + @Override + public String draw(String fieldName, EditConfigurationVTwo editConfig, + MultiValueEditSubmission editSub, Configuration fmConfig) { + Map map = getMapForTemplate( editConfig, editSub); + return merge( fmConfig, TEMPLATE_NAME, map); + } + + /** + * This produces a map for use in the template. Will be using this b/c + */ + public Map getMapForTemplate(EditConfigurationVTwo editConfig, MultiValueEditSubmission editSub) { + Mapmap = new HashMap(); + + //always need the fieldName, required precision, and constants + map.put("fieldName", fieldName); + addPrecisionConstants(map); + map.put("minimumPrecision", minimumPrecision.uri()); + map.put("requiredLevel", displayRequiredLevel.uri()); + + //Still expecting single precision uri not multiple + String precisionUri= getPrecision(editConfig,editSub); + + VitroVocabulary.Precision existingPrec = toPrecision(precisionUri); + + if( precisionUri != null && !"".equals(precisionUri) && existingPrec == null ){ + log.error("field " + fieldName + ": existing precision uri was " + + "'" + precisionUri + "' but could not convert to Precision object"); + } + + if( precisionUri == null || precisionUri.isEmpty() || existingPrec == null){ + map.put("existingPrecision", ""); + + /* no precision so there should also be no datetime */ + DateTime value = getTimeValue(editConfig,editSub); + if( value != null ) + log.info("Unexpected state: Precision for " + fieldName + + " was '" + precisionUri + "' but date time was " + value); + + map.put("year", ""); + map.put("month", ""); + map.put("day", ""); + map.put("hour", ""); + map.put("minute", ""); + map.put("second", "") ; + } else if( VitroVocabulary.Precision.NONE.uri().equals(precisionUri) ){ + //bdc34: not sure what to do with the NONE precision + map.put("existingPrecision", precisionUri); + + map.put("year", ""); + map.put("month", ""); + map.put("day", ""); + map.put("hour", ""); + map.put("minute", ""); + map.put("second", "") ; + }else{ + map.put("existingPrecision", precisionUri); + + DateTime value = getTimeValue(editConfig,editSub); + /* This is the case where there is a precision so there should be a datetime */ + if( value == null ) + log.error("Field " + fieldName + " has precision " + precisionUri + + " but the date time is " + value); + + /* only put the values in the map for ones which are significant based on the precision */ + if( existingPrec.ordinal() >= VitroVocabulary.Precision.SECOND.ordinal() ) + map.put("second", Integer.toString(value.getSecondOfMinute() )) ; + else + map.put("second", ""); + + if( existingPrec.ordinal() >= VitroVocabulary.Precision.MINUTE.ordinal() ) + map.put("minute", Integer.toString(value.getMinuteOfHour()) ); + else + map.put("minute", ""); + + if( existingPrec.ordinal() >= VitroVocabulary.Precision.HOUR.ordinal() ) + map.put("hour", Integer.toString(value.getHourOfDay()) ); + else + map.put("hour", ""); + + if( existingPrec.ordinal() >= VitroVocabulary.Precision.DAY.ordinal() ) + map.put("day", Integer.toString(value.getDayOfMonth()) ); + else + map.put("day", ""); + + if( existingPrec.ordinal() >= VitroVocabulary.Precision.MONTH.ordinal() ) + map.put("month", Integer.toString(value.getMonthOfYear())); + else + map.put("month", ""); + + if( existingPrec.ordinal() >= VitroVocabulary.Precision.YEAR.ordinal() ) + map.put("year", Integer.toString(value.getYear())); + else + map.put("year", ""); + } + + return map; + } + + /** Adds precisionURIs for use by the templates */ + private void addPrecisionConstants(Map map){ + Map constants = new HashMap(); + for( VitroVocabulary.Precision pc: VitroVocabulary.Precision.values()){ + constants.put(pc.name().toLowerCase(),pc.uri()); + } + map.put("precisionConstants", constants); + } + + /** + * Gets the currently set precision. May return null. + */ + private String getPrecision(EditConfigurationVTwo editConfig, MultiValueEditSubmission editSub) { + if( editSub != null ){ + List submittedPrecisionURI = editSub.getUrisFromForm().get( getPrecisionVariableName() ); + if( submittedPrecisionURI != null + && submittedPrecisionURI.size() > 0 + && submittedPrecisionURI.get(0) != null){ + return submittedPrecisionURI.get(0); + } + } + + List existingPrecisionURI = editConfig.getUrisInScope().get( getPrecisionVariableName() ); + if( existingPrecisionURI != null + && existingPrecisionURI.size() > 0 + && existingPrecisionURI.get(0) != null){ + //TODO: Check if relevant to return more than one element + return existingPrecisionURI.get(0); + }else{ + return null; + } + } + + private DateTime getTimeValue(EditConfigurationVTwo editConfig, MultiValueEditSubmission editSub) { + if( editSub != null ){ + List submittedValue = editSub.getLiteralsFromForm().get( getValueVariableName() ); + if( submittedValue != null ) { + //TODO: Check what to do with multiple values, currently handling one value + if(submittedValue.size() > 0 && submittedValue.get(0) != null) { + return new DateTime( submittedValue.get(0).getLexicalForm() ); + } + } + } + + List dtValue = editConfig.getLiteralsInScope().get( getValueVariableName() ); + if( dtValue != null ){ + if(dtValue.size() > 0 && dtValue.get(0) != null) + { + return new DateTime( dtValue.get(0).getLexicalForm() ); + } + } + + return null; + } + + /** + * This gets the literals for a submitted form from the queryParmeters. + * It will only be called if getValidationErrors() doesn't return any errors. + */ + @Override + public Map> getLiterals(String fieldName, + EditConfigurationVTwo editConfig, Map queryParameters) { + Map> literalMap = new HashMap>(); + + Literal datetime =getDateTime( queryParameters); + List literals = new ArrayList(); + literals.add(datetime); + literalMap.put(fieldName+"-value", literals); + + return literalMap; + } + + protected Literal getDateTime( Map queryParameters ) { + String submittedPrec = BLANK_SENTINEL; + try { + submittedPrec = getSubmittedPrecision( queryParameters); + } catch (Exception e) { + log.error("could not get submitted precsion",e); + } + + if( BLANK_SENTINEL.equals( submittedPrec ) ) + return null; + + Integer year = parseToInt(fieldName+"-year", queryParameters); + + //this is the case where date has not been filled out at all. + if( year == null ) + return null; + + Integer month = parseToInt(fieldName+"-month", queryParameters); + if( month == null || month == 0 ) + month = 1; + Integer day = parseToInt(fieldName+"-day", queryParameters); + if( day == null || day == 0 ) + day = 1; + Integer hour = parseToInt(fieldName+"-hour", queryParameters); + if( hour == null ) + hour = 0; + Integer minute = parseToInt(fieldName+"-minute", queryParameters); + if( minute == null ) + minute = 0; + Integer second = parseToInt(fieldName+"-second", queryParameters); + if( second == null ) + second = 0; + + DateTime value = new DateTime( + year.intValue(),month.intValue(),day.intValue(), + hour.intValue(),minute.intValue(),second.intValue(),0/*millis*/ + ); + + return ResourceFactory.createTypedLiteral( + ISODateTimeFormat.dateHourMinuteSecond().print(value), /*does not include timezone*/ + XSDDatatype.XSDdateTime); + } + + /** + * This gets the URIs for a submitted form from the queryParmeters. + * It will only be called if getValidationErrors() doesn't return any errors. + */ + @Override + public Map> getURIs(String fieldName, + EditConfigurationVTwo editConfig, Map queryParameters) { + String precisionUri; + try { + precisionUri = getSubmittedPrecision( queryParameters); + } catch (Exception e) { + log.error("getURIs() should only be called on input that passed getValidationErrors()"); + return Collections.emptyMap(); + } + Map> uriMap = new HashMap>(); + if( precisionUri != null ){ + List uris = new ArrayList(); + uris.add(precisionUri); + uriMap.put(fieldName+"-precision", uris); + } + return uriMap; + } + + /** + * Precision is based on the values returned by the form. Throws an exception with + * the error message if the queryParameters cannot make a valid date/precision because + * there are values missing. + */ + protected String getSubmittedPrecision(Map queryParameters) throws Exception { + + Integer year = parseToInt(fieldName+"-year",queryParameters); + Integer month = parseToInt(fieldName+"-month",queryParameters); + Integer day = parseToInt(fieldName+"-day",queryParameters); + Integer hour = parseToInt(fieldName+"-hour",queryParameters); + Integer minute = parseToInt(fieldName+"-minute",queryParameters); + Integer second = parseToInt(fieldName+"-second",queryParameters); + Integer[] values = { year, month, day, hour, minute, second }; + + /* find the most significant date field that is null. */ + int indexOfFirstNull= -1; + for(int i=0; i < values.length ; i++){ + if( values[i] == null ){ + indexOfFirstNull = i; + break; + } + } + + /* the field wasn't filled out at all */ + if( indexOfFirstNull == 0 ) + //return VitroVocabulary.Precision.NONE.uri(); + return BLANK_SENTINEL; + + /* if they all had values then we have seconds precision */ + if( indexOfFirstNull == -1 ) + return VitroVocabulary.Precision.SECOND.uri(); + + + /* check that there are no values after the most significant null field + * that are non-null. */ + boolean nonNullAfterFirstNull=false; + for(int i=0; i < values.length ; i++){ + if( i > indexOfFirstNull && values[i] != null ){ + nonNullAfterFirstNull = true; + break; + } + } + if( nonNullAfterFirstNull ) + throw new Exception("Invalid date-time value. When creating a date-time value, there cannot be gaps between any of the selected fields."); + else{ + return precisions[ indexOfFirstNull ].uri(); + } + } + + @Override + public Map getValidationMessages(String fieldName, + EditConfigurationVTwo editConfig, Map queryParameters) { + Map errorMsgMap = new HashMap(); + + //check that any parameters we got are single values + String[] names = {"year","month","day","hour","minute","second", "precision"}; + for( String name:names){ + if ( !hasNoneOrSingle(fieldName+"-"+name, queryParameters)) + errorMsgMap.put(fieldName+"-"+name, "must have only one value for " + name); + } + + String precisionURI = null; + try{ + precisionURI = getSubmittedPrecision( queryParameters); + }catch(Exception ex){ + errorMsgMap.put(fieldName,ex.getMessage()); + return errorMsgMap; + } + + errorMsgMap.putAll(checkDate( precisionURI, queryParameters) ); + + return errorMsgMap; + } + + /** + * This checks for invalid date times. + */ + final static String NON_INTEGER_YEAR = "must enter a valid year"; + final static String NON_INTEGER_MONTH = "must enter a valid month"; + final static String NON_INTEGER_DAY = "must enter a valid day"; + final static String NON_INTEGER_HOUR = "must enter a valid hour"; + final static String NON_INTEGER_MINUTE = "must enter a valid minute"; + final static String NON_INTEGER_SECOND = "must enter a valid second"; + + private Map checkDate( String precisionURI, Map qp){ + if( precisionURI == null ) + return Collections.emptyMap(); + + Map errors = new HashMap(); + + Integer year,month,day,hour,minute,second; + + //just check if the values for the precision parse to integers + if( precisionURI.equals(VitroVocabulary.Precision.YEAR.uri() ) ){ + if( ! canParseToNumber(fieldName+"-year" ,qp)) + errors.put(fieldName+"-year", NON_INTEGER_YEAR); + }else if( precisionURI.equals( VitroVocabulary.Precision.MONTH.uri() )){ + if( ! canParseToNumber(fieldName+"-year" ,qp)) + errors.put(fieldName+"-year", NON_INTEGER_YEAR); + if( ! canParseToNumber(fieldName+"-month" ,qp)) + errors.put(fieldName+"-month", NON_INTEGER_MONTH); + }else if( precisionURI.equals( VitroVocabulary.Precision.DAY.uri() )){ + if( ! canParseToNumber(fieldName+"-year" ,qp)) + errors.put(fieldName+"-year", NON_INTEGER_YEAR); + if( ! canParseToNumber(fieldName+"-month" ,qp)) + errors.put(fieldName+"-month", NON_INTEGER_MONTH); + if( ! canParseToNumber(fieldName+"-day" ,qp)) + errors.put(fieldName+"-day", NON_INTEGER_DAY); + }else if( precisionURI.equals( VitroVocabulary.Precision.HOUR.uri() )){ + if( ! canParseToNumber(fieldName+"-year" ,qp)) + errors.put(fieldName+"-year", NON_INTEGER_YEAR); + if( ! canParseToNumber(fieldName+"-month" ,qp)) + errors.put(fieldName+"-month", NON_INTEGER_MONTH); + if( ! canParseToNumber(fieldName+"-day" ,qp)) + errors.put(fieldName+"-day", NON_INTEGER_DAY); + if( ! canParseToNumber(fieldName+"-hour" ,qp)) + errors.put(fieldName+"-hour", NON_INTEGER_HOUR); + }else if( precisionURI.equals( VitroVocabulary.Precision.MINUTE.uri() )){ + if( ! canParseToNumber(fieldName+"-year" ,qp)) + errors.put(fieldName+"-year", NON_INTEGER_YEAR); + if( ! canParseToNumber(fieldName+"-month" ,qp)) + errors.put(fieldName+"-month", NON_INTEGER_MONTH); + if( ! canParseToNumber(fieldName+"-day" ,qp)) + errors.put(fieldName+"-day", NON_INTEGER_DAY); + if( ! canParseToNumber(fieldName+"-hour" ,qp)) + errors.put(fieldName+"-hour", NON_INTEGER_HOUR); + if( ! canParseToNumber(fieldName+"-minute" ,qp)) + errors.put(fieldName+"-minute", NON_INTEGER_HOUR); + }else if( precisionURI.equals( VitroVocabulary.Precision.SECOND.uri() )){ + if( ! canParseToNumber(fieldName+"-year" ,qp)) + errors.put(fieldName+"-year", NON_INTEGER_YEAR); + if( ! canParseToNumber(fieldName+"-month" ,qp)) + errors.put(fieldName+"-month", NON_INTEGER_MONTH); + if( ! canParseToNumber(fieldName+"-day" ,qp)) + errors.put(fieldName+"-day", NON_INTEGER_DAY); + if( ! canParseToNumber(fieldName+"-hour" ,qp)) + errors.put(fieldName+"-hour", NON_INTEGER_HOUR); + if( ! canParseToNumber(fieldName+"-minute" ,qp)) + errors.put(fieldName+"-minute", NON_INTEGER_HOUR); + if( ! canParseToNumber(fieldName+"-second" ,qp)) + errors.put(fieldName+"-second", NON_INTEGER_SECOND); + } + + //check if we can make a valid date with these integers + year = parseToInt(fieldName+"-year", qp); + if( year == null ) + year = 1999; + month= parseToInt(fieldName+"-month", qp); + if(month == null ) + month = 1; + day = parseToInt(fieldName+"-day", qp); + if( day == null ) + day = 1; + hour = parseToInt(fieldName+"-hour", qp); + if( hour == null ) + hour = 0; + minute = parseToInt(fieldName+"-minute",qp); + if( minute == null ) + minute = 0; + second = parseToInt(fieldName+"-second", qp); + if( second == null ) + second = 0; + + //initialize to something so that we can be assured not to get + //system date dependent behavior + DateTime dateTime = new DateTime("1970-01-01T00:00:00Z"); + + try{ + dateTime = dateTime.withYear(year); + }catch(IllegalArgumentException iae){ + errors.put(fieldName+"-year", iae.getLocalizedMessage()); + } + try{ + dateTime = dateTime.withMonthOfYear(month); + }catch(IllegalArgumentException iae){ + errors.put(fieldName+"-month", iae.getLocalizedMessage()); + } + try{ + dateTime = dateTime.withDayOfMonth(day); + }catch(IllegalArgumentException iae){ + errors.put(fieldName+"-day", iae.getLocalizedMessage()); + } + try{ + dateTime = dateTime.withHourOfDay(hour); + }catch(IllegalArgumentException iae){ + errors.put(fieldName+"-hour", iae.getLocalizedMessage()); + } + try{ + dateTime = dateTime.withSecondOfMinute(second); + }catch(IllegalArgumentException iae){ + errors.put(fieldName+"-second", iae.getLocalizedMessage()); + } + + return errors; + } + + + private boolean fieldMatchesPattern( String fieldName, MapqueryParameters, Pattern pattern){ + String[] varg = queryParameters.get(fieldName); + if( varg == null || varg.length != 1 || varg[0] == null) + return false; + String value = varg[0]; + Matcher match = pattern.matcher(value); + return match.matches(); + } + + private boolean emptyOrBlank(String key,Map queryParameters){ + String[] vt = queryParameters.get(key); + return ( vt == null || vt.length ==0 || vt[0] == null || vt[0].length() == 0 ); + } + + private boolean canParseToNumber(String key,Map queryParameters){ + Integer out = null; + try{ + String[] vt = queryParameters.get(key); + if( vt == null || vt.length ==0 || vt[0] == null) + return false; + else{ + out = Integer.parseInt(vt[0]); + return true; + } + }catch(IndexOutOfBoundsException iex){ + out = null; + }catch(NumberFormatException nfe){ + out = null; + }catch(NullPointerException npe){ + out = null; + } + return false; + } + + + + private Integer parseToInt(String key,Map queryParameters){ + Integer out = null; + try{ + String[] vt = queryParameters.get(key); + if( vt == null || vt.length ==0 || vt[0] == null) + out = null; + else + out = Integer.parseInt(vt[0]); + }catch(IndexOutOfBoundsException iex){ + out = null; + }catch(NumberFormatException nfe){ + out = null; + }catch(NullPointerException npe){ + out = null; + } + return out; + } + + public VitroVocabulary.Precision getRequiredMinimumPrecision() { + return minimumPrecision; + } + + public void setRequiredMinimumPrecision( + VitroVocabulary.Precision requiredMinimumPrecision) { + this.minimumPrecision = requiredMinimumPrecision; + } + + /* returns null if it cannot convert */ + public static VitroVocabulary.Precision toPrecision(String precisionUri){ + for( VitroVocabulary.Precision precision : VitroVocabulary.Precision.values()){ + if( precision.uri().equals(precisionUri)) + return precision; + } + return null; + } + + public String getValueVariableName(){ return fieldName + "-value" ; } + public String getPrecisionVariableName(){ return fieldName + "-precision" ; } +} + + 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 630108cdc..937b30620 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 @@ -2,6 +2,7 @@ package edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -11,18 +12,23 @@ import javax.servlet.http.HttpSession; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import com.hp.hpl.jena.rdf.model.Literal; import com.hp.hpl.jena.rdf.model.Model; +import com.hp.hpl.jena.vocabulary.XSD; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.EditConfiguration; +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.web.templatemodels.edit.EditConfigurationTemplateModel; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerConfigurationLoader; 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 freemarker.template.Configuration; public class EditConfigurationUtils { private static Log log = LogFactory.getLog(EditConfigurationUtils.class); @@ -186,5 +192,49 @@ public class EditConfigurationUtils { } return dataHash; } + + //Copied from the original input element formatting tag + //Allows the retrieval of the string values for the literals + //Useful for cases with date/time and other mechanisms + public static Map> getExistingLiteralValues(VitroRequest vreq, EditConfigurationVTwo editConfig) { + Map> literalsInScopeStringValues = new HashMap>(); + Map> literalsInScope = editConfig.getLiteralsInScope(); + + for(String key: literalsInScope.keySet() ) { + List stringValues = processLiteral(editConfig, key); + literalsInScopeStringValues.put(key, stringValues); + } + return literalsInScopeStringValues; + } + + //Copied from input element formatting tag + private static List processLiteral(EditConfigurationVTwo editConfig, String fieldName) { + Map> literalsInScope = editConfig.getLiteralsInScope(); + List stringValues = new ArrayList(); + List literalValues = literalsInScope.get(fieldName); + for(Literal l: literalValues) { + //Could do additional processing here if required, for example if date etc. if need be + stringValues.add(l.getValue().toString()); + } + return stringValues; + } + + public static Map> getExistingUriValues(EditConfigurationVTwo editConfig) { + return editConfig.getUrisInScope(); + } + + //Generate HTML for a specific field name given + public static String generateHTMLForElement(VitroRequest vreq, String fieldName, EditConfigurationVTwo editConfig) { + String html = ""; + Configuration fmConfig = FreemarkerConfigurationLoader.getConfig(vreq, vreq.getSession().getServletContext()); + + FieldVTwo field = editConfig == null ? null : editConfig.getField(fieldName); + MultiValueEditSubmission editSub = new MultiValueEditSubmission(vreq.getParameterMap(), editConfig); + if( field != null && field.getEditElement() != null ){ + html = field.getEditElement().draw(fieldName, editConfig, editSub, fmConfig); + } + return html; + } + } 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 4d16514d5..1a70f91b5 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 @@ -114,16 +114,18 @@ public class EditConfigurationVTwo { String formUrl; String editKey; - List validators = Collections.emptyList(); + List validators; EditN3GeneratorVTwo n3generator; private List modelChangePreprocessors; - private List editSubmissionPreprocessors = Collections.emptyList(); + private List editSubmissionPreprocessors; private ProhibitedFromSearch prohibitedFromSearch; + private HashMap formSpecificData; + /** Name of freemarker template to generate form. */ String template; @@ -879,13 +881,13 @@ public class EditConfigurationVTwo { this.resourceModelSelector = resourceModelSelector; } - public List getValidators() { + public List getValidators() { return validators; } - public void addValidator( N3Validator validator){ + public void addValidator( N3ValidatorVTwo validator){ if( this.validators == null ) - this.validators = new ArrayList(); + this.validators = new ArrayList(); this.validators.add(validator); } @@ -922,4 +924,15 @@ public class EditConfigurationVTwo { public boolean isDataPropertyUpdate() { return this.getDatapropKey() != null && this.getDatapropKey().length() > 0; } + + //This is for specific data for a form that will be set by the generator + + public void setFormSpecificData(HashMap formSpecificData) { + this.formSpecificData = formSpecificData; + } + + public HashMap getFormSpecificData() { + // TODO Auto-generated method stub + return this.formSpecificData; + } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditElementVTwo.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditElementVTwo.java index 677b0831a..6c035ad9a 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditElementVTwo.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditElementVTwo.java @@ -39,6 +39,11 @@ public interface EditElementVTwo { */ public String draw(String fieldName, EditConfigurationVTwo editConfig, MultiValueEditSubmission editSub, Configuration fmConfig); + /** + * This method gets the map with the data that can then be passed to the template + */ + public Map getMapForTemplate(EditConfigurationVTwo editConfig, MultiValueEditSubmission editSub); + /* in the future, we may need to get existing values */ /* public Map getExistingLiterals(???) diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/N3ValidatorVTwo.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/N3ValidatorVTwo.java new file mode 100644 index 000000000..fb0529a0e --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/N3ValidatorVTwo.java @@ -0,0 +1,12 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo; + +import java.util.Map; + +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.EditConfiguration; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.processEdit.EditSubmission; + +public interface N3ValidatorVTwo { + public Map validate(EditConfigurationVTwo editConfig, MultiValueEditSubmission editSub); +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/AddClinicalRoleToPersonGenerator.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/AddClinicalRoleToPersonGenerator.java new file mode 100644 index 000000000..1e886f355 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/AddClinicalRoleToPersonGenerator.java @@ -0,0 +1,123 @@ +/* $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 java.util.Set; +import org.apache.commons.lang.StringUtils; +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.DateTimeWithPrecisionVTwo; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationUtils; +import edu.cornell.mannlib.vitro.webapp.dao.jena.QueryUtils; + +import com.hp.hpl.jena.rdf.model.Literal; +import com.hp.hpl.jena.rdf.model.Model; +import com.hp.hpl.jena.vocabulary.RDFS; +import com.hp.hpl.jena.vocabulary.RDF; +import com.hp.hpl.jena.vocabulary.XSD; +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.VitroVocabulary; +import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo; +import edu.cornell.mannlib.vitro.webapp.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; +import edu.cornell.mannlib.vitro.webapp.utils.FrontEndEditingUtils; +import edu.cornell.mannlib.vitro.webapp.utils.FrontEndEditingUtils.EditMode; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.validators.DateTimeIntervalValidation; +/** + * Generates the edit configuration for adding a Role to a Person. + + Stage one is selecting the type of the non-person thing + associated with the Role with the intention of reducing the + number of Individuals that the user has to select from. + Stage two is selecting the non-person Individual to associate + with the Role. + + This is intended to create a set of statements like: + + ?person core:hasResearchActivityRole ?newRole. + ?newRole rdf:type core:ResearchActivityRole ; + roleToActivityPredicate ?someActivity . + ?someActivity rdf:type core:ResearchActivity . + ?someActivity rdfs:label "activity title" . + + + Each subclass of the abstract two stage Generator class will have the option of overriding certain + methods, and must always implement the following methods: + getRoleType + getRoleActivityTypeOptionsType + getRoleActivityTypeObjectClassUri + getRoleActivityTypeLiteralOptions + + * + */ +public class AddClinicalRoleToPersonGenerator extends AddRoleToPersonTwoStageGenerator { + + private Log log = LogFactory.getLog(AddClinicalRoleToPersonGenerator.class); + private static String template = "addClinicalRoleToPerson.ftl"; + + //Should this be overridden + @Override + protected void setTemplate(EditConfigurationVTwo editConfiguration, + VitroRequest vreq) { + editConfiguration.setTemplate(template); + } + + + //The default activityToRolePredicate and roleToActivityPredicates are + //correct for this subclass so they don't need to be overwritten + + //role type will always be set based on particular form + public String getRoleType(VitroRequest vreq) { + //TODO: Get dynamic way of including vivoweb ontology + return "http://vivoweb.org/ontology/core#ClinicalRole"; + } + + //Each subclass generator will return its own type of option here: + //whether literal hardcoded, based on class group, or subclasses of a specific class + //The latter two will apparently lend some kind of uri to objectClassUri ? + public RoleActivityOptionTypes getRoleActivityTypeOptionsType(VitroRequest vreq) { + return RoleActivityOptionTypes.HARDCODED_LITERALS; + } + + //This too will depend on the specific subclass of generator + public String getRoleActivityTypeObjectClassUri(VitroRequest vreq) { + return null; + } + + + //Clinical role involves hard-coded options for the "right side" of the role or activity + protected HashMap getRoleActivityTypeLiteralOptions(VitroRequest vreq) { + HashMap literalOptions = new HashMap(); + literalOptions.put("", "Select one"); + literalOptions.put("http://vivoweb.org/ontology/core#Project", "Project"); + literalOptions.put("http://vivoweb.org/ontology/core#Service","Service"); + return literalOptions; + } + + //isShowRoleLabelField remains true for this so doesn't need to be overwritten + + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/AddRoleToPersonTwoStageGenerator.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/AddRoleToPersonTwoStageGenerator.java new file mode 100644 index 000000000..370411b4a --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/AddRoleToPersonTwoStageGenerator.java @@ -0,0 +1,983 @@ +/* $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 java.util.Set; +import org.apache.commons.lang.StringUtils; +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.DateTimeWithPrecisionVTwo; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.DateTimeIntervalValidationVTwo; + +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationUtils; +import edu.cornell.mannlib.vitro.webapp.dao.jena.QueryUtils; + +import com.hp.hpl.jena.rdf.model.Literal; +import com.hp.hpl.jena.rdf.model.Model; +import com.hp.hpl.jena.vocabulary.RDFS; +import com.hp.hpl.jena.vocabulary.RDF; +import com.hp.hpl.jena.vocabulary.XSD; +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.VitroVocabulary; +import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo; +import edu.cornell.mannlib.vitro.webapp.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; +import edu.cornell.mannlib.vitro.webapp.utils.FrontEndEditingUtils; +import edu.cornell.mannlib.vitro.webapp.utils.FrontEndEditingUtils.EditMode; +/** + * Generates the edit configuration for adding a Role to a Person. + + Stage one is selecting the type of the non-person thing + associated with the Role with the intention of reducing the + number of Individuals that the user has to select from. + Stage two is selecting the non-person Individual to associate + with the Role. + + This is intended to create a set of statements like: + + ?person core:hasResearchActivityRole ?newRole. + ?newRole rdf:type core:ResearchActivityRole ; + roleToActivityPredicate ?someActivity . + ?someActivity rdf:type core:ResearchActivity . + ?someActivity rdfs:label "activity title" . + + + Important: This form cannot be directly used as a custom form. It has parameters that must be set. + See addClinicalRoleToPerson.jsp for an example. + + * + */ +public abstract class AddRoleToPersonTwoStageGenerator implements EditConfigurationGenerator { + + private Log log = LogFactory.getLog(AddRoleToPersonTwoStageGenerator.class); + private boolean isObjectPropForm = false; + 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 = "addRoleToPersonTwoStage.ftl"; + private static HashMap defaultsForXSDtypes ; + + //Types of options to populate drop-down for types for the "right side" of the role + public static enum RoleActivityOptionTypes { + VCLASSGROUP, + CHILD_VCLASSES, + HARDCODED_LITERALS + }; + + @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()); + + //Todo: what do new resources depend on here? + //In original form, these variables start off empty + editConfiguration.setNewResources(generateNewResources(vreq)); + //In scope + this.setUrisAndLiteralsInScope(editConfiguration, vreq); + + //on Form + this.setUrisAndLiteralsOnForm(editConfiguration, vreq); + + editConfiguration.setFilesOnForm(new ArrayList()); + + //Sparql queries + this.setSparqlQueries(editConfiguration, vreq); + + //set fields + setFields(editConfiguration, vreq, EditConfigurationUtils.getPredicateUri(vreq)); + + // No need to put in session here b/c put in session within edit request dispatch controller instead + //placing in session depends on having edit key which is handled in edit request dispatch controller + // editConfiguration.putConfigInSession(editConfiguration, session); + + 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(editConfiguration, vreq); + //Add validator + editConfiguration.addValidator(new DateTimeIntervalValidationVTwo("startField","endField") ); + //Adding additional data, specifically edit mode + addFormSpecificData(editConfiguration, vreq); + return editConfiguration; + } + + private void setEditKey(EditConfigurationVTwo editConfiguration, VitroRequest vreq) { + String editKey = EditConfigurationUtils.getEditKey(vreq); + editConfiguration.setEditKey(editKey); + } + + protected void setTemplate(EditConfigurationVTwo editConfiguration, + VitroRequest vreq) { + editConfiguration.setTemplate(template); + + } + + //Initialize setup: process parameters + //There will be specialized parameters as well, we may include them here or in a + //separate method + 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("person"); + editConfiguration.setSubjectUri(subjectUri); + editConfiguration.setEntityToReturnTo(subjectUri); + editConfiguration.setVarNameForPredicate("rolePredicate"); + editConfiguration.setPredicateUri(predicateUri); + //by definition, this is an object property + this.initObjectParameters(vreq); + this.processObjectPropForm(vreq, editConfiguration); + + } + + + + private void initObjectParameters(VitroRequest vreq) { + //in case of object property + objectUri = EditConfigurationUtils.getObjectUri(vreq); + } + + private void processObjectPropForm(VitroRequest vreq, EditConfigurationVTwo editConfiguration) { + editConfiguration.setVarNameForObject("role"); + 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); + } + } + + + /* + * N3 Required and Optional Generators as well as supporting methods + */ + + private String getPrefixesString() { + //TODO: Include dynamic way of including this + return "@prefix core: http://vivoweb.org/ontology/core# ."; + } + + //TODO: Check if single string or multiple strings - check rdfslabel form etc. for prefix + //processing + private List generateN3Required(VitroRequest vreq) { + List n3ForEdit = new ArrayList(); + String editString = getPrefixesString() + " /n"; + editString += "?person ?rolePredicate ?role ."; + editString += "?role a <" + getRoleType(vreq) + "> ."; + editString += "?role <" + getRoleToActivityPredicate(vreq) + "> ?roleActivity ."; + editString += "?roleActivity <" + getActivityToRolePredicate(vreq) + "> ?role ."; + n3ForEdit.add(editString); + return n3ForEdit; + } + + + private List generateN3Optional() { + List n3Optional = new ArrayList(); + //n3 for activity label + n3Optional.add(getN3ForActivityLabel()); + //n3 for activity type + n3Optional.add(getN3ForActivityType()); + //n3 for inverse + n3Optional.add("?role ?inverseRolePredicate ?person ."); + //N3ForStart + n3Optional.addAll(getN3ForStart()); + //N3 For End + n3Optional.addAll(getN3ForEnd()); + //role label assertion + n3Optional.add(getN3RoleLabelAssertion()); + return n3Optional; + } + + + public String getN3ForActivityLabel() { + return "?roleActivity <" + RDFS.label.getURI() + "> ?activityLabel ."; + } + + public String getN3ForActivityType() { + return "?roleActivity a ?roleActivityType ."; + } + + public String getN3RoleLabelAssertion() { + return "?role <" + RDFS.label.getURI() + "> ?roleLabel ."; + } + + //Method b/c used in two locations, n3 optional and n3 assertions + private List getN3ForStart() { + List n3ForStart = new ArrayList(); + n3ForStart.add("?role <" + getRoleToIntervalURI() + "> ?intervalNode ." + + "?intervalNode <" + RDF.type.getURI() + "> <" + getIntervalTypeURI() + "> ." + + "?intervalNode <" + getIntervalToStartURI() + "> ?startNode ." + + "?startNode <" + RDF.type.getURI() + "> <" + getDateTimeValueTypeURI() + "> ." + + "?startNode <" + getDateTimeValueURI() + "> ?startField-value ." + + "?startNode <" + getDateTimePrecisionURI() + "> ?startField-precision ."); + return n3ForStart; + } + + private List getN3ForEnd() { + List n3ForEnd = new ArrayList(); + n3ForEnd.add("?role <" + getRoleToIntervalURI() + "> ?intervalNode . " + + "?intervalNode <" + RDF.type.getURI() + "> <" + getIntervalTypeURI() + "> ." + + "?intervalNode <" + getIntervalToEndURI() + "> ?endNode ." + + "?endNode <" + RDF.type.getURI() + "> <" + getDateTimeValueTypeURI() + "> ." + + "?endNode <" + getDateTimeValueURI() + "> ?endField-value ." + + "?endNode <" + getDateTimePrecisionURI() + "> ?endField-precision ."); + return n3ForEnd; + + } + + + /* + * Get new resources + */ + private Map generateNewResources(VitroRequest vreq) { + HashMap newResources = new HashMap(); + //TODO: Get default namespace + String defaultNamespace = vreq.getWebappDaoFactory().getDefaultNamespace(); + newResources.put("role", defaultNamespace + "individual"); + newResources.put("roleActivity", defaultNamespace + "individual"); + newResources.put("intervalNode", defaultNamespace + "individual"); + newResources.put("startNode", defaultNamespace + "individual"); + newResources.put("endNode", defaultNamespace + "individual"); + return newResources; + } + + + + + /* + * Set URIS and Literals In Scope and on form and supporting methods + */ + + private void setUrisAndLiteralsInScope(EditConfigurationVTwo editConfiguration, VitroRequest vreq) { + HashMap> urisInScope = new HashMap>(); + //note that at this point the subject, predicate, and object var parameters have already been processed + //these two were always set when instantiating an edit configuration object from json, + //although the json itself did not specify subject/predicate as part of uris in scope + urisInScope.put(editConfiguration.getVarNameForSubject(), + Arrays.asList(new String[]{editConfiguration.getSubjectUri()})); + urisInScope.put(editConfiguration.getVarNameForPredicate(), + Arrays.asList(new String[]{editConfiguration.getPredicateUri()})); + //Setting inverse role predicate + urisInScope.put("inverseRolePredicate", getInversePredicate(vreq)); + + + editConfiguration.setUrisInScope(urisInScope); + //Uris in scope include subject, predicate, and object var + //literals in scope empty initially, usually populated by code in prepare for update + //with existing values for variables + editConfiguration.setLiteralsInScope(new HashMap>()); + } + + private List getInversePredicate(VitroRequest vreq) { + List inversePredicateArray = new ArrayList(); + ObjectProperty op = EditConfigurationUtils.getObjectProperty(vreq); + if(op != null && op.getURIInverse() != null) { + inversePredicateArray.add(op.getURIInverse()); + } + return inversePredicateArray; + } + + //n3 should look as follows + //?subject ?predicate ?objectVar + + private void setUrisAndLiteralsOnForm(EditConfigurationVTwo editConfiguration, VitroRequest vreq) { + List urisOnForm = new ArrayList(); + List literalsOnForm = new ArrayList(); + //add role activity and roleActivityType to uris on form + urisOnForm.add("roleActivity"); + urisOnForm.add("roleActivityType"); + editConfiguration.setUrisOnform(urisOnForm); + //activity label and role label are literals on form + literalsOnForm.add("activityLabel"); + literalsOnForm.add("roleLabel"); + editConfiguration.setLiteralsOnForm(literalsOnForm); + } + + + /** + * Set SPARQL Queries and supporting methods + */ + + + private void setSparqlQueries(EditConfigurationVTwo editConfiguration, VitroRequest vreq) { + //Sparql queries defining retrieval of literals etc. + editConfiguration.setSparqlForAdditionalLiteralsInScope(new HashMap()); + + Map urisInScope = new HashMap(); + editConfiguration.setSparqlForAdditionalUrisInScope(urisInScope); + + editConfiguration.setSparqlForExistingLiterals(generateSparqlForExistingLiterals(vreq)); + editConfiguration.setSparqlForExistingUris(generateSparqlForExistingUris(vreq)); + } + + + //Get page uri for object + private HashMap generateSparqlForExistingUris(VitroRequest vreq) { + HashMap map = new HashMap(); + //Queries for role activity, activity type query, interval node, start node, end node, start field precision, endfield precision + map.put("roleActivity", getRoleActivityQuery(vreq)); + map.put("roleActivityType", getActivityTypeQuery(vreq)); + map.put("intervalNode", getIntervalNodeQuery(vreq)); + map.put("startNode", getStartNodeQuery(vreq)); + map.put("endNode", getEndNodeQuery(vreq)); + map.put("startField-precision", getStartPrecisionQuery(vreq)); + map.put("endField-precision", getEndPrecisionQuery(vreq)); + return map; + } + + private String getEndPrecisionQuery(VitroRequest vreq) { + String query = "SELECT ?existingEndPrecision WHERE {" + + "?role <" + getRoleToIntervalURI() + "> ?intervalNode ." + + "?intervalNode <" + VitroVocabulary.RDF_TYPE + "> <" + getIntervalTypeURI() + "> ." + + "?intervalNode <" + getIntervalToEndURI() + "> ?endNode ." + + "?endNode <" + VitroVocabulary.RDF_TYPE + "> <" + getDateTimeValueTypeURI() + "> . " + + "?endNode <" + getDateTimePrecisionURI() + "> ?existingEndPrecision . }"; + return query; + } + + private String getStartPrecisionQuery(VitroRequest vreq) { + String query = "SELECT ?existingStartPrecision WHERE {" + + "?role <" + getRoleToIntervalURI() + "> ?intervalNode ." + + "?intervalNode <" + VitroVocabulary.RDF_TYPE + "> <" + getIntervalTypeURI() + "> ." + + "?intervalNode <" + getIntervalToStartURI() + "> ?startNode ." + + "?startNode <" + VitroVocabulary.RDF_TYPE + "> <" + getDateTimeValueTypeURI() + "> . " + + "?startNode <" + getDateTimePrecisionURI() + "> ?existingStartPrecision . }"; + return query; + } + + private String getEndNodeQuery(VitroRequest vreq) { + String query = "SELECT ?existingEndNode WHERE {"+ + "?role <" + getRoleToIntervalURI() + "> ?intervalNode ."+ + "?intervalNode <" + VitroVocabulary.RDF_TYPE + "> <" + getIntervalTypeURI() + "> ."+ + " ?intervalNode <" + getIntervalToEndURI() + "> ?existingEndNode . "+ + "?existingEndNode <" + VitroVocabulary.RDF_TYPE + "> <" + getDateTimeValueTypeURI() + "> .}"; + return query; + } + + private String getStartNodeQuery(VitroRequest vreq) { + String query = "SELECT ?existingStartNode WHERE {"+ + "?role <" + getRoleToIntervalURI() + "> ?intervalNode ."+ + "?intervalNode <" + VitroVocabulary.RDF_TYPE + "> <" + getIntervalTypeURI() + "> ."+ + "?intervalNode <" + getIntervalToStartURI() + "> ?existingStartNode . "+ + "?existingStartNode <" + VitroVocabulary.RDF_TYPE + "> <" + getDateTimeValueTypeURI() + "> .}"; + return query; + } + + private String getIntervalNodeQuery(VitroRequest vreq) { + String query = "SELECT ?existingIntervalNode WHERE { " + + "?role <" + getRoleToIntervalURI() + "> ?existingIntervalNode . " + + " ?existingIntervalNode <" + VitroVocabulary.RDF_TYPE + "> <" + getIntervalTypeURI() + "> . }"; + return query; + } + + + /* + * The activity type query results must be limited to the values in the activity type select element. + * Sometimes the query returns a superclass such as owl:Thing instead. + * Make use of vitro:mostSpecificType so that, for example, an individual is both a + * core:InvitedTalk and a core:Presentation, core:InvitedTalk is selected. + * vitro:mostSpecificType alone may not suffice, since it does not guarantee that the value returned + * is in the select list. + * We could still have problems if the value from the select list is not a vitro:mostSpecificType, + * but that is unlikely. + */ + //This method had some code already setup in the jsp file + private String getActivityTypeQuery(VitroRequest vreq) { + String activityTypeQuery = null; + + //roleActivityType_optionsType: This gets you whether this is a literal + // + RoleActivityOptionTypes optionsType = getRoleActivityTypeOptionsType(vreq); + + // Note that this value is overloaded to specify either object class uri or classgroup uri + String objectClassUri = getRoleActivityTypeObjectClassUri(vreq); + + if (StringUtils.isNotBlank(objectClassUri)) { + log.debug("objectClassUri = " + objectClassUri); + + if (RoleActivityOptionTypes.VCLASSGROUP.equals(optionsType)) { + activityTypeQuery = getClassgroupActivityTypeQuery(vreq); + activityTypeQuery = QueryUtils.subUriForQueryVar(activityTypeQuery, "classgroup", objectClassUri); + + } else if (RoleActivityOptionTypes.CHILD_VCLASSES.equals(optionsType)) { + activityTypeQuery = getSubclassActivityTypeQuery(vreq); + activityTypeQuery = QueryUtils.subUriForQueryVar(activityTypeQuery, "objectClassUri", objectClassUri); + + } else { + activityTypeQuery = getDefaultActivityTypeQuery(vreq); + } + + // Select options are hardcoded + } else if (RoleActivityOptionTypes.HARDCODED_LITERALS.equals(optionsType)) { + + //literal options + HashMap typeLiteralOptions = getRoleActivityTypeLiteralOptions(vreq); + if (typeLiteralOptions.size() > 0) { + try { + List typeUris = new ArrayList(); + Set optionUris = typeLiteralOptions.keySet(); + for(String uri: optionUris) { + typeUris.add("(?existingActivityType = <" + uri + ">)"); + } + String typeFilters = "FILTER (" + StringUtils.join(typeUris, "||") + ")"; + String defaultActivityTypeQuery = getDefaultActivityTypeQuery(vreq); + activityTypeQuery = defaultActivityTypeQuery.replaceAll("}$", "") + typeFilters + "}"; + } catch (Exception e) { + activityTypeQuery = getDefaultActivityTypeQuery(vreq); + } + + } else { + activityTypeQuery = getDefaultActivityTypeQuery(vreq); + } + + } else { + activityTypeQuery = getDefaultActivityTypeQuery(vreq); + } + + String roleToActivityPredicate = getRoleToActivityPredicate(vreq); + activityTypeQuery = QueryUtils.subUriForQueryVar(activityTypeQuery, "predicate", roleToActivityPredicate); + log.debug("Activity type query: " + activityTypeQuery); + + return activityTypeQuery; + } + + + private String getDefaultActivityTypeQuery(VitroRequest vreq) { + String query = "PREFIX core: <" + getVivoCoreNamespace() + ">\n" + + "PREFIX vitro: <" + VitroVocabulary.vitroURI + "> \n" + + "SELECT ?existingActivityType WHERE { \n" + + " ?role ?predicate ?existingActivity . \n" + + " ?existingActivity vitro:mostSpecificType ?existingActivityType . \n" + + "}"; + return query; + } + + private String getSubclassActivityTypeQuery(VitroRequest vreq) { + String query = "PREFIX core: <" + getVivoCoreNamespace() + ">\n" + + "PREFIX rdfs: <" + VitroVocabulary.RDFS + ">\n" + + "PREFIX vitro: <" + VitroVocabulary.vitroURI + "> \n" + + "SELECT ?existingActivityType WHERE {\n" + + " ?role ?predicate ?existingActivity . \n" + + " ?existingActivity vitro:mostSpecificType ?existingActivityType . \n" + + " ?existingActivityType rdfs:subClassOf ?objectClassUri . \n" + + "}"; + return query; + } + + private String getClassgroupActivityTypeQuery(VitroRequest vreq) { + String query = "PREFIX core: <" + getVivoCoreNamespace() + ">\n" + + "PREFIX vitro: <" + VitroVocabulary.vitroURI + "> \n" + + "SELECT ?existingActivityType WHERE { \n" + + " ?role ?predicate ?existingActivity . \n" + + " ?existingActivity vitro:mostSpecificType ?existingActivityType . \n" + + " ?existingActivityType vitro:inClassGroup ?classgroup . \n" + + "}"; + return query; + } + + + private String getRoleActivityQuery(VitroRequest vreq) { + String query = "PREFIX core: <" + getVivoCoreNamespace() + ">" + + "SELECT ?existingActivity WHERE { ?role <" + getRoleToActivityPredicate(vreq) + "> ?existingActivity . }"; + return query; + } + + private HashMap generateSparqlForExistingLiterals(VitroRequest vreq) { + HashMap map = new HashMap(); + //Queries for activity label, role label, start Field value, end Field value + map.put("activityLabel", getActivityLabelQuery(vreq)); + map.put("roleLabel", getRoleLabelQuery(vreq)); + map.put("startField-value", getExistingStartDateQuery(vreq)); + map.put("endField-value", getExistingEndDateQuery(vreq)); + return map; + } + + + private String getExistingEndDateQuery(VitroRequest vreq) { + String query = " SELECT ?existingEndDate WHERE {\n" + + "?role <" + getRoleToIntervalURI() + "> ?intervalNode .\n" + + "?intervalNode <" + VitroVocabulary.RDF_TYPE + "> <" + getIntervalTypeURI() + "> .\n" + + "?intervalNode <" + getIntervalToEndURI() + "> ?endNode .\n" + + "?endNode <" + VitroVocabulary.RDF_TYPE + "> <" + getDateTimeValueTypeURI() + "> .\n" + + "?endNode <" + getDateTimeValueURI() + "> ?existingEndDate . }"; + return query; + } + + private String getExistingStartDateQuery(VitroRequest vreq) { + String query = "SELECT ?existingDateStart WHERE {\n" + + "?role <" + getRoleToIntervalURI() + "> ?intervalNode .\n" + + "?intervalNode <" + VitroVocabulary.RDF_TYPE + "> <" + getIntervalTypeURI() + "> .\n" + + "?intervalNode <" + getIntervalToStartURI() + "> ?startNode .\n" + + "?startNode <" + VitroVocabulary.RDF_TYPE + "> <" + getDateTimeValueTypeURI() + "> .\n" + + "?startNode <" + getDateTimeValueURI() + "> ?existingDateStart . }"; + + return query; + } + + private String getRoleLabelQuery(VitroRequest vreq) { + String query = "SELECT ?existingRoleLabel WHERE { ?role <" + VitroVocabulary.LABEL + "> ?existingRoleLabel . }"; + return query; + } + + private String getActivityLabelQuery(VitroRequest vreq) { + String query = "PREFIX core: <" + getVivoCoreNamespace() + "> \n" + + "PREFIX rdfs: <" + RDFS.getURI() + "> \n" + + "SELECT ?existingTitle WHERE { \n" + + "?role <" + getRoleToActivityPredicate(vreq) + "> ?existingActivity . \n" + + "?existingActivity rdfs:label ?existingTitle . }"; + return query; + } + + /** + * + * Set Fields and supporting methods + */ + + private void setFields(EditConfigurationVTwo editConfiguration, VitroRequest vreq, String predicateUri) { + Map fields = new HashMap(); + //Multiple fields + getActivityLabelField(editConfiguration, vreq, fields); + getRoleActivityTypeField(editConfiguration, vreq, fields); + getRoleActivityField(editConfiguration, vreq, fields); + getRoleLabelField(editConfiguration, vreq, fields); + getStartField(editConfiguration, vreq, fields); + getEndField(editConfiguration, vreq, fields); + + editConfiguration.setFields(fields); + } + + + //Label of "right side" of role, i.e. label for role roleIn Activity + private void getActivityLabelField(EditConfigurationVTwo editConfiguration, + VitroRequest vreq, Map fields) { + String fieldName = "activityLabel"; + //get range data type uri and range language + String stringDatatypeUri = XSD.xstring.toString(); + + FieldVTwo field = new FieldVTwo(); + field.setName(fieldName); + field.setNewResource(false); + //queryForExisting is not being used anywhere in Field + + + List validators = new ArrayList(); + //If add mode or repair, etc. need to add label required validator + if(isAddMode(vreq) || isRepairMode(vreq)) { + validators.add("nonempty"); + } + validators.add("datatype:" + stringDatatypeUri); + field.setValidators(validators); + + //subjectUri and subjectClassUri are not being used in Field + + field.setOptionsType("UNDEFINED"); + //why isn't predicate uri set for data properties? + field.setPredicateUri(null); + field.setObjectClassUri(null); + field.setRangeDatatypeUri(stringDatatypeUri); + + + field.setLiteralOptions(new ArrayList>()); + + //set assertions + List assertions = new ArrayList(); + assertions.add(getN3ForActivityLabel()); + field.setAssertions(assertions); + fields.put(field.getName(), field); + } + + //type of "right side" of role, i.e. type of activity from role roleIn activity + private void getRoleActivityTypeField( + EditConfigurationVTwo editConfiguration, VitroRequest vreq, + Map fields) { + String fieldName = "roleActivityType"; + //get range data type uri and range language + + FieldVTwo field = new FieldVTwo(); + field.setName(fieldName); + field.setNewResource(true); + //queryForExisting is not being used anywhere in Field + + + List validators = new ArrayList(); + if(isAddMode(vreq) || isRepairMode(vreq)) { + validators.add("nonempty"); + } + field.setValidators(validators); + + //subjectUri and subjectClassUri are not being used in Field + //TODO: Check if this is correct + field.setOptionsType(getRoleActivityTypeOptionsType(vreq).toString()); + //why isn't predicate uri set for data properties? + field.setPredicateUri(null); + field.setObjectClassUri(getRoleActivityTypeObjectClassUri(vreq)); + field.setRangeDatatypeUri(null); + + + HashMap literalOptionsMap = getRoleActivityTypeLiteralOptions(vreq); + List> fieldLiteralOptions = new ArrayList>(); + Set optionUris = literalOptionsMap.keySet(); + for(String optionUri: optionUris) { + List uriLabelArray = new ArrayList(); + uriLabelArray.add(optionUri); + uriLabelArray.add(literalOptionsMap.get(optionUri)); + fieldLiteralOptions.add(uriLabelArray); + } + field.setLiteralOptions(fieldLiteralOptions); + + //set assertions + List assertions = new ArrayList(); + assertions.add(getN3ForActivityType()); + field.setAssertions(assertions); + fields.put(field.getName(), field); + + } + + //Assuming URI for activity for role? + private void getRoleActivityField(EditConfigurationVTwo editConfiguration, + VitroRequest vreq, Map fields) { + String fieldName = "roleActivity"; + //get range data type uri and range language + + FieldVTwo field = new FieldVTwo(); + field.setName(fieldName); + field.setNewResource(true); + + List validators = new ArrayList(); + field.setValidators(validators); + + //subjectUri and subjectClassUri are not being used in Field + + field.setOptionsType("UNDEFINED"); + //why isn't predicate uri set for data properties? + field.setPredicateUri(null); + field.setObjectClassUri(null); + field.setRangeDatatypeUri(null); + //empty + field.setLiteralOptions(new ArrayList>()); + + //set assertions + List assertions = new ArrayList(); + //N3ForRoleToActivity + String n3ForRoleToActivity = "@prefix core: <" + getVivoCoreNamespace() + "> ." + + "?role <" + getRoleToActivityPredicate(vreq) + "> ?roleActivity ." + + "?roleActivity <" + getActivityToRolePredicate(vreq) + "> ?role ."; + assertions.add(n3ForRoleToActivity); + field.setAssertions(assertions); + fields.put(field.getName(), field); + + } + + private void getRoleLabelField(EditConfigurationVTwo editConfiguration, + VitroRequest vreq, Map fields) { + String fieldName = "roleLabel"; + String stringDatatypeUri = XSD.xstring.toString(); + + + FieldVTwo field = new FieldVTwo(); + field.setName(fieldName); + field.setNewResource(false); + + List validators = new ArrayList(); + validators.add("datatype:" + stringDatatypeUri); + if(isShowRoleLabelField(vreq)) { + validators.add("nonempty"); + } + field.setValidators(validators); + + //subjectUri and subjectClassUri are not being used in Field + + field.setOptionsType("UNDEFINED"); + //why isn't predicate uri set for data properties? + field.setPredicateUri(null); + field.setObjectClassUri(null); + field.setRangeDatatypeUri(stringDatatypeUri); + //empty + field.setLiteralOptions(new ArrayList>()); + + //set assertions + List assertions = new ArrayList(); + assertions.add(getN3RoleLabelAssertion()); + field.setAssertions(assertions); + fields.put(field.getName(), field); + + } + + + + private void getStartField(EditConfigurationVTwo editConfiguration, + VitroRequest vreq, Map fields) { + String fieldName = "startField"; + + FieldVTwo field = new FieldVTwo(); + field.setName(fieldName); + field.setNewResource(false); + + List validators = new ArrayList(); + field.setValidators(validators); + + //subjectUri and subjectClassUri are not being used in Field + + field.setOptionsType("UNDEFINED"); + //why isn't predicate uri set for data properties? + field.setPredicateUri(null); + field.setObjectClassUri(null); + field.setRangeDatatypeUri(null); + //empty + field.setLiteralOptions(new ArrayList>()); + + //set assertions + List assertions = new ArrayList(); + assertions.addAll(getN3ForStart()); + field.setAssertions(assertions); + + //This logic was originally after edit configuration object created from json in original jsp + field.setEditElement( + new DateTimeWithPrecisionVTwo(field, + VitroVocabulary.Precision.YEAR.uri(), + VitroVocabulary.Precision.NONE.uri())); + + fields.put(field.getName(), field); + + } + + private void getEndField(EditConfigurationVTwo editConfiguration, + VitroRequest vreq, Map fields) { + String fieldName = "endField"; + + FieldVTwo field = new FieldVTwo(); + field.setName(fieldName); + field.setNewResource(false); + + List validators = new ArrayList(); + field.setValidators(validators); + + //subjectUri and subjectClassUri are not being used in Field + + field.setOptionsType("UNDEFINED"); + //why isn't predicate uri set for data properties? + field.setPredicateUri(null); + field.setObjectClassUri(null); + field.setRangeDatatypeUri(null); + //empty + field.setLiteralOptions(new ArrayList>()); + + //set assertions + List assertions = new ArrayList(); + assertions.addAll(getN3ForEnd()); + field.setAssertions(assertions); + //Set edit element + field.setEditElement( + new DateTimeWithPrecisionVTwo(field, + VitroVocabulary.Precision.YEAR.uri(), + VitroVocabulary.Precision.NONE.uri())); + + fields.put(field.getName(), field); + + } + + /** + * Prepare edit configuration for update + * @param vreq + * @param session + * @param editConfiguration + */ + + private void prepareForUpdate(VitroRequest vreq, HttpSession session, EditConfigurationVTwo editConfiguration) { + //Here, retrieve model from + Model model = (Model) session.getServletContext().getAttribute("jenaOntModel"); + //Object property by definition + String objectUri = EditConfigurationUtils.getObjectUri(vreq); + if(objectUri != null) { + //update existing object + editConfiguration.prepareForObjPropUpdate(model); + } else { + //new object to be created + editConfiguration.prepareForNonUpdate( model ); + } + } + + + + + /** + * Methods that are REQUIRED to be implemented in subclasses + **/ + //role type will always be set based on particular form + abstract public String getRoleType(VitroRequest vreq); + //In the case of literal options, subclass generator will set the options to be returned + abstract protected HashMap getRoleActivityTypeLiteralOptions(VitroRequest vreq); + //Each subclass generator will return its own type of option here: + //whether literal hardcoded, based on class group, or subclasses of a specific class + //The latter two will apparently lend some kind of uri to objectClassUri ? + abstract public RoleActivityOptionTypes getRoleActivityTypeOptionsType(VitroRequest vreq); + //This too will depend on the specific subclass of generator + abstract public String getRoleActivityTypeObjectClassUri(VitroRequest vreq); + + /** + * Methods with default values that may be overwritten when required by a subclass + * Both Default value and method that can be overwritten are included below + **/ + + public boolean isShowRoleLabelField(VitroRequest vreq) { + return true; + } + + public String getActivityToRolePredicate(VitroRequest vreq) { + return getDefaultActivityToRolePredicate(); + } + + //This has a default value, but note that even that will not be used + //in the update with realized in or contributes to + //Overridden when need be in subclassed generator + public String getRoleToActivityPredicate(VitroRequest vreq) { + return getDefaultRoleToActivityPredicate(); + } + + //Some values will have a default value + //activityToRolePredicate + public String getDefaultActivityToRolePredicate() { + return "http://vivoweb.org/ontology/core#relatedRole"; + } + + //roleToActivityPredicate + public String getDefaultRoleToActivityPredicate() { + return "http://vivoweb.org/ontology/core#roleIn"; + + } + + /** + * Methods that check edit mode + */ + + //Get edit mode + private EditMode getEditMode(VitroRequest vreq) { + String roleToActivityPredicate = getRoleToActivityPredicate(vreq); + EditMode mode = FrontEndEditingUtils.getEditMode(vreq, roleToActivityPredicate); + return mode; + //(mode == EditMode.ADD || mode == EditMode.REPAIR) ? "\"nonempty\" + } + private boolean isAddMode(VitroRequest vreq) { + EditMode mode = getEditMode(vreq); + return (mode == EditMode.ADD); + } + + private boolean isEditMode(VitroRequest vreq) { + EditMode mode = getEditMode(vreq); + return (mode == EditMode.EDIT); + } + + private boolean isRepairMode(VitroRequest vreq) { + EditMode mode = getEditMode(vreq); + return (mode == EditMode.REPAIR); + } + + + /** + * Methods to return URIS for various predicates + **/ + public String getVivoCoreNamespace() { + return "http://vivoweb.org/ontology/core#"; + } + + public String getRoleToIntervalURI() { + return getVivoCoreNamespace() + "dateTimeInterval"; + } + + public String getIntervalTypeURI() { + return getVivoCoreNamespace() + "DateTimeInterval"; + } + + public String getIntervalToStartURI() { + return getVivoCoreNamespace() + "start"; + } + + public String getIntervalToEndURI() { + return getVivoCoreNamespace() + "end"; + } + + public String getStartYearPredURI() { + return getVivoCoreNamespace() + "startYear"; + } + + public String getEndYearPredURI() { + return getVivoCoreNamespace() + "endYear"; + } + + public String getDateTimeValueTypeURI() { + return getVivoCoreNamespace() + "DateTimeValue"; + } + + public String getDateTimePrecisionURI() { + return getVivoCoreNamespace() + "dateTimePrecision"; + } + + public String getDateTimeValueURI() { + return getVivoCoreNamespace() + "dateTime"; + } + + //Form specific data + public void addFormSpecificData(EditConfigurationVTwo editConfiguration, VitroRequest vreq) { + HashMap formSpecificData = new HashMap(); + formSpecificData.put("editMode", getEditMode(vreq).name()); + //Fields that will need select lists generated + //Store field names + List objectSelect = new ArrayList(); + objectSelect.add("roleActivityType"); + //TODO: Check if this is the proper way to do this? + formSpecificData.put("objectSelect", objectSelect); + //Put in the fact that we require field + editConfiguration.setFormSpecificData(formSpecificData); + } + +} 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 6ef2ddb61..85657e77b 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 @@ -141,7 +141,10 @@ public class EditRequestDispatchController extends FreemarkerHttpServlet { editConfGeneratorName = DEFAULT_DELETE_FORM; } // *** handle the case where the form is specified as a request parameter *** - else if( predicateUri == null && ( formParam != null && !formParam.isEmpty()) ){ + //TODO: Substitute the original line in again which checks for null predicate, currently overriding + //in order to test + //else if( predicateUri == null && ( formParam != null && !formParam.isEmpty()) ){ + else if( formParam != null && !formParam.isEmpty() ){ //form parameter must be a fully qualified java class name of a EditConfigurationVTwoGenerator implementation. editConfGeneratorName = formParam; } else if(isVitroLabel(predicateUri)) { //in case of data property @@ -212,7 +215,7 @@ public class EditRequestDispatchController extends FreemarkerHttpServlet { String subjectUri = EditConfigurationUtils.getSubjectUri(vreq); String predicateUri = EditConfigurationUtils.getPredicateUri(vreq); String formParam = getFormParam(vreq); - + //if no form parameter, then predicate uri and subject uri must both be populated if (formParam == null || "".equals(formParam)) { if ((predicateUri == null || predicateUri.trim().length() == 0)) { return true; @@ -225,7 +228,11 @@ public class EditRequestDispatchController extends FreemarkerHttpServlet { //Check predicate - if not vitro label and neither data prop nor object prop return error WebappDaoFactory wdf = vreq.getWebappDaoFactory(); - if(!EditConfigurationUtils.isObjectProperty(predicateUri, vreq) + //TODO: Check if any error conditions are not met here + //At this point, if there is a form paramter, we don't require a predicate uri + if(formParam == null + && predicateUri != null + && !EditConfigurationUtils.isObjectProperty(predicateUri, vreq) && !isVitroLabel(predicateUri) && !EditConfigurationUtils.isDataProperty(predicateUri, vreq)) { @@ -255,7 +262,7 @@ public class EditRequestDispatchController extends FreemarkerHttpServlet { //should return null private String getFormParam(VitroRequest vreq) { - String formParam = (String) vreq.getAttribute("editForm"); + String formParam = (String) vreq.getParameter("editForm"); return formParam; } 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 2487fb4d3..3eea60a28 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,9 +7,13 @@ 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.VTwo.FieldVTwo; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditElementVTwo; + 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.utils.FrontEndEditingUtils; +import edu.cornell.mannlib.vitro.webapp.utils.FrontEndEditingUtils.EditMode; import edu.cornell.mannlib.vitro.webapp.web.templatemodels.BaseTemplateModel; import java.io.UnsupportedEncodingException; @@ -22,6 +26,7 @@ import java.util.LinkedHashMap; import java.util.Map; import java.util.List; import java.util.ArrayList; +import java.util.Set; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; @@ -64,29 +69,57 @@ public class EditConfigurationTemplateModel extends BaseTemplateModel { public String getSubmitToUrl(){ return getUrl( editConfig.getSubmitToUrl() ); } - //TODO: Check whether to include additoinal data here or elsewhere - //For now, using attributes off of vitro request to add to template - //TODO: find better mechanism - //Calculate data here + + /* + * Used to calculate/retrieve/extract additional form-specific data + * Such as options for a drop-down etc. + */ + private void retrieveEditData() { //Get vitro request attributes for setFormTitle(); setSubmitLabel(); - //this should only be called if this is an object property form - //how would we do this? - if(EditConfigurationUtils.isObjectProperty(editConfig.getPredicateUri(), vreq)) { - setRangeOptions(); - } - //range data type probably not set here but for edit configuration's field - /* - if(EditConfigurationUtils.isDataProperty(editConfig.getPredicateUri(), vreq)) { - setRangeDatatype(); - }*/ - + //Get the form specific data + HashMap formSpecificData = editConfig.getFormSpecificData(); + pageData.putAll(formSpecificData); + populateDropdowns(); + //populate html with edit element where appropriate + populateGeneratedHtml(); } + //Based on certain pre-set fields/variables, look for what + //drop-downs need to be populated + private void populateDropdowns() { + if(EditConfigurationUtils.isObjectProperty(editConfig.getPredicateUri(), vreq)) { + setRangeOptions(); + } + if(pageData.containsKey("objectSelect")) { + List fieldNames = (List)pageData.get("objectSelect"); + for(String field:fieldNames) { + WebappDaoFactory wdf = vreq.getWebappDaoFactory(); + Map optionsMap = SelectListGeneratorVTwo.getOptions(editConfig, field , wdf); + pageData.put(field, optionsMap); + } + } + + } + + //TODO: Check if this should return a list instead + //Also check if better manipulated/handled within the freemarker form itself + private String getSelectedValue(String field) { + String selectedValue = null; + Map> urisInScope = editConfig.getUrisInScope(); + if(urisInScope.containsKey(field)) { + List values = urisInScope.get(field); + //Unsure how to deal with multi-select drop-downs + //TODO: Handle multiple select dropdowns + selectedValue = StringUtils.join(values, ","); + } + return selectedValue; + } + private boolean isRangeOptionsExist() { boolean rangeOptionsExist = (pageData.get("rangeOptionsExist") != null && (Boolean) pageData.get("rangeOptionsExist") == true); return rangeOptionsExist; @@ -189,9 +222,10 @@ public class EditConfigurationTemplateModel extends BaseTemplateModel { ObjectProperty prop = EditConfigurationUtils.getObjectProperty(vreq); if( prop.getSelectFromExisting() ){ WebappDaoFactory wdf = vreq.getWebappDaoFactory(); - - - Map rangeOptions = SelectListGeneratorVTwo.getOptions(editConfig, "objectVar" , wdf); + //TODO: Change this to varname for object from object property? + String fieldName = editConfig.getVarNameForObject(); + //TODO: Check if this still works? + Map rangeOptions = SelectListGeneratorVTwo.getOptions(editConfig, fieldName , wdf); if( rangeOptions != null && rangeOptions.size() > 0 ) { pageData.put("rangeOptionsExist", true); pageData.put("rangeOptions", rangeOptions); @@ -243,6 +277,7 @@ public class EditConfigurationTemplateModel extends BaseTemplateModel { return literalValues; } + //Check if possible to send in particular parameter public String dataLiteralValueFor(String dataLiteralName) { List literalValues = getLiteralStringValue(dataLiteralName); @@ -567,4 +602,40 @@ public class EditConfigurationTemplateModel extends BaseTemplateModel { return vitroNsProp; } + //Additional data to be returned + public HashMap getPageData() { + return pageData; + } + + //Literals in scope and uris in scope are the values + //that currently exist for any of the fields/values + + //Get literals in scope returned as string values + public Map> getExistingLiteralValues() { + return EditConfigurationUtils.getExistingLiteralValues(vreq, editConfig); + } + + public Map> getExistingUriValues() { + return editConfig.getUrisInScope(); + } + + //Get editElements with html + public void populateGeneratedHtml() { + Map generatedHtml = new HashMap(); + Map fieldMap = editConfig.getFields(); + //Check if any of the fields have edit elements and should be generated + Set keySet = fieldMap.keySet(); + for(String key: keySet) { + FieldVTwo field = fieldMap.get(key); + EditElementVTwo editElement = field.getEditElement(); + String fieldName = field.getName(); + if(editElement != null) { + generatedHtml.put(fieldName, EditConfigurationUtils.generateHTMLForElement(vreq, fieldName, editConfig)); + } + } + + //Put in pageData + pageData.put("htmlForElements", generatedHtml); + } + } diff --git a/webapp/web/templates/freemarker/edit/forms/addClinicalRoleToPerson.ftl b/webapp/web/templates/freemarker/edit/forms/addClinicalRoleToPerson.ftl new file mode 100644 index 000000000..4cfc12bd8 --- /dev/null +++ b/webapp/web/templates/freemarker/edit/forms/addClinicalRoleToPerson.ftl @@ -0,0 +1,7 @@ +<#--Assign property-specific variables here--> +<#assign roleDescriptor = "clinical activity" /> +<#assign typeSelectorLabel = "clinical activity type" /> + +<#--Can Also set buttonText for a given form-> +<#--Each of the two stage forms will include the form below--> +<#include "addRoleToPersonTwoStage.ftl"> \ No newline at end of file diff --git a/webapp/web/templates/freemarker/edit/forms/addRoleToPersonTwoStage.ftl b/webapp/web/templates/freemarker/edit/forms/addRoleToPersonTwoStage.ftl new file mode 100644 index 000000000..b18c81263 --- /dev/null +++ b/webapp/web/templates/freemarker/edit/forms/addRoleToPersonTwoStage.ftl @@ -0,0 +1,192 @@ +<#-- $This file is distributed under the terms of the license in /doc/license.txt$ --> + +<#--Retrieve certain edit configuration information--> +<#assign editMode = editConfiguration.pageData.editMode /> +<#assign literalValues = editConfiguration.existingLiteralValues /> +<#assign uriValues = editConfiguration.existingUriValues /> +<#assign htmlForElements = editConfiguration.pageData.htmlForElements /> + +Edit Mode is ${editMode} +<#--Freemarker variables with default values that can be overridden by specific forms--> + + +<#--buttonText, typeSelectorLabel, numDateFields, showRoleLabelField, roleExamples--> +<#if !buttonText?has_content> + <#assign buttonText = roleDescriptor /> + +<#if !typeSelectorLabel?has_content> + <#assign typeSelectorLabel = roleDescriptor /> + +<#if !numDateFields?has_content> + <#assign numDateFields = 2 /> + +<#if !showRoleLabelField?has_content> + <#assign showRoleLabelField = true /> + +<#if !roleExamples?has_content> + <#assign roleExamples = "" /> + + +<#--Setting values for titleVerb, submitButonText, and disabled Value--> +<#if editConfiguration.objectUri?has_content> + <#assign titleVerb = "Edit"/> + <#assign submitButtonText>Edit ${buttonText} + <#if editMode = "repair"> + <#assign disabledVal = ""/> + <#else> + <#assign disabledVal = "disabled"/> + +<#else> + <#assign titleVerb = "Create"/> + <#assign submitButtonText>${buttonText} + <#assign disabledVal = ""/> + <#--The original jsp sets editMode to add, why?--> + + +<#--Get existing value for specific data literals and uris--> + + +<#--Get selected activity type value if it exists, this is alternative to below--> +<#assign activityTypeValue = ""/> +<#if uriValues?keys?seq_contains("activityType") && uriValues.activityType?size > 0> + <#assign activityTypeValue = uriValues.activityType[0] /> + + + <#--Get activity label value--> +<#assign activityLabelValue = "" /> +<#if literalValues?keys?seq_contains("activityLabel") && literalValues.activityLabel?size > 0> + <#assign activityLabelValue = literalValues.activityLabel[0] /> + + +<#--Get role label--> +<#assign roleLabel = "" /> +<#if literalValues?keys?seq_contains("roleLabel") && literalValues.roleLabel?size > 0 > + <#assign roleLabel = literalValues.roleLabel[0] /> + + + +ActivityLabel:${activityLabelValue} +Activity type: ${activityTypeValue} + +

${titleVerb} ${roleDescriptor} entry for ${editConfiguration.subjectName}

+ +<#--Display error messages if any--> +<#if errorNameFieldIsEmpty??> + <#assign errorMessage = "Enter a name for the ." /> + + +<#if errorRoleFieldIsEmpty??> + <#assign errorMessage = "Specify a role for this ." /> + + +<#if errorMessage?has_content> + + + + +
+ +
+ +

+ +

+ + + +
+

+ + + disabled=${disabledVal} + + /> +

+ + <#if editMode = "edit"> + + + + +
+

+ + + (Verify this match) +

+ + +
+ + <#if showRoleLabelField = true> +

+ +

+ + + <#if numDateFields == 1 > + <#--Generated html is a map with key name mapping to html string--> + <#if htmlForElements?keys?seq_contains("startField")> + + ${htmlForElements["startField"]} + + <#else> +

Years of Participation in ${roleDescriptor?capitalize}

+ <#if htmlForElements?keys?seq_contains("startField")> + + ${htmlForElements["startField"]} + + <#if htmlForElements?keys?seq_contains("endField")> + + ${htmlForElements["endField"]} + + +
+ + or Cancel +

+ +

* required fields

+ + +<#--Specifying form-specific script and adding stylesheets and scripts--> + + + +${stylesheets.add('')} +${stylesheets.add('')} +${stylesheets.add('')} + +${scripts.add('')} +${scripts.add('')} +${scripts.add('')} + + +
\ No newline at end of file