View Javadoc
1   package org.nuiton.eugene.models.extension.tagvalue;
2   
3   /*-
4    * #%L
5    * EUGene :: EUGene
6    * %%
7    * Copyright (C) 2004 - 2016 CodeLutin
8    * %%
9    * This program is free software: you can redistribute it and/or modify
10   * it under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation, either version 3 of the
12   * License, or (at your option) any later version.
13   * 
14   * This program is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   * GNU General Lesser Public License for more details.
18   * 
19   * You should have received a copy of the GNU General Lesser Public
20   * License along with this program.  If not, see
21   * <http://www.gnu.org/licenses/lgpl-3.0.html>.
22   * #L%
23   */
24  
25  import com.google.common.collect.ImmutableSet;
26  import org.apache.commons.lang3.StringUtils;
27  import org.nuiton.eugene.models.object.ObjectModelElement;
28  import org.nuiton.eugene.models.object.ObjectModelPackage;
29  
30  import java.util.Set;
31  import java.util.regex.Matcher;
32  import java.util.regex.Pattern;
33  
34  /**
35   * Created on 24/09/16.
36   *
37   * @author Tony Chemit - chemit@codelutin.com
38   */
39  public class TagValueUtil {
40  
41      /**
42       * Pattern to define tag values authorized at classifier level in the model
43       * properties file.
44       *
45       * L'expression réguliere match les chaines de type
46       * &lt;package.ClassName&gt;.&lt;class|attribute|operation&gt;.[name].&lt;stereotype|tagvalue&gt;.[tag]
47       * fr.isisfish.entities.Population.class.stereotype=entity
48       * fr.isisfish.entities.Population.class.tagvalue.persistenceType=flatfile
49       * fr.isisfish.entities.Population.attribute.name.stereotype=...
50       * fr.isisfish.entities.Population.attribute.name.tagvalue.pk=topiaId
51       * fr.isisfish.entities.Population.operation.getRegion.stereotype=...
52       * fr.isisfish.entities.Population.operation.getRegion.tagvalue.pk=...
53       */
54      protected static final Pattern TAG_VALUE_PATTERN =
55              Pattern.compile("^((?:[_a-zA-Z0-9]+\\.)+(?:_?[A-Z][_a-zA-Z0-9]*\\.)+)(?:(class|attribute|operation))\\.(?:([_a-zA-Z0-9]+)\\.)?(?:(tagvalue|tagValue)?)\\.((?:[_a-zA-Z0-9]+)+(?:\\.?[_a-zA-Z0-9]+)*)?$");
56  
57      /**
58       * Pattern to define tag values authorized at model level in the model
59       * properties file.
60       */
61      protected static final Pattern MODEL_TAG_VALUE_PATTERN = Pattern.compile(
62              "^model\\.(?:(tagvalue|tagValue)?)\\.((?:[_a-zA-Z0-9]+)+(?:\\.?[_a-zA-Z0-9]+)*)$");
63  
64      /**
65       * Pattern to define tag values authorized at model level in the model
66       * properties file.
67       */
68      protected static final Pattern PACKAGE_TAG_VALUE_PATTERN = Pattern.compile(
69              "^package\\.((?:[_a-zA-Z0-9]+\\.)+)(?:(tagvalue|tagValue)?)\\.((?:[_a-zA-Z0-9]+)+(?:\\.?[_a-zA-Z0-9]+)*)$");
70      protected static final Pattern PACKAGE_STEREOTYPE_PATTERN = Pattern
71              .compile("^package\\.((?:[_a-zA-Z0-9]+\\.)+)?(?:(stereotype)?)$");
72      protected static final Pattern STEREOTYPE_PATTERN = Pattern
73              .compile("^((?:[_a-zA-Z0-9]+\\.)+(?:_?[a-zA-Z][_a-zA-Z0-9]*\\.)+)(?:(class|attribute|operation))\\.(?:([_a-zA-Z0-9]+)\\.)?(?:(stereotype)?)$");
74  
75      public static Matcher getModelMatcher(String key) throws InvalidTagValueSyntaxException {
76          Matcher matcher = MODEL_TAG_VALUE_PATTERN.matcher(key);
77          if (!matcher.find()) {
78              throw new InvalidTagValueSyntaxException();
79          }
80          return matcher;
81      }
82  
83      public static Matcher getPackageMatcher(String key) throws InvalidTagValueSyntaxException {
84          Matcher matcher = PACKAGE_TAG_VALUE_PATTERN.matcher(key);
85          if (!matcher.find()) {
86              throw new InvalidTagValueSyntaxException();
87          }
88          return matcher;
89      }
90  
91      public static Matcher getMatcher(String key) throws InvalidTagValueSyntaxException {
92          Matcher matcher = TAG_VALUE_PATTERN.matcher(key);
93          if (!matcher.find()) {
94              throw new InvalidTagValueSyntaxException();
95          }
96          return matcher;
97      }
98  
99      /**
100      * Seek for a tag value amoung elements given using these rules:
101      * <ul>
102      * <li>Look into {@code elements} and return the first not empty tag value found.</li>
103      * <li>If not found, Look into {@code elements} declaringElement (for each
104      * element that is a {@link ObjectModelElement} and return the first not empty tag
105      * value found.</li>
106      * <li>If not found return {@code defaultValue}</li>
107      * </ul>
108      * <strong>Note:</strong> Order of {@code elements} is important, better then to
109      * always starts from specialized to more general level (for example from attribute,
110      * to classifier or model).
111      *
112      * @param tagName  tag name to find
113      * @param elements not null elements to test
114      * @return found tag value or {@code null} if not found
115      * @since 3.0
116      */
117     public static String findTagValue(TagValueMetadata tagName, WithTagValuesOrStereotypes... elements) {
118         String result = findDirectTagValue(tagName, elements);
119 
120         if (result != null) {
121             return result;
122         }
123 
124         for (WithTagValuesOrStereotypes element : elements) {
125             if (element instanceof ObjectModelElement) {
126                 // try in declaring element
127                 ObjectModelElement declaringElement = ((ObjectModelElement) element).getDeclaringElement();
128                 if (declaringElement != null) {
129                     String value = findNotEmptyTagValue(tagName, declaringElement);
130                     if (value != null) {
131                         return value;
132                     }
133                 }
134             }
135         }
136         return tagName.getDefaultValue();
137     }
138 
139     /**
140      * Seek for a tag value amoung elements given using these rules:
141      * <ul>
142      * <li>Look into {@code elements} and return the first not empty tag value found.</li>
143      * <li>If not found, Look into {@code elements} declaringElement (for each
144      * element that is a {@link ObjectModelElement} and return the first not empty tag
145      * value found.</li>
146      * <li>If not found return {@code defaultValue}</li>
147      * </ul>
148      * <strong>Note:</strong> Order of {@code elements} is important, better then to
149      * always starts from specialized to more general level (for example from attribute,
150      * to classifier or model).
151      *
152      * @param tagName      tag name to find
153      * @param defaultValue default value to use if not found
154      * @param elements     not null elements to test
155      * @return found tag value or {@code defaultValue} if not found
156      * @since 3.0
157      */
158     public static String findTagValue(String tagName, String defaultValue, WithTagValuesOrStereotypes... elements) {
159         String result = findDirectTagValue(tagName, elements);
160 
161         if (result != null) {
162             return result;
163         }
164 
165         for (WithTagValuesOrStereotypes element : elements) {
166             if (element instanceof ObjectModelElement) {
167                 // try in declaring element
168                 ObjectModelElement declaringElement = ((ObjectModelElement) element).getDeclaringElement();
169                 if (declaringElement != null) {
170                     String value = findNotEmptyTagValue(tagName, declaringElement);
171                     if (value != null) {
172                         return value;
173                     }
174                 }
175             }
176         }
177         return defaultValue;
178     }
179 
180     public static boolean findBooleanTagValue(TagValueMetadata tagName, WithTagValuesOrStereotypes... elements) {
181         String value = findTagValue(tagName, elements);
182         return value != null && "true".equalsIgnoreCase(value);
183     }
184 
185     /**
186      * Seek for a Boolean tag value.
187      *
188      * Will first the tag value using the method {@link #findTagValue(TagValueMetadata, WithTagValuesOrStereotypes...)}.
189      *
190      * If not found, return {@code null}, otherwise return boolean value (case is ignored).
191      *
192      * <strong>Note:</strong> Order of {@code elements} is important, better then to
193      * always starts from specialized to more general level (for example from attribute,
194      * to classifier or model).
195      *
196      * @param tagName  tag name to find
197      * @param elements not null elements to test
198      * @return found boolean tag value or {@code null} if tag value not found.
199      * @since 3.0
200      */
201     public static Boolean findNullableBooleanTagValue(TagValueMetadata tagName, WithTagValuesOrStereotypes... elements) {
202         String value = findTagValue(tagName, elements);
203         return value == null ? null : "true".equalsIgnoreCase(value);
204     }
205 
206     /**
207      * Seek for a tag value amoung elements given using these rules:
208      * <ul>
209      * <li>Look into {@code elements} and return the first not empty tag value found.</li>
210      * <li>If not found return {@code defaultValue}</li>
211      * </ul>
212      * <strong>Note:</strong> Order of {@code elements} is important, better then to
213      * always starts from specialized to more general level (for example from attribute,
214      * to classifier or model).
215      *
216      * @param tagName  tag name to find
217      * @param elements not null elements to test
218      * @return found tag value or {@code null} if not found
219      * @since 3.0
220      */
221     public static String findDirectTagValue(TagValueMetadata tagName, WithTagValuesOrStereotypes... elements) {
222 
223         for (WithTagValuesOrStereotypes element : elements) {
224             String value = findNotEmptyTagValue(tagName, element);
225             if (value != null) {
226                 return value;
227             }
228         }
229 
230         return tagName.getDefaultValue();
231     }
232 
233     /**
234      * Seek for a tag value amoung elements given using these rules:
235      * <ul>
236      * <li>Look into {@code elements} and return the first not empty tag value found.</li>
237      * <li>If not found return {@code defaultValue}</li>
238      * </ul>
239      * <strong>Note:</strong> Order of {@code elements} is important, better then to
240      * always starts from specialized to more general level (for example from attribute,
241      * to classifier or model).
242      *
243      * @param tagName  tag name to find
244      * @param elements not null elements to test
245      * @return found tag value or {@code null} if not found
246      * @since 3.0
247      */
248     public static String findDirectTagValue(String tagName, WithTagValuesOrStereotypes... elements) {
249 
250         for (WithTagValuesOrStereotypes element : elements) {
251             String value = findNotEmptyTagValue(tagName, element);
252             if (value != null) {
253                 return value;
254             }
255         }
256 
257         return null;
258     }
259 
260     public static String findNotEmptyTagValue(TagValueMetadata tagName, WithTagValuesOrStereotypes element) {
261 
262         String value = null;
263         if (element != null) {
264             if (element instanceof ObjectModelPackage) {
265                 value = findNotEmptyTagValue(tagName, (ObjectModelPackage) element);
266             } else {
267                 value = element.getTagValue(tagName.getName());
268                 if (StringUtils.isEmpty(value)) {
269                     value = null;
270                 }
271             }
272         }
273         return value;
274 
275     }
276 
277     public static String findNotEmptyTagValue(String tagName, WithTagValuesOrStereotypes element) {
278 
279         String value = null;
280         if (element != null) {
281             if (element instanceof ObjectModelPackage) {
282                 value = findNotEmptyTagValue(tagName, (ObjectModelPackage) element);
283             } else {
284                 value = element.getTagValue(tagName);
285                 if (StringUtils.isEmpty(value)) {
286                     value = null;
287                 }
288             }
289         }
290         return value;
291 
292     }
293 
294 
295     protected static String findNotEmptyTagValue(TagValueMetadata tagName, ObjectModelPackage element) {
296 
297         String value = element.getTagValue(tagName.getName());
298         if (StringUtils.isEmpty(value)) {
299             value = null;
300         }
301         if (value == null && element.getParentPackage() != null) {
302             value = findNotEmptyTagValue(tagName, element.getParentPackage());
303         }
304         return value;
305 
306     }
307 
308     protected static String findNotEmptyTagValue(String tagName, ObjectModelPackage element) {
309 
310         String value = element.getTagValue(tagName);
311         if (StringUtils.isEmpty(value)) {
312             value = null;
313         }
314         if (value == null && element.getParentPackage() != null) {
315             value = findNotEmptyTagValue(tagName, element.getParentPackage());
316         }
317         return value;
318 
319     }
320 
321     public static Matcher getStereotypeMatcher(String key) throws InvalidStereotypeSyntaxException {
322         Matcher matcher = STEREOTYPE_PATTERN.matcher(key);
323         if (!matcher.find()) {
324             throw new InvalidStereotypeSyntaxException();
325         }
326         return matcher;
327     }
328 
329     public static Matcher getPackageStereotypeMatcher(String key) throws InvalidStereotypeSyntaxException {
330         Matcher matcher = PACKAGE_STEREOTYPE_PATTERN.matcher(key);
331         if (!matcher.find()) {
332             throw new InvalidStereotypeSyntaxException();
333         }
334         return matcher;
335     }
336 
337     public static Set<String> getStereotypes(String value) {
338         String[] split = value.split("\\s*,\\s*");
339         return ImmutableSet.<String>builder().add(split).build();
340     }
341 }