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.geronimo.jaxws.builder;
018    
019    import java.net.URI;
020    import java.net.URISyntaxException;
021    import java.util.HashMap;
022    import java.util.List;
023    import java.util.Map;
024    
025    import javax.xml.namespace.QName;
026    import javax.xml.ws.Service;
027    import javax.xml.ws.handler.Handler;
028    
029    import org.apache.commons.logging.Log;
030    import org.apache.commons.logging.LogFactory;
031    import org.apache.geronimo.common.DeploymentException;
032    import org.apache.geronimo.j2ee.deployment.Module;
033    import org.apache.geronimo.kernel.repository.Environment;
034    import org.apache.geronimo.naming.deployment.AbstractNamingBuilder;
035    import org.apache.geronimo.naming.deployment.ServiceRefBuilder;
036    import org.apache.geronimo.xbeans.geronimo.naming.GerServiceRefDocument;
037    import org.apache.geronimo.xbeans.geronimo.naming.GerServiceRefType;
038    import org.apache.geronimo.xbeans.javaee.PortComponentRefType;
039    import org.apache.geronimo.xbeans.javaee.ServiceRefHandlerChainType;
040    import org.apache.geronimo.xbeans.javaee.ServiceRefHandlerChainsType;
041    import org.apache.geronimo.xbeans.javaee.ServiceRefHandlerType;
042    import org.apache.geronimo.xbeans.javaee.ServiceRefType;
043    
044    import org.apache.xmlbeans.QNameSet;
045    import org.apache.xmlbeans.XmlObject;
046    
047    public abstract class JAXWSServiceRefBuilder extends AbstractNamingBuilder implements ServiceRefBuilder {
048        private static final Log log = LogFactory.getLog(JAXWSServiceRefBuilder.class);
049    
050        private static final QName GER_SERVICE_REF_QNAME = 
051            GerServiceRefDocument.type.getDocumentElementName();
052    
053        private static final QNameSet GER_SERVICE_REF_QNAME_SET = 
054            QNameSet.singleton(GER_SERVICE_REF_QNAME);
055    
056        private final QNameSet serviceRefQNameSet;
057        
058        public JAXWSServiceRefBuilder(Environment defaultEnvironment,
059                                      String[] eeNamespaces) {
060            super(defaultEnvironment);
061            serviceRefQNameSet = buildQNameSet(eeNamespaces, "service-ref");
062        }
063    
064        protected boolean willMergeEnvironment(XmlObject specDD, XmlObject plan) {
065            return specDD.selectChildren(serviceRefQNameSet).length > 0;
066        }
067    
068        public void buildNaming(XmlObject specDD,
069                XmlObject plan,
070                Module module,
071                Map componentContext) throws DeploymentException {
072            List<ServiceRefType> serviceRefsUntyped = convert(specDD.selectChildren(serviceRefQNameSet), JEE_CONVERTER, ServiceRefType.class, ServiceRefType.type);
073            XmlObject[] gerServiceRefsUntyped = plan == null ? NO_REFS : plan.selectChildren(GER_SERVICE_REF_QNAME_SET);
074            Map serviceRefMap = mapServiceRefs(gerServiceRefsUntyped);
075            
076            for (ServiceRefType serviceRef : serviceRefsUntyped) {
077                String name = getStringValue(serviceRef.getServiceRefName());            
078                addInjections(name, serviceRef.getInjectionTargetArray(), componentContext);
079                GerServiceRefType serviceRefType = (GerServiceRefType) serviceRefMap.get(name);
080                serviceRefMap.remove(name);
081                buildNaming(serviceRef, serviceRefType, module, componentContext);
082            }        
083    
084            if (serviceRefMap.size() > 0) {
085                log.warn("Failed to build reference to service reference "+serviceRefMap.keySet()+" defined in plan file, reason - corresponding entry in deployment descriptor missing.");
086            }
087        }
088    
089        private Class loadClass(String className, ClassLoader cl, String classDescription) throws DeploymentException {
090            try {
091                return cl.loadClass(className);
092            } catch (ClassNotFoundException e) {
093                throw new DeploymentException("Could not load " + classDescription + " class " + className, e);                
094            }         
095        }
096        
097        public void buildNaming(XmlObject serviceRef, GerServiceRefType gerServiceRefType, Module module, Map componentContext) throws DeploymentException {
098            ServiceRefType serviceRefType = 
099                (ServiceRefType)convert(serviceRef, JEE_CONVERTER, ServiceRefType.type);
100            buildNaming(serviceRefType, gerServiceRefType, module, componentContext);
101        }
102        
103        public void buildNaming(ServiceRefType serviceRef, GerServiceRefType gerServiceRef, Module module, Map componentContext) throws DeploymentException {
104            ClassLoader cl = module.getEarContext().getClassLoader();        
105            String name = getStringValue(serviceRef.getServiceRefName());
106            
107            String serviceInterfaceName = getStringValue(serviceRef.getServiceInterface());
108            Class serviceInterfaceClass = loadClass(serviceInterfaceName, cl, "service");        
109            if (!Service.class.isAssignableFrom(serviceInterfaceClass)) {
110                throw new DeploymentException(serviceInterfaceName + " service class does not extend " + Service.class.getName());
111            }
112            
113            QName serviceQName = null;
114            if (serviceRef.isSetServiceQname()) {
115                serviceQName = serviceRef.getServiceQname().getQNameValue();
116            }
117            
118            URI wsdlURI = null;
119            if (serviceRef.isSetWsdlFile()) {
120                String wsdlLocation = serviceRef.getWsdlFile().getStringValue().trim();
121                try {
122                    wsdlURI = new URI(wsdlLocation);
123                } catch (URISyntaxException e) {
124                    throw new DeploymentException("Could not construct WSDL URI from " + wsdlLocation, e);
125                }
126            }
127            
128            Class serviceReferenceType = null;
129            if (serviceRef.isSetServiceRefType()) {
130                String referenceClassName = getStringValue(serviceRef.getServiceRefType());            
131                serviceReferenceType = loadClass(referenceClassName, cl, "service reference");
132            }
133      
134            if (serviceRef.isSetHandlerChains()) {                   
135                ServiceRefHandlerChainsType handlerChains = serviceRef.getHandlerChains();
136                for (ServiceRefHandlerChainType handlerChain : handlerChains.getHandlerChainArray()) {               
137                    for (ServiceRefHandlerType handler : handlerChain.getHandlerArray()) {
138                        String handlerClassName = getStringValue(handler.getHandlerClass());
139                        Class handlerClass = loadClass(handlerClassName, cl, "handler");
140                        if (!Handler.class.isAssignableFrom(handlerClass)) {
141                            throw new DeploymentException(handlerClassName + " handler class does not extend " + Handler.class.getName());
142                        }
143                    }
144                }
145            }
146                           
147            Map<Class, PortComponentRefType> portComponentRefMap = new HashMap<Class, PortComponentRefType>();
148            PortComponentRefType[] portComponentRefs = serviceRef.getPortComponentRefArray();
149            if (portComponentRefs != null) {
150                for (int j = 0; j < portComponentRefs.length; j++) {
151                    PortComponentRefType portComponentRef = portComponentRefs[j];
152                    String serviceEndpointInterfaceType = getStringValue(portComponentRef.getServiceEndpointInterface());
153                    Class serviceEndpointClass = loadClass(serviceEndpointInterfaceType, cl, "service endpoint");
154                    
155                    // TODO: check if it is annotated?
156                    
157                    portComponentRefMap.put(serviceEndpointClass, portComponentRef);
158                }
159            }
160            
161            Object ref = createService(serviceRef, gerServiceRef, module, cl,
162                                       serviceInterfaceClass, serviceQName, 
163                                       wsdlURI, serviceReferenceType, portComponentRefMap);
164            getJndiContextMap(componentContext).put(ENV + name, ref);
165        }
166    
167        public abstract Object createService(ServiceRefType serviceRef, GerServiceRefType gerServiceRef, 
168                                             Module module, ClassLoader cl, Class serviceInterfaceClass, 
169                                             QName serviceQName, URI wsdlURI, Class serviceReferenceType, 
170                                             Map<Class, PortComponentRefType> portComponentRefMap) throws DeploymentException;
171           
172        private static Map mapServiceRefs(XmlObject[] refs) {
173            Map refMap = new HashMap();
174            if (refs != null) {
175                for (int i = 0; i < refs.length; i++) {
176                    GerServiceRefType ref = (GerServiceRefType) refs[i].copy()
177                            .changeType(GerServiceRefType.type);
178                    String serviceRefName = ref.getServiceRefName().trim();
179                    refMap.put(serviceRefName, ref);
180                }
181            }
182            return refMap;
183        }
184    
185        public QNameSet getSpecQNameSet() {
186            return serviceRefQNameSet;
187        }
188    
189        public QNameSet getPlanQNameSet() {
190            return GER_SERVICE_REF_QNAME_SET;
191        }
192    
193    }