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.axis.client;
018    
019    import java.io.Serializable;
020    import java.lang.reflect.InvocationTargetException;
021    import java.math.BigInteger;
022    import java.net.MalformedURLException;
023    import java.net.URI;
024    import java.net.URL;
025    import java.rmi.Remote;
026    import java.util.Iterator;
027    import java.util.List;
028    
029    import javax.xml.namespace.QName;
030    import javax.xml.rpc.ServiceException;
031    import javax.xml.rpc.handler.HandlerChain;
032    
033    import net.sf.cglib.core.Signature;
034    import net.sf.cglib.proxy.Callback;
035    import net.sf.cglib.proxy.Enhancer;
036    import net.sf.cglib.proxy.MethodInterceptor;
037    import net.sf.cglib.proxy.MethodProxy;
038    import net.sf.cglib.proxy.NoOp;
039    import net.sf.cglib.reflect.FastClass;
040    import net.sf.cglib.reflect.FastConstructor;
041    import org.apache.axis.AxisEngine;
042    import org.apache.axis.Constants;
043    import org.apache.axis.client.Service;
044    import org.apache.axis.constants.Use;
045    import org.apache.axis.description.TypeDesc;
046    import org.apache.axis.encoding.TypeMapping;
047    import org.apache.axis.encoding.TypeMappingRegistry;
048    import org.apache.axis.encoding.ser.SimpleDeserializerFactory;
049    import org.apache.axis.encoding.ser.SimpleSerializerFactory;
050    import org.apache.axis.handlers.HandlerInfoChainFactory;
051    
052    /**
053     * @version $Rev: 548434 $ $Date: 2007-06-18 14:27:34 -0400 (Mon, 18 Jun 2007) $
054     */
055    public class SEIFactoryImpl implements SEIFactory, Serializable {
056    
057        private final QName serviceName;
058        private final QName portQName;
059        private final String serviceEndpointClassName;
060        private final OperationInfo[] operationInfos;
061        private transient FastConstructor constructor;
062        private Object serviceImpl;
063        private final List typeInfo;
064        private final URL location;
065        private final List handlerInfos;
066        private final String credentialsName;
067        private transient HandlerInfoChainFactory handlerInfoChainFactory;
068        private transient OperationInfo[] sortedOperationInfos;
069        private Class serviceEndpointClass;
070    
071        public SEIFactoryImpl(QName serviceName, String portName, String serviceEndpointClassName, OperationInfo[] operationInfos, List typeInfo, URL location, List handlerInfos, String credentialsName) {
072            this.serviceName = serviceName;
073            this.portQName = new QName("", portName);
074            this.serviceEndpointClassName = serviceEndpointClassName;
075            this.operationInfos = operationInfos;
076            this.typeInfo = typeInfo;
077            this.location = location;
078            this.handlerInfos = handlerInfos;
079            this.credentialsName = credentialsName;
080        }
081    
082        void initialize(Object serviceImpl, ClassLoader classLoader) throws ClassNotFoundException {
083            this.serviceImpl = serviceImpl;
084            Class serviceEndpointBaseClass = classLoader.loadClass(serviceEndpointClassName);
085            serviceEndpointClass = enhanceServiceEndpointInterface(serviceEndpointBaseClass, classLoader);
086            Class[] constructorTypes = new Class[]{classLoader.loadClass(GenericServiceEndpoint.class.getName())};
087            this.constructor = FastClass.create(serviceEndpointClass).getConstructor(constructorTypes);
088            this.handlerInfoChainFactory = new HandlerInfoChainFactory(handlerInfos);
089            sortedOperationInfos = new OperationInfo[FastClass.create(serviceEndpointClass).getMaxIndex() + 1];
090            String encodingStyle = "";
091            for (int i = 0; i < operationInfos.length; i++) {
092                OperationInfo operationInfo = operationInfos[i];
093                Signature signature = operationInfo.getSignature();
094                MethodProxy methodProxy = MethodProxy.find(serviceEndpointClass, signature);
095                if (methodProxy == null) {
096                    throw new RuntimeException("No method proxy for operationInfo " + signature);
097                }
098                int index = methodProxy.getSuperIndex();
099                sortedOperationInfos[index] = operationInfo;
100                if (operationInfo.getOperationDesc().getUse() == Use.ENCODED) {
101                    encodingStyle = org.apache.axis.Constants.URI_SOAP11_ENC;
102                }
103            }
104            //register our type descriptors
105            Service service = ((ServiceImpl) serviceImpl).getService();
106            AxisEngine axisEngine = service.getEngine();
107            TypeMappingRegistry typeMappingRegistry = axisEngine.getTypeMappingRegistry();
108            TypeMapping typeMapping = typeMappingRegistry.getOrMakeTypeMapping(encodingStyle);
109            typeMapping.register(BigInteger.class,
110                    Constants.XSD_UNSIGNEDLONG,
111                    new SimpleSerializerFactory(BigInteger.class, Constants.XSD_UNSIGNEDLONG),
112                    new SimpleDeserializerFactory(BigInteger.class, Constants.XSD_UNSIGNEDLONG));
113            typeMapping.register(URI.class,
114                    Constants.XSD_ANYURI,
115                    new SimpleSerializerFactory(URI.class, Constants.XSD_ANYURI),
116                    new SimpleDeserializerFactory(URI.class, Constants.XSD_ANYURI));
117            //It is essential that the types be registered before the typeInfos create the serializer/deserializers.
118            for (Iterator iter = typeInfo.iterator(); iter.hasNext();) {
119                TypeInfo info = (TypeInfo) iter.next();
120                TypeDesc.registerTypeDescForClass(info.getClazz(), info.buildTypeDesc());
121            }
122            TypeInfo.register(typeInfo, typeMapping);
123        }
124    
125        private Class enhanceServiceEndpointInterface(Class serviceEndpointInterface, ClassLoader classLoader) {
126            Enhancer enhancer = new Enhancer();
127            enhancer.setClassLoader(classLoader);
128            enhancer.setSuperclass(GenericServiceEndpointWrapper.class);
129            enhancer.setInterfaces(new Class[]{serviceEndpointInterface});
130            enhancer.setCallbackFilter(new NoOverrideCallbackFilter(GenericServiceEndpointWrapper.class));
131            enhancer.setCallbackTypes(new Class[]{NoOp.class, MethodInterceptor.class});
132            enhancer.setUseFactory(false);
133            enhancer.setUseCache(false);
134    
135            return enhancer.createClass();
136        }
137        public Remote createServiceEndpoint() throws ServiceException {
138            //TODO figure out why this can't be called in readResolve!
139    //        synchronized (this) {
140    //            if (!initialized) {
141    //                initialize();
142    //                initialized = true;
143    //            }
144    //        }
145            Service service = ((ServiceImpl) serviceImpl).getService();
146            GenericServiceEndpoint serviceEndpoint = new GenericServiceEndpoint(portQName, service, location);
147            Callback callback = new ServiceEndpointMethodInterceptor(serviceEndpoint, sortedOperationInfos, credentialsName);
148            Callback[] callbacks = new Callback[]{SerializableNoOp.INSTANCE, callback};
149            Enhancer.registerCallbacks(serviceEndpointClass, callbacks);
150            try {
151                return (Remote) constructor.newInstance(new Object[]{serviceEndpoint});
152            } catch (InvocationTargetException e) {
153                throw (ServiceException)new ServiceException("Could not construct service instance", e.getTargetException()).initCause(e);
154            }
155        }
156    
157        public HandlerChain createHandlerChain() {
158            return handlerInfoChainFactory.createHandlerChain();
159        }
160    
161    //    private Object readResolve() throws ObjectStreamException {
162    //            SEIFactoryImpl seiFactory =  new SEIFactoryImpl(serviceName, portQName.getLocalPart(), serviceEndpointClassName, operationInfos, typeInfo, location, handlerInfos, credentialsName);
163    //            seiFactory.initialize();
164    //            return seiFactory;
165    //    }
166    
167        public OperationInfo[] getOperationInfos() {
168            return operationInfos;
169        }
170    
171        public QName getPortQName() {
172            return portQName;
173        }
174    
175        public QName getServiceName() {
176            return serviceName;
177        }
178    
179        public URL getWSDLDocumentLocation() {
180            try {
181                return new URL(location.toExternalForm() + "?wsdl");
182            } catch (MalformedURLException e) {
183                return null;
184            }
185        }
186    }