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    
018    package org.apache.geronimo.axis2;
019    
020    import java.net.URL;
021    import java.util.ArrayList;
022    import java.util.List;
023    
024    import javax.jws.HandlerChain;
025    import javax.jws.WebService;
026    import javax.xml.ws.WebServiceException;
027    import javax.xml.ws.handler.Handler;
028    import javax.xml.ws.handler.LogicalHandler;
029    
030    import org.apache.commons.logging.Log;
031    import org.apache.commons.logging.LogFactory;
032    import org.apache.geronimo.xbeans.javaee.HandlerChainType;
033    import org.apache.geronimo.xbeans.javaee.HandlerChainsDocument;
034    import org.apache.geronimo.xbeans.javaee.HandlerChainsType;
035    import org.apache.geronimo.xbeans.javaee.PortComponentHandlerType;
036    
037    /**
038     * @version $Rev$ $Date$
039     */
040    public class AnnotationHandlerChainBuilder {
041    
042        private static final Log log = LogFactory.getLog(AnnotationHandlerChainBuilder.class);
043    
044        public AnnotationHandlerChainBuilder() {
045        }
046    
047        /**
048         * @param clz
049         * @param existingHandlers
050         * @return
051         */
052        public List<Handler> buildHandlerChainFromClass(Class<?> clz, List<Handler> existingHandlers) {
053            log.debug("building handler chain");
054            HandlerChainAnnotation hcAnn = findHandlerChainAnnotation(clz, true);
055            List<Handler> chain = null;
056            if (hcAnn == null) {
057                log.debug("no HandlerChain annotation on " + clz);
058                chain = new ArrayList<Handler>();
059            } else {
060                hcAnn.validate();
061    
062                try {
063                    URL handlerFileURL = clz.getResource(hcAnn.getFileName());
064                    HandlerChainsType handlerChainsType = HandlerChainsDocument.Factory.parse(handlerFileURL).getHandlerChains();
065    
066                    if (null == handlerChainsType || handlerChainsType.getHandlerChainArray() == null) {
067                        throw new WebServiceException("Chain not specified");
068                    }
069                    
070                    chain = new ArrayList<Handler>();
071                    for (HandlerChainType hc : handlerChainsType.getHandlerChainArray()) {
072                        chain.addAll(buildHandlerChain(hc, clz.getClassLoader()));
073                    }
074    
075                } catch (Exception e) {
076                    throw new WebServiceException("Chain not specified", e);
077                }
078            }
079            
080            assert chain != null;
081            if (existingHandlers != null) {
082                chain.addAll(existingHandlers);
083            }
084            return sortHandlers(chain);
085        }
086    
087        public List<Handler> buildHandlerChainFromClass(Class<?> clz) {
088            return buildHandlerChainFromClass(clz, null);
089        }
090    
091        private HandlerChainAnnotation findHandlerChainAnnotation(Class<?> clz, boolean searchSEI) {        
092            if (log.isDebugEnabled()) {
093                log.debug("Checking for HandlerChain annotation on " + clz.getName());
094            }
095            HandlerChainAnnotation hcAnn = null;
096            HandlerChain ann = clz.getAnnotation(HandlerChain.class);
097            if (ann == null) {
098                if (searchSEI) {
099                    /* HandlerChain annotation can be specified on the SEI
100                     * but the implementation bean might not implement the SEI.          
101                     */
102                    WebService ws = clz.getAnnotation(WebService.class);
103                    if (ws != null 
104                        && ws.endpointInterface() != null 
105                        && ws.endpointInterface().trim().length() > 0) {
106                        String seiClassName = ws.endpointInterface().trim();
107                        Class seiClass = null;
108                        try {
109                            seiClass = clz.getClassLoader().loadClass(seiClassName);
110                        } catch (ClassNotFoundException e) {                       
111                            throw new WebServiceException("Failed to load SEI class: " + seiClassName, e);
112                        }
113    
114                        // check SEI class and its interfaces for HandlerChain annotation
115                        hcAnn = findHandlerChainAnnotation(seiClass, false);
116                    }
117                }
118                if (hcAnn == null) {
119                    // check interfaces for HandlerChain annotation
120                    for (Class<?> iface : clz.getInterfaces()) {
121                        if (log.isDebugEnabled()) {
122                            log.debug("Checking for HandlerChain annotation on " + iface.getName());
123                        }
124                        ann = iface.getAnnotation(HandlerChain.class);
125                        if (ann != null) {
126                            hcAnn = new HandlerChainAnnotation(ann, iface);
127                            break;
128                        }
129                    }
130                }
131            } else {
132                hcAnn = new HandlerChainAnnotation(ann, clz);
133            }
134            
135            return hcAnn;
136        }
137        
138        protected List<Handler> buildHandlerChain(HandlerChainType hc, ClassLoader classLoader) {
139            List<Handler> handlerChain = new ArrayList<Handler>();
140            for (PortComponentHandlerType ht : hc.getHandlerArray()) {
141                try {
142                    log.debug("loading handler :" + trimString(ht.getHandlerName().getStringValue()));
143    
144                    Class<? extends Handler> handlerClass = Class.forName(
145                            trimString(ht.getHandlerClass()
146                                    .getStringValue()), true, classLoader)
147                            .asSubclass(Handler.class);
148    
149                    Handler handler = handlerClass.newInstance();
150                    log.debug("adding handler to chain: " + handler);
151                    handlerChain.add(handler);
152                } catch (Exception e) {
153                    throw new WebServiceException("Failed to instantiate handler", e);
154                }
155            }
156            return handlerChain;
157        }
158    
159        private String trimString(String str) {
160            return str != null ? str.trim() : null;
161        }
162    
163        /**
164         * sorts the handlers into correct order. All of the logical handlers first
165         * followed by the protocol handlers
166         *
167         * @param handlers
168         * @return sorted list of handlers
169         */
170        public List<Handler> sortHandlers(List<Handler> handlers) {
171    
172            List<LogicalHandler> logicalHandlers = new ArrayList<LogicalHandler>();
173            List<Handler> protocolHandlers = new ArrayList<Handler>();
174    
175            for (Handler handler : handlers) {
176                if (handler instanceof LogicalHandler) {
177                    logicalHandlers.add((LogicalHandler) handler);
178                } else {
179                    protocolHandlers.add(handler);
180                }
181            }
182    
183            List<Handler> sortedHandlers = new ArrayList<Handler>();
184            sortedHandlers.addAll(logicalHandlers);
185            sortedHandlers.addAll(protocolHandlers);
186            return sortedHandlers;
187        }
188    
189        private static class HandlerChainAnnotation {
190            private final Class<?> declaringClass;
191            private final HandlerChain ann;
192    
193            HandlerChainAnnotation(HandlerChain hc, Class<?> clz) {
194                ann = hc;
195                declaringClass = clz;
196            }
197    
198            public Class<?> getDeclaringClass() {
199                return declaringClass;
200            }
201    
202            public String getFileName() {
203                return ann.file();
204            }
205    
206            public void validate() {
207                if (null == ann.file() || "".equals(ann.file())) {
208                    throw new WebServiceException("@HandlerChain annotation does not contain a file name or url.");
209                }
210            }
211    
212            public String toString() {
213                return "[" + declaringClass + "," + ann + "]";
214            }
215        }
216    }