View Javadoc

1   /* This file is part of COPAL (COntext Provisioning for All).
2    *
3    * COPAL is a part of SM4All (Smart hoMes for All) project.
4    *
5    * COPAL is free software: you can redistribute it and/or modify
6    * it under the terms of the GNU Lesser General Public License as published by
7    * the Free Software Foundation, either version 3 of the License, or
8    * (at your option) any later version.
9    *
10   * COPAL is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU Lesser General Public License for more details.
14   *
15   * You should have received a copy of the GNU Lesser General Public License
16   * along with COPAL. If not, see <http://www.gnu.org/licenses/>.
17   */
18  package at.ac.tuwien.infosys.sm4all.copal.api.event.xml;
19  
20  import java.util.Iterator;
21  import javax.xml.XMLConstants;
22  import javax.xml.namespace.NamespaceContext;
23  import javax.xml.xpath.XPath;
24  import javax.xml.xpath.XPathConstants;
25  import javax.xml.xpath.XPathExpression;
26  import javax.xml.xpath.XPathExpressionException;
27  import javax.xml.xpath.XPathFactory;
28  import org.w3c.dom.Document;
29  import org.w3c.dom.Element;
30  import org.w3c.dom.Node;
31  import at.ac.tuwien.infosys.sm4all.copal.api.Constants;
32  import at.ac.tuwien.infosys.sm4all.copal.api.event.ContextEvent;
33  
34  /**
35   * The interface which all COPAL elements that are injected and/or can be
36   * retrieved from a XML DOM document generated by {@link XMLContextEvent}.
37   * 
38   * @param <T> the class of element's value.
39   * @author sanjin
40   */
41  public abstract class COPALElement<T> {
42  
43      private static final XPathFactory XPATH_FACTORY = XPathFactory.newInstance();
44      private static final COPALNamespaceContext NAMESPACE_CONTEXT = new COPALNamespaceContext();
45  
46      private final Class<?> type;
47      private final String qualifiedName;
48      private final XPathExpression xPathExpression;
49  
50      /**
51       * @param type the XML type of this COPAL element returned by the xPath.
52       */
53      protected COPALElement(final Class<?> type) {
54          super();
55          this.type = type;
56          this.qualifiedName = Constants.COPAL_PREFIX + ":"
57                  + getClass().getSimpleName();
58          this.xPathExpression = createXPathExpression(getXPath());
59      }
60  
61      /**
62       * Retrieve the value of this element from specified XML DOM element.
63       * 
64       * @param element the XML DOM element.
65       * @return the value of this property.
66       */
67      protected abstract T retrieve(Element element);
68  
69      /**
70       * Update specified XML DOM element with value retrieved from specified
71       * {@link ContextEvent}.
72       * 
73       * @param element the XML DOM element to update.
74       * @param event the {@link ContextEvent}.
75       */
76      public abstract void update(Element element, ContextEvent event);
77  
78      /**
79       * @return the qualified name of this COPAL element.
80       */
81      public String getQualifiedName() {
82          return this.qualifiedName;
83      }
84  
85      /**
86       * @return the XPath which can be used to retrieve the value of this COPAL
87       *         element from a XML DOM document.
88       */
89      public String getXPath() {
90          return "//" + getQualifiedName();
91      }
92  
93      /**
94       * @return the XML type of this COPAL element returned by the xPath.
95       */
96      public Class<?> getXMLType() {
97          return this.type;
98      }
99  
100     /**
101      * Creates a XML DOM element with namespace URI set to
102      * {@link Constants#COPAL_NAMESPACE_URI} and qualified name set to
103      * {@link #getQualifiedName()} and updated using the
104      * {@link #update(Element, ContextEvent)} method.
105      * 
106      * @param document the XML DOM document used to create the XML DOM element.
107      * @param event the {@link ContextEvent} to use for updating the XML DOM
108      *        element.
109      * @return the XML DOM element.
110      */
111     public Element createElement(final Document document,
112             final ContextEvent event) {
113         if (document == null)
114             throw new NullPointerException("XML DOM document cannot be null.");
115         if (event == null)
116             throw new NullPointerException("Context event cannot be null.");
117 
118         final Element result = document.createElementNS(
119                 Constants.COPAL_NAMESPACE_URI, getQualifiedName());
120 
121         update(result, event);
122 
123         return result;
124     }
125 
126     /**
127      * Retrieve the value of this element from specified XML DOM document.
128      * 
129      * @param document the XML DOM element.
130      * @return the value of this property.
131      */
132     public T retrieve(final Document document) {
133         if (document == null)
134             throw new NullPointerException("XML DOM document cannot be null.");
135 
136         T result = null;
137 
138         final Element element = getElement(document);
139         if (element != null)
140             result = retrieve(element);
141 
142         return result;
143     }
144 
145     /**
146      * Get the XML DOM element of this COPAL element in specified XML DOM
147      * document.
148      * 
149      * @param document the XML DOM document.
150      * @return the first element that matches or <code>null</code>.
151      */
152     public Element getElement(final Document document) {
153         if (document == null)
154             throw new NullPointerException("XML DOM document cannot be null.");
155 
156         Element result = null;
157 
158         try {
159             final Node node = (Node) this.xPathExpression.evaluate(document,
160                     XPathConstants.NODE);
161             if ((node != null) && (node.getNodeType() == Node.ELEMENT_NODE))
162                 result = (Element) node;
163         } catch (final XPathExpressionException ex) {
164             /* ignore and return null */
165         }
166 
167         return result;
168     }
169 
170     /**
171      * @return the XPath expression created from the {@link #getXPath()}.
172      */
173     protected XPathExpression getExpression() {
174         return this.xPathExpression;
175     }
176 
177     private static XPathExpression createXPathExpression(final String expression) {
178         final XPath xPath = XPATH_FACTORY.newXPath();
179         XPathExpression result = null;
180 
181         xPath.setNamespaceContext(NAMESPACE_CONTEXT);
182         try {
183             result = xPath.compile(expression);
184         } catch (final XPathExpressionException ex) {
185             /* ignore and return null */
186         }
187 
188         return result;
189     }
190 
191     private static class COPALNamespaceContext implements NamespaceContext {
192 
193         public COPALNamespaceContext() {
194             super();
195         }
196 
197         @Override
198         public Iterator<?> getPrefixes(final String namespaceURI) {
199             throw new UnsupportedOperationException();
200         }
201 
202         @Override
203         public String getPrefix(final String namespaceURI) {
204             throw new UnsupportedOperationException();
205         }
206 
207         @Override
208         public String getNamespaceURI(final String prefix) {
209             if (Constants.COPAL_PREFIX.equals(prefix))
210                 return Constants.COPAL_NAMESPACE_URI;
211 
212             return XMLConstants.NULL_NS_URI;
213         }
214     }
215 }