1/* 2 * Copyright (c) 1997, 2013, 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 26package com.sun.xml.internal.ws.client; 27 28import com.sun.istack.internal.NotNull; 29import com.sun.istack.internal.Nullable; 30import com.sun.xml.internal.ws.api.client.WSPortInfo; 31import com.sun.xml.internal.ws.binding.BindingImpl; 32import com.sun.xml.internal.ws.handler.HandlerChainsModel; 33import com.sun.xml.internal.ws.util.HandlerAnnotationInfo; 34import com.sun.xml.internal.ws.util.HandlerAnnotationProcessor; 35 36import javax.jws.HandlerChain; 37import javax.xml.ws.Service; 38import javax.xml.ws.handler.Handler; 39import javax.xml.ws.handler.HandlerResolver; 40import javax.xml.ws.handler.PortInfo; 41import javax.xml.ws.soap.SOAPBinding; 42import java.util.ArrayList; 43import java.util.HashMap; 44import java.util.List; 45import java.util.Map; 46import java.util.logging.Level; 47import 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 */ 57abstract 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} 186