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.text.MessageFormat;
21  import java.util.Arrays;
22  import java.util.HashSet;
23  import java.util.LinkedList;
24  import java.util.List;
25  import java.util.Set;
26  import org.w3c.dom.Document;
27  import org.w3c.dom.Element;
28  import org.w3c.dom.Node;
29  import org.w3c.dom.NodeList;
30  import at.ac.tuwien.infosys.sm4all.copal.api.event.ContextEvent;
31  import at.ac.tuwien.infosys.sm4all.copal.api.event.ContextEventAction;
32  import at.ac.tuwien.infosys.sm4all.copal.api.event.CurrentAction;
33  import at.ac.tuwien.infosys.sm4all.copal.api.event.ProcessedAction;
34  import at.ac.tuwien.infosys.sm4all.copal.api.event.UnprocessedAction;
35  import at.ac.tuwien.infosys.sm4all.copal.api.util.Constants;
36  import at.ac.tuwien.infosys.sm4all.copal.api.util.FailedUnmarshallingException;
37  import at.ac.tuwien.infosys.sm4all.copal.api.util.InvalidFieldValueException;
38  import at.ac.tuwien.infosys.sm4all.copal.api.util.MissingFieldException;
39  
40  /**
41   * The COPAL element for the event's actions,
42   * 
43   * @author sanjin
44   */
45  public class Actions extends ConcreteElement<ContextEventAction[]> {
46  
47      private static final Set<String> ACTION_LOCAL_NAMES = new HashSet<String>(
48              Arrays.asList(new String[]{ "UnprocessedAction", "CurrentAction",
49                      "ProcessedAction" }));
50  
51      @Override
52      protected ContextEventAction[] retrieve(final Element element)
53              throws FailedUnmarshallingException {
54          if (element == null)
55              throw new NullPointerException("XML DOM element cannot be null.");
56  
57          final NodeList children = element.getChildNodes();
58          final List<ContextEventAction> result = new LinkedList<ContextEventAction>();
59  
60          for (int i = 0; i < children.getLength(); i++) {
61              final Node child = children.item(i);
62              if ((child.getNodeType() == Node.ELEMENT_NODE)
63                      && (Constants.COPAL_NAMESPACE.equals(child.getNamespaceURI()))
64                      && (ACTION_LOCAL_NAMES.contains(child.getLocalName()))) {
65                  final ContextEventAction action = retrieveAction((Element) child);
66                  if (action != null)
67                      result.add(action);
68              } else if (child.getNodeType() == Node.TEXT_NODE)
69                  throw new InvalidFieldValueException(MessageFormat.format(
70                          "Unknown action ''{0}''.", child.getTextContent()));
71              else if (child.getNodeType() == Node.ELEMENT_NODE)
72                  throw new InvalidFieldValueException(MessageFormat.format(
73                          "Unknown action ''{0}''.", child.getLocalName()));
74          }
75  
76          return result.toArray(new ContextEventAction[result.size()]);
77      }
78  
79      @Override
80      public void update(final Element element, final ContextEvent event) {
81          if (element == null)
82              throw new NullPointerException("XML DOM element cannot be null.");
83          if (event == null)
84              throw new NullPointerException("Context event cannot be null.");
85  
86          // remove all children
87          while (element.hasChildNodes())
88              element.removeChild(element.getFirstChild());
89  
90          final Document document = element.getOwnerDocument();
91  
92          // add action elements
93          for (final ContextEventAction action : event.getActions())
94              element.appendChild(createActionElement(document, action));
95      }
96  
97      private ContextEventAction retrieveAction(final Element element)
98              throws FailedUnmarshallingException {
99          final ContextEventAction result;
100 
101         if (!element.hasAttribute("name"))
102             throw new MissingFieldException("Action name");
103 
104         final String name = element.getAttribute("name");
105 
106         if (name.trim().isEmpty())
107             throw new InvalidFieldValueException(
108                     "Action name is empty or blank.");
109 
110         if ("UnprocessedAction".equals(element.getLocalName()))
111             result = retrieveUnprocessedAction(name, element);
112         else if ("CurrentAction".equals(element.getLocalName()))
113             result = retrieveCurrentAction(name, element);
114         else if ("ProcessedAction".equals(element.getLocalName()))
115             result = retrieveProcessedAction(name, element);
116         else
117             throw new FailedUnmarshallingException(MessageFormat.format(
118                     "Unknown action ''{0}''.", element.getLocalName()));
119 
120         return result;
121     }
122 
123     private UnprocessedAction retrieveUnprocessedAction(final String name,
124             final Element element) throws FailedUnmarshallingException {
125         if (!element.hasAttribute("required"))
126             throw new MissingFieldException("Action requirement");
127 
128         final String required = element.getAttribute("required").trim();
129 
130         if (!required.equalsIgnoreCase("true")
131                 && !required.equalsIgnoreCase("false"))
132             throw new InvalidFieldValueException(
133                     "Action requirement is not true or false.");
134 
135         return new UnprocessedAction(name, Boolean.valueOf(required));
136     }
137 
138     private CurrentAction retrieveCurrentAction(final String name,
139             final Element element) throws FailedUnmarshallingException {
140         if (!element.hasAttribute("required"))
141             throw new MissingFieldException("Action requirement");
142 
143         final String required = element.getAttribute("required").trim();
144 
145         if (!required.equalsIgnoreCase("true")
146                 && !required.equalsIgnoreCase("false"))
147             throw new InvalidFieldValueException(
148                     "Action requirement is not true or false.");
149 
150         final CurrentAction result = new CurrentAction(name,
151                 Boolean.valueOf(required));
152 
153         if (!hasBlankContent(element)) {
154             final NodeList children = element.getChildNodes();
155             for (int i = 0; i < children.getLength(); i++) {
156                 final Node child = children.item(i);
157                 if ((child.getNodeType() == Node.ELEMENT_NODE)
158                         && (Constants.COPAL_NAMESPACE.equals(child.getNamespaceURI()))
159                         && ("ProcessedBy".equals(child.getLocalName()))) {
160                     final Element processor = (Element) child;
161                     if (!processor.hasAttribute("processor"))
162                         throw new MissingFieldException("Processor name");
163 
164                     final String processorName = processor.getAttribute("processor");
165 
166                     if (processorName.trim().isEmpty())
167                         throw new InvalidFieldValueException(
168                                 "Processor name is empty or blank.");
169 
170                     result.processedBy(processorName);
171                 } else if (child.getNodeType() == Node.TEXT_NODE)
172                     throw new InvalidFieldValueException(MessageFormat.format(
173                             "Unknown processor ''{0}''.",
174                             child.getTextContent()));
175                 else if (child.getNodeType() == Node.ELEMENT_NODE)
176                     throw new InvalidFieldValueException(MessageFormat.format(
177                             "Unknown processor ''{0}''.", child.getLocalName()));
178             }
179         }
180 
181         return result;
182     }
183 
184     private ProcessedAction retrieveProcessedAction(final String name,
185             final Element element) throws FailedUnmarshallingException {
186         final List<String> processedBy = new LinkedList<String>();
187 
188         if (!hasBlankContent(element)) {
189             final NodeList children = element.getChildNodes();
190             for (int i = 0; i < children.getLength(); i++) {
191                 final Node child = children.item(i);
192                 if ((child.getNodeType() == Node.ELEMENT_NODE)
193                         && (Constants.COPAL_NAMESPACE.equals(child.getNamespaceURI()))
194                         && ("ProcessedBy".equals(child.getLocalName()))) {
195                     final Element processor = (Element) child;
196                     if (!processor.hasAttribute("processor"))
197                         throw new MissingFieldException("Processor name");
198 
199                     final String processorName = processor.getAttribute("processor");
200 
201                     if (processorName.trim().isEmpty())
202                         throw new InvalidFieldValueException(
203                                 "Processor name is empty or blank.");
204 
205                     processedBy.add(processorName);
206                 } else if (child.getNodeType() == Node.TEXT_NODE)
207                     throw new InvalidFieldValueException(MessageFormat.format(
208                             "Unknown processor ''{0}''.",
209                             child.getTextContent()));
210                 else if (child.getNodeType() == Node.ELEMENT_NODE)
211                     throw new InvalidFieldValueException(MessageFormat.format(
212                             "Unknown processor ''{0}''.", child.getLocalName()));
213             }
214         }
215 
216         return new ProcessedAction(name,
217                 processedBy.toArray(new String[processedBy.size()]));
218     }
219 
220     private Element createActionElement(final Document document,
221             final ContextEventAction action) {
222         Element result = null;
223 
224         if (action instanceof UnprocessedAction)
225             result = createActionElement(document, (UnprocessedAction) action);
226         else if (action instanceof CurrentAction)
227             result = createActionElement(document, (CurrentAction) action);
228         else if (action instanceof ProcessedAction)
229             result = createActionElement(document, (ProcessedAction) action);
230 
231         return result;
232     }
233 
234     private Element createActionElement(final Document document,
235             final UnprocessedAction action) {
236         final Element result = document.createElementNS(
237                 Constants.COPAL_NAMESPACE, Constants.COPAL_PREFIX
238                         + ":UnprocessedAction");
239 
240         result.setAttribute("name", action.getName());
241         result.setAttribute("required", String.valueOf(action.isRequried()));
242 
243         return result;
244     }
245 
246     private Element createActionElement(final Document document,
247             final CurrentAction action) {
248         final Element result = document.createElementNS(
249                 Constants.COPAL_NAMESPACE, Constants.COPAL_PREFIX
250                         + ":CurrentAction");
251 
252         result.setAttribute("name", action.getName());
253         result.setAttribute("required", String.valueOf(action.isRequried()));
254 
255         for (final String processor : action.getProcessedBy()) {
256             final Element processedBy = document.createElementNS(
257                     Constants.COPAL_NAMESPACE, Constants.COPAL_PREFIX
258                             + ":ProcessedBy");
259             processedBy.setAttribute("processor", processor);
260             result.appendChild(processedBy);
261         }
262 
263         return result;
264     }
265 
266     private Element createActionElement(final Document document,
267             final ProcessedAction action) {
268         final Element result = document.createElementNS(
269                 Constants.COPAL_NAMESPACE, Constants.COPAL_PREFIX
270                         + ":ProcessedAction");
271 
272         result.setAttribute("name", action.getName());
273 
274         for (final String processor : action.getProcessedBy()) {
275             final Element processedBy = document.createElementNS(
276                     Constants.COPAL_NAMESPACE, Constants.COPAL_PREFIX
277                             + ":ProcessedBy");
278             processedBy.setAttribute("processor", processor);
279             result.appendChild(processedBy);
280         }
281 
282         return result;
283     }
284 
285     private static boolean hasBlankContent(final Node node) {
286         final NodeList children = node.getChildNodes();
287 
288         return (children.getLength() == 0)
289                 || ((children.getLength() == 1)
290                         && (children.item(0).getNodeType() == Node.TEXT_NODE) && (children.item(
291                         0).getTextContent().trim().isEmpty()));
292     }
293 
294     /**
295      * Singleton instance.
296      */
297     public static final Actions INSTANCE = new Actions();
298 
299     private Actions() {
300         super(String[].class);
301     }
302 }