1 10 package org.mmbase.datatypes.util.xml; 11 12 import java.util.*; 13 import org.w3c.dom.*; 14 import java.lang.reflect.Method ; 15 import java.lang.reflect.InvocationTargetException ; 16 17 import org.mmbase.bridge.Field; 18 import org.mmbase.datatypes.processors.*; 19 import org.mmbase.bridge.util.Queries; 20 import org.mmbase.datatypes.*; 21 import org.mmbase.core.util.Fields; 22 import org.mmbase.util.*; 23 import org.mmbase.util.functions.Parameters; 24 import org.mmbase.util.xml.DocumentReader; 25 import org.mmbase.util.xml.XMLWriter; 26 import org.mmbase.util.logging.*; 27 import org.mmbase.util.transformers.*; 28 29 40 public class DataTypeDefinition { 41 42 private static final Logger log = Logging.getLoggerInstance(DataTypeDefinition.class); 43 44 47 public BasicDataType dataType = null; 48 49 52 private BasicDataType baseDataType = null; 53 54 57 protected final DataTypeCollector collector; 58 59 62 public DataTypeDefinition(DataTypeCollector collector) { 63 this.collector = collector; 64 } 65 66 72 private void getImplementation(Element dataTypeElement, String id) { 73 BasicDataType dt = id.equals("") ? null : collector.getDataType(id); 74 if (dt != null) { 75 collector.rewrite(dt); 76 } 77 78 NodeList childNodes = dataTypeElement.getChildNodes(); 80 for (int i = 0; i < childNodes.getLength(); i++) { 81 if (childNodes.item(i) instanceof Element) { 82 Element childElement = (Element) childNodes.item(i); 83 if (childElement.getLocalName().equals("class")) { 84 String className = childElement.getAttribute("name"); 85 if (dt != null) { 86 log.debug("Already defined " + id); 87 if (! className.equals(dt.getClass().getName())) { 88 log.error("Cannot change class for '" + id + "' from " + dt.getClass().getName() + " to '" + className + "'"); 89 } 90 } else { 91 try { 92 Class claz = Class.forName(className); 93 log.debug("Instantiating " + claz + " for " + dataType); 94 java.lang.reflect.Constructor constructor = claz.getConstructor(new Class [] { String .class}); 95 dt = (BasicDataType) constructor.newInstance(new Object [] { id }); 96 if (baseDataType != null) { 97 dt.inherit((BasicDataType) baseDataType); 99 } 100 } catch (Exception e) { 101 log.error(e); 102 } 103 } 104 break; 105 } else { 106 continue; 107 } 108 } 109 } 110 if (dt == null) { if (baseDataType == null) { 112 log.warn("No base datatype available and no class specified for datatype '" + id + "', using 'unknown' for know.\n" + XMLWriter.write(dataTypeElement, true, true)); 113 baseDataType = Constants.DATATYPE_UNKNOWN; 114 } 115 dataType = (BasicDataType) baseDataType.clone(id); 116 } else { log.debug("Existing datatype " + dt + " with base " + baseDataType); 118 dataType = dt; 119 } 120 121 } 122 123 126 DataTypeDefinition configure(Element dataTypeElement, BasicDataType requestBaseDataType) { 127 128 String id = DataTypeXml.getAttribute(dataTypeElement, "id"); 129 130 String base = DataTypeXml.getAttribute(dataTypeElement, "base"); 131 132 if (log.isDebugEnabled()) { 133 log.debug("Reading element id='" + id + "' base='" + base + "' req datatype " + requestBaseDataType); 134 } 135 if (! base.equals("")) { 137 BasicDataType definedBaseDataType = collector.getDataType(base, true); 138 if (requestBaseDataType != null) { 139 if (requestBaseDataType != definedBaseDataType) { 140 if ("".equals(id)) { 141 log.debug("Inheriting a " + definedBaseDataType + " from " + requestBaseDataType + ", functionality may get lost"); 144 } else { 145 log.warn("Attribute 'base' ('" + base+ "') not allowed with datatype '" + id + "', because it has already an baseDataType '" + definedBaseDataType + "' in " + XMLWriter.write(dataTypeElement, true, true) + " of " + XMLWriter.write(dataTypeElement.getParentNode(), true, true)); 146 } 147 definedBaseDataType = requestBaseDataType; } 149 } 150 151 if (definedBaseDataType == null) { 152 log.warn("Attribute 'base' ('" + base + "') of datatype '" + id + "' is an unknown datatype."); 153 } else { 154 requestBaseDataType = definedBaseDataType; 155 } 156 } 157 158 baseDataType = requestBaseDataType; 159 getImplementation(dataTypeElement, id); 160 LocalizedString description = dataType.getLocalizedDescription(); 161 DataTypeXml.getLocalizedDescription("description", dataTypeElement, description, dataType.getName()); 162 configureConditions(dataTypeElement, id); 163 164 return this; 165 } 166 167 private static final java.util.regex.Pattern nonConditions = java.util.regex.Pattern.compile("specialization|datatype|class|description"); 168 169 172 protected void configureConditions(Element dataTypeElement, String id) { 173 log.debug("Now going to configure " + dataType); 174 NodeList childNodes = dataTypeElement.getChildNodes(); 176 for (int k = 0; k < childNodes.getLength(); k++) { 177 if (childNodes.item(k) instanceof Element) { 178 Element childElement = (Element) childNodes.item(k); 179 if (childElement.getLocalName().equals("")) { 180 continue; 181 } 182 if (nonConditions.matcher(childElement.getLocalName()).matches()) { 183 continue; 184 } 185 log.debug("Considering " + childElement.getLocalName() + " for " + dataType); 186 if (!addCondition(childElement)) { 187 log.error("" + XMLWriter.write(childElement, true, true) + " defines '" + childElement.getLocalName() + "', but " + dataType + " doesn't support that"); 188 } 189 } 190 } 191 } 192 193 198 protected boolean addCondition(Element childElement) { 199 boolean ret = false; 200 String childTag = childElement.getLocalName(); 201 if ("property".equals(childTag)) { 202 ret = setProperty(childElement); 203 } else if ("required".equals(childTag)) { 204 boolean value = DataTypeXml.getBooleanValue(childElement, false); 205 dataType.setRequired(value); 206 setRestrictionData(dataType.getRequiredRestriction(), childElement); 207 ret = true; 208 } else if ("unique".equals(childTag)) { 209 boolean value = DataTypeXml.getBooleanValue(childElement, false); 210 dataType.setUnique(value); 211 setRestrictionData(dataType.getUniqueRestriction(), childElement); 212 ret = true; 213 } else if ("getprocessor".equals(childTag)) { 214 addProcessor(DataType.PROCESS_GET, childElement); 215 ret = true; 216 } else if ("setprocessor".equals(childTag)) { 217 addProcessor(DataType.PROCESS_SET, childElement); 218 ret = true; 219 } else if ("commitprocessor".equals(childTag)) { 220 addCommitProcessor(childElement); 221 ret = true; 222 } else if ("enumeration".equals(childTag)) { 223 addEnumeration(childElement); 224 ret = true; 225 } else if ("default".equals(childTag)) { 226 String value = DataTypeXml.getAttribute(childElement, "value"); 227 dataType.setDefaultValue(value); 228 ret = true; 229 } else if (addPatternCondition(childElement)) { 230 ret = true; 231 } else if (addPasswordProperty(childElement)) { 232 ret = true; 233 } else if (addLengthDataCondition(childElement)) { 234 ret = true; 235 } else if (addComparableCondition(childElement)) { 236 ret = true; 237 } 238 return ret; 239 } 240 241 242 private void addProcessor(int action, int processingType, Processor newProcessor) { 243 Processor oldProcessor = dataType.getProcessor(action, processingType); 244 newProcessor = DataTypeXml.chainProcessors(oldProcessor, newProcessor); 245 log.debug(dataType + " Found processor " + oldProcessor + "--> " + newProcessor); 246 dataType.setProcessor(action, newProcessor, processingType); 247 } 248 249 250 protected void addProcessor(int action, Element processorElement) { 251 Processor newProcessor = DataTypeXml.createProcessor(processorElement); 252 if (newProcessor != null) { 253 String type = processorElement.getAttribute("type"); 254 if (type.equals("")) { 255 addProcessor(action, Field.TYPE_UNKNOWN, newProcessor); 256 } else if (type.equals("*")) { 257 for (int i = Fields.TYPE_MINVALUE; i <= Fields.TYPE_MAXVALUE; i++) { 258 BasicDataType basicDataType = DataTypes.getDataType(i); 259 int processingType = Fields.classToType(basicDataType.getTypeAsClass()); 260 addProcessor(action, processingType, newProcessor); 261 } 262 } else { 263 int processingType = Field.TYPE_UNKNOWN; 264 BasicDataType basicDataType = DataTypes.getDataType(type); 265 if (basicDataType != null) { 267 processingType = Fields.classToType(basicDataType.getTypeAsClass()); 268 } else { 269 log.warn("Datatype " + type + " is unknown, create processor as a default processor"); 270 } 271 addProcessor(action, processingType, newProcessor); 272 } 273 } 274 } 275 276 protected void addCommitProcessor(Element processorElement) { 277 CommitProcessor newProcessor = DataTypeXml.createCommitProcessor(processorElement); 278 CommitProcessor oldProcessor = dataType.getCommitProcessor(); 279 newProcessor = DataTypeXml.chainProcessors(oldProcessor, newProcessor); 280 dataType.setCommitProcessor(newProcessor); 281 } 282 283 protected void setRestrictionData(DataType.Restriction restriction, Element element) { 284 if (DataTypeXml.hasAttribute(element, "fixed")) { 285 boolean isFixed = Boolean.valueOf(DataTypeXml.getAttribute(element, "fixed")).booleanValue(); 286 restriction.setFixed(isFixed); 287 } 288 String enforce = DataTypeXml.getAttribute(element, "enforce").toLowerCase(); 289 if (enforce.equals("absolute")) { 290 restriction.setEnforceStrength(DataType.ENFORCE_ABSOLUTE); 291 } else if (enforce.equals("always") || enforce.equals("")) { 292 restriction.setEnforceStrength(DataType.ENFORCE_ALWAYS); 293 } else if (enforce.equals("onchange")) { 294 restriction.setEnforceStrength(DataType.ENFORCE_ONCHANGE); 295 } else if (enforce.equals("oncreate")) { 296 restriction.setEnforceStrength(DataType.ENFORCE_ONCREATE); 297 } else if (enforce.equals("never")) { 298 restriction.setEnforceStrength(DataType.ENFORCE_NEVER); 299 } else { 300 log.warn("Unrecognised value for 'enforce' attribute '" + enforce + "' in " + XMLWriter.write(element, true, true)); 301 } 302 LocalizedString descriptions = restriction.getErrorDescription(); 303 restriction.setErrorDescription(DataTypeXml.getLocalizedDescription("description", element, descriptions, null)); 304 } 305 306 309 protected void addEnumeration(Element enumerationElement) { 310 LocalizedEntryListFactory fact = dataType.getEnumerationFactory(); 311 setRestrictionData(dataType.getEnumerationRestriction(), enumerationElement); 312 fact.clear(); 313 fact.fillFromXml(enumerationElement, dataType.getTypeAsClass()); 314 } 315 316 protected boolean setProperty(Element element) { 317 try { 318 String name = DataTypeXml.getAttribute(element, "name"); 319 String methodName = "set" + name.substring(0, 1).toUpperCase() + name.substring(1); 320 String value = DataTypeXml.getAttribute(element, "value"); 321 Class claz = dataType.getClass(); 322 Method method = claz.getMethod(methodName, new Class [] {String .class}); 323 method.invoke(dataType, new Object [] { value }); 324 } catch (NoSuchMethodException nsme) { 325 log.warn(nsme); 326 return false; 327 } catch (SecurityException se) { 328 log.warn(se); 329 return false; 330 } catch (IllegalAccessException iae) { 331 log.warn(iae); 332 return false; 333 } catch (InvocationTargetException ite) { 334 log.warn(ite); 335 return false; 336 } 337 return true; 338 } 339 340 344 protected boolean addLengthDataCondition(Element conditionElement) { 345 if (dataType instanceof LengthDataType) { 346 String localName = conditionElement.getLocalName(); 347 LengthDataType bDataType = (LengthDataType) dataType; 348 if ("minLength".equals(localName)) { 349 long value = DataTypeXml.getLongValue(conditionElement); 350 bDataType.setMinLength(value); 351 setRestrictionData(bDataType.getMinLengthRestriction(), conditionElement); 352 return true; 353 } else if ("maxLength".equals(localName)) { 354 long value = DataTypeXml.getLongValue(conditionElement); 355 bDataType.setMaxLength(value); 356 setRestrictionData(bDataType.getMaxLengthRestriction(), conditionElement); 357 return true; 358 } else if ("length".equals(localName)) { 359 long value = DataTypeXml.getLongValue(conditionElement); 360 bDataType.setMinLength(value); 361 setRestrictionData(bDataType.getMinLengthRestriction(), conditionElement); 362 bDataType.setMaxLength(value); 363 setRestrictionData(bDataType.getMaxLengthRestriction(), conditionElement); 364 return true; 365 } 366 } 367 return false; 368 } 369 370 371 372 protected boolean addPasswordProperty(Element propertyElement) { 373 String localName = propertyElement.getLocalName(); 374 if ("password".equals(localName) && (dataType instanceof StringDataType)) { 375 StringDataType stringDataType = (StringDataType) dataType; 376 boolean value = Casting.toBoolean(DataTypeXml.getAttribute(propertyElement, "value")); 377 stringDataType.setPassword(value); 378 return true; 379 } 380 return false; 381 } 382 383 387 388 protected boolean addPatternCondition(Element conditionElement) { 389 String localName = conditionElement.getLocalName(); 390 if (dataType instanceof StringDataType) { 391 StringDataType sDataType = (StringDataType) dataType; 392 if ("pattern".equals(localName)) { 393 String value = DataTypeXml.getAttribute(conditionElement, "value"); 394 log.debug("Setting pattern on " + sDataType); 395 sDataType.setPattern(java.util.regex.Pattern.compile(value)); 396 setRestrictionData(sDataType.getPatternRestriction(), conditionElement); 397 return true; 398 } 399 } else if (dataType instanceof DateTimeDataType) { 400 DateTimeDataType sDataType = (DateTimeDataType) dataType; 401 if ("pattern".equals(localName)) { 402 String value = DataTypeXml.getAttribute(conditionElement, "value"); 403 Locale locale = LocalizedString.getLocale(conditionElement); 404 sDataType.setPattern(value, locale); 405 return true; 406 } 407 } else if (dataType instanceof BinaryDataType) { BinaryDataType sDataType = (BinaryDataType) dataType; 409 if ("pattern".equals(localName)) { 410 String value = DataTypeXml.getAttribute(conditionElement, "value"); 411 sDataType.setValidMimeTypes(java.util.regex.Pattern.compile(value)); 412 return true; 413 } 414 } 415 return false; 416 } 417 418 423 424 protected boolean addComparableCondition(Element conditionElement) { 425 if (dataType instanceof ComparableDataType) { 426 String localName = conditionElement.getLocalName(); 427 ComparableDataType dDataType = (ComparableDataType) dataType; 428 if ("minExclusive".equals(localName) || "minInclusive".equals(localName)) { 429 Comparable value = (Comparable ) dDataType.cast(DataTypeXml.getValue(conditionElement), null, null); 430 dDataType.setMin(value, "minInclusive".equals(localName)); 431 setRestrictionData(dDataType.getMinRestriction(), conditionElement); 432 return true; 433 } else if ("maxExclusive".equals(localName) || "maxInclusive".equals(localName)) { 434 Comparable value = (Comparable ) dDataType.cast(DataTypeXml.getValue(conditionElement), null, null); 435 dDataType.setMax(value, "maxInclusive".equals(localName)); 436 setRestrictionData(dDataType.getMaxRestriction(), conditionElement); 437 return true; 438 } 439 } 440 return false; 441 } 442 443 444 public String toString() { 445 return "definition(" + (dataType == null ? "NONE" : dataType.toString()) + ")"; 446 } 447 448 } 449 | Popular Tags |