View Javadoc
1   /*
2    * #%L
3    * Nuiton Utils
4    * %%
5    * Copyright (C) 2004 - 2010 CodeLutin
6    * %%
7    * This program is free software: you can redistribute it and/or modify
8    * it under the terms of the GNU Lesser General Public License as 
9    * published by the Free Software Foundation, either version 3 of the 
10   * License, or (at your option) any later version.
11   * 
12   * This program is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   * GNU General Lesser Public License for more details.
16   * 
17   * You should have received a copy of the GNU General Lesser Public 
18   * License along with this program.  If not, see
19   * <http://www.gnu.org/licenses/lgpl-3.0.html>.
20   * #L%
21   */
22  
23  package org.nuiton.util;
24  
25  import java.util.regex.Matcher;
26  import java.util.regex.Pattern;
27  
28  /**
29   * Une classe avec des méthodes utiles sur les cardinalités :
30   *
31   * parser une cardinalité {@link #parseCardinalite(String, boolean)}
32   *
33   * afficher une cardinité {@link #printCardinalite(StringBuilder, String, int, int, boolean, String, String, String, String)}
34   *
35   * et pour tester des cardinalités :
36   *
37   * {@link #isMandatory(int)}, savoir si une cardinalité est obligatoire à
38   * partir de son min.
39   *
40   * {@link #isRepetable(int)}, savoir si une cardinalité est répétable à partir
41   * de son max.
42   *
43   * {@link #isMaxBounded(int)}, savoir si une cardinalité est bornée sur son max
44   * à partir de son max.
45   *
46   * {@link #isDefaultMandatory(int, int)}, savoir si la cardinalité est la
47   * cardinalité obligatoire par défaut {1}.
48   *
49   * {@link #isDefaultOptional(int, int)}, savoir si la cardinalité est la
50   * cardinalité optionel par défaut {0,1}.
51   *
52   * {@link #isAvailable(int, int)}, savoir si il reste encore des occurrences
53   * disponibles sur une cardianlité à partir d'un nombre d'oocurrence et du max
54   * de la cardinalité.
55   *
56   * @author Tony Chemit - chemit@codelutin.com
57   */
58  public class CardinalityHelper {
59  
60      static final Pattern PATTERN_OPTIONAL = Pattern.compile("\\[.*\\]");
61  
62      static final Pattern PATTERN_MANDATORY = Pattern.compile("\\<.*\\>");
63  
64      /** XXX + ou XXX * */
65      public static final Pattern PATTERN_NO_MAX_BOUND = Pattern.compile("(.*)(\\+|\\*)");
66  
67      /** XXX {n} n est un entier */
68      public static final Pattern PATTERN_EXTACLY = Pattern.compile("(.*)\\{([0-9]+)\\}");
69  
70      /** XXX {n,m} n est un entier, m est un entier ou * */
71      public static final Pattern PATTERN_BOUNDED = Pattern.compile("(.*)\\{([0-9]+),([0-9]+|\\*)\\}");
72  
73      /**
74       * Indique si une cardinalité est la cardinalité obligatoire par défaut {1}
75       *
76       * @param min le min de la cardinalité à tester
77       * @param max le max de la cardinalité à tester
78       * @return {@code true} si min==1 et max=1
79       */
80      public static boolean isDefaultMandatory(int min, int max) {
81          return min == 1 && max == 1;
82      }
83  
84      /**
85       * Indique si une cardinalité est la cardinalité optionel par défaut {0,1}
86       *
87       * @param min le min de la cardinalité à tester
88       * @param max le max de la cardinalité à tester
89       * @return {@code true} si min==0 et max==1
90       */
91      public static boolean isDefaultOptional(int min, int max) {
92          return min == 0 && max == 1;
93      }
94  
95      /**
96       * Indique si une cardinalité est obligatoire à partir de son min
97       *
98       * @param min le min de la cardinalité à tester
99       * @return {@code true} si min&gt;0
100      */
101     public static boolean isMandatory(int min) {
102         return min > 0;
103     }
104 
105     /**
106      * Indique si une cardinalité est majorée à partir de son max
107      *
108      * @param max le max de la cardinalité à tester
109      * @return {@code true} si max≠-1
110      */
111     public static boolean isMaxBounded(int max) {
112         return max != -1;
113     }
114 
115     /**
116      * Indique si une cardinalité est répétable à partir de son max
117      *
118      * @param max le max de la cardinalité à tester
119      * @return {@code true} si max&gt;0 || max==-1
120      */
121     public static boolean isRepetable(int max) {
122         return !isMaxBounded(max) || max > 1;
123     }
124 
125     /**
126      * Indique si on n'a pas encore  atteint la borne max d'une cardinalité à
127      * partir de son max et d'un nombre d'occurrences déjà atteint.
128      *
129      * @param current le nombre d'occurence actuel
130      * @param max     la borne max de la cardinalité
131      * @return {@code true} si la cardinalité n'a pas atteint sa borne max
132      */
133 
134     public static boolean isAvailable(int current, int max) {
135         return !isMaxBounded(max) || current < max;
136     }
137 
138     /**
139      * Retourne le min par défault d'une cardinalité à partir du critère
140      * obligatoire ou non.
141      *
142      * @param mandatory le critère à tester
143      * @return {@code 1} si obligatoire, 0 sinon.
144      */
145     public static int getDefaultMin(boolean mandatory) {
146         return mandatory ? 1 : 0;
147     }
148 
149     /**
150      * Parse la cardinalite à la fin d'un texte.
151      *
152      * @param txt       la valeur dont on cherche la cardinalité
153      * @param mandatory si vrai, valeurs par default {1}, sinon {0,1}
154      * @return un tableau contenant 3 object : le texte donné sans les
155      *         informations de cardinalité, la répétitionMin, la répétitionMax.
156      */
157     public static Object[] parseCardinalite(String txt, boolean mandatory) {
158 
159         Object[] result = new Object[3];
160         Matcher matcher;
161 
162         // always trim the text
163         txt = txt.trim();
164         if ((matcher = PATTERN_NO_MAX_BOUND.matcher(txt)).matches()) {
165             // find a no max cardinalite *|+
166             result[0] = matcher.group(1).trim();
167             result[1] = getDefaultMin(matcher.group(2).equals("+"));
168             result[2] = -1;
169         } else if ((matcher = PATTERN_EXTACLY.matcher(txt)).matches()) {
170             // found a exactly cardinalite {n}
171             result[0] = matcher.group(1).trim();
172             result[1] = Integer.valueOf(matcher.group(2));
173             result[2] = result[1];
174         } else if ((matcher = PATTERN_BOUNDED.matcher(txt)).matches()) {
175             // found a bounded cardinalite {n,m}
176             result[0] = matcher.group(1).trim();
177             result[1] = Integer.valueOf(matcher.group(2));
178             String max = matcher.group(3);
179             result[2] = max.equals("*") ? -1 : Integer.valueOf(max);
180         } else {
181             // no cardinalite was found, use default values
182             result[0] = txt.trim();
183             result[1] = getDefaultMin(mandatory);
184             result[2] = 1;
185         }
186         return result;
187     }
188 
189     /**
190      * Imprime dans le builder, le txt + une cardinalité.
191      *
192      * @param sb        le builder
193      * @param txt       le txt à imprimer
194      * @param min       la caridnalité min
195      * @param max       la cardinalité max
196      * @param mandatory pour indiquer dans quel cas on affiche la cardinalité :
197      *                  si elle correspond aux valeurs par défaut
198      *                  de mandatory {1} ou optionel {0,1}, pas d'impression.
199      * @param mo        le caractère ouvrant pour un object obligatoire
200      * @param mc        le caractère fermant pour un object obligatoire
201      * @param oo        le caractère ouvrant pour un object optionel
202      * @param oc        le caractère fermant pour un object optionel
203      */
204     public static void printCardinalite(StringBuilder sb, String txt, int min, int max, boolean mandatory, String mo, String mc, String oo, String oc) {
205         // flag pour indiquer s'il faut ou non imprimer les bordures
206         boolean print = false;
207 
208         boolean maxBounded = isMaxBounded(max);
209         if (isMandatory(min)) {
210             sb.append(mo).append(txt).append(mc);
211             if (isDefaultMandatory(min, max)) {
212                 if (mandatory || mo.length() > 0) {
213                     // rien a faire on a la valeur par defaut attendue, ou la
214                     // bordure existe et remplace la valeur par defaut
215                 } else {
216                     // pas de bordure, ou valeur optionel attendue, on doit imprimer la cardinalite
217                     print = true;
218                 }
219             } else {
220                 if (!maxBounded && min == 1) {
221                     sb.append('+');
222                 } else {
223                     print = true;
224                 }
225             }
226         } else {
227             sb.append(oo).append(txt).append(oc);
228             if (isDefaultOptional(min, max)) {
229                 if (!mandatory || oo.length() > 0) {
230                     // rien a faire on a la valeur par defaut attendue, ou la
231                     // bordure existe et remplace la valeur par defaut
232                 } else {
233                     // pas de bordure, ou valeur optionel attendue, on doit imprimer la cardinalite
234                     print = true;
235                 }
236             } else {
237                 if (!maxBounded) {
238                     sb.append('*');
239                 } else {
240                     print = true;
241                 }
242             }
243         }
244         if (print) {
245             sb.append('{');
246             sb.append(min);
247             if (max != min) {
248                 sb.append(',');
249                 sb.append(maxBounded ? max : "*");
250             }
251             sb.append('}');
252         }
253     }
254 
255     protected CardinalityHelper() {
256         // do not instanciate
257     }
258 
259 }