001    /**
002     *
003     *  Licensed to the Apache Software Foundation (ASF) under one or more
004     *  contributor license agreements.  See the NOTICE file distributed with
005     *  this work for additional information regarding copyright ownership.
006     *  The ASF licenses this file to You under the Apache License, Version 2.0
007     *  (the "License"); you may not use this file except in compliance with
008     *  the License.  You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     *  Unless required by applicable law or agreed to in writing, software
013     *  distributed under the License is distributed on an "AS IS" BASIS,
014     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     *  See the License for the specific language governing permissions and
016     *  limitations under the License.
017     */
018    package org.apache.geronimo.axis.client;
019    
020    import java.lang.reflect.Method;
021    import java.rmi.RemoteException;
022    import java.util.Arrays;
023    import java.util.Iterator;
024    import java.util.Set;
025    import java.util.List;
026    import java.util.Map;
027    import javax.security.auth.Subject;
028    import javax.xml.rpc.holders.Holder;
029    import javax.wsdl.OperationType;
030    
031    import net.sf.cglib.proxy.MethodInterceptor;
032    import net.sf.cglib.proxy.MethodProxy;
033    import org.apache.axis.client.Call;
034    import org.apache.axis.description.ParameterDesc;
035    import org.apache.axis.utils.JavaUtils;
036    import org.apache.geronimo.security.ContextManager;
037    import org.apache.geronimo.security.jaas.NamedUsernamePasswordCredential;
038    
039    /**
040     * @version $Rev: 470597 $ $Date: 2006-11-02 15:30:55 -0800 (Thu, 02 Nov 2006) $
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            int index = methodProxy.getSuperIndex();
056            OperationInfo operationInfo = operations[index];
057            if (operationInfo == null) {
058                throw new RuntimeException("Operation not mapped: " + method.getName() + " index: " + index + "\n OperationInfos: " + Arrays.asList(operations));
059            }
060            stub.checkCachedEndpoint();
061    
062            Call call = stub.createCall();
063    
064            operationInfo.prepareCall(call);
065    
066            stub.setUpCall(call);
067            if (credentialsName != null) {
068                Subject subject = ContextManager.getNextCaller();
069                if (subject == null) {
070                    throw new IllegalStateException("Subject missing but authentication turned on");
071                } else {
072                    Set creds = subject.getPrivateCredentials(NamedUsernamePasswordCredential.class);
073                    boolean found = false;
074                    for (Iterator iterator = creds.iterator(); iterator.hasNext();) {
075                        NamedUsernamePasswordCredential namedUsernamePasswordCredential = (NamedUsernamePasswordCredential) iterator.next();
076                        if (credentialsName.equals(namedUsernamePasswordCredential.getName())) {
077                            call.setUsername(namedUsernamePasswordCredential.getUsername());
078                            call.setPassword(new String(namedUsernamePasswordCredential.getPassword()));
079                            found = true;
080                            break;
081                        }
082                    }
083                    if (!found) {
084                        throw new IllegalStateException("no NamedUsernamePasswordCredential found for name " + credentialsName);
085                    }
086                }
087            }
088            Object response = null;
089            List parameterDescs = operationInfo.getOperationDesc().getParameters();
090            Object[] unwrapped = extractFromHolders(objects, parameterDescs, operationInfo.getOperationDesc().getNumInParams());
091            if (operationInfo.getOperationDesc().getMep() == OperationType.REQUEST_RESPONSE) {
092                try {
093                    response = call.invoke(unwrapped);
094                } catch (RemoteException e) {
095                    throw operationInfo.unwrapFault(e);
096                }
097    
098                if (response instanceof RemoteException) {
099                    throw operationInfo.unwrapFault((RemoteException) response);
100                } else {
101                    stub.extractAttachments(call);
102                    Map outputParameters = call.getOutputParams();
103                    putInHolders(outputParameters, objects, parameterDescs);
104                    Class returnType = operationInfo.getOperationDesc().getReturnClass();
105                    //return type should never be null... but we are not objecting if wsdl-return-value-mapping is not set.
106                    if (response == null || returnType == null || returnType.isAssignableFrom(response.getClass())) {
107                        return response;
108                    } else {
109                        return JavaUtils.convert(response, returnType);
110                    }
111                }
112            } else if (operationInfo.getOperationDesc().getMep() == OperationType.ONE_WAY) {
113                //one way
114                call.invokeOneWay(unwrapped);
115                return null;
116            } else {
117                throw new RuntimeException("Invalid messaging style: " + operationInfo.getOperationDesc().getMep());
118            }
119        }
120    
121        private Object[] extractFromHolders(Object[] objects, List parameterDescs, int inParameterCount) throws JavaUtils.HolderException {
122            if (objects.length != parameterDescs.size()) {
123                throw new IllegalArgumentException("Mismatch parameter count: expected: " + parameterDescs.size() + ", actual: " + objects.length);
124            }
125            Object[] unwrapped = new Object[inParameterCount];
126            int j = 0;
127            for (int i = 0; objects != null && i < objects.length; i++) {
128                Object parameter = objects[i];
129                ParameterDesc parameterDesc = (ParameterDesc) parameterDescs.get(i);
130    
131                if (parameterDesc.getMode() == ParameterDesc.INOUT) {
132                    unwrapped[j++] = JavaUtils.getHolderValue((Holder) parameter);
133                } else if (parameterDesc.getMode() == ParameterDesc.IN) {
134                    unwrapped[j++] = parameter;
135                }
136            }
137            return unwrapped;
138        }
139    
140        private void putInHolders(Map outputParameters, Object[] objects, List parameterDescs) throws JavaUtils.HolderException {
141            for (int i = 0; i < objects.length; i++) {
142                Object parameter = objects[i];
143                ParameterDesc parameterDesc = (ParameterDesc) parameterDescs.get(i);
144                if ((parameterDesc.getMode() == ParameterDesc.INOUT) ||
145                        (parameterDesc.getMode() == ParameterDesc.OUT)) {
146                    Object returned = outputParameters.get(parameterDesc.getQName());
147                    if (returned instanceof Holder) {
148                        //TODO this must be a bug somewhere!!!!
149                        returned = JavaUtils.getHolderValue(returned);
150                    }
151                    JavaUtils.setHolderValue((Holder) parameter, returned);
152                }
153            }
154        }
155    
156    }