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 }