1/* 2 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package com.sun.xml.internal.ws.spi.db; 27 28import static com.sun.xml.internal.ws.model.RuntimeModeler.DocWrappeeNamespapceQualified; 29 30import java.io.IOException; 31import java.util.ArrayList; 32import java.util.Map.Entry; 33import java.util.HashMap; 34import java.util.HashSet; 35import java.util.List; 36import java.util.Set; 37 38import static com.sun.xml.internal.ws.wsdl.writer.WSDLGenerator.XsdNs; 39 40import javax.xml.bind.JAXBException; 41import javax.xml.bind.SchemaOutputResolver; 42import javax.xml.namespace.QName; 43import javax.xml.transform.Result; 44import javax.xml.ws.WebServiceException; 45 46import com.sun.xml.internal.bind.v2.schemagen.xmlschema.ComplexType; 47import com.sun.xml.internal.bind.v2.schemagen.xmlschema.Element; 48import com.sun.xml.internal.bind.v2.schemagen.xmlschema.ExplicitGroup; 49import com.sun.xml.internal.bind.v2.schemagen.xmlschema.LocalElement; 50import com.sun.xml.internal.bind.v2.schemagen.xmlschema.Occurs; 51import com.sun.xml.internal.txw2.TXW; 52import com.sun.xml.internal.txw2.output.ResultFactory; 53import com.sun.xml.internal.ws.api.model.SEIModel; 54import com.sun.xml.internal.ws.model.AbstractSEIModelImpl; 55import com.sun.xml.internal.ws.model.JavaMethodImpl; 56import com.sun.xml.internal.ws.model.ParameterImpl; 57import com.sun.xml.internal.ws.model.WrapperParameter; 58import com.sun.xml.internal.ws.wsdl.writer.document.xsd.Schema; 59 60/** 61 * ServiceArtifactSchemaGenerator generates XML schema for service artifacts including the wrapper types of 62 * document-literal stype operation and exceptions. 63 * 64 * @author shih-chang.chen@oracle.com 65 */ 66public class ServiceArtifactSchemaGenerator { 67 68 protected AbstractSEIModelImpl model; 69 protected SchemaOutputResolver xsdResolver; 70 71 public ServiceArtifactSchemaGenerator(SEIModel model) { 72 this.model = (AbstractSEIModelImpl)model; 73 } 74 75 static final String FilePrefix = "jaxwsGen"; 76 protected int fileIndex = 0; 77 protected Schema create(String tns) { 78 try { 79 Result res = xsdResolver.createOutput(tns, FilePrefix + (fileIndex++) + ".xsd"); 80 return TXW.create(Schema.class, ResultFactory.createSerializer(res)); 81 } catch (IOException e) { 82 // TODO Auto-generated catch block 83 throw new WebServiceException(e); 84 } 85 } 86 87 public void generate(SchemaOutputResolver resolver) { 88 xsdResolver = resolver; 89 List<WrapperParameter> wrappers = new ArrayList<WrapperParameter>(); 90 for (JavaMethodImpl method : model.getJavaMethods()) { 91 if(method.getBinding().isRpcLit()) continue; 92 for (ParameterImpl p : method.getRequestParameters()) { 93 if (p instanceof WrapperParameter) { 94 if (WrapperComposite.class.equals((((WrapperParameter)p).getTypeInfo().type))) { 95 wrappers.add((WrapperParameter)p); 96 } 97 } 98 } 99 for (ParameterImpl p : method.getResponseParameters()) { 100 if (p instanceof WrapperParameter) { 101 if (WrapperComposite.class.equals((((WrapperParameter)p).getTypeInfo().type))) { 102 wrappers.add((WrapperParameter)p); 103 } 104 } 105 } 106 } 107 if (wrappers.isEmpty()) return; 108 HashMap<String, Schema> xsds = initWrappersSchemaWithImports(wrappers); 109 postInit(xsds); 110 for(WrapperParameter wp : wrappers) { 111 String tns = wp.getName().getNamespaceURI(); 112 Schema xsd = xsds.get(tns); 113 Element e = xsd._element(Element.class); 114 e._attribute("name", wp.getName().getLocalPart()); 115 e.type(wp.getName()); 116 ComplexType ct = xsd._element(ComplexType.class); 117 ct._attribute("name", wp.getName().getLocalPart()); 118 ExplicitGroup sq = ct.sequence(); 119 for (ParameterImpl p : wp.getWrapperChildren() ) if (p.getBinding().isBody()) addChild(sq, p); 120 } 121 for(Schema xsd: xsds.values()) xsd.commit(); 122 } 123 124 protected void postInit(HashMap<String, Schema> xsds) { 125 } 126 127 protected void addChild(ExplicitGroup sq, ParameterImpl param) { 128 TypeInfo typeInfo = param.getItemType(); 129 boolean repeatedElement = false; 130 if (typeInfo == null) { 131 typeInfo = param.getTypeInfo(); 132 } else { 133 if (typeInfo.getWrapperType() != null) typeInfo = param.getTypeInfo(); 134 else repeatedElement = true; 135 } 136 Occurs child = addChild(sq, param.getName(), typeInfo); 137 if (repeatedElement && child != null) { 138 child.maxOccurs("unbounded"); 139 } 140 } 141 142 protected Occurs addChild(ExplicitGroup sq, QName name, TypeInfo typeInfo) { 143 LocalElement le = null;; 144 QName type = model.getBindingContext().getTypeName(typeInfo); 145 if (type != null) { 146 le = sq.element(); 147 le._attribute("name", name.getLocalPart()); 148 le.type(type); 149 } else { 150 if (typeInfo.type instanceof Class) { 151 try { 152 QName elemName = model.getBindingContext().getElementName((Class)typeInfo.type); 153 if (elemName.getLocalPart().equals("any") && elemName.getNamespaceURI().equals(XsdNs)) { 154 return sq.any(); 155 } else { 156 le = sq.element(); 157 le.ref(elemName); 158 } 159 } catch (JAXBException je) { 160 throw new WebServiceException(je.getMessage(), je); 161 } 162 } 163 } 164 return le; 165 } 166 167 //All the imports have to go first ... 168 private HashMap<String, Schema> initWrappersSchemaWithImports(List<WrapperParameter> wrappers) { 169 Object o = model.databindingInfo().properties().get(DocWrappeeNamespapceQualified); 170 boolean wrappeeQualified = (o!= null && o instanceof Boolean) ? ((Boolean) o) : false; 171 HashMap<String, Schema> xsds = new HashMap<String, Schema>(); 172 HashMap<String, Set<String>> imports = new HashMap<String, Set<String>>(); 173 for(WrapperParameter wp : wrappers) { 174 String tns = wp.getName().getNamespaceURI(); 175 Schema xsd = xsds.get(tns); 176 if (xsd == null) { 177 xsd = create(tns); 178 xsd.targetNamespace(tns); 179 if (wrappeeQualified) xsd._attribute("elementFormDefault", "qualified"); 180 xsds.put(tns, xsd); 181 } 182 for (ParameterImpl p : wp.getWrapperChildren() ) { 183 String nsToImport = (p.getBinding().isBody())? bodyParamNS(p): null; 184 if (nsToImport != null && !nsToImport.equals(tns) && !nsToImport.equals("http://www.w3.org/2001/XMLSchema")) { 185 Set<String> importSet = imports.get(tns); 186 if (importSet == null) { 187 importSet = new HashSet<String>(); 188 imports.put(tns, importSet); 189 } 190 importSet.add(nsToImport); 191 } 192 } 193 } 194 for(Entry<String, Set<String>> entry: imports.entrySet()) { 195 String tns = entry.getKey(); 196 Set<String> importSet = entry.getValue(); 197 Schema xsd = xsds.get(tns); 198 for(String nsToImport : importSet) xsd._namespace(nsToImport, true); 199 for(String nsToImport : importSet) { 200 com.sun.xml.internal.ws.wsdl.writer.document.xsd.Import imp = xsd._import(); 201 imp.namespace(nsToImport); 202 } 203 } 204 return xsds; 205 } 206 207 protected String bodyParamNS(ParameterImpl p) { 208 String nsToImport = null; 209 TypeInfo typeInfo = p.getItemType(); 210 if (typeInfo == null) typeInfo = p.getTypeInfo(); 211 QName type = model.getBindingContext().getTypeName(typeInfo); 212 if (type != null) { 213 nsToImport = type.getNamespaceURI(); 214 } else { 215 if (typeInfo.type instanceof Class) { 216 try { 217 QName elemRef = model.getBindingContext().getElementName((Class)typeInfo.type); 218 if (elemRef != null) nsToImport = elemRef.getNamespaceURI(); 219 } catch (JAXBException je) { 220 throw new WebServiceException(je.getMessage(), je); 221 } 222 } 223 } 224 return nsToImport; 225 } 226} 227