View Javadoc
1   /*
2    * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package com.sun.xml.internal.ws.client;
27  
28  import com.sun.istack.internal.NotNull;
29  import com.sun.istack.internal.Nullable;
30  import com.sun.xml.internal.ws.api.client.WSPortInfo;
31  import com.sun.xml.internal.ws.binding.BindingImpl;
32  import com.sun.xml.internal.ws.handler.HandlerChainsModel;
33  import com.sun.xml.internal.ws.util.HandlerAnnotationInfo;
34  import com.sun.xml.internal.ws.util.HandlerAnnotationProcessor;
35  
36  import javax.jws.HandlerChain;
37  import javax.xml.ws.Service;
38  import javax.xml.ws.handler.Handler;
39  import javax.xml.ws.handler.HandlerResolver;
40  import javax.xml.ws.handler.PortInfo;
41  import javax.xml.ws.soap.SOAPBinding;
42  import java.util.ArrayList;
43  import java.util.HashMap;
44  import java.util.List;
45  import java.util.Map;
46  import java.util.logging.Level;
47  import java.util.logging.Logger;
48  
49  /**
50   * Used by {@link WSServiceDelegate} to configure {@link BindingImpl}
51   * with handlers. The two mechanisms encapsulated by this abstraction
52   * is {@link HandlerChain} annotaion and {@link HandlerResolver}
53   * interface.
54   *
55   * @author Kohsuke Kawaguchi
56   */
57  abstract class HandlerConfigurator {
58      /**
59       * Configures the given {@link BindingImpl} object by adding handlers to it.
60       */
61      abstract void configureHandlers(@NotNull WSPortInfo port, @NotNull BindingImpl binding);
62  
63      /**
64       * Returns a {@link HandlerResolver}, if this object encapsulates any {@link HandlerResolver}.
65       * Otherwise null.
66       */
67      abstract HandlerResolver getResolver();
68  
69  
70      /**
71       * Configures handlers by calling {@link HandlerResolver}.
72       * <p>
73       * When a null {@link HandlerResolver} is set by the user to
74       * {@link Service#setHandlerResolver(HandlerResolver)}, we'll use this object
75       * with null {@link #resolver}.
76       */
77      static final class HandlerResolverImpl extends HandlerConfigurator {
78          private final @Nullable HandlerResolver resolver;
79  
80          public HandlerResolverImpl(HandlerResolver resolver) {
81              this.resolver = resolver;
82          }
83  
84          @Override
85          void configureHandlers(@NotNull WSPortInfo port, @NotNull BindingImpl binding) {
86              if (resolver!=null) {
87                  binding.setHandlerChain(resolver.getHandlerChain(port));
88              }
89          }
90  
91  
92          @Override
93          HandlerResolver getResolver() {
94              return resolver;
95          }
96      }
97  
98      /**
99       * Configures handlers from {@link HandlerChain} annotation.
100      *
101      * <p>
102      * This class is a simple
103      * map of PortInfo objects to handler chains. It is used by a
104      * {@link WSServiceDelegate} object, and can
105      * be replaced by user code with a different class implementing
106      * HandlerResolver. This class is only used on the client side, and
107      * it includes a lot of logging to help when there are issues since
108      * it deals with port names, service names, and bindings. All three
109      * must match when getting a handler chain from the map.
110      *
111      * <p>It is created by the {@link WSServiceDelegate}
112      * class , which uses {@link HandlerAnnotationProcessor} to create
113      * a handler chain and then it sets the chains on this class and they
114      * are put into the map. The ServiceContext uses the map to set handler
115      * chains on bindings when they are created.
116      */
117     static final class AnnotationConfigurator extends HandlerConfigurator {
118         private final HandlerChainsModel handlerModel;
119         private final Map<WSPortInfo,HandlerAnnotationInfo> chainMap = new HashMap<WSPortInfo,HandlerAnnotationInfo>();
120         private static final Logger logger = Logger.getLogger(
121             com.sun.xml.internal.ws.util.Constants.LoggingDomain + ".handler");
122 
123         AnnotationConfigurator(WSServiceDelegate delegate) {
124             handlerModel = HandlerAnnotationProcessor.buildHandlerChainsModel(delegate.getServiceClass());
125             assert handlerModel!=null; // this class is suppeod to be called only when there's @HandlerCHain
126         }
127 
128 
129         void configureHandlers(WSPortInfo port, BindingImpl binding) {
130             //Check in cache first
131             HandlerAnnotationInfo chain = chainMap.get(port);
132 
133             if(chain==null) {
134                 logGetChain(port);
135                 // Put it in cache
136                 chain = handlerModel.getHandlersForPortInfo(port);
137                 chainMap.put(port,chain);
138             }
139 
140             if (binding instanceof SOAPBinding) {
141                 ((SOAPBinding) binding).setRoles(chain.getRoles());
142             }
143 
144             logSetChain(port,chain);
145             binding.setHandlerChain(chain.getHandlers());
146         }
147 
148         HandlerResolver getResolver() {
149             return new HandlerResolver() {
150                 public List<Handler> getHandlerChain(PortInfo portInfo) {
151                     return new ArrayList<Handler>(
152                         handlerModel.getHandlersForPortInfo(portInfo).getHandlers());
153                 }
154             };
155         }
156         // logged at finer level
157         private void logSetChain(WSPortInfo info, HandlerAnnotationInfo chain) {
158             logger.finer("Setting chain of length " + chain.getHandlers().size() +
159                 " for port info");
160             logPortInfo(info, Level.FINER);
161         }
162 
163         // logged at fine level
164         private void logGetChain(WSPortInfo info) {
165             logger.fine("No handler chain found for port info:");
166             logPortInfo(info, Level.FINE);
167             logger.fine("Existing handler chains:");
168             if (chainMap.isEmpty()) {
169                 logger.fine("none");
170             } else {
171                 for (WSPortInfo key : chainMap.keySet()) {
172                     logger.fine(chainMap.get(key).getHandlers().size() +
173                         " handlers for port info ");
174                     logPortInfo(key, Level.FINE);
175                 }
176             }
177         }
178 
179         private void logPortInfo(WSPortInfo info, Level level) {
180             logger.log(level, "binding: " + info.getBindingID() +
181                 "\nservice: " + info.getServiceName() +
182                 "\nport: " + info.getPortName());
183         }
184     }
185 }