You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by fr...@apache.org on 2013/01/31 23:40:12 UTC

[1/6] git commit: refs/heads/javelin - CloudStack CLOUDSTACK-723 Enhanced baremetal servers support on Cisco UCS

CloudStack CLOUDSTACK-723
Enhanced baremetal servers support on Cisco UCS

introduce an python etree like xml helper.
Ok, this is not a new wheel. Frankly speaking, all Java XML API just suc**.
there are two popular types of XML API in java, one class is for data binding, JAXB,
XStream fall into this category. Another class is tree based, like JDOM, XOM ...

for XML api call, data binding library is painful as you have to specify the schema
that how xml stream converts to java object, which means you have to pre-define all
schemas(xsd file for JAXB, java object for XStream ...). This is not productive, because you
must add new schema when XML document grows.

Tree based library shines in this case, for it's able to dynamically create an object tree
from xml stream without any knowledge of its structure. However, all tree based
XML API library fall into below convention:

Element e = root.getChildElement("child1").getChildElement("child2").getChildElement("child3")...getChildElement("childN")

anything wrong with it???

the sadness is if there is no "child2", you will get a NPE with above code, which means you have to judge
before getting.

And, why so verbose?? why not:

Element e = root.child1.child2.child3...childN ???

Ok I am joking, it's impossible in Java the world knows Java is a static language.

but you can actually do:

Element e = root.get("child1.child2.child3");

or

List<Element> e = root.getAsList("child1.child2.child3")

this is known as XPath style(though XPATH use '/'), python etree has supported it.

so I did this toy for my UCS xml api call, it's quite like etree which is easy to use, for example:

<components.xml>
    <system-integrity-checker class="com.cloud.upgrade.DatabaseUpgradeChecker">
        <checker name="ManagementServerNode" class="com.cloud.cluster.ManagementServerNode"/>
        <checker name="EncryptionSecretKeyChecker" class="com.cloud.utils.crypt.EncryptionSecretKeyChecker"/>
        <checker name="DatabaseIntegrityChecker" class="com.cloud.upgrade.DatabaseIntegrityChecker"/>
        <checker name="DatabaseUpgradeChecker" class="com.cloud.upgrade.PremiumDatabaseUpgradeChecker"/>
    </system-integrity-checker>
</components.xml>

XmlObject xo = XmlObjectParser.parseFromFile("~/components.xml.in");
List<XmlObject> checkers = xo.getAsList("system-integrity-checker.checker");

then you get a list of XmlObject which represent each 'checker' element:

XmlObject firstChecker = checkers.get(0);
// firstChecker.get("name") == "ManagementServerNode"
// firstChecker.get("class") == "com.cloud.cluster.ManagementServerNode"
// firstChecker.getTag() == "checker"
// firstChecker.getText() == "" if it's <checker/>xxx</checker>, then getText() == "xxx"

example 2:
<checker name="ManagementServerNode" class="com.cloud.cluster.ManagementServerNode"/>
    <system-integrity-checker class="com.cloud.upgrade.DatabaseUpgradeChecker">
        <checker name="ManagementServerNode" class="com.cloud.cluster.ManagementServerNode"/>
    </system-integrity-checker>
</components.xml>

yout can do:

XmlObject xo = XmlObjectParser.parseFromFile("~/components.xml.in");
XmlObject checker = xo.get("system-integrity-checker.checker");

then it returns a single object as we only have one "checker" in xml stream,

or you still do

List<XmlObject> checkers = xo.getAsList("system-integrity-checker.checker");

it returns a list which only contains one element of "checker"

if you do:

XmlObject checker = xo.get("system-integrity-checker.checker.this_middle_element_doesnt_exist.some_element");

it returns a null without any exception, so you don't have to worry if a parent element is missing when getting a leaf element

again it's not a new wheel, I just hate JAVA xml api


Project: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/commit/53473c07
Tree: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/tree/53473c07
Diff: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/diff/53473c07

Branch: refs/heads/javelin
Commit: 53473c07b904dc97630d635dfac9d94c3c5c4f17
Parents: 339c09b
Author: frank <fr...@citrix.com>
Authored: Wed Jan 16 16:27:21 2013 -0800
Committer: frank <fr...@citrix.com>
Committed: Wed Jan 16 16:27:21 2013 -0800

----------------------------------------------------------------------
 .../utils/exception/CloudRuntimeException.java     |    6 +
 .../utils/exception/RuntimeCloudException.java     |    4 +
 utils/src/com/cloud/utils/xmlobject/XmlObject.java |  117 +++++++++++++++
 .../com/cloud/utils/xmlobject/XmlObjectParser.java |  107 +++++++++++++
 .../com/cloud/utils/xmlobject/TestXmlObject.java   |   29 ++++
 5 files changed, 263 insertions(+), 0 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/53473c07/utils/src/com/cloud/utils/exception/CloudRuntimeException.java
----------------------------------------------------------------------
diff --git a/utils/src/com/cloud/utils/exception/CloudRuntimeException.java b/utils/src/com/cloud/utils/exception/CloudRuntimeException.java
index 7807594..dabb715 100755
--- a/utils/src/com/cloud/utils/exception/CloudRuntimeException.java
+++ b/utils/src/com/cloud/utils/exception/CloudRuntimeException.java
@@ -16,6 +16,8 @@
 // under the License.
 package com.cloud.utils.exception;
 
+import java.io.FileNotFoundException;
+
 import com.cloud.utils.SerialVersionUID;
 
 /**
@@ -36,4 +38,8 @@ public class CloudRuntimeException extends RuntimeCloudException {
     protected CloudRuntimeException() {
         super();
     }
+
+    public CloudRuntimeException(Throwable t) {
+        super(t);
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/53473c07/utils/src/com/cloud/utils/exception/RuntimeCloudException.java
----------------------------------------------------------------------
diff --git a/utils/src/com/cloud/utils/exception/RuntimeCloudException.java b/utils/src/com/cloud/utils/exception/RuntimeCloudException.java
old mode 100644
new mode 100755
index a2de516..422d66c
--- a/utils/src/com/cloud/utils/exception/RuntimeCloudException.java
+++ b/utils/src/com/cloud/utils/exception/RuntimeCloudException.java
@@ -64,6 +64,10 @@ public class RuntimeCloudException extends RuntimeException {
         setCSErrorCode(CSExceptionErrorCode.getCSErrCode(this.getClass().getName()));
     }
 
+    public RuntimeCloudException(Throwable t) {
+        super(t);
+    }
+
     public ArrayList<String> getIdProxyList() {
         return idList;
     }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/53473c07/utils/src/com/cloud/utils/xmlobject/XmlObject.java
----------------------------------------------------------------------
diff --git a/utils/src/com/cloud/utils/xmlobject/XmlObject.java b/utils/src/com/cloud/utils/xmlobject/XmlObject.java
new file mode 100755
index 0000000..4ebf371
--- /dev/null
+++ b/utils/src/com/cloud/utils/xmlobject/XmlObject.java
@@ -0,0 +1,117 @@
+package com.cloud.utils.xmlobject;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.xml.sax.SAXException;
+
+import com.cloud.utils.exception.CloudRuntimeException;
+
+import edu.emory.mathcs.backport.java.util.Collections;
+
+public class XmlObject {
+    private Map<String, Object> elements = new HashMap<String, Object>();
+    private String text;
+    private String tag;
+    
+    XmlObject() {
+    }
+    
+    XmlObject putElement(String key, Object e) {
+        Object old = elements.get(key);
+        if (old == null) {
+            System.out.println(String.format("no %s, add new", key));
+            elements.put(key, e);
+        } else {
+            if (old instanceof List) {
+                System.out.println(String.format("already list %s, add", key));
+                ((List)old).add(e);
+            } else {
+                System.out.println(String.format("not list list %s, add list", key));
+                List lst = new ArrayList();
+                lst.add(old);
+                lst.add(e);
+                elements.put(key, lst);
+            }
+        }
+        
+        return this;
+    }
+    
+    private Object recurGet(XmlObject obj, Iterator<String> it) {
+        String key = it.next();
+        Object e = obj.elements.get(key);
+        if (!it.hasNext()) {
+            return e;
+        } else {
+            if (!(e instanceof XmlObject)) {
+                throw new CloudRuntimeException(String.format("%s doesn't reference to a XmlObject", it.next()));
+            }
+            return recurGet((XmlObject) e, it);
+        }
+    }
+    
+    public <T> T get(String elementStr) {
+        String[] strs = elementStr.split("\\.");
+        List<String> lst = new ArrayList<String>(strs.length);
+        Collections.addAll(lst, strs);
+        return (T)recurGet(this, lst.iterator());
+    }
+    
+    public <T> List<T> getAsList(String elementStr) {
+        Object e = get(elementStr);
+        if (e instanceof List) {
+            return (List<T>)e;
+        }
+        List lst = new ArrayList(1);
+        lst.add(e);
+        return lst;
+    }
+    
+    public String getText() {
+        return text;
+    }
+
+    void setText(String text) {
+        this.text = text;
+    }
+
+    public String getTag() {
+        return tag;
+    }
+
+    void setTag(String tag) {
+        this.tag = tag;
+    }
+    
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder("<" + tag);
+        for (Map.Entry<String, Object> e : elements.entrySet()) {
+            String key = e.getKey();
+            Object value = e.getValue();
+            if (!(value instanceof String)) {
+                continue;
+            }
+            sb.append(String.format(" %s=\"%s\"", key, value.toString()));
+        }
+        
+        if (text == null || "".equals(text.trim())) {
+            sb.append(" />");
+        } else {
+            sb.append(">").append(text).append(String.format("</ %s>", tag));
+        }
+        return sb.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/53473c07/utils/src/com/cloud/utils/xmlobject/XmlObjectParser.java
----------------------------------------------------------------------
diff --git a/utils/src/com/cloud/utils/xmlobject/XmlObjectParser.java b/utils/src/com/cloud/utils/xmlobject/XmlObjectParser.java
new file mode 100755
index 0000000..68a822f
--- /dev/null
+++ b/utils/src/com/cloud/utils/xmlobject/XmlObjectParser.java
@@ -0,0 +1,107 @@
+package com.cloud.utils.xmlobject;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.util.Stack;
+
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import com.cloud.utils.exception.CloudRuntimeException;
+
+public class XmlObjectParser {
+    final private InputStream is;
+
+    private class XmlHandler extends DefaultHandler {
+        private Stack<XmlObject> stack;
+        private String currentValue;
+        private XmlObject root;
+
+        XmlHandler() {
+            stack = new Stack<XmlObject>();
+        }
+
+        @Override
+        public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
+            //System.out.println(String.format("startElement: namespaceURI:%s, localName:%s, qName:%s", namespaceURI, localName, qName));
+            currentValue = null;
+            XmlObject obj = new XmlObject();
+            for (int i=0; i<atts.getLength(); i++) {
+                obj.putElement(atts.getQName(i), atts.getValue(i));
+            }
+            obj.setTag(qName);
+            if (!stack.isEmpty()) {
+                XmlObject parent = stack.peek();
+                parent.putElement(qName, obj);
+            }
+            stack.push(obj);
+        }
+
+        @Override
+        public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
+            XmlObject currObj = stack.pop();
+            if (currentValue != null) {
+                currObj.setText(currentValue);
+            }
+            
+            if (stack.isEmpty()) {
+                root = currObj;
+            }
+            
+            //System.out.println(String.format("endElement: namespaceURI:%s, localName:%s, qName:%s", namespaceURI, localName, qName));
+        }
+        
+        @Override
+        public void characters(char[] ch, int start, int length) throws SAXException {
+            StringBuilder str = new StringBuilder();
+            str.append(ch, start, length);
+            currentValue = str.toString();
+            //System.out.println(String.format("characters: %s", str.toString()));
+        }
+        
+        XmlObject getRoot() {
+            return root;
+        }
+    }
+
+    private XmlObjectParser(InputStream is) {
+        super();
+        this.is = is;
+    }
+
+    public static XmlObject parseFromFile(String filePath) {
+        FileInputStream fs;
+        try {
+            fs = new FileInputStream(new File(filePath));
+            XmlObjectParser p = new XmlObjectParser(fs);
+            return p.parse();
+        } catch (FileNotFoundException e) {
+            throw new CloudRuntimeException(e);
+        }
+    }
+    
+    public static XmlObject parseFromString(String xmlString) {
+        InputStream stream = new ByteArrayInputStream(xmlString.getBytes());
+        XmlObjectParser p = new XmlObjectParser(stream);
+        return p.parse();
+    }
+
+    private XmlObject parse() {
+        SAXParserFactory spfactory = SAXParserFactory.newInstance();
+        try {
+            SAXParser saxParser = spfactory.newSAXParser();
+            XmlHandler handler = new XmlHandler();
+            saxParser.parse(is, handler);
+            return handler.getRoot();
+        } catch (Exception e) {
+            throw new CloudRuntimeException(e);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/53473c07/utils/test/com/cloud/utils/xmlobject/TestXmlObject.java
----------------------------------------------------------------------
diff --git a/utils/test/com/cloud/utils/xmlobject/TestXmlObject.java b/utils/test/com/cloud/utils/xmlobject/TestXmlObject.java
new file mode 100755
index 0000000..f94c68c
--- /dev/null
+++ b/utils/test/com/cloud/utils/xmlobject/TestXmlObject.java
@@ -0,0 +1,29 @@
+package com.cloud.utils.xmlobject;
+
+import static org.junit.Assert.*;
+
+import java.util.List;
+
+import org.junit.Test;
+
+public class TestXmlObject {
+
+    void p(String str) {
+        System.out.println(str);
+    }
+    
+    @Test
+    public void test() {
+        XmlObject xo = XmlObjectParser.parseFromFile("z:/components.xml.in");
+        p(xo.getTag());
+        p((String) xo.get("system-integrity-checker.checker").toString());
+        List<XmlObject> lst = xo.get("management-server.adapters");
+        for (XmlObject x : lst) {
+            List<XmlObject> lst1 = x.getAsList("adapter");
+            for (XmlObject y : lst1) {
+                p(y.toString());
+            }
+        }
+    }
+
+}