package com.openMap1.mapper.mapping; import java.util.Iterator; import java.util.Vector; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EObject; import com.openMap1.mapper.core.MapperException; import com.openMap1.mapper.core.SortableRow; import com.openMap1.mapper.core.Xpth; import com.openMap1.mapper.AssocEndMapping; import com.openMap1.mapper.AssocMapping; import com.openMap1.mapper.ConversionImplementation; import com.openMap1.mapper.ElementDef; import com.openMap1.mapper.FixedPropertyValue; import com.openMap1.mapper.ImportMappingSet; import com.openMap1.mapper.JavaConversionImplementation; import com.openMap1.mapper.LocalPropertyConversion; import com.openMap1.mapper.Mapping; import com.openMap1.mapper.MappingCondition; import com.openMap1.mapper.ModelFilter; import com.openMap1.mapper.ModelFilterSet; import com.openMap1.mapper.MultiWay; import com.openMap1.mapper.ObjMapping; import com.openMap1.mapper.ParameterClassValue; import com.openMap1.mapper.PropMapping; import com.openMap1.mapper.ValuePair; import com.openMap1.mapper.XSLTConversionImplementation; /** * An instance of this class is a row in the Mappings View, consistent with the Open Mapping Language definition. * * There is one row for each: * - object mapping * - property mapping * - association end mapping * * There is no row for an association mapping. * @author robert * */ public class OpenMappingRow implements SortableRow{ protected Mapping mapping; public Mapping mapping() {return mapping;} protected ImportMappingSet importSet; public ImportMappingSet importSet() {return importSet;} protected boolean isImport; // core mapping columns public static int MAPTYPE = 0; public static int MAPPEDCLASS = 1; public static int FEATURE = 2; public static int XPATH = 3; public static int COMMENTS = 4; // extended mapping columns public static int CONDITION = 5; public static int KEY = 6; public static int FILTER = 7; public static int APEX = 8; public static int CONVERT_IN = 9; public static int CONVERT_OUT = 10; public static int MODULE = 11; public static int ALTERNATES = 12; public static String[] columnTitle = {"Type", "Class", "Feature","XPath","Comments", "Condition","Key","Filter","Apex", "Convert_In","Convert_Out","Module","Alternates"}; public static int[] columnWidth = {60,100,150,300,100, 200,100,100,200, 100,100,300,60}; /** * int constants STRING, NUMBER defined in SortableRow which define how * each column is to be sorted */ public static int[] sortType() { int len = columnTitle.length; int[] sType = new int[len]; for (int i = 0; i < len; i++) sType[i] = STRING; return sType; } //----------------------------------------------------------------------------- // constructor //----------------------------------------------------------------------------- /** * constructor for an object mapping, property mapping, * or association end mapping */ public OpenMappingRow(Mapping mapping){ this.mapping = mapping; isImport = false; } /** * constructor for a call or macro import of a mapping set */ public OpenMappingRow(ImportMappingSet importSet){ this.importSet = importSet; isImport = true; } public String cellContents(int colNumber) { if (colNumber == MAPTYPE) return mappingType(); if (colNumber == MAPPEDCLASS) return owningClassName(); if (colNumber == FEATURE) return featureName(); if (colNumber == XPATH) return path(); if (colNumber == COMMENTS) return comments(); if (colNumber == CONDITION) return condition(); if (colNumber == KEY) return key(); if (colNumber == FILTER) return filter(); if (colNumber == APEX) return apex(); if (colNumber == CONVERT_IN) return convert(true); if (colNumber == CONVERT_OUT) return convert(false); if (colNumber == MODULE) return module(); if (colNumber == ALTERNATES) return alternates(); return ""; } /** * for interface SortableRow */ public Vector<String> rowVector() { Vector<String> row = new Vector<String>(); for (int i = 0; i < columnTitle.length;i++) row.add(cellContents(i)); return row; } /** * @return true if this mapping is to be shown in the mappings view. * now true for association ends which are not navigable */ public boolean isShowable() { boolean showable = true; if (isImport) {} // import rows are always showable // never show association mappings else if (mapping instanceof AssocMapping) showable = false; // legacy code - fixed to return true else if (mapping instanceof AssocEndMapping) { showable = true; // now both association end mappings always show String role = ((AssocEndMapping)mapping).getMappedRole(); if ((role != null) && (!role.equals(""))) showable = true; } return showable; } //------------------------------------------------------------------------------------------ // Methods to compute column contents //------------------------------------------------------------------------------------------ /** * @return content of 'Type' column. Type is preceded by '*' if this mapping is a break */ private String mappingType() { String type = ""; // do not yet support macro import mapping sets if (isImport) type = "call"; // types of mappings else if (mapping instanceof ObjMapping) type = "object"; else if (mapping instanceof PropMapping) type = "attrib"; else if (mapping instanceof AssocEndMapping) type = "assoc"; if (isBreak()) type = "*" + type; return type; } /** * @return true if this mapping or its parent association mapping has a breakpoint; otherwise false */ private boolean isBreak() { boolean isBreak = false; if (isImport) {} else if (mapping.isBreakPoint()) isBreak = true; else if (mapping instanceof AssocEndMapping) { EObject parent = mapping.eContainer(); if ((parent instanceof Mapping) && (((Mapping)parent).isBreakPoint())) isBreak = true; } return isBreak; } /** * 'Class' column * @return name of the class owning this feature (or the mapped class) * with subset name in brackets if non-empty */ private String owningClassName() { String cName = ""; // for imports, define the class and subset if (isImport) { boolean foundOne = false; for (Iterator<ParameterClassValue> it = importSet.getParameterClassValues().iterator();it.hasNext();) { ParameterClassValue pcv = it.next(); if (foundOne) cName = cName + "; "; // should not occur as we now only allow one parameter class cName = cName + pcv.getMappedPackage() + "." + pcv.getMappedClass(); String subset = pcv.getSubset(); if (!subset.equals("")) cName = cName + "(" + subset + ")"; foundOne = true; } } else if (mapping instanceof ObjMapping) cName = mapping.labelClassName(); else if (mapping instanceof PropMapping) cName = mapping.labelClassName(); // for association end mappings, get the class which is target class of the other end mapping if (mapping instanceof AssocEndMapping) { AssocEndMapping aem = ((AssocEndMapping)mapping).otherEndMapping(); cName = aem.labelClassName(); } return cName; } /** * @return content of the 'Feature' column */ private String featureName() { String name = ""; if (isImport) {} else if (mapping instanceof ObjMapping) name = ""; else if (mapping instanceof PropMapping) name = ((PropMapping)mapping).getMappedProperty(); else if (mapping instanceof AssocEndMapping) { AssocEndMapping aem = (AssocEndMapping)mapping; String role = aem.getMappedRole(); // if there is no role, identify the other end mapping, to pair up the ends unambiguously if (role.equals("")) { AssocEndMapping opposite = aem.otherEndMapping(); role = "(-" + opposite.getMappedRole() + ")"; } name = role + "." + aem.getMappedClass(); if ((aem.getSubset() != null) && !(aem.getSubset().equals(""))) name = name + "(" + aem.getSubset() + ")"; } return name; } /** * @return content of the 'XPath' column */ private String path() { String path = ""; // for an Import Mapping set, get the XPath of the importing node if (isImport) { ElementDef importingEl = (ElementDef)importSet.eContainer(); path = importingEl.getPath(); } // for mappings, the XPath of the mapped node else { try {path = mapping.getStringRootPath();} catch(Exception ex) {path = ex.getMessage();System.out.println("Mapping row exception: " + path);} } return path; } /** * * @return content of the 'Comments' column */ private String comments() { String comments = ""; if (isImport) {} else comments = mapping.getDescription(); if (comments == null) comments = ""; // there were some nulls coming through, but now fixed in the mapper package return comments; } /** * * @return content of the 'Condition' column */ private String condition() { String conds = ""; if (isImport) {} else { boolean foundOne = false; for (Iterator<MappingCondition> it = mapping.getMappingConditions().iterator();it.hasNext();) { MappingCondition mc = it.next(); String cond = mc.getDetails(); if (foundOne) conds = conds + "; "; conds = conds + cond; foundOne = true; } } return conds; } /** * * @return content of the 'Filter' column */ private String filter() { String filter = ""; boolean foundOne = false; if (isImport) {} else if (mapping instanceof ObjMapping) { // filters representing fixed property values for (Iterator<FixedPropertyValue> it = ((ObjMapping)mapping).getFixedPropertyValues().iterator();it.hasNext();) { FixedPropertyValue fpv = it.next(); if (foundOne) filter = filter + "; "; filter = filter + fpv.getDetails(); foundOne = true; } // FIXME: filters from association mappings required for the object (harder to implement, so not yet done // filters which were stated as filters ModelFilterSet mfs = ((ObjMapping)mapping).getModelFilterSet(); if (mfs != null) { for (Iterator<ModelFilter> it = mfs.getModelFilters().iterator();it.hasNext();) { ModelFilter mf = it.next(); if (foundOne) filter = filter + "; "; filter = filter + mf.getFilterColumnText(); foundOne = true; } } } return filter; } /** * FIXME - keys for multiply represented objects are not yet in the mapper metamodel * @return content of the 'Key' column */ private String key() { String key = ""; if (isImport) {} else if (mapping instanceof ObjMapping) { ObjMapping om = (ObjMapping)mapping; if (om.isMultiplyRepresented()) { } } return key; } /** * temporary version which calculates the Apex from a cross-path. * For property mappings, this is the object-to-property path. * For association nodes, there is a choice of two paths: object to association, * or the reverse. They should have the same apex. * I arbitrarily choose object to association for this case * @return content of the 'Apex' column */ private String apex() { String apexPath = ""; if (isImport) {} else try { //check if any non-default cross path has been specified Xpth crossPath = null; if (mapping instanceof PropMapping) { PropMapping pm = (PropMapping)mapping; if (!pm.getObjectToPropertyPath().equals("")) crossPath = pm.getObjectToPropertyXPath(); } else if (mapping instanceof AssocEndMapping) { AssocEndMapping am = (AssocEndMapping)mapping; if (!am.getObjectToAssociationPath().equals("")) crossPath = am.getAssociationToObjectXPath(); } // if some cross path has been specified if (crossPath != null) { // find the node name for the apex step of the path (could it be 'node()'? No) String apexName = crossPath.step(crossPath.apexIndex()).nodeTest(); // in theory this path might be ambiguous if the node name repeats, but use it anyway apexPath = "//" + apexName; } } catch (MapperException ex) {} // don't fuss about XPath exceptions return apexPath; } /** * * @return content of the 'Convert_In' and 'Convert_Out' columns */ private String convert(boolean inOut) { String convert = ""; if (isImport) {} else if (mapping instanceof PropMapping) { PropMapping pm = (PropMapping)mapping; LocalPropertyConversion lpc = pm.getLocalPropertyConversion(); if (lpc != null) { boolean foundOne = false; EList<ConversionImplementation> ciList = null; if (inOut) ciList = lpc.getInConversionImplementations(); else ciList = lpc.getOutConversionImplementations(); if ((ciList != null) && (ciList.size() > 0)) { for (Iterator<ConversionImplementation> it = ciList.iterator();it.hasNext();) { ConversionImplementation ci = it.next(); if (foundOne) convert = convert + "; "; if (ci instanceof JavaConversionImplementation) { JavaConversionImplementation jci = (JavaConversionImplementation)ci; convert = convert + "Java " + jci.getPackageName() + "." + jci.getClassName() + "." + jci.getMethodName(); } else if (ci instanceof XSLTConversionImplementation) { XSLTConversionImplementation xci = (XSLTConversionImplementation)ci; convert = convert + "XSLT template " + xci.getTemplateName() + " at " + xci.getTemplateFileURI(); } foundOne = true; } } // if no conversions have been found, look for a local table of value pairs else if (inOut) { EList<ValuePair> vpl = lpc.getValuePairs(); if ((vpl != null) && (vpl.size() > 0)) for (Iterator<ValuePair> ip = vpl.iterator();ip.hasNext();) { ValuePair vp = ip.next(); if (foundOne) convert = convert + ", "; convert = convert + "[" + vp.getStructureValue() + "," + vp.getModelValue() + "]"; foundOne = true; } } } } return convert; } /** * @return content of the 'Module' column */ private String module() { String module = ""; if (isImport) { module = importSet.getMappingSetURI(); } return module; } /** * @return content of the 'Alternates' column */ private String alternates() { String alternates = ""; if (isImport) {} else { if (mapping.getMultiWay() == MultiWay.REDUNDANT) alternates = "all"; if (mapping.getMultiWay() == MultiWay.CHOICE) alternates = "some"; } return alternates; } }