gr.abiss.calipso.wicket.CalipsoApplication.java Source code

Java tutorial

Introduction

Here is the source code for gr.abiss.calipso.wicket.CalipsoApplication.java

Source

/*
 * Copyright (c) 2007 - 2010 Abiss.gr <info@abiss.gr>  
 *
 *  This file is part of Calipso, a software platform by www.Abiss.gr.
 *
 *  Calipso is free software: you can redistribute it and/or modify 
 *  it under the terms of the GNU Affero General Public License as published by 
 *  the Free Software Foundation, either version 3 of the License, or 
 *  (at your option) any later version.
 * 
 *  Calipso is distributed in the hope that it will be useful, 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 *  GNU Affero General Public License for more details.
 * 
 *  You should have received a copy of the GNU General Public License 
 *  along with Calipso. If not, see http://www.gnu.org/licenses/agpl.html
 * 
 * This file incorporates work released by the JTrac project and  covered 
 * by the following copyright and permission notice:  
 * 
 *   Copyright 2002-2005 the original author or 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
 * 
 *      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 gr.abiss.calipso.wicket;

import gr.abiss.calipso.CalipsoService;
import gr.abiss.calipso.acegi.CalipsoCasProxyTicketValidator;
import gr.abiss.calipso.config.CalipsoPropertiesEditor;
import gr.abiss.calipso.domain.I18nStringIdentifier;
import gr.abiss.calipso.domain.I18nStringResource;
import gr.abiss.calipso.domain.RoleType;
import gr.abiss.calipso.domain.Space;
import gr.abiss.calipso.domain.User;
import gr.abiss.calipso.wicket.components.formfields.FieldConfig;
import gr.abiss.calipso.wicket.register.RegisterAnonymousUserFormPage;
import gr.abiss.calipso.wicket.register.RegisterUserFormPage;
import gr.abiss.calipso.wicket.yui.TestPage;

import java.util.List;
import java.util.Locale;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.velocity.app.Velocity;
import org.apache.wicket.Component;
import org.apache.wicket.ConverterLocator;
import org.apache.wicket.DefaultExceptionMapper;
import org.apache.wicket.IConverterLocator;
import org.apache.wicket.RestartResponseAtInterceptPageException;
import org.apache.wicket.RuntimeConfigurationType;
import org.apache.wicket.Session;
import org.apache.wicket.authorization.Action;
import org.apache.wicket.authorization.IAuthorizationStrategy;
import org.apache.wicket.markup.html.SecurePackageResourceGuard;
import org.apache.wicket.markup.html.pages.RedirectPage;
import org.apache.wicket.page.CouldNotLockPageException;
import org.apache.wicket.protocol.http.WebApplication;
import org.apache.wicket.protocol.http.servlet.ServletWebRequest;
import org.apache.wicket.request.IExceptionMapper;
import org.apache.wicket.request.IRequestHandler;
import org.apache.wicket.request.Request;
import org.apache.wicket.request.Response;
import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.wicket.request.handler.PageProvider;
import org.apache.wicket.request.handler.RenderPageRequestHandler;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.apache.wicket.resource.loader.IStringResourceLoader;
import org.apache.wicket.settings.IExceptionSettings.ThreadDumpStrategy;
import org.apache.wicket.util.IProvider;
import org.apache.wicket.util.convert.IConverter;
import org.apache.wicket.util.cookies.CookieUtils;
import org.apache.wicket.util.time.Duration;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.security.Authentication;
import org.springframework.security.AuthenticationException;
import org.springframework.security.AuthenticationManager;
import org.springframework.security.context.SecurityContextHolder;
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
import org.springframework.web.context.support.WebApplicationContextUtils;

/**
 * main wicket application for calipsoService holds singleton service layer
 * instance pulled from spring
 */
public class CalipsoApplication extends WebApplication {

    private final static Logger logger = Logger.getLogger(CalipsoApplication.class);

    public static final String REMEMBER_ME = "calipsoService";

    private CalipsoService calipsoService;
    private ApplicationContext applicationContext;
    private CalipsoCasProxyTicketValidator calipsoCasProxyTicketValidator;
    private CalipsoPropertiesEditor calipsoPropertiesEditor;

    private final boolean runStartupPlugins = true;

    public CalipsoService getCalipso() {
        return calipsoService;
    }

    public ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    // used only by CasLoginPage
    public String getCasLoginUrl() {
        if (calipsoCasProxyTicketValidator == null) {
            return null;
        }
        return calipsoCasProxyTicketValidator.getLoginUrl();
    }

    // used only by logout link in HeaderPanel
    public String getCasLogoutUrl() {
        if (calipsoCasProxyTicketValidator == null) {
            return null;
        }
        return calipsoCasProxyTicketValidator.getLogoutUrl();
    }

    @Override
    public void init() {

        super.init();
        // DEVELOPMENT or DEPLOYMENT
        RuntimeConfigurationType configurationType = this.getConfigurationType();
        if (RuntimeConfigurationType.DEVELOPMENT.equals(configurationType)) {
            logger.info("You are in DEVELOPMENT mode");
            // getResourceSettings().setResourcePollFrequency(Duration.ONE_SECOND);
            // getDebugSettings().setComponentUseCheck(true);
            getResourceSettings().setResourcePollFrequency(null);
            getDebugSettings().setComponentUseCheck(false);
            // getDebugSettings().setSerializeSessionAttributes(true);
            // getMarkupSettings().setStripWicketTags(false);
            // getExceptionSettings().setUnexpectedExceptionDisplay(
            // UnexpectedExceptionDisplay.SHOW_EXCEPTION_PAGE);
            // getAjaxSettings().setAjaxDebugModeEnabled(true);
        } else if (RuntimeConfigurationType.DEPLOYMENT.equals(configurationType)) {
            getResourceSettings().setResourcePollFrequency(null);
            getDebugSettings().setComponentUseCheck(false);
            // getDebugSettings().setSerializeSessionAttributes(false);
            // getMarkupSettings().setStripWicketTags(true);
            // getExceptionSettings().setUnexpectedExceptionDisplay(
            // UnexpectedExceptionDisplay.SHOW_INTERNAL_ERROR_PAGE);
            // getAjaxSettings().setAjaxDebugModeEnabled(false);
        }
        // initialize velocity
        try {
            Velocity.init();
            if (logger.isInfoEnabled()) {
                logger.info("Initialized Velocity engine");
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            logger.error("Failed to initialize velocity engine", e);
        }

        // Set custom page for internal errors
        getApplicationSettings().setInternalErrorPage(CalipsoErrorPage.class);

        // don't break down on missing resources
        getResourceSettings().setThrowExceptionOnMissingResource(false);

        // Redirect to PageExpiredError Page if current page is expired
        getApplicationSettings().setPageExpiredErrorPage(CalipsoPageExpiredErrorPage.class);

        // get hold of spring managed service layer (see BasePage, BasePanel etc
        // for how it is used)
        ServletContext sc = getServletContext();
        applicationContext = WebApplicationContextUtils.getWebApplicationContext(sc);
        calipsoService = (CalipsoService) applicationContext.getBean("calipsoService");

        calipsoPropertiesEditor = new CalipsoPropertiesEditor();

        // check if acegi-cas authentication is being used, get reference to
        // object to be used
        // by wicket authentication to redirect to right pages for login /
        // logout
        try {
            calipsoCasProxyTicketValidator = (CalipsoCasProxyTicketValidator) applicationContext
                    .getBean("casProxyTicketValidator");
            logger.info("casProxyTicketValidator retrieved from application context: "
                    + calipsoCasProxyTicketValidator);
        } catch (NoSuchBeanDefinitionException nsbde) {
            logger.info(
                    "casProxyTicketValidator not found in application context, CAS single-sign-on is not being used");
        }
        // delegate wicket i18n support to spring i18n
        getResourceSettings().getStringResourceLoaders().add(new IStringResourceLoader() {

            @Override
            public String loadStringResource(Class<?> clazz, String key, Locale locale, String style,
                    String variation) {
                return applicationContext.getMessage(key, null, null, locale);
            }

            @Override
            public String loadStringResource(Component component, String key, Locale locale, String style,
                    String variation) {
                return applicationContext.getMessage(key, null, null, locale);
            }
        });

        // add DB i18n resources
        getResourceSettings().getStringResourceLoaders().add(new IStringResourceLoader() {
            @Override
            public String loadStringResource(Class<?> clazz, String key, Locale locale, String style,
                    String variation) {
                if (StringUtils.isNotBlank(locale.getVariant())) {
                    // always ignore the variant
                    locale = new Locale(locale.getLanguage(), locale.getCountry());
                }
                String lang = locale.getLanguage();
                I18nStringResource resource = CalipsoApplication.this.calipsoService
                        .loadI18nStringResource(new I18nStringIdentifier(key, lang));
                if (resource == null && !lang.equalsIgnoreCase("en")) {
                    resource = CalipsoApplication.this.calipsoService
                            .loadI18nStringResource(new I18nStringIdentifier(key, "en"));
                }
                return resource != null ? resource.getValue() : null;
            }

            @Override
            public String loadStringResource(Component component, String key, Locale locale, String style,
                    String variation) {
                locale = component == null ? Session.get().getLocale() : component.getLocale();
                if (StringUtils.isNotBlank(locale.getVariant())) {
                    // always ignore the variant
                    locale = new Locale(locale.getLanguage(), locale.getCountry());
                }
                String lang = locale.getLanguage();
                I18nStringResource resource = CalipsoApplication.this.calipsoService
                        .loadI18nStringResource(new I18nStringIdentifier(key, lang));
                if (resource == null && !lang.equalsIgnoreCase("en")) {
                    resource = CalipsoApplication.this.calipsoService
                            .loadI18nStringResource(new I18nStringIdentifier(key, "en"));
                }
                return resource != null ? resource.getValue() : null;
            }
        });
        // cache resources. resource cache is cleared when creating/updating a space
        getResourceSettings().getLocalizer().setEnableCache(true);
        getSecuritySettings().setAuthorizationStrategy(new IAuthorizationStrategy() {
            @Override
            public boolean isActionAuthorized(Component c, Action a) {
                return true;
            }

            @Override
            public boolean isInstantiationAuthorized(Class clazz) {
                if (BasePage.class.isAssignableFrom(clazz)) {
                    if (((CalipsoSession) Session.get()).isAuthenticated()) {
                        return true;
                    }
                    if (calipsoCasProxyTicketValidator != null) {
                        // attempt CAS authentication
                        // ==========================
                        // logger.debug("checking if context contains CAS authentication");
                        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
                        if (authentication != null && authentication.isAuthenticated()) {
                            // logger.debug("security context contains CAS authentication, initializing session");
                            ((CalipsoSession) Session.get()).setUser((User) authentication.getPrincipal());
                            return true;
                        }
                    }
                    // attempt remember-me auto login
                    // ==========================
                    if (attemptRememberMeAutoLogin()) {
                        return true;
                    }

                    // attempt *anonymous* guest access if there are
                    // spaces that allow it
                    if (((CalipsoSession) Session.get()).getUser() == null) {
                        List<Space> anonymousSpaces = getCalipso().findSpacesWhereAnonymousAllowed();
                        if (anonymousSpaces.size() > 0) {
                            // logger.debug("Found "+anonymousSpaces.size()
                            // +
                            // " anonymousSpaces allowing ANONYMOUS access, initializing anonymous user");
                            User guestUser = new User();//getCalipso().loadUser(2);
                            guestUser.setLoginName("guest");
                            guestUser.setName("Anonymous");
                            guestUser.setLastname("Guest");
                            guestUser.setLocale(Session.get().getLocale().getLanguage());
                            getCalipso().initImplicitRoles(guestUser, anonymousSpaces, RoleType.ANONYMOUS);
                            // store user in session
                            ((CalipsoSession) Session.get()).setUser(guestUser);
                            return true;
                        } else {
                            if (logger.isDebugEnabled()) {
                                // logger.debug("Found no public spaces.");
                            }
                        }
                    }

                    // allow registration
                    if (clazz.equals(RegisterUserFormPage.class)) {
                        return true;
                    }
                    // not authenticated, go to login page
                    // logger.debug("not authenticated, forcing login, page requested was "
                    // + clazz.getName());
                    if (calipsoCasProxyTicketValidator != null) {
                        String serviceUrl = calipsoCasProxyTicketValidator.getLoginUrl();
                        //                              .getServiceProperties().getService();
                        String loginUrl = calipsoCasProxyTicketValidator.getLoginUrl();
                        // logger.debug("cas authentication: service URL: "
                        // + serviceUrl);
                        String redirectUrl = loginUrl + "?service=" + serviceUrl;
                        // logger.debug("attempting to redirect to: " +
                        // redirectUrl);
                        throw new RestartResponseAtInterceptPageException(new RedirectPage(redirectUrl));
                    } else {
                        throw new RestartResponseAtInterceptPageException(LoginPage.class);
                    }
                }
                return true;
            }
        });
        // TODO: create friendly URLs for all created pages
        // friendly URLs for selected pages
        if (calipsoCasProxyTicketValidator != null) {
            mountPage("/login", CasLoginPage.class);
        } else {
            mountPage("/login", LoginPage.class);
        }
        mountPage("/register", RegisterAnonymousUserFormPage.class);
        mountPage("/logout", LogoutPage.class);
        mountPage("/svn", SvnStatsPage.class);
        mountPage("/test", TestPage.class);
        mountPage("/casError", CasLoginErrorPage.class);
        mountPage("/item/", ItemViewPage.class);
        mountPage("/item/${itemId}", ItemViewPage.class);
        mountPage("/itemreport/", ItemTemplateViewPage.class);
        mountPage("/newItem/${spaceCode}", NewItemPage.class);
        //      MixedParamUrlCodingStrategy newItemUrls = new MixedParamUrlCodingStrategy(
        //                "/newItem",
        //                NewItemPage.class,
        //                new String[]{"spaceCode"}
        //        );
        //        mount(newItemUrls);

        //fix for tinyMCE bug, see https://github.com/wicketstuff/core/issues/113
        SecurePackageResourceGuard guard = (SecurePackageResourceGuard) getResourceSettings()
                .getPackageResourceGuard();
        guard.addPattern("+*.htm");

        this.getRequestCycleSettings().setTimeout(Duration.minutes(6));
        this.getPageSettings().setVersionPagesByDefault(true);
        this.getExceptionSettings().setThreadDumpStrategy(ThreadDumpStrategy.THREAD_HOLDING_LOCK);
    }

    @Override
    public Session newSession(Request request, Response response) {
        return new CalipsoSession(request);
    }

    @Override
    public Class getHomePage() {
        return DashboardPage.class;
    }

    public User authenticate(String loginName, String password) {
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(loginName, password);
        AuthenticationManager am = (AuthenticationManager) applicationContext.getBean("authenticationManager");
        User user = null;
        try {
            Authentication authentication = am.authenticate(token);
            user = (User) authentication.getPrincipal();
        } catch (AuthenticationException ae) {
            logger.error("Acegi authentication failed", ae);
            // ae.printStackTrace();
        }
        return user;
    }

    private boolean attemptRememberMeAutoLogin() {
        String value = new CookieUtils().load(REMEMBER_ME);
        if (StringUtils.isNotBlank(value)) {
            int index = value.indexOf(':');
            if (index > -1) {
                String loginName = value.substring(0, index);
                String encodedPassword = value.substring(index + 1);
                // logger.debug("valid cookie, attempting authentication");
                User user = (User) getCalipso().loadUserByUsername(loginName);
                if (encodedPassword.equals(user.getPassword())) {
                    ((CalipsoSession) Session.get()).setUser(user);
                    // user.setRoleSpaceStdFieldList(getJtrac().findSpaceFieldsForUser(user));
                    // ((CalipsoSession) Session.get()).setUser(user);

                    // logger.debug("remember me login success");
                    return true;
                }
            }
        }
        // no valid cookies were found
        return false;
    }

    public String getCalipsoPropertyValue(String property) {
        return this.calipsoPropertiesEditor.getValue(property);
    }

    @Override
    protected IConverterLocator newConverterLocator() {
        ConverterLocator locator = (ConverterLocator) super.newConverterLocator();
        locator.set(FieldConfig.class, new IConverter<FieldConfig>() {

            @Override
            public FieldConfig convertToObject(String value, Locale locale) {
                return FieldConfig.fromXML(value);
            }

            @Override
            public String convertToString(FieldConfig value, Locale locale) {
                return FieldConfig.toXML(value);
            }

        });
        return locator;
    }

    /**
     * Maps exceptions to pages.
     */
    @Override
    public IProvider<IExceptionMapper> getExceptionMapperProvider() {
        return new IProvider<IExceptionMapper>() {
            @Override
            public IExceptionMapper get() {
                return new IExceptionMapper() {
                    final DefaultExceptionMapper def = new DefaultExceptionMapper();

                    @Override
                    public IRequestHandler map(Exception ex) {
                        PageParameters par = new PageParameters().add("ex", ex);
                        boolean couldNotLock = false;
                        if (ex.getClass().equals(CouldNotLockPageException.class)) {
                            couldNotLock = true;
                        } else if (ex.getCause() != null
                                && (ex.getCause().getClass().equals(CouldNotLockPageException.class)
                                        || (ex.getCause().getCause() != null && ex.getCause().getCause().getClass()
                                                .equals(CouldNotLockPageException.class)))) {
                            couldNotLock = true;

                        }

                        if (couldNotLock) {
                            Request request = RequestCycle.get().getRequest();
                            HttpServletRequest httpRequest = ((ServletWebRequest) request).getContainerRequest();
                            logger.error("Page lock timed out, invalidating session");
                            if (httpRequest.getSession(false) != null) {
                                httpRequest.getSession().invalidate();
                            }
                            return new RenderPageRequestHandler(new PageProvider(LoginPage.class, par));
                        }
                        return def.map(ex);
                    }
                };
            }
        };
    }

}