org.xsystem.sql2.http.PageServlet2.java Source code

Java tutorial

Introduction

Here is the source code for org.xsystem.sql2.http.PageServlet2.java

Source

/*
 * Copyright 2017 Andrey Timofeev.
 *
 * 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.xsystem.sql2.http;

import com.google.gson.Gson;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.jxpath.ClassFunctions;
import org.apache.commons.jxpath.JXPathContext;
import org.w3c.dom.Document;
import org.xsystem.http.RestApiTemplate;
import org.xsystem.system.sql.JDBCTransationManager2;

import static org.xsystem.sql2.http.Enviroment.FILEPRFX;
import org.xsystem.sql2.http.impl.ActionExecuter;
import org.xsystem.sql2.http.impl.Config;
import org.xsystem.sql2.http.impl.FileFormat;
import org.xsystem.sql2.http.impl.HttpHelper;
import org.xsystem.sql2.http.impl.PageLoader;
//import org.xsystem.sql2.dml.SqlHelper;
//import org.xsystem.sql2.http.impl.ActionExecuter;
//import org.xsystem.sql2.http.impl.Config;
//import org.xsystem.sql2.http.impl.FileFormat;
//import org.xsystem.sql2.http.impl.HttpHelper;
//import org.xsystem.sql2.http.impl.PageLoader;
import org.xsystem.utils.Auxilary;
import org.xsystem.utils.FileTransfer;
import org.xsystem.utils.XMLUtil;

/**
 *
 * @author Andrey Timofeev
 */
public class PageServlet2 extends RestApiTemplate {
    String repositoryPath;
    ServletConfig config;

    Config pagesConfig = null;
    volatile String errorReport = null;

    static ThreadLocal<Enviroment> enviromentLocal = new ThreadLocal();

    FilesWatcher fileWatcher = null;

    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        this.config = config;
        repositoryPath = config.getInitParameter("repository");
        repositoryPath = config.getServletContext().getRealPath(repositoryPath);
        loadRepository();
    }

    synchronized void loadRepository() {
        PageLoader loader = new PageLoader();
        EnviromentImpl enviroment = createEnviroment();
        pagesConfig = null;
        try {
            loader.load(repositoryPath);
            pagesConfig = new Config();
            pagesConfig.setConnectionManager(loader.getConnectionManager());
            pagesConfig.setActions(loader.getActions());
            pagesConfig.setConnections(loader.getConnections());
            pagesConfig.setAfterCreateConnectionEventListeners(loader.getAfterCreateConnectionEventListeners());
            pagesConfig.setBeforeCloseConnectionEventListeners(loader.getBeforeCloseConnectionEventListeners());
            pagesConfig.setFileStorages(loader.getFileStorages());
            pagesConfig.setErrorHandler(loader.getErrorHandler());
            pagesConfig.setObjectNames(loader.getObjectNames());

            Set<File> fileSet = loader.getFileSet();
            List<File> listFile = new ArrayList();
            listFile.addAll(fileSet);

            if (fileWatcher != null) {
                if (fileWatcher.isStopped()) {
                    fileWatcher.stopThread();
                }
            }
            fileWatcher = new FilesWatcher(listFile, (f -> {
                changeFile(f);
            }));
            fileWatcher.start();

        } catch (RuntimeException ex) {
            ex.printStackTrace();
            errorReport = Auxilary.throwableToString(ex);
        } finally {
            destroyEnviroment(enviroment);
        }
    }

    synchronized void changeFile(File f) {
        fileWatcher.stopThread();
        loadRepository();
    }

    synchronized void chekLoadRepository() {
    }

    synchronized Config getConfig() {
        return pagesConfig;
    }

    static Enviroment getEnviroment() {
        return enviromentLocal.get();
    }

    EnviromentImpl createEnviroment() {
        EnviromentImpl enviroment = new EnviromentImpl();
        enviromentLocal.set(enviroment);
        return enviroment;
    }

    void destroyEnviroment(EnviromentImpl enviroment) {
        if (enviroment != null) {
            enviroment.close();
        }
        enviromentLocal.remove();
    }

    @Override
    protected Object getJson(ServletInputStream input) throws IOException {
        String json = getContentAsString(input);
        if (Auxilary.isEmptyOrNull(json)) {
            return new HashMap();
        }
        Gson gson = gsonBuilder.create();
        Object jsonContext = gson.fromJson(json, Object.class);
        return jsonContext;
    }

    static Map<String, Object> getContext(Map<String, String> evals, Map<String, Object> reqContext) {
        JXPathContext context = JXPathContext.newContext(reqContext);
        context.setFunctions(new ClassFunctions(Base64Decode.class, "BASE64"));
        context.setLenient(true);

        Map ret = new HashMap();
        evals.entrySet().forEach(entry -> {
            String key = entry.getKey();
            String eval = entry.getValue();
            Object value = context.getValue(eval);
            ret.put(key, value);
        });

        return ret;
    }

    void onCreateConnection(Config cofig, String connectionName) {//, Connection connection) {
        AfterCreateConnectionEventListener listener = cofig.getAfterCreateConnectionEventListeners()
                .get(connectionName);
        if (listener != null) {
            Connection connection = JDBCTransationManager2.getConnection();
            listener.onCreateConnection(connection);
        }
    }

    void onCloseConnection(Config cofig, String connectionName) {//, Connection connection) {
        BeforeCloseConnectionEventListener listener = cofig.getBeforeCloseConnectionEventListeners()
                .get(connectionName);

        if (listener != null) {
            try {
                Connection connection = JDBCTransationManager2.getConnection();
                listener.onCloseConnection(connection);
            } catch (Throwable tr) {
                tr.printStackTrace();
            }
        }
    }

    Object execute(HttpServletRequest request, Config cofig, ActionExecuter action, Map params) {

        EnviromentImpl enviroment = createEnviroment();
        String connectionName = action.getConnectionName();
        enviroment.setHttpRequest(request);
        enviroment.setObjectNames(pagesConfig.getObjectNames());
        String path = action.getLocation();
        File f = enviroment.getFile(path);
        Document doc = XMLUtil.getDocumentE(f);

        enviroment.setDocument(doc);

        JDBCTransationManager2 tm = new JDBCTransationManager2(() -> cofig.getConnection(connectionName));

        Executer executer = action.getAction();
        boolean isError = true;
        try {
            tm.begin();
            onCreateConnection(cofig, connectionName);
            ActionEventListener beforeEvent = action.getBeforeEvent();
            if (beforeEvent != null) {
                beforeEvent.onEvent(params);
            }
            Object ret = executer.execute(params);
            ActionEventListener afterEvent = action.getAfterEvent();
            if (afterEvent != null) {
                if (ret instanceof Map) {
                    params.putAll((Map) ret); // 
                    ret = params;
                }
                afterEvent.onEvent(ret);
            }
            onCloseConnection(cofig, connectionName);
            tm.commit();
            isError = false;
            return ret;
        } finally {
            if (isError) {
                tm.rollback();
            }
            destroyEnviroment(enviroment);
            tm.close();
        }

    }

    @Override
    public void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        //  response.setHeader("Pragma", "No-cache");
        response.setHeader("Pragma", "no-cache");
        response.setDateHeader("Expires", 0);
        //response.setHeader("Cache-Control", "no-cache");

        response.setHeader("Cache-Control", "private, no-store, no-cache, must-revalidate");

        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json;charset=UTF-8");

        String path = request.getPathInfo();
        ErrorHandler errorHansdler = null;
        try (ServletOutputStream out = response.getOutputStream();
                ServletInputStream input = request.getInputStream()) {
            try {

                if (path == null) {
                    loadRepository();
                    if (errorReport != null) {
                        Map error = Auxilary.makeJsonError("Loading error-" + errorReport);
                        response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                        writeJson(error, out);
                    } else {
                        writeJson(Auxilary.makeJsonSuccess(), out);
                    }
                    return;
                }
                if (errorReport != null) {
                    Map error = Auxilary.makeJsonError("Loading error-" + errorReport);
                    response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                    writeJson(error, out);
                    return;
                }
                Config cofig = getConfig();
                errorHansdler = cofig.getErrorHandler();

                Matcher matcher = Pattern.compile("").matcher(path);
                List<ActionExecuter> lstActions = cofig.getActions();
                Optional<ActionExecuter> opt = lstActions.stream()
                        .filter(action -> matcher.reset().usePattern(action.getPattern()).find()).findFirst();
                if (opt.isPresent()) {
                    ActionExecuter action = opt.get();

                    List groups = HttpHelper.getGroups(matcher);

                    Map params = Collections.emptyMap();
                    Object json = Collections.emptyMap();
                    Long skip = null;
                    Integer total = null;

                    if (action.isMultipart()) {
                        json = HttpHelper.getMultipartJson(request);
                    } else {
                        params = HttpHelper.getParams(request);
                        skip = HttpHelper.getParamSkip(request);
                        total = HttpHelper.getParamTotal(request);
                        if (!action.isForm()) {
                            json = getJson(input);
                        }
                    }

                    Map<String, Object> context = Auxilary.newMap("groups", groups, "params", params, "json", json,
                            "request", request);

                    Map<String, String> evals = action.getContextParams();
                    FileFormat fileFormat = action.getFileFormat();
                    int thumb = HttpHelper.getThumb(fileFormat, context);
                    context = getContext(evals, context);
                    if (skip != null) {
                        context.put("skip", skip);
                    }
                    if (total != null) {
                        context.put("total", total);
                    }
                    Object rezult = execute(request, cofig, action, context);
                    if (fileFormat == null) {
                        writeJson(Auxilary.makeJsonSuccess("data", rezult), out);
                    } else {
                        FileTransfer fileTransfer = HttpHelper.getFileTransfer(fileFormat, rezult,
                                (format, data) -> {
                                    return getContent(format, data, "defualt");
                                });

                        if (fileTransfer == null && !fileFormat.isDownload()
                                && !Auxilary.isEmptyOrNull(fileFormat.getNotfound())) {
                            String fname = fileFormat.getNotfound();
                            if (fname.startsWith(FILEPRFX)) {
                                fname = fname.substring(FILEPRFX.length());
                                fname = config.getServletContext().getRealPath(fname);
                                File f = new File(fname);
                                if (f.exists()) {
                                    fileTransfer = new FileTransfer();
                                    String contentType = Files.probeContentType(Paths.get(fname));
                                    String fileType = Auxilary.getFileExtention(fname);
                                    byte[] b = Auxilary.readBinaryFile(f);
                                    fileTransfer.setContentType(contentType);
                                    fileTransfer.setFileType(fileType);
                                    fileTransfer.setData(b);
                                }
                            }
                        }

                        if (fileTransfer == null) {

                            Map error = Auxilary.makeJsonError("File not found ");
                            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
                            writeJson(error, out);
                        } else {
                            boolean isDownload = fileFormat.isDownload();

                            HttpHelper.writeFile(fileTransfer, isDownload, thumb, request, response, out);
                        }
                    }
                } else {
                    Map error = Auxilary.makeJsonError("Page not found [" + path + "]");
                    response.setStatus(HttpServletResponse.SC_NOT_FOUND);
                    writeJson(error, out);
                }

            } catch (Throwable err) {

                // response.setStatus();
                if (errorHansdler == null) {
                    error(err, out);
                } else {
                    Object error = errorHansdler.handler(err);
                    writeJson(error, out);
                }
            }
        }
    }

    byte[] getContent(String srcType, Object data, String storage) {
        String type = srcType.trim().toLowerCase();
        if (data == null) {
            return null;
        }
        switch (type) {
        case "blob": {
            byte[] content = (byte[]) data;
            return content;
        }
        case "file": {
            String path = (String) data;
            byte[] content = getFileContent(storage, path);
            return content;
        }
        }
        return null;
    }

    byte[] getFileContent(String storageName, String path) {
        Map<String, String> fileStorages = pagesConfig.getFileStorages();
        if (fileStorages == null) {
            throw new Error("fileStorages not define");
        }

        String res = fileStorages.get(storageName);
        if (res == null) {
            return null;
        }

        String rootpath = Auxilary.getJndiResource(res, String.class);
        File f = new File(rootpath, path);
        try {
            byte[] ret = Auxilary.readBinaryFile(f);
            return ret;
        } catch (Exception ex) {
            throw new Error(ex);
        }
    }

    class EnviromentImpl implements Enviroment {
        Map<String, String> objectNames;
        //Connection connection = null;
        Document document = null;
        HttpServletRequest request = null;

        @Override
        public Map<String, String> getObjectNames() {
            return this.objectNames;
        }

        void setObjectNames(Map<String, String> objectNames) {
            this.objectNames = objectNames;
        }

        //void setConnection(Connection connection) {
        //    this.connection = connection;
        //}
        void setDocument(Document document) {
            this.document = document;
        }

        void setHttpRequest(HttpServletRequest request) {
            this.request = request;
        }

        public HttpServletRequest getHttpRequest() {
            return request;
        }

        void close() {
            request = null;
            //  Auxilary.close(connection);
        }

        @Override
        public Connection getConnection() {
            return JDBCTransationManager2.getConnection();
        }

        @Override
        public Document getDocument() {
            return document;
        }

        @Override
        public File getFile(String fname) {
            if (fname.startsWith(FILEPRFX)) {
                fname = fname.substring(FILEPRFX.length());
                String path = config.getServletContext().getRealPath(fname);
                File f = new File(path);
                return f;
            }
            return null;
        }

    }

    public static <T> T getJndiResource(String path, Class<T> type) {
        try {
            InitialContext cxt = new InitialContext();

            Object ret = cxt.lookup(path);

            return (T) ret;
        } catch (NamingException ex) {
            throw new Error(ex);
        }
    }

    public static java.sql.Connection getJndiJDBConnection(String path) {
        try {
            javax.sql.DataSource ds = getJndiResource(path, javax.sql.DataSource.class);
            return ds.getConnection();
        } catch (SQLException ex) {
            throw new Error(ex);
        }
    }
}