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.cxfbc;
018
019 import java.util.ArrayList;
020 import java.util.Collection;
021 import java.util.HashMap;
022 import java.util.IdentityHashMap;
023 import java.util.Iterator;
024 import java.util.List;
025 import java.util.Map;
026 import java.util.Map.Entry;
027
028 import javax.wsdl.Definition;
029 import javax.wsdl.Import;
030 import javax.wsdl.Types;
031 import javax.wsdl.extensions.UnknownExtensibilityElement;
032 import javax.wsdl.extensions.schema.Schema;
033 import javax.wsdl.extensions.schema.SchemaImport;
034 import javax.wsdl.extensions.schema.SchemaReference;
035
036 import org.w3c.dom.Attr;
037 import org.w3c.dom.Element;
038 import org.w3c.dom.NodeList;
039
040 import org.apache.cxf.Bus;
041 import org.apache.cxf.catalog.CatalogXmlSchemaURIResolver;
042 import org.apache.cxf.common.xmlschema.SchemaCollection;
043 import org.apache.cxf.helpers.CastUtils;
044 import org.apache.cxf.service.model.SchemaInfo;
045 import org.apache.cxf.service.model.ServiceInfo;
046 import org.apache.ws.commons.schema.XmlSchema;
047
048 import static org.apache.cxf.helpers.CastUtils.cast;
049
050 public final class SchemaUtil {
051 private final Map<String, Element> schemaList;
052 private final Map<String, String> catalogResolved = new HashMap<String, String>();
053 private final Bus bus;
054
055 public SchemaUtil(final Bus b, final Map<String, Element> s) {
056 this.bus = b;
057 this.schemaList = s;
058 }
059 public void getSchemas(final Definition def, final ServiceInfo serviceInfo) {
060 SchemaCollection schemaCol = serviceInfo.getXmlSchemaCollection();
061 getSchemas(def, schemaCol, serviceInfo);
062 }
063 public void getSchemas(final Definition def,
064 SchemaCollection schemaCol,
065 ServiceInfo serviceInfo) {
066 getSchemas(def, schemaCol, serviceInfo.getSchemas());
067 }
068
069 public void getSchemas(final Definition def,
070 final SchemaCollection schemaCol,
071 List<SchemaInfo> schemas) {
072 List<Definition> defList = new ArrayList<Definition>();
073 parseImports(def, defList);
074 extractSchema(def, schemaCol, schemas);
075 // added
076 getSchemaList(def);
077
078 Map<Definition, Definition> done = new IdentityHashMap<Definition, Definition>();
079 done.put(def, def);
080 for (Definition def2 : defList) {
081 if (!done.containsKey(def2)) {
082 extractSchema(def2, schemaCol, schemas);
083 // added
084 getSchemaList(def2);
085 done.put(def2, def2);
086 }
087 }
088 }
089
090 @SuppressWarnings("unchecked")
091 private void extractSchema(Definition def, SchemaCollection schemaCol, List<SchemaInfo> schemaInfos) {
092 Types typesElement = def.getTypes();
093 if (typesElement != null) {
094 int schemaCount = 1;
095 for (Object obj : typesElement.getExtensibilityElements()) {
096 org.w3c.dom.Element schemaElem = null;
097 if (obj instanceof Schema) {
098 Schema schema = (Schema)obj;
099 schemaElem = schema.getElement();
100 } else if (obj instanceof UnknownExtensibilityElement) {
101 org.w3c.dom.Element elem = ((UnknownExtensibilityElement)obj).getElement();
102 if (elem.getLocalName().equals("schema")) {
103 schemaElem = elem;
104 }
105 }
106 if (schemaElem != null) {
107 synchronized (schemaElem.getOwnerDocument()) {
108 //for (Object prefix : def.getNamespaces().keySet()) {
109 Map<String, String> nameSpaces = CastUtils.cast(def.getNamespaces());
110 for (Entry<String, String> ent : nameSpaces.entrySet()) {
111 String prefix = ent.getKey();
112 String ns = nameSpaces.get(prefix);
113 if ("".equals(prefix)) {
114 if (!schemaElem.hasAttribute("xmlns")) {
115 Attr attr =
116 schemaElem.getOwnerDocument()
117 .createAttributeNS(javax.xml.XMLConstants.XMLNS_ATTRIBUTE_NS_URI,
118 "xmlns");
119 attr.setValue(ns);
120 schemaElem.setAttributeNodeNS(attr);
121 }
122 } else if (!schemaElem.hasAttribute("xmlns:" + prefix)) {
123 String namespace = javax.xml.XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
124 Attr attr =
125 schemaElem.getOwnerDocument().createAttributeNS(namespace,
126 "xmlns:" + prefix);
127 attr.setValue(ns);
128 schemaElem.setAttributeNodeNS(attr);
129 }
130 }
131 String systemId = def.getDocumentBaseURI() + "#types" + schemaCount;
132
133 schemaCol.setBaseUri(def.getDocumentBaseURI());
134 CatalogXmlSchemaURIResolver schemaResolver =
135 new CatalogXmlSchemaURIResolver(bus);
136 schemaCol.setSchemaResolver(schemaResolver);
137
138 XmlSchema xmlSchema = schemaCol.read(schemaElem, systemId);
139 catalogResolved.putAll(schemaResolver.getResolvedMap());
140 SchemaInfo schemaInfo = new SchemaInfo(xmlSchema.getTargetNamespace());
141 schemaInfo.setSchema(xmlSchema);
142 schemaInfo.setSystemId(systemId);
143 schemaInfo.setElement(schemaElem);
144 schemaInfos.add(schemaInfo);
145 schemaCount++;
146 }
147 }
148 }
149 }
150 }
151
152 private void parseImports(Definition def, List<Definition> defList) {
153 List<Import> importList = new ArrayList<Import>();
154
155 Collection<List<Import>> ilist = cast(def.getImports().values());
156 for (List<Import> list : ilist) {
157 importList.addAll(list);
158 }
159 for (Import impt : importList) {
160 if (!defList.contains(impt.getDefinition())) {
161 defList.add(impt.getDefinition());
162 parseImports(impt.getDefinition(), defList);
163 }
164 }
165 }
166
167 // Workaround for getting the elements
168 private void getSchemaList(Definition def) {
169 Types typesElement = def.getTypes();
170 if (typesElement != null) {
171 Iterator ite = typesElement.getExtensibilityElements().iterator();
172 while (ite.hasNext()) {
173 Object obj = ite.next();
174 if (obj instanceof Schema) {
175 Schema schema = (Schema)obj;
176 addSchema(schema.getDocumentBaseURI(), schema);
177 }
178 }
179 }
180 }
181
182 private void addSchema(String docBaseURI, Schema schema) {
183 //String docBaseURI = schema.getDocumentBaseURI();
184 Element schemaEle = schema.getElement();
185 if (schemaList.get(docBaseURI) == null) {
186 schemaList.put(docBaseURI, schemaEle);
187 } else if (schemaList.get(docBaseURI) != null && schemaList.containsValue(schemaEle)) {
188 // do nothing
189 } else {
190 String tns = schema.getDocumentBaseURI() + "#"
191 + schema.getElement().getAttribute("targetNamespace");
192 if (schemaList.get(tns) == null) {
193 schemaList.put(tns, schema.getElement());
194 }
195 }
196
197 //handle imports
198 Map<String, List> imports = CastUtils.cast(schema.getImports());
199 if (imports != null && imports.size() > 0) {
200 for (Entry<String, List> ent : imports.entrySet()) {
201 String importNamespace = ent.getKey();
202 List<SchemaImport> schemaImports = CastUtils.cast(imports.get(importNamespace));
203
204 for (SchemaImport schemaImport : schemaImports) {
205 Schema tempImport = schemaImport.getReferencedSchema();
206 String key = schemaImport.getSchemaLocationURI();
207 if (importNamespace == null && tempImport != null) {
208 importNamespace = tempImport.getDocumentBaseURI();
209 }
210
211 if (tempImport != null && !catalogResolved.containsKey(key)) {
212 key = tempImport.getDocumentBaseURI();
213 }
214
215 if (tempImport != null
216 && !isSchemaParsed(key, importNamespace)
217 && !schemaList.containsValue(tempImport.getElement())) {
218 addSchema(key, tempImport);
219 }
220 if (tempImport != null) {
221 //keep this imported schema inline
222 inlineTransformer(key, tempImport.getElement(), schema.getElement(), false);
223 }
224 }
225
226 }
227 }
228 //handle includes
229 List<SchemaReference> includes = CastUtils.cast(schema.getIncludes());
230 if (includes != null && includes.size() > 0) {
231 String includeNamespace = schema.getElement().getAttribute("targetNamespace");
232
233 for (SchemaReference schemaInclude : includes) {
234 Schema tempInclude = schemaInclude.getReferencedSchema();
235 String key = tempInclude.getDocumentBaseURI();
236 if (includeNamespace == null && tempInclude != null) {
237 includeNamespace = tempInclude.getDocumentBaseURI();
238 }
239
240 if (tempInclude != null && !catalogResolved.containsKey(key)) {
241 key = tempInclude.getDocumentBaseURI();
242 }
243
244 if (tempInclude != null && !isSchemaParsed(key, includeNamespace)
245 && !schemaList.containsValue(tempInclude.getElement())) {
246 addSchema(key, tempInclude);
247 }
248 if (tempInclude != null) {
249 //keep this included schema inline
250 inlineTransformer(key, tempInclude.getElement(), schema.getElement(), true);
251 }
252 }
253
254 }
255 }
256
257 private boolean isSchemaParsed(String baseUri, String ns) {
258 if (schemaList.get(baseUri) != null) {
259 Element ele = schemaList.get(baseUri);
260 String tns = ele.getAttribute("targetNamespace");
261 if (ns.equals(tns)) {
262 return true;
263 }
264 }
265 return false;
266 }
267
268 private void inlineTransformer(String key, Element inlineSchema, Element outerSchema, boolean isInclude) {
269 NodeList nl = null;
270 if (isInclude) {
271 nl = outerSchema.getElementsByTagNameNS(
272 "http://www.w3.org/2001/XMLSchema", "include");
273 } else {
274 nl = outerSchema.getElementsByTagNameNS(
275 "http://www.w3.org/2001/XMLSchema", "import");
276 }
277 for (int j = 0; j < nl.getLength(); j++) {
278
279 String schemaLocation = ((Element)nl.item(j)).getAttribute("schemaLocation");
280
281 if (schemaLocation != null && getXsdFileName(schemaLocation, "/").
282 equals(getXsdFileName(key, "/"))) {
283
284 outerSchema.removeChild(nl.item(j));
285 for (int i = 0; i < inlineSchema.getChildNodes().getLength(); i++) {
286 outerSchema.appendChild(
287 outerSchema.getOwnerDocument().importNode(
288 inlineSchema.getChildNodes().item(i), true));
289 }
290 outerSchema.setPrefix("xs");
291 outerSchema.setAttribute("xmlns:xs", "http://www.w3.org/2001/XMLSchema");
292 }
293 }
294 }
295
296 private String getXsdFileName(String path, String sep) {
297 String name = "";
298 if (path.lastIndexOf(sep) >= 0) {
299 name = path.substring(path.lastIndexOf(sep) + 1);
300 } else {
301 name = path;
302 }
303 return name;
304 }
305 }