001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.servicemix.common.tools.wsdl;
018
019 import java.net.URI;
020 import java.util.Collection;
021 import java.util.ArrayList;
022 import java.util.Collections;
023 import java.util.HashMap;
024 import java.util.Iterator;
025 import java.util.List;
026 import java.util.Map;
027
028 import javax.xml.parsers.DocumentBuilder;
029 import javax.xml.parsers.DocumentBuilderFactory;
030
031 import org.apache.commons.logging.Log;
032 import org.apache.commons.logging.LogFactory;
033 import org.w3c.dom.Document;
034 import org.w3c.dom.Element;
035 import org.w3c.dom.Node;
036 import org.w3c.dom.NodeList;
037 import org.xml.sax.InputSource;
038
039 /**
040 * Collection of schemas.
041 *
042 * @author gnodet
043 */
044 public class SchemaCollection {
045
046 private static Log log = LogFactory.getLog(SchemaCollection.class);
047
048 private Map<String, Schema> schemas;
049 private URI baseUri;
050
051 public SchemaCollection() {
052 this(null);
053 }
054
055 public SchemaCollection(URI baseUri) {
056 if (log.isDebugEnabled()) {
057 log.debug("Initializing schema collection with baseUri: " + baseUri);
058 }
059 this.baseUri = baseUri;
060 this.schemas = new HashMap<String, Schema>();
061 }
062
063 public Schema getSchema(String namespaceURI) {
064 return schemas.get(namespaceURI);
065 }
066
067 public void read(Element elem, URI sourceUri) throws Exception {
068 String namespace = elem.getAttribute("targetNamespace");
069 Schema schema = schemas.get(namespace);
070 if (schema == null) {
071 schema = new Schema();
072 schema.addSourceUri(sourceUri);
073 schema.setRoot(elem);
074 schema.setNamespace(elem.getAttribute("targetNamespace"));
075 schemas.put(schema.getNamespace(), schema);
076 } else if (!schema.getSourceUris().contains(sourceUri)) {
077 NodeList nodes = elem.getChildNodes();
078 for (int i = 0; i < nodes.getLength(); i++) {
079 schema.getRoot().appendChild(schema.getRoot().getOwnerDocument().importNode(nodes.item(i), true));
080 }
081 schema.addSourceUri(sourceUri);
082 }
083 handleImports(schema, sourceUri);
084 }
085
086 public void read(String location, URI baseUri) throws Exception {
087 if (log.isDebugEnabled()) {
088 log.debug("Reading schema at '" + location + "' with baseUri '" + baseUri + "'");
089 }
090 if (baseUri == null) {
091 baseUri = this.baseUri;
092 }
093 URI loc;
094 if (baseUri != null) {
095 loc = resolve(baseUri, location);
096 if (!loc.isAbsolute()) {
097 throw new IllegalArgumentException("Unable to resolve '" + loc.toString() + "' relative to '" + baseUri + "'");
098 }
099 } else {
100 loc = new URI(location);
101 if (!loc.isAbsolute()) {
102 throw new IllegalArgumentException("Location '" + loc.toString() + "' is not absolute and no baseUri specified");
103 }
104 }
105 InputSource inputSource = new InputSource();
106 inputSource.setByteStream(loc.toURL().openStream());
107 inputSource.setSystemId(loc.toString());
108 read(inputSource);
109 }
110
111 public void read(InputSource inputSource) throws Exception {
112 DocumentBuilderFactory docFac = DocumentBuilderFactory.newInstance();
113 docFac.setNamespaceAware(true);
114 DocumentBuilder builder = docFac.newDocumentBuilder();
115 Document doc = builder.parse(inputSource);
116 read(doc.getDocumentElement(),
117 inputSource.getSystemId() != null ? new URI(inputSource.getSystemId()) : null);
118 }
119
120 protected void handleImports(Schema schema, URI baseUri) throws Exception {
121 NodeList children = schema.getRoot().getChildNodes();
122 List<Element> imports = new ArrayList<Element>();
123 List<Element> includes = new ArrayList<Element>();
124 for (int i = 0; i < children.getLength(); i++) {
125 Node child = children.item(i);
126 if (child instanceof Element) {
127 Element ce = (Element) child;
128 if ("http://www.w3.org/2001/XMLSchema".equals(ce.getNamespaceURI()) &&
129 "import".equals(ce.getLocalName())) {
130 imports.add(ce);
131 } else if ("http://www.w3.org/2001/XMLSchema".equals(ce.getNamespaceURI()) &&
132 "include".equals(ce.getLocalName())) {
133 includes.add(ce);
134 }
135 }
136 }
137 for (Iterator<Element> iter = imports.iterator(); iter.hasNext();) {
138 Element ce = iter.next();
139 String namespace = ce.getAttribute("namespace");
140 String location = ce.getAttribute("schemaLocation");
141 schema.addImport(namespace);
142 schema.getRoot().removeChild(ce);
143 if (location != null && !"".equals(location)) {
144 read(location, baseUri);
145 }
146 }
147 for (Iterator<Element> iter = includes.iterator(); iter.hasNext();) {
148 Element ce = iter.next();
149 String location = ce.getAttribute("schemaLocation");
150 Node parentNode = ce.getParentNode();
151 Element root = schema.getRoot();
152 if (root == parentNode) {
153 log.debug("Removing child include node: " + ce);
154 schema.getRoot().removeChild(ce);
155 } else {
156 log.warn("Skipping child include node removal: " + ce);
157 }
158 if (location != null && !"".equals(location)) {
159 read(location, baseUri);
160 }
161 }
162 }
163
164 protected static URI resolve(URI base, String location) {
165 if ("jar".equals(base.getScheme())) {
166 String str = base.toString();
167 String[] parts = str.split("!");
168 parts[1] = URI.create(parts[1]).resolve(location).toString();
169 return URI.create(parts[0] + "!" + parts[1]);
170 }
171 return base.resolve(location);
172 }
173
174 public int getSize() {
175 if (schemas != null) {
176 return schemas.size();
177 } else {
178 return 0;
179 }
180 }
181
182 public Collection<Schema> getSchemas() {
183 if (schemas != null) {
184 return schemas.values();
185 } else {
186 return Collections.emptySet();
187 }
188 }
189 }