package com.openMap1.mapper.mapping; import com.openMap1.mapper.core.MapperException; import com.openMap1.mapper.core.Xpth; import com.openMap1.mapper.util.messageChannel; import com.openMap1.mapper.util.ModelUtil; import com.openMap1.mapper.ConversionImplementation; import com.openMap1.mapper.ConversionSense; import com.openMap1.mapper.FixedPropertyValue; import com.openMap1.mapper.JavaConversionImplementation; import com.openMap1.mapper.LocalPropertyConversion; import com.openMap1.mapper.ObjMapping; import com.openMap1.mapper.PropMapping; import com.openMap1.mapper.ValuePair; import java.util.*; /** * A property mapping - describes how a property of object in some class is represented in XML * * @author Robert Worden * @version 1.0 */ public class propertyMapping extends MappingTwo { public PropMapping pMap() {return (PropMapping)map();} private FixedPropertyValue fixedPropertyValue = null; // only reset for fixed property mappings public FixedPropertyValue fixedPropertyValue() {return fixedPropertyValue;} private String propertyName; // property represented private Xpth objectToProperty; // path from object-rep node to property-rep node private String type; // type of property (as in XML Schema?) private boolean fixed; // true if this is a property with a fixed value private String value; // the fixed value private boolean hasDefault = false; // true if there is a default value for the property private String defaultValue; // the default value /* whether or not the property is optional in the object model. This is not defined in MDL, but in the class model; and is only set when validating the MDL, in check 3. */ private boolean optional; /* property optionality as defined in the MDL. This is either undefined (value '') or 'no' - i.e the MDL can only make the property more constrained, than either the object model or the XML structure would imply. It cannot make it less constrained. */ private String optionalFromMDL = ""; /** * @return a non-null property conversion, if this property has a local conversion with a Java implementation */ public propertyConversion localInConversion() {return localInConversion;} private propertyConversion localInConversion = null; /** * @return a non-null property conversion, if this property has a local conversion with a Java implementation */ public propertyConversion localOutConversion() {return localOutConversion;} private propertyConversion localOutConversion = null; /* * @return true if this property has a conversion defined as a lookup table of values */ public boolean hasLookupTable() {return hasLookupTable;} private boolean hasLookupTable = false; // key = XML value; value = model value private Hashtable<String,String> inLookupTable = new Hashtable<String,String>(); // key = model value; value = XML value private Hashtable<String,String> outLookupTable = new Hashtable<String,String>(); /** the name of the property */ public String propertyName() {return propertyName;} /** path from object-rep node to property-rep node */ public Xpth objectToProperty() {return objectToProperty;} /** type of property (as in XML Schema?) */ public String type() {return type;} /** true if this is a property with a fixed value */ public boolean fixed() {return fixed;} /** the fixed value, if the property has one */ public String value() {return value;} /** whether or not the property is optional in the object model. This is not defined in MDL, but in the class model; and is only set when validating the MDL, in check 3. */ public boolean optional() {return optional;} /** property optionality as defined in the MDL. This is either undefined (value '') or 'no' - i.e the MDL can only make the property more constrained, than either the object model or the XML structure would imply. It cannot make it less constrained. */ public String optionalFromMDL() {return optionalFromMDL;} /** true if the property has a default value (in the object model instance, if not defined in the XML) */ public boolean hasDefault() {return hasDefault;} /** the default value of the property in the object model, if it has one */ public String defaultValue() {return defaultValue;} /** set the path from object-rep node to property-rep node */ public void setObjectToProperty(Xpth p) {objectToProperty = p;} /** make the property optional or not in the object model */ public void setOptional(boolean b) {optional = b;} /** * constructor for non-fixed property mappings * * @param md messageChannel: for writing messages */ public propertyMapping(PropMapping pMap, messageChannel md) throws MapperException { super(pMap, md); mappingType = MappingTwo.PROPERTY; propertyName = pMap().getMappedProperty(); type = pMap().getPropertyType(); fixed = false; optional = true; // default until known otherwise, when validating defaultValue = pMap().getDefaultValue(); hasDefault = ((defaultValue != null) && !(defaultValue.equals(""))); objectToProperty = pMap().getObjectToPropertyXPath(); setLocalConversions(); } /** * constructor for fixed values * * @param md messageChanel: the set of in-memory mappings * @param xp Xpth: path to the node mapped * @param cc classSet: class name and subset * @param pn String: the property name * @param t String: property type * @param v String: the fixed value */ public propertyMapping(FixedPropertyValue fixedPropertyValue, messageChannel md) throws MapperException { super((ObjMapping)fixedPropertyValue.eContainer(),md); mappingType = MappingTwo.PROPERTY; this.fixedPropertyValue = fixedPropertyValue; propertyName = fixedPropertyValue.getMappedProperty(); type = fixedPropertyValue.getValueType(); fixed = true; value = fixedPropertyValue.getFixedValue(); optional = false; // 'self()' path from object node to property node objectToProperty = new Xpth(ModelUtil.getGlobalNamespaceSet(fixedPropertyValue),"."); } /** the full name is 'class(subset):property' */ public String fullName() {return (className() + "(" + subset() + "):" + propertyName);} /** write a text message describing the property mapping */ public void write() { mChan().message(""); mChan().message("Property mapping of " + fullName() + " to node " + nodePath().stringForm()); writeConditions(); } /** XPaths to nodes required to evaluate link conditions for this representation */ public Vector<Xpth> linkConditionPaths() { int i; Vector<Xpth> res = new Vector<Xpth>(); for (i = 0; i < linkConditions().size(); i++) { res.addElement(linkConditions().elementAt(i).rootToLeftValue()); res.addElement(linkConditions().elementAt(i).rootToRightValue()); } return res; } /** brief string description */ public String description() { return("mapping for property '" + className() + "." + propertyName); } //-------------------------------------------------------------------------------------------------- // Initialising local property conversions //-------------------------------------------------------------------------------------------------- private void setLocalConversions() { boolean inFound = false; boolean outFound = false; LocalPropertyConversion localPropertyConversion = pMap().getLocalPropertyConversion(); if (localPropertyConversion != null) { // find the one Java implementation of the in-conversion, if it exists for (Iterator<ConversionImplementation> ic = localPropertyConversion.getInConversionImplementations().iterator(); ic.hasNext();) { ConversionImplementation ci = ic.next(); // take the first Java in conversion as defining the conversion; there should not be more than one if ((ci instanceof JavaConversionImplementation) && !inFound) { inFound = true; localInConversion = new propertyConversion(this,(JavaConversionImplementation)ci,ConversionSense.IN); } } // find the one Java implementation of the out-conversion, if it exists for (Iterator<ConversionImplementation> ic = localPropertyConversion.getOutConversionImplementations().iterator(); ic.hasNext();) { ConversionImplementation ci = ic.next(); // take the first Java in conversion as defining the conversion; there should not be more than one if ((ci instanceof JavaConversionImplementation) && !outFound) { outFound = true; localOutConversion = new propertyConversion(this,(JavaConversionImplementation)ci,ConversionSense.OUT); } } // lookup table values are ignored if there are any local Java conversion implementations if (!inFound && !outFound && (localPropertyConversion.getValuePairs().size()> 0)) { hasLookupTable = true; for (Iterator<ValuePair> ip = localPropertyConversion.getValuePairs().iterator();ip.hasNext();) { ValuePair vp = ip.next(); String inValue = vp.getModelValue(); String outValue = vp.getStructureValue(); String prevInValue = inLookupTable.get(outValue); String prevOutValue = outLookupTable.get(inValue); /* if there is more than one in value given for any out value, * select one of the preferred in values (there should be only one) */ if ((prevInValue == null)|(vp.isPreferredIn())) inLookupTable.put(outValue, inValue); /* if there is more than one out value given for any in value, * select one of the preferred out values (there should be only one) */ if ((prevOutValue == null)|(vp.isPreferredOut())) outLookupTable.put(inValue,outValue); } } } } /** * look up a value from the XML structure in the lookup table * to find the model value. * If there is no entry in the table, pass the structure value through * @param structureValue * @return value converted to the model value by the lookup table */ public String getModelValue(String structureValue) { String tableValue = inLookupTable.get(structureValue); if (tableValue == null) tableValue = structureValue; return tableValue; } /** * look up a value from the model in the lookup table * to find the XML structure value * If there is no entry in the table, pass the model value through * @param modelValue * @return value converted to the structure value by the lookup table */ public String getStructureValue(String modelValue) { String tableValue = outLookupTable.get(modelValue); if (tableValue == null) tableValue = modelValue; return tableValue; } }