View Javadoc

1   /*
2    * Copyright 2012-2013 smartics, Kronseder & Reiner GmbH
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package de.smartics.properties.spi.core.constraint.jsr303;
17  
18  import java.lang.annotation.Annotation;
19  import java.util.StringTokenizer;
20  import java.util.regex.Matcher;
21  import java.util.regex.Pattern;
22  
23  /**
24   * A helper class to make JSR-303 constraints human readable in the context of
25   * smartics properties.
26   */
27  final class ConstraintPrettifier
28  {
29    // ********************************* Fields *********************************
30  
31    // --- constants ------------------------------------------------------------
32  
33    /**
34     * The pattern to match constraints in their native, typical
35     * {@link Annotation#toString()} representation.
36     */
37    private static final Pattern PATTERN = Pattern
38        .compile("@([^(]+)\\(([^)]+)\\)");
39  
40    // --- members --------------------------------------------------------------
41  
42    /**
43     * The annotation prettified by this instance.
44     */
45    private final Annotation annotation;
46  
47    /**
48     * The prettified instance of the annotation.
49     */
50    private final String pretty;
51  
52    // ****************************** Initializer *******************************
53  
54    // ****************************** Constructors ******************************
55  
56    /**
57     * Default constructor.
58     *
59     * @param annotation the annotation prettified by this instance.
60     * @throws NullPointerException if {@code annotation} is <code>null</code>.
61     */
62    ConstraintPrettifier(final Annotation annotation) throws NullPointerException
63    {
64      this.pretty = prettify(annotation);
65      this.annotation = annotation;
66    }
67  
68    // ****************************** Inner Classes *****************************
69  
70    /**
71     * A parameter token.
72     */
73    private static final class ParameterToken
74    {
75      /**
76       * The name of the token.
77       */
78      private String name;
79  
80      /**
81       * Flag to check if the token a name/value pair.
82       */
83      private boolean isNameValue;
84  
85      /**
86       * The original token.
87       */
88      private String token;
89  
90      private boolean isRelevantParameter()
91      {
92        return !("message".equals(name) || "groups".equals(name) || "payload"
93            .equals(name)) && !tokenIsEmptyArray();
94      }
95  
96      private boolean tokenIsEmptyArray()
97      {
98        return token.endsWith("=[]");
99      }
100 
101     private void append(final StringBuilder buffer)
102     {
103       buffer.append(' ').append(token.trim()).append(',');
104     }
105   }
106 
107   // ********************************* Methods ********************************
108 
109   // --- init -----------------------------------------------------------------
110 
111   // --- get&set --------------------------------------------------------------
112 
113   private static String prettify(final Annotation annotation)
114     throws NullPointerException
115   {
116     final String plain = annotation.toString();
117 
118     final Matcher matcher = PATTERN.matcher(plain);
119     if (matcher.matches())
120     {
121       final StringBuilder buffer = new StringBuilder(128);
122       final String constraint = matcher.group(1);
123       addConstraint(buffer, constraint);
124       final String parameter = matcher.group(2);
125       addParameter(buffer, parameter);
126       return buffer.toString();
127     }
128     else
129     {
130       return plain;
131     }
132   }
133 
134   private static void addConstraint(final StringBuilder buffer,
135       final String constraint)
136   {
137     final int index = constraint.lastIndexOf('.');
138     if (index > -1 && index < constraint.length() - 1)
139     {
140       final String shortName = constraint.substring(index + 1);
141       buffer.append(shortName);
142     }
143     else
144     {
145       buffer.append(constraint);
146     }
147   }
148 
149   private static void addParameter(final StringBuilder buffer,
150       final String parameter)
151   {
152     final int initialLength = buffer.length();
153     final StringTokenizer tokenizer = new StringTokenizer(parameter, ",");
154     while (tokenizer.hasMoreTokens())
155     {
156       final ParameterToken token = fetchToken(tokenizer);
157       if (token.isNameValue)
158       {
159         if (token.isRelevantParameter())
160         {
161           token.append(buffer);
162         }
163       }
164       else
165       {
166         token.append(buffer);
167       }
168     }
169 
170     if (initialLength < buffer.length())
171     {
172       buffer.setCharAt(initialLength, '(');
173       buffer.setCharAt(buffer.length() - 1, ')');
174     }
175   }
176 
177   private static ParameterToken fetchToken(final StringTokenizer tokenizer)
178   {
179     final ParameterToken result = new ParameterToken();
180 
181     String token = tokenizer.nextToken();
182     final int index = token.indexOf('=');
183     result.isNameValue = index != -1;
184     if (result.isNameValue)
185     {
186       final StringBuilder buffer = new StringBuilder(24);
187       if (token.charAt(index + 1) == '[')
188       {
189         while (tokenizer.hasMoreTokens() && !token.endsWith("]"))
190         {
191           buffer.append(token).append(',');
192           token = tokenizer.nextToken();
193         }
194         buffer.append(token);
195         result.token = buffer.toString();
196       }
197       else
198       {
199         result.token = token;
200       }
201 
202       result.name = result.token.substring(0, index).trim();
203     }
204 
205     return result;
206   }
207 
208   /**
209    * Returns the annotation prettified by this instance.
210    *
211    * @return the annotation prettified by this instance.
212    */
213   public Annotation getAnnotation()
214   {
215     return annotation;
216   }
217 
218   /**
219    * Returns the prettified instance of the annotation.
220    *
221    * @return the prettified instance of the annotation.
222    */
223   public String getPretty()
224   {
225     return pretty;
226   }
227 
228   // --- business -------------------------------------------------------------
229 
230   // --- object basics --------------------------------------------------------
231 
232   @Override
233   public String toString()
234   {
235     return pretty;
236   }
237 }