Package com.jaxws.json.codec

Source Code of com.jaxws.json.codec.MessageBodyBuilder

package com.jaxws.json.codec;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;

import javax.jws.soap.SOAPBinding.Style;
import javax.xml.namespace.QName;
import javax.xml.ws.handler.MessageContext;

import org.jvnet.mimepull.MIMEPart;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.jaxws.json.JSONMessage;
import com.jaxws.json.codec.decode.WSJSONPopulator;
import com.jaxws.json.codec.encode.JSONEncoder;
import com.jaxws.json.feature.JSONWebService;
import com.jaxws.json.packet.handler.Encoder;
import com.sun.xml.bind.api.Bridge;
import com.sun.xml.bind.api.CompositeStructure;
import com.sun.xml.bind.v2.runtime.JAXBContextImpl;
import com.sun.xml.ws.api.message.Message;
import com.sun.xml.ws.api.message.Packet;
import com.sun.xml.ws.api.model.JavaMethod;
import com.sun.xml.ws.api.model.SEIModel;
import com.sun.xml.ws.api.model.wsdl.WSDLBoundOperation;
import com.sun.xml.ws.api.model.wsdl.WSDLPart;
import com.sun.xml.ws.message.jaxb.JAXBMessage;
import com.sun.xml.ws.model.JavaMethodImpl;
import com.sun.xml.ws.model.ParameterImpl;
import com.sun.xml.ws.model.WrapperParameter;
import com.sun.xml.ws.model.wsdl.WSDLBoundOperationImpl;
import com.sun.xml.ws.util.ServiceFinder;

public class MessageBodyBuilder {
  final protected JSONCodec   codec;
  private static Logger LOG  = Logger.getLogger(JSONCodec.class.getName());

  static Field jaxbObjectAccessor = null;
 
  static Method javaMethodAccessor = null;
 
  /**
   * Since jaxb object is private access it via reflection way. If property name renamed or on error
   * go with old serialization way.
   * TODO find better way in JAX_WS 2.x
   */
  public static boolean CAN_HANDLE_RESPONE  = false;
 
  static{
    try {
      jaxbObjectAccessor  = JAXBMessage.class.getDeclaredField("jaxbObject");
      jaxbObjectAccessor.setAccessible(true);
      CAN_HANDLE_RESPONE = true;
    } catch (Throwable e) {
      LOG.log(Level.SEVERE,"JAXBMessage reading private field jaxbObject failed.",e);
    }
   
    try{
      javaMethodAccessor = SEIModel.class.getMethod("getJavaMethodForWsdlOperation",QName.class);
    }catch(Throwable th){
      LOG.log(Level.INFO,"Old version of metro used. java method accessed using \"getJavaMethod\" operation from sei model");
    }
  }
 
  public MessageBodyBuilder(JSONCodec codec) {
    super();
    this.codec = codec;
   
  }

  @SuppressWarnings("unchecked")
  public Message handleMessage(Packet packet,String payloadName) throws Exception{
    Map<String, Object> invocationProperties = packet.invocationProperties;
    boolean OUT_BOUND = invocationProperties.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY) != null &&
              (Boolean)invocationProperties.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
    SEIModel       seiModel   = this.codec.getSEIModel(packet);
    JAXBContextImpl   context   = (JAXBContextImpl)seiModel.getJAXBContext();
    Style style = seiModel.getPort().getBinding().getStyle();
    if(!OUT_BOUND){
      // Request message
      // TODO when operation <input><json:body contains different namespace than port level name space bellow call fails to identify operation.
      WSDLBoundOperation operation   = seiModel.getPort().getBinding().getOperation(seiModel.getTargetNamespace(),payloadName);
      if(operation == null || !packet.invocationProperties.containsKey(JSONCodec.JSON_MAP_KEY)){
        throw new RuntimeException("Operation %s input parameter(s) not found or invalid.");
      }
      JavaMethod       javaMethod   = seiModel.getJavaMethod(operation.getName());
      if(javaMethod == null && javaMethodAccessor != null){
        javaMethod = (JavaMethod) javaMethodAccessor.invoke(seiModel, operation.getName());
      }else{
        // TODO iterate all method and find
      }
      Method         seiMethod   = javaMethod.getSEIMethod();
      JSONWebService  jsonwebService  = javaMethod.getMethod().getAnnotation(JSONWebService.class);
      // Put codec specific properties in invoke
      invocationProperties.put(JSONCodec.globalMapKeyPattern_KEY, (jsonwebService == null || jsonwebService.listMapKey().isEmpty())?
          JSONCodec.globalMapKeyPattern : Pattern.compile(jsonwebService.listMapKey()));
      invocationProperties.put(JSONCodec.globalMapValuePattern_KEY, (jsonwebService == null || jsonwebService.listMapValue().isEmpty())?
          JSONCodec.globalMapValuePattern : Pattern.compile(jsonwebService.listMapValue()));
      //
     
      Map<String,Object>   operationParameters = (Map<String, Object>) invocationProperties.remove(JSONCodec.JSON_MAP_KEY);
     
      WSJSONPopulator   jsonPopulator     = new WSJSONPopulator((Pattern)invocationProperties.get(JSONCodec.globalMapKeyPattern_KEY),
          (Pattern)invocationProperties.get(JSONCodec.globalMapValuePattern_KEY),JSONCodec.dateFormat,
          codec.getCustomSerializer()
          ,(DebugTrace)invocationProperties.get(JSONCodec.TRACE));
     
      Object[]      parameterObjects  = new Object[operation.getInParts().size()];
      Class<?>[]       parameterTypes     = seiMethod.getParameterTypes();// This parameter types not trustable in case of HOLDER
      for(Map.Entry<String, WSDLPart> part : operation.getInParts().entrySet()){
        Class<?>     parameterType;
        if(context.getGlobalType(part.getValue().getDescriptor().name()) != null)
          parameterType = context.getGlobalType(part.getValue().getDescriptor().name()).jaxbType;
        else
          /*
           * This parameter types not trustable in case of HOLDER
           * We can't find it in global type once user extend simple type and use it as method parameter.
           * E.g String255 extended from String
           */
          parameterType = parameterTypes[part.getValue().getIndex()];
        if(!operationParameters.containsKey(part.getKey())){
          return new JSONMessage(null, operation, operationParameters, jsonPopulator);
                //throw new RuntimeException(String.format("Request parameter %s can't be null. B.P 1.1 vilation", part.getKey()));
              }
       
        Object val = null;
              if(!WSJSONPopulator.isJSONPrimitive(parameterType)){
                val = jsonPopulator.populateObject(jsonPopulator.getNewInstance(parameterType),
                    (Map<String,Object>)operationParameters.get(part.getKey()),jsonwebService,
                    (List<MIMEPart>) invocationProperties.get(JSONCodec.MIME_ATTACHMENTS));
              } else {
                val  = jsonPopulator.convert(parameterType, null, operationParameters.get(part.getKey()),
                    seiMethod != null ? seiMethod.getAnnotation(JSONWebService.class) : null, null);
              }
              parameterObjects[part.getValue().getIndex()] = val;
      }
     
      // TODO find better way with out using JavaMethodImpl
      List<ParameterImpl> requestParameters = ((JavaMethodImpl)javaMethod).getRequestParameters();
      List<ParameterImpl> responseParameters = ((JavaMethodImpl)javaMethod).getResponseParameters();
      invocationProperties.put(JSONEncoder.RESPONSEPARAMETERS, responseParameters);
     
      if(operation instanceof WSDLBoundOperationImpl && ((WSDLBoundOperationImpl)operation).getOutputMimeTypes().size() > 0){
        // Use only one in case of multipart use attachment
        String mimeType = String.valueOf(((WSDLBoundOperationImpl)operation).getOutputMimeTypes().values().toArray()[0]);
        for (Encoder handler : ServiceFinder.find(Encoder.class)) {
          if(mimeType.equals(handler.mimeContent())){
            invocationProperties.put(JSONCodec.ENCODER, handler);
            break;
          }
        }
      }
      if(requestParameters != null && requestParameters.size() == 1){
        ParameterImpl parameter = requestParameters.get(0);
        if(parameter.isWrapperStyle()){
          // RPC literal
          List<ParameterImpl> childParameters = ((WrapperParameter)parameter).getWrapperChildren();
          if(parameterObjects.length != childParameters.size())
            throw new RuntimeException("Invalid count of parameters");
          Object  obj  = null;
          if(style == Style.RPC){
            CompositeStructure cs = new CompositeStructure();
            cs.values  = parameterObjects;
            cs.bridges  = new Bridge[childParameters.size()];
            for(ParameterImpl parameterChild : childParameters){
              cs.bridges[parameterChild.getIndex()] = parameterChild.getBridge();
            }
            obj  = cs;
          }else{
            Class<?> type = (Class<?>)parameter.getBridge().getTypeReference().type;
            obj   = jsonPopulator.getNewInstance(type);
            for(ParameterImpl parameterChild : childParameters){
              type.getField(parameterChild.getPartName()).set(obj,
                  parameterObjects[parameterChild.getIndex()]);
            }
          }
          return JAXBMessage.create(parameter.getBridge(), obj, this.codec.soapVersion);
        }else{
          // BARE
          return new JSONMessage(null, operation, operationParameters,jsonPopulator);
        }
      }else{
        return new JSONMessage(null, operation, operationParameters,jsonPopulator);
      }
    }else{
      Message message = packet.getMessage();
      if(message == null){
        throw new RuntimeException("Null response message");
      }
      List<ParameterImpl> responseParameters   = (List<ParameterImpl>) invocationProperties.remove(JSONEncoder.RESPONSEPARAMETERS);
      Map<String,Object>   responseParametersMap = new HashMap<String, Object>();
      if(CAN_HANDLE_RESPONE && message instanceof JAXBMessage){
        if(style == Style.RPC ){
          Object jaxbObject = jaxbObjectAccessor.get(message);
          if(jaxbObject instanceof com.sun.xml.bind.api.CompositeStructure){
            com.sun.xml.bind.api.CompositeStructure responseWraper = (com.sun.xml.bind.api.CompositeStructure)jaxbObject;
            if(responseWraper != null){
              for(int index = 0; index < responseWraper.bridges.length; index++){
                responseParametersMap.put(responseWraper.bridges[index].getTypeReference().tagName.getLocalPart(),
                  responseWraper.values[index]);
              }
            }
          }else{
            responseParametersMap.put(message.getPayloadLocalPart(), jaxbObject);
          }
        }else{
          // Docunemnt
          Object object = jaxbObjectAccessor.get(message);
          for(Field field : object.getClass().getFields()){
            responseParametersMap.put(field.getName(), field.get(object));
          }
        }
      } else if(responseParameters != null && responseParameters.size() == 1){
        // object deserialized. might perform bad.
        ParameterImpl     parameter   = responseParameters.get(0);
        Iterator<Node>     paramBody   = message.readAsSOAPMessage().getSOAPBody().getChildElements(parameter.getName());
        if(paramBody.hasNext()){
          Element responseElm = (Element)paramBody.next();
          if(parameter.isWrapperStyle()){
            List<ParameterImpl> children = ((WrapperParameter)parameter).getWrapperChildren();
            for(ParameterImpl param : children){
              NodeList paramElm = responseElm.getElementsByTagNameNS(param.getName().getNamespaceURI(),
                  param.getPartName());
              if(paramElm.getLength() == 1){
                responseParametersMap.put(param.getPartName(),
                    param.getBridge().unmarshal(paramElm.item(0)));
              }
            }
          }else{
            responseParametersMap.put(parameter.getPartName(),
                parameter.getBridge().unmarshal(responseElm));
          }
        }
      }
      invocationProperties.put(JSONCodec.JSON_MAP_KEY, responseParametersMap);
      return message;
    }
  }
     
}
TOP

Related Classes of com.jaxws.json.codec.MessageBodyBuilder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.