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

org.tinystruct.handler.DefaultHandler Maven / Gradle / Ivy

Go to download

A simple framework for Java development. Simple is hard, Complex is easy. Better thinking, better design.

There is a newer version: 1.4.4
Show newest version
/*******************************************************************************
 * Copyright  (c) 2013, 2023 James Mover Zhou
 *
 * 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 org.tinystruct.handler;

import jakarta.servlet.*;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.tinystruct.ApplicationContext;
import org.tinystruct.ApplicationException;
import org.tinystruct.application.Context;
import org.tinystruct.http.*;
import org.tinystruct.http.servlet.RequestBuilder;
import org.tinystruct.http.servlet.ResponseBuilder;
import org.tinystruct.system.*;
import org.tinystruct.system.util.StringUtilities;

import java.io.*;
import java.nio.charset.Charset;
import java.util.logging.Level;
import java.util.logging.Logger;

import static org.tinystruct.Application.LANGUAGE;
import static org.tinystruct.Application.METHOD;
import static org.tinystruct.http.Constants.*;

/**
 * DefaultHandler is responsible for handling HTTP requests and managing the application's lifecycle.
 */
public class DefaultHandler extends HttpServlet implements Bootstrap, Filter {
    private static final Logger logger = Logger.getLogger(DefaultHandler.class.getName());
    private static final long serialVersionUID = 0;
    private String charsetName;
    private Configuration settings;
    private String path;

    @Override
    public void init(ServletConfig config) {
        this.path = config.getServletContext().getRealPath("");
        try {
            this.start();
        } catch (ApplicationException e) {
            logger.severe(e.getMessage());
        }

        logger.info("Initialized servlet config and starting...");
    }

    @Override
    public void init(FilterConfig config) throws ServletException {
        this.path = config.getServletContext().getRealPath("");
        try {
            this.start();
        } catch (ApplicationException e) {
            logger.severe(e.getMessage());
        }

        logger.info("Initialized filter config and starting...");
    }

    @Override
    public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
        request.setCharacterEncoding(charsetName);
        response.setContentType("text/html;charset=" + charsetName);
        response.setCharacterEncoding(charsetName);
        response.setHeader("Pragma", "No-cache");
        response.setHeader("Cache-Control", "No-cache");
        response.setDateHeader("Expires", 0);

        final Context context = new ApplicationContext();
        Request _request = new RequestBuilder(request, isSSL());
        Response _response = new ResponseBuilder(response);
        try {
            context.setId(_request.getSession().getId());
            context.setAttribute(HTTP_REQUEST, _request);
            context.setAttribute(HTTP_RESPONSE, _response);
            context.setAttribute(HTTP_SCHEME, request.getScheme());
            context.setAttribute(HTTP_SERVER, request.getServerName());
            context.setAttribute(HTTP_PROTOCOL, getProtocol(request));

            String lang = _request.getParameter("lang"), language = "";
            if (lang != null && !lang.trim().isEmpty()) {
                String name = lang.replace('-', '_');

                if (Language.support(name) && !lang.equalsIgnoreCase(this.settings.get("language"))) {
                    String[] local = name.split("_");
                    context.setAttribute(LANGUAGE, name);
                    language = "lang=" + local[0] + "-" + local[1].toUpperCase() + "&";
                }
            }

            String url_prefix = "/";
            if (this.settings.get("default.url_rewrite") != null && !"enabled".equalsIgnoreCase(this.settings.get("default.url_rewrite"))) {
                url_prefix = "/?" + language + "q=";
            }

            context.setAttribute(HTTP_HOST, getHost(request) + url_prefix);
            context.setAttribute(METHOD, request.getMethod());

            String query = _request.getParameter("q");
            if (query != null) {
                handleRequest(query, context, _response);
            } else {
                handleDefaultPage(context, _response);
            }
        } catch (ApplicationException e) {
            try {
                handleApplicationException(_request, _response, e);
            } catch (ApplicationException ex) {
                logger.log(Level.SEVERE, ex.getMessage(), ex);
            }
        }
    }

    /**
     * Handles the HTTP request by processing the query.
     *
     * @param query     The query string
     * @param context   The application context
     * @param response The HTTP response object
     * @throws IOException if an I/O error occurs
     */
    private void handleRequest(String query, Context context, Response response) throws IOException, ApplicationException {
        // Handle request
        query = StringUtilities.htmlSpecialChars(query);
        Object message = ApplicationManager.call(query, context);
        if (message != null) {
            if (message instanceof byte[]) {
                byte[] bytes = (byte[]) message;
                response.addHeader(Header.CONTENT_LENGTH.name(), String.valueOf(bytes.length));
                response.get().write(bytes);
            } else {
                try (BufferedWriter bufferedWriter = getWriter(response.get())) {
                    bufferedWriter.write(String.valueOf(message));
                }
            }
        } else {
            try (BufferedWriter bufferedWriter = getWriter(response.get())) {
                bufferedWriter.write("No response retrieved!");
            }
        }
    }

    /**
     * Handles the default page request.
     *
     * @param context   The application context
     * @param response The HTTP response object
     * @throws IOException if an I/O error occurs
     */
    private void handleDefaultPage(Context context, Response response) throws IOException, ApplicationException {
        try (BufferedWriter bufferedWriter = getWriter(response.get())) {
            bufferedWriter.write(String.valueOf(ApplicationManager.call(settings.getOrDefault("default.home.page", "say/Praise to the Lord."), context)));
        }
    }

    /**
     * Handles application exceptions.
     *
     * @param request  The HTTP servlet request
     * @param response The HTTP servlet response
     * @param e        The application exception
     */
    private void handleApplicationException(Request request, Response response, ApplicationException e) throws ApplicationException {
        response.setStatus(ResponseStatus.valueOf(e.getStatus()));
        Session session = request.getSession();
        session.setAttribute("error", e);
        if (!Boolean.parseBoolean(settings.get("default.error.process"))) {
            String defaultErrorPage = settings.get("default.error.page");
            Reforward forward = new Reforward(request, response);
            forward.setDefault(defaultErrorPage.trim().isEmpty() ? "/?q=error" : "/?q=" + defaultErrorPage);
            forward.forward();
        }
    }

    @Override
    public void start() throws ApplicationException {
        settings = new Settings();
        charsetName = settings.getOrDefault("default.file.encoding", Charset.defaultCharset().name());
        settings.set("language", "zh_CN");
        settings.setIfAbsent("system.directory", path);
    }

    private boolean isSSL() {
        String sslEnabled = settings.get("ssl.enabled");
        return Boolean.parseBoolean(sslEnabled);
    }

    private String getProtocol(HttpServletRequest request) {
        return isSSL() ? "https://" : "http://";
    }

    private String getHost(HttpServletRequest request) {
        int serverPort = request.getServerPort();
        String defaultHostName = request.getServerName();
        String protocol = getProtocol(request);

        if (serverPort == 80) {
            return protocol + defaultHostName;
        } else {
            return protocol + defaultHostName + ":" + serverPort;
        }
    }

    /**
     * Use BufferedWriter for top efficiency.
     *
     * @param out OutputStream
     * @return BufferedWriter
     */
    private BufferedWriter getWriter(OutputStream out) {
        return new BufferedWriter(new OutputStreamWriter(out, Charset.forName(charsetName)));
    }

    @Override
    public void stop() {
        System.out.println("Stopping...");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        final HttpServletRequest req = (HttpServletRequest) request;
        final HttpServletResponse resp = (HttpServletResponse) response;
        final long now = System.currentTimeMillis();
        resp.addHeader("Cache-Control", "public, max-age=86400, must-revalidate");
        resp.setDateHeader("Expires", now + 86400000L);

        // Process the static files in the project
        String uri = req.getRequestURI().replaceAll("^/+", "");
        if (uri.length() > 1) {
            if (uri.indexOf('/') != -1)
                uri = uri.substring(0, uri.indexOf("/"));

            uri = uri.replace("%2e", ".");
            uri = uri.replace("%2f", "/");
            uri = uri.replace("%5c", "/");

            File resource = new File(uri);
            if (resource.exists()) {
                chain.doFilter(request, response);
            } else {
                this.service(req, resp);
            }
        } else
            this.service(req, resp);
    }

    @Override
    public void destroy() {
        this.stop();
    }

    @Override
    public void run() {
        //TODO
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy