org.openlegacy.mvc.web.AbstractGenericEntitiesController.java Source code

Java tutorial

Introduction

Here is the source code for org.openlegacy.mvc.web.AbstractGenericEntitiesController.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.web;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openlegacy.EntitiesRegistry;
import org.openlegacy.EntityDefinition;
import org.openlegacy.Session;
import org.openlegacy.definitions.ActionDefinition;
import org.openlegacy.definitions.FieldDefinition;
import org.openlegacy.layout.PageBuilder;
import org.openlegacy.modules.menu.Menu.MenuEntity;
import org.openlegacy.mvc.MvcUtils;
import org.openlegacy.mvc.OpenLegacyWebProperties;
import org.openlegacy.utils.ProxyUtil;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.mobile.device.site.SitePreference;
import org.springframework.mobile.device.site.SitePreferenceUtils;
import org.springframework.ui.Model;
import org.springframework.util.Assert;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import java.io.IOException;
import java.net.MalformedURLException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;

import javax.inject.Inject;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * OpenLegacy generic web controller for a session. Handles GET/POST requests of a web application. Works closely with
 * generic.jspx / composite.jspx. Saves the need for a dedicated controller and page for each screen API, if such doesn't exists.
 * 
 * @author Roi Mor
 * 
 */
public abstract class AbstractGenericEntitiesController<S extends Session> implements InitializingBean {

    protected static final String ACTION = "action";

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

    private static final String PAGE = "page";

    private static final String MAIN_MENU = "mainMenu";

    @Inject
    private S session;

    protected S getSession() {
        return session;
    }

    @Inject
    private EntitiesRegistry<?, ?, ?> entitiesRegistry;

    @Inject
    private ServletContext servletContext;

    private List<String> mobileViewsPaths = new ArrayList<String>();

    private List<String> webViewsPaths = new ArrayList<String>();

    private String viewsSuffix = ".jspx";

    @Inject
    private OpenLegacyWebProperties openlegacyWebProperties;

    @SuppressWarnings("rawtypes")
    @Inject
    private PageBuilder pageBuilder;

    @RequestMapping(value = "/{entity}", method = RequestMethod.GET)
    public String getEntity(@PathVariable("entity") String entityName,
            @RequestParam(value = "partial", required = false) String partial, Model uiModel,
            HttpServletRequest request) throws IOException {
        if (entityName.equals(MAIN_MENU)) {
            return MvcConstants.ROOTMENU_VIEW;
        }
        return getEntityWithKey(entityName, null, partial, uiModel, request);

    }

    @RequestMapping(value = "/{entity}/{key:[[\\w\\p{L}]+[:-_ ,]*[\\w\\p{L}]+]+}", method = RequestMethod.GET)
    public String getEntityWithKey(@PathVariable("entity") String entityName, @PathVariable("key") String key,
            @RequestParam(value = "partial", required = false) String partial, Model uiModel,
            HttpServletRequest request) throws IOException {

        try {
            // enable sending more then one key, concatenated with "+"
            Object[] keys = new Object[0];
            if (key != null) {
                String[] keysArr = key.split("\\+");
                keys = new Object[keysArr.length];
                List<? extends FieldDefinition> keyFields = entitiesRegistry.get(entityName).getKeys();
                for (int i = 0; i < keyFields.size(); i++) {
                    keys[i] = keysArr[i];
                    if (keyFields.get(i).getJavaType() == Integer.class) {
                        keys[i] = Integer.valueOf(keysArr[i]);
                    }
                }
            }
            Object entity = session.getEntity(entityName, keys);
            return prepareView(entity, uiModel, partial != null, request);
        } catch (RuntimeException e) {
            logger.fatal(e, e);
            return handleFallbackUrl(e);
        }
    }

    protected String handleFallbackUrl(RuntimeException e) {
        if (openlegacyWebProperties.isFallbackUrlOnError()) {
            Assert.notNull(openlegacyWebProperties.getFallbackUrl(), "No fallback URL defined");
            logger.error(e.getMessage());
            return MvcConstants.REDIRECT + openlegacyWebProperties.getFallbackUrl();
        } else {
            throw (e);
        }
    }

    protected abstract ActionDefinition findAction(Object entity, String action);

    protected String handleEntity(HttpServletRequest request, Model uiModel, Object resultEntity, String urlPrefix)
            throws MalformedURLException {
        if (resultEntity == null) {
            Assert.notNull(openlegacyWebProperties.getFallbackUrl(), "No fallback URL defined");
            return MvcConstants.REDIRECT + openlegacyWebProperties.getFallbackUrl();
        } else {
            if (StringUtils.isEmpty(urlPrefix)) {
                return prepareView(resultEntity, uiModel, true, request);
            } else {
                EntityDefinition<?> entityDefinition = entitiesRegistry.get(resultEntity.getClass());
                return urlPrefix + entityDefinition.getEntityName();
            }
        }
    }

    @SuppressWarnings("unchecked")
    protected String prepareView(Object entity, Model uiModel, boolean partial, HttpServletRequest request)
            throws MalformedURLException {
        String entityName = ProxyUtil.getOriginalClass(entity.getClass()).getSimpleName();
        uiModel.addAttribute(StringUtils.uncapitalize(entityName), entity);
        EntityDefinition<?> entityDefinition = entitiesRegistry.get(entityName);
        uiModel.addAttribute(PAGE, pageBuilder.build(entityDefinition));

        SitePreference sitePreference = SitePreferenceUtils.getCurrentSitePreference(request);

        boolean isComposite = entityDefinition.getChildEntitiesDefinitions().size() > 0 && !partial;
        String suffix = isComposite ? MvcConstants.COMPOSITE_SUFFIX : "";
        String viewName = entityDefinition.getEntityName() + suffix;

        boolean isEmpty = !isComposite && entityDefinition.isEmpty();

        List<String> viewsPaths = sitePreference == SitePreference.MOBILE ? mobileViewsPaths : webViewsPaths;

        // check if custom view exists, if not load generic view by
        // characteristics
        if (!isResourceExists(viewsPaths, viewName, viewsSuffix)) {
            if (isComposite) {
                // generic composite view (multi tabbed page)
                viewName = MvcConstants.COMPOSITE;
            } else if (entityDefinition.getType() == MenuEntity.class) {
                // generic menu view
                viewName = MvcConstants.ROOTMENU_VIEW;
            } else if (partial) {
                // generic inner page view (inner tab)
                viewName = MvcConstants.GENERIC_VIEW;
            } else if (entityDefinition.isWindow()) {
                // generic window pop-pup view
                viewName = MvcConstants.GENERIC_WINDOW;
            } else if (isEmpty) {
                viewName = MvcConstants.REDIRECT + openlegacyWebProperties.getFallbackUrl();
            } else {
                // generic view
                viewName = MvcConstants.GENERIC;
            }
        }

        return viewName;
    }

    private boolean isResourceExists(List<String> viewsPaths, String viewName, String viewsSuffix)
            throws MalformedURLException {
        for (String viewsPath : viewsPaths) {
            if (servletContext
                    .getResource(MessageFormat.format("{0}/{1}{2}", viewsPath, viewName, viewsSuffix)) != null) {
                return true;
            }
        }
        return 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 = entitiesRegistry.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;
    }

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        MvcUtils.registerEditors(binder, entitiesRegistry);
    }

    public List<String> getWebViewsPaths() {
        return webViewsPaths;
    }

    public void setWebViewsPaths(List<String> webViewsPaths) {
        this.webViewsPaths = webViewsPaths;
    }

    public List<String> getMobileViewsPaths() {
        return mobileViewsPaths;
    }

    public void setMobileViewsPaths(List<String> mobileViewsPaths) {
        this.mobileViewsPaths = mobileViewsPaths;
    }

    public void setViewsSuffix(String viewsSuffix) {
        this.viewsSuffix = viewsSuffix;
    }

    protected EntitiesRegistry<?, ?, ?> getEntitiesRegistry() {
        return entitiesRegistry;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        if (webViewsPaths.size() == 0) {
            webViewsPaths.add("/WEB-INF/web/views");
        }
        if (mobileViewsPaths.size() == 0) {
            mobileViewsPaths.add("/WEB-INF/mobile/views");
        }
    }

}