All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.noear.solon.web.servlet.SolonServletContext Maven / Gradle / Ivy

There is a newer version: 3.0.0-M4
Show newest version
/*
 * Copyright 2017-2024 noear.org and 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
 *
 *      https://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 org.noear.solon.web.servlet;

import org.noear.solon.Utils;
import org.noear.solon.boot.ServerProps;
import org.noear.solon.boot.web.Constants;
import org.noear.solon.boot.web.WebContextBase;
import org.noear.solon.boot.web.RedirectUtils;
import org.noear.solon.core.NvMap;
import org.noear.solon.core.handle.ContextAsyncListener;
import org.noear.solon.core.handle.UploadedFile;
import org.noear.solon.core.util.IgnoreCaseMap;
import org.noear.solon.core.util.IoUtil;

import javax.servlet.AsyncContext;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.nio.charset.Charset;
import java.util.*;

/**
 * Servlet,适配为 Context
 *
 * @author noear
 * @since 1.2
 * */
public class SolonServletContext extends WebContextBase {
    private HttpServletRequest _request;
    private HttpServletResponse _response;

    protected boolean innerIsAsync() {
        return asyncContext != null;
    }

    public SolonServletContext(HttpServletRequest request, HttpServletResponse response) {
        _request = request;
        _response = response;
        _filesMap = new HashMap<>();

        if (sessionState().replaceable()) {
            sessionState = new SolonServletSessionState(request);
        }
    }

    private boolean _loadMultipartFormData = false;
    private void loadMultipartFormData() throws IOException, ServletException {
        if (_loadMultipartFormData) {
            return;
        } else {
            _loadMultipartFormData = true;
        }

        //文件上传需要
        if (isMultipartFormData()) {
            MultipartUtil.buildParamsAndFiles(this, _filesMap);
        }
    }

    @Override
    public Object pull(Class clz) {
        Object tmp = super.pull(clz);

        if (tmp == null) {
            if (clz.isInstance(_request.getSession())) {
                return _request.getSession();
            }
        }

        return tmp;
    }

    @Override
    public Object request() {
        return _request;
    }

    @Override
    public String remoteIp() {
        return _request.getRemoteAddr();
    }

    @Override
    public int remotePort() {
        return _request.getRemotePort();
    }

    @Override
    public String method() {
        return _request.getMethod();
    }

    @Override
    public String protocol() {
        return _request.getProtocol();
    }

    private URI _uri;

    @Override
    public URI uri() {
        if (_uri == null) {
            _uri = URI.create(url());
        }

        return _uri;
    }

    @Override
    public boolean isSecure() {
        return _request.isSecure();
    }

    private String _url;

    @Override
    public String url() {
        if (_url == null) {
            _url = _request.getRequestURL().toString();
        }

        return _url;
    }

    @Override
    public long contentLength() {
        return _request.getContentLengthLong();
    }

    @Override
    public String contentType() {
        return _request.getContentType();
    }


    @Override
    public String queryString() {
        return _request.getQueryString();
    }


    @Override
    public InputStream bodyAsStream() throws IOException {
        return _request.getInputStream();
    }


    private NvMap _paramMap;

    @Override
    public NvMap paramMap() {
        paramsMapInit();

        return _paramMap;
    }

    private Map> _paramsMap;

    @Override
    public Map> paramsMap() {
        paramsMapInit();

        return _paramsMap;
    }

    private Map> paramsMapInit() {
        if (_paramsMap == null) {
            _paramsMap = new LinkedHashMap<>();
            _paramMap = new NvMap();

            try {
                if (autoMultipart()) {
                    loadMultipartFormData();
                }

                for (Map.Entry kv : _request.getParameterMap().entrySet()) {
                    String name = ServerProps.urlDecode(kv.getKey());

                    _paramsMap.put(name, Utils.asList(kv.getValue()));
                    _paramMap.put(name, kv.getValue()[0]);
                }
            } catch (IOException | ServletException e) {
                throw new IllegalStateException(e);
            }
        }

        return _paramsMap;
    }

    @Override
    public Map> filesMap() throws IOException {
        if (isMultipartFormData()) {
            try {
                loadMultipartFormData();
            } catch (ServletException e) {
                throw new IOException(e);
            }

            return _filesMap;
        } else {
            return Collections.emptyMap();
        }
    }

    private NvMap _cookieMap;

    @Override
    public NvMap cookieMap() {
        if (_cookieMap == null) {
            _cookieMap = new NvMap();

            Cookie[] _cookies = _request.getCookies();

            if (_cookies != null) {
                for (Cookie c : _cookies) {
                    _cookieMap.put(c.getName(), c.getValue());
                }
            }
        }

        return _cookieMap;
    }

    @Override
    public NvMap headerMap() {
        if (_headerMap == null) {
            _headerMap = new NvMap();
            Enumeration headers = _request.getHeaderNames();

            while (headers.hasMoreElements()) {
                String key = headers.nextElement();
                String value = _request.getHeader(key);
                _headerMap.put(key, value);
            }
        }

        return _headerMap;
    }

    private NvMap _headerMap;


    @Override
    public Map> headersMap() {
        if (_headersMap == null) {
            _headersMap = new IgnoreCaseMap<>();

            Enumeration headers = _request.getHeaderNames();

            while (headers.hasMoreElements()) {
                String key = headers.nextElement();
                _headersMap.put(key, Collections.list(_request.getHeaders(key)));
            }
        }
        return _headersMap;
    }
    private Map> _headersMap;


    //====================================

    @Override
    public Object response() {
        return _response;
    }

    @Override
    public void charset(String charset) {
        _response.setCharacterEncoding(charset);
        this.charset = Charset.forName(charset);
    }

    @Override
    protected void contentTypeDoSet(String contentType) {
        _response.setContentType(contentType);
    }


    @Override
    public OutputStream outputStream() throws IOException {
        sendHeaders();

        return _response.getOutputStream();
    }

    @Override
    public void output(byte[] bytes) {
        try {
            OutputStream out = outputStream();

            out.write(bytes);
        } catch (Throwable ex) {
            throw new RuntimeException(ex);
        }
    }

    @Override
    public void output(InputStream stream) {
        try {
            OutputStream out = outputStream();

            IoUtil.transferTo(stream, out);
        } catch (Throwable ex) {
            throw new RuntimeException(ex);
        }
    }

    @Override
    public void headerSet(String key, String val) {
        _response.setHeader(key, val);
    }

    @Override
    public void headerAdd(String key, String val) {
        _response.addHeader(key, val);
    }


    @Override
    public String headerOfResponse(String name) {
        return _response.getHeader(name);
    }

    @Override
    public Collection headerValuesOfResponse(String name) {
        return _response.getHeaders(name);
    }

    @Override
    public Collection headerNamesOfResponse(){
        return _response.getHeaderNames();
    }


    @Override
    public void cookieSet(String key, String val, String domain, String path, int maxAge) {
        Cookie c = new Cookie(key, val);

        if (Utils.isNotEmpty(path)) {
            c.setPath(path);
        }

        if (maxAge >= 0) {
            c.setMaxAge(maxAge);
        }

        if (Utils.isNotEmpty(domain)) {
            c.setDomain(domain);
        }

        _response.addCookie(c);
    }

    @Override
    public void redirect(String url, int code) {
        url = RedirectUtils.getRedirectPath(url);

        headerSet(Constants.HEADER_LOCATION, url);
        statusDoSet(code);
    }

    @Override
    public int status() {
        return _response.getStatus();
    }

    @Override
    protected void statusDoSet(int status) {
        _response.setStatus(status);
    }

    AsyncContext asyncContext;

    @Override
    public boolean asyncSupported() {
        return true;
    }

    @Override
    public void asyncStart(long timeout, ContextAsyncListener listener) {
        if (asyncContext == null) {
            asyncContext = _request.startAsync();

            if (listener != null) {
                asyncContext.addListener(new AsyncListenerWrap(this, listener));
            }

            if (timeout != 0) {
                //内部默认30秒
                asyncContext.setTimeout(timeout);
            }
        }
    }

    @Override
    public void asyncComplete() throws IOException {
        if (asyncContext != null) {
            try {
                innerCommit();
            } finally {
                asyncContext.complete();
            }
        }
    }

    @Override
    public void flush() throws IOException {
        outputStream().flush();
    }

    @Override
    public void close() throws IOException {
        outputStream().close();
    }

    @Override
    protected void innerCommit() throws IOException {
        if (getHandled() || status() >= 200) {
            sendHeaders();
        } else {
            _response.setStatus(404);
        }
    }

    private boolean _headers_sent = false;

    private void sendHeaders() throws IOException {
        if (!_headers_sent) {
            _headers_sent = true;

            if (sessionState() != null) {
                sessionState().sessionPublish();
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy