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.lang.reflect.Method;
020    import java.rmi.RemoteException;
021    import java.util.Arrays;
022    import java.util.Iterator;
023    import java.util.Set;
024    import java.util.List;
025    import java.util.Map;
026    import javax.security.auth.Subject;
027    import javax.xml.rpc.holders.Holder;
028    import javax.wsdl.OperationType;
029    
030    import net.sf.cglib.proxy.MethodInterceptor;
031    import net.sf.cglib.proxy.MethodProxy;
032    import org.apache.axis.client.Call;
033    import org.apache.axis.description.ParameterDesc;
034    import org.apache.axis.utils.JavaUtils;
035    import org.apache.geronimo.security.ContextManager;
036    import org.apache.geronimo.security.jaas.NamedUsernamePasswordCredential;
037    import org.apache.geronimo.webservices.saaj.SAAJUniverse;
038    
039    /**
040     * @version $Rev: 520432 $ $Date: 2007-03-20 11:35:27 -0400 (Tue, 20 Mar 2007) $
041     */
042    public class ServiceEndpointMethodInterceptor implements MethodInterceptor {
043    
044        private final GenericServiceEndpoint stub;
045        private final OperationInfo[] operations;
046        private final String credentialsName;
047    
048        public ServiceEndpointMethodInterceptor(GenericServiceEndpoint stub, OperationInfo[] operations, String credentialsName) {
049            this.stub = stub;
050            this.operations = operations;
051            this.credentialsName = credentialsName;
052        }
053    
054        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
055            SAAJUniverse universe = new SAAJUniverse();
056            universe.set(SAAJUniverse.AXIS1);
057            try {
058                return doIntercept(o, method, objects, methodProxy);
059            } finally {
060                universe.unset();
061            }
062        }
063        
064        private Object doIntercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
065            int index = methodProxy.getSuperIndex();
066            OperationInfo operationInfo = operations[index];
067            if (operationInfo == null) {
068                throw new RuntimeException("Operation not mapped: " + method.getName() + " index: " + index + "\n OperationInfos: " + Arrays.asList(operations));
069            }
070            stub.checkCachedEndpoint();
071    
072            Call call = stub.createCall();
073    
074            operationInfo.prepareCall(call);
075    
076            stub.setUpCall(call);
077            if (credentialsName != null) {
078                Subject subject = ContextManager.getNextCaller();
079                if (subject == null) {
080                    throw new IllegalStateException("Subject missing but authentication turned on");
081                } else {
082                    Set creds = subject.getPrivateCredentials(NamedUsernamePasswordCredential.class);
083                    boolean found = false;
084                    for (Iterator iterator = creds.iterator(); iterator.hasNext();) {
085                        NamedUsernamePasswordCredential namedUsernamePasswordCredential = (NamedUsernamePasswordCredential) iterator.next();
086                        if (credentialsName.equals(namedUsernamePasswordCredential.getName())) {
087                            call.setUsername(namedUsernamePasswordCredential.getUsername());
088                            call.setPassword(new String(namedUsernamePasswordCredential.getPassword()));
089                            found = true;
090                            break;
091                        }
092                    }
093                    if (!found) {
094                        throw new IllegalStateException("no NamedUsernamePasswordCredential found for name " + credentialsName);
095                    }
096                }
097            }
098            Object response = null;
099            List parameterDescs = operationInfo.getOperationDesc().getParameters();
100            Object[] unwrapped = extractFromHolders(objects, parameterDescs, operationInfo.getOperationDesc().getNumInParams());
101            if (operationInfo.getOperationDesc().getMep() == OperationType.REQUEST_RESPONSE) {
102                try {
103                    response = call.invoke(unwrapped);
104                } catch (RemoteException e) {
105                    throw operationInfo.unwrapFault(e);
106                }
107    
108                if (response instanceof RemoteException) {
109                    throw operationInfo.unwrapFault((RemoteException) response);
110                } else {
111                    stub.extractAttachments(call);
112                    Map outputParameters = call.getOutputParams();
113                    putInHolders(outputParameters, objects, parameterDescs);
114                    Class returnType = operationInfo.getOperationDesc().getReturnClass();
115                    //return type should never be null... but we are not objecting if wsdl-return-value-mapping is not set.
116                    if (response == null || returnType == null || returnType.isAssignableFrom(response.getClass())) {
117                        return response;
118                    } else {
119                        return JavaUtils.convert(response, returnType);
120                    }
121                }
122            } else if (operationInfo.getOperationDesc().getMep() == OperationType.ONE_WAY) {
123                //one way
124                call.invokeOneWay(unwrapped);
125                return null;
126            } else {
127                throw new RuntimeException("Invalid messaging style: " + operationInfo.getOperationDesc().getMep());
128            }
129        }
130    
131        private Object[] extractFromHolders(Object[] objects, List parameterDescs, int inParameterCount) throws JavaUtils.HolderException {
132            if (objects.length != parameterDescs.size()) {
133                throw new IllegalArgumentException("Mismatch parameter count: expected: " + parameterDescs.size() + ", actual: " + objects.length);
134            }
135            Object[] unwrapped = new Object[inParameterCount];
136            int j = 0;
137            for (int i = 0; objects != null && i < objects.length; i++) {
138                Object parameter = objects[i];
139                ParameterDesc parameterDesc = (ParameterDesc) parameterDescs.get(i);
140    
141                if (parameterDesc.getMode() == ParameterDesc.INOUT) {
142                    unwrapped[j++] = JavaUtils.getHolderValue((Holder) parameter);
143                } else if (parameterDesc.getMode() == ParameterDesc.IN) {
144                    unwrapped[j++] = parameter;
145                }
146            }
147            return unwrapped;
148        }
149    
150        private void putInHolders(Map outputParameters, Object[] objects, List parameterDescs) throws JavaUtils.HolderException {
151            for (int i = 0; i < objects.length; i++) {
152                Object parameter = objects[i];
153                ParameterDesc parameterDesc = (ParameterDesc) parameterDescs.get(i);
154                if ((parameterDesc.getMode() == ParameterDesc.INOUT) ||
155                        (parameterDesc.getMode() == ParameterDesc.OUT)) {
156                    Object returned = outputParameters.get(parameterDesc.getQName());
157                    if (returned instanceof Holder) {
158                        //TODO this must be a bug somewhere!!!!
159                        returned = JavaUtils.getHolderValue(returned);
160                    }
161                    JavaUtils.setHolderValue((Holder) parameter, returned);
162                }
163            }
164        }
165    
166    }