package gr.ntua.ivml.mint.mapping; import gr.ntua.ivml.mint.db.DB; import gr.ntua.ivml.mint.persistent.DataUpload; import gr.ntua.ivml.mint.persistent.Mapping; import gr.ntua.ivml.mint.persistent.XmlSchema; import gr.ntua.ivml.mint.persistent.XpathHolder; import gr.ntua.ivml.mint.xsd.SchemaValidator; import gr.ntua.ivml.mint.xsd.XSDParser; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.StringWriter; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import javax.xml.transform.stream.StreamSource; import org.apache.log4j.Logger; import net.sf.json.JSONArray; import net.sf.json.JSONObject; import net.sf.json.JSONSerializer; public class MappingManager { protected static final Logger log = Logger.getLogger( MappingManager.class); protected XSDParser xsdParser; String dataUploadId = null; String mappingId = null; Mapping mapping = null; protected Schema inputSchema; protected XmlSchema outputSchema; File targetDefinitionFile = null; String inputFileName = "input.xml"; JSONObject targetDefinition = null; JSONObject targetConfiguration = null; public JSONObject getConfiguration() { return this.targetConfiguration; } JSONObject templateCache = null; HashMap<String, JSONObject> elementCache = new HashMap<String, JSONObject>(); HashMap<String, JSONObject> parentCache = new HashMap<String, JSONObject>(); HashMap<String, JSONObject> groupsCache = new HashMap<String, JSONObject>(); JSONObject documentation = null; protected String getDocumentationForKey(String key) { if(documentation == null) { documentation = (JSONObject) JSONSerializer.toJSON(outputSchema.getDocumentation()); } String result = null; if(documentation.has(key)) { result = documentation.getString(key); // TODO: this could result in bugs, remove if documentation is rebuild in all deployed applications. } else if(key.contains(":")){ String[] parts = key.split(":"); if(parts.length > 1 && documentation.has(parts[1])) { result = documentation.getString(parts[1]); } } if(result == null) { result = "No documentation for '" + key + "'"; } return result; } DataUpload dataUpload = null; public MappingManager() { } public XSDParser getXSDParser() { if(this.xsdParser == null) { String schemaFileName = targetDefinitionFile.getParent() + "/" + targetDefinition.getString("xsd"); this.xsdParser = new XSDParser(schemaFileName); } return this.xsdParser; } public void init(String uploadId, String mId, String output) { this.dataUploadId = uploadId; this.mappingId = mId; this.templateCache = null; this.groupsCache.clear(); this.elementCache.clear(); this.parentCache.clear(); log.debug("read input schema from dataUpload: " + this.dataUploadId); this.setInputSchema(this.dataUploadId); log.debug("read target definition: " + output); targetDefinitionFile = new File(output); if(targetDefinitionFile != null) { this.inputFileName = targetDefinitionFile.getParent() + "/input.xml"; } if(this.dataUpload != null) { String savedMappings = null; log.debug("get mapping object: " + mappingId); this.mapping = DB.getMappingDAO().getById(Long.parseLong(mappingId), false); this.outputSchema = this.mapping.getTargetSchema(); if(mapping != null) { log.debug("get saved mappings"); savedMappings = this.mapping.getJsonString(); targetConfiguration = (JSONObject) JSONSerializer.toJSON(this.mapping.getTargetSchema().getJsonConfig()); } else { log.error("mapping object is null"); } log.debug("savedMappings: " + savedMappings); if(savedMappings != null) { targetDefinition = (JSONObject) JSONSerializer.toJSON(savedMappings); // check mapping version, if older then convert to newer version /* if(!MappingVersionControl.checkVersion(targetDefinition)) { String version = "-"; if(targetDefinition.has("version")) { version = targetDefinition.getString("version"); } log.debug("Mapping definition version: " + version + " != " + MappingVersionControl.CURRENT_VERSION + " (current). Mapping will be converted"); targetDefinition = MappingVersionControl.convertToCurrent(targetDefinition); } */ // cache groups JSONArray groups = targetDefinition.getJSONArray("groups"); Iterator i = groups.iterator(); while(i.hasNext()) { JSONObject group = (JSONObject) i.next(); JSONObject contents = group.getJSONObject("contents"); String element = group.getString("element"); this.groupsCache.put(element, contents); this.cacheElements(contents); } } else { targetDefinition = (JSONObject) JSONSerializer.toJSON(this.outputSchema.getJsonTemplate()); // initialise namespaces if(this.targetDefinition.has("namespaces")) { JSONObject object = this.targetDefinition.getJSONObject("namespaces"); HashMap<String, String> map = new HashMap<String, String>(); for(Object entry : object.keySet()) { String key = (String) entry; String value = object.getString(key); map.put(value, key); } this.getXSDParser().setNamespaces(map); } // initialise mapping definition this.targetDefinition = this.getTargetDefinition(); // set namespaces JSONObject namespaces = new JSONObject(); this.dataUpload = DB.getDataUploadDAO().getById(Long.parseLong(this.dataUploadId), false); XpathHolder xp = this.dataUpload.getRootXpath(); // dataupload namespaces Map<String, String> map = xp.getNamespaces(true); for(Entry<String, String> entry: map.entrySet()) { String key = entry.getKey(); String value = entry.getValue(); // key is the xpath, value is the prefix namespaces = namespaces.element(value, key); } // xsd schema namespaces Map<String, String> acc = this.getXSDParser().getNamespaces(); for(Entry<String, String> entry: acc.entrySet()) { String key = entry.getKey(); String value = entry.getValue(); namespaces = namespaces.element(value, key); } this.targetDefinition = this.targetDefinition.element("namespaces", namespaces); // override to customize mapping generation this.initCustomMappingContent(); } // cache template JSONObject template = null; if(!this.targetDefinition.has("template") || this.targetDefinition.getJSONObject("template").isEmpty()) { template = this.buildTemplate(this.targetDefinition.getJSONObject("item").getString("element")); this.targetDefinition = this.targetDefinition.element("template", template); } else { template = targetDefinition.getJSONObject("template"); } this.templateCache = template; this.cacheElements(this.templateCache); //this.saveMappings(); } } public void setArrayFixed(JSONArray array, boolean fixed) { Iterator i = array.iterator(); while(i.hasNext()) { JSONObject object = (JSONObject) i.next(); object = this.setFixedRecursive(object, fixed); } } public JSONObject setFixed(JSONObject object, boolean fixed) { if(fixed) { if(!object.has("fixed")) { object = object.element("fixed", ""); } } else { if(object.has("fixed")) { object.remove("fixed"); } } return object; } public JSONObject setFixedRecursive(JSONObject object, boolean fixed) { this.setFixed(object, fixed); if(object.has("attributes")) { this.setArrayFixed(object.getJSONArray("attributes"), fixed); } if(object.has("children")) { this.setArrayFixed(object.getJSONArray("children"), fixed); } return object; } protected void initCustomMappingContent() { } public JSONObject getElementDescription(String element) { //log.debug("requested element description: " + element); if(this.groupsCache.containsKey(element)) { // log.debug("Reading JSON Object " + element + " from cache!"); return groupsCache.get(element); } else { JSONObject result = this.getXSDParser().getRootElementDescription(element); this.groupsCache.put(element, result); this.cacheElements(result); return this.groupsCache.get(element); } } protected void cacheElements(JSONObject object) { String id = this.generateUniqueId(); object.put("id", id); this.elementCache.put(id, object); if(object.has("attributes")) { JSONArray attributes = object.getJSONArray("attributes"); for(int i = 0; i < attributes.size(); i++) { JSONObject a = (JSONObject) attributes.get(i); this.cacheElements(a); this.parentCache.put(a.getString("id"), object); } } if(object.has("children")) { JSONArray children = object.getJSONArray("children"); for(int i = 0; i < children.size(); i++) { JSONObject a = (JSONObject) children.get(i); this.cacheElements(a); this.parentCache.put(a.getString("id"), object); } } } private int elementid = 0; protected String generateUniqueId() { elementid++; return "" + elementid; } public JSONObject getTargetDefinition() { JSONArray groups = this.targetDefinition.getJSONArray("groups"); Iterator i = groups.iterator(); while(i.hasNext()) { JSONObject item = (JSONObject) i.next(); String element = item.getString("element"); item.put("contents", this.getElementDescription(element)); } if(!this.targetDefinition.has("template") || this.targetDefinition.getJSONObject("template").isEmpty()) { JSONObject template = this.buildTemplate(this.targetDefinition.getJSONObject("item").getString("element")); this.templateCache = template; this.cacheElements(this.templateCache); } this.targetDefinition.put("template", this.templateCache); return this.targetDefinition; } protected JSONObject buildTemplate(String root) { log.debug("building template element: " + root); JSONArray groups = this.targetDefinition.getJSONArray("groups"); return this.getXSDParser().buildTemplate(groups, root); } /* public Schema getOutputSchema() { return outputSchema; } public void setOutputSchema(String outputSchema) { if(outputSchema == null) { this.outputSchema = null; return; } this.outputSchema = new Schema("2"); this.outputSchema.initFromFile(outputSchema); } */ public Schema getInputSchema() { return inputSchema; } public void setInputSchema(String uploadId) { if(uploadId == null) { this.inputSchema = null; return; } this.dataUpload = DB.getDataUploadDAO().findById(Long.parseLong(uploadId), false); this.inputSchema = new Schema("1"); this.inputSchema.initFromUpload(this.dataUpload); } //for item/label set tooltip public void setDataUploadId(String uploadId){ this.dataUploadId=uploadId; } public String getItemLevelElementTooltip(String element) { StringBuffer out = new StringBuffer(); MappingElement input = this.inputSchema.getMappingElement(element); XpathHolder xp = input.getXPathHolder(); if(xp != null) { StringWriter writer = new StringWriter(); String prefix = xp.getUriPrefix(); long count = 0; long dcount = 0; count = input.getXPathHolder().getCount(); dcount = input.getXPathHolder().getDistinctCount(); out.append("<table width='100%' class='tooltipTable'>"); out.append("<tr><td><b>Namespace:</b></td><td style='padding-x: 5px'>" + prefix + "</td></tr>"); out.append("<tr><td><b>Name:</b></td><td style='padding-x: 5px'>" + input.getName() + "</td></tr>"); out.append("<tr><td><b>Count:</b></td><td style='padding-x: 5px'>" + count + "</td></tr>"); out.append("<tr><td><b>Distinct Count:</b></td><td style='padding-x: 5px'>" + dcount + "</td></tr>"); out.append("<tr><td colspan='2'><b>Example:</b></td></tr>"); out.append("<tr><td colspan='2' style=\"width: 100%\">"); DB.getSession().refresh(this.dataUpload); out.append("<div style=\"width: 100%; overflow-y: auto\" id=\"exampleTableContainer\">"); out.append("<table id=\"exampleTable\">"); out.append("<thead>"); out.append("<tr>"); out.append("<th>Value</th>"); out.append("<th>Frequency</th>"); out.append("</tr>"); out.append("</thead>"); out.append("<tbody>"); if (xp.getTextNode() != null) xp = xp.getTextNode(); if (xp.isAttributeNode() || xp.isTextNode()) { List<Object[]> elements = xp.getCountByValue(30); if(elements.isEmpty()) { out.append("<tr><td></td><td><i>This element has no values.</i></td></tr>"); } else { for (Object[] oa : elements) { String value = (String) oa[0]; Long valueCount = (Long) oa[1]; out.append( "<tr>" ); out.append( "<td> " + value + "</td>" ); out.append( "<td> " + valueCount + "</td>" ); out.append( "</tr>" ); } } } out.append("</tbody>"); out.append("</table>"); out.append("</div>"); out.append("</td></tr>"); //changed to work with new stats out.append("<tr><td colspan='2'><a href=\"#\" onclick=\"javascript:window.open('Stats.action?uploadId=" + this.dataUploadId + "','mywin','left=20,top=20,width=1024,height=510,toolbar=0,resizable=1');\">Statistics page</a></td></tr>"); out.append("</table>"); } else { out.append("<b>Error</b>: Node name " + element + " not found"); } return out.toString(); } public String getElementTooltip(String element) { StringBuffer out = new StringBuffer(); MappingElement input = this.inputSchema.getMappingElement(element); XpathHolder xp = input.getXPathHolder(); if(xp != null) { StringWriter writer = new StringWriter(); String prefix = xp.getUriPrefix(); long count = 0; long dcount = 0; count = input.getXPathHolder().getCount(); dcount = input.getXPathHolder().getDistinctCount(); // start tab code out.append("<div id=\"tooltipTabs\" class=\"yui-navset\">"); out.append("<ul class=\"yui-nav\">"); out.append("<li class=\"selected\"><a href=\"#tab1\"><em>Values</em></a></li>"); out.append("<li><a href=\"#tab2\"><em>Mapping</em></a></li>"); out.append("</ul>"); out.append("<div class=\"yui-content\">"); // start table html code out.append("<div><p><div style=\"width: 100%; height: 400px; overflow-x: auto; overflow-y: auto\">"); out.append("<div style=\"width: 100%; overflow-y: auto\" id=\"valuesTableInfoContainer\">"); out.append("<table width='100%' class='tooltipTable'>"); out.append("<tr><td><b>Namespace:</b></td><td style='padding-x: 5px'>" + prefix + "</td></tr>"); out.append("<tr><td><b>Name:</b></td><td style='padding-x: 5px'>" + input.getName() + "</td></tr>"); out.append("<tr><td><b>Count:</b></td><td style='padding-x: 5px'>" + count + "</td></tr>"); out.append("<tr><td><b>Distinct Count:</b></td><td style='padding-x: 5px'>" + dcount + "</td></tr>"); out.append("<tr><td colspan='2'><b>Example:</b></td></tr>"); out.append("<tr><td colspan='2' style=\"width: 100%\">"); DB.getSession().refresh(this.dataUpload); out.append("<div style=\"width: 100%; overflow-y: auto\" id=\"valuesTableContainer\">"); out.append("<table id=\"valuesTable\">"); out.append("<thead>"); out.append("<tr>"); out.append("<th>Value</th>"); out.append("<th>Frequency</th>"); out.append("</tr>"); out.append("</thead>"); out.append("<tbody>"); if (xp.getTextNode() != null) xp = xp.getTextNode(); if (xp.isAttributeNode() || xp.isTextNode()) { List<Object[]> elements = xp.getCountByValue(30); if(elements.isEmpty()) { out.append("<tr><td></td><td><i>This element has no values.</i></td></tr>"); } else { for (Object[] oa : elements) { String value = (String) oa[0]; Long valueCount = (Long) oa[1]; out.append( "<tr>" ); out.append( "<td> " + value + "</td>" ); out.append( "<td> " + valueCount + "</td>" ); out.append( "</tr>" ); } } } out.append("</tbody>"); out.append("</table>"); out.append("</div>"); out.append("</td></tr>"); //changed to work with new stats out.append("<tr><td colspan='2'><a href=\"#\" onclick=\"javascript:window.open('Stats.action?uploadId=" + this.dataUploadId + "','mywin','left=20,top=20,width=1024,height=510,toolbar=0,resizable=1');\">Statistics page</a></td></tr>"); out.append("</table>"); out.append("</div>"); out.append("</div></p></div>"); // end table html code // start mapping html code out.append("<div><p><div style=\"width: 100%; height: 400px; overflow-x: auto; overflow-y: auto\">"); out.append("<div style=\"width: 100%; overflow-y: auto\" id=\"mappingInfoContainer\">"); out.append("<table width='100%' class='tooltipTable'>"); // out.append("<tr><td><b>Namespace:</b></td><td style='padding-x: 5px'>" + prefix + "</td></tr>"); // out.append("<tr><td><b>Name:</b></td><td style='padding-x: 5px'>" + input.getName() + "</td></tr>"); // out.append("<tr><td><b>Count:</b></td><td style='padding-x: 5px'>" + count + "</td></tr>"); // out.append("<tr><td><b>Distinct Count:</b></td><td style='padding-x: 5px'>" + dcount + "</td></tr>"); // out.append("<tr><td colspan='2'><b>Example:</b></td></tr>"); out.append("<tr><td colspan='2' style=\"width: 100%\">"); DB.getSession().refresh(this.dataUpload); out.append("<div style=\"width: 100%; overflow-y: auto\" id=\"mappingInfoTableContainer\">"); out.append("<table id=\"mappingInfoTable\">"); out.append("<thead>"); out.append("<tr>"); out.append("<th>XPath</th>"); out.append("</tr>"); out.append("</thead>"); out.append("<tbody>"); Collection<String> mappings = MappingSummary.mappingsWithXPath(this.getTargetDefinition(), input.getXPathHolder().getXpathWithPrefix(true)); Iterator<String> it = mappings.iterator(); if(!it.hasNext()) { out.append("<tr><td><i>This element is not used in any mapping.</i></td></tr>"); } else { while(it.hasNext()) { String value = it.next(); out.append( "<tr>" ); out.append( "<td> " + value + "</td>" ); out.append( "</tr>" ); } } out.append("</tbody>"); out.append("</table>"); out.append("</div>"); out.append("</td></tr>"); //changed to work with new stats out.append("<tr><td colspan='2'><a href=\"#\" onclick=\"javascript:window.open('Stats.action?uploadId=" + this.dataUploadId + "','mywin','left=20,top=20,width=1024,height=510,toolbar=0,resizable=1');\">Statistics page</a></td></tr>"); out.append("</table>"); out.append("</div>"); out.append("</div></p></div>"); // end table html code // end mapping html code out.append("</div>"); out.append("</div>"); // end tab code } else { out.append("<b>Error</b>: Node name " + element + " not found"); } return out.toString(); } public JSONObject setXPathMapping(String source, String target, int index) { MappingElement sourceElement = this.inputSchema.getMappingElement(source); JSONObject targetElement = this.elementCache.get(target); String xpath = sourceElement.getXPath(); setXPathMapping(xpath, targetElement, index); saveMappings(); return targetElement; } public void setXPathMapping(String xpath, JSONObject target, int index) { JSONArray mappings = target.getJSONArray("mappings"); JSONObject mapping = null; if(index > -1) { mapping = mappings.getJSONObject(index); mapping.put("type", "xpath"); mapping.put("value", xpath); } else { mapping = new JSONObject(); mapping.put("type", "xpath"); mapping.put("value", xpath); mappings.add(mapping); } if(mapping != null) { } //mappings.clear(); } public JSONObject setXPathFunction(String id, int index, String data) { JSONObject target = this.elementCache.get(id); JSONArray mappings = target.getJSONArray("mappings"); JSONObject mapping = null; JSONObject function = (JSONObject) JSONSerializer.toJSON(data); if(index > -1) { mapping = mappings.getJSONObject(index); mapping.put("func", function); } saveMappings(); return target; } public JSONObject clearXPathFunction(String id, int index) { JSONObject target = this.elementCache.get(id); JSONArray mappings = target.getJSONArray("mappings"); JSONObject mapping = null; if(index > -1) { mapping = mappings.getJSONObject(index); mapping.remove("func"); } saveMappings(); return target; } public JSONObject setValueMapping(String input, String output, String target, int index) { JSONObject targetElement = this.elementCache.get(target); setValueMapping(input, output, targetElement, index); saveMappings(); return targetElement; } public JSONObject removeValueMapping(String input, String target, int index) { JSONObject targetElement = this.elementCache.get(target); removeValueMapping(input, targetElement, index); saveMappings(); return targetElement; } public void setValueMapping(String input, String output, JSONObject target, int index) { JSONArray mappings = target.getJSONArray("mappings"); JSONObject mapping = null; if(index > -1) { mapping = mappings.getJSONObject(index); if(!mapping.has("valuemap")) { mapping.element("valuemap", new JSONArray()); } JSONArray valuemap = mapping.getJSONArray("valuemap"); JSONObject map = null; Iterator i = valuemap.iterator(); while(i.hasNext()) { JSONObject m = (JSONObject) i.next(); if(m.getString("input").equals(input)) { map = m; break; } } if(map == null) { map = new JSONObject().element("input", input).element("output", output); valuemap.add(map); } else { map.put("output", output); } } } public void removeValueMapping(String input, JSONObject target, int index) { JSONArray mappings = target.getJSONArray("mappings"); JSONObject mapping = null; if(index > -1) { mapping = mappings.getJSONObject(index); if(mapping.has("valuemap")) { JSONArray valuemap = mapping.getJSONArray("valuemap"); JSONObject map = null; Iterator i = valuemap.iterator(); while(i.hasNext()) { JSONObject m = (JSONObject) i.next(); if(m.getString("input").equals(input)) { map = m; break; } } if(map != null) { valuemap.remove(map); } } } } private JSONArray generateValueMappingsTable(String xpath, JSONArray enumerations) { JSONArray result = new JSONArray(); ArrayList<String> values = new ArrayList<String>(); // get xpath values from import //MappingElement input = this.inputSchema.getMappingElement(xpath); //XpathHolder xp = input.getXPathHolder(); //values = xp.getValues(); // populate list and assign identical enumeration values for(String v: values) { JSONObject m = new JSONObject(); m.element("key", v); Iterator i = enumerations.iterator(); while(i.hasNext()) { String e = (String) i.next(); if(v.compareToIgnoreCase(e) == 0) { m.element("value", e); } } result.add(m); } return result; } public JSONObject setConstantValueMapping(String target, String value, int index) { JSONObject targetElement = this.elementCache.get(target); if(targetElement == null) { System.out.println("*** Could not find " + targetElement + " in element cache!"); } setConstantValueMapping(targetElement, value, index); saveMappings(); return targetElement; } public JSONObject setEnumerationValueMapping(String target, String value) { JSONObject targetElement = this.elementCache.get(target); if(targetElement == null) { System.out.println("*** Could not find " + targetElement + " in element cache!"); } setEnumerationValueMapping(targetElement, value); saveMappings(); return targetElement; } public void setConstantValueMapping(JSONObject target, String value, int index) { JSONArray mappings = target.getJSONArray("mappings"); JSONObject mapping = null; if(index > -1) { mapping = mappings.getJSONObject(index); mapping.put("type", "constant"); mapping.put("value", value); } else { mapping = new JSONObject(); mapping.put("type", "constant"); mapping.put("value", value); mappings.add(mapping); } } public void setEnumerationValueMapping(JSONObject target, String value) { JSONArray mappings = target.getJSONArray("mappings"); JSONObject mapping = null; mappings.clear(); if(value != null && value.length() > 0) { mapping = new JSONObject(); mapping.put("type", "constant"); mapping.put("value", value); mappings.add(mapping); } } public JSONObject addCondition(String target, int depth) { JSONObject targetElement = this.elementCache.get(target); if(depth == 0) { JSONObject condition = new JSONObject().element("xpath", "").element("value", ""); JSONObject elseMapping = duplicateJSONObject(targetElement); condition = condition.element("elseMapping", elseMapping); targetElement.put("condition", condition); saveMappings(); } else { } return targetElement; } public JSONObject removeCondition(String target, int depth) { JSONObject targetElement = this.elementCache.get(target); if(depth == 0) { targetElement.remove("condition"); saveMappings(); } else { } return targetElement; } public JSONObject setConditionXPath(String target, String value) { JSONObject targetElement = this.elementCache.get(target); MappingElement sourceElement = this.inputSchema.getMappingElement(value); String xpath = sourceElement.getXPath(); if(targetElement.has("condition")) { log.debug("Set condition xpath for " + target + " to " + xpath); targetElement.getJSONObject("condition").put("xpath", xpath); saveMappings(); } return targetElement; } public JSONObject removeConditionXPath(String target) { JSONObject targetElement = this.elementCache.get(target); if(targetElement.has("condition")) { log.debug("remove condition xpath for " + target); targetElement.getJSONObject("condition").put("xpath", ""); saveMappings(); } return targetElement; } public JSONObject setConditionValue(String target, String value) { JSONObject targetElement = this.elementCache.get(target); if(targetElement.has("condition")) { log.debug("Set condition value for " + target + " to " + value); targetElement.getJSONObject("condition").put("value", value); saveMappings(); } return targetElement; } public JSONObject removeConditionValue(String target) { JSONObject targetElement = this.elementCache.get(target); if(targetElement.has("condition")) { log.debug("remove condition value for " + target); targetElement.getJSONObject("condition").put("value", ""); saveMappings(); } return targetElement; } public JSONObject removeMappings(String target, int index) { JSONObject targetElement = this.elementCache.get(target); removeMappings(targetElement, index); saveMappings(); return targetElement; } public void removeMappings(JSONObject target, int index) { JSONArray mappings = target.getJSONArray("mappings"); if(index > -1) { mappings.remove(index); } } public JSONObject additionalMappings(String target, int index) { JSONObject targetElement = this.elementCache.get(target); JSONArray mappings = targetElement.getJSONArray("mappings"); JSONObject empty = new JSONObject() .element("type", "empty") .element("value", ""); if(index > -1) { mappings.add(index + 1, empty); } saveMappings(); return targetElement; } public JSONObject objectForTargetXPath(String xpath) { //System.out.println("objectForTargetXPath: " + xpath); if(xpath.startsWith("/")) { xpath = xpath.replaceFirst("/", ""); } String[] tokens = xpath.split("/"); if(tokens.length > 0) { JSONObject result = null; JSONObject group = this.groupsCache.get(tokens[0]); System.out.println("objectForTargetXPath token: " + tokens[0]); if(group != null) { // System.out.println("group: " + group.getString("name")); // JSONObject content = group.getJSONObject("contents"); result = this.objectForTargetXPath(group, xpath); if(result != null) return result; } } return null; } public JSONObject objectForTargetXPath(JSONArray array, String xpath) { Iterator i = array.iterator(); while(i.hasNext()) { JSONObject object = (JSONObject) i.next(); JSONObject result = this.objectForTargetXPath(object, xpath); if(result != null) return result; } return null; } public JSONObject objectForTargetXPath(JSONObject object, String xpath) { System.out.println("objectForTargetXPath: " + object.getString("name") + " - " + xpath); if(xpath.startsWith("/")) { xpath = xpath.replaceFirst("/", ""); } String[] tokens = xpath.split("/"); if(tokens.length > 0) { log.debug("looking path:" + xpath + " in object:" + object); if(object.has("name")) { if(tokens[0].equals(object.getString("name"))) { if(tokens.length == 1) { return object; } else { String path = tokens[1]; for(int i = 2; i < tokens.length; i++) { path += "/" + tokens[i]; } if(path.startsWith("@")) { if(object.has("attributes")) { return this.objectForTargetXPath(object.getJSONArray("attributes"), path); } } else { if(object.has("children")) { return this.objectForTargetXPath(object.getJSONArray("children"), path); } } } } } } return null; } public JSONObject duplicateObjectWithXPath(String xpath) { System.out.println("duplicate object: " + xpath); JSONObject result = null; JSONObject object = this.objectForTargetXPath(xpath); if(object != null) { result = this.duplicateNode(object.getString("id")); result = this.elementCache.get(result.getJSONObject("duplicate").getString("id")); } return result; } public JSONObject duplicateNode(String id) { JSONObject targetElement = this.elementCache.get(id); JSONObject parent = this.parentCache.get(id); JSONObject duplicate = duplicateJSONObject(targetElement); JSONArray children = parent.getJSONArray("children"); if(children != null) { int index = -1; for(int i = 0; i < children.size(); i++) { JSONObject child = (JSONObject) children.get(i); if(child.getString("id").equals(id)) { index = i; break; } } if(index >= 0) { children.add(index, duplicate); duplicate = children.getJSONObject(index); } } else { JSONArray array = new JSONArray(); array.add(duplicate); parent.put("children", array); children = parent.getJSONArray("children"); duplicate = children.getJSONObject(0); } this.cacheElements(duplicate); String duplicateId = duplicate.getString("id"); this.parentCache.put(duplicateId, parent); this.saveMappings(); return new JSONObject() .element("parent", parent.getString("id")) .element("original", id) .element("duplicate", duplicate); } public JSONObject removeNode(String id) { JSONObject result = new JSONObject(); JSONObject targetElement = this.elementCache.get(id); JSONObject parent = this.parentCache.get(id); JSONArray children = parent.getJSONArray("children"); if(children != null && !children.isEmpty()) { int targetIndex = -1; int targetCount = 0; for(int i = 0; i < children.size(); i++) { JSONObject child = (JSONObject) children.get(i); if(child.getString("id").equals(id)) { targetIndex = i; } } if(targetIndex >= 0) { children.remove(targetIndex); this.elementCache.remove(id); this.parentCache.remove(id); } result = result.element("id", id); result = result.element("parent", parent.getString("id")); } else { result = result.element("error", "could not find target element"); } this.saveMappings(); return result; } private JSONObject duplicateJSONObject(JSONObject source) { String json = source.toString(); JSONObject out = null; out = (JSONObject) JSONSerializer.toJSON(json); out.put("duplicate", ""); clearAllMappings(out); return out; } protected void clearAllMappings(JSONObject object) { JSONArray mappings = object.getJSONArray("mappings"); mappings.clear(); if(object.has("attributes")) { JSONArray attributes = object.getJSONArray("attributes"); for(int i = 0; i < attributes.size(); i++) { JSONObject a = (JSONObject) attributes.get(i); clearAllMappings(a); } } if(object.has("children")) { JSONArray children = object.getJSONArray("children"); for(int i = 0; i < children.size(); i++) { JSONObject a = (JSONObject) children.get(i); clearAllMappings(a); } } } public JSONObject mappingElementsUsedInMapping() { JSONObject result = new JSONObject(); JSONArray used = new JSONArray(); JSONArray not_used = new JSONArray(); JSONArray parent_used = new JSONArray(); JSONObject mappings = this.getTargetDefinition(); Map<String, MappingElement> map = this.inputSchema.getMap(); Collection<String> list = MappingSummary.getMappedXPathList(mappings); Iterator<String> keys = map.keySet().iterator(); while(keys.hasNext()) { String id = keys.next(); String xpath = map.get(id).getXPath(); for(String xp: list){ if(xp.length()>xpath.length()&& xp.indexOf(xpath)>-1){ parent_used.add(id); break; } } if(list.contains(xpath)) { used.add(id); } else { not_used.add(id); } } return result.element("used", used).element("not_used", not_used).element("parent_used",parent_used); } public JSONObject getDocumentation(String id) { JSONObject result = new JSONObject(); JSONObject targetElement = this.elementCache.get(id); String key = targetElement.getString("name"); if(targetElement.has("prefix") && targetElement.getString("prefix").length() > 0) { if(key.startsWith("@")) { key = "@" + targetElement.getString("prefix") + ":" + key.replace("@", ""); } else { key = targetElement.getString("prefix") + ":" + key; } } result.element("title", key); result.element("documentation", this.getDocumentationForKey(key)); return result; } public JSONObject initComplexCondition(String id) { String defaultLogicalOp = "AND"; boolean conditionInit = false; JSONObject targetElement = this.elementCache.get(id); if(targetElement.has("condition")) { JSONObject condition = targetElement.getJSONObject("condition"); if(!condition.has("logicalop")) { condition.element("logicalop", defaultLogicalOp); JSONArray clauses = new JSONArray(); JSONObject clause = new JSONObject(); if(condition.has("xpath") && condition.getString("xpath").length() > 0) { clause.element("xpath", condition.getString("xpath")); } if(condition.has("value") && condition.getString("value").length() > 0) { clause.element("value", condition.getString("value")); } if(condition.has("relationalop")) { clause.element("relationalop", condition.getString("=")); } clauses.add(clause); condition.element("clauses", clauses); conditionInit = true; } } else { targetElement.element("condition", new JSONObject().element("logicalop", defaultLogicalOp).element("clauses", new JSONArray())); conditionInit = true; } if(conditionInit) { saveMappings(); } return targetElement.getJSONObject("condition"); } public JSONObject addConditionClause(String id, String path, boolean complex) { JSONObject result = new JSONObject(); JSONObject targetElement = this.elementCache.get(id); if(targetElement.has("condition")) { JSONObject condition = targetElement.getJSONObject("condition"); this.addConditionClause(condition, path, complex); result = condition; saveMappings(); } return result; } protected void addConditionClause(JSONObject condition, String path, boolean complex) { if(condition.has("clauses")) { addConditionClause(condition.getJSONArray("clauses"), path, complex); } } protected void addConditionClause(JSONArray clauses, String path, boolean complex) { JSONObject clause = new JSONObject(); if(complex) { clause.element("logicalop", "AND"); JSONArray array = new JSONArray(); array.add(new JSONObject()); clause.element("clauses", array); } if(path.length() == 0) { clauses.add(clause); } else { if(path.contains(".")) { String[] parts = path.split("\\.", 2); System.out.println("'" + path + "' '" + parts[0] + "' '" + parts[1] + "'"); int index = Integer.parseInt(parts[0]); addConditionClause(clauses.getJSONObject(index), parts[1], complex); } else { int index = Integer.parseInt(path); addConditionClause(clauses.getJSONObject(index), "", complex); } } } public JSONObject removeConditionClause(String id, String path) { JSONObject result = new JSONObject(); JSONObject targetElement = this.elementCache.get(id); if(targetElement.has("condition")) { JSONObject condition = targetElement.getJSONObject("condition"); this.removeConditionClause(condition, path); result = condition; saveMappings(); } return result; } protected void removeConditionClause(JSONObject condition, String path) { if(condition.has("clauses")) { removeConditionClause(condition.getJSONArray("clauses"), path); } } protected void removeConditionClause(JSONArray clauses, String path) { if(path.length() > 0) { if(path.contains(".")) { String[] parts = path.split("\\.", 2); int index = Integer.parseInt(parts[0]); if(parts[1].length() > 0) { removeConditionClause(clauses.getJSONObject(index), parts[1]); } else { clauses.remove(index); } } else { int index = Integer.parseInt(path); clauses.remove(index); } } } public JSONObject setConditionClauseKey(String id, String path, String key, String value) { JSONObject result = new JSONObject(); JSONObject targetElement = this.elementCache.get(id); if(targetElement.has("condition")) { JSONObject condition = targetElement.getJSONObject("condition"); this.setConditionClauseKey(condition, path, key, value); result = condition; saveMappings(); } return result; } public JSONObject setConditionClauseXPath(String id, String path, String source) { JSONObject result = new JSONObject(); JSONObject targetElement = this.elementCache.get(id); if(targetElement.has("condition")) { MappingElement sourceElement = this.inputSchema.getMappingElement(source); String value = sourceElement.getXPath(); JSONObject condition = targetElement.getJSONObject("condition"); this.setConditionClauseKey(condition, path, "xpath", value); result = condition; saveMappings(); } return result; } protected void setConditionClauseKey(JSONObject condition, String path, String key, String value) { if(path.length() == 0) { if(condition.has(key)) { condition.remove(key); } condition.element(key, value); } else { if(condition.has("clauses")) { JSONArray clauses = condition.getJSONArray("clauses"); if(path.contains(".")) { String[] parts = path.split("\\.", 2); int index = Integer.parseInt(parts[0]); setConditionClauseKey(clauses.getJSONObject(index), parts[1], key, value); } else { int index = Integer.parseInt(path); setConditionClauseKey(clauses.getJSONObject(index), "", key, value); } } } } public JSONObject removeConditionClauseKey(String id, String path, String key) { JSONObject result = new JSONObject(); JSONObject targetElement = this.elementCache.get(id); if(targetElement.has("condition")) { JSONObject condition = targetElement.getJSONObject("condition"); this.removeConditionClauseKey(condition, path, key); result = condition; saveMappings(); } return result; } protected void removeConditionClauseKey(JSONObject condition, String path, String key) { if(path.length() == 0) { condition.remove(key); } else { if(condition.has("clauses")) { JSONArray clauses = condition.getJSONArray("clauses"); if(path.contains(".")) { String[] parts = path.split("\\.", 2); int index = Integer.parseInt(parts[0]); removeConditionClauseKey(clauses.getJSONObject(index), parts[1], key); } else { int index = Integer.parseInt(path); removeConditionClauseKey(clauses.getJSONObject(index), "", key); } } } } public JSONObject mappingSummary() { JSONObject object = new JSONObject(); DataUpload du = DB.getDataUploadDAO().findById(Long.parseLong(this.dataUploadId), false); String mappings = this.getTargetDefinition().toString(); Collection<String> missing = MappingSummary.getMissingMappings(mappings); Collection<String> invalid = MappingSummary.getInvalidXPaths(du, mappings); Map<String, String> mapped = MappingSummary.getMappedItems(mappings); // Map<String, String> summary = MappingSummary.getSummary(mappings); // JSONObject tree_usage = this.mappingElementsUsedInMapping(); object = object.element("missing", missing); object = object.element("invalid", invalid); object = object.element("mapped", mapped); // object = object.element("used", tree_usage.getJSONArray("used")); // object = object.element("not_used", tree_usage.getJSONArray("not_used")); //object = object.element("summary", summary); //log.debug(object); return object; } protected void saveMappings() { if(this.mappingId != null) { DB.getSession().beginTransaction(); String targetDefinitionString = this.getTargetDefinition().toString(); Mapping map = DB.getMappingDAO().getById(Long.parseLong(this.mappingId), false); if(map == null) { log.error("No mapping object loaded!"); } else { map.setJsonString(targetDefinitionString); } DB.commit(); log.debug("Mapping definition saved"); } } }