1    /*
2     * Copyright 2009 :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.component.statistics.model;
19   
20   import java.util.ArrayList;
21   import java.util.List;
22   
23   import javax.persistence.Basic;
24   import javax.persistence.CascadeType;
25   import javax.persistence.MappedSuperclass;
26   import javax.persistence.OneToMany;
27   import javax.persistence.Table;
28   import javax.persistence.UniqueConstraint;
29   import javax.xml.bind.annotation.XmlAccessOrder;
30   import javax.xml.bind.annotation.XmlAccessType;
31   import javax.xml.bind.annotation.XmlAccessorOrder;
32   import javax.xml.bind.annotation.XmlAccessorType;
33   import javax.xml.bind.annotation.XmlAttribute;
34   import javax.xml.bind.annotation.XmlElement;
35   import javax.xml.bind.annotation.XmlElementWrapper;
36   import javax.xml.bind.annotation.XmlRootElement;
37   import javax.xml.bind.annotation.XmlTransient;
38   
39   import org.hibernate.LazyInitializationException;
40   import org.slf4j.Logger;
41   import org.slf4j.LoggerFactory;
42   import org.torweg.pulse.util.entity.AbstractNamedEntity;
43   
44   /**
45    * Abstract base class to derive "versioned" from.
46    * 
47    * @author Daniel Dietz
48    * @version $Revision: 1573 $
49    */
50   @XmlRootElement(name = "abstract-regex-versioned")
51   @XmlAccessorOrder(XmlAccessOrder.UNDEFINED)
52   @XmlAccessorType(XmlAccessType.FIELD)
53   @MappedSuperclass
54   @Table(uniqueConstraints = @UniqueConstraint(columnNames = { "category" }))
55   public abstract class AbstractRegexVersioned extends AbstractNamedEntity {
56   
57       /**
58        * The serialVersionUID.
59        */
60       private static final long serialVersionUID = -3693288011013232056L;
61   
62       /**
63        * The logger.
64        */
65       private static final Logger LOGGER = LoggerFactory
66               .getLogger(AbstractRegexVersioned.class);
67   
68       /**
69        * The string "unknown" - to be used as <tt>category</tt> and
70        * <tt>defaultDisplayName</tt> for an "unknown" {@code AbstractVersioned}.
71        */
72       public static final String UNKNOWN = "unknown";
73   
74       /**
75        * The {@code Version}s.
76        */
77       @OneToMany(cascade = CascadeType.ALL)
78       @XmlTransient
79       // getter JAXB-annotated
80       private final List<RegexVersion> versions = new ArrayList<RegexVersion>();
81   
82       /**
83        * The identifier of the category.
84        */
85       @XmlAttribute(name = "category")
86       @Basic(optional = false)
87       private String category;
88   
89       /**
90        * The regular expression to match the operating system-string to.
91        */
92       @XmlAttribute(name = "regex")
93       @Basic(optional = false)
94       private String regex = "";
95   
96       /**
97        * Returns the {@code Version}s.
98        * 
99        * @return the <tt>versions</tt>
100       */
101      @XmlTransient
102      public final List<RegexVersion> getVersions() {
103          return this.versions;
104      }
105  
106      /**
107       * For JAXB only.
108       * 
109       * @return this.getVersions()
110       */
111      @XmlElementWrapper(name = "versions")
112      @XmlElement(name = "version")
113      @SuppressWarnings("unused")
114      @Deprecated
115      private List<RegexVersion> getVersionsJAXB() {
116          try {
117              return getVersions();
118          } catch (LazyInitializationException e) {
119              LOGGER.debug("ignored: {}", e.getLocalizedMessage());
120              return null;
121          }
122      }
123  
124      /**
125       * Adds the given {@code Version}.
126       * 
127       * @param version
128       *            the {@code Version} to add
129       * 
130       * @return {@code true} if and only if the given {@code Version} has been
131       *         added to the internal {@code List&lt;Version&gt;}, {@code false}
132       *         otherwise
133       */
134      public final boolean addVersion(final RegexVersion version) {
135          return this.versions.add(version);
136      }
137  
138      /**
139       * Returns the category identifier.
140       * 
141       * @return the <tt>category</tt>
142       */
143      public final String getCategory() {
144          return this.category;
145      }
146  
147      /**
148       * Sets the category identifier.
149       * 
150       * @param cat
151       *            the category
152       * 
153       * @throws IllegalArgumentException
154       *             if the given category is {@code null} or empty string
155       */
156      public final void setCategory(final String cat) {
157          if (cat == null || cat.trim().equals("")) {
158              throw new IllegalArgumentException(
159                      "The category must not be null or empty string.");
160          }
161          this.category = cat;
162      }
163  
164      /**
165       * Sets the default display name.
166       * 
167       * @param n
168       *            the name
169       * 
170       * @throws IllegalArgumentException
171       *             if the given name is {@code null} or empty string
172       */
173      @Override
174      public final void setName(final String n) {
175          if (n == null || n.trim().equals("")) {
176              throw new IllegalArgumentException(
177                      "The regular name must not be null or empty string.");
178          }
179          super.setName(n);
180      }
181  
182      /**
183       * Returns the default regular expression.
184       * 
185       * @return the <tt>regex</tt>
186       */
187      public final String getRegex() {
188          return this.regex;
189      }
190  
191      /**
192       * Sets the default regular expression.
193       * 
194       * @param reg
195       *            the regular expression
196       * 
197       * @throws IllegalArgumentException
198       *             if the given regular expression is {@code null} or empty
199       *             string
200       */
201      public final void setRegex(final String reg) {
202          if (reg == null || reg.trim().equals("")) {
203              throw new IllegalArgumentException(
204                      "The regular expression must not be null or empty string.");
205          }
206          this.regex = reg;
207      }
208  
209      /**
210       * Returns a {@code RegexVersion} by a value to be used for the
211       * version-check.
212       * 
213       * @param s
214       *            the string to be used for the check
215       * 
216       * @return a matching {@code RegexVersion} if any matches, {@code null}
217       *         otherwise
218       */
219      public final RegexVersion getVersion(final String s) {
220          for (RegexVersion version : getVersions()) {
221              if (version.isMatch(s)) {
222                  return version;
223              }
224          }
225          return null;
226      }
227  
228      /**
229       * Checks if the given operating system-string matches the regular
230       * expression.
231       * 
232       * @param osString
233       *            the operating system-string
234       * 
235       * @return {@code true} if and only if the string is a match, {@code false}
236       *         otherwise
237       */
238      public final boolean isMatch(final String osString) {
239          if (this.regex.equals("")) {
240              // "unknown"
241              return false;
242          }
243          return osString.matches(this.regex);
244      }
245  
246      /**
247       * Checks if the the current {@code OperatingSystem} is the "unknown"
248       * operating system.
249       * 
250       * @return {@code true} if the {@code OperatingSystem} is the "unknown"
251       *         operating system, {@code false} otherwise
252       */
253      public final boolean isUnknown() {
254          return (getCategory().equals(AbstractRegexVersioned.UNKNOWN) && getRegex()
255                  .equals(""));
256      }
257  
258      /**
259       * Returns a string representation of the {@code UserAgent}.
260       * 
261       * @return a string representation of the {@code UserAgent}
262       */
263      @Override
264      public String toString() {
265          return "{" + super.toString() + "@[" + getId() + "], category: "
266                  + getCategory() + ", default-display-name: " + getName()
267                  + ", noOfVersions: " + getVersions().size() + "}";
268      }
269  
270  }
271