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.client;
018    
019    import net.sf.cglib.proxy.MethodInterceptor;
020    import net.sf.cglib.proxy.MethodProxy;
021    import org.apache.commons.logging.Log;
022    import org.apache.commons.logging.LogFactory;
023    import org.apache.geronimo.jaxws.JAXWSUtils;
024    import org.apache.geronimo.security.ContextManager;
025    import org.apache.geronimo.security.jaas.NamedUsernamePasswordCredential;
026    
027    import javax.security.auth.Subject;
028    import javax.xml.namespace.QName;
029    import javax.xml.ws.BindingProvider;
030    import javax.xml.ws.WebEndpoint;
031    import javax.xml.ws.soap.SOAPBinding;
032    
033    import java.lang.reflect.Method;
034    import java.net.URL;
035    import java.util.Iterator;
036    import java.util.Map;
037    import java.util.Set;
038    
039    public class PortMethodInterceptor implements MethodInterceptor {
040    
041        private static final Log LOG = LogFactory.getLog(PortMethodInterceptor.class);
042        
043        private Map<Object, EndpointInfo> seiInfoMap;
044    
045        public PortMethodInterceptor(Map<Object, EndpointInfo> seiInfoMap) {
046            this.seiInfoMap = seiInfoMap;
047        }
048    
049        public Object intercept(Object target, Method method, Object[] arguments, MethodProxy methodProxy) throws Throwable {
050            Object proxy = methodProxy.invokeSuper(target, arguments);       
051            
052            if (method.getName().equals("getPort")) {     
053                // it's a generic getPort() method
054                if (arguments.length == 1) {
055                    // getPort(Class) called - use SEI annotation
056                    setProperties((BindingProvider)proxy, JAXWSUtils.getPortType((Class)arguments[0]));
057                } else if (arguments.length == 2) {
058                    // getPort(QName, Class) called
059                    if (arguments[0] == null) {
060                        // port qname not specified - use SEI annotation
061                        setProperties((BindingProvider)proxy, JAXWSUtils.getPortType((Class)arguments[1]));
062                    } else {
063                        // port qname specified
064                        setProperties((BindingProvider)proxy, ((QName)arguments[0]).getLocalPart());
065                    }
066                }
067            } else if (method.getName().startsWith("get")) {
068                // it's a generated get<PortName>() method
069                WebEndpoint endpoint = method.getAnnotation(WebEndpoint.class);
070                setProperties((BindingProvider)proxy, endpoint.name());
071            } else if (method.getName().equals("createDispatch")) {
072                // it's one of createDispatch() methods
073                setProperties((BindingProvider)proxy, ((QName)arguments[0]).getLocalPart());
074            }
075                    
076            return proxy;
077        }
078        
079        private void setProperties(BindingProvider proxy, QName portType) {
080            if (portType == null) {
081                return;
082            }
083            EndpointInfo info = this.seiInfoMap.get(portType);
084            setProperties(proxy, info);        
085        }
086        
087        private void setProperties(BindingProvider proxy, String portName) {
088            if (portName == null) {
089                return;
090            }
091            EndpointInfo info = this.seiInfoMap.get(portName);
092            setProperties(proxy, info);
093        }
094        
095        private void setProperties(BindingProvider proxy, EndpointInfo info) {
096            if (info == null) {
097                return;
098            }       
099            
100            // set mtom
101            boolean enableMTOM = info.isMTOMEnabled();
102            if (enableMTOM && proxy.getBinding() instanceof SOAPBinding) {
103                ((SOAPBinding)proxy.getBinding()).setMTOMEnabled(enableMTOM);
104                LOG.debug("Set mtom property: " + enableMTOM);
105            }
106          
107            // set address
108            URL location = info.getLocation();
109            if (location != null) {
110                proxy.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, location.toString());
111                LOG.debug("Set address property: " + location);
112            }
113            
114            // set credentials
115            String credentialsName = info.getCredentialsName();
116            if (credentialsName != null) {
117                Subject subject = ContextManager.getNextCaller();
118                if (subject == null) {
119                    throw new IllegalStateException("Subject missing but authentication turned on");
120                } else {
121                    Set creds = subject.getPrivateCredentials(NamedUsernamePasswordCredential.class);
122                    boolean found = false;
123                    
124                    for (Iterator iterator = creds.iterator(); iterator.hasNext();) {
125                        NamedUsernamePasswordCredential namedUsernamePasswordCredential = (NamedUsernamePasswordCredential) iterator.next();
126                        if (credentialsName.equals(namedUsernamePasswordCredential.getName())) {
127                            proxy.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, 
128                                                          namedUsernamePasswordCredential.getUsername());
129                            proxy.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, 
130                                                          new String(namedUsernamePasswordCredential.getPassword()));
131                            LOG.debug("Set username/password property: " + credentialsName);
132                            found = true;
133                            break;
134                        }
135                    }
136                    if (!found) {
137                        throw new IllegalStateException("no NamedUsernamePasswordCredential found for name " + credentialsName);
138                    }
139                }
140            }
141        }
142    }