package com.baselet.gwt.client.element; import java.util.ArrayList; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.baselet.control.basics.geom.Rectangle; import com.baselet.control.constants.SharedConstants; import com.baselet.control.enums.ElementId; import com.baselet.element.interfaces.Diagram; import com.baselet.element.interfaces.GridElement; import com.baselet.gwt.client.base.Notification; import com.baselet.gwt.client.version.BuildInfoProperties; import com.google.gwt.http.client.URL; import com.google.gwt.user.client.Window; import com.google.gwt.xml.client.DOMException; import com.google.gwt.xml.client.Document; import com.google.gwt.xml.client.Element; import com.google.gwt.xml.client.Node; import com.google.gwt.xml.client.NodeList; import com.google.gwt.xml.client.XMLParser; public class DiagramXmlParser { private static final String NUMBER_SIGN = "#"; // # is not automatically encoded by URL.encode() and URL.decode() private static final String NUMBER_SIGN_URL_ENCODED = "%23"; private static final String GT = ">"; private static final String GT_ENCODED = ">"; // in some cases the xml parser doesn't convert automatically (especially together with URL.encoded strings) therefore replace manually private static final String LT = "<"; private static final String LT_ENCODED = "<"; private static final String AMP = "&"; private static final String AMP_ENCODED = "&"; private static final Logger log = LoggerFactory.getLogger(DiagramXmlParser.class); private static final String DIAGRAM = "diagram"; private static final String ELEMENT = "element"; private static final String ZOOM_LEVEL = "zoom_level"; private static final String HELP_TEXT = "help_text"; private static final String ID = "id"; private static final String COORDINATES = "coordinates"; private static final String X = "x"; private static final String Y = "y"; private static final String W = "w"; private static final String H = "h"; private static final String PANEL_ATTRIBUTES = "panel_attributes"; private static final String ADDITIONAL_ATTRIBUTES = "additional_attributes"; private static final String ATTR_PROGRAM = "program"; private static final String ATTR_VERSION = "version"; public static Diagram xmlToDiagram(boolean decodeUrl, String xml) { if (decodeUrl) { xml = URL.decode(xml).replace(NUMBER_SIGN_URL_ENCODED, NUMBER_SIGN); } return xmlToDiagram(xml); } public static Diagram xmlToDiagram(String xml) { log.debug("Serializing " + xml); if (xml.startsWith(SharedConstants.UTF8_BOM)) { xml = xml.substring(1); // remove BOM if it is given } Diagram diagram = null; String helpText = null; try { // parse the XML document into a DOM Document messageDom = XMLParser.parse(xml); Node helpTextNode = messageDom.getElementsByTagName(HELP_TEXT).item(0); if (helpTextNode != null) { Node firstChild = helpTextNode.getFirstChild(); if (firstChild != null) { helpText = helpTextNode.getFirstChild().getNodeValue(); } else { helpText = ""; // empty helptext should also work } } float zoomScale = 1.0f; Node zoomElement = messageDom.getElementsByTagName(ZOOM_LEVEL).item(0); if (zoomElement != null) { zoomScale = Float.valueOf(zoomElement.getFirstChild().getNodeValue()) / SharedConstants.DEFAULT_GRID_SIZE; } diagram = new DiagramGwt(helpText, new ArrayList<GridElement>()); NodeList elements = messageDom.getElementsByTagName(ELEMENT); for (int i = 0; i < elements.getLength(); i++) { Element element = (Element) elements.item(i); try { ElementId id = ElementId.valueOf(element.getElementsByTagName(ID).item(0).getFirstChild().getNodeValue()); Element coord = (Element) element.getElementsByTagName(COORDINATES).item(0); Rectangle rect = new Rectangle(getInt(coord, X), getInt(coord, Y), getInt(coord, W), getInt(coord, H)); String panelAttributes = ""; Node panelAttrNode = element.getElementsByTagName(PANEL_ATTRIBUTES).item(0).getFirstChild(); if (panelAttrNode != null) { panelAttributes = panelAttrNode.getNodeValue(); } String additionalPanelAttributes = ""; Node additionalAttrNode = element.getElementsByTagName(ADDITIONAL_ATTRIBUTES).item(0); if (additionalAttrNode != null && additionalAttrNode.getFirstChild() != null) { additionalPanelAttributes = additionalAttrNode.getFirstChild().getNodeValue(); } if (zoomScale != 1.0f) { rect.setX((int) (rect.getX() / zoomScale)); rect.setY((int) (rect.getY() / zoomScale)); rect.setWidth((int) (rect.getWidth() / zoomScale)); rect.setHeight((int) (rect.getHeight() / zoomScale)); } GridElement gridElement = ElementFactoryGwt.create(id, rect, panelAttributes, additionalPanelAttributes, diagram); diagram.getGridElements().add(gridElement); } catch (Exception e) { log.error("Element has invalid XML structure: " + element, e); Notification.showFeatureNotSupported("Diagram has invalid element: " + element, true); } } } catch (DOMException e) { log.error("Parsing error", e); Window.alert("Could not parse XML document."); } return diagram; } private static Integer getInt(Element coordinates, String tag) { return Integer.valueOf(coordinates.getElementsByTagName(tag).item(0).getFirstChild().getNodeValue()); } public static String diagramToXml(Diagram diagram) { Document doc = XMLParser.createDocument(); Element diagramElement = doc.createElement(DIAGRAM); diagramElement.setAttribute(ATTR_PROGRAM, "umletino"); diagramElement.setAttribute(ATTR_VERSION, BuildInfoProperties.getVersion()); diagramElement.appendChild(create(doc, ZOOM_LEVEL, doc.createTextNode("10"))); String helpText = diagram.getPanelAttributes(); if (helpText != null) { diagramElement.appendChild(create(doc, HELP_TEXT, doc.createTextNode(helpText))); } doc.appendChild(diagramElement); for (GridElement ge : diagram.getGridElements()) { diagramElement.appendChild( create(doc, ELEMENT, create(doc, ID, doc.createTextNode(ge.getId().toString())), create(doc, COORDINATES, create(doc, X, doc.createTextNode(ge.getRectangle().getX() + "")), create(doc, Y, doc.createTextNode(ge.getRectangle().getY() + "")), create(doc, W, doc.createTextNode(ge.getRectangle().getWidth() + "")), create(doc, H, doc.createTextNode(ge.getRectangle().getHeight() + ""))), create(doc, PANEL_ATTRIBUTES, doc.createTextNode(ge.getPanelAttributes())), create(doc, ADDITIONAL_ATTRIBUTES, doc.createTextNode(ge.getAdditionalAttributes())))); } String xml = doc.toString(); log.debug("Deserializing to " + xml); return xml; } public static String diagramToXml(boolean encodeUrl, boolean encodeXml, Diagram diagram) { String xml = diagramToXml(diagram); if (encodeXml) { xml = xml.replace(AMP, AMP_ENCODED).replace(LT, LT_ENCODED).replace(GT, GT_ENCODED); // AMP must be before LT and GT (see #282) } if (encodeUrl) { xml = URL.encode(xml).replace(NUMBER_SIGN, NUMBER_SIGN_URL_ENCODED); } return xml; } private static Element create(Document doc, String name, Node... children) { Element element = doc.createElement(name); for (Node c : children) { element.appendChild(c); } return element; } public static String gridElementsToXml(List<GridElement> gridElements) { return diagramToXml(new DiagramGwt(gridElements)); } public static List<GridElement> xmlToGridElements(String string) { return xmlToDiagram(string).getGridElements(); } }