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.type;
19  
20  import java.util.Arrays;
21  import java.util.LinkedList;
22  import java.util.List;
23  import org.w3c.dom.Element;
24  import at.ac.tuwien.infosys.sm4all.copal.api.event.ContextEventType;
25  import at.ac.tuwien.infosys.sm4all.copal.api.event.DefaultAction;
26  import at.ac.tuwien.infosys.sm4all.copal.api.security.Authorization;
27  import at.ac.tuwien.infosys.sm4all.copal.api.util.Attribute;
28  import at.ac.tuwien.infosys.sm4all.copal.api.util.FailedUnmarshallingException;
29  import at.ac.tuwien.infosys.sm4all.copal.api.util.MissingFieldException;
30  import at.ac.tuwien.infosys.sm4all.copal.api.util.Unmarshaller;
31  import at.ac.tuwien.infosys.sm4all.copal.api.xml.Append;
32  import at.ac.tuwien.infosys.sm4all.copal.api.xml.BaseUnmarshallerBuilder;
33  import at.ac.tuwien.infosys.sm4all.copal.api.xml.ElementUnmarshaller;
34  import at.ac.tuwien.infosys.sm4all.copal.api.xml.InsertAfter;
35  import at.ac.tuwien.infosys.sm4all.copal.api.xml.InsertBefore;
36  import at.ac.tuwien.infosys.sm4all.copal.api.xml.IntegerAttribute;
37  import at.ac.tuwien.infosys.sm4all.copal.api.xml.ListUnmarshaller;
38  import at.ac.tuwien.infosys.sm4all.copal.api.xml.LongAttribute;
39  import at.ac.tuwien.infosys.sm4all.copal.api.xml.Optional;
40  import at.ac.tuwien.infosys.sm4all.copal.api.xml.StringAttribute;
41  import static at.ac.tuwien.infosys.sm4all.copal.api.event.ContextEventType.PRIORITY_DEFAULT;
42  import static at.ac.tuwien.infosys.sm4all.copal.api.event.ContextEventType.TTL_DEFAULT;
43  
44  /**
45   * Unmarshalls and marshalls a {@link ContextEventType} from/into an
46   * {@link Element}.
47   * 
48   * @author sanjin
49   */
50  public class ContextEventTypeUnmarshaller implements
51          Unmarshaller<ContextEventType> {
52  
53      /**
54       * The local name of child {@link Element}s used in the
55       * {@link ListUnmarshaller.Builder} that is returned by the
56       * {@link #getListBuilder()}.
57       */
58      public static final String EVENT_TYPE_ELEMENT = "Event";
59      /**
60       * The name of attribute that holds marshalled name.
61       */
62      public static final String NAME_ATTRIBUTE = "name";
63      /**
64       * The name of attribute that holds marshalled time-to-live.
65       */
66      public static final String TTL_ATTRIBUTE = "ttl";
67      /**
68       * The name of attribute that holds marshalled priority.
69       */
70      public static final String PRIORITY_ATTRIBUTE = "priority";
71      /**
72       * The local name of child {@link Element} that holds marshalled
73       * {@link Attribute}s.
74       */
75      public static final String ATTRIBUTES_ELEMENT = "Attributes";
76      /**
77       * The local name of child {@link Element} that holds marshalled
78       * {@link Authorization}s.
79       */
80      public static final String AUTHORIZATIONS_ELEMENT = "Authorizations";
81      /**
82       * The local name of child {@link Element} that holds marshalled
83       * {@link DefaultAction}s.
84       */
85      public static final String ACTIONS_ELEMENT = "Actions";
86  
87      private static final ListUnmarshaller.Builder<ContextEventType> LIST_BUILDER = new ListUnmarshaller.Builder<ContextEventType>().withChildName(
88              EVENT_TYPE_ELEMENT).withBuilder(new Builder()).withStrategy(
89              new Append());
90  
91      private final Element element;
92      private final Unmarshaller<String> name;
93      private final Unmarshaller<Long> ttl;
94      private final Unmarshaller<Integer> priority;
95      private final Unmarshaller<List<Attribute>> attributes;
96      private final Unmarshaller<List<Authorization>> authorizations;
97      private final Unmarshaller<List<DefaultAction>> actions;
98  
99      /**
100      * Creates instance of {@link ContextEventType} {@link Unmarshaller} which
101      * uses specified {@link Element} for unmarshalling and/or marshalling.
102      * 
103      * @param element the {@link Element} used for unmarshalling and
104      *        marshalling.
105      * @throws NullPointerException if specified {@link Element} is
106      *         <code>null</code>.
107      */
108     public ContextEventTypeUnmarshaller(final Element element) {
109         super();
110 
111         if (element == null)
112             throw new NullPointerException("XML DOM element cannot be null.");
113 
114         this.element = element;
115         this.name = new StringAttribute(NAME_ATTRIBUTE, element);
116         this.ttl = new Optional<Long>(new LongAttribute(TTL_ATTRIBUTE, element));
117         this.priority = new Optional<Integer>(new IntegerAttribute(
118                 PRIORITY_ATTRIBUTE, element));
119         this.attributes = new ElementUnmarshaller<List<Attribute>>(element,
120                 ATTRIBUTES_ELEMENT, AttributeUnmarshaller.getListBuilder(),
121                 new InsertBefore(AUTHORIZATIONS_ELEMENT, new InsertBefore(
122                         ACTIONS_ELEMENT, new Append())));
123         this.authorizations = new ElementUnmarshaller<List<Authorization>>(
124                 element, AUTHORIZATIONS_ELEMENT,
125                 AuthorizationUnmarshaller.getListBuilder(), new InsertBefore(
126                         ACTIONS_ELEMENT, new InsertAfter(ATTRIBUTES_ELEMENT,
127                                 new Append())));
128         this.actions = new ElementUnmarshaller<List<DefaultAction>>(element,
129                 ACTIONS_ELEMENT, DefaultActionUnmarshaller.getListBuilder(),
130                 new InsertAfter(AUTHORIZATIONS_ELEMENT, new InsertAfter(
131                         ATTRIBUTES_ELEMENT, new Append())));
132     }
133 
134     /**
135      * Returns the {@link Element} used for unmarshalling and marshalling.
136      * 
137      * @return the {@link Element} used for unmarshalling and marshalling.
138      */
139     public Element getElement() {
140         return this.element;
141     }
142 
143     /**
144      * Unmarshalls an {@link ContextEventType} from the {@link Element}.
145      * 
146      * @return the unmarshalled {@link ContextEventType}.
147      * @throws FailedUnmarshallingException if unmarshalling was unsuccessful.
148      */
149     @Override
150     public ContextEventType unmarshal() throws FailedUnmarshallingException {
151         final ContextEventType result = new ContextEventType(unmarshalName());
152 
153         result.setTTL(unmarshalTTL());
154         result.setPriority(unmarshalPriority());
155         for (final Attribute attribute : unmarshalAttributes())
156             result.setAttribute(attribute.getName(), attribute.getValue());
157         for (final Authorization authorization : unmarshalAuthorizations())
158             result.addAuthorization(authorization);
159         result.appendActions(unmarshalActions());
160 
161         return result;
162     }
163 
164     /**
165      * Unmarshalls name of {@link ContextEventType} from the {@link Element}.
166      * 
167      * @return the name of marshalled {@link ContextEventType}.
168      * @throws FailedUnmarshallingException if unmarshalling was unsuccessful.
169      */
170     public String unmarshalName() throws FailedUnmarshallingException {
171         final String result;
172 
173         try {
174             result = this.name.unmarshal();
175         } catch (final MissingFieldException ex) {
176             throw new MissingFieldException("Event name", ex);
177         }
178 
179         return result;
180     }
181 
182     /**
183      * Unmarshalls time-to-live of {@link ContextEventType} from the
184      * {@link Element}. If the time-to-live value is missing then the
185      * {@link ContextEventType#TTL_DEFAULT} is returned.
186      * 
187      * @return the time-to-live of marshalled {@link ContextEventType}.
188      * @throws FailedUnmarshallingException if unmarshalling was unsuccessful.
189      */
190     public long unmarshalTTL() throws FailedUnmarshallingException {
191         Long result = this.ttl.unmarshal();
192 
193         if (result == null)
194             result = TTL_DEFAULT;
195 
196         return result;
197     }
198 
199     /**
200      * Unmarshalls priority of {@link ContextEventType} from the {@link Element}
201      * . If the priority value is missing then the
202      * {@link ContextEventType#PRIORITY_DEFAULT} is returned.
203      * 
204      * @return the priority of marshalled {@link ContextEventType}.
205      * @throws FailedUnmarshallingException if unmarshalling was unsuccessful.
206      */
207     public int unmarshalPriority() throws FailedUnmarshallingException {
208         Integer result = this.priority.unmarshal();
209 
210         if (result == null)
211             result = PRIORITY_DEFAULT;
212 
213         return result;
214     }
215 
216     /**
217      * Unmarshalls {@link Attribute}s of {@link ContextEventType} from the
218      * {@link Element}.
219      * 
220      * @return the {@link Attribute}s of marshalled {@link ContextEventType}.
221      * @throws FailedUnmarshallingException if unmarshalling was unsuccessful.
222      */
223     public Attribute[] unmarshalAttributes()
224             throws FailedUnmarshallingException {
225         List<Attribute> result;
226 
227         try {
228             result = this.attributes.unmarshal();
229         } catch (final MissingFieldException ex) {
230             if (ATTRIBUTES_ELEMENT.equals(ex.getFieldName()))
231                 result = new LinkedList<Attribute>();
232             else
233                 throw ex;
234         }
235 
236         return result.toArray(new Attribute[result.size()]);
237     }
238 
239     /**
240      * Unmarshalls {@link Authorization}s of {@link ContextEventType} from the
241      * {@link Element}.
242      * 
243      * @return the {@link Authorization}s of marshalled {@link ContextEventType}
244      *         .
245      * @throws FailedUnmarshallingException if unmarshalling was unsuccessful.
246      */
247     public Authorization[] unmarshalAuthorizations()
248             throws FailedUnmarshallingException {
249         List<Authorization> result;
250 
251         try {
252             result = this.authorizations.unmarshal();
253         } catch (final MissingFieldException ex) {
254             if (AUTHORIZATIONS_ELEMENT.equals(ex.getFieldName()))
255                 result = new LinkedList<Authorization>();
256             else
257                 throw ex;
258         }
259 
260         return result.toArray(new Authorization[result.size()]);
261     }
262 
263     /**
264      * Unmarshalls {@link DefaultAction}s of {@link ContextEventType} from the
265      * {@link Element}.
266      * 
267      * @return the {@link DefaultAction}s of marshalled {@link ContextEventType}
268      *         .
269      * @throws FailedUnmarshallingException if unmarshalling was unsuccessful.
270      */
271     public DefaultAction[] unmarshalActions()
272             throws FailedUnmarshallingException {
273         List<DefaultAction> result;
274 
275         try {
276             result = this.actions.unmarshal();
277         } catch (final MissingFieldException ex) {
278             if (ACTIONS_ELEMENT.equals(ex.getFieldName()))
279                 result = new LinkedList<DefaultAction>();
280             else
281                 throw ex;
282         }
283 
284         return result.toArray(new DefaultAction[result.size()]);
285     }
286 
287     /**
288      * Marshalls specified {@link ContextEventType} into the {@link Element}.
289      * 
290      * @param eventType the {@link ContextEventType}.
291      * @throws NullPointerException if specified {@link ContextEventType} is
292      *         <code>null</code>.
293      */
294     @SuppressWarnings("hiding")
295     @Override
296     public void marshal(final ContextEventType eventType) {
297         if (eventType == null)
298             throw new NullPointerException("Event type cannot be null.");
299 
300         this.name.marshal(eventType.getName());
301         final long ttl = eventType.getTTL();
302         if (ttl == TTL_DEFAULT)
303             this.ttl.remove();
304         else
305             this.ttl.marshal(eventType.getTTL());
306         final int priority = eventType.getPriority();
307         if (priority == PRIORITY_DEFAULT)
308             this.priority.remove();
309         else
310             this.priority.marshal(eventType.getPriority());
311         final Attribute[] attributes = eventType.getAttributes();
312         if (attributes.length > 0)
313             this.attributes.marshal(Arrays.asList(attributes));
314         else
315             this.attributes.remove();
316         final Authorization[] authorizations = eventType.getAuthorizations();
317         if (authorizations.length > 0)
318             this.authorizations.marshal(Arrays.asList(authorizations));
319         else
320             this.authorizations.remove();
321         final DefaultAction[] actions = eventType.getActions();
322         if (actions.length > 0)
323             this.actions.marshal(Arrays.asList(actions));
324         else
325             this.actions.remove();
326     }
327 
328     /**
329      * Removes any marshalled {@link ContextEventType} from the {@link Element}.
330      */
331     @Override
332     public void remove() {
333         this.name.remove();
334         this.ttl.remove();
335         this.priority.remove();
336         this.attributes.remove();
337         this.authorizations.remove();
338         this.actions.remove();
339     }
340 
341     /**
342      * Creates instance of {@link ListUnmarshaller.Builder} for
343      * {@link ContextEventType}s. The returned {@link ListUnmarshaller.Builder}
344      * does not have the parent {@link Element} set and caller should set it
345      * before building the {@link ListUnmarshaller} for {@link ContextEventType}
346      * s. The name for child {@link Element}s is set to
347      * {@link #EVENT_TYPE_ELEMENT} and the strategy is set to {@link Append}.
348      * 
349      * @return the {@link ListUnmarshaller.Builder} for {@link ContextEventType}
350      *         s.
351      */
352     public static ListUnmarshaller.Builder<ContextEventType> getListBuilder() {
353         return LIST_BUILDER;
354     }
355 
356     /**
357      * Builder of {@link ContextEventTypeUnmarshaller}.
358      * 
359      * @author sanjin
360      */
361     public static class Builder extends
362             BaseUnmarshallerBuilder<ContextEventType> {
363 
364         /**
365          * Create uninitialized instance of
366          * {@link ContextEventTypeUnmarshaller.Builder}.
367          */
368         public Builder() {
369             super();
370         }
371 
372         /**
373          * Clone-constructor.
374          * 
375          * @param builder the cloned
376          *        {@link ContextEventTypeUnmarshaller.Builder}.
377          */
378         private Builder(final Builder builder) {
379             super(builder);
380         }
381 
382         /**
383          * Create instance of {@link ContextEventTypeUnmarshaller}.
384          * 
385          * @return a {@link ContextEventTypeUnmarshaller}.
386          */
387         @Override
388         public ContextEventTypeUnmarshaller build() {
389             return new ContextEventTypeUnmarshaller(getElement());
390         }
391 
392         @Override
393         protected Builder clone() {
394             return new Builder(this);
395         }
396     }
397 }