firebats.http.server.exts.form.Form.java Source code

Java tutorial

Introduction

Here is the source code for firebats.http.server.exts.form.Form.java

Source

/*
 * Copyright 2013 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package firebats.http.server.exts.form;

import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.http.DefaultHttpContent;
import io.netty.handler.codec.http.DefaultHttpRequest;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.LastHttpContent;
import io.netty.handler.codec.http.multipart.Attribute;
import io.netty.handler.codec.http.multipart.FileUpload;
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder;
import io.netty.handler.codec.http.multipart.InterfaceHttpData;
import io.reactivex.netty.protocol.http.server.HttpServerRequest;

import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import play.data.validation.ValidationError;
import rx.functions.Action0;

import com.google.common.base.Throwables;
import com.google.common.collect.Maps;

import firebats.check.Check;
import firebats.http.server.Context;

/**
 * http?Content-TypeContent-Type??MediaTypehttp request?MediaType?
 * <ul>
 * <li>application/x-www-form-urlencoded</li>
 * <li>multipart/form-data</li>
 * <li>application/json</li>
 * <li>text/xml</li>
 * </ul>
 * 
 * application/x-www-form-urlencodedmultipart/form-data??Form(Play
 * |Ratpack) Form3???
 * <ul>
 * <li>uriqueryString</li>
 * <li>x-www-form-urlencodedmultipart/form-data</li>
 * <li></li>
 * </ul>
 * Form
 * <table border="1">
 * <tr>
 * <th>?</th>
 * <th></th>
 * <th>???</th>
 * <th></th>
 * </tr>
 * <tr>
 * <td>query</td><td> {@link #getQuery} {@link #getQuery(String name)}</td><td>uri queryString(??uri??)</td><td>String</td>
 * </tr>
 * <tr>
 * <td>form</td><td> {@link #getForm} {@link #getForm(String name)}</td><td>x-www-form-urlencodedmultipart/form-data</td><td>String</td>
 * </tr>
 * <td>attr</td><td> {@link #getAttrs} {@link #getAttr(String name)}</td><td>query + form</td><td>String</td>
 * </tr>
 * <tr>
 * <td>file</td><td> {@link #getFiles} {@link #getFile(String name)}</td><td></td><td>{@link UploadedFile}</td>
 * </tr>
 * </table>
 */
public class Form {
    private static Logger log = LoggerFactory.getLogger(Form.class);

    private final Map<String, String> formParams;
    private final Map<String, UploadedFile> fileParams;
    private Map<String, String> queryParams;
    private Map<String, String> formAndQuery;

    private Form(Map<String, String> queryParams, Map<String, String> formParams, Map<String, UploadedFile> files) {
        this.queryParams = Collections.unmodifiableMap(queryParams);
        this.formParams = Collections.unmodifiableMap(formParams);
        this.fileParams = Collections.unmodifiableMap(files);
        formAndQuery = Maps.newLinkedHashMap();
        formAndQuery.putAll(queryParams);
        formAndQuery.putAll(formParams);
        formAndQuery = Collections.unmodifiableMap(formAndQuery);
    }

    public static Form decode(Context context, ByteBuf content) {
        return content != null && content.isReadable() ? Form.decodeWithContent(context, content)
                : Form.decodeWithoutContent(context);
    }

    public static Form fromQuery(Map<String, String> queryParams) {
        return new Form(queryParams, Collections.<String, String>emptyMap(),
                Collections.<String, UploadedFile>emptyMap());
    }

    public static Form fromAll(Map<String, String> queryParams, Map<String, String> formAndQuery,
            Map<String, UploadedFile> fileParams) {
        return new Form(queryParams, formAndQuery, fileParams);
    }

    /**
     * @return copy new HttpForm with formParams
     **/
    public Form withForm(Map<String, String> formParams) {
        return new Form(queryParams, formParams, fileParams);
    }

    /**
     * @return copy new HttpForm with filesParams
     **/
    public Form withFiles(Map<String, UploadedFile> filesParams) {
        return new Form(queryParams, formParams, filesParams);
    }

    /**?*/
    public UploadedFile getFile(String key) {
        return getFiles().get(key);
    }

    /**getForm()+getQuery()
     *
     * QueryParameters | application/x-www-form-urlencoded | multipart/form-data ??</br>
     * ???getFrom()
     * <pre>
     * String email = requestContext.get("email");
     * _VerificationCodeApiBus.SendCodeToEmail cmd=new _VerificationCodeApiBus.SendCodeToEmail();
     * cmd.email=email;
     * bus.request(cmd);
     * </pre>
     */
    public String getAttr(String key) {
        return getAttrs().get(key);
    }

    public boolean contains(String key) {
        return getAttrs().containsKey(key) || getFiles().containsKey(key);
    }

    public boolean containsAttr(String key) {
        return getAttrs().containsKey(key);
    }

    public boolean containsFile(String key) {
        return fileParams.containsKey(key);
    }

    /**uri?*/
    public Map<String, String> getQuery() {
        return queryParams;
    }

    /**getForm()+getQuery()*/
    public Map<String, String> getAttrs() {
        return formAndQuery;
    }

    /**?*/
    public Map<String, UploadedFile> getFiles() {
        return fileParams;
    }

    /**form???post?,??uri?*/
    public Map<String, String> getForm() {
        return formParams;
    }

    /**attrs + files*/
    public Map<String, Object> getAll() {
        LinkedHashMap<String, Object> result = Maps.<String, Object>newLinkedHashMap(fileParams);
        result.putAll(getAttrs());
        return result;
    }

    public <T> T as(Class<T> clazz) {
        play.data.Form<T> result = play.data.Form.form(clazz).bind(formAndQuery);
        if (result.hasErrors()) {
            //TODO ERROR ?
            Entry<String, List<ValidationError>> x = result.errors().entrySet().iterator().next();
            Check.GeneralFail.check(!result.hasErrors(), p -> {
                p.info = clazz.getName() + ":" + x.getValue();
            });
        }
        return result.get();
    }

    @Override
    public String toString() {
        return "" + queryParams + formParams + fileParams;
    }

    public static Map<String, String> toFlatQueryParams(Map<String, List<String>> queryParameters) {
        Map<String, String> result = new LinkedHashMap<>();
        for (String key : queryParameters.keySet()) {
            Collection<String> values = queryParameters.get(key);
            if (!values.isEmpty()) {
                result.put(key, values.iterator().next());
            }
        }
        return result;
    }

    private static Form decodeWithContent(Context context, ByteBuf content) {
        //new DefaultHttpDataFactory(/*useDisk*/true)decoder?
        //Mix?16K???
        //       final HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(new DefaultHttpDataFactory(/*useDisk*/true),toNettyHttpRequest(context.request));
        HttpServerRequest<ByteBuf> rxRequest = context.getRequest();
        HttpRequest nettyRequest = new DefaultHttpRequest(HttpVersion.HTTP_1_1, rxRequest.getHttpMethod(),
                rxRequest.getUri());
        for (Map.Entry<String, String> header : rxRequest.getHeaders().entries()) {
            nettyRequest.headers().add(header.getKey(), header.getValue());
        }
        final HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(nettyRequest);
        HttpContent httpContent = new DefaultHttpContent(content);
        decoder.offer(httpContent);
        decoder.offer(LastHttpContent.EMPTY_LAST_CONTENT);

        Map<String, String> formParams = new LinkedHashMap<>();
        Map<String, UploadedFile> files = new LinkedHashMap<>();
        try {
            while (decoder.hasNext()) {
                InterfaceHttpData data = decoder.next();
                if (data.getHttpDataType().equals(InterfaceHttpData.HttpDataType.Attribute)) {
                    try {
                        Attribute attr = (Attribute) data;
                        if (!formParams.containsKey(data.getName())) {
                            formParams.put(attr.getName(), attr.getValue());
                        }
                    } catch (IOException e) {
                        Throwables.propagate(e);
                    } finally {
                        //?
                        data.release();
                    }
                } else if (data.getHttpDataType().equals(InterfaceHttpData.HttpDataType.FileUpload)) {
                    try {
                        if (!files.containsKey(data.getName())) {
                            final FileUpload nettyFileUpload = (FileUpload) data;
                            final ByteBuf byteBuf = nettyFileUpload.content();
                            byteBuf.retain();
                            context.onComplete(new Action0() {
                                @Override
                                public void call() {
                                    if (log.isDebugEnabled()) {
                                        log.debug("form upload file release[" + data.getName() + ":"
                                                + nettyFileUpload.getFilename() + "]");
                                    }
                                    byteBuf.release();
                                }
                            });
                            UploadedFile fileUpload = new UploadedFile(nettyFileUpload.getFilename(),
                                    nettyFileUpload.getContentType(), byteBuf);
                            files.put(data.getName(), fileUpload);
                        }
                    } finally {
                        data.release();
                    }
                }
            }
        } catch (HttpPostRequestDecoder.EndOfDataDecoderException ignore) {
            // ignore
        } finally {
            decoder.destroy();
        }
        Map<String, String> query = Form.toFlatQueryParams(context.getRequest().getQueryParameters());
        return fromAll(query, formParams, files);
    }

    private static Form decodeWithoutContent(Context context) {
        return fromQuery(Form.toFlatQueryParams(context.getRequest().getQueryParameters()));
    }
}