Package com.jaxws.json.codec.decode

Source Code of com.jaxws.json.codec.decode.FormDecoder

package com.jaxws.json.codec.decode;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.ServletRequest;
import javax.xml.ws.WebServiceException;
import javax.xml.ws.handler.MessageContext;

import org.jvnet.mimepull.MIMEMessage;
import org.jvnet.mimepull.MIMEPart;

import com.jaxws.json.codec.JSONCodec;
import com.jaxws.json.codec.JSONContentType;
import com.jaxws.json.codec.JSONFault;
import com.jaxws.json.codec.MessageBodyBuilder;
import com.sun.xml.messaging.saaj.packaging.mime.internet.ContentDisposition;
import com.sun.xml.messaging.saaj.packaging.mime.internet.ParseException;
import com.sun.xml.ws.api.message.Message;
import com.sun.xml.ws.api.message.Packet;
import com.sun.xml.ws.encoding.ContentType;
import com.sun.xml.ws.transport.Headers;

/**
* @author ssaminathan
*
*/
public class FormDecoder {
  public   static final String FORM_MULTIPART     = "multipart/form-data";
  public   static final String FORM_URLENCODED   = "application/x-www-form-urlencoded";
 
  /**
   * Codec instance to read JSON configuration properties, date format etc.
   */
  private JSONCodec     codec;
  /**
   * Input stream with/out attachment.
   */
  private InputStream   input;
  /**
   * JAXB read packet to get trace log.
   */
  private Packet       packet;
  /**
   * Request content type either multipart/form-data or application/x-www-form-urlencoded with boundtry or encoding
   */
  private ContentType    contentType;
 
  private final String  JSON_PARAM_NAME;
  /**
   * @param codec
   * @param in
   * @param packet
   * @param contentType
   */
  public FormDecoder(JSONCodec codec, InputStream in, Packet packet,
      ContentType contentType) {
    if(!(contentType.getBaseType().equalsIgnoreCase(FORM_MULTIPART) ||
        contentType.getBaseType().equalsIgnoreCase(FORM_URLENCODED))){
      throw new RuntimeException("Invalid contenty type. FormDecoder handle only " + FORM_MULTIPART + " " + FORM_URLENCODED);
    }
    this.codec       = codec;
    this.input       = in;
    this.packet     = packet;
    this.contentType   = contentType;
    this.JSON_PARAM_NAME =  (packet.supports(MessageContext.HTTP_REQUEST_HEADERS) &&
          ((Headers)packet.get(MessageContext.HTTP_REQUEST_HEADERS)).getFirst(JSONCodec.XJSONPARAM_HEADER) != null)?
          ((Headers)packet.get(MessageContext.HTTP_REQUEST_HEADERS)).getFirst(JSONCodec.XJSONPARAM_HEADER) :
            JSONCodec.XJSONPARAM_DEFAULT;
  }
 
  /**
   * @return
   * @throws UnsupportedEncodingException
   */
  public Message getWSMessage() throws UnsupportedEncodingException {
    if(contentType.getBaseType().equalsIgnoreCase(FORM_MULTIPART)){
      return getMultiPartMessageWithAttachement();
    }else{
      return getFormData();
    }
  }

  /**
   * @return Message with from data.
   * @throws UnsupportedEncodingException
   */
  private Message getMultiPartMessageWithAttachement() throws UnsupportedEncodingException {
    if(input != null){
        String boundary = contentType.getParameter("boundary");
          if (boundary == null || boundary.equals("")) {
              throw new WebServiceException("MIME boundary parameter not found" + contentType);
          }
          
          MIMEMessage message =  new MIMEMessage(input, boundary);
          MIMEPart  jsonPart  = null;   
      for(MIMEPart mimeAttach : message.getAttachments()){
        if(mimeAttach.getContentType().equalsIgnoreCase(JSONContentType.JSON_MIME_TYPE)) {
          jsonPart  = mimeAttach;
          break;
        } else {
          List<String> contentDisposition = mimeAttach.getHeader(JSONCodec.CONTENT_DISPOSITION_HEADER);
          if(contentDisposition != null && contentDisposition.size() > 0){
            try {
              ContentDisposition disp = new ContentDisposition(contentDisposition.get(0));
              if(disp.getParameter("name") != null && disp.getParameter("name").equals(JSON_PARAM_NAME)){
                jsonPart = mimeAttach;
                break;
              }
            } catch (ParseException e) {}
          }
        }
      }
      if(jsonPart == null){
        throw new RuntimeException(String.format("There is no request JSON found in multipart mime. Your JSON input http \"parameter\"" +
            " must be named as \"%s\" or pass %s: <Your json param name>. In alternate case body part content type should be %s " +
            " json content as mime part body.", JSONCodec.XJSONPARAM_DEFAULT, JSONCodec.XJSONPARAM_HEADER, JSONContentType.JSON_MIME_TYPE));
      }
      List<MIMEPart> attachments = message.getAttachments();
      /*
       * Remove JSON part from attachment list. JSON part reseved for codec. and handled by JSONDecoder.
       *
       */
      attachments.remove(jsonPart);
      /*
       * Put attachemnts into invoke properties of packet.
       */
      this.packet.invocationProperties.put(JSONCodec.MIME_ATTACHMENTS,attachments);
      /*
       * Decode message
       */
      com.sun.xml.ws.api.message.Message wsMessage = new JSONDecoder(this.codec,jsonPart.readOnce(),packet).getWSMessage();
      /*
       * Remove attachment. Else same packet object used in response. It leads attachment fall back in response.
       */
      this.packet.invocationProperties.remove(JSONCodec.MIME_ATTACHMENTS);
      /*
       * TODO
       * Its weared all form post leads to multipart response. Investigate and find better response type for form post.
       * In case of application/json form post leads popup in browser.
       * So multipart or text/plain preferred by user. But when XMLHttp support attachment, its good to send application/json or
       * multi part mime.
       *
       */
      if(this.packet.invocationProperties.get(JSONCodec.ENCODER) == null){
        this.packet.invocationProperties.put(JSONCodec.FORCED_RESPONSE_CONTENT_TYPE,JSONContentType.MULTIPART_MIXED);
      }
      return wsMessage;
    } else {
      throw new RuntimeException("Multipart form data should be POST. No input stream found.");
    }
  }
 
  /**
   * @return
   */
  private Message getFormData() {
    ServletRequest request = (ServletRequest) this.packet.get(MessageContext.SERVLET_REQUEST);

    @SuppressWarnings("unchecked")
    Map<String,Object> parameter = request.getParameterMap();
    Map<String,Object> jsonMap  = new HashMap<String, Object>();
    if(parameter.isEmpty() && request.getContentLength() > 0){
      processPostBody(jsonMap,request);
    }else{
      for(Entry<String, Object> paramEntry : parameter.entrySet()){
        fillParameterMap(paramEntry.getKey(), request.getParameter(paramEntry.getKey()), jsonMap);
      }
    }
    try {
      if(jsonMap.size() == 1){
        // Must be only one operation
        packet.invocationProperties.put(JSONCodec.FORCED_RESPONSE_CONTENT_TYPE, null);
        Entry<String, Object> operation = jsonMap.entrySet().iterator().next();
        this.packet.invocationProperties.put(JSONCodec.JSON_MAP_KEY, operation.getValue());
        return new MessageBodyBuilder(this.codec).handleMessage(this.packet,operation.getKey());
      }else if(jsonMap.containsKey("JSON_OPERATION") && jsonMap.get("JSON_OPERATION") instanceof String){
        String opertionName    = (String)jsonMap.get("JSON_OPERATION");
        this.packet.invocationProperties.put(JSONCodec.JSON_MAP_KEY, jsonMap);
        return new MessageBodyBuilder(this.codec).handleMessage(this.packet, opertionName);
      }else{
        throw new RuntimeException("Unknown or More than one operation found. " +
            "Your using form data. " +
            "Use your parameter as json like \"{operation:{\"myaparam\":.. OR specify " +
            "\"JSON_OPERATION\" parameter with your operation name.");
      }
    } catch (Exception e) {
      throw new JSONFault("Client","Failed to create message body."+e.getMessage(),"MessageBody Builder",null,e);
   
   
  }
 
  private void fillParameterMap(String parameter,Object value,Map<String,Object> mapValue){
    if(parameter.indexOf('.') > -1){
      String key = parameter.substring(0, parameter.indexOf('.'));
      // TODO IF key is idex like 0..x then its array
      @SuppressWarnings("unchecked")
      Map<String,Object> jsonMap  = mapValue.containsKey(key)? (Map<String,Object>)mapValue.get(key) : new HashMap<String, Object>();
      if(!mapValue.containsKey(key))
        mapValue.put(key, jsonMap);
      fillParameterMap(parameter.substring(parameter.indexOf('.') + 1), value, jsonMap);
    }else{
      mapValue.put(parameter, value);
    }
  }
 
  @SuppressWarnings("unchecked")
  private void processPostBody(Map<String,Object> jsonMap,ServletRequest request){
    StringBuffer  buffer  = new StringBuffer();
    try{
      BufferedReader   reader  = new BufferedReader(new InputStreamReader(request.getInputStream()));
      String       line   = reader.readLine();
      while(line != null){
        buffer.append(line);
        line = reader.readLine();
      }
      reader.close();
    }catch(Throwable th){
      th.printStackTrace();
    }
    String content = buffer.toString().trim();
    if(content.startsWith("{")){
      // JSON
      JSONReader   reader = new JSONReader();
      Object     object = reader.read(content);
      if(object instanceof Map){
        jsonMap.putAll((Map<String, ? extends Object>) object);
      }
    } else if(content.startsWith("JOSN=")){
      JSONReader   reader = new JSONReader();
      Object     object = reader.read(content.substring(4));
      if(object instanceof Map){
        jsonMap.putAll((Map<String, ? extends Object>) object);
      }
    } else {
      // As parmeter
      String     charSet = Charset.defaultCharset().name();
      String[] nameValuePairs = content.split("&");
      for (String nameValuePair : nameValuePairs) {
        String[] namVal = nameValuePair.split("=");
        try{
        fillParameterMap(URLDecoder.decode(namVal[0],charSet),
            namVal.length > 1 ? URLDecoder.decode(namVal[1],charSet) : null, jsonMap);
        } catch (UnsupportedEncodingException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }

    }
  }
}


TOP

Related Classes of com.jaxws.json.codec.decode.FormDecoder

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.