com.bstek.dorado.web.loader.DoradoLoader.java Source code

Java tutorial

Introduction

Here is the source code for com.bstek.dorado.web.loader.DoradoLoader.java

Source

/*
 * This file is part of Dorado 7.x (http://dorado7.bsdn.org).
 * 
 * Copyright (c) 2002-2012 BSTEK Corp. All rights reserved.
 * 
 * This file is dual-licensed under the AGPLv3 (http://www.gnu.org/licenses/agpl-3.0.html) 
 * and BSDN commercial (http://www.bsdn.org/licenses) licenses.
 * 
 * If you are unsure which license is appropriate for your use, please contact the sales department
 * at http://www.bstek.com/contact.
 */

package com.bstek.dorado.web.loader;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Timer;
import java.util.TimerTask;

import javax.servlet.ServletContext;

import org.apache.commons.jexl2.JexlContext;
import org.apache.commons.jexl2.MapContext;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.web.util.WebUtils;

import com.bstek.dorado.core.Configure;
import com.bstek.dorado.core.ConfigureStore;
import com.bstek.dorado.core.Context;
import com.bstek.dorado.core.DoradoAbout;
import com.bstek.dorado.core.EngineStartupListenerManager;
import com.bstek.dorado.core.el.DefaultExpressionHandler;
import com.bstek.dorado.core.el.Expression;
import com.bstek.dorado.core.el.ExpressionHandler;
import com.bstek.dorado.core.io.LocationTransformerHolder;
import com.bstek.dorado.core.io.Resource;
import com.bstek.dorado.core.io.ResourceLoader;
import com.bstek.dorado.core.io.ResourceUtils;
import com.bstek.dorado.core.pkgs.PackageConfigurer;
import com.bstek.dorado.core.pkgs.PackageInfo;
import com.bstek.dorado.core.pkgs.PackageListener;
import com.bstek.dorado.core.pkgs.PackageManager;
import com.bstek.dorado.util.TempFileUtils;
import com.bstek.dorado.web.ConsoleUtils;
import com.bstek.dorado.web.DoradoContext;
import com.bstek.dorado.web.servlet.ServletContextResourceLoader;

public class DoradoLoader {
    private static final Log logger = LogFactory.getLog(DoradoLoader.class);

    private static final String CORE_PROPERTIES_LOCATION_PREFIX = "classpath:com/bstek/dorado/core/";
    private static final String HOME_LOCATION_PREFIX = "home:";
    private static final int HOME_LOCATION_PREFIX_LEN = HOME_LOCATION_PREFIX.length();

    private static final String DEFAULT_DORADO_HOME = "/WEB-INF/dorado-home";
    private static final String RESOURCE_LOADER_PROPERTY = "core.resourceLoader";
    private static final String BYTE_CODE_PROVIDER_PROPERTY = "core.defaultByteCodeProvider";

    private static final String HOME_PROPERTY = "core.doradoHome";
    private static final String CONTEXT_CONFIG_PROPERTY = "core.contextConfigLocation";
    private static final String SERVLET_CONTEXT_CONFIG_PROPERTY = "core.servletContextConfigLocation";

    private static final String CONTEXT_CONFIG_LOCATION = "contextConfigLocation";
    private static final String SERVLET_CONTEXT_CONFIG_LOCATION = "servletContextConfigLocation";

    private static final String CONTEXT_FILE_EXT = ".xml";
    private static final String HOME_CONTEXT_PREFIX = HOME_LOCATION_PREFIX + "context";
    private static final String HOME_CONTEXT_XML = HOME_CONTEXT_PREFIX + CONTEXT_FILE_EXT;
    private static final String HOME_SERVLET_CONTEXT_PREFIX = HOME_LOCATION_PREFIX + "servlet-context";
    private static final String HOME_SERVLET_CONTEXT_XML = HOME_SERVLET_CONTEXT_PREFIX + CONTEXT_FILE_EXT;

    private boolean preloaded;
    private boolean loaded;
    private String doradoHome;
    private List<String> contextLocations = new ArrayList<String>();
    private List<String> servletContextLocations = new ArrayList<String>();

    private DoradoLoader() {
    }

    private static class SingletonHolder {
        public static DoradoLoader instance = new DoradoLoader();
    }

    public static DoradoLoader getInstance() {
        return SingletonHolder.instance;
    }

    public String[] getRealResourcesPath(List<String> locations) throws IOException {
        if (locations == null || locations.isEmpty()) {
            return null;
        }
        List<String> result = new ArrayList<String>();
        for (String location : locations) {
            if (StringUtils.isNotEmpty(location)) {
                result.add(location);
            }
        }
        return result.toArray(new String[0]);
    }

    private void pushLocation(List<String> locationList, String location) {
        if (StringUtils.isNotEmpty(location)) {
            location = LocationTransformerHolder.transformLocation(location);
            locationList.add(location);
        }
    }

    private void pushLocations(List<String> locationList, String locations) {
        if (StringUtils.isNotEmpty(locations)) {
            for (String location : org.springframework.util.StringUtils.tokenizeToStringArray(locations,
                    ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS)) {
                pushLocation(locationList, location);
            }
        }
    }

    private void loadConfigureProperties(ConfigureStore configureStore, ResourceLoader resourceLoader,
            String configureLocation, boolean silence) throws IOException {
        // ??
        ConsoleUtils.outputLoadingInfo("Loading configure from [" + configureLocation + "]...");
        if (StringUtils.isNotEmpty(configureLocation)) {
            Resource resource = resourceLoader.getResource(configureLocation);
            if (!resource.exists()) {
                if (silence) {
                    logger.warn("Can not found resource [" + configureLocation + "].");
                    return;
                } else {
                    throw new IOException("Can not found resource [" + configureLocation + "].");
                }
            }
            InputStream in = resource.getInputStream();
            Properties properties = new Properties();
            try {
                properties.load(in);
            } finally {
                in.close();
            }

            ExpressionHandler expressionHandler = new DefaultExpressionHandler() {
                @Override
                public JexlContext getJexlContext() {
                    JexlContext elContext = new MapContext();
                    elContext.set("env", System.getenv());
                    return elContext;
                }
            };

            for (Map.Entry<?, ?> entry : properties.entrySet()) {
                String text = (String) entry.getValue();
                Object value = text;
                if (StringUtils.isNotEmpty(text)) {
                    Expression expression = expressionHandler.compile(text);
                    if (expression != null) {
                        value = expression.evaluate();
                    }
                }
                configureStore.set((String) entry.getKey(), value);
            }
        }
    }

    public boolean isPreloaded() {
        return preloaded;
    }

    public boolean isLoaded() {
        return loaded;
    }

    public String getDoradoHome() {
        return doradoHome;
    }

    public List<String> getContextLocations(boolean toRealPath) {
        return contextLocations;
    }

    public List<String> getServletContextLocations(boolean toRealPath) {
        return servletContextLocations;
    }

    public synchronized void preload(ServletContext servletContext, boolean processOriginContextConfigLocation)
            throws Exception {
        if (preloaded) {
            throw new IllegalStateException("Dorado base configurations already loaded.");
        }
        preloaded = true;

        // ?
        ConsoleUtils.outputLoadingInfo("Initializing " + DoradoAbout.getProductTitle() + " engine...");
        ConsoleUtils.outputLoadingInfo("[Vendor: " + DoradoAbout.getVendor() + "]");

        ConfigureStore configureStore = Configure.getStore();
        doradoHome = System.getenv("DORADO_HOME");

        // ?DoradoHome
        String intParam;
        intParam = servletContext.getInitParameter("doradoHome");
        if (intParam != null) {
            doradoHome = intParam;
        }
        if (doradoHome == null) {
            doradoHome = DEFAULT_DORADO_HOME;
        }

        configureStore.set(HOME_PROPERTY, doradoHome);
        ConsoleUtils.outputLoadingInfo("[Home: " + StringUtils.defaultString(doradoHome, "<not assigned>") + "]");

        // ResourceLoader
        ResourceLoader resourceLoader = new ServletContextResourceLoader(servletContext) {
            @Override
            public Resource getResource(String resourceLocation) {
                if (resourceLocation != null && resourceLocation.startsWith(HOME_LOCATION_PREFIX)) {
                    resourceLocation = ResourceUtils.concatPath(doradoHome,
                            resourceLocation.substring(HOME_LOCATION_PREFIX_LEN));
                }
                return super.getResource(resourceLocation);
            }
        };

        String runMode = null;
        if (StringUtils.isNotEmpty(doradoHome)) {
            String configureLocation = HOME_LOCATION_PREFIX + "configure.properties";
            loadConfigureProperties(configureStore, resourceLoader, configureLocation, false);
        }

        runMode = configureStore.getString("core.runMode");

        if (StringUtils.isNotEmpty(runMode)) {
            loadConfigureProperties(configureStore, resourceLoader,
                    CORE_PROPERTIES_LOCATION_PREFIX + "configure-" + runMode + ".properties", true);

            if (StringUtils.isNotEmpty(doradoHome)) {
                loadConfigureProperties(configureStore, resourceLoader,
                        HOME_LOCATION_PREFIX + "configure-" + runMode + ".properties", true);
            }
        }

        ConsoleUtils.outputConfigureItem("core.runMode");
        ConsoleUtils.outputConfigureItem("core.addonLoadMode");

        File tempDir;
        String tempDirPath = configureStore.getString("core.tempDir");
        if (StringUtils.isNotBlank(tempDirPath)) {
            tempDir = new File(tempDirPath);
        } else {
            tempDir = new File(WebUtils.getTempDir(servletContext), ".dorado");
        }

        boolean supportsTempFile = configureStore.getBoolean("core.supportsTempFile");
        TempFileUtils.setSupportsTempFile(supportsTempFile);
        if (supportsTempFile) {
            if ((tempDir.exists() && tempDir.isDirectory()) || tempDir.mkdir()) {
                TempFileUtils.setTempDir(tempDir);
            }
            ConsoleUtils.outputLoadingInfo("[TempDir: " + TempFileUtils.getTempDir().getPath() + "]");
        } else {
            ConsoleUtils.outputLoadingInfo("Temp file is forbidden.");
        }

        // 
        File storeDir;
        String storeDirSettring = configureStore.getString("core.storeDir");
        if (StringUtils.isNotEmpty(storeDirSettring)) {
            storeDir = new File(storeDirSettring);
            File testFile = new File(storeDir, ".test");
            if (!testFile.mkdirs()) {
                throw new IllegalStateException(
                        "Store directory [" + storeDir.getAbsolutePath() + "] is not writable in actually.");
            }
            testFile.delete();
        } else {
            storeDir = new File(tempDir, "dorado-store");
            configureStore.set("core.storeDir", storeDir.getAbsolutePath());
        }
        ConsoleUtils.outputConfigureItem("core.storeDir");

        // gothrough packages
        String addonLoadMode = Configure.getString("core.addonLoadMode");
        String[] enabledAddons = StringUtils.split(Configure.getString("core.enabledAddons"), ",; \n\r");
        String[] disabledAddon = StringUtils.split(Configure.getString("core.disabledAddon"), ",; \n\r");

        Collection<PackageInfo> packageInfos = PackageManager.getPackageInfoMap().values();
        int addonNumber = 0;
        for (PackageInfo packageInfo : packageInfos) {
            String packageName = packageInfo.getName();
            if (packageName.equals("dorado-core")) {
                continue;
            }

            if (addonNumber > 9999) {
                packageInfo.setEnabled(false);
            } else if (StringUtils.isEmpty(addonLoadMode) || "positive".equals(addonLoadMode)) {
                packageInfo.setEnabled(!ArrayUtils.contains(disabledAddon, packageName));
            } else {
                // addonLoadMode == negative
                packageInfo.setEnabled(ArrayUtils.contains(enabledAddons, packageName));
            }

            if (packageInfo.isEnabled()) {
                addonNumber++;
            }
        }

        // print packages
        int i = 0;
        for (PackageInfo packageInfo : packageInfos) {
            ConsoleUtils.outputLoadingInfo(
                    StringUtils.rightPad(String.valueOf(++i) + '.', 4) + "Package [" + packageInfo.getName() + " - "
                            + StringUtils.defaultIfBlank(packageInfo.getVersion(), "<Unknown Version>") + "] found."
                            + ((packageInfo.isEnabled() ? "" : " #DISABLED# ")));
        }

        // load packages
        for (PackageInfo packageInfo : packageInfos) {
            if (!packageInfo.isEnabled()) {
                pushLocations(contextLocations, packageInfo.getComponentLocations());
                continue;
            }

            PackageListener packageListener = packageInfo.getListener();
            if (packageListener != null) {
                packageListener.beforeLoadPackage(packageInfo, resourceLoader);
            }

            PackageConfigurer packageConfigurer = packageInfo.getConfigurer();

            if (StringUtils.isNotEmpty(packageInfo.getPropertiesLocations())) {
                for (String location : org.springframework.util.StringUtils.tokenizeToStringArray(
                        packageInfo.getPropertiesLocations(),
                        ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS)) {
                    loadConfigureProperties(configureStore, resourceLoader, location, false);
                }
            }

            String[] locations;
            if (packageConfigurer != null) {
                locations = packageConfigurer.getPropertiesConfigLocations(resourceLoader);
                if (locations != null) {
                    for (String location : locations) {
                        loadConfigureProperties(configureStore, resourceLoader, location, false);
                    }
                }
            }

            // ?Spring?
            pushLocations(contextLocations, packageInfo.getContextLocations());
            if (packageConfigurer != null) {
                locations = packageConfigurer.getContextConfigLocations(resourceLoader);
                if (locations != null) {
                    for (String location : locations) {
                        pushLocation(contextLocations, location);
                    }
                }
            }

            pushLocations(servletContextLocations, packageInfo.getServletContextLocations());
            if (packageConfigurer != null) {
                locations = packageConfigurer.getServletContextConfigLocations(resourceLoader);
                if (locations != null) {
                    for (String location : locations) {
                        pushLocation(servletContextLocations, location);
                    }
                }
            }

            packageInfo.setLoaded(true);
        }

        // ?dorado-homepropertiesaddon
        if (StringUtils.isNotEmpty(doradoHome)) {
            String configureLocation = HOME_LOCATION_PREFIX + "configure.properties";
            loadConfigureProperties(configureStore, resourceLoader, configureLocation, true);
            if (StringUtils.isNotEmpty(runMode)) {
                loadConfigureProperties(configureStore, resourceLoader,
                        CORE_PROPERTIES_LOCATION_PREFIX + "configure-" + runMode + ".properties", true);
                loadConfigureProperties(configureStore, resourceLoader,
                        HOME_LOCATION_PREFIX + "configure-" + runMode + ".properties", true);
            }
        }

        Resource resource;

        // context
        if (processOriginContextConfigLocation) {
            intParam = servletContext.getInitParameter(CONTEXT_CONFIG_LOCATION);
            if (intParam != null) {
                pushLocations(contextLocations, intParam);
            }
        }

        resource = resourceLoader.getResource(HOME_CONTEXT_XML);
        if (resource.exists()) {
            pushLocations(contextLocations, HOME_CONTEXT_XML);
        }

        if (StringUtils.isNotEmpty(runMode)) {
            String extHomeContext = HOME_CONTEXT_PREFIX + '-' + runMode + CONTEXT_FILE_EXT;
            resource = resourceLoader.getResource(extHomeContext);
            if (resource.exists()) {
                pushLocations(contextLocations, extHomeContext);
            }
        }

        // servlet-context
        intParam = servletContext.getInitParameter(SERVLET_CONTEXT_CONFIG_LOCATION);
        if (intParam != null) {
            pushLocations(servletContextLocations, intParam);
        }
        resource = resourceLoader.getResource(HOME_SERVLET_CONTEXT_XML);
        if (resource.exists()) {
            pushLocations(servletContextLocations, HOME_SERVLET_CONTEXT_XML);
        }

        if (StringUtils.isNotEmpty(runMode)) {
            String extHomeContext = HOME_SERVLET_CONTEXT_PREFIX + '-' + runMode + CONTEXT_FILE_EXT;
            resource = resourceLoader.getResource(extHomeContext);
            if (resource.exists()) {
                pushLocations(servletContextLocations, extHomeContext);
            }
        }

        ConsoleUtils.outputConfigureItem(RESOURCE_LOADER_PROPERTY);
        ConsoleUtils.outputConfigureItem(BYTE_CODE_PROVIDER_PROPERTY);

        String contextLocationsFromProperties = configureStore.getString(CONTEXT_CONFIG_PROPERTY);
        if (contextLocationsFromProperties != null) {
            pushLocations(contextLocations, contextLocationsFromProperties);
        }
        configureStore.set(CONTEXT_CONFIG_PROPERTY, StringUtils.join(getRealResourcesPath(contextLocations), ';'));
        ConsoleUtils.outputConfigureItem(CONTEXT_CONFIG_PROPERTY);

        String serlvetContextLocationsFromProperties = configureStore.getString(SERVLET_CONTEXT_CONFIG_PROPERTY);
        if (serlvetContextLocationsFromProperties != null) {
            pushLocations(servletContextLocations, serlvetContextLocationsFromProperties);
        }
        configureStore.set(SERVLET_CONTEXT_CONFIG_PROPERTY,
                StringUtils.join(getRealResourcesPath(servletContextLocations), ';'));
        ConsoleUtils.outputConfigureItem(SERVLET_CONTEXT_CONFIG_PROPERTY);

        // ?WebContext
        DoradoContext context = DoradoContext.init(servletContext, false);
        Context.setFailSafeContext(context);
    }

    public synchronized void load(ServletContext servletContext) throws Exception {
        if (!preloaded) {
            throw new IllegalStateException("Can not load dorado services before base configurations loaded.");
        }

        if (loaded) {
            throw new IllegalStateException("Dorado services already loaded.");
        }
        loaded = true;

        EngineStartupListenerManager.notifyStartup();

        ConsoleStartedMessagesOutputter consoleStartedMessagesOutputter = (ConsoleStartedMessagesOutputter) DoradoContext
                .getCurrent().getServiceBean("consoleStartedMessagesOutputter");
        StringWriter buffer = new StringWriter();
        try {
            consoleStartedMessagesOutputter.output(buffer);
        } finally {
            buffer.close();
        }
        DoradoContext.dispose();

        Timer timer = new Timer();
        timer.schedule(new ConsoleMessageTimerTask(buffer.toString()), 500L);
    }
}

class ConsoleMessageTimerTask extends TimerTask {
    private static final Log logger = LogFactory.getLog(ConsoleMessageTimerTask.class);

    private String content;

    public ConsoleMessageTimerTask(String content) {
        this.content = content;
    }

    @Override
    public void run() {
        try {
            System.out.print(content);
        } catch (Exception e) {
            logger.error(e, e);
        }
    }
}