1 package org.objectweb.celtix.configuration.impl; 2 3 4 import java.io.File ; 5 import java.io.IOException ; 6 import java.io.InputStream ; 7 import java.io.Reader ; 8 import java.net.MalformedURLException ; 9 import java.net.URI ; 10 import java.net.URISyntaxException ; 11 import java.net.URL ; 12 import java.util.Collection ; 13 import java.util.HashMap ; 14 import java.util.Map ; 15 import java.util.logging.Level ; 16 import java.util.logging.Logger ; 17 18 import javax.xml.XMLConstants ; 19 import javax.xml.bind.JAXBContext; 20 import javax.xml.bind.JAXBElement; 21 import javax.xml.bind.JAXBException; 22 import javax.xml.bind.Unmarshaller; 23 import javax.xml.namespace.QName ; 24 import javax.xml.parsers.DocumentBuilder ; 25 import javax.xml.parsers.DocumentBuilderFactory ; 26 import javax.xml.parsers.ParserConfigurationException ; 27 import javax.xml.transform.Source ; 28 import javax.xml.transform.dom.DOMSource ; 29 import javax.xml.validation.Schema ; 30 import javax.xml.validation.SchemaFactory ; 31 import javax.xml.validation.Validator ; 32 33 import org.w3c.dom.Document ; 34 import org.w3c.dom.Element ; 35 import org.w3c.dom.Node ; 36 import org.w3c.dom.ls.LSInput ; 37 import org.w3c.dom.ls.LSResourceResolver ; 38 39 import org.xml.sax.ErrorHandler ; 40 import org.xml.sax.InputSource ; 41 import org.xml.sax.SAXException ; 42 import org.xml.sax.SAXParseException ; 43 44 import org.objectweb.celtix.common.i18n.Message; 45 import org.objectweb.celtix.common.logging.LogUtils; 46 import org.objectweb.celtix.configuration.ConfigurationException; 47 import org.objectweb.celtix.configuration.ConfigurationItemMetadata; 48 import org.objectweb.celtix.jaxb.JAXBUtils; 49 import org.objectweb.celtix.resource.DefaultResourceManager; 50 51 public class TypeSchema { 52 53 static final Logger LOG = LogUtils.getL7dLogger(TypeSchema.class); 54 55 private Schema schema; 56 private Validator validator; 57 private final String namespaceURI; 58 private String packageName; 59 private final Map <String , QName > elementDefinitions; 60 private final Map <String , String > typeDefinitions; 61 private final boolean forceDefaults; 62 63 66 protected TypeSchema(String nsuri, String baseURI, String location, Boolean fd) { 67 forceDefaults = fd; 68 namespaceURI = nsuri; 69 elementDefinitions = new HashMap <String , QName >(); 70 typeDefinitions = new HashMap <String , String >(); 71 72 LOG.fine("Creating type schema for namespace " + namespaceURI); 73 74 InputSource is = getSchemaInputSource(baseURI, location); 75 76 Document document = null; 77 try { 78 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 79 factory.setNamespaceAware(true); 80 DocumentBuilder parser = factory.newDocumentBuilder(); 81 document = parser.parse(is); 82 } catch (ParserConfigurationException ex) { 83 throw new ConfigurationException (new Message("PARSER_CONFIGURATION_ERROR_EXC", 84 LOG, location), ex); 85 } catch (SAXException ex) { 86 throw new ConfigurationException (new Message("PARSE_ERROR_EXC", LOG), ex); 87 } catch (IOException ex) { 88 throw new ConfigurationException (new Message("FILE_OPEN_ERROR_EXC", LOG, location), ex); 89 } 90 91 deserialize(document); 92 93 Source src = new DOMSource (document); 94 src.setSystemId(is.getSystemId()); 95 96 SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); 97 final LSResourceResolver oldResolver = factory.getResourceResolver(); 98 99 LSResourceResolver resolver = new LSResourceResolver () { 100 101 public LSInput resolveResource(String type, String nsURI, 102 String publicId, String systemId, String baseURI) { 103 if (LOG.isLoggable(Level.FINE)) { 104 LOG.fine("resolving resource type: " + type + "\n" 105 + " namespaceURI:" + nsURI + "\n" 106 + " publicId:" + publicId + "\n" 107 + " systemId:" + systemId + "\n" 108 + " baseURI:" + baseURI); 109 } 110 111 if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(type)) { 112 LSInput lsi = new SchemaInput(type, nsURI, publicId, systemId, baseURI); 113 String resourceName = systemId; 114 115 InputSource src = getSchemaInputSource(baseURI, resourceName); 116 lsi.setByteStream(src.getByteStream()); 117 lsi.setSystemId(src.getSystemId()); 118 return lsi; 119 } 120 return oldResolver == null ? null 121 : oldResolver.resolveResource(type, nsURI, publicId, systemId, baseURI); 122 } 123 }; 124 125 factory.setResourceResolver(resolver); 126 try { 127 schema = factory.newSchema(src); 128 } catch (SAXException ex) { 129 throw new ConfigurationException (new Message("SCHEMA_CREATION_ERROR_EXC", LOG, location), ex); 130 } 131 document = null; 132 133 LOG.fine("Created type schema for namespace " + namespaceURI); 134 } 135 136 public Validator getValidator() { 137 if (null == validator) { 138 Schema s = getSchema(); 139 validator = s.newValidator(); 140 validator.setErrorHandler(new TypeSchemaErrorHandler()); 141 } 142 return validator; 143 } 144 145 public Collection <String > getTypes() { 146 return typeDefinitions.keySet(); 147 } 148 149 public boolean hasType(String typeName) { 150 return typeDefinitions.containsKey(typeName); 151 } 152 153 public Collection <String > getElements() { 154 return elementDefinitions.keySet(); 155 } 156 157 public boolean hasElement(String elementName) { 158 return elementDefinitions.containsKey(elementName); 159 } 160 161 public QName getDeclaredType(String typeName) { 162 return elementDefinitions.get(typeName); 163 } 164 165 public String getXMLSchemaBaseType(String typeName) { 166 if (!hasType(typeName)) { 167 throw new ConfigurationException (new Message("TYPE_NOT_DEFINED_IN_NAMESPACE_EXC", LOG, 168 typeName, namespaceURI)); 169 170 } 171 return typeDefinitions.get(typeName); 172 } 173 174 public String getPackageName() { 175 return packageName; 176 } 177 178 public Schema getSchema() { 179 return schema; 180 } 181 182 public Object unmarshalDefaultValue(ConfigurationItemMetadata item, Element data) { 183 return unmarshalDefaultValue(item, data, false); 184 } 185 186 public Object unmarshalDefaultValue(ConfigurationItemMetadata item, Element data, boolean doValidate) { 187 try { 188 return unmarshal(item.getType(), data, doValidate); 189 } catch (JAXBException ex) { 190 if (forceDefaults) { 191 Message msg = new Message("DEFAULT_VALUE_UNMARSHAL_ERROR_EXC", LOG, item.getName()); 192 throw new ConfigurationException (msg, ex); 193 } 194 return null; 195 } 196 } 197 198 public Object unmarshal(QName type, Element data) throws JAXBException { 199 return unmarshal(type, data, true); 200 } 201 202 public Object unmarshal(QName type, Element data, boolean doValidate) throws JAXBException { 203 204 if (LOG.isLoggable(Level.FINE)) { 205 LOG.fine("unmarshalling: element namespaceURI: " + data.getNamespaceURI() + "\n" 206 + " localName: " + data.getLocalName() + "\n" 207 + " type: " + type + "\n" 208 + " type schema package name: " + packageName); 209 } 210 JAXBContext context = null; 211 Object obj = null; 212 213 context = JAXBContext.newInstance(packageName, getClass().getClassLoader()); 214 Unmarshaller u = context.createUnmarshaller(); 215 if (doValidate) { 216 u.setSchema(schema); 217 } 218 obj = u.unmarshal(data); 219 if (obj instanceof JAXBElement<?>) { 220 JAXBElement<?> el = (JAXBElement<?>)obj; 221 obj = el.getValue(); 222 225 } 226 227 if (null != obj && LOG.isLoggable(Level.FINE)) { 228 LOG.fine("Unmarshaled default value into object of type: " + obj.getClass().getName() 229 + " value: " + obj); 230 } 231 return obj; 232 } 233 234 private void deserialize(Document document) { 235 deseralizePackageName(document); 236 deserializeTypes(document); 237 deserializeElements(document); 238 } 239 240 private void deserializeElements(Document document) { 241 Element root = document.getDocumentElement(); 242 for (Node nd = root.getFirstChild(); nd != null; nd = nd.getNextSibling()) { 243 if (Node.ELEMENT_NODE == nd.getNodeType() && "element".equals(nd.getLocalName())) { 244 String elementName = ((Element)nd).getAttribute("name"); 245 246 QName type = ConfigurationMetadataUtils 247 .elementAttributeToQName(document, (Element)nd, "type"); 248 249 elementDefinitions.put(elementName, type); 250 if (LOG.isLoggable(Level.FINE)) { 251 LOG.fine("Added type " + type + " for key: " + elementName); 252 } 253 } 254 } 255 } 256 257 private void deserializeTypes(Document document) { 258 Element root = document.getDocumentElement(); 259 for (Node nd = root.getFirstChild(); nd != null; nd = nd.getNextSibling()) { 260 if (Node.ELEMENT_NODE == nd.getNodeType() 261 && ("simpleType".equals(nd.getLocalName()) || ("complexType".equals(nd.getLocalName())))) { 262 263 String typeName = ((Element)nd).getAttribute("name"); 264 265 String baseType = null; 266 if ("simpleType".equals(nd.getLocalName())) { 267 baseType = getBaseType(document, typeName); 268 } 269 270 if (!typeDefinitions.containsKey(typeName)) { 271 typeDefinitions.put(typeName, baseType); 272 if (LOG.isLoggable(Level.FINE)) { 273 LOG.fine("Added base type " + baseType + " for key: " + typeName); 274 } 275 } 276 277 } 278 } 279 } 280 281 private String getBaseType(Document document, String typeName) { 282 String currentType = typeName; 283 QName baseType; 284 do { 285 baseType = getBaseTypeInternal(document, currentType); 286 if (null == baseType) { 287 LOG.severe(new Message("UNDEFINED_SIMPLE_TYPE_MSG", LOG, typeName).toString()); 288 return null; 289 } else if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(baseType.getNamespaceURI())) { 290 if (LOG.isLoggable(Level.FINE)) { 291 LOG.fine("Base type for " + typeName + ": " + baseType); 292 } 293 return baseType.getLocalPart(); 294 } else if (!namespaceURI.equals(baseType.getNamespaceURI())) { 295 LOG.severe(new Message("SIMPLE_TYPE_DEFINED_IN_OTHER_NAMESPACE_MSG", LOG, typeName, 296 namespaceURI).toString()); 297 return null; 298 } 299 currentType = baseType.getLocalPart(); 300 } while (true); 301 } 302 303 private QName getBaseTypeInternal(Document document, String type) { 304 Element root = document.getDocumentElement(); 305 Element simpleTypeElement = null; 306 307 for (Node nd = root.getFirstChild(); nd != null; nd = nd.getNextSibling()) { 308 if (Node.ELEMENT_NODE == nd.getNodeType() && "simpleType".equals(nd.getLocalName()) 309 && ((Element)nd).getAttribute("name").equals(type)) { 310 simpleTypeElement = (Element)nd; 311 } 312 } 313 if (null == simpleTypeElement) { 314 return null; 315 } 316 317 for (Node nd = simpleTypeElement.getFirstChild(); nd != null; nd = nd.getNextSibling()) { 318 if (Node.ELEMENT_NODE == nd.getNodeType() && "restriction".equals(nd.getLocalName())) { 319 324 return ConfigurationMetadataUtils.elementAttributeToQName(document, (Element)nd, "base"); 325 } 326 } 327 return null; 328 } 329 330 private void deseralizePackageName(Document document) { 331 Element root = document.getDocumentElement(); 332 Element annotationElement = null; 333 for (Node nd = root.getFirstChild(); nd != null; nd = nd.getNextSibling()) { 334 if (Node.ELEMENT_NODE == nd.getNodeType() && "annotation".equals(nd.getLocalName())) { 335 annotationElement = (Element)nd; 336 break; 337 } 338 } 339 Element appInfoElement = null; 340 if (null != annotationElement) { 341 for (Node nd = annotationElement.getFirstChild(); nd != null; nd = nd.getNextSibling()) { 342 if (Node.ELEMENT_NODE == nd.getNodeType() && "appinfo".equals(nd.getLocalName())) { 343 appInfoElement = (Element)nd; 344 break; 345 } 346 } 347 } 348 Element schemaBindingsElement = null; 349 if (null != appInfoElement) { 350 for (Node nd = appInfoElement.getFirstChild(); nd != null; nd = nd.getNextSibling()) { 351 if (Node.ELEMENT_NODE == nd.getNodeType() && "schemaBindings".equals(nd.getLocalName())) { 352 schemaBindingsElement = (Element)nd; 353 break; 354 } 355 } 356 } 357 Element packageElement = null; 358 if (null != schemaBindingsElement) { 359 for (Node nd = schemaBindingsElement.getFirstChild(); nd != null; nd = nd.getNextSibling()) { 360 if (Node.ELEMENT_NODE == nd.getNodeType() && "package".equals(nd.getLocalName())) { 361 packageElement = (Element)nd; 362 break; 363 } 364 } 365 } 366 367 if (null != packageElement) { 368 packageName = packageElement.getAttribute("name"); 369 } else { 370 packageName = JAXBUtils.namespaceURIToPackage(namespaceURI); 371 } 372 373 if (null == packageName) { 374 throw new ConfigurationException (new Message("MISSING_PACKAGE_NAME_EXC", LOG, namespaceURI)); 375 } 376 377 } 378 379 static InputSource getSchemaInputSource(String baseURI, String location) { 380 URI uri = null; 381 URI base = null; 382 URI resolved = null; 383 try { 384 uri = new URI (location); 385 if (baseURI != null) { 386 try { 387 base = new URI (baseURI); 388 resolved = base.resolve(uri); 389 } catch (URISyntaxException ex) { 390 base = null; 391 resolved = null; 392 } 393 } 394 } catch (URISyntaxException ex) { 395 Message msg = new Message("SCHEMA_LOCATION_ERROR_EXC", LOG, location); 396 throw new ConfigurationException (msg, ex); 397 } 398 399 if (!uri.isAbsolute() && resolved != null && resolved.isAbsolute()) { 400 uri = resolved; 401 } 402 403 if (uri.isAbsolute()) { 404 if ("file".equals(uri.getScheme())) { 405 String path = uri.getPath(); 406 if (null == path) { 407 Message msg = new Message("FILE_OPEN_ERROR_EXC", LOG, location); 408 throw new ConfigurationException (msg); 409 } 410 File file = new File (path); 411 if (file.exists()) { 412 return new InputSource (file.toURI().toString()); 413 } 414 } else { 415 } 417 } 418 419 URL url = DefaultResourceManager.instance().resolveResource(location, URL .class); 421 if (null != url) { 422 return new InputSource (url.toString()); 423 } 424 425 if (baseURI != null) { 427 try { 428 url = new URL (baseURI); 429 url = new URL (url, location); 430 InputStream ins = url.openStream(); 431 if (ins != null) { 432 InputSource src = new InputSource (ins); 433 src.setSystemId(url.toString()); 434 return src; 435 } 436 } catch (MalformedURLException e) { 437 } catch (IOException e) { 439 } 441 } 442 443 452 453 throw new ConfigurationException (new Message("SCHEMA_LOCATION_ERROR_EXC", LOG, location)); 454 } 455 456 458 static class TypeSchemaErrorHandler implements ErrorHandler { 459 460 public void error(SAXParseException exception) throws SAXParseException { 461 throw exception; 462 } 463 464 public void fatalError(SAXParseException exception) throws SAXParseException { 465 throw exception; 466 } 467 468 public void warning(SAXParseException exception) throws SAXParseException { 469 throw exception; 470 } 471 } 472 473 static final class SchemaInput implements LSInput { 474 String type; 475 String namespaceURI; 476 String publicId; 477 String systemId; 478 String baseURI; 479 InputStream is; 480 481 SchemaInput(String t, String nsuri, String pid, String sid, String buri) { 482 type = t; 483 namespaceURI = nsuri; 484 publicId = pid; 485 systemId = sid; 486 baseURI = buri; 487 } 488 489 public String getBaseURI() { 490 return baseURI; 491 } 492 493 public InputStream getByteStream() { 494 return is; 495 } 496 497 public boolean getCertifiedText() { 498 return false; 499 } 500 501 public Reader getCharacterStream() { 502 return null; 503 } 504 505 public String getEncoding() { 506 return null; 507 } 508 509 public String getPublicId() { 510 return publicId; 511 } 512 513 public String getStringData() { 514 return null; 515 } 516 517 public String getSystemId() { 518 return systemId; 519 } 520 521 public void setBaseURI(String buri) { 522 baseURI = buri; 523 } 524 525 public void setByteStream(InputStream byteStream) { 526 is = byteStream; 527 } 528 529 public void setCertifiedText(boolean certifiedText) { 530 } 531 532 public void setCharacterStream(Reader characterStream) { 533 } 534 535 public void setEncoding(String encoding) { 536 } 537 538 public void setPublicId(String pid) { 539 publicId = pid; 540 } 541 542 public void setStringData(String stringData) { 543 } 544 545 public void setSystemId(String sid) { 546 systemId = sid; 547 } 548 549 } 550 } 551 | Popular Tags |