1 /**
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one or more
4 * contributor license agreements. See the NOTICE file distributed with
5 * this work for additional information regarding copyright ownership.
6 * The ASF licenses this file to You under the Apache License, Version 2.0
7 * (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18 package org.apache.geronimo.webservices.builder;
19
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.lang.reflect.Method;
23 import java.math.BigDecimal;
24 import java.math.BigInteger;
25 import java.net.URI;
26 import java.net.URISyntaxException;
27 import java.net.URL;
28 import java.util.ArrayList;
29 import java.util.Calendar;
30 import java.util.HashMap;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.jar.JarFile;
34 import java.util.zip.ZipEntry;
35
36 import javax.wsdl.Definition;
37 import javax.wsdl.Operation;
38 import javax.wsdl.Port;
39 import javax.xml.namespace.QName;
40 import javax.xml.rpc.handler.HandlerInfo;
41 import javax.xml.rpc.holders.BigDecimalHolder;
42 import javax.xml.rpc.holders.BigIntegerHolder;
43 import javax.xml.rpc.holders.BooleanHolder;
44 import javax.xml.rpc.holders.BooleanWrapperHolder;
45 import javax.xml.rpc.holders.ByteArrayHolder;
46 import javax.xml.rpc.holders.ByteHolder;
47 import javax.xml.rpc.holders.ByteWrapperHolder;
48 import javax.xml.rpc.holders.CalendarHolder;
49 import javax.xml.rpc.holders.DoubleHolder;
50 import javax.xml.rpc.holders.DoubleWrapperHolder;
51 import javax.xml.rpc.holders.FloatHolder;
52 import javax.xml.rpc.holders.FloatWrapperHolder;
53 import javax.xml.rpc.holders.IntHolder;
54 import javax.xml.rpc.holders.IntegerWrapperHolder;
55 import javax.xml.rpc.holders.LongHolder;
56 import javax.xml.rpc.holders.LongWrapperHolder;
57 import javax.xml.rpc.holders.ObjectHolder;
58 import javax.xml.rpc.holders.QNameHolder;
59 import javax.xml.rpc.holders.ShortHolder;
60 import javax.xml.rpc.holders.ShortWrapperHolder;
61 import javax.xml.rpc.holders.StringHolder;
62
63 import org.apache.geronimo.common.DeploymentException;
64 import org.apache.geronimo.kernel.ClassLoading;
65 import org.apache.geronimo.xbeans.j2ee.ExceptionMappingType;
66 import org.apache.geronimo.xbeans.j2ee.JavaWsdlMappingDocument;
67 import org.apache.geronimo.xbeans.j2ee.JavaWsdlMappingType;
68 import org.apache.geronimo.xbeans.j2ee.PackageMappingType;
69 import org.apache.geronimo.xbeans.j2ee.ParamValueType;
70 import org.apache.geronimo.xbeans.j2ee.PortComponentHandlerType;
71 import org.apache.geronimo.xbeans.j2ee.PortComponentType;
72 import org.apache.geronimo.xbeans.j2ee.ServiceEndpointInterfaceMappingType;
73 import org.apache.geronimo.xbeans.j2ee.ServiceEndpointMethodMappingType;
74 import org.apache.geronimo.xbeans.j2ee.ServiceImplBeanType;
75 import org.apache.geronimo.xbeans.j2ee.WebserviceDescriptionType;
76 import org.apache.geronimo.xbeans.j2ee.WebservicesDocument;
77 import org.apache.geronimo.xbeans.j2ee.WebservicesType;
78 import org.apache.geronimo.xbeans.j2ee.XsdQNameType;
79 import org.apache.geronimo.deployment.xmlbeans.XmlBeansUtil;
80 import org.apache.geronimo.webservices.builder.PortInfo;
81 import org.apache.geronimo.webservices.builder.SchemaInfoBuilder;
82 import org.apache.xmlbeans.XmlException;
83
84 /**
85 * @version $Rev: 470597 $ $Date: 2006-11-02 15:30:55 -0800 (Thu, 02 Nov 2006) $
86 */
87 public class WSDescriptorParser {
88
89
90 public static JavaWsdlMappingType readJaxrpcMapping(JarFile moduleFile, URI jaxrpcMappingURI) throws DeploymentException {
91 String jaxrpcMappingPath = jaxrpcMappingURI.toString();
92 return readJaxrpcMapping(moduleFile, jaxrpcMappingPath);
93 }
94
95 public static JavaWsdlMappingType readJaxrpcMapping(JarFile moduleFile, String jaxrpcMappingPath) throws DeploymentException {
96 JavaWsdlMappingType mapping;
97 InputStream jaxrpcInputStream = null;
98 try {
99 ZipEntry zipEntry = moduleFile.getEntry(jaxrpcMappingPath);
100 if(zipEntry == null){
101 throw new DeploymentException("The JAX-RPC mapping file "+jaxrpcMappingPath+" specified in webservices.xml for the ejb module could not be found.");
102 }
103 jaxrpcInputStream = moduleFile.getInputStream(zipEntry);
104 } catch (IOException e) {
105 throw new DeploymentException("Could not open stream to jaxrpc mapping document", e);
106 }
107 JavaWsdlMappingDocument mappingDocument = null;
108 try {
109 mappingDocument = JavaWsdlMappingDocument.Factory.parse(jaxrpcInputStream);
110 } catch (XmlException e) {
111 throw new DeploymentException("Could not parse jaxrpc mapping document", e);
112 } catch (IOException e) {
113 throw new DeploymentException("Could not read jaxrpc mapping document", e);
114 }
115 mapping = mappingDocument.getJavaWsdlMapping();
116 return mapping;
117 }
118
119
120 public static Map getExceptionMap(JavaWsdlMappingType mapping) {
121 Map exceptionMap = new HashMap();
122 if (mapping != null) {
123 ExceptionMappingType[] exceptionMappings = mapping.getExceptionMappingArray();
124 for (int i = 0; i < exceptionMappings.length; i++) {
125 ExceptionMappingType exceptionMapping = exceptionMappings[i];
126 QName exceptionMessageQName = exceptionMapping.getWsdlMessage().getQNameValue();
127 exceptionMap.put(exceptionMessageQName, exceptionMapping);
128 }
129 }
130 return exceptionMap;
131 }
132
133 public static String getPackageFromNamespace(String namespace, JavaWsdlMappingType mapping) throws DeploymentException {
134 PackageMappingType[] packageMappings = mapping.getPackageMappingArray();
135 for (int i = 0; i < packageMappings.length; i++) {
136 PackageMappingType packageMapping = packageMappings[i];
137 if (namespace.equals(packageMapping.getNamespaceURI().getStringValue().trim())) {
138 return packageMapping.getPackageType().getStringValue().trim();
139 }
140 }
141 throw new DeploymentException("Namespace " + namespace + " was not mapped in jaxrpc mapping file");
142 }
143
144 private static final Map rpcHolderClasses = new HashMap();
145
146 static {
147 rpcHolderClasses.put(BigDecimal.class, BigDecimalHolder.class);
148 rpcHolderClasses.put(BigInteger.class, BigIntegerHolder.class);
149 rpcHolderClasses.put(boolean.class, BooleanHolder.class);
150 rpcHolderClasses.put(Boolean.class, BooleanWrapperHolder.class);
151 rpcHolderClasses.put(byte[].class, ByteArrayHolder.class);
152 rpcHolderClasses.put(byte.class, ByteHolder.class);
153 rpcHolderClasses.put(Byte.class, ByteWrapperHolder.class);
154 rpcHolderClasses.put(Calendar.class, CalendarHolder.class);
155 rpcHolderClasses.put(double.class, DoubleHolder.class);
156 rpcHolderClasses.put(Double.class, DoubleWrapperHolder.class);
157 rpcHolderClasses.put(float.class, FloatHolder.class);
158 rpcHolderClasses.put(Float.class, FloatWrapperHolder.class);
159 rpcHolderClasses.put(int.class, IntHolder.class);
160 rpcHolderClasses.put(Integer.class, IntegerWrapperHolder.class);
161 rpcHolderClasses.put(long.class, LongHolder.class);
162 rpcHolderClasses.put(Long.class, LongWrapperHolder.class);
163 rpcHolderClasses.put(Object.class, ObjectHolder.class);
164 rpcHolderClasses.put(QName.class, QNameHolder.class);
165 rpcHolderClasses.put(short.class, ShortHolder.class);
166 rpcHolderClasses.put(Short.class, ShortWrapperHolder.class);
167 rpcHolderClasses.put(String.class, StringHolder.class);
168 }
169
170 public static Class getHolderType(String paramJavaTypeName, boolean isInOnly, QName typeQName, boolean isComplexType, JavaWsdlMappingType mapping, ClassLoader classLoader) throws DeploymentException {
171 Class paramJavaType = null;
172 if (isInOnly) {
173
174 try {
175 paramJavaType = ClassLoading.loadClass(paramJavaTypeName, classLoader);
176 } catch (ClassNotFoundException e) {
177 throw new DeploymentException("could not load parameter type", e);
178 }
179 return paramJavaType;
180 } else {
181
182 String holderName;
183 if (isComplexType) {
184
185
186
187 String namespace = typeQName.getNamespaceURI();
188 String packageName = WSDescriptorParser.getPackageFromNamespace(namespace, mapping);
189 StringBuffer buf = new StringBuffer(packageName.length() + typeQName.getLocalPart().length() + 14);
190 buf.append(packageName).append(".holders.").append(typeQName.getLocalPart()).append("Holder");
191 buf.setCharAt(packageName.length() + 9, Character.toUpperCase(typeQName.getLocalPart().charAt(0)));
192 holderName = buf.toString();
193 } else {
194
195 try {
196 paramJavaType = ClassLoading.loadClass(paramJavaTypeName, classLoader);
197 } catch (ClassNotFoundException e) {
198 throw new DeploymentException("could not load parameter type", e);
199 }
200 Class holder = (Class) rpcHolderClasses.get(paramJavaType);
201 if (holder != null) {
202 try {
203
204 holder = ClassLoading.loadClass(holder.getName(), classLoader);
205 } catch (ClassNotFoundException e) {
206 throw new DeploymentException("could not load holder type in correct classloader", e);
207 }
208 return holder;
209 }
210
211
212
213 String paramTypeName = paramJavaType.getName();
214 StringBuffer buf = new StringBuffer(paramTypeName.length() + 14);
215 int dot = paramTypeName.lastIndexOf(".");
216
217 buf.append(paramTypeName.substring(0, dot)).append(".holders").append(paramTypeName.substring(dot)).append("Holder");
218 holderName = buf.toString();
219 }
220 try {
221 Class holder = ClassLoading.loadClass(holderName, classLoader);
222 return holder;
223 } catch (ClassNotFoundException e) {
224 throw new DeploymentException("Could not load holder class", e);
225 }
226 }
227 }
228
229 public static ServiceEndpointMethodMappingType getMethodMappingForOperation(String operationName, ServiceEndpointMethodMappingType[] methodMappings) throws DeploymentException {
230 for (int i = 0; i < methodMappings.length; i++) {
231 ServiceEndpointMethodMappingType methodMapping = methodMappings[i];
232 if (operationName.equals(methodMapping.getWsdlOperation().getStringValue())) {
233 return methodMapping;
234 }
235 }
236
237 StringBuffer availOps = new StringBuffer(128);
238 for (int i = 0; i < methodMappings.length; i++) {
239 if (i != 0) availOps.append(",");
240 availOps.append(methodMappings[i].getWsdlOperation().getStringValue());
241 }
242 throw new DeploymentException("No method found for operation named '" + operationName + "'. Available operations: " + availOps);
243 }
244
245 public static ServiceEndpointInterfaceMappingType getServiceEndpointInterfaceMapping(ServiceEndpointInterfaceMappingType[] endpointMappings, QName portTypeQName) throws DeploymentException {
246 for (int i = 0; i < endpointMappings.length; i++) {
247 ServiceEndpointInterfaceMappingType endpointMapping = endpointMappings[i];
248 QName testPortQName = endpointMapping.getWsdlPortType().getQNameValue();
249 if (portTypeQName.equals(testPortQName)) {
250 return endpointMapping;
251 }
252 }
253 throw new DeploymentException("Could not find service endpoint interface for port named " + portTypeQName);
254 }
255
256 public static javax.wsdl.Service getService(QName serviceQName, Definition definition) throws DeploymentException {
257 javax.wsdl.Service service;
258 if (serviceQName != null) {
259 service = definition.getService(serviceQName);
260 } else {
261 Map services = definition.getServices();
262 if (services.size() != 1) {
263 throw new DeploymentException("no serviceQName supplied, and there are " + services.size() + " services");
264 }
265 service = (javax.wsdl.Service) services.values().iterator().next();
266 }
267 if (service == null) {
268 throw new DeploymentException("No service wsdl for supplied service qname " + serviceQName);
269 }
270 return service;
271 }
272
273 public static Method getMethodForOperation(Class serviceEndpointInterface, Operation operation) throws DeploymentException {
274 Method[] methods = serviceEndpointInterface.getMethods();
275 String opName = operation.getName();
276 Method found = null;
277 for (int i = 0; i < methods.length; i++) {
278 Method method = methods[i];
279 if (method.getName().equals(opName)) {
280 if (found != null) {
281 throw new DeploymentException("Overloaded methods are not allowed in lightweight mappings");
282 }
283 found = method;
284 }
285 }
286 if (found == null) {
287 throw new DeploymentException("No method found for operation named " + opName);
288 }
289 return found;
290 }
291
292 /**
293 * Parses a webservice.xml file and returns a map PortInfo instances indexed by the
294 * corresponding ejb-link or servlet-link element .
295 *
296 * @param webservicesType
297 * @param moduleFile
298 * @param isEJB
299 * @param servletLocations
300 * @return
301 * @throws org.apache.geronimo.common.DeploymentException
302 */
303 public static Map parseWebServiceDescriptor(WebservicesType webservicesType, JarFile moduleFile, boolean isEJB, Map servletLocations) throws DeploymentException {
304 Map portMap = new HashMap();
305 WebserviceDescriptionType[] webserviceDescriptions = webservicesType.getWebserviceDescriptionArray();
306 for (int i = 0; i < webserviceDescriptions.length; i++) {
307 WebserviceDescriptionType webserviceDescription = webserviceDescriptions[i];
308 URI wsdlURI = null;
309 try {
310 wsdlURI = new URI(webserviceDescription.getWsdlFile().getStringValue().trim());
311 } catch (URISyntaxException e) {
312 throw new DeploymentException("could not construct wsdl uri from " + webserviceDescription.getWsdlFile().getStringValue(), e);
313 }
314 URI jaxrpcMappingURI = null;
315 try {
316 jaxrpcMappingURI = new URI(webserviceDescription.getJaxrpcMappingFile().getStringValue().trim());
317 } catch (URISyntaxException e) {
318 throw new DeploymentException("Could not construct jaxrpc mapping uri from " + webserviceDescription.getJaxrpcMappingFile(), e);
319 }
320 SchemaInfoBuilder schemaInfoBuilder = new SchemaInfoBuilder(moduleFile, wsdlURI);
321 Map wsdlPortMap = schemaInfoBuilder.getPortMap();
322
323 JavaWsdlMappingType javaWsdlMapping = readJaxrpcMapping(moduleFile, jaxrpcMappingURI);
324 HashMap seiMappings = new HashMap();
325 ServiceEndpointInterfaceMappingType[] mappings = javaWsdlMapping.getServiceEndpointInterfaceMappingArray();
326 for (int j = 0; j < mappings.length; j++) {
327 ServiceEndpointInterfaceMappingType seiMapping = mappings[j];
328 seiMappings.put(seiMapping.getServiceEndpointInterface().getStringValue(), seiMapping);
329 }
330
331 PortComponentType[] portComponents = webserviceDescription.getPortComponentArray();
332 for (int j = 0; j < portComponents.length; j++) {
333 PortComponentType portComponent = portComponents[j];
334 String portComponentName = portComponent.getPortComponentName().getStringValue().trim();
335 QName portQName = portComponent.getWsdlPort().getQNameValue();
336 String seiInterfaceName = portComponent.getServiceEndpointInterface().getStringValue().trim();
337 ServiceImplBeanType serviceImplBeanType = portComponent.getServiceImplBean();
338 if (isEJB == serviceImplBeanType.isSetServletLink()) {
339 throw new DeploymentException("Wrong kind of web service described in web service descriptor: expected " + (isEJB ? "EJB" : "POJO(Servlet)"));
340 }
341 String linkName;
342 String servletLocation;
343 if (serviceImplBeanType.isSetServletLink()) {
344 linkName = serviceImplBeanType.getServletLink().getStringValue().trim();
345 servletLocation = (String) servletLocations.get(linkName);
346 if (servletLocation == null) {
347 throw new DeploymentException("No servlet mapping for port " + portQName);
348 }
349 schemaInfoBuilder.movePortLocation(portQName.getLocalPart(), servletLocation);
350 } else {
351 linkName = serviceImplBeanType.getEjbLink().getStringValue().trim();
352 servletLocation = (String) servletLocations.get(linkName);
353 servletLocation = schemaInfoBuilder.movePortLocation(portQName.getLocalPart(), servletLocation);
354 }
355 PortComponentHandlerType[] handlers = portComponent.getHandlerArray();
356
357 Port port = (Port) wsdlPortMap.get(portQName.getLocalPart());
358 if (port == null) {
359 throw new DeploymentException("No WSDL Port definition for port-component " + portComponentName);
360 }
361
362 ServiceEndpointInterfaceMappingType seiMapping = (ServiceEndpointInterfaceMappingType) seiMappings.get(seiInterfaceName);
363
364 String wsdlLocation = webserviceDescription.getWsdlFile().getStringValue().trim();
365 URI contextURI = null;
366 try {
367 contextURI = new URI(servletLocation);
368 } catch (URISyntaxException e) {
369 throw new DeploymentException("Could not construct URI for web service location", e);
370 }
371
372 PortInfo portInfo = new PortInfo(portComponentName, portQName, schemaInfoBuilder, javaWsdlMapping, seiInterfaceName, handlers, port, seiMapping, wsdlLocation, contextURI);
373
374 if (portMap.put(linkName, portInfo) != null) {
375 throw new DeploymentException("Ambiguous description of port associated with j2ee component " + linkName);
376 }
377 }
378 }
379 return portMap;
380 }
381
382 public static Map parseWebServiceDescriptor(URL wsDDUrl, JarFile moduleFile, boolean isEJB, Map servletLocations) throws DeploymentException {
383 try {
384 WebservicesDocument webservicesDocument = WebservicesDocument.Factory.parse(wsDDUrl);
385 XmlBeansUtil.validateDD(webservicesDocument);
386 WebservicesType webservicesType = webservicesDocument.getWebservices();
387 return parseWebServiceDescriptor(webservicesType, moduleFile, isEJB, servletLocations);
388 } catch (XmlException e) {
389 throw new DeploymentException("Could not read descriptor document", e);
390 } catch (IOException e) {
391 return null;
392 }
393
394 }
395
396 public static List createHandlerInfoList(PortComponentHandlerType[] handlers, ClassLoader classLoader) throws DeploymentException {
397 List list = new ArrayList();
398 for (int i = 0; i < handlers.length; i++) {
399 PortComponentHandlerType handler = handlers[i];
400
401
402 Class handlerClass = null;
403 String className = handler.getHandlerClass().getStringValue().trim();
404 try {
405 handlerClass = classLoader.loadClass(className);
406 } catch (ClassNotFoundException e) {
407 throw new DeploymentException("Unable to load handler class: " + className, e);
408 }
409
410
411 Map config = new HashMap();
412 ParamValueType[] paramValues = handler.getInitParamArray();
413 for (int j = 0; j < paramValues.length; j++) {
414 ParamValueType paramValue = paramValues[j];
415 String paramName = paramValue.getParamName().getStringValue().trim();
416 String paramStringValue = paramValue.getParamValue().getStringValue().trim();
417 config.put(paramName, paramStringValue);
418 }
419
420
421 XsdQNameType[] soapHeaderQNames = handler.getSoapHeaderArray();
422 QName[] headers = new QName[soapHeaderQNames.length];
423 for (int j = 0; j < soapHeaderQNames.length; j++) {
424 XsdQNameType soapHeaderQName = soapHeaderQNames[j];
425 headers[j] = soapHeaderQName.getQNameValue();
426 }
427
428 list.add(new HandlerInfo(handlerClass, config, headers));
429 }
430 return list;
431 }
432 }