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
018 package org.apache.geronimo.axis2.builder;
019
020 import java.io.FileNotFoundException;
021 import java.io.IOException;
022 import java.io.InputStream;
023 import java.io.StringWriter;
024 import java.net.URI;
025 import java.net.URL;
026 import java.util.Collections;
027 import java.util.HashMap;
028 import java.util.Map;
029 import java.util.jar.JarFile;
030
031 import javax.xml.namespace.QName;
032 import javax.xml.ws.http.HTTPBinding;
033
034 import org.apache.commons.logging.Log;
035 import org.apache.commons.logging.LogFactory;
036 import org.apache.geronimo.axis2.client.Axis2ServiceReference;
037 import org.apache.geronimo.axis2.pojo.POJOWebServiceContainerFactoryGBean;
038 import org.apache.geronimo.common.DeploymentException;
039 import org.apache.geronimo.deployment.DeploymentContext;
040 import org.apache.geronimo.gbean.GBeanData;
041 import org.apache.geronimo.gbean.GBeanInfo;
042 import org.apache.geronimo.gbean.GBeanInfoBuilder;
043 import org.apache.geronimo.j2ee.deployment.Module;
044 import org.apache.geronimo.j2ee.deployment.WebModule;
045 import org.apache.geronimo.j2ee.deployment.WebServiceBuilder;
046 import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
047 import org.apache.geronimo.jaxws.JAXWSUtils;
048 import org.apache.geronimo.jaxws.PortInfo;
049 import org.apache.geronimo.jaxws.builder.EndpointInfoBuilder;
050 import org.apache.geronimo.jaxws.builder.JAXWSServiceBuilder;
051 import org.apache.geronimo.jaxws.builder.WsdlGenerator;
052 import org.apache.geronimo.jaxws.client.EndpointInfo;
053 import org.apache.geronimo.kernel.repository.Environment;
054 import org.apache.geronimo.xbeans.geronimo.naming.GerServiceRefType;
055 import org.apache.geronimo.xbeans.javaee.PortComponentRefType;
056 import org.apache.geronimo.xbeans.javaee.PortComponentType;
057 import org.apache.geronimo.xbeans.javaee.ServiceImplBeanType;
058 import org.apache.geronimo.xbeans.javaee.ServiceRefHandlerChainsType;
059 import org.apache.geronimo.xbeans.javaee.WebserviceDescriptionType;
060 import org.apache.geronimo.xbeans.javaee.WebservicesDocument;
061 import org.apache.geronimo.xbeans.javaee.WebservicesType;
062 import org.apache.xmlbeans.XmlCursor;
063 import org.apache.xmlbeans.XmlObject;
064 import org.apache.xmlbeans.XmlOptions;
065
066 /**
067 * @version $Rev$ $Date$
068 */
069 public class Axis2Builder extends JAXWSServiceBuilder {
070
071 private static final Log log = LogFactory.getLog(Axis2Builder.class);
072
073 public Axis2Builder(Environment defaultEnviroment) {
074 super(defaultEnviroment);
075 }
076
077 public Axis2Builder(){
078 super(null);
079 }
080
081 protected GBeanInfo getContainerFactoryGBeanInfo() {
082 return POJOWebServiceContainerFactoryGBean.GBEAN_INFO;
083 }
084
085 protected Map<String, PortInfo> parseWebServiceDescriptor(InputStream in,
086 URL wsDDUrl,
087 JarFile moduleFile,
088 boolean isEJB,
089 Map correctedPortLocations)
090 throws DeploymentException {
091
092 log.debug("Parsing descriptor " + wsDDUrl);
093
094 Map<String, PortInfo> map = null;
095 XmlCursor cursor = null;
096
097 try {
098 XmlObject xobj = XmlObject.Factory.parse(in);
099
100 cursor = xobj.newCursor();
101 cursor.toStartDoc();
102 cursor.toFirstChild();
103 //the checking is needed as we also send JAX-RPC based webservices.xml here
104 if ("http://java.sun.com/xml/ns/javaee".equals(cursor.getName().getNamespaceURI())) {
105 WebservicesDocument wd = (WebservicesDocument)xobj.changeType(WebservicesDocument.type);
106 WebservicesType wst = wd.getWebservices();
107
108 for (WebserviceDescriptionType desc : wst.getWebserviceDescriptionArray()) {
109 String wsdlFile = null;
110 if (desc.getWsdlFile() != null) {
111 wsdlFile = getString(desc.getWsdlFile().getStringValue());
112 }
113
114 String serviceName = desc.getWebserviceDescriptionName().getStringValue();
115
116 for (PortComponentType port : desc.getPortComponentArray()) {
117
118 PortInfo portInfo = new PortInfo();
119 String serviceLink = null;
120 ServiceImplBeanType beanType = port.getServiceImplBean();
121 if (beanType.getEjbLink() != null) {
122 serviceLink = beanType.getEjbLink().getStringValue();
123 } else if (beanType.getServletLink().getStringValue() != null) {
124 serviceLink = beanType.getServletLink().getStringValue();
125 }
126 portInfo.setServiceLink(serviceLink);
127
128 if (port.getServiceEndpointInterface() != null) {
129 String sei = port.getServiceEndpointInterface().getStringValue();
130 portInfo.setServiceEndpointInterfaceName(sei);
131 }
132
133 String portName = port.getPortComponentName().getStringValue();
134 portInfo.setPortName(portName);
135
136 portInfo.setProtocolBinding(port.getProtocolBinding());
137 portInfo.setServiceName(serviceName);
138 portInfo.setWsdlFile(wsdlFile);
139
140 if (port.getEnableMtom() != null) {
141 portInfo.setEnableMTOM(port.getEnableMtom().getBooleanValue());
142 }
143
144 if (port.getHandlerChains() != null) {
145 StringBuffer chains = new StringBuffer("<handler-chains xmlns=\"http://java.sun.com/xml/ns/javaee\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">");
146 chains.append(port.getHandlerChains().xmlText());
147 chains.append("</handler-chains>");
148 portInfo.setHandlersAsXML(chains.toString());
149 }
150
151 if (port.getWsdlPort() != null) {
152 portInfo.setWsdlPort(port.getWsdlPort().getQNameValue());
153 }
154
155 if (port.getWsdlService() != null) {
156 portInfo.setWsdlService(port.getWsdlService().getQNameValue());
157 }
158
159 String location = (String) correctedPortLocations.get(serviceLink);
160 portInfo.setLocation(location);
161
162 if (map == null) {
163 map = new HashMap<String, PortInfo>();
164 }
165
166 map.put(serviceLink, portInfo);
167 }
168 }
169 } else {
170 log.debug("Descriptor ignored (not a Java EE 5 descriptor)");
171 }
172
173 return map;
174 } catch (FileNotFoundException e) {
175 return Collections.emptyMap();
176 } catch (IOException ex) {
177 throw new DeploymentException("Unable to read " + wsDDUrl, ex);
178 } catch (Exception ex) {
179 throw new DeploymentException("Unknown deployment error", ex);
180 } finally {
181 if (cursor != null) {
182 cursor.dispose();
183 }
184 try {
185 in.close();
186 } catch (IOException e) {
187 // ignore
188 }
189 }
190 }
191
192 public boolean configurePOJO(GBeanData targetGBean,
193 String servletName,
194 Module module,
195 String seiClassName,
196 DeploymentContext context)
197 throws DeploymentException {
198
199 boolean status = super.configurePOJO(targetGBean, servletName, module, seiClassName, context);
200 if(!status) {
201 return false;
202 }
203
204 //change the URL
205 Map sharedContext = ((WebModule) module).getSharedContext();
206 String contextRoot = ((WebModule) module).getContextRoot();
207 Map portInfoMap = (Map) sharedContext.get(getKey());
208 PortInfo portInfo;
209
210 if(portInfoMap != null && portInfoMap.get(servletName) != null){
211 portInfo = (PortInfo) portInfoMap.get(servletName);
212 processURLPattern(contextRoot, portInfo);
213 }
214
215 return status;
216 }
217
218 public Object createService(Class serviceInterface,
219 Class serviceReference,
220 URI wsdlURI,
221 QName serviceQName,
222 Map<Class, PortComponentRefType> portComponentRefMap,
223 ServiceRefHandlerChainsType handlerChains,
224 GerServiceRefType serviceRefType,
225 Module module,
226 ClassLoader cl) throws DeploymentException {
227 EndpointInfoBuilder builder = new EndpointInfoBuilder(serviceInterface,
228 serviceRefType, portComponentRefMap, module.getModuleFile(),
229 wsdlURI, serviceQName);
230 builder.build();
231
232 wsdlURI = builder.getWsdlURI();
233 serviceQName = builder.getServiceQName();
234 Map<Object, EndpointInfo> seiInfoMap = builder.getEndpointInfo();
235
236 String handlerChainsXML = null;
237 try {
238 handlerChainsXML = getHandlerChainAsString(handlerChains);
239 } catch (IOException e) {
240 // this should not happen
241 log.warn("Failed to serialize handler chains", e);
242 }
243
244 String serviceReferenceName = (serviceReference == null) ? null : serviceReference.getName();
245 return new Axis2ServiceReference(serviceInterface.getName(), serviceReferenceName, wsdlURI,
246 serviceQName, module.getModuleName(), handlerChainsXML, seiInfoMap);
247 }
248
249 private static String getHandlerChainAsString(ServiceRefHandlerChainsType handlerChains)
250 throws IOException {
251 String xml = null;
252 if (handlerChains != null) {
253 StringWriter w = new StringWriter();
254 XmlOptions options = new XmlOptions();
255 options.setSaveSyntheticDocumentElement(new QName("http://java.sun.com/xml/ns/javaee", "handler-chains"));
256 handlerChains.save(w, options);
257 xml = w.toString();
258 }
259 return xml;
260 }
261
262 private static String getString(String in) {
263 if (in != null) {
264 in = in.trim();
265 if (in.length() == 0) {
266 return null;
267 }
268 }
269 return in;
270 }
271
272 private void processURLPattern(String contextRoot, PortInfo portInfo) throws DeploymentException {
273 //if the user specifies a url-pattern, set it here.
274 String oldup = portInfo.getLocation();
275 if (oldup == null || oldup.length() == 0) {
276 //if we cannot grab a valid urlpattern, default it to the port-component-name.
277 oldup = portInfo.getPortName();
278 } else {
279 int i = oldup.indexOf(contextRoot);
280 oldup = oldup.substring(i + contextRoot.length() + 1);
281 oldup = oldup.trim();
282 if (oldup.indexOf("*") > 0) {
283 //uncomment this before we fix this issue. workarond by assuming * is at the end.
284 //throw new DeploymentException("Per JSR 109, the url-pattern should not contain an asterisk.");
285 oldup = oldup.substring(0, oldup.length() - 1);
286 }
287 //trim the forward slashes at the beginning or end.
288 if (oldup.substring(0, 1).equalsIgnoreCase("/")) {
289 oldup = oldup.substring(1);
290 }
291 if (oldup.substring(oldup.length()-1).equalsIgnoreCase("/")) {
292 oldup = oldup.substring(0, oldup.length() - 1);
293 }
294
295 }
296 portInfo.setLocation(oldup);
297 }
298
299 @Override
300 protected void initialize(GBeanData targetGBean, Class serviceClass, PortInfo portInfo, Module module)
301 throws DeploymentException {
302 if (isWsdlSet(portInfo, serviceClass)) {
303 log.debug("Service " + portInfo.getServiceName() + " has WSDL.");
304 return;
305 }
306
307 if (isHTTPBinding(portInfo, serviceClass)) {
308 log.debug("Service " + portInfo.getServiceName() + " is HTTPBinding. Only SOAP 1.1 or 1.2 is supported.");
309 return;
310 }
311
312 log.debug("Service " + portInfo.getServiceName() + " does not have WSDL. Generating WSDL...");
313
314 WsdlGenerator generator = new WsdlGenerator();
315 generator.setAxis2SAAJ();
316
317 // set wsdl service
318 if (portInfo.getWsdlService() == null) {
319 generator.setWsdlService(JAXWSUtils.getServiceQName(serviceClass));
320 } else {
321 generator.setWsdlService(portInfo.getWsdlService());
322 }
323
324 // set wsdl port
325 if (portInfo.getWsdlPort() != null) {
326 generator.setWsdlPort(portInfo.getWsdlPort());
327 }
328
329 String wsdlFile = generator.generateWsdl(module, serviceClass.getName(), module.getEarContext(), portInfo);
330 portInfo.setWsdlFile(wsdlFile);
331
332 log.debug("Generated " + wsdlFile + " for service " + portInfo.getServiceName());
333 }
334
335 private boolean isWsdlSet(PortInfo portInfo, Class serviceClass) {
336 return (portInfo.getWsdlFile() != null && !portInfo.getWsdlFile().trim().equals(""))
337 || JAXWSUtils.containsWsdlLocation(serviceClass, serviceClass.getClassLoader());
338 }
339
340 private boolean isHTTPBinding(PortInfo portInfo, Class serviceClass) {
341 String bindingURI = "";
342 String bindingURIFromAnnot;
343
344 if (portInfo.getProtocolBinding() != null) {
345 bindingURI = JAXWSUtils.getBindingURI(portInfo.getProtocolBinding());
346 }
347 bindingURIFromAnnot = JAXWSUtils.getBindingURIFromAnnot(serviceClass, serviceClass.getClassLoader());
348
349 if (bindingURI != null && !bindingURI.trim().equals("")) {
350 return bindingURI.equals(HTTPBinding.HTTP_BINDING);
351 } else if (bindingURIFromAnnot != null && !bindingURIFromAnnot.trim().equals("")) {
352 return bindingURIFromAnnot.equals(HTTPBinding.HTTP_BINDING);
353 }
354
355 return false;
356 }
357
358 public static final GBeanInfo GBEAN_INFO;
359
360 static {
361 GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic(Axis2Builder.class, NameFactory.MODULE_BUILDER);
362 infoBuilder.addInterface(WebServiceBuilder.class);
363 infoBuilder.addAttribute("defaultEnvironment", Environment.class, true, true);
364 infoBuilder.setConstructor(new String[]{"defaultEnvironment"});
365 GBEAN_INFO = infoBuilder.getBeanInfo();
366 }
367
368 public static GBeanInfo getGBeanInfo() {
369 return GBEAN_INFO;
370 }
371 }