org.deviceconnect.message.http.impl.factory.AbstractHttpMessageFactory.java Source code

Java tutorial

Introduction

Here is the source code for org.deviceconnect.message.http.impl.factory.AbstractHttpMessageFactory.java

Source

/*
 AbstractHttpMessageFactory.java
 Copyright (c) 2014 NTT DOCOMO,INC.
 Released under the MIT license
 http://opensource.org/licenses/mit-license.php
 */
package org.deviceconnect.message.http.impl.factory;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.SequenceInputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpMessage;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.message.BasicHeader;
import org.apache.http.protocol.HTTP;
import org.apache.james.mime4j.MimeException;
import org.apache.james.mime4j.descriptor.BodyDescriptor;
import org.apache.james.mime4j.message.SimpleContentHandler;
import org.apache.james.mime4j.parser.Field;
import org.apache.james.mime4j.parser.MimeEntityConfig;
import org.apache.james.mime4j.parser.MimeStreamParser;
import org.deviceconnect.message.DConnectMessage;
import org.deviceconnect.message.HttpHeaders;
import org.deviceconnect.message.basic.message.BasicDConnectMessage;
import org.deviceconnect.message.basic.message.DConnectRequestMessage;
import org.deviceconnect.message.basic.message.DConnectResponseMessage;
import org.deviceconnect.message.factory.MessageFactory;
import org.json.JSONException;

/**
 * HTTP.
 * @param <M> 
 * @author NTT DOCOMO, INC.
 */
public abstract class AbstractHttpMessageFactory<M extends HttpMessage> implements MessageFactory<M> {

    /**
     * ?.
     */
    private static final int BUFFER_SIZE = 1024;

    /**
     * .
     */
    private Logger mLogger = Logger.getLogger("org.deviceconnect.sdk");

    /**
     * HTTP 1???dConnect??.
     * @param message HTTP
     * @return dConnect
     */
    protected DConnectMessage parseFirstLine(final M message) {
        mLogger.entering(getClass().getName(), "parseFirstLine", message);
        DConnectMessage dmessage = null;

        if (message instanceof HttpRequest) {

            // put action
            String method = ((HttpRequest) message).getRequestLine().getMethod();
            mLogger.fine("HTTP request method: " + method);

            DConnectRequestMessage drequest = new DConnectRequestMessage();
            if (HttpGet.METHOD_NAME.equals(method)) {
                drequest.setMethod(DConnectRequestMessage.METHOD_GET);
            } else if (HttpPut.METHOD_NAME.equals(method)) {
                drequest.setMethod(DConnectRequestMessage.METHOD_PUT);
            } else if (HttpPost.METHOD_NAME.equals(method)) {
                drequest.setMethod(DConnectRequestMessage.METHOD_POST);
            } else if (HttpDelete.METHOD_NAME.equals(method)) {
                drequest.setMethod(DConnectRequestMessage.METHOD_DELETE);
            } else {
                throw new IllegalArgumentException("invalid http request mehtod: " + method);
            }

            dmessage = drequest;
        } else if (message instanceof HttpResponse) {
            dmessage = new DConnectResponseMessage();
        } else {
            throw new IllegalArgumentException(
                    "unkown http message class instance: " + message.getClass().getName());
        }

        mLogger.exiting(getClass().getName(), "parseFirstLine", dmessage);
        return dmessage;
    }

    /**
     * HTTP???dConnect???.
     * @param dmessage dConnect
     * @param message HTTP
     */
    protected void parseHttpHeader(final DConnectMessage dmessage, final M message) {
        mLogger.entering(getClass().getName(), "newDConnectMessage", new Object[] { dmessage, message });

        Header requestCode = message.getFirstHeader(HttpHeaders.X_REQUEST_CODE);
        if (requestCode != null) {
            try {
                dmessage.put(DConnectMessage.EXTRA_REQUEST_CODE, Integer.parseInt(requestCode.getValue()));
            } catch (NumberFormatException e) {
                mLogger.warning(HttpHeaders.X_REQUEST_CODE + " is not number: " + requestCode);
            }
        }

        mLogger.exiting(getClass().getName(), "newDConnectMessage");
    }

    /**
     * HTTP???dConnect???.
     * @param dmessage dConnect
     * @param message HTTP
     */
    protected void parseHttpBody(final DConnectMessage dmessage, final M message) {
        mLogger.entering(getClass().getName(), "newDConnectMessage", new Object[] { dmessage, message });

        HttpEntity entity = getHttpEntity(message);
        if (entity != null) {

            MimeStreamParser parser = new MimeStreamParser(new MimeEntityConfig());
            MultipartContentHandler handler = new MultipartContentHandler(dmessage);
            parser.setContentHandler(handler);

            StringBuilder headerBuffer = new StringBuilder();

            for (Header header : message.getAllHeaders()) {
                headerBuffer.append(header.getName());
                headerBuffer.append(": ");
                headerBuffer.append(header.getValue());
                headerBuffer.append(Character.toChars(HTTP.CR));
                headerBuffer.append(Character.toChars(HTTP.LF));
                mLogger.fine("header: " + header.getName() + ":" + header.getValue());
            }
            headerBuffer.append(Character.toChars(HTTP.CR));
            headerBuffer.append(Character.toChars(HTTP.LF));

            try {
                parser.parse(new SequenceInputStream(
                        new ByteArrayInputStream(headerBuffer.toString().getBytes("US-ASCII")),
                        entity.getContent()));
            } catch (IllegalStateException e) {
                mLogger.log(Level.FINE, e.toString(), e);
                mLogger.warning(e.toString());
            } catch (MimeException e) {
                mLogger.log(Level.FINE, e.toString(), e);
                mLogger.warning(e.toString());
            } catch (IOException e) {
                mLogger.log(Level.FINE, e.toString(), e);
                mLogger.warning(e.toString());
            }
        }

        mLogger.exiting(getClass().getName(), "newDConnectMessage");
    }

    /**
     * dConnect?HTTP??.
     * @param dmessage dConnec
     * @return HTTP
     */
    protected List<Header> createHttpHeader(final DConnectMessage dmessage) {
        mLogger.entering(getClass().getName(), "createHttpHeader", dmessage);
        List<Header> headers = new ArrayList<Header>();

        Object requestCode = dmessage.get(DConnectMessage.EXTRA_REQUEST_CODE);
        if (requestCode != null) {
            headers.add(new BasicHeader(HttpHeaders.X_REQUEST_CODE, requestCode.toString()));
        }

        mLogger.exiting(getClass().getName(), "createHttpHeader", headers);
        return headers;
    }

    /**
     * dConnect?HTTP??.
     * @param dmessage dConnect
     * @return HTTP
     */
    protected HttpEntity createHttpEntity(final DConnectMessage dmessage) {
        mLogger.entering(getClass().getName(), "createHttpEntity", dmessage);

        HttpEntity entity = null;
        try {
            DConnectMessage message = new BasicDConnectMessage(dmessage);
            message.remove(DConnectMessage.EXTRA_PROFILE);
            message.remove(DConnectMessage.EXTRA_INTERFACE);
            message.remove(DConnectMessage.EXTRA_ATTRIBUTE);
            message.remove(DConnectMessage.EXTRA_METHOD);

            entity = new ByteArrayEntity(message.toString(2).getBytes(HTTP.UTF_8));
        } catch (UnsupportedEncodingException e) {
            mLogger.log(Level.FINE, e.toString(), e);
            mLogger.warning(e.toString());
        }

        mLogger.exiting(getClass().getName(), "createHttpEntity", entity);
        return entity;
    }

    /**
     * HTTP??.
     * HTTP?HTTP???????? null ?
     * @param message HTTP
     * @return HTTP
     */
    private HttpEntity getHttpEntity(final M message) {
        mLogger.entering(getClass().getName(), "getHttpEntity", message);
        HttpEntity entity = null;

        if (message instanceof HttpEntityEnclosingRequest) {
            entity = ((HttpEntityEnclosingRequest) message).getEntity();
        } else if (message instanceof HttpResponse) {
            entity = ((HttpResponse) message).getEntity();
        }

        mLogger.exiting(getClass().getName(), "getHttpEntity", entity);
        return entity;
    }

    /**
     * ?byte??.
     * @param is 
     * @return byte?
     * @throws IOException I/O????
     */
    private byte[] loadBytes(final InputStream is) throws IOException {
        mLogger.entering(this.getClass().getName(), "loadBytes");

        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        byte[] buf = new byte[BUFFER_SIZE];
        while (true) {
            int len = is.read(buf);
            if (len < 0) {
                break;
            }
            bout.write(buf, 0, len);
        }
        byte[] bytes = bout.toByteArray();

        mLogger.exiting(this.getClass().getName(), "loadBytes", bytes);
        return bytes;
    }

    /**
     * ??.
     */
    private class MultipartContentHandler extends SimpleContentHandler {

        /**
         * .
         */
        private DConnectMessage mMessage;

        /** 
         * name.
         */
        private String mName;

        /** 
         * ???.
         */
        private boolean mFileFlg;

        /** 
         * ???.
         */
        private boolean mMultipartFlg;

        /** 
         * ????????.
         * ????????
         */
        private boolean mBodyPartFlg;

        /**
         * .
         * @param dmessage dConnect
         */
        public MultipartContentHandler(final DConnectMessage dmessage) {
            mMessage = dmessage;
        }

        @Override
        public void startMultipart(final BodyDescriptor bd) throws MimeException {
            super.startMultipart(bd);
            mMultipartFlg = true;
        }

        @Override
        public void endMultipart() throws MimeException {
            super.endMultipart();
            mMultipartFlg = false;
        }

        @Override
        public void startBodyPart() throws MimeException {
            super.startBodyPart();
            mBodyPartFlg = true;
        }

        @Override
        public void endBodyPart() throws MimeException {
            super.endBodyPart();
            mBodyPartFlg = false;
        }

        @Override
        public void headers(final org.apache.james.mime4j.message.Header header) {

            if (mMultipartFlg && mBodyPartFlg) {
                for (Field field : header.getFields()) {
                    if (field.getName().equalsIgnoreCase("Content-Disposition")) {

                        String body = field.getBody();
                        String[] attrs = body.split(";");
                        for (String attr : attrs) {
                            if (attr.contains("filename")) {
                                mFileFlg = true;
                            } else if (attr.contains("name")) {
                                String[] values = attr.split("=");
                                if (values.length == 2) {
                                    mName = values[1].replaceAll("\"", "");
                                }
                            }

                        }
                    }
                    mLogger.fine("header: " + field.getName() + ":" + field.getBody());
                }
            }
        }

        @Override
        public void bodyDecoded(final BodyDescriptor bd, final InputStream is) throws IOException {
            mLogger.entering(getClass().getName(), "bodyDecoded", new Object[] { bd, is });

            byte[] bytes = loadBytes(is);

            if (mMultipartFlg && mName != null) {
                if (mFileFlg) {
                    mMessage.put(mName, bytes);
                } else if (bd.getMimeType().equals("text/plain")) {
                    mMessage.put(mName, new String(bytes, HTTP.UTF_8));
                }
            } else if (!mMultipartFlg) {
                if (bd.getMimeType().equals("application/json")) {
                    if (bytes.length > 0) {
                        String body = new String(bytes, HTTP.UTF_8);
                        mLogger.fine("response body: " + body);

                        try {
                            mMessage.putAll(new DConnectResponseMessage(body));
                        } catch (JSONException e) {
                            mLogger.warning(e.toString());
                        }
                    }
                } else if (bd.getMimeType().equals("text/plain")) {
                    String body = new String(bytes, HTTP.UTF_8);
                    // ?
                    String[] parameters = body.split("&");
                    if (parameters.length > 0) {
                        for (String param : parameters) {
                            setKeyValue(param);
                        }
                    } else {
                        setKeyValue(body);
                    }
                }
            }

            mName = null;
            mFileFlg = false;
            mLogger.exiting(getClass().getName(), "bodyDecoded");
        }

        /**
         * ??????????.
         * 
         * @param param 
         */
        private void setKeyValue(final String param) {
            String[] entry = param.split("=");
            if (entry.length != 2) {
                return;
            }

            mMessage.put(entry[0], entry[1]);
        }

    }

}