/******************************************************************************* * Copyright (c) 2007 Exadel, Inc. and Red Hat, Inc. * Distributed under license by Red Hat, Inc. All rights reserved. * This program is made available under the terms of the * Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Exadel, Inc. and Red Hat, Inc. - initial API and implementation ******************************************************************************/ package org.jboss.tools.common.model.util; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.OutputStream; import java.io.Reader; import java.io.StringWriter; import java.io.Writer; import java.text.MessageFormat; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.StringTokenizer; import org.apache.xml.serialize.OutputFormat; import org.apache.xml.serialize.XMLSerializer; import org.w3c.dom.Comment; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.jboss.tools.common.meta.XAttribute; import org.jboss.tools.common.meta.XChild; import org.jboss.tools.common.meta.XModelEntity; import org.jboss.tools.common.model.ServiceDialog; import org.jboss.tools.common.model.XModel; import org.jboss.tools.common.model.XModelConstants; import org.jboss.tools.common.model.XModelException; import org.jboss.tools.common.model.XModelObject; import org.jboss.tools.common.model.XModelObjectConstants; import org.jboss.tools.common.model.engines.impl.EnginesLoader; import org.jboss.tools.common.model.filesystems.XFileObject; import org.jboss.tools.common.model.filesystems.impl.FileAnyImpl; import org.jboss.tools.common.model.impl.XModelImpl; import org.jboss.tools.common.model.impl.XModelObjectImpl; import org.jboss.tools.common.model.loaders.XObjectLoader; import org.jboss.tools.common.model.plugin.ModelMessages; import org.jboss.tools.common.model.plugin.ModelPlugin; import org.jboss.tools.common.util.FileUtil; import org.jboss.tools.common.xml.XMLUtilities; public class XModelObjectLoaderUtil { public static String ENT_ANY_ELEMENT = "AnyElement"; //$NON-NLS-1$ public static String ATTR_ID_NAME = "_id_"; //$NON-NLS-1$ private Hashtable<String,String> singular = null; private boolean saveentity = true; private String namespace = null; private NamespaceMapping namespaceMapping = null; protected String error = null; public XModelObjectLoaderUtil() {} public void setup(Hashtable<String,String> singular, boolean saveentity) { this.singular = singular; this.saveentity = saveentity; error = null; } public String getError() { return error; } public void setNamespace(String namespace) { this.namespace = namespace; } public void setNamespaceMapping(NamespaceMapping nm) { namespaceMapping = nm; } public void setSaveEntity(boolean b) { saveentity = b; } public void load(Element element, XModelObject o) { if(ENT_ANY_ELEMENT.equals(o.getModelEntity().getName())) { loadAnyElement(element, o); } else { loadAttributes(element, o); loadChildren(element, o); if(error == null) { Set<String> allowed = getAllowedChildren(o.getModelEntity()); if(allowed != null && hasUnallowedChildren(element, allowed)); } if(error == null) { Set<String> allowed = getAllowedAttributes(o.getModelEntity()); if(allowed != null && hasUnallowedAttributes(element, allowed)); } } } static Map<XModelEntity, Set<String>> allowedChildren = new HashMap<XModelEntity, Set<String>>(); protected Set<String> getAllowedChildren(XModelEntity entity) { if(entity.getChild(ENT_ANY_ELEMENT) != null) return null; Set<String> x = allowedChildren.get(entity); if(x != null) return x; Set<String> children = new HashSet<String>(); XAttribute[] as = entity.getAttributes(); for (int i = 0; i < as.length; i++) { String xml = as[i].getXMLName(); if(xml == null) continue; int s = xml.indexOf('|'); if(s > 0) { StringTokenizer st = new StringTokenizer(xml, "|"); //$NON-NLS-1$ while(st.hasMoreTokens()) { String dxml = st.nextToken(); int k = dxml.indexOf('.'); if(k >= 0) children.add(dxml.substring(0, k)); } } else { int k = xml.indexOf('.'); if(k < 0) continue; children.add(xml.substring(0, k)); } } XChild[] cs = entity.getChildren(); for (int i = 0; i < cs.length; i++) { XModelEntity c = entity.getMetaModel().getEntity(cs[i].getName()); if(c == null) continue; String xml = c.getXMLSubPath(); if(xml == null || xml.length() == 0) { if(cs[i].isRequired()) { Set<String> a1 = getAllowedChildren(c); if(a1 == null) return null; children.addAll(a1); } } int k = xml.indexOf('.'); if(k >= 0) xml = xml.substring(0, k); children.add(xml); } if(children != null) allowedChildren.put(entity, children); return children; } protected Set<String> getAllowedAttributes(XModelEntity entity) { if(entity.getChild(ENT_ANY_ELEMENT) != null) return null; Set<String> attributes = new HashSet<String>(); if(saveentity) { attributes.add(XModelConstants.XMODEL_ENTITY_ATTR); attributes.add(XModelConstants.XMODEL_ENTITY_ATTR_OLD); } XAttribute[] as = entity.getAttributes(); for (int i = 0; i < as.length; i++) { String xml = as[i].getXMLName(); if(xml == null) continue; int s = xml.indexOf('|'); if(s > 0) { StringTokenizer st = new StringTokenizer(xml, "|"); //$NON-NLS-1$ while(st.hasMoreTokens()) { String dxml = st.nextToken(); int k = dxml.indexOf('.'); if(k < 0) attributes.add(dxml); } } else { int k = xml.indexOf('.'); if(k >= 0) continue; attributes.add(xml); } } return attributes; } private boolean hasUnallowedChildren(Element element, Set<String> allowed) { NodeList nl = element.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node n = nl.item(i); if(n.getNodeType() == Node.ELEMENT_NODE) { String name = n.getNodeName(); if(namespaceMapping != null) { name = namespaceMapping.convertToDefault(name); } if(allowed.contains(name)) continue; error = MessageFormat .format( "Editor model does not support child element {0} of {1}:0:0", name, element.getNodeName()); return true; } } return false; } private boolean hasUnallowedAttributes(Element element, Set<String> allowed) { NamedNodeMap nl = element.getAttributes(); for (int i = 0; i < nl.getLength(); i++) { Node n = nl.item(i); if(n.getNodeType() == Node.ATTRIBUTE_NODE) { String name = n.getNodeName(); if(allowed.contains(name)) continue; if(name.startsWith("xmlns")) continue; //$NON-NLS-1$ error = MessageFormat .format( "Editor model does not support attribute {0} of {1}:0:0", name, element.getNodeName());; return true; } } return false; } public void loadAttributes(Element element, XModelObject o) { XModelEntity entity = o.getModelEntity(); XAttribute[] as = entity.getAttributes(); for (int i = 0; i < as.length; i++) { String n = as[i].getName(); if("attributes".equals(n) && "true".equals(as[i].getProperty("any"))) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ loadAnyAtributes(element, o); continue; } String xmlname = as[i].getXMLName(); if (xmlname == null || xmlname.length() == 0) continue; String value = getAttribute(element, xmlname, as[i]); if (value != null) o.setAttributeValue(n, value); String commentName = getAttributeCommentName(xmlname); if(commentName != null) { String fn = xmlname.substring(0, xmlname.indexOf('.')); Element child = XMLUtilities.getFirstChild(element, fn); if(child != null) { String comment = getComment(child); if(comment != null && comment.length() > 0) { o.set(commentName, comment); } } } } String s = getFinalComment(element); if(s != null && s.length() > 0) o.set("#final-comment", s); //$NON-NLS-1$ } private String applyNamespaceToAttribute(String xmlname) { if(namespaceMapping != null) { xmlname = namespaceMapping.convertToActual(xmlname); } if(namespace == null || namespace.length() == 0) return xmlname; if(xmlname.indexOf(':') > 0 || xmlname.indexOf('.') >= 0 || xmlname.indexOf('#') >= 0) return xmlname; if(xmlname.equals("xmlns")) { //$NON-NLS-1$ return xmlname + ":" + namespace; //$NON-NLS-1$ } return xmlname; } public final String applyNamespaceToTag(String xmlname) { if(namespaceMapping != null) { xmlname = namespaceMapping.convertToActual(xmlname); } if(namespace != null && namespace.length() > 0) { return namespace + ":" + xmlname; //$NON-NLS-1$ } return xmlname; } //TODO final. getAttribute(Element, String, XAttribute) should be overridden public String getAttribute(Element element, String xmlname) { return getAttribute(element, xmlname, null); } public String getAttribute(Element element, String xmlname, XAttribute attr) { if (xmlname.equals("CDATA") || xmlname.equals("#text")) { //$NON-NLS-1$ //$NON-NLS-2$ return getCDATA(element, attr == null || attr.isTrimmable()); } else if (xmlname.equals("#comment")) { //$NON-NLS-1$ return getComment(element); } else { int ind = xmlname.indexOf('.'); if (ind > 0) { String childName = xmlname.substring(0, ind); if(namespaceMapping != null) { childName = namespaceMapping.convertToActual(childName); } if(namespace != null && namespace.length() > 0 && childName.indexOf(':') < 0) { childName = namespace + ":" + childName; //$NON-NLS-1$ } Element child = XMLUtil.getFirstChild(element, childName); if (child != null) return getAttribute(child, xmlname.substring(ind+1), attr); } else { xmlname = applyNamespaceToAttribute(xmlname); if (XMLUtil.hasAttribute(element, xmlname)) { return element.getAttribute(xmlname); } } } return null; } public void loadChildren(Element element, XModelObject o) { XModelEntity entity = o.getModelEntity(); XModel model = o.getModel(); Set<String> childset = entity.getRequiredChildren(); NodeList nl = element.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node n = nl.item(i); if(n.getNodeType() != Node.ELEMENT_NODE) continue; Element e = (Element)n; String en = getChildEntity(entity, e); if(en == null && entity.getChild(ENT_ANY_ELEMENT) != null) en = ENT_ANY_ELEMENT; if(en == null) continue; XModelObject co = model.createModelObject(en, null); if(co == null) continue; load(e, co); if(!o.addChild(co) && co.getFileType() == XModelObject.NONE) { if(co.getModelEntity().getAttribute(ATTR_ID_NAME) != null) { int k = 1; String pp = co.getPathPart(); while(o.getChildByPath(pp) != null) { co.setAttributeValue(ATTR_ID_NAME, "" + k); //$NON-NLS-1$ String ppn = co.getPathPart(); if(ppn.equals(pp)) break; pp = ppn; ++k; } o.addChild(co); } else if(o.isActive() || (entity.getChild(en) != null && entity.getChild(en).isRequired())) try { XModelObject q = o.getChildByPath(co.getPathPart()); if(q != null) EnginesLoader.merge(q, co, false); } catch (XModelException exc) { ModelPlugin.getPluginLog().logError("XModelObjectLoaderUtil:loadChildren:" + exc.getMessage(), exc); //$NON-NLS-1$ } else { int k = 1; String pp = co.getPathPart(); while(o.getChildByPath(pp) != null) { co.set(XModelObjectImpl.DUPLICATE, "" + k); //$NON-NLS-1$ String ppn = co.getPathPart(); if(ppn.equals(pp)) break; pp = ppn; ++k; } o.addChild(co); } continue; } if(childset.contains(en)) { childset.remove(en); } } if(!childset.isEmpty()) { //in most cases the set is empty and this check is faster than creating an iterator. for (String en: childset) { o.addChild(createValidObject(model, en)); } } } public static String getModelEntityAttribute(Element element) { if(XMLUtil.hasAttribute(element, XModelConstants.XMODEL_ENTITY_ATTR)) { return element.getAttribute(XModelConstants.XMODEL_ENTITY_ATTR); } if(XMLUtil.hasAttribute(element, XModelConstants.XMODEL_ENTITY_ATTR_OLD)) { return element.getAttribute(XModelConstants.XMODEL_ENTITY_ATTR_OLD); } return null; } protected String getChildEntity(XModelEntity entity, Element e) { String en = getModelEntityAttribute(e); if(en == null || en.length() == 0) { String n = e.getNodeName(); if(namespaceMapping != null) { n = namespaceMapping.convertToDefault(n); } if(namespace != null && namespace.length() > 0 && n.startsWith(namespace + ":")) { //$NON-NLS-1$ n = n.substring(namespace.length() + 1); } en = entity.getChildByXML(n); } return en; } protected boolean acceptElement(Element e, String entity) { return !saveentity || (entity.equals(e.getAttribute(XModelConstants.XMODEL_ENTITY_ATTR)) || entity.equals(e.getAttribute(XModelConstants.XMODEL_ENTITY_ATTR_OLD))); } public static XModelObject createValidObject(XModel model, String entityname) { return createValidObject(model, entityname, null); } public static XModelObject createValidObject(XModel model, String entityname, Properties p) { XModelObject o = model.createModelObject(entityname, p); if(o != null) addRequiredChildren(o); return o; } public static void addRequiredChildren(XModelObject object) { XChild[] cs = object.getModelEntity().getChildren(); for (int i = 0; i < cs.length; i++) { if(cs[i].getMaxCount() != 1 || !cs[i].isRequired()) continue; XModelObject c = createValidObject(object.getModel(), cs[i].getName(), null); if(c != null) object.addChild(c); } } public static void addRequiredChildren(XModelObject object, boolean onlyHavingNoXMLPath) { XChild[] cs = object.getModelEntity().getChildren(); for (int i = 0; i < cs.length; i++) { if(cs[i].getMaxCount() != 1 || !cs[i].isRequired()) continue; if(onlyHavingNoXMLPath) { XModelEntity e = cs[i].getMetaModel().getEntity(cs[i].getName()); if(e == null) continue; String xml = e.getXMLSubPath(); if(xml != null && xml.length() > 0) continue; } XModelObject c = createValidObject(object.getModel(), cs[i].getName(), null); if(c != null) object.addChild(c); } } public boolean save(Element parent, XModelObject o) { if(ENT_ANY_ELEMENT.equals(o.getModelEntity().getName())) { saveAnyElement(parent, o); return true; } else { String xmlname = getXMLSubPath(o); if(xmlname == null || xmlname.trim().length() == 0) return true; if(namespaceMapping != null) { xmlname = namespaceMapping.convertToActual(xmlname); } if(namespace != null && namespace.length() > 0) { xmlname = namespace + ":" + xmlname; //$NON-NLS-1$ } Element element = XMLUtil.createElement(parent, xmlname); saveAttributes(element, o); boolean b = saveChildren(element, o); saveFinalComment(element, o); if(b) o.setModified(false); return b; } } protected String getXMLSubPath(XModelObject o) { return o.getModelEntity().getXMLSubPath(); } public void saveAttributes(Element element, XModelObject o) { XModelEntity entity = o.getModelEntity(); XAttribute[] as = entity.getAttributes(); if (saveentity) { element.setAttribute(XModelConstants.XMODEL_ENTITY_ATTR, entity.getName()); } for (int i = 0; i < as.length; i++) { if (as[i].isFake()) continue; String n = as[i].getName(); if("attributes".equals(n) && "true".equals(as[i].getProperty("any"))) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ saveAnyAtributes(element, o); continue; } String xmlname = as[i].getXMLName(); if (xmlname == null || xmlname.length() == 0) continue; String v = o.getAttributeValue(n); if (isSaveable(entity, n, v, as[i].getDefaultValue())) { saveAttribute(element, xmlname, v); String commentName = getAttributeCommentName(xmlname); if(commentName != null) { String comment = o.get(commentName); if(comment != null && comment.length() > 0) { String cn = xmlname.substring(0, xmlname.indexOf('.')); Element child = XMLUtilities.getLastChild(element, cn); if(child != null) { setComment(child, comment); } } } } } } public void saveAttribute(Element element, String xmlname, String value) { if (xmlname.equals("CDATA")) { //$NON-NLS-1$ setCDATA(element, value); } else if (xmlname.equals("#text")) { //$NON-NLS-1$ setText(element, value); } else if (xmlname.equals("#comment")) { //$NON-NLS-1$ setComment(element, value); } else { int ind = xmlname.indexOf('.'); if (ind > 0) { String childName = xmlname.substring(0, ind); if(namespaceMapping != null) { childName = namespaceMapping.convertToActual(childName); } if(namespace != null && namespace.length() > 0 && childName.indexOf(':') < 0) { childName = namespace + ":" + childName; //$NON-NLS-1$ } Element child = XMLUtil.getFirstChild(element, childName); if (child == null) child = XMLUtil.createElement(element, childName); saveAttribute(child, xmlname.substring(ind+1), value); } else { xmlname = applyNamespaceToAttribute(xmlname); element.setAttribute(xmlname, value); } } } protected boolean isSaveable(XModelEntity entity, String n, String v, String dv) { if (v == null || v.length() == 0) return false; if (!v.equals(dv)) return true; return (singular != null && singular.get(n) != null); } public void saveFinalComment(Element element, XModelObject o) { String data = o.get("#final-comment"); //$NON-NLS-1$ if(data == null || data.length() == 0) return; Comment comm = element.getOwnerDocument().createComment(data); element.appendChild(comm); } public boolean saveChildren(Element element, XModelObject o) { XModelObject[] os = ((XModelObjectImpl)o).getChildrenForSave(); boolean b = true; for (int i = 0; i < os.length; i++) if(!save(element, os[i])) b = false; return b; } public XModelObject parse(XModel model, Reader reader) { Element element = XMLUtil.getElement(reader); if(element == null) return null; String entity = getModelEntityAttribute(element); XModelObject o = model.createModelObject(entity, null); load(element, o); return o; } public Element asElement(XModelObject o) { Element root = XMLUtil.createDocumentElement(o.getModelEntity().getXMLSubPath()); saveAttributes(root, o); boolean b = saveChildren(root, o); //// if(o instanceof XSavable && !((XSavable)o).save()) b = false; return (b) ? root : null; } public static final void serialize(Element element, String filename) throws IOException { File f = new File(filename); if(f.exists() && !f.canWrite()) return; if(!f.exists()) f.createNewFile(); FileWriter fw = new FileWriter(f); serialize(element, new BufferedWriter(fw)); fw.close(); } public static String getEncoding(String body) { if(body == null || body.length() == 0) return null; //"UTF-8" String encoding = FileUtil.getEncoding(body); if(encoding == null) return null; //"UTF-8" return FileUtil.validateEncoding(encoding, "UTF-8"); //$NON-NLS-1$ } public static OutputFormat createOutputFormat(String encoding) { return XMLUtilities.createOutputFormat(encoding); } public static final boolean serialize(Element element, Writer w) throws IOException { if(element == null) return false; serialize(element, new XMLSerializer(w, createOutputFormat("UTF-8"))); //$NON-NLS-1$ w.close(); return true; } public boolean serialize(XModelObject object, Writer w) throws XModelException, IOException { return serialize(asElement(object), w); } public static final boolean serialize(Element element, OutputStream w) throws IOException { if(element == null) return false; serialize(element, new XMLSerializer(w, createOutputFormat("UTF-8"))); //$NON-NLS-1$ w.close(); return true; } public boolean serialize(XModelObject object, OutputStream w) throws XModelException, IOException { return serialize(asElement(object), w); } public static void serialize(Element element, XMLSerializer serial) throws IOException { serial.asDOMSerializer(); serial.serialize(element); } public static void serialize(Document document, XMLSerializer serial) throws IOException { serial.asDOMSerializer(); serial.serialize(document); } public static final boolean serialize(Document document, Writer w) throws IOException { return serialize(document, w, null); } public static final boolean serialize(Document document, Writer w, String encoding) throws IOException, IOException { if(document == null) return false; serialize(document, new XMLSerializer(w, createOutputFormat(encoding))); w.close(); return true; } public String asString(XModelObject object) { StringWriter w = new StringWriter(); Exception e = null; try { serialize(object, w); return w.toString(); } catch (XModelException e1) { e = e1; } catch (IOException e2) { e = e2; } ModelPlugin.getPluginLog().logError("XModelObjectLoaderUtil:asString:" + e.getMessage(), e); //$NON-NLS-1$ return ""; //$NON-NLS-1$ } public static final String getCDATA(Element elem) { return XMLUtilities.getCDATA(elem, true); } public static final String getCDATA(Element elem, boolean trim) { return XMLUtilities.getCDATA(elem, trim); } public static final String getComment(Element elem) { StringBuffer sb = new StringBuffer(); Node node = elem.getPreviousSibling(); loadComment(sb, node); return sb.toString(); } public static final String getFinalComment(Element elem) { StringBuffer sb = new StringBuffer(); NodeList nl = elem.getChildNodes(); if(nl == null || nl.getLength() == 0) return ""; //$NON-NLS-1$ Node node = nl.item(nl.getLength() - 1); loadComment(sb, node); return sb.toString(); } static final void loadComment(StringBuffer sb, Node node) { while (node != null) { if (node.getNodeType() == Node.ELEMENT_NODE) break; if (node.getNodeType() == Node.COMMENT_NODE) { if (sb.length() > 0) { sb.insert(0, '\n'); sb.insert(0, ((Comment) node).getData()); } else { sb.append(((Comment) node).getData()); } } node = node.getPreviousSibling(); } } public static final void setCDATA(Element element, String data) { if (data == null) data = ""; //$NON-NLS-1$ element.appendChild(element.getOwnerDocument().createCDATASection(data)); } public static final void setText(Element element, String data) { if (data == null) data = ""; //$NON-NLS-1$ element.appendChild(element.getOwnerDocument().createTextNode(data)); } public static final void setComment(Element element, String data) { if (data == null) data = ""; //$NON-NLS-1$ Comment comm = element.getOwnerDocument().createComment(data); element.getParentNode().insertBefore(comm, element); } public void load(File f, XModelObject o) { if(f == null || !f.isFile()) return; Element element = XMLUtil.getElement(f.getAbsolutePath()); if(element != null) { load(element, o); } } public boolean save(File f, XModelObject o) { if(f.exists() && !o.isModified()) return true; StringWriter w = new StringWriter(); Exception e = null; try { if(!serialize(o, w)) return false; } catch (XModelException e1) { e = e1; } catch (IOException e2) { e = e2; } if(e != null) { ModelPlugin.getPluginLog().logError("XModelObjectLoaderUtil:save(f,o):" + e.getMessage(), e); //$NON-NLS-1$ return false; } String r = w.toString(); boolean c = coincides(f, r); int i = (c) ? 0 : handleReadOnly(f, o); if(i != 0) return (i == 1); if(!c) writeFile(f, r); o.setModified(false); return true; } public static boolean saveBody(File f, XModelObject o, String defaultEncoding) { boolean same = FileUtil.isSameFile(f); if(same && !o.isModified()) return true; String r = getTempBody(o); boolean c = same && coincides(f, r); int i = (c) ? 0 : handleReadOnly(f, o); if(i != 0) return (i == 1); if(!c) { if(!FileUtil.writeFileWithEncodingCheck(f, r, defaultEncoding)) return false; } o.setModified(false); return true; } public static int handleReadOnly(File f, XModelObject o) { int i = 0; while(i == 0 && f.exists() && !f.canWrite()) i = o.getModel().getService().showDialog("Question", getReadOnlyMessage(f), new String[]{"Retry", "Discard", ModelMessages.Cancel}, null, ServiceDialog.QUESTION); return i; } public static String getReadOnlyMessage(File f) { return MessageFormat.format("Cannot save to read-only file {0}.", f.getAbsolutePath()); } public static String getTempBody(XModelObject o) { String b = o.get(XModelObjectConstants.ATTR_NAME__BODY_); o.set(XModelObjectConstants.ATTR_NAME__BODY_, ""); //$NON-NLS-1$ return b; } public static void setTempBody(XModelObject o, String body) { o.set(XModelObjectConstants.ATTR_NAME__BODY_, body); } //////pass correct properties! private static String expandString(String s) { return Paths.expand(s, System.getProperties()); } public static String readFile(String filename) { if(filename == null) return ""; //$NON-NLS-1$ return readFile(new File(expandString(filename))); } public static String readFile(File f) { return FileUtil.readFile(f); } public static boolean isTextFile(File f, int length) { return FileUtil.isTextFile(f, length); } public static boolean writeFile(String filename, String value) { if(filename == null) return false; return writeFile(new File(expandString(filename)), value); } public static boolean writeFile(File f, String value) { return FileUtil.writeFile(f, value); } public static boolean coincides(File f, String value) { return f.isFile() && value != null && readFile(f).equals(value); } public static XObjectLoader getObjectLoader(XModelObject object) { if(object == null) return null; return object.getModelEntity().getObjectLoader(); } public static void remove(File f) { FileUtil.remove(f); } public static final String getResourcePath(XModelObject object) { int t = object.getFileType(); if(t == XFileObject.SYSTEM) return ""; //$NON-NLS-1$ XModelObject p = object.getParent(); if(p == null) return null; String n = (t == XFileObject.FOLDER) ? object.get(XModelObjectConstants.XML_ATTR_NAME) : (t == XFileObject.FILE) ? FileAnyImpl.toFileName(object) : object.getPathPart(); String pp = getResourcePath(p); return (pp == null) ? n : pp + XModelObjectConstants.SEPARATOR + n; } /* * Multilined text may be saved as xml attribute value * by coding chars '\\', '\n' and '\t' * with strings "\\\\", "\\n" and "\\t" * Editor for this attribute uses load-method to present * true value of attribute and save-method to write * modified value. */ public static String loadFromXMLAttribute(String text) { StringBuffer sb = new StringBuffer(); char[] c = text.toCharArray(); boolean slash = false; for (int i = 0; i < c.length; i++) { if(!slash) { if(c[i] != '\\') { sb.append(c[i]); } else if(c[i] == '\\') { slash = true; } } else { slash = false; if(c[i] == '\\') sb.append('\\'); else if(c[i] == 'n') sb.append('\n'); else if(c[i] == 't') sb.append('\t'); else sb.append('\\').append(c[i]); } } return sb.toString(); } public static String saveToXMLAttribute(String text) { StringBuffer sb = new StringBuffer(); char[] c = text.toCharArray(); for (int i = 0; i < c.length; i++) { if(c[i] == '\r') continue; else if(c[i] == '\n') sb.append('\\').append('n'); else if(c[i] == '\\') sb.append('\\').append('\\'); else if(c[i] == '\t') sb.append('\\').append('t'); else sb.append(c[i]); } return sb.toString(); } // public static void updateModifiedOnSave(XModelObject o) { if(!o.isModified()) updateModifiedFlag(o.getParent()); } public static void updateModifiedFlag(XModelObject o) { if(o == null) return; XModelObject[] cs = o.getChildren(); for (int i = 0; i < cs.length; i++) if(cs[i].isModified()) return; o.setModified(false); updateModifiedFlag(o.getParent()); } protected void loadAnyElement(Element element, XModelObject o) { o.setAttributeValue("tag", element.getTagName()); //$NON-NLS-1$ loadAnyAtributes(element, o); String text = getAttribute(element, "#text").trim(); //$NON-NLS-1$ if(text.length() > 0) { while(text.startsWith("\n") || text.startsWith("\r")) text = text.substring(1); //$NON-NLS-1$ //$NON-NLS-2$ while(text.endsWith("\n") || text.endsWith("\r")) text = text.substring(0, text.length() - 1); //$NON-NLS-1$ //$NON-NLS-2$ o.setAttributeValue("text", text); //$NON-NLS-1$ } loadChildren(element, o); } public static void loadAnyAtributes(Element element, XModelObject o) { HashSet<String> attrs = new HashSet<String>(); XAttribute[] oas = o.getModelEntity().getAttributes(); for (XAttribute a: oas) { String xml = a.getXMLName(); if(xml != null && xml.length() > 0) attrs.add(xml); } StringBuffer sb = new StringBuffer(); NamedNodeMap as = element.getAttributes(); for (int i = 0; i < as.getLength(); i++) { Node n = as.item(i); String nm = n.getNodeName(); if(attrs.contains(nm)) continue; String v = n.getNodeValue(); if(v == null) continue; if(sb.length() > 0) sb.append(";"); //$NON-NLS-1$ sb.append(nm).append("=").append(v); //$NON-NLS-1$ } o.setAttributeValue("attributes", sb.toString()); //$NON-NLS-1$ } protected void saveAnyElement(Element parent, XModelObject o) { String xmlname = o.getAttributeValue("tag"); //$NON-NLS-1$ if(xmlname == null || xmlname.trim().length() == 0) return; if(namespace != null && namespace.length() > 0) { xmlname = namespace + ":" + xmlname; //$NON-NLS-1$ } Element element = XMLUtil.createElement(parent, xmlname); saveAnyAtributes(element, o); String text = o.getAttributeValue("text"); //$NON-NLS-1$ if(text != null && text.length() > 0) { saveAttribute(element, "#text", text); //$NON-NLS-1$ } XModelObject[] cs = o.getChildren(); for (int i = 0; i < cs.length; i++) { saveAnyElement(element, cs[i]); } } public static void saveAnyAtributes(Element element, XModelObject o) { String attrs = o.getAttributeValue("attributes"); //$NON-NLS-1$ StringTokenizer st = new StringTokenizer(attrs, ";"); //$NON-NLS-1$ while(st.hasMoreTokens()) { String t = st.nextToken(); int i = t.indexOf('='); if(i < 0) continue; String n = t.substring(0, i); String v = t.substring(i + 1); element.setAttribute(n, v); } } protected void eitherOr(Element element, String attr1, String attr2) { Element e1 = XMLUtil.getUniqueChild(element, attr1); Element e2 = XMLUtil.getUniqueChild(element, attr2); if(e1 != null && e2 != null) element.removeChild(e2); } protected void saveArray(Element element, String xmlname, String value) { String[] ns = XModelObjectUtil.asStringArray(value); if(namespaceMapping != null) { xmlname = namespaceMapping.convertToActual(xmlname); } if(namespace != null && namespace.length() > 0 && xmlname.indexOf(':') < 0) { xmlname = namespace + ":" + xmlname; //$NON-NLS-1$ } for (int i = 0; i < ns.length; i++) { Element c = XMLUtil.createElement(element, xmlname); saveAttribute(c, "#text", ns[i]); //$NON-NLS-1$ } } protected String loadArray(Element element, String xmlname) { Element[] es = XMLUtil.getChildren(element, xmlname); if(es == null || es.length == 0) return ""; //$NON-NLS-1$ StringBuffer sb = new StringBuffer(); for (int i = 0; i < es.length; i++) { if(i > 0) sb.append(","); //$NON-NLS-1$ sb.append(getAttribute(es[i], "#text")); //$NON-NLS-1$ } return sb.toString(); } public static void mergeAttributes(XModelObject destination, XModelObject source) throws XModelException { mergeAttributes(destination, source, destination.isActive()); } public static void mergeAttributes(XModelObject destination, XModelObject source, boolean fire) throws XModelException { XAttribute[] as = destination.getModelEntity().getAttributes(); for (int i = 0; i < as.length; i++) { String n = as[i].getName(); if(!as[i].isCopyable()) continue; mergeAttributeComment(destination, source, as[i], fire); String ov = destination.getAttributeValue(n); String nv = source.getAttributeValue(n); if(nv == null || (ov != null && ov.equals(nv))) continue; if(fire) { destination.getModel().changeObjectAttribute(destination, n, nv); } else { destination.setAttributeValue(n, nv); } } mergeFinalComment(destination, source, fire); String d = destination.get(XModelObjectImpl.DUPLICATE); if(d != null && d.length() > 0) destination.set(XModelObjectImpl.DUPLICATE, ""); } public static void mergeAttributeComment(XModelObject destination, XModelObject source, XAttribute attr, boolean fire) { String commentName = getAttributeCommentName(attr.getXMLName()); mergeComment(destination, source, commentName, fire); } private static String getAttributeCommentName(String xmlname) { if(xmlname != null && xmlname.indexOf('.') > 0 && !xmlname.endsWith("#comment")) { //$NON-NLS-1$ return xmlname + ".#comment"; //$NON-NLS-1$ } return null; } public static void mergeFinalComment(XModelObject destination, XModelObject source, boolean fire) { String commentName = "#final-comment"; //$NON-NLS-1$ mergeComment(destination, source, commentName, fire); } static void mergeComment(XModelObject destination, XModelObject source, String commentName, boolean fire) { if(commentName == null) return; String newComment = source.get(commentName); String oldComment = destination.get(commentName); String set = null; if(newComment == null || newComment.length() == 0) { if(oldComment != null && oldComment.length() > 0) { set = ""; //$NON-NLS-1$ } } else { if(oldComment == null || !oldComment.equals(newComment)) { set = newComment; } } if(set != null) { destination.set(commentName, set); if(fire) { XModelImpl impl = (XModelImpl)destination.getModel(); impl.fireNodeChanged(destination, destination.getPath()); } } } }