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.server.sei; 27 28import com.sun.xml.internal.ws.api.SOAPVersion; 29import com.sun.xml.internal.ws.api.message.Message; 30import com.sun.xml.internal.ws.api.message.Messages; 31import com.sun.xml.internal.ws.message.jaxb.JAXBMessage; 32import com.sun.xml.internal.ws.model.ParameterImpl; 33import com.sun.xml.internal.ws.model.WrapperParameter; 34import com.sun.xml.internal.ws.spi.db.BindingContext; 35import com.sun.xml.internal.ws.spi.db.XMLBridge; 36import com.sun.xml.internal.ws.spi.db.PropertyAccessor; 37import com.sun.xml.internal.ws.spi.db.WrapperComposite; 38 39import javax.xml.bind.JAXBException; 40import javax.xml.namespace.QName; 41import javax.xml.ws.Holder; 42import javax.xml.ws.WebServiceException; 43import java.util.List; 44 45/** 46 * Builds a JAXB object that represents the payload. 47 * 48 * @see MessageFiller 49 * @author Jitendra Kotamraju 50 */ 51public abstract class EndpointResponseMessageBuilder { 52 public abstract Message createMessage(Object[] methodArgs, Object returnValue); 53 54 public static final EndpointResponseMessageBuilder EMPTY_SOAP11 = new Empty(SOAPVersion.SOAP_11); 55 public static final EndpointResponseMessageBuilder EMPTY_SOAP12 = new Empty(SOAPVersion.SOAP_12); 56 57 private static final class Empty extends EndpointResponseMessageBuilder { 58 private final SOAPVersion soapVersion; 59 60 public Empty(SOAPVersion soapVersion) { 61 this.soapVersion = soapVersion; 62 } 63 64 public Message createMessage(Object[] methodArgs, Object returnValue) { 65 return Messages.createEmpty(soapVersion); 66 } 67 } 68 69 /** 70 * Base class for those {@link EndpointResponseMessageBuilder}s that build a {@link Message} 71 * from JAXB objects. 72 */ 73 private static abstract class JAXB extends EndpointResponseMessageBuilder { 74 /** 75 * This object determines the binding of the object returned 76 * from {@link #createMessage(Object[], Object)} 77 */ 78 private final XMLBridge bridge; 79 private final SOAPVersion soapVersion; 80 81 protected JAXB(XMLBridge bridge, SOAPVersion soapVersion) { 82 assert bridge!=null; 83 this.bridge = bridge; 84 this.soapVersion = soapVersion; 85 } 86 87 public final Message createMessage(Object[] methodArgs, Object returnValue) { 88 return JAXBMessage.create( bridge, build(methodArgs, returnValue), soapVersion ); 89 } 90 91 /** 92 * Builds a JAXB object that becomes the payload. 93 */ 94 abstract Object build(Object[] methodArgs, Object returnValue); 95 } 96 97 /** 98 * Used to create a payload JAXB object just by taking 99 * one of the parameters. 100 */ 101 public final static class Bare extends JAXB { 102 /** 103 * The index of the method invocation parameters that goes into the payload. 104 */ 105 private final int methodPos; 106 107 private final ValueGetter getter; 108 109 /** 110 * Creates a {@link EndpointResponseMessageBuilder} from a bare parameter. 111 */ 112 public Bare(ParameterImpl p, SOAPVersion soapVersion) { 113 super(p.getXMLBridge(), soapVersion); 114 this.methodPos = p.getIndex(); 115 this.getter = ValueGetter.get(p); 116 } 117 118 /** 119 * Picks up an object from the method arguments and uses it. 120 */ 121 Object build(Object[] methodArgs, Object returnValue) { 122 if (methodPos == -1) { 123 return returnValue; 124 } 125 return getter.get(methodArgs[methodPos]); 126 } 127 } 128 129 130 /** 131 * Used to handle a 'wrapper' style request. 132 * Common part of rpc/lit and doc/lit. 133 */ 134 abstract static class Wrapped extends JAXB { 135 136 /** 137 * Where in the method argument list do they come from? 138 */ 139 protected final int[] indices; 140 141 /** 142 * Abstracts away the {@link Holder} handling when touching method arguments. 143 */ 144 protected final ValueGetter[] getters; 145 146 /** 147 * How does each wrapped parameter binds to XML? 148 */ 149 protected XMLBridge[] parameterBridges; 150 151 /** 152 * Used for error diagnostics. 153 */ 154 protected List<ParameterImpl> children; 155 156 protected Wrapped(WrapperParameter wp, SOAPVersion soapVersion) { 157 super(wp.getXMLBridge(), soapVersion); 158 159 children = wp.getWrapperChildren(); 160 161 indices = new int[children.size()]; 162 getters = new ValueGetter[children.size()]; 163 for( int i=0; i<indices.length; i++ ) { 164 ParameterImpl p = children.get(i); 165 indices[i] = p.getIndex(); 166 getters[i] = ValueGetter.get(p); 167 } 168 } 169 170 /** 171 * Packs a bunch of arguments intoa {@link WrapperComposite}. 172 */ 173 WrapperComposite buildWrapperComposite(Object[] methodArgs, Object returnValue) { 174 WrapperComposite cs = new WrapperComposite(); 175 cs.bridges = parameterBridges; 176 cs.values = new Object[parameterBridges.length]; 177 178 // fill in wrapped parameters from methodArgs 179 for( int i=indices.length-1; i>=0; i-- ) { 180 Object v; 181 if (indices[i] == -1) { 182 v = getters[i].get(returnValue); 183 } else { 184 v = getters[i].get(methodArgs[indices[i]]); 185 } 186 if(v==null) { 187 throw new WebServiceException("Method Parameter: "+ 188 children.get(i).getName() +" cannot be null. This is BP 1.1 R2211 violation."); 189 } 190 cs.values[i] = v; 191 } 192 193 return cs; 194 } 195 } 196 197 /** 198 * Used to create a payload JAXB object by wrapping 199 * multiple parameters into one "wrapper bean". 200 */ 201 public final static class DocLit extends Wrapped { 202 /** 203 * How does each wrapped parameter binds to XML? 204 */ 205 private final PropertyAccessor[] accessors; 206 207 //private final RawAccessor retAccessor; 208 209 /** 210 * Wrapper bean. 211 */ 212 private final Class wrapper; 213 private boolean dynamicWrapper; 214 215 /** 216 * Needed to get wrapper instantiation method. 217 */ 218 private BindingContext bindingContext; 219 220 /** 221 * Creates a {@link EndpointResponseMessageBuilder} from a {@link WrapperParameter}. 222 */ 223 public DocLit(WrapperParameter wp, SOAPVersion soapVersion) { 224 super(wp, soapVersion); 225 bindingContext = wp.getOwner().getBindingContext(); 226 wrapper = (Class)wp.getXMLBridge().getTypeInfo().type; 227 dynamicWrapper = WrapperComposite.class.equals(wrapper); 228 children = wp.getWrapperChildren(); 229 parameterBridges = new XMLBridge[children.size()]; 230 accessors = new PropertyAccessor[children.size()]; 231 for( int i=0; i<accessors.length; i++ ) { 232 ParameterImpl p = children.get(i); 233 QName name = p.getName(); 234 if (dynamicWrapper) { 235 parameterBridges[i] = children.get(i).getInlinedRepeatedElementBridge(); 236 if (parameterBridges[i] == null) parameterBridges[i] = children.get(i).getXMLBridge(); 237 } else { 238 try { 239 accessors[i] = (dynamicWrapper) ? null : 240 p.getOwner().getBindingContext().getElementPropertyAccessor( 241 wrapper, name.getNamespaceURI(), name.getLocalPart() ); 242 } catch (JAXBException e) { 243 throw new WebServiceException( // TODO: i18n 244 wrapper+" do not have a property of the name "+name,e); 245 } 246 } 247 } 248 249 } 250 251 /** 252 * Packs a bunch of arguments into a {@link WrapperComposite}. 253 */ 254 Object build(Object[] methodArgs, Object returnValue) { 255 if (dynamicWrapper) return buildWrapperComposite(methodArgs, returnValue); 256 try { 257 //Object bean = wrapper.newInstance(); 258 Object bean = bindingContext.newWrapperInstace(wrapper); 259 260 // fill in wrapped parameters from methodArgs 261 for( int i=indices.length-1; i>=0; i-- ) { 262 if (indices[i] == -1) { 263 accessors[i].set(bean, returnValue); 264 } else { 265 accessors[i].set(bean,getters[i].get(methodArgs[indices[i]])); 266 } 267 } 268 269 return bean; 270 } catch (InstantiationException e) { 271 // this is irrecoverable 272 Error x = new InstantiationError(e.getMessage()); 273 x.initCause(e); 274 throw x; 275 } catch (IllegalAccessException e) { 276 // this is irrecoverable 277 Error x = new IllegalAccessError(e.getMessage()); 278 x.initCause(e); 279 throw x; 280 } catch (com.sun.xml.internal.ws.spi.db.DatabindingException e) { 281 // this can happen when the set method throw a checked exception or something like that 282 throw new WebServiceException(e); // TODO:i18n 283 } 284 } 285 } 286 287 288 /** 289 * Used to create a payload JAXB object by wrapping 290 * multiple parameters into a {@link WrapperComposite}. 291 * 292 * <p> 293 * This is used for rpc/lit, as we don't have a wrapper bean for it. 294 * (TODO: Why don't we have a wrapper bean for this, when doc/lit does!?) 295 */ 296 public final static class RpcLit extends Wrapped { 297 298 /** 299 * Creates a {@link EndpointResponseMessageBuilder} from a {@link WrapperParameter}. 300 */ 301 public RpcLit(WrapperParameter wp, SOAPVersion soapVersion) { 302 super(wp, soapVersion); 303 // we'll use CompositeStructure to pack requests 304 assert wp.getTypeInfo().type==WrapperComposite.class; 305 306 parameterBridges = new XMLBridge[children.size()]; 307 for( int i=0; i<parameterBridges.length; i++ ) 308 parameterBridges[i] = children.get(i).getXMLBridge(); 309 } 310 311 /** 312 * Packs a bunch of arguments intoa {@link WrapperComposite}. 313 */ 314 Object build(Object[] methodArgs, Object returnValue) { 315 return buildWrapperComposite(methodArgs, returnValue); 316 } 317 } 318} 319