org.projectforge.web.wicket.WicketApplication.java Source code

Java tutorial

Introduction

Here is the source code for org.projectforge.web.wicket.WicketApplication.java

Source

/////////////////////////////////////////////////////////////////////////////
//
// Project ProjectForge Community Edition
//         www.projectforge.org
//
// Copyright (C) 2001-2013 Kai Reinhard (k.reinhard@micromata.de)
//
// ProjectForge is dual-licensed.
//
// This community edition is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation; version 3 of the License.
//
// This community edition 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 General
// Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, see http://www.gnu.org/licenses/.
//
/////////////////////////////////////////////////////////////////////////////

package org.projectforge.web.wicket;

import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.TimeZone;

import javax.servlet.ServletContext;

import net.fortuna.ical4j.util.CompatibilityHints;

import org.apache.commons.lang.StringUtils;
import org.apache.wicket.Application;
import org.apache.wicket.ConverterLocator;
import org.apache.wicket.IConverterLocator;
import org.apache.wicket.Page;
import org.apache.wicket.RuntimeConfigurationType;
import org.apache.wicket.Session;
import org.apache.wicket.core.request.handler.PageProvider;
import org.apache.wicket.core.request.handler.RenderPageRequestHandler;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.protocol.http.PageExpiredException;
import org.apache.wicket.protocol.http.WebApplication;
import org.apache.wicket.request.IRequestHandler;
import org.apache.wicket.request.Request;
import org.apache.wicket.request.Response;
import org.apache.wicket.request.cycle.AbstractRequestCycleListener;
import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.wicket.resource.loader.BundleStringResourceLoader;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.apache.wicket.spring.injection.annot.SpringComponentInjector;
import org.apache.wicket.util.lang.Bytes;
import org.projectforge.AppVersion;
import org.projectforge.admin.SystemUpdater;
import org.projectforge.common.BeanHelper;
import org.projectforge.common.ExceptionHelper;
import org.projectforge.core.ConfigXml;
import org.projectforge.core.Configuration;
import org.projectforge.core.ConfigurationDao;
import org.projectforge.core.CronSetup;
import org.projectforge.core.SystemInfoCache;
import org.projectforge.database.DatabaseUpdateDao;
import org.projectforge.database.HibernateUtils;
import org.projectforge.plugins.core.PluginsRegistry;
import org.projectforge.registry.DaoRegistry;
import org.projectforge.storage.StorageClient;
import org.projectforge.user.Login;
import org.projectforge.user.LoginDefaultHandler;
import org.projectforge.user.LoginHandler;
import org.projectforge.user.PFUserContext;
import org.projectforge.user.UserDao;
import org.projectforge.user.UserXmlPreferencesCache;
import org.projectforge.web.UserFilter;
import org.projectforge.web.WebConfiguration;
import org.projectforge.web.calendar.CalendarPage;
import org.projectforge.web.registry.WebRegistry;
import org.projectforge.web.wicket.converter.MyDateConverter;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.orm.hibernate3.LocalSessionFactoryBean;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.context.support.XmlWebApplicationContext;

import de.micromata.less.LessWicketApplicationInstantiator;

/**
 * Application object for your web application. If you want to run this application without deploying, run the Start class.
 * 
 * @see org.projectforge.web.AbstractStartHelper.demo.Start#main(String[])
 */
public class WicketApplication extends WebApplication implements WicketApplicationInterface {
    // If you change this you have to change this also in PFApplication. This is used for updating the hsqldb.
    // private static final String SYSTEM_PROPERTY_HSQLDB_18_UPDATE = "hsqldb18Update";

    private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(WicketApplication.class);

    public static final String RESOURCE_BUNDLE_NAME = "I18nResources";

    static Class<? extends WebPage> DEFAULT_PAGE = CalendarPage.class;

    private static Boolean developmentMode;

    private static Boolean stripWicketTags;

    private static String alertMessage;

    private static Map<Class<? extends Page>, String> mountedPages = new HashMap<Class<? extends Page>, String>();

    @SpringBean(name = "wicketApplicationFilter")
    private WicketApplicationFilter wicketApplicationFilter;

    private UserXmlPreferencesCache userXmlPreferencesCache;

    @SpringBean(name = "configurationDao")
    private ConfigurationDao configurationDao;

    private ConfigXml configXml;

    private Configuration configuration;

    @SpringBean(name = "cronSetup")
    private CronSetup cronSetup;

    @SpringBean(name = "daoRegistry")
    private DaoRegistry daoRegistry;

    @SpringBean(name = "systemUpdater")
    private SystemUpdater systemUpdater;

    @SpringBean(name = "userDao")
    private UserDao userDao;

    @SpringBean(name = "systemInfoCache")
    private SystemInfoCache systemInfoCache;

    private static long startTime = System.currentTimeMillis();

    /**
     * At application start the flag developmentMode is perhaps not already set. If possible please use {@link #isDevelopmentSystem()}
     * instead.<br/>
     * Please use {@link WebConfiguration#isDevelopmentMode()}.
     */
    public static Boolean internalIsDevelopmentMode() {
        return developmentMode;
    }

    /**
     * Please don't use this method, use {@link WicketUtils#getDefaultPage()} instead.
     * @return
     */
    public static Class<? extends WebPage> internalGetDefaultPage() {
        return DEFAULT_PAGE;
    }

    /**
     * Use this method only if you want to change the default page (if no other is defined in config.xml).
     * @param defaultPage
     */
    public static void setDefaultPage(final Class<? extends WebPage> defaultPage) {
        DEFAULT_PAGE = defaultPage;
    }

    public static String getBookmarkableMountPath(final Class<? extends Page> pageClass) {
        return mountedPages.get(pageClass);
    }

    public void setWicketApplicationFilter(final WicketApplicationFilter wicketApplicationFilter) {
        this.wicketApplicationFilter = wicketApplicationFilter;
    }

    public void setUserXmlPreferencesCache(final UserXmlPreferencesCache userXmlPreferencesCache) {
        this.userXmlPreferencesCache = userXmlPreferencesCache;
    }

    public void setConfigXml(final ConfigXml configXml) {
        this.configXml = configXml;
    }

    public void setConfiguration(final Configuration configuration) {
        this.configuration = configuration;
    }

    public void setConfigurationDao(final ConfigurationDao configurationDao) {
        this.configurationDao = configurationDao;
    }

    public void setCronSetup(final CronSetup cronSetup) {
        this.cronSetup = cronSetup;
    }

    public void setDaoRegistry(final DaoRegistry daoRegistry) {
        this.daoRegistry = daoRegistry;
    }

    public void setSystemUpdater(final SystemUpdater systemUpdater) {
        this.systemUpdater = systemUpdater;
    }

    public void setUserDao(final UserDao userDao) {
        this.userDao = userDao;
    }

    public void setSystemInfoCache(final SystemInfoCache systemInfoCache) {
        this.systemInfoCache = systemInfoCache;
    }

    /**
     * Returns the alert message, if exists. The alert message will be displayed on every screen (red on top) and is edit-able via
     * Administration -> System.
     */
    public static String getAlertMessage() {
        if (UserFilter.isUpdateRequiredFirst() == true) {
            return "Maintenance mode: Please restart ProjectForge after finishing."
                    + (alertMessage != null ? " " + alertMessage : "");
        } else {
            return alertMessage;
        }
    }

    /**
     * @param alertMessage
     * @see #getAlertMessage()
     */
    public static void setAlertMessage(final String alertMessage) {
        WicketApplication.alertMessage = alertMessage;
    }

    /**
     * Constructor
     */
    public WicketApplication() {
        super();
    }

    /**
     * Own solution: uses development parameter of servlet context init parameter (see context.xml or server.xml).
     * @return DEVELOPMENT, if development variable of servlet context is set to "true" otherwise DEPLOYMENT.
     * @see org.apache.wicket.protocol.http.WebApplication#getConfigurationType()
     */
    @Override
    public RuntimeConfigurationType getConfigurationType() {
        if (isDevelopmentSystem() == true) {
            return RuntimeConfigurationType.DEVELOPMENT;
        }
        return RuntimeConfigurationType.DEPLOYMENT;
    }

    @Override
    protected void init() {
        super.init();
        // Own error page for deployment mode and UserException and AccessException.
        getRequestCycleListeners().add(new AbstractRequestCycleListener() {
            /**
             * Log only non ProjectForge exceptions.
             * @see org.apache.wicket.request.cycle.AbstractRequestCycleListener#onException(org.apache.wicket.request.cycle.RequestCycle,
             *      java.lang.Exception)
             */
            @Override
            public IRequestHandler onException(final RequestCycle cycle, final Exception ex) {
                // in case of expired session, please redirect to home page
                if (ex instanceof PageExpiredException) {
                    return new RenderPageRequestHandler(new PageProvider(getHomePage()));
                }
                final Throwable rootCause = ExceptionHelper.getRootCause(ex);
                // log.error(rootCause.getMessage(), ex);
                // if (rootCause instanceof ProjectForgeException == false) {
                // return super.onException(cycle, ex);
                // }
                // return null;
                if (isDevelopmentSystem() == true) {
                    log.error(ex.getMessage(), ex);
                    if (rootCause instanceof SQLException) {
                        SQLException next = (SQLException) rootCause;
                        while ((next = next.getNextException()) != null) {
                            log.error(next.getMessage(), next);
                        }
                    }
                    return super.onException(cycle, ex);
                } else {
                    // Show always this error page in production mode:
                    return new RenderPageRequestHandler(new PageProvider(new ErrorPage(ex)));
                }
            }
        });

        getApplicationSettings().setDefaultMaximumUploadSize(Bytes.megabytes(100));
        getMarkupSettings().setDefaultMarkupEncoding("utf-8");
        final MyAuthorizationStrategy authStrategy = new MyAuthorizationStrategy();
        getSecuritySettings().setAuthorizationStrategy(authStrategy);
        getSecuritySettings().setUnauthorizedComponentInstantiationListener(authStrategy);
        // Prepend the resource bundle for overwriting some Wicket default localizations (such as StringValidator.*)
        getResourceSettings().getStringResourceLoaders().add(new BundleStringResourceLoader(RESOURCE_BUNDLE_NAME));
        getResourceSettings().setThrowExceptionOnMissingResource(false); // Don't throw MissingResourceException for missing i18n keys.
        getApplicationSettings().setPageExpiredErrorPage(PageExpiredPage.class); // Don't show expired page.
        // getSessionSettings().setMaxPageMaps(20); // Map up to 20 pages per session (default is 5).
        getComponentInstantiationListeners().add(new SpringComponentInjector(this));
        getApplicationSettings().setInternalErrorPage(ErrorPage.class);
        // getRequestCycleSettings().setGatherExtendedBrowserInfo(true); // For getting browser width and height.

        // Select2:
        // final ApplicationSettings select2Settings = ApplicationSettings.get();
        // select2Settings.setIncludeJavascript(false);

        final XmlWebApplicationContext webApplicationContext = (XmlWebApplicationContext) WebApplicationContextUtils
                .getWebApplicationContext(getServletContext());
        final ConfigurableListableBeanFactory beanFactory = webApplicationContext.getBeanFactory();
        beanFactory.autowireBeanProperties(this, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, false);
        final LocalSessionFactoryBean localSessionFactoryBean = (LocalSessionFactoryBean) beanFactory
                .getBean("&sessionFactory");

        // if ("true".equals(System.getProperty(SYSTEM_PROPERTY_HSQLDB_18_UPDATE)) == true) {
        // try {
        // log.info("Send SHUTDOWN COMPACT to upgrade data-base version:");
        // final DataSource dataSource = (DataSource)beanFactory.getBean("dataSource");
        // dataSource.getConnection().createStatement().execute("SHUTDOWN COMPACT");
        // log.fatal("************ PLEASE RESTART APPLICATION NOW FOR PROPER INSTALLATION !!!!!!!!!!!!!! ************");
        // return;
        // } catch (final SQLException ex) {
        // log.fatal("Data-base SHUTDOWN COMPACT failed: " + ex.getMessage());
        // }
        // }
        final org.hibernate.cfg.Configuration hibernateConfiguration = localSessionFactoryBean.getConfiguration();
        HibernateUtils.setConfiguration(hibernateConfiguration);
        final ServletContext servletContext = getServletContext();
        final String configContextPath = configXml.getServletContextPath();
        String contextPath;
        if (StringUtils.isBlank(configContextPath) == true) {
            contextPath = servletContext.getContextPath();
            configXml.setServletContextPath(contextPath);
        } else {
            contextPath = configContextPath;
        }
        log.info("Using servlet context path: " + contextPath);
        if (configuration.getBeanFactory() == null) {
            configuration.setBeanFactory(beanFactory);
        }
        configuration.setConfigurationDao(configurationDao);
        SystemInfoCache.internalInitialize(systemInfoCache);
        WicketUtils.setContextPath(contextPath);
        UserFilter.initialize(userDao, contextPath);
        if (this.wicketApplicationFilter != null) {
            this.wicketApplicationFilter.setApplication(this);
        } else {
            throw new RuntimeException("this.wicketApplicationFilter is null");
        }
        daoRegistry.init();

        final PluginsRegistry pluginsRegistry = PluginsRegistry.instance();
        pluginsRegistry.set(beanFactory, getResourceSettings());
        pluginsRegistry.set(systemUpdater);
        pluginsRegistry.initialize();

        for (final Map.Entry<String, Class<? extends WebPage>> mountPage : WebRegistry.instance().getMountPages()
                .entrySet()) {
            final String path = mountPage.getKey();
            final Class<? extends WebPage> pageClass = mountPage.getValue();
            mountPage(path, pageClass);
            mountedPages.put(pageClass, path);
        }
        if (isDevelopmentSystem() == true) {
            if (isStripWicketTags() == true) {
                log.info("Strip Wicket tags also in development mode at default (see context.xml).");
                Application.get().getMarkupSettings().setStripWicketTags(true);
            }
            getDebugSettings().setOutputMarkupContainerClassName(true);
        }
        log.info("Default TimeZone is: " + TimeZone.getDefault());
        if ("UTC".equals(TimeZone.getDefault().getID()) == false) {
            for (final String str : UTC_RECOMMENDED) {
                log.fatal(str);
            }
            for (final String str : UTC_RECOMMENDED) {
                System.err.println(str);
            }
        }
        log.info("user.timezone is: " + System.getProperty("user.timezone"));
        cronSetup.initialize();
        log.info(AppVersion.APP_ID + " " + AppVersion.NUMBER + " (" + AppVersion.RELEASE_TIMESTAMP
                + ") initialized.");

        PFUserContext.setUser(DatabaseUpdateDao.__internalGetSystemAdminPseudoUser()); // Logon admin user.
        if (systemUpdater.isUpdated() == false) {
            // Force redirection to update page:
            UserFilter.setUpdateRequiredFirst(true);
        }
        PFUserContext.setUser(null);
        UserXmlPreferencesCache.setInternalInstance(userXmlPreferencesCache);
        LoginHandler loginHandler;
        if (StringUtils.isNotBlank(configXml.getLoginHandlerClass()) == true) {
            loginHandler = (LoginHandler) BeanHelper.newInstance(configXml.getLoginHandlerClass());
        } else {
            loginHandler = new LoginDefaultHandler();
        }
        if (loginHandler == null) {
            log.error("Can't load login handler '" + configXml.getLoginHandlerClass()
                    + "'. No login will be possible!");
        } else {
            loginHandler.initialize();
            Login.getInstance().setLoginHandler(loginHandler);
        }
        try {
            StorageClient.getInstance(); // Initialize storage
        } catch (final Exception ex) {
            log.error(ex.getMessage(), ex);
        }
        getPageSettings().setRecreateMountedPagesAfterExpiry(false);

        // initialize ical4j to be more "relaxed"
        CompatibilityHints.setHintEnabled(CompatibilityHints.KEY_RELAXED_PARSING, true);
        CompatibilityHints.setHintEnabled(CompatibilityHints.KEY_RELAXED_UNFOLDING, true);
        CompatibilityHints.setHintEnabled(CompatibilityHints.KEY_RELAXED_VALIDATION, true);

        // initialize styles compiler
        try {
            final LessWicketApplicationInstantiator lessInstantiator = new LessWicketApplicationInstantiator(this,
                    "styles", "projectforge.less", "projectforge.css");
            lessInstantiator.instantiate();
        } catch (final Exception e) {
            log.error("Unable to instantiate wicket less compiler", e);
        }
    }

    @Override
    protected void onDestroy() {
        log.info("Syncing all user preferences to database.");
        userXmlPreferencesCache.forceReload();
        cronSetup.shutdown();
        log.info("Destroyed");
    }

    /**
     * @return True if configured as servlet context param.
     */
    public boolean isDevelopmentSystem() {
        if (developmentMode == null) {
            final String value = getServletContext().getInitParameter("development");
            developmentMode = "true".equals(value);
            Configuration.getInstance().internalSetDevelopmentMode(developmentMode);
        }
        return developmentMode;
    }

    @Override
    public boolean isStripWicketTags() {
        if (stripWicketTags == null) {
            if (isDevelopmentSystem() == false) {
                stripWicketTags = true;
            } else {
                final String value = getServletContext().getInitParameter("stripWicketTags");
                stripWicketTags = "true".equals(value);
            }
        }
        return stripWicketTags;
    }

    /**
     * @see org.apache.wicket.Application#getHomePage()
     */
    @Override
    public Class<? extends WebPage> getHomePage() {
        return WicketUtils.getDefaultPage();
    }

    @Override
    public Session newSession(final Request request, final Response response) {
        final MySession mySession = new MySession(request);
        return mySession;
    }

    /**
     * From http://www.danwalmsley.com/2009/04/08/apache-wicket-on-google-app-engine-for-java/<br/>
     * Override the newSessionStore() method to return HttpSessionStore, because the default second level session store uses java.io.File,
     * which is sometimes not allowed.
     * @see org.apache.wicket.Application#newSessionStore()
     */
    /*
     * @Override protected ISessionStore newSessionStore() { return new org.apache.wicket.protocol.http.HttpSessionStore(this); }
     */

    /**
     * 
     */
    @Override
    protected IConverterLocator newConverterLocator() {
        final ConverterLocator converterLocator = new ConverterLocator();
        converterLocator.set(java.util.Date.class, new MyDateConverter());
        converterLocator.set(java.sql.Date.class, new MyDateConverter(java.sql.Date.class, "S-"));
        return converterLocator;
    }

    public static long getStartTime() {
        return startTime;
    }

    private static final String[] UTC_RECOMMENDED = { //
            "**********************************************************", //
            "***                                                    ***", //
            "*** It's highly recommended to start ProjectForge      ***", //
            "*** with TimeZone UTC. This default TimeZone has to be ***", //
            "*** set before any initialization of Hibernate!!!!     ***", //
            "*** You can do this e. g. in JAVA_OPTS etc.            ***", //
            "***                                                    ***", //
            "**********************************************************" };
}