org.openlegacy.mvc.AbstractRestController.java Source code

Java tutorial

Introduction

Here is the source code for org.openlegacy.mvc.AbstractRestController.java

Source

/*******************************************************************************
 * Copyright (c) 2014 OpenLegacy Inc.
 * All rights reserved. This program and the accompanying materials 
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     OpenLegacy Inc. - initial API and implementation
 *******************************************************************************/
package org.openlegacy.mvc;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.exolab.castor.xml.MarshalException;
import org.exolab.castor.xml.Unmarshaller;
import org.exolab.castor.xml.ValidationException;
import org.openlegacy.EntitiesRegistry;
import org.openlegacy.EntityDefinition;
import org.openlegacy.Session;
import org.openlegacy.definitions.ActionDefinition;
import org.openlegacy.exceptions.EntityNotFoundException;
import org.openlegacy.exceptions.RegistryException;
import org.openlegacy.json.EntitySerializationUtils;
import org.openlegacy.modules.login.LoginException;
import org.openlegacy.modules.menu.Menu;
import org.openlegacy.modules.menu.MenuItem;
import org.openlegacy.modules.navigation.Navigation;
import org.openlegacy.support.SimpleEntityWrapper;
import org.openlegacy.utils.ProxyUtil;
import org.openlegacy.utils.UrlUtil;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import org.xml.sax.InputSource;

import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.URLConnection;
import java.text.MessageFormat;
import java.util.List;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;

public abstract class AbstractRestController {

    public static final String JSON = "application/json";
    public static final String XML = "application/xml";
    protected static final String MODEL = "model";
    protected static final String ACTION = "action";

    protected abstract Session getSession();

    protected abstract EntitiesRegistry<?, ?, ?> getEntitiesRegistry();

    private final static Log logger = LogFactory.getLog(AbstractRestController.class);

    /**
     * Whether to perform login on session start. Can be overridden from /application.properties
     * defaultRestController.requiresLogin=true
     */
    private boolean requiresLogin = false;

    /**
     * Whether to enable /login URL calls. Can be overridden from /application.properties
     */
    private boolean enableLogin = true;

    /**
     * Whether to enable /login via URL GET calls. Can be overridden from /application.properties
     */
    private boolean enableGetLogin = true;
    private String uploadDir;

    public Object login(String user, String password, HttpServletResponse response)
            throws IOException, LoginException {
        if (!enableLogin || !enableGetLogin) {
            throw (new UnsupportedOperationException("/login is not support"));
        }

        try {
            org.openlegacy.modules.login.Login loginModule = getSession()
                    .getModule(org.openlegacy.modules.login.Login.class);
            if (loginModule != null) {
                loginModule.login(user, password);
            } else {
                logger.warn("No login module defined. Skipping login");
            }
        } catch (RegistryException e) {
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, e.getMessage());
        } catch (LoginException e) {
            getSession().disconnect();
            response.resetBuffer();
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.setContentType("text/plain; charset=UTF-8");
            response.getOutputStream().print(e.getMessage());
            throw e;
        }
        response.setStatus(HttpServletResponse.SC_OK);
        return getMenu(response);

    }

    protected ModelAndView getEntity(String entityName, boolean children, HttpServletResponse response)
            throws IOException {
        try {
            return getEntityRequest(entityName, null, children, response);
        } catch (RuntimeException e) {
            return handleException(response, e);
        }
    }

    protected ModelAndView getEntityWithKey(String entityName, String key, boolean children,
            HttpServletResponse response) throws IOException {
        try {
            return getEntityRequest(entityName, key, children, response);
        } catch (RuntimeException e) {
            return handleException(response, e);
        }
    }

    protected ModelAndView getEntityDefinitions(String entityName, HttpServletResponse response)
            throws IOException {
        EntityDefinition<?> entityDefinitions = getEntitiesRegistry().get(entityName);
        return new ModelAndView("definitions", "definitions", entityDefinitions);

    }

    protected ModelAndView getEntityRequest(String entityName, String key, boolean children,
            HttpServletResponse response) throws IOException {
        if (!authenticate(response)) {
            return null;
        }
        try {
            Object entity = getApiEntity(entityName, key);
            return getEntityInner(entity, children);
        } catch (EntityNotFoundException e) {
            logger.fatal(e, e);
            response.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
            return null;
        }
    }

    protected Object postApiEntity(String entityName, Class<?> entityClass, String key) {
        return getApiEntity(entityName, key);
    }

    protected Object getApiEntity(String entityName, String key) {
        Object entity;
        Object[] keys = new Object[0];
        if (key != null) {
            keys = key.split("\\+");
        }

        if (key == null) {
            entity = getSession().getEntity(entityName);
        } else {
            entity = getSession().getEntity(entityName, keys);
        }
        return entity;
    }

    /**
     * 
     * @param entity
     * @param child
     *            whether to include child entities
     * @return
     */
    protected ModelAndView getEntityInner(Object entity, boolean children) {
        if (entity == null) {
            throw (new EntityNotFoundException("No entity found"));
        }
        entity = ProxyUtil.getTargetObject(entity, children);
        Navigation navigationModule = getSession().getModule(Navigation.class);
        boolean isWindow = getEntitiesRegistry().get(entity.getClass()).isWindow();
        SimpleEntityWrapper wrapper = new SimpleEntityWrapper(entity,
                navigationModule != null ? navigationModule.getPaths() : null, getActions(entity), isWindow);
        return new ModelAndView(MODEL, MODEL, wrapper);
    }

    protected abstract List<ActionDefinition> getActions(Object entity);

    protected Object getMenu(HttpServletResponse response) throws IOException {
        try {
            Menu menuModule = getSession().getModule(Menu.class);
            if (menuModule == null) {
                return null;
            }
            MenuItem menus = menuModule.getMenuTree();
            return menus;

        } catch (RuntimeException e) {
            handleException(response, e);
        }
        return null;
    }

    /**
     * Accepts a post request in JSON format, de-serialize it to a entity, and send it to the host
     * 
     * @param entityName
     * @param action
     * @param json
     * @param response
     *            Return HTTP OK (200) is success
     * @return
     * @throws IOException
     */
    protected ModelAndView postEntityJson(String entityName, String action, boolean children, String json,
            HttpServletResponse response) throws IOException {
        try {
            return postEntityJsonInner(entityName, null, action, children, json, response);
        } catch (RuntimeException e) {
            return handleException(response, e);
        }
    }

    protected ModelAndView handleException(HttpServletResponse response, RuntimeException e) throws IOException {
        response.setStatus(500);
        response.getWriter().write("{\"error\":\"" + e.getMessage() + "\"}");
        logger.fatal(e.getMessage(), e);
        return null;
    }

    protected ModelAndView postEntityJsonWithKey(String entityName, String key, String action, boolean children,
            String json, HttpServletResponse response) throws IOException {
        try {
            return postEntityJsonInner(entityName, key, action, children, json, response);
        } catch (RuntimeException e) {
            return handleException(response, e);
        }
    }

    private ModelAndView postEntityJsonInner(String entityName, String key, String action, boolean children,
            String json, HttpServletResponse response) throws IOException {

        Object entity = preSendJsonEntity(entityName, key, json, response);

        Object resultEntity = sendEntity(entity, action);
        return getEntityInner(resultEntity, children);
    }

    protected Object preSendJsonEntity(String entityName, String key, String json, HttpServletResponse response)
            throws IOException {
        json = UrlUtil.decode(json, "{");

        if (!authenticate(response)) {
            return null;
        }

        Class<?> entityClass = findAndHandleNotFound(entityName, response);
        if (entityClass == null) {
            return null;
        }

        Object entity = null;
        postApiEntity(entityName, entityClass, key);

        try {
            if (json.length() == 0) {
                json = "{}";
            }
            entity = EntitySerializationUtils.deserialize(json, entityClass);
        } catch (Exception e) {
            handleDeserializationException(entityName, response, e);
            return null;
        }
        return entity;
    }

    protected ModelAndView postEntityXmlWithKey(String entityName, String key, String action, String xml,
            HttpServletResponse response) throws IOException {
        try {
            return postEntityXmlInner(entityName, key, action, xml, response);
        } catch (RuntimeException e) {
            return handleException(response, e);
        }
    }

    protected ModelAndView postEntityXml(String entityName, String action, String xml, HttpServletResponse response)
            throws IOException {
        try {
            return postEntityXmlInner(entityName, null, action, xml, response);
        } catch (RuntimeException e) {
            return handleException(response, e);
        }
    }

    private ModelAndView postEntityXmlInner(String entityName, String key, String action, String xml,
            HttpServletResponse response) throws IOException {

        xml = UrlUtil.decode(xml, "<");

        if (!authenticate(response)) {
            return null;
        }

        Class<?> entityClass = findAndHandleNotFound(entityName, response);
        if (entityClass == null) {
            return null;
        }

        Object entity = null;
        postApiEntity(entityName, entityClass, key);

        try {
            InputSource inputSource = new InputSource(new ByteArrayInputStream(xml.getBytes()));
            entity = Unmarshaller.unmarshal(entityClass, inputSource);
        } catch (MarshalException e) {
            handleDeserializationException(entityName, response, e);
            return null;
        } catch (ValidationException e) {
            handleDeserializationException(entityName, response, e);
            return null;
        }

        Object resultEntity = sendEntity(entity, action);
        return getEntityInner(resultEntity, false);
    }

    /**
     * Look for the given entity in the registry, and return HTTP 400 (BAD REQUEST) in case it's not found
     * 
     * @param entityName
     * @param response
     * @return
     * @throws IOException
     */
    protected Class<?> findAndHandleNotFound(String entityName, HttpServletResponse response) throws IOException {
        Class<?> entityClass = getEntitiesRegistry().getEntityClass(entityName);
        if (entityClass == null) {
            String message = MessageFormat.format("Entity {0} not found", entityName);
            response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
            logger.error(message);
        }
        return entityClass;
    }

    public static void handleDeserializationException(String entityName, HttpServletResponse response, Exception e)
            throws IOException {
        String message = MessageFormat.format("Unable to desirialize entity {0}", entityName);
        response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
        logger.fatal(message, e);
        return;
    }

    protected abstract Object sendEntity(Object entity, String action);

    protected boolean authenticate(HttpServletResponse response) throws IOException {
        if (!requiresLogin) {
            return true;
        }
        org.openlegacy.modules.login.Login loginModule = getSession()
                .getModule(org.openlegacy.modules.login.Login.class);
        if (!loginModule.isLoggedIn()) {
            sendError(HttpServletResponse.SC_UNAUTHORIZED, "User unauthorized!", response);
        }
        return true;

    }

    public Object loginPostJson(String json, HttpServletResponse response) throws IOException {
        json = UrlUtil.decode(json, "{");
        if (!enableLogin) {
            throw (new UnsupportedOperationException("/login is not support"));
        }

        try {
            LoginObject login = EntitySerializationUtils.deserialize(json, LoginObject.class);
            getSession().getModule(org.openlegacy.modules.login.Login.class).login(login.getUser(),
                    login.getPassword());
        } catch (LoginException e) {
            getSession().disconnect();
            sendError(HttpServletResponse.SC_UNAUTHORIZED, e.getMessage(), response);
        } catch (Exception e) {
            sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid login", response);
            logger.fatal("Invalid login", e);
        }

        return getMenu(response);
    }

    private static void sendError(int errorCode, String message, HttpServletResponse response) throws IOException {
        response.resetBuffer();
        response.setStatus(errorCode);
        response.setHeader("Content-Type", "application/json");
        response.setCharacterEncoding("UTF-8");
        response.getWriter().write(String.format("{\"error\":\"%s\"}", message));
        response.flushBuffer();
    }

    public Object loginPostXml(String xml, HttpServletResponse response) throws IOException {
        xml = UrlUtil.decode(xml, "{");
        if (!enableLogin) {
            throw (new UnsupportedOperationException("/login is not support"));
        }

        try {
            InputSource inputSource = new InputSource(new ByteArrayInputStream(xml.getBytes()));
            LoginObject login = (LoginObject) Unmarshaller.unmarshal(LoginObject.class, inputSource);
            getSession().getModule(org.openlegacy.modules.login.Login.class).login(login.getUser(),
                    login.getPassword());
        } catch (LoginException e) {
            getSession().disconnect();
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
        } catch (Exception e) {
            response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid login");
            logger.fatal("Invalid login", e);
        }
        return getMenu(response);
    }

    protected void uploadImage(MultipartFile file, HttpServletResponse response) throws IOException {
        String fileName = file.getOriginalFilename();
        fileName = fileName.replaceAll(" ", "_");

        if (uploadDir == null) {
            String property = "java.io.tmpdir";
            // Get the temporary directory and print it.
            uploadDir = System.getProperty(property);
        }
        file.transferTo(new File(uploadDir, fileName));

        response.setContentType("application/json");

        PrintWriter out = response.getWriter();
        out.print("{\"filename\":\"" + fileName + "\"}");
        out.flush();
    }

    protected void getImage(HttpServletResponse response, String filename) throws IOException {

        if (uploadDir == null) {
            String property = "java.io.tmpdir";
            // Get the temporary directory and print it.
            uploadDir = System.getProperty(property);
        }
        File file = new File(uploadDir, filename);
        BufferedImage bufferedImage = ImageIO.read(file);

        response.setContentType(URLConnection.guessContentTypeFromName(filename));
        OutputStream out = response.getOutputStream();

        String ext = "";

        int i = filename.lastIndexOf('.');
        if (i >= 0) {
            ext = filename.substring(i + 1);
        }

        ImageIO.write(bufferedImage, ext, out);
        out.close();
    }

    public void setRequiresLogin(boolean requiresLogin) {
        this.requiresLogin = requiresLogin;
    }

    public void setEnableLogin(boolean enableLogin) {
        this.enableLogin = enableLogin;
    }

    public void setEnableGetLogin(boolean enableGetLogin) {
        this.enableGetLogin = enableGetLogin;
    }

    public void setUploadDir(String uploadDir) {
        this.uploadDir = uploadDir;
    }

    public static class LoginObject {

        private String user;
        private String password;

        public String getUser() {
            return user;
        }

        public void setUser(String user) {
            this.user = user;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }

    }
}