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.xml;
19  
20  import java.util.concurrent.atomic.AtomicReference;
21  import org.w3c.dom.Element;
22  import at.ac.tuwien.infosys.sm4all.copal.api.util.InvalidFieldValueException;
23  import at.ac.tuwien.infosys.sm4all.copal.api.util.MissingFieldException;
24  import at.ac.tuwien.infosys.sm4all.copal.api.util.Unmarshaller;
25  
26  /**
27   * Unmarshals and marshals an attribute from/to an {@link Element}.
28   * 
29   * @param <T> the type of unmarshaled and marshaled attribute value.
30   * @author sanjin
31   */
32  public abstract class Attribute<T> implements Unmarshaller<T> {
33  
34      private final String name;
35      private final Element element;
36  
37      /**
38       * Creates instance of an attribute {@link Unmarshaller} which uses
39       * specified {@link Element} to unmarshal and/or marshal the attribute with
40       * specified name.
41       * 
42       * @param name the name of the attribute in the {@link Element} used for
43       *        unmarshalling and marshalling.
44       * @param element the {@link Element} used for unmarshalling and
45       *        marshalling.
46       * @throws NullPointerException if specified {@link Element} or name is
47       *         <code>null</code>.
48       * @throws IllegalArgumentException if specified name is an empty or blank
49       *         string.
50       */
51      protected Attribute(final String name, final Element element) {
52          super();
53  
54          if (null == element) {
55              throw new NullPointerException("XML DOM element cannot be null.");
56          }
57          if (null == name) {
58              throw new NullPointerException("Name cannot be null.");
59          }
60          if (name.trim().isEmpty()) {
61              throw new IllegalArgumentException(
62                      "Name cannot be an empty or blank string.");
63          }
64  
65          this.element = element;
66          this.name = name;
67      }
68  
69      /**
70       * Converts specified {@link String} value of the attribute to desired
71       * class.
72       * 
73       * @param str the {@link String} value of the attribute.
74       * @return the attribute as instance of the desired class.
75       * @throws InvalidFieldValueException if specified value is not valid.
76       */
77      protected abstract T valueOf(String str) throws InvalidFieldValueException;
78  
79      /**
80       * Converts specified value of attribute to {@link String}.
81       * 
82       * @param value the value of the attribute.
83       * @return the attribute as {@link String}.
84       */
85      protected abstract String toString(T value);
86  
87      /**
88       * Returns the name of the attribute in the {@link Element} used for
89       * unmarshalling/marshalling.
90       * 
91       * @return the name of the attribute in the {@link Element} used for
92       *         unmarshalling/marshalling.
93       */
94      public String getName() {
95          return this.name;
96      }
97  
98      /**
99       * Returns the {@link Element} used for unmarshalling/marshalling.
100      * 
101      * @return the {@link Element} used for unmarshalling/marshalling.
102      */
103     public Element getElement() {
104         return this.element;
105     }
106 
107     /**
108      * Unmarshals the attribute from the {@link Element}.
109      * 
110      * @return the unmarshaled attribute.
111      * @throws MissingFieldException if specified {@link Element} does not have
112      *         the attribute.
113      * @throws InvalidFieldValueException if the attribute is empty or blank
114      *         string or invalid value.
115      */
116     @Override
117     public T unmarshal() throws MissingFieldException,
118             InvalidFieldValueException {
119         if (!this.element.hasAttribute(this.name)) {
120             throw new MissingFieldException(this.name);
121         }
122 
123         return valueOf(this.element.getAttribute(this.name));
124     }
125 
126     /**
127      * Marshals specified value into the attribute in the {@link Element}.
128      * 
129      * @param value the value of the attribute.
130      * @throws NullPointerException if specified value is <code>null</code>.
131      */
132     @Override
133     public void marshal(final T value) {
134         if (null == value) {
135             throw new NullPointerException("Value cannot be null.");
136         }
137 
138         this.element.setAttribute(this.name, toString(value));
139     }
140 
141     /**
142      * Removes the attribute from the {@link Element}.
143      */
144     @Override
145     public void remove() {
146         if (this.element.hasAttribute(this.name)) {
147             this.element.removeAttribute(this.name);
148         }
149     }
150 
151     /**
152      * Builder of {@link Attribute}.
153      * 
154      * @param <T> the type of unmarshaled and marshaled attribute value.
155      * @author sanjin
156      */
157     public abstract static class Builder<T> extends BaseUnmarshallerBuilder<T> {
158 
159         private final AtomicReference<String> nameRef = new AtomicReference<String>();
160 
161         /**
162          * Create uninitialized instance of {@link Attribute.Builder}.
163          */
164         protected Builder() {
165             super();
166         }
167 
168         /**
169          * Clone-constructor.
170          * 
171          * @param builder the cloned {@link Attribute.Builder}.
172          */
173         protected Builder(final Builder<T> builder) {
174             super(builder);
175 
176             this.nameRef.set(builder.nameRef.get());
177         }
178 
179         /**
180          * Create instance of {@link Attribute.Builder} by copying this
181          * {@link Attribute.Builder}.
182          * 
183          * @return an {@link Attribute.Builder}.
184          */
185         @Override
186         protected abstract Builder<T> copy();
187 
188         /**
189          * Returns the name of the attribute.
190          * 
191          * @return the name of the attribute.
192          */
193         public String getName() {
194             return this.nameRef.get();
195         }
196 
197         /**
198          * Create instance of {@link Attribute.Builder} that will build
199          * {@link Attribute}s that will unmarshal and/or marshal values from/to
200          * specified attribute.
201          * 
202          * @param name the name of attribute.
203          * @return an {@link Attribute.Builder}.
204          */
205         public Builder<T> withName(final String name) {
206             final Builder<T> result = copy();
207 
208             result.nameRef.set(name);
209 
210             return result;
211         }
212 
213         @Override
214         public Builder<T> withElement(final Element element) {
215             return (Builder<T>) super.withElement(element);
216         }
217     }
218 }