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>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>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 }