/* * Copyright (C) Yutaka Matsuno 2010-2012 All rights reserved. */ package net.dependableos.dcase.diagram.common.util; import java.io.IOException; import java.math.BigDecimal; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import net.dependableos.dcase.BasicLink; import net.dependableos.dcase.BasicNode; import net.dependableos.dcase.Goal; import net.dependableos.dcase.Justification; import net.dependableos.dcase.Monitor; import net.dependableos.dcase.diagram.common.exception.DcaseSystemException; import net.dependableos.dcase.diagram.common.model.AttributeType; import net.dependableos.dcase.diagram.common.model.LinkInfo; import net.dependableos.dcase.diagram.common.model.LinkType; import net.dependableos.dcase.diagram.common.model.NodeInfo; import net.dependableos.dcase.diagram.common.model.NodeType; import net.dependableos.dcase.Context; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.common.util.WrappedException; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.xmi.XMLResource; import org.eclipse.emf.transaction.TransactionalEditingDomain; import org.eclipse.gmf.runtime.emf.core.GMFEditingDomainFactory; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; /** * A utility class with methods to handle the GMF model. */ public final class ModelUtil { /** * The empty string. */ public static final String STRING_EMPTY = ""; //$NON-NLS-1$ /** * The integer that represents 1. */ public static final Integer INTEGER_ONE = Integer.valueOf(1); /** * the string that represents the root of the workspace. */ private static final String PLATFORM = "platform:/resource"; //$NON-NLS-1$ /** * the xpath to elements. */ private static final String EXPRESSION = "//element"; //$NON-NLS-1$ /** * the XML attribute of reference to a model file. */ private static final String ATTRIBUTE_HREF = "href"; //$NON-NLS-1$ /** * the encoding output property. */ private static final String ENCODING = "encoding"; //$NON-NLS-1$ /** * the separator between a model file and an element . */ private static final String SHARP_STRING = "#"; //$NON-NLS-1$ /** * A constractor. */ private ModelUtil() { } /** * Returns the duplicated object. * This throws an exception if the type of the object is unsupported. * * @param <T> the type of the object. * @param originalObject the object. * @return the duplicated object. */ @SuppressWarnings("unchecked") public static <T> T duplicateBasicObject(T originalObject) { if (originalObject == null) { return null; } // String if (originalObject instanceof String) { // substituting string value means copying. return originalObject; } // Integer if (originalObject instanceof Integer) { return (T) Integer.valueOf(((Integer) originalObject).intValue()); } // BigDecimal if (originalObject instanceof BigDecimal) { return (T) new BigDecimal(((BigDecimal) originalObject).toString()); } // Boolean if (originalObject instanceof Boolean) { return (T) Boolean.valueOf(((Boolean) originalObject) .booleanValue()); } // Unsupported throw new DcaseSystemException(Messages.ModelUtil_0, null, MessageTypeImpl.UNDEFINED); } /** * Returns the duplicated map. * This throws an exception if the type of the map is unsupported. * * @param <K> the type of the key. * @param <V> the type of the value. * @param originalMap the map. * @return the duplicated map. */ public static <K, V> Map<K, V> duplicateMap(Map<K, V> originalMap) { if (originalMap == null) { return null; } // HashMap if (originalMap.getClass().equals(HashMap.class)) { HashMap<K, V> duplicateMap = new HashMap<K, V>(); for (Map.Entry<K, V> attribute : originalMap.entrySet()) { V value = attribute.getValue(); V newValue = duplicateBasicObject(value); duplicateMap.put(attribute.getKey(), newValue); } return duplicateMap; } // Unsupported throw new DcaseSystemException(Messages.ModelUtil_1, null, MessageTypeImpl.UNDEFINED); } /** * Returns the duplicated list. * This throws an exception if the type of the list is unsupported. * * @param <T> the type of the elements. * @param originalList the list. * @return the duplicated list. */ public static <T> List<T> duplicateList(List<T> originalList) { if (originalList == null) { return null; } // ArrayList if (originalList.getClass().equals(ArrayList.class)) { List<T> duplicateList = new ArrayList<T>(); for (T element : originalList) { T newValue = duplicateBasicObject(element); duplicateList.add(newValue); } return duplicateList; } // Unsupported throw new DcaseSystemException(Messages.ModelUtil_2, null, MessageTypeImpl.UNDEFINED); } /** * Creates a NodeInfo object that represents the specified BasicNode object. * * @param basicNode a BasicNode object. * @return a NodeInfo object. */ public static NodeInfo createNodeInfo(BasicNode basicNode) { if (basicNode == null) { return null; } XMLResource xmlResource = (XMLResource) basicNode.eResource(); String id = xmlResource.getID(basicNode); NodeInfo nodeInfo = new NodeInfo(NodeType.getNodeType(basicNode)); // sets the common attributes. nodeInfo.setAttribute(AttributeType.ID, id); nodeInfo.setAttribute(AttributeType.NAME, basicNode.getName()); nodeInfo.setAttribute(AttributeType.DESC, basicNode.getDesc()); nodeInfo.setAttribute(AttributeType.ATTACHMENT, basicNode .getAttachment()); nodeInfo.setAttribute(AttributeType.STATUS, basicNode.getStatus()); nodeInfo.setAttribute(AttributeType.FLAG, basicNode.getFlag()); nodeInfo.setAttribute(AttributeType.RESPNAME, basicNode.getRespName()); nodeInfo.setAttribute(AttributeType.RESPADDRESS, basicNode.getRespAddress()); nodeInfo.setAttribute(AttributeType.RESPICON, basicNode.getRespIcon()); nodeInfo.setAttribute(AttributeType.RESPTIME, basicNode.getRespTime()); nodeInfo.setAttribute(AttributeType.MESSAGE, basicNode.getMessage()); nodeInfo.setAttribute(AttributeType.REQUIREMENT, basicNode.getRequirement()); nodeInfo.setAttribute(AttributeType.PARENT, basicNode.getParent()); nodeInfo.setAttribute(AttributeType.REFSOURCE, basicNode.getRefSource()); nodeInfo.setAttribute(AttributeType.PARAMETERDEFS, basicNode.getParameterDefs()); nodeInfo.setAttribute(AttributeType.PARAMETERVALS, basicNode.getParameterVals()); nodeInfo.setAttribute(AttributeType.PARAMETERIZEDDESC, basicNode.getParameterizedDesc()); nodeInfo.setAttribute(AttributeType.USERDEF001, basicNode .getUserdef001()); nodeInfo.setAttribute(AttributeType.USERDEF002, basicNode .getUserdef002()); nodeInfo.setAttribute(AttributeType.USERDEF003, basicNode .getUserdef003()); nodeInfo.setAttribute(AttributeType.USERDEF004, basicNode .getUserdef004()); nodeInfo.setAttribute(AttributeType.USERDEF005, basicNode .getUserdef005()); nodeInfo.setAttribute(AttributeType.USERDEF006, basicNode .getUserdef006()); nodeInfo.setAttribute(AttributeType.USERDEF007, basicNode .getUserdef007()); nodeInfo.setAttribute(AttributeType.USERDEF008, basicNode .getUserdef008()); nodeInfo.setAttribute(AttributeType.USERDEF009, basicNode .getUserdef009()); nodeInfo.setAttribute(AttributeType.USERDEF010, basicNode .getUserdef010()); nodeInfo.setAttribute(AttributeType.USERDEF011, basicNode .getUserdef011()); nodeInfo.setAttribute(AttributeType.USERDEF012, basicNode .getUserdef012()); nodeInfo.setAttribute(AttributeType.USERDEF013, basicNode .getUserdef013()); nodeInfo.setAttribute(AttributeType.USERDEF014, basicNode .getUserdef014()); nodeInfo.setAttribute(AttributeType.USERDEF015, basicNode .getUserdef015()); nodeInfo.setAttribute(AttributeType.USERDEF016, basicNode .getUserdef016()); // sets the proprietary attributes. if (basicNode instanceof Goal) { Goal goalNode = (Goal) basicNode; nodeInfo.setAttribute(AttributeType.SCORE, goalNode.getScore()); nodeInfo.setAttribute(AttributeType.WEIGHT, goalNode.getWeight()); } else if (basicNode instanceof Monitor) { Monitor monitorNode = (Monitor) basicNode; nodeInfo.setAttribute(AttributeType.IS_NORMAL, monitorNode .isIsNormal()); } else if (basicNode instanceof Justification) { Justification justificationNode = (Justification) basicNode; nodeInfo.setAttribute(AttributeType.STAKEHOLDER, justificationNode .getStakeholder()); nodeInfo.setAttribute(AttributeType.RISK_ANALYSIS, justificationNode.getRiskAnalysis()); } else if (basicNode instanceof net.dependableos.dcase.System) { net.dependableos.dcase.System systemNode = (net.dependableos.dcase.System) basicNode; nodeInfo.setAttribute(AttributeType.SUBTYPE, systemNode.getSubType()); nodeInfo.setAttribute(AttributeType.LEAFNODE, systemNode.getLeafNode()); nodeInfo.setAttribute(AttributeType.I, systemNode.getI()); nodeInfo.setAttribute(AttributeType.J, systemNode.getJ()); } else if (basicNode instanceof net.dependableos.dcase.Context) { nodeInfo.setAttribute(AttributeType.REQUIREMENT, ((Context) basicNode).getRequirements()); } return nodeInfo; } /** * Returns a LinkInfo object that represents the specified BasicLink. * * @param basicLink a BasicLink object. * @return a LinkInfo object. */ public static LinkInfo createLinkInfo(BasicLink basicLink) { if (basicLink == null) { return null; } XMLResource xmlResource = (XMLResource) basicLink.eResource(); String id = xmlResource.getID(basicLink); String sourceId = xmlResource.getID(basicLink.getSource()); String targetId = xmlResource.getID(basicLink.getTarget()); LinkInfo linkInfo = new LinkInfo(LinkType.BASIC_LINK); // sets the common attributes. linkInfo.setAttribute(AttributeType.ID, id); linkInfo.setAttribute(AttributeType.DESC, basicLink.getDesc()); linkInfo.setAttribute(AttributeType.ATTACHMENT, basicLink .getAttachment()); linkInfo.setAttribute(AttributeType.SOURCE, sourceId); linkInfo.setAttribute(AttributeType.TARGET, targetId); linkInfo.setAttribute(AttributeType.NAME, basicLink.getName()); linkInfo.setAttribute(AttributeType.STATUS, basicLink.getStatus()); linkInfo.setAttribute(AttributeType.SIBLINGORDER, basicLink.getSiblingOrder()); linkInfo.setAttribute(AttributeType.MESSAGE, basicLink.getMessage()); linkInfo.setAttribute(AttributeType.USERDEF001, basicLink .getUserdef001()); linkInfo.setAttribute(AttributeType.USERDEF002, basicLink .getUserdef002()); linkInfo.setAttribute(AttributeType.USERDEF003, basicLink .getUserdef003()); linkInfo.setAttribute(AttributeType.USERDEF004, basicLink .getUserdef004()); linkInfo.setAttribute(AttributeType.USERDEF005, basicLink .getUserdef005()); linkInfo.setAttribute(AttributeType.USERDEF006, basicLink .getUserdef006()); linkInfo.setAttribute(AttributeType.USERDEF007, basicLink .getUserdef007()); linkInfo.setAttribute(AttributeType.USERDEF008, basicLink .getUserdef008()); linkInfo.setAttribute(AttributeType.USERDEF009, basicLink .getUserdef009()); linkInfo.setAttribute(AttributeType.USERDEF010, basicLink .getUserdef010()); linkInfo.setAttribute(AttributeType.USERDEF011, basicLink .getUserdef011()); linkInfo.setAttribute(AttributeType.USERDEF012, basicLink .getUserdef012()); linkInfo.setAttribute(AttributeType.USERDEF013, basicLink .getUserdef013()); linkInfo.setAttribute(AttributeType.USERDEF014, basicLink .getUserdef014()); linkInfo.setAttribute(AttributeType.USERDEF015, basicLink .getUserdef015()); linkInfo.setAttribute(AttributeType.USERDEF016, basicLink .getUserdef016()); return linkInfo; } /** * Returns the EObject from the model file. * * @param modelFile the model file. * @return the EObject */ public static EObject getModel(IFile modelFile) { return getModel(modelFile, false); } /** * Returns the EObject from the model file. * * @param modelFile the model file. * @param isIgnoreException ignore exception if true. * @return the EObject */ public static EObject getModel(IFile modelFile, boolean isIgnoreException) { // creates URI. URI modelURI = URI.createPlatformResourceURI(modelFile.getFullPath() .toString(), true); TransactionalEditingDomain editingDomain = GMFEditingDomainFactory.INSTANCE .createEditingDomain(); ResourceSet resourceSet = editingDomain.getResourceSet(); EObject diagramRoot = null; try { // gets the model. Resource resource = resourceSet.getResource(modelURI, true); diagramRoot = (EObject) resource.getContents().get(0); } catch (WrappedException we) { if (! isIgnoreException) { throw new DcaseSystemException( Messages.TemplateModelAdditionAction_4, we, MessageTypeImpl.TEMPLATE_INSERT_INTERNAL_ERROR); } } return diagramRoot; } /** * Returns the file in the relative path. * * @param base the base path. * @param modelPath relative path to the file. * @return the file. */ private static IFile getFileInRelativePath(IPath base, String modelPath) { IFile result = null; // in the case of different project. if (modelPath.startsWith(PLATFORM)) { modelPath = modelPath.replaceAll(PLATFORM, ""); //$NON-NLS-1$ result = ResourcesPlugin.getWorkspace().getRoot().getFile( new Path(modelPath)); return result; } // in the case of same project. IPath path = base.append(modelPath); result = ResourcesPlugin.getWorkspace().getRoot().getFile(path); return result; } /** * Returns the GMF model file that is referred from the GMF diagram file. * * @param diagramFile the GMF diagram file. * @return the GMF model file. */ public static IFile getModelFileFromDiagramFile(IFile diagramFile) { if (diagramFile == null) { return null; } IFile result = null; try { DocumentBuilderFactory domFactory = DocumentBuilderFactory .newInstance(); domFactory.setNamespaceAware(true); DocumentBuilder builder; builder = domFactory.newDocumentBuilder(); // parses the XML. Document doc = builder.parse(diagramFile.getLocation().toFile()); // creates a XPathFactory. XPathFactory factory = XPathFactory.newInstance(); XPath xpath = factory.newXPath(); XPathExpression expr = xpath.compile(EXPRESSION); Object nodeListObj = expr.evaluate(doc, XPathConstants.NODESET); NodeList nodeList = (NodeList) nodeListObj; //gets the name of the model file. String modelFilename = null; for (int i = 0; i < nodeList.getLength(); i++) { NamedNodeMap maps = nodeList.item(i).getAttributes(); Node node = maps.getNamedItem(ATTRIBUTE_HREF); if (node != null) { modelFilename = node.getNodeValue(); break; } } if (modelFilename != null) { int index = modelFilename.indexOf(SHARP_STRING); modelFilename = modelFilename.substring(0, index); //gets the model file. result = getFileInRelativePath(diagramFile.getFullPath() .removeLastSegments(1), modelFilename); } } catch (ParserConfigurationException e) { throw new DcaseSystemException(Messages.ModelUtil_4, e, MessageTypeImpl.GET_MODEL_FILE_FAILED); } catch (SAXException e) { throw new DcaseSystemException(Messages.ModelUtil_4, e, MessageTypeImpl.GET_MODEL_FILE_FAILED); } catch (IOException e) { throw new DcaseSystemException(Messages.ModelUtil_4, e, MessageTypeImpl.GET_MODEL_FILE_FAILED); } catch (XPathExpressionException e) { throw new DcaseSystemException(Messages.ModelUtil_4, e, MessageTypeImpl.GET_MODEL_FILE_FAILED); } return result; } /** * Updates the reference to the GMF model file of the GMF diagram file. * * @param diagramFile the source GMF diagram file. * @param modelFile the GMF model file * @param destFile the destination GMF diagram file. * @param deleteSourceDiagram true if delete the source; false otherwise. */ public static void updateModelFileReference(IFile diagramFile, IFile modelFile, IFile destFile, boolean deleteSourceDiagram) { if (diagramFile == null || modelFile == null || destFile == null) { return; } // gets the relative path from the diagram file to the model file. IPath base = destFile.getFullPath().removeLastSegments(1); String modelFilename = getRelativePath(base, modelFile); try { DocumentBuilderFactory domFactory = DocumentBuilderFactory .newInstance(); domFactory.setNamespaceAware(true); DocumentBuilder builder = domFactory.newDocumentBuilder(); // parses XML. Document doc = builder.parse(diagramFile.getLocation().toFile()); // creates a XPathFactory. XPathFactory factory = XPathFactory.newInstance(); XPathExpression expr = factory.newXPath().compile(EXPRESSION); Object nodeListObj = expr.evaluate(doc, XPathConstants.NODESET); NodeList nodeList = (NodeList) nodeListObj; String baseAttribute = modelFilename.concat(SHARP_STRING); String attributeValue = null; // updates the reference to the model file. for (int i = 0; i < nodeList.getLength(); i++) { NamedNodeMap maps = nodeList.item(i).getAttributes(); Node hrefAttribute = maps.getNamedItem(ATTRIBUTE_HREF); if (hrefAttribute == null) { continue; } attributeValue = hrefAttribute.getNodeValue(); int objIdIndex = attributeValue.indexOf(SHARP_STRING); // updates the value of the attribute. hrefAttribute.setNodeValue(baseAttribute.concat(attributeValue .substring(objIdIndex + 1))); } // overrides the diagram file. TransformerFactory tff = TransformerFactory.newInstance(); Transformer tf; tf = tff.newTransformer(); tf.setOutputProperty(ENCODING, "UTF-8"); //$NON-NLS-1$ tf.transform(new DOMSource(doc), new StreamResult(destFile .getLocation().toOSString())); // deletes the original file. if (deleteSourceDiagram) { diagramFile.delete(true, null); } // refreshes. destFile.refreshLocal(IResource.DEPTH_INFINITE, null); } catch (ParserConfigurationException e) { throw new DcaseSystemException(Messages.ModelUtil_3, e, MessageTypeImpl.UPDATE_MODEL_FILE_REFERENCE_FAILED); } catch (SAXException e) { throw new DcaseSystemException(Messages.ModelUtil_3, e, MessageTypeImpl.UPDATE_MODEL_FILE_REFERENCE_FAILED); } catch (IOException e) { throw new DcaseSystemException(Messages.ModelUtil_3, e, MessageTypeImpl.UPDATE_MODEL_FILE_REFERENCE_FAILED); } catch (XPathExpressionException e) { throw new DcaseSystemException(Messages.ModelUtil_3, e, MessageTypeImpl.UPDATE_MODEL_FILE_REFERENCE_FAILED); } catch (TransformerException e) { throw new DcaseSystemException(Messages.ModelUtil_3, e, MessageTypeImpl.UPDATE_MODEL_FILE_REFERENCE_FAILED); } catch (CoreException e) { throw new DcaseSystemException(Messages.ModelUtil_3, e, MessageTypeImpl.UPDATE_MODEL_FILE_REFERENCE_FAILED); } } /** * Returns the string that represents the relative path from the base to the file. * * @param base the base. * @param file the file. * @return the string that represents the relative path. */ private static String getRelativePath(IPath base, IFile file) { String result = null; String[] segs = base.segments(); String[] companionSegs = file.getFullPath().segments(); if (!segs[0].equals(companionSegs[0])) { // in the case of different project. result = PLATFORM.concat(file.getFullPath().toString()); } else { IPath companionPath = file.getFullPath(); // in the case of same project. result = companionPath.makeRelativeTo(base).toString(); } return result; } }