1    /*
2     * Copyright 2005 :torweg free software group
3     * 
4     * This program is free software: you can redistribute it and/or modify
5     * it under the terms of the GNU General Public License as published by
6     * the Free Software Foundation, either version 3 of the License, or
7     * (at your option) any later version.
8     * 
9     * This program is distributed in the hope that it will be useful,
10    * but WITHOUT ANY WARRANTY; without even the implied warranty of
11    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    * GNU General Public License for more details.
13    * 
14    * You should have received a copy of the GNU General Public License
15    * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16    *
17    */
18   package org.torweg.pulse.service.request;
19   
20   import java.util.ArrayList;
21   import java.util.Collection;
22   import java.util.Collections;
23   import java.util.HashSet;
24   import java.util.List;
25   
26   import javax.persistence.Basic;
27   import javax.persistence.Column;
28   import javax.persistence.ElementCollection;
29   import javax.persistence.Entity;
30   import javax.persistence.FetchType;
31   import javax.xml.bind.annotation.XmlAccessOrder;
32   import javax.xml.bind.annotation.XmlAccessType;
33   import javax.xml.bind.annotation.XmlAccessorOrder;
34   import javax.xml.bind.annotation.XmlAccessorType;
35   import javax.xml.bind.annotation.XmlElement;
36   import javax.xml.bind.annotation.XmlElementWrapper;
37   import javax.xml.bind.annotation.XmlRootElement;
38   import javax.xml.bind.annotation.XmlTransient;
39   
40   import org.hibernate.LazyInitializationException;
41   import org.hibernate.annotations.BatchSize;
42   import org.jdom.Element;
43   import org.slf4j.Logger;
44   import org.slf4j.LoggerFactory;
45   import org.torweg.pulse.bundle.JDOMable;
46   import org.torweg.pulse.util.INamed;
47   import org.torweg.pulse.util.entity.AbstractBasicEntity;
48   
49   /**
50    * is an entity representing a {@code Parameter} which may have a set of values.
51    * <p>
52    * A {@code Parameter} consists of the following attributes:
53    * <ul * type="disc">
54    * <li>{@code id}: constant unique identifier (primary key)</li>
55    * <li>{@code name}: the name of the {@code Parameter}</li>
56    * <li>{@code values}: a set of {@code String}s as the values of the
57    * {@code Parameter}</li>
58    * </ul>
59    * </p>
60    * 
61    * @author Christian Schatt, Daniel Dietz
62    * @version $Revision: 1956 $
63    */
64   @Entity
65   @XmlRootElement(name = "parameter")
66   @XmlAccessorOrder(XmlAccessOrder.UNDEFINED)
67   @XmlAccessorType(XmlAccessType.FIELD)
68   public class Parameter extends AbstractBasicEntity implements INamed, JDOMable {
69   
70       /**
71        * The serialVersionUID of the {@code Parameter}.
72        */
73       private static final long serialVersionUID = 8780220576098673232L;
74   
75       /**
76        * the logger.
77        */
78       private static final Logger LOGGER = LoggerFactory
79               .getLogger(Parameter.class);
80   
81       /**
82        * The name of the {@code Parameter}.
83        */
84       @Basic
85       @Column(nullable = false)
86       @XmlElement(name = "name")
87       private String name = null;
88   
89       /**
90        * The {@code List} of values of the {@code Parameter}.
91        */
92       @ElementCollection(fetch = FetchType.EAGER)
93       @Column(name = "value")
94       @BatchSize(size = 20)
95       @XmlTransient
96       // getter JAXB-annotated
97       private final List<String> values = new ArrayList<String>();
98   
99       /**
100       * used for Hibernate<sup>TM</sup>.
101       */
102      @Deprecated
103      protected Parameter() {
104          super();
105      }
106  
107      /**
108       * The {@code Constructor} that sets the name of the {@code Parameter}.
109       * 
110       * @param newName
111       *            the name of the {@code Parameter}
112       */
113      public Parameter(final String newName) {
114          super();
115          this.setName(newName);
116      }
117  
118      /**
119       * The {@code Constructor} that sets name and value of this
120       * {@code Parameter}.
121       * 
122       * @param newName
123       *            the name of the {@code Parameter}
124       * @param newValue
125       *            the value of the {@code Parameter}
126       */
127      public Parameter(final String newName, final String newValue) {
128          super();
129          this.setName(newName);
130          this.addValue(newValue);
131      }
132  
133      /**
134       * The {@code Constructor} that sets name and values of this
135       * {@code Parameter}.
136       * 
137       * @param newName
138       *            the name of the {@code Parameter}
139       * @param newValues
140       *            the values of the {@code Parameter}
141       */
142      public Parameter(final String newName, final List<String> newValues) {
143          super();
144          this.setName(newName);
145          this.setValues(newValues);
146          Collections.sort(this.values);
147      }
148  
149      /**
150       * Returns the name of the {@code Parameter}.
151       * 
152       * @return the name of the {@code Parameter}
153       */
154      public final String getName() {
155          return this.name;
156      }
157  
158      /**
159       * Sets the name of the {@code Parameter}.
160       * 
161       * @param newName
162       *            the new name of the {@code Parameter}
163       */
164      protected final void setName(final String newName) {
165          if (newName == null) {
166              throw new NullPointerException(
167                      "Parameter.name must not be set to null.");
168          }
169          this.name = newName;
170      }
171  
172      /**
173       * Returns the {@code List} of values of the {@code Parameter}.
174       * 
175       * @return the {@code List} of values of the {@code Parameter}
176       */
177      public final List<String> getValues() {
178          return this.values;
179      }
180  
181      /**
182       * For JAXB only.
183       * 
184       * @return this.getValues()
185       */
186      @XmlElementWrapper(name = "values")
187      @XmlElement(name = "value")
188      @SuppressWarnings("unused")
189      @Deprecated
190      private HashSet<String> getValuesJAXB() { // NOPMD
191          try {
192              return new HashSet<String>(getValues());
193          } catch (LazyInitializationException e) {
194              LOGGER.debug("ignored: {}", e.getLocalizedMessage());
195              return null;
196          }
197      }
198  
199      /**
200       * Sets the {@code Parameter}'s {@code List} of values.
201       * 
202       * @param newValues
203       *            the new {@code List} of values of the {@code Parameter}
204       */
205      public final void setValues(final Collection<? extends String> newValues) {
206          this.values.clear();
207          this.values.addAll(newValues);
208          Collections.sort(this.values);
209      }
210  
211      /**
212       * Returns the first value of the {@code Parameter}'s {@code List} of
213       * values.
214       * 
215       * @return the first value of the {@code Parameter}'s {@code List} of values
216       *         or an empty string
217       */
218      public final String getFirstValue() {
219          if (this.getValues().isEmpty()) {
220              return "";
221          }
222          return this.getValues().iterator().next();
223      }
224  
225      /**
226       * Adds a value to the {@code Parameter}'s {@code List} of values.
227       * 
228       * @param val
229       *            the value to be added
230       */
231      public final void addValue(final String val) {
232          this.values.add(val);
233          Collections.sort(this.values);
234      }
235  
236      /**
237       * Adds a {@code Collection} of values to the {@code Parameter}'s
238       * {@code List} of values.
239       * 
240       * @param vals
241       *            the values to be added
242       */
243      public final void addAllValues(final Collection<? extends String> vals) {
244          this.values.addAll(vals);
245          Collections.sort(this.values);
246      }
247  
248      /**
249       * Determines if a value is part of the {@code Parameter}'s {@code List} of
250       * values.
251       * 
252       * @param val
253       *            the value to be sought-after
254       * @return true if the value is part of the {@code List}
255       */
256      public final boolean containsValue(final String val) {
257          return this.values.contains(val);
258      }
259  
260      /**
261       * Determines if all elements of a {@code Collection} of values are part of
262       * the {@code Parameter}'s {@code List} of values.
263       * 
264       * @param vals
265       *            the values to be sought-after
266       * @return true if all values are part of the {@code List}
267       */
268      public final boolean containsAllValues(
269              final Collection<? extends String> vals) {
270          return this.values.containsAll(vals);
271      }
272  
273      /**
274       * Removes a value from the {@code Parameter}'s {@code List} of values if it
275       * is part of it.
276       * 
277       * @param val
278       *            the value to be removed
279       * @return true if the {@code List} changed as a result of the call
280       */
281      public final boolean removeValue(final String val) {
282          return this.values.remove(val);
283      }
284  
285      /**
286       * Removes all elements of a {@code Collection} of values from the
287       * {@code Parameter}'s {@code List} of values if they are part of it.
288       * 
289       * @param vals
290       *            the values to be removed
291       * @return true if the {@code List} changed as a result of the call
292       */
293      public final boolean removeAllValues(final Collection<? extends String> vals) {
294          return this.values.removeAll(vals);
295      }
296  
297      /**
298       * Serializes the state of the {@code Parameter} as a JDOM {@code Element}.
299       * 
300       * @return the state of the {@code Parameter} as a JDOM {@code Element}
301       */
302      public final Element deserializeToJDOM() {
303          Element element = new Element(this.getClass().getSimpleName());
304          if (this.getId() != null) {
305              element.setAttribute("id", this.getId().toString());
306          }
307          element.setAttribute("name", this.getName());
308          if (this.getValues() != null) {
309              for (String value : this.getValues()) {
310                  Element val = new Element("value");
311                  val.addContent(value);
312                  element.addContent(val);
313              }
314          }
315          return element;
316      }
317  
318      /**
319       * Checks if the {@code Parameter} is equal to the parameter object.
320       * {@code Parameter}s are equal, if their names are equal and their
321       * {@code List}s of values contain the same elements.
322       * 
323       * @param object
324       *            the {@code Object} to be checked for equality with the
325       *            {@code Parameter}
326       * @return {@code true} if the parameter object equals the {@code Parameter}
327       */
328      @Override
329      public final boolean equals(final Object object) {
330          if (object == null) {
331              return false;
332          }
333          Parameter param;
334          try {
335              param = (Parameter) object;
336          } catch (ClassCastException exception) {
337              return false;
338          }
339          if (this.getName().equals(param.getName())) {
340              if ((this.getValues() == null) || (param.getValues() == null)) {
341                  return ((this.getValues() == null) && (param.getValues() == null));
342              }
343              return ((this.getValues().size() == param.getValues().size()) && this
344                      .getValues().containsAll(param.getValues()));
345          }
346          return false;
347      }
348  
349      /**
350       * Returns a hashCode for the {@code Parameter}.
351       * 
352       * @return a hashCode for the {@code Parameter}
353       */
354      @Override
355      public final int hashCode() {
356          final int prime = 31; // NOPMD
357          int result = 1;
358          result = prime * result + this.name.hashCode();
359          int vSize = this.values.size();
360          result = prime * result + vSize;
361          for (String value : this.values) {
362              result = prime * result + value.hashCode();
363          }
364          return result;
365      }
366  
367      /**
368       * returns a human readable string representation of the {@code Parameter}.
369       * 
370       * @return a human readable string representation
371       */
372      @Override
373      public String toString() {
374          if (getName() == null) {
375              return super.toString();
376          }
377          StringBuilder str = new StringBuilder();
378          str.append(getName()).append('[');
379          int i = 0;
380          for (String v : getValues()) {
381              str.append(v);
382              if (i < getValues().size()) {
383                  str.append(',');
384              }
385          }
386          str.append(']');
387          return str.toString();
388      }
389  
390      /**
391       * returns a copy of the {@code Parameter}.
392       * 
393       * @return the copied parameter
394       */
395      public final Parameter createCopy() {
396          Parameter copy = new Parameter(getName());
397          copy.addAllValues(getValues());
398          return copy;
399      }
400  
401  }
402