org.tinygroup.weblayer.webcontext.parser.valueparser.impl.ParameterParserImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.tinygroup.weblayer.webcontext.parser.valueparser.impl.ParameterParserImpl.java

Source

/**
 *  Copyright (c) 1997-2013, www.tinygroup.org (luo_guo@icloud.com).
 *
 *  Licensed under the GPL, Version 3.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.gnu.org/licenses/gpl.html
 *
 *  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 org.tinygroup.weblayer.webcontext.parser.valueparser.impl;

import org.apache.commons.fileupload.FileItem;
import org.tinygroup.commons.tools.StringEscapeUtil;
import org.tinygroup.commons.tools.StringUtil;
import org.tinygroup.vfs.FileObject;
import org.tinygroup.weblayer.webcontext.parser.ParserWebContext;
import org.tinygroup.weblayer.webcontext.parser.exception.UploadException;
import org.tinygroup.weblayer.webcontext.parser.exception.UploadSizeLimitExceededException;
import org.tinygroup.weblayer.webcontext.parser.fileupload.TinyFileItem;
import org.tinygroup.weblayer.webcontext.parser.fileupload.TinyItemFileObject;
import org.tinygroup.weblayer.webcontext.parser.impl.*;
import org.tinygroup.weblayer.webcontext.parser.upload.*;
import org.tinygroup.weblayer.webcontext.parser.valueparser.AbstractValueParser;
import org.tinygroup.weblayer.webcontext.parser.valueparser.ParameterParser;
import org.tinygroup.weblayer.webcontext.parser.valueparser.ValueList;
import org.tinygroup.weblayer.webcontext.util.QueryStringParser;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static org.tinygroup.commons.tools.ArrayUtil.isEmptyArray;
import static org.tinygroup.commons.tools.BasicConstant.EMPTY_STRING;
import static org.tinygroup.commons.tools.CollectionUtil.createLinkedList;
import static org.tinygroup.commons.tools.StringUtil.trimToEmpty;
import static org.tinygroup.weblayer.webcontext.parser.ParserWebContext.DEFAULT_CHARSET_ENCODING;

/**
 * ??HTTPGETPOST??<code>ParameterParser</code>
 * 
 * @author renhui
 */
public class ParameterParserImpl extends AbstractValueParser implements ParameterParser {
    private final UploadService upload;
    private final boolean trimming;
    private boolean uploadProcessed;
    private final ParameterParserFilter[] filters;
    private final String htmlFieldSuffix;
    private List<FileItem> fileItems = new ArrayList<FileItem>();

    /** requestparametersmultipart-form? */
    public ParameterParserImpl(ParserWebContext webContext, UploadService upload, boolean trimming,
            ParameterParserFilter[] filters, String htmlFieldSuffix) {
        super(webContext);

        this.upload = upload;
        this.trimming = trimming;
        this.filters = filters;
        this.htmlFieldSuffix = htmlFieldSuffix;

        HttpServletRequestWrapper wrapper = (HttpServletRequestWrapper) webContext.getRequest();
        HttpServletRequest wrappedRequest = (HttpServletRequest) wrapper.getRequest();
        boolean isMultipart = false;

        // upload
        if (webContext.isAutoUpload() && upload != null) {
            // multipart/*upload service??
            isMultipart = upload.isMultipartContent(wrappedRequest);

            if (isMultipart) {
                try {
                    parseUpload();
                } catch (UploadSizeLimitExceededException e) {
                    add(ParserWebContext.UPLOAD_FAILED, Boolean.TRUE);
                    add(ParserWebContext.UPLOAD_SIZE_LIMIT_EXCEEDED, Boolean.TRUE);
                    logger.errorMessage("File upload exceeds the size limit", e);
                    throw e;
                } catch (UploadException e) {
                    add(ParserWebContext.UPLOAD_FAILED, Boolean.TRUE);
                    logger.errorMessage("Upload failed", e);
                    throw e;
                }
            }
        }

        // request??
        if (!isMultipart) {
            String method = wrappedRequest.getMethod();

            // URL?US-ASCII?URL?
            // ?????
            //
            // ?
            // 1. ????????
            // GBK?????GBK?methodGETPOST
            //
            // 2. ???URL?????
            // Windowsiefirefox?GBK
            // macsafarifirefox?UTF-8
            //
            // ??
            // 1. Tomcatserver.xml<Connector
            // URIEncoding="xxx">??GET?8859_1
            // 2. JettyUTF-8??GET?
            // 3.
            // POSTrequest.setCharacterEncoding("xxx")?8859_1
            // 4. Tomcat5?<Connector
            // useBodyEncodingForURI="true">GETrequest.setCharacterEncoding("xxx")?
            //
            // ???Tomcat/Jetty8859_1UTF-8??URL query?
            //
            // ????POST/PUTGET???servlet
            // engine?
            // ?useServletEngineParser=true
            if (webContext.isUseServletEngineParser() || "post".equalsIgnoreCase(method)
                    || "put".equalsIgnoreCase(method)) {
                parseByServletEngine(wrappedRequest);
            } else {
                parseQueryString(webContext, wrappedRequest);
            }

            postProcessParams();
        }
    }

    /** servlet engine??? */
    private void parseByServletEngine(HttpServletRequest wrappedRequest) {
        @SuppressWarnings("unchecked")
        Map<String, String[]> parameters = wrappedRequest.getParameterMap();

        if (parameters != null && parameters.size() > 0) {
            for (Map.Entry<String, String[]> entry : parameters.entrySet()) {
                String key = entry.getKey();
                String[] values = entry.getValue();

                for (String value : values) {
                    add(key, value);
                }
            }
        }
    }

    /** ?query string */
    private void parseQueryString(ParserWebContext requestContext, HttpServletRequest wrappedRequest) {
        // useBodyEncodingForURI=truerequest.setCharacterEncoding()???URIEncodingUTF-8
        // useBodyEncodingForURItrue
        // tomcat?tomcat8859_1
        String charset = requestContext.isUseBodyEncodingForURI() ? wrappedRequest.getCharacterEncoding()
                : requestContext.getURIEncoding();

        QueryStringParser parser = new QueryStringParser(charset, DEFAULT_CHARSET_ENCODING) {

            protected void add(String key, String value) {
                ParameterParserImpl.this.add(key, value);
            }
        };

        parser.parse(wrappedRequest.getQueryString());
    }

    /**
     * ??
     * <p>
     * ???.~htmlHTML???
     * </p>
     */
    private void postProcessParams() {
        HttpServletRequestWrapper wrapper = (HttpServletRequestWrapper) webContext.getRequest();
        HttpServletRequest wrappedRequest = (HttpServletRequest) wrapper.getRequest();
        boolean[] filtering = null;

        if (!isEmptyArray(filters)) {
            filtering = new boolean[filters.length];

            for (int i = 0; i < filters.length; i++) {
                filtering[i] = filters[i].isFiltering(wrappedRequest);
            }
        }

        String[] keys = getKeys();
        List<String> keysToRemove = createLinkedList();

        for (String key : keys) {
            if (key.endsWith(htmlFieldSuffix)) {
                keysToRemove.add(key);
                key = key.substring(0, key.length() - htmlFieldSuffix.length());

                if (!containsKey(key)) {
                    setObjects(key, processValues(key, true, filtering));
                }

                continue;
            }

            boolean isHtml = !StringUtil.isBlank(getString(key + htmlFieldSuffix));
            setObjects(key, processValues(key, isHtml, filtering));
        }

        for (String key : keysToRemove) {
            remove(key);
        }
    }

    private Object[] processValues(String key, boolean isHtmlField, boolean[] filtering) {
        Object[] values = getObjects(key);
        List<Object> paramValues = new ArrayList<Object>();
        for (int i = 0; i < values.length; i++) {
            Object value = values[i];
            if (value instanceof ItemFileObject) {
                FileItem fileItem = ((ItemFileObject) value).getFileItem();
                if (fileItem.isFormField()) {//???String
                    value = fileItem.toString();
                }
            }
            //??
            if (value instanceof String) {
                stringValueFilter(key, isHtmlField, filtering, value, paramValues);
            } else if (value instanceof ItemFileObject) {
                fileItemFilter(key, filtering, value, paramValues);
            }

        }
        if (paramValues.size() > 0) {
            if (paramValues.size() == 1) {
                webContext.put(key, paramValues.get(0));
            } else {
                webContext.put(key, paramValues.toArray());
            }
        }
        return paramValues.toArray();
    }

    private void fileItemFilter(String key, boolean[] filtering, Object value, List<Object> paramValues) {
        FileItem fileItem = ((ItemFileObject) value).getFileItem();
        FileItem processFileItem = fileItem;
        // 
        if (filtering != null) {
            for (int j = 0; j < filters.length; j++) {
                ParameterParserFilter filter = filters[j];

                if (filter instanceof UploadedFileFilter && filtering[j]) {
                    processFileItem = ((UploadedFileFilter) filter).filter(key, processFileItem);
                }
            }
        }
        if (processFileItem == null) {
            remove(key, value);//?fileitem
            fileItems.remove(fileItem);
            fileItem.delete();
        } else {
            fileItem = processFileItem;
            if (!fileItem.isFormField() && fileItem.getContentType() != null) {//
                paramValues.add(value);
            }
        }
    }

    private void stringValueFilter(String key, boolean isHtmlField, boolean[] filtering, Object value,
            List<Object> paramValues) {
        Object processValue = value;
        // ?HTML&#12345;??unicode
        if (!isHtmlField && webContext.isUnescapeParameters()) {
            processValue = StringEscapeUtil.unescapeEntities(null, (String) value);
        }

        // 
        if (filtering != null) {
            for (int j = 0; j < filters.length; j++) {
                ParameterParserFilter filter = filters[j];

                if (filter instanceof ParameterValueFilter && filtering[j]) {
                    processValue = ((ParameterValueFilter) filter).filter(key, (String) processValue, isHtmlField);
                }
                if (filter instanceof ParamValueFilter && filtering[j]
                        && ((ParamValueFilter) filter).isFilter(key)) {
                    processValue = ((ParamValueFilter) filter).valueFilter((String) processValue, webContext);
                }
            }
        }
        paramValues.add(processValue);
    }

    /**
     * ???<code>FileItem</code>?<code>null</code>
     * 
     * @param key
     *            ???
     * @return <code>FileItem</code>
     */
    public FileObject getFileObject(String key) {
        ValueList container = getValueList(key, false);

        return container == null ? null : container.getFileObject();
    }

    /**
     * ???<code>FileItem</code>?<code>null</code>
     * 
     * @param key
     *            ???
     * @return <code>FileItem</code>
     */
    public FileObject[] getFileObjects(String key) {
        ValueList container = getValueList(key, false);

        return container == null ? new FileObject[0] : container.getFileObjects();
    }

    /**
     * <code>FileItem</code>
     * 
     * @param key
     *            ???
     * @param value
     *            ?
     */
    public void add(String key, FileItem value) {
        if (value.isFormField()) {
            add(key, value.getString());
        } else {
            // 
            if (!StringUtil.isEmpty(value.getName()) || value.getSize() > 0) {
                add(key, (Object) value);
            }
        }
    }

    /**
     * ???/?
     * 
     * @param key
     *            ???
     * @param value
     *            ?
     */

    public void add(String key, Object value) {
        if (value == null) {
            value = EMPTY_STRING;
        }

        if (trimming && value instanceof String) {
            value = trimToEmpty((String) value);
        }

        getValueList(key, true).addValue(value);
    }

    /**
     * ??<a href="http://www.ietf.org/rfc/rfc1867.txt">RFC 1867</a>
     * <code>multipart/form-data</code>HTTP
     * <p>
     * ?<code>UploadService.automatic</code>???<code>false</code>
     * service?actionservlet
     * </p>
     * 
     * @throws UploadException
     *             ?
     */
    public void parseUpload() throws UploadException {
        parseUpload(null);
    }

    /**
     * ??<a href="http://www.ietf.org/rfc/rfc1867.txt">RFC 1867</a>
     * <code>multipart/form-data</code>HTTP
     * <p>
     * ?<code>UploadService.automatic</code>???<code>false</code>
     * service?actionservlet
     * </p>
     * 
     * @param sizeThreshold
     *            ???0
     * @param sizeMax
     *            HTTP
     * @param repositoryPath
     *            ?
     * @throws UploadException
     *             ?
     */
    public void parseUpload(UploadParameters params) throws UploadException {
        if (uploadProcessed || upload == null) {
            return;
        }

        FileItem[] items = upload.parseRequest(webContext.getRequest(), params);

        for (FileItem item : items) {
            FileObject fileObject = null;
            if (item instanceof InMemoryFormFieldItem) {
                fileObject = new FileObjectInMemory((InMemoryFormFieldItem) item);
            } else if (item instanceof DiskFileItem) {
                fileObject = new FileObjectInDisk((DiskFileItem) item);
            } else if (item instanceof TinyFileItem) {
                fileObject = new TinyItemFileObject((TinyFileItem) item);
            }
            add(item.getFieldName(), fileObject);
            fileItems.add(item);
        }

        uploadProcessed = true;

        postProcessParams();
    }

    /**
     * ??????????<code>ParameterParser</code>
     * ?<code>request.getCharacterEncoding()</code>
     * <p>
     * <code>ISO-8859-1</code>
     * </p>
     * 
     * @return ?
     */

    protected String getCharacterEncoding() {
        String charset = webContext.getRequest().getCharacterEncoding();

        return charset == null ? ParserWebContext.DEFAULT_CHARSET_ENCODING : charset;
    }

    /**
     * parameters??query string
     * 
     * @return query string?<code>null</code>
     */
    public String toQueryString() {
        QueryStringParser parser = new QueryStringParser();

        for (Object element : keySet()) {
            String key = (String) element;
            Object[] values = getObjects(key);

            if (isEmptyArray(values)) {
                continue;
            }

            for (Object valueObject : values) {
                if (valueObject == null || valueObject instanceof String) {
                    parser.append(key, (String) valueObject);
                }
            }
        }

        return parser.toQueryString();
    }

    public FileItem[] getFileItems() {
        if (fileItems.isEmpty()) {
            return new FileItem[0];
        }
        return fileItems.toArray(new FileItem[0]);
    }
}