1 /* 2 * Copyright (c) 1997, 2017, 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.binding; 27 28 import com.oracle.webservices.internal.api.message.MessageContextFactory; 29 import com.sun.istack.internal.NotNull; 30 import com.sun.istack.internal.Nullable; 31 import com.sun.xml.internal.ws.api.BindingID; 32 import com.sun.xml.internal.ws.api.SOAPVersion; 33 import com.sun.xml.internal.ws.api.WSBinding; 34 import com.sun.xml.internal.ws.api.addressing.AddressingVersion; 35 import com.sun.xml.internal.ws.api.pipe.Codec; 36 import com.sun.xml.internal.ws.client.HandlerConfiguration; 37 import com.sun.xml.internal.ws.developer.MemberSubmissionAddressingFeature; 38 import com.sun.xml.internal.ws.developer.BindingTypeFeature; 39 40 import javax.activation.CommandInfo; 41 import javax.activation.CommandMap; 42 import javax.activation.MailcapCommandMap; 43 import javax.xml.namespace.QName; 44 import javax.xml.ws.Service; 45 import javax.xml.ws.WebServiceFeature; 46 import javax.xml.ws.soap.AddressingFeature; 47 import javax.xml.ws.handler.Handler; 48 import java.util.Collections; 49 import java.util.HashMap; 50 import java.util.HashSet; 51 import java.util.List; 52 import java.util.Set; 53 import java.util.Map; 54 55 56 /** 57 * Instances are created by the service, which then 58 * sets the handler chain on the binding impl. 59 * 60 * <p> 61 * This class is made abstract as we don't see a situation when 62 * a BindingImpl has much meaning without binding id. 63 * IOW, for a specific binding there will be a class 64 * extending BindingImpl, for example SOAPBindingImpl. 65 * 66 * <p> 67 * The spi Binding interface extends Binding. 68 * 69 * @author WS Development Team 70 */ 71 public abstract class BindingImpl implements WSBinding { 72 73 protected static final WebServiceFeature[] EMPTY_FEATURES = new WebServiceFeature[0]; 74 75 //This is reset when ever Binding.setHandlerChain() or SOAPBinding.setRoles() is called. 76 private HandlerConfiguration handlerConfig; 77 private final Set<QName> addedHeaders = new HashSet<QName>(); 78 private final Set<QName> knownHeaders = Collections.synchronizedSet(new HashSet<QName>()); 79 private final Set<QName> unmodKnownHeaders = Collections.unmodifiableSet(knownHeaders); 80 private final BindingID bindingId; 81 // Features that are set(enabled/disabled) on the binding 82 protected final WebServiceFeatureList features; 83 // Features that are set(enabled/disabled) on the binding or an operation 84 protected final Map<QName, WebServiceFeatureList> operationFeatures = new HashMap<QName, WebServiceFeatureList>(); 85 // Features that are set(enabled/disabled) on the binding, an operation or an input message 86 protected final Map<QName, WebServiceFeatureList> inputMessageFeatures = new HashMap<QName, WebServiceFeatureList>(); 87 // Features that are set(enabled/disabled) on the binding, an operation or an output message 88 protected final Map<QName, WebServiceFeatureList> outputMessageFeatures = new HashMap<QName, WebServiceFeatureList>(); 89 // Features that are set(enabled/disabled) on the binding, an operation or a fault message 90 protected final Map<MessageKey, WebServiceFeatureList> faultMessageFeatures = new HashMap<MessageKey, WebServiceFeatureList>(); 91 92 protected javax.xml.ws.Service.Mode serviceMode = javax.xml.ws.Service.Mode.PAYLOAD; 93 94 protected MessageContextFactory messageContextFactory; 95 96 protected BindingImpl(BindingID bindingId, WebServiceFeature ... features) { 97 this.bindingId = bindingId; 98 handlerConfig = new HandlerConfiguration(Collections.<String>emptySet(), Collections.<Handler>emptyList()); 99 if (handlerConfig.getHandlerKnownHeaders() != null) 100 knownHeaders.addAll(handlerConfig.getHandlerKnownHeaders()); 101 this.features = new WebServiceFeatureList(features); 102 this.features.validate(); 103 } 104 105 public 106 @NotNull 107 List<Handler> getHandlerChain() { 108 return handlerConfig.getHandlerChain(); 109 } 110 111 public HandlerConfiguration getHandlerConfig() { 112 return handlerConfig; 113 } 114 115 protected void setHandlerConfig(HandlerConfiguration handlerConfig) { 116 this.handlerConfig = handlerConfig; 117 knownHeaders.clear(); 118 knownHeaders.addAll(addedHeaders); 119 if (handlerConfig != null && handlerConfig.getHandlerKnownHeaders() != null) 120 knownHeaders.addAll(handlerConfig.getHandlerKnownHeaders()); 121 } 122 123 public void setMode(@NotNull Service.Mode mode) { 124 this.serviceMode = mode; 125 } 126 127 public Set<QName> getKnownHeaders() { 128 return unmodKnownHeaders; 129 } 130 131 public boolean addKnownHeader(QName headerQName) { 132 addedHeaders.add(headerQName); 133 return knownHeaders.add(headerQName); 134 } 135 136 public 137 @NotNull 138 BindingID getBindingId() { 139 return bindingId; 140 } 141 142 public final SOAPVersion getSOAPVersion() { 143 return bindingId.getSOAPVersion(); 144 } 145 146 public AddressingVersion getAddressingVersion() { 147 AddressingVersion addressingVersion; 148 if (features.isEnabled(AddressingFeature.class)) 149 addressingVersion = AddressingVersion.W3C; 150 else if (features.isEnabled(MemberSubmissionAddressingFeature.class)) 151 addressingVersion = AddressingVersion.MEMBER; 152 else 153 addressingVersion = null; 154 return addressingVersion; 155 } 156 157 @NotNull 158 public final Codec createCodec() { 159 160 // initialization from here should cover most of cases; 161 // if not, it would be necessary to call 162 // BindingImpl.initializeJavaActivationHandlers() 163 // explicitly by programmer 164 initializeJavaActivationHandlers(); 165 166 return bindingId.createEncoder(this); 167 } 168 169 public static void initializeJavaActivationHandlers() { 170 // DataHandler.writeTo() may search for DCH. So adding some default ones. 171 try { 172 CommandMap map = CommandMap.getDefaultCommandMap(); 173 if (map instanceof MailcapCommandMap) { 174 MailcapCommandMap mailMap = (MailcapCommandMap) map; 175 176 // registering our DCH since javamail's DCH doesn't handle 177 if (!cmdMapInitialized(mailMap)) { 178 mailMap.addMailcap("text/xml;;x-java-content-handler=com.sun.xml.internal.ws.encoding.XmlDataContentHandler"); 179 mailMap.addMailcap("application/xml;;x-java-content-handler=com.sun.xml.internal.ws.encoding.XmlDataContentHandler"); 180 mailMap.addMailcap("image/*;;x-java-content-handler=com.sun.xml.internal.ws.encoding.ImageDataContentHandler"); 181 mailMap.addMailcap("text/plain;;x-java-content-handler=com.sun.xml.internal.ws.encoding.StringDataContentHandler"); 182 } 183 } 184 } catch (Throwable t) { 185 // ignore the exception. 186 } 187 } 188 189 private static boolean cmdMapInitialized(MailcapCommandMap mailMap) { 190 CommandInfo[] commands = mailMap.getAllCommands("text/xml"); 191 if (commands == null || commands.length == 0) { 192 return false; 193 } 194 195 // SAAJ RI implements it's own DataHandlers which can be used for JAX-WS too; 196 // see com.sun.xml.internal.messaging.saaj.soap.AttachmentPartImpl#initializeJavaActivationHandlers 197 // so if found any of SAAJ or our own handler registered, we are ok; anyway using SAAJ directly here 198 // is not good idea since we don't want standalone JAX-WS to depend on specific SAAJ impl. 199 // This is also reason for duplication of Handler's code by JAX-WS 200 String saajClassName = "com.sun.xml.internal.messaging.saaj.soap.XmlDataContentHandler"; 201 String jaxwsClassName = "com.sun.xml.internal.ws.encoding.XmlDataContentHandler"; 202 for (CommandInfo command : commands) { 203 String commandClass = command.getCommandClass(); 204 if (saajClassName.equals(commandClass) || 205 jaxwsClassName.equals(commandClass)) { 206 return true; 207 } 208 } 209 return false; 210 } 211 212 public static BindingImpl create(@NotNull BindingID bindingId) { 213 if (bindingId.equals(BindingID.XML_HTTP)) 214 return new HTTPBindingImpl(); 215 else 216 return new SOAPBindingImpl(bindingId); 217 } 218 219 public static BindingImpl create(@NotNull BindingID bindingId, WebServiceFeature[] features) { 220 // Override the BindingID from the features 221 for(WebServiceFeature feature : features) { 222 if (feature instanceof BindingTypeFeature) { 223 BindingTypeFeature f = (BindingTypeFeature)feature; 224 bindingId = BindingID.parse(f.getBindingId()); 225 } 226 } 227 if (bindingId.equals(BindingID.XML_HTTP)) 228 return new HTTPBindingImpl(features); 229 else 230 return new SOAPBindingImpl(bindingId, features); 231 } 232 233 public static WSBinding getDefaultBinding() { 234 return new SOAPBindingImpl(BindingID.SOAP11_HTTP); 235 } 236 237 public String getBindingID() { 238 return bindingId.toString(); 239 } 240 241 public @Nullable <F extends WebServiceFeature> F getFeature(@NotNull Class<F> featureType){ 242 return features.get(featureType); 243 } 244 245 public @Nullable <F extends WebServiceFeature> F getOperationFeature(@NotNull Class<F> featureType, 246 @NotNull final QName operationName) { 247 final WebServiceFeatureList operationFeatureList = this.operationFeatures.get(operationName); 248 return FeatureListUtil.mergeFeature(featureType, operationFeatureList, features); 249 } 250 251 public boolean isFeatureEnabled(@NotNull Class<? extends WebServiceFeature> feature){ 252 return features.isEnabled(feature); 253 } 254 255 public boolean isOperationFeatureEnabled(@NotNull Class<? extends WebServiceFeature> featureType, 256 @NotNull final QName operationName) { 257 final WebServiceFeatureList operationFeatureList = this.operationFeatures.get(operationName); 258 return FeatureListUtil.isFeatureEnabled(featureType, operationFeatureList, features); 259 } 260 261 @NotNull 262 public WebServiceFeatureList getFeatures() { 263 //TODO scchen convert BindingID to WebServiceFeature[] 264 if(!isFeatureEnabled(com.oracle.webservices.internal.api.EnvelopeStyleFeature.class)) { 265 WebServiceFeature[] f = { getSOAPVersion().toFeature() }; 266 features.mergeFeatures(f, false); 267 } 268 return features; 269 } 270 271 public @NotNull WebServiceFeatureList getOperationFeatures(@NotNull final QName operationName) { 272 final WebServiceFeatureList operationFeatureList = this.operationFeatures.get(operationName); 273 return FeatureListUtil.mergeList(operationFeatureList, features); 274 } 275 276 public @NotNull WebServiceFeatureList getInputMessageFeatures(@NotNull final QName operationName) { 277 final WebServiceFeatureList operationFeatureList = this.operationFeatures.get(operationName); 278 final WebServiceFeatureList messageFeatureList = this.inputMessageFeatures.get(operationName); 279 return FeatureListUtil.mergeList(operationFeatureList, messageFeatureList, features); 280 281 } 282 283 public @NotNull WebServiceFeatureList getOutputMessageFeatures(@NotNull final QName operationName) { 284 final WebServiceFeatureList operationFeatureList = this.operationFeatures.get(operationName); 285 final WebServiceFeatureList messageFeatureList = this.outputMessageFeatures.get(operationName); 286 return FeatureListUtil.mergeList(operationFeatureList, messageFeatureList, features); 287 } 288 289 public @NotNull WebServiceFeatureList getFaultMessageFeatures(@NotNull final QName operationName, 290 @NotNull final QName messageName) { 291 final WebServiceFeatureList operationFeatureList = this.operationFeatures.get(operationName); 292 final WebServiceFeatureList messageFeatureList = this.faultMessageFeatures.get( 293 new MessageKey(operationName, messageName)); 294 return FeatureListUtil.mergeList(operationFeatureList, messageFeatureList, features); 295 } 296 297 public void setOperationFeatures(@NotNull final QName operationName, WebServiceFeature... newFeatures) { 298 if (newFeatures != null) { 299 WebServiceFeatureList featureList = operationFeatures.get(operationName); 300 if (featureList == null) { 301 featureList = new WebServiceFeatureList(); 302 } 303 for (WebServiceFeature f : newFeatures) { 304 featureList.add(f); 305 } 306 operationFeatures.put(operationName, featureList); 307 } 308 } 309 310 public void setInputMessageFeatures(@NotNull final QName operationName, WebServiceFeature... newFeatures) { 311 if (newFeatures != null) { 312 WebServiceFeatureList featureList = inputMessageFeatures.get(operationName); 313 if (featureList == null) { 314 featureList = new WebServiceFeatureList(); 315 } 316 for (WebServiceFeature f : newFeatures) { 317 featureList.add(f); 318 } 319 inputMessageFeatures.put(operationName, featureList); 320 } 321 } 322 323 public void setOutputMessageFeatures(@NotNull final QName operationName, WebServiceFeature... newFeatures) { 324 if (newFeatures != null) { 325 WebServiceFeatureList featureList = outputMessageFeatures.get(operationName); 326 if (featureList == null) { 327 featureList = new WebServiceFeatureList(); 328 } 329 for (WebServiceFeature f : newFeatures) { 330 featureList.add(f); 331 } 332 outputMessageFeatures.put(operationName, featureList); 333 } 334 } 335 336 public void setFaultMessageFeatures(@NotNull final QName operationName, @NotNull final QName messageName, WebServiceFeature... newFeatures) { 337 if (newFeatures != null) { 338 final MessageKey key = new MessageKey(operationName, messageName); 339 WebServiceFeatureList featureList = faultMessageFeatures.get(key); 340 if (featureList == null) { 341 featureList = new WebServiceFeatureList(); 342 } 343 for (WebServiceFeature f : newFeatures) { 344 featureList.add(f); 345 } 346 faultMessageFeatures.put(key, featureList); 347 } 348 } 349 350 public synchronized @NotNull com.oracle.webservices.internal.api.message.MessageContextFactory getMessageContextFactory () { 351 if (messageContextFactory == null) { 352 messageContextFactory = MessageContextFactory.createFactory(getFeatures().toArray()); 353 } 354 return messageContextFactory; 355 } 356 357 /** 358 * Experimental: Identify messages based on the name of the message and the 359 * operation that uses this message. 360 */ 361 protected static class MessageKey { 362 363 final private QName operationName; 364 final private QName messageName; 365 366 public MessageKey(final QName operationName, final QName messageName) { 367 this.operationName = operationName; 368 this.messageName = messageName; 369 } 370 371 @Override 372 public int hashCode() { 373 final int hashFirst = this.operationName != null ? this.operationName.hashCode() : 0; 374 final int hashSecond = this.messageName != null ? this.messageName.hashCode() : 0; 375 376 return (hashFirst + hashSecond) * hashSecond + hashFirst; 377 } 378 379 @Override 380 public boolean equals(Object obj) { 381 if (obj == null) { 382 return false; 383 } 384 if (getClass() != obj.getClass()) { 385 return false; 386 } 387 final MessageKey other = (MessageKey) obj; 388 if (this.operationName != other.operationName && (this.operationName == null || !this.operationName.equals(other.operationName))) { 389 return false; 390 } 391 if (this.messageName != other.messageName && (this.messageName == null || !this.messageName.equals(other.messageName))) { 392 return false; 393 } 394 return true; 395 } 396 397 @Override 398 public String toString() { 399 return "(" + this.operationName + ", " + this.messageName + ")"; 400 } 401 402 } 403 404 }