com.bstek.dorado.data.config.ConfigurableDataConfigManager.java Source code

Java tutorial

Introduction

Here is the source code for com.bstek.dorado.data.config.ConfigurableDataConfigManager.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.data.config;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.bstek.dorado.config.ParseContext;
import com.bstek.dorado.config.xml.XmlParser;
import com.bstek.dorado.core.Context;
import com.bstek.dorado.core.io.Resource;
import com.bstek.dorado.core.io.ResourceUtils;
import com.bstek.dorado.core.xml.XmlDocumentBuilder;
import com.bstek.dorado.data.config.definition.DataProviderDefinition;
import com.bstek.dorado.data.config.definition.DataProviderDefinitionManager;
import com.bstek.dorado.data.config.definition.DataResolverDefinition;
import com.bstek.dorado.data.config.definition.DataResolverDefinitionManager;
import com.bstek.dorado.data.config.definition.DataTypeDefinition;
import com.bstek.dorado.data.config.definition.DataTypeDefinitionManager;
import com.bstek.dorado.data.config.xml.DataParseContext;

/**
 * ?????????
 * 
 * @author Benny Bao (mailto:benny.bao@bstek.com)
 * @since Feb 20, 2007
 */
public class ConfigurableDataConfigManager extends ReloadableDataConfigManagerSupport {
    private static final String[] EMPTY_LOCATION_ARRAY = new String[0];
    private static final String XML_SUFFIX = ".xml";
    private static final String MODEL_XML_SUFFIX = ".model" + XML_SUFFIX;
    private static final long ONE_SECOND = 1000L;
    private static final char WILDCARD = '*';

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

    private class RecalculateThread extends Thread {
        public RecalculateThread() {
            setDaemon(true);
        }

        @Override
        public void run() {
            try {
                while (true) {
                    sleep(recalcLocationsThreadIntervalSeconds * ONE_SECOND);
                    recalcConfigLocations();
                }
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }
    }

    private static class DocumentWrapper {
        private Object documentObject;
        private Resource resource;

        DocumentWrapper(Object documentObject, Resource resource) {
            this.documentObject = documentObject;
            this.resource = resource;
        }

        Object getDocumentObject() {
            return documentObject;
        }

        Resource getResource() {
            return resource;
        }

    }

    private XmlDocumentBuilder xmlDocumentBuilder;
    private XmlParser preloadParser;
    private List<String> configLocations;
    private String[] configLocationArray;
    private DataTypeDefinitionManager dataTypeDefinitionManager;
    private DataProviderDefinitionManager dataProviderDefinitionManager;
    private DataResolverDefinitionManager dataResolverDefinitionManager;
    private XmlParser dataObjectParserDispatcher;
    private boolean autoRecalculatePaths;
    private long recalcLocationsThreadIntervalSeconds;

    /**
     * XML?
     */
    public void setXmlDocumentBuilder(XmlDocumentBuilder xmlDocumentBuilder) {
        this.xmlDocumentBuilder = xmlDocumentBuilder;
    }

    /**
     * ?XML??
     */
    public void setPreloadParser(XmlParser preloadParser) {
        this.preloadParser = preloadParser;
    }

    /**
     * ??<br>
     * ???
     * 
     * @param configLocations
     *            ???String??
     */
    public void setConfigLocations(List<String> configLocations) {
        this.configLocations = null;
        addConfigLocations(configLocations);
    }

    public void addConfigLocation(String configLocation) {
        if (this.configLocations == null) {
            this.configLocations = new ArrayList<String>();
        }
        this.configLocations.add(StringUtils.trim(configLocation));
        configLocationArray = null;
    }

    /**
     * ??
     * 
     * @param configLocations
     *            ???String??
     */
    public void addConfigLocations(List<String> configLocations) {
        if (this.configLocations == null) {
            this.configLocations = new ArrayList<String>();
        }
        for (String location : configLocations) {
            this.configLocations.add(StringUtils.trim(location));
        }
        configLocationArray = null;
    }

    /**
     * DataType?
     */
    public void setDataTypeDefinitionManager(DataTypeDefinitionManager dataTypeDefinitionManager) {
        this.dataTypeDefinitionManager = dataTypeDefinitionManager;
    }

    /**
     * DataProvider?
     */
    public void setDataProviderDefinitionManager(DataProviderDefinitionManager dataProviderDefinitionManager) {
        this.dataProviderDefinitionManager = dataProviderDefinitionManager;
    }

    /**
     * DataResolver?
     */
    public void setDataResolverDefinitionManager(DataResolverDefinitionManager dataResolverDefinitionManager) {
        this.dataResolverDefinitionManager = dataResolverDefinitionManager;
    }

    public void setDataObjectParserDispatcher(XmlParser dataObjectParserDispatcher) {
        this.dataObjectParserDispatcher = dataObjectParserDispatcher;
    }

    public boolean isAutoRecalculatePaths() {
        return autoRecalculatePaths;
    }

    public void setAutoRecalculatePaths(boolean autoRecalculatePaths) {
        this.autoRecalculatePaths = autoRecalculatePaths;
    }

    /**
     * ??
     */
    public long getRecalcLocationsThreadIntervalSeconds() {
        return recalcLocationsThreadIntervalSeconds;
    }

    /**
     * ??
     */
    public void setRecalcLocationsThreadIntervalSeconds(long recalcLocationsThreadIntervalSeconds) {
        this.recalcLocationsThreadIntervalSeconds = recalcLocationsThreadIntervalSeconds;
    }

    /**
     * ??configLocations??????
     * 
     * @throws Exception
     */
    public void initialize() throws Exception {
        boolean shouldStartRecalculateThread = false;

        if (configLocations != null) {
            if (autoRecalculatePaths) {
                for (String location : configLocations) {
                    if (location.indexOf(WILDCARD) >= 0) {
                        shouldStartRecalculateThread = true;
                    }
                }
            }

            String[] locations = new String[configLocations.size()];
            configLocations.toArray(locations);
            loadConfigs(ResourceUtils.getResources(locations), true);
        }

        if (isUseAutoReloadThread() && isAutoReloadEnabled()) {
            startValidateThead();

            if (autoRecalculatePaths && shouldStartRecalculateThread) {
                RecalculateThread recalculateThread = new RecalculateThread();
                recalculateThread.start();
            }
        }
    }

    @Override
    protected boolean internalLoadConfig(Resource[] resources) throws Exception {
        // Resource?
        DocumentWrapper[] documents = getDocuments(resources);

        DataParseContext parseContext = new DataParseContext();
        parseContext.setDataTypeDefinitionManager(dataTypeDefinitionManager);
        parseContext.setDataProviderDefinitionManager(dataProviderDefinitionManager);
        parseContext.setDataResolverDefinitionManager(dataResolverDefinitionManager);
        boolean changed = false;

        // ?DataTypeDataProvider
        for (DocumentWrapper wrapper : documents) {
            Resource resource = wrapper.getResource();
            parseContext.setResource(resource);

            String path = resource.getPath(), resourceName = null;
            if (StringUtils.isNotEmpty(path)) {
                if (path.endsWith(MODEL_XML_SUFFIX)) {
                    resourceName = path.substring(0, path.length() - MODEL_XML_SUFFIX.length());
                } else if (path.endsWith(XML_SUFFIX)) {
                    resourceName = path.substring(0, path.length() - XML_SUFFIX.length());
                }
            }
            parseContext.setResourceName(resourceName);

            Object documentObject = wrapper.getDocumentObject();
            if (documentObject instanceof Document) {
                preloadConfig((Document) documentObject, parseContext);
            }
        }

        dataObjectParserDispatcher.parse(null, parseContext);

        Map<String, DataTypeDefinition> parsedDataTypes = parseContext.getParsedDataTypes();
        if (!parsedDataTypes.isEmpty()) {
            StringBuffer message = new StringBuffer();
            boolean needComma = false;
            message.append("Registered DataTypes: [");
            synchronized (dataTypeDefinitionManager) {
                for (Map.Entry<String, DataTypeDefinition> entry : parsedDataTypes.entrySet()) {
                    String name = entry.getKey();
                    dataTypeDefinitionManager.registerDefinition(name, entry.getValue());

                    if (needComma) {
                        message.append(", ");
                    }
                    needComma = true;
                    message.append(name);
                }

                for (DataTypeDefinition dataTypeDefinition : parsedDataTypes.values()) {
                    try {
                        dataTypeDefinitionManager.registerMatchType(dataTypeDefinition);
                    } catch (Exception e) {
                        logger.warn(e, e);
                    }
                }
            }
            message.append("]");
            logger.info(message.toString());
        }

        Map<String, DataProviderDefinition> parsedDataProviders = parseContext.getParsedDataProviders();
        if (!parsedDataProviders.isEmpty()) {
            StringBuffer message = new StringBuffer();
            boolean needComma = false;
            message.append("Registered DataProviders: [");
            synchronized (dataProviderDefinitionManager) {
                for (Map.Entry<String, DataProviderDefinition> entry : parsedDataProviders.entrySet()) {
                    String name = entry.getKey();
                    dataProviderDefinitionManager.registerDefinition(name, entry.getValue());

                    if (needComma) {
                        message.append(", ");
                    }
                    needComma = true;
                    message.append(name);
                }
            }
            message.append("]");
            logger.info(message.toString());
        }

        Map<String, DataResolverDefinition> parsedDataResolvers = parseContext.getParsedDataResolvers();
        if (!parsedDataResolvers.isEmpty()) {
            StringBuffer message = new StringBuffer();
            boolean needComma = false;
            message.append("Registered DataResolvers: [");
            synchronized (dataResolverDefinitionManager) {
                for (Map.Entry<String, DataResolverDefinition> entry : parsedDataResolvers.entrySet()) {
                    String name = entry.getKey();
                    dataResolverDefinitionManager.registerDefinition(name, entry.getValue());

                    if (needComma) {
                        message.append(", ");
                    }
                    needComma = true;
                    message.append(name);
                }
            }
            message.append("]");
            logger.info(message.toString());
        }
        return changed;
    }

    private DocumentWrapper[] getDocuments(Resource[] resources) throws Exception {
        List<DocumentWrapper> documentList = new ArrayList<DocumentWrapper>();
        for (Resource resource : resources) {
            if (resource.exists()) {
                String filename = resource.getFilename().toLowerCase();
                if (filename.endsWith(XML_SUFFIX)) {
                    Document document = xmlDocumentBuilder.loadDocument(resource);
                    documentList.add(new DocumentWrapper(document, resource));
                } else {
                    logger.warn("Unsupported data configure - [" + resource + "]");
                }
            } else {
                logger.warn("File not exists - [" + resource + "]");
            }
        }
        return documentList.toArray(new DocumentWrapper[0]);
    }

    /**
     * ??? ??????
     * 
     * @param document
     *            XMLDOM
     * @param parseContext
     *            ?
     * @throws Exception
     */
    protected void preloadConfig(Document document, ParseContext context) throws Exception {
        Element documentElement = document.getDocumentElement();
        preloadParser.parse(documentElement, context);
    }

    @Override
    protected boolean internalUnloadConfigs(Resource[] resources) throws Exception {
        Set<Resource> resourceSet = new HashSet<Resource>();
        for (Resource resouce : resources) {
            resourceSet.add(resouce);
        }

        // DataType
        Set<DataTypeDefinition> dataTypesForRemove = new HashSet<DataTypeDefinition>();
        DataTypeDefinitionManager dataTypeDefinitionManager = dataTypeManager.getDataTypeDefinitionManager();
        Map<String, DataTypeDefinition> dataTypes = dataTypeDefinitionManager.getDefinitions();
        for (DataTypeDefinition dataType : dataTypes.values()) {
            if (resourceSet.contains(dataType.getResource())) {
                dataTypesForRemove.add(dataType);
            }
        }

        for (DataTypeDefinition dataType : dataTypesForRemove) {
            dataTypeDefinitionManager.unregisterDefinition(dataType.getName());
        }

        // DataProvider
        Set<DataProviderDefinition> dataProvidersForRemove = new HashSet<DataProviderDefinition>();
        DataProviderDefinitionManager dataProviderDefinitionManager = dataProviderManager
                .getDataProviderDefinitionManager();
        Map<String, DataProviderDefinition> dataProviders = dataProviderDefinitionManager.getDefinitions();
        for (DataProviderDefinition dataProvider : dataProviders.values()) {
            if (resourceSet.contains(dataProvider.getResource())) {
                dataProvidersForRemove.add(dataProvider);
            }
        }

        for (DataProviderDefinition dataProvider : dataProvidersForRemove) {
            dataProviderDefinitionManager.unregisterDefinition(dataProvider.getName());
        }

        // DataResolver
        Set<DataResolverDefinition> dataResolversForRemove = new HashSet<DataResolverDefinition>();
        DataResolverDefinitionManager dataResolverDefinitionManager = dataResolverManager
                .getDataResolverDefinitionManager();
        Map<String, DataResolverDefinition> dataResolvers = dataResolverDefinitionManager.getDefinitions();
        for (DataResolverDefinition dataResolver : dataResolvers.values()) {
            if (resourceSet.contains(dataResolver.getResource())) {
                dataResolversForRemove.add(dataResolver);
            }
        }

        for (DataResolverDefinition dataResolver : dataResolversForRemove) {
            dataResolverDefinitionManager.unregisterDefinition(dataResolver.getName());
        }

        return (!dataTypesForRemove.isEmpty() || !dataProvidersForRemove.isEmpty());
    }

    /**
     * ?????
     * 
     * @return ???
     */
    public synchronized boolean recalcConfigLocations() {
        boolean configsChanged = false;
        try {
            Context context = Context.getCurrent();
            if (context == null) {
                return configsChanged;
            }

            if (configLocationArray == null) {
                if (configLocations != null) {
                    configLocationArray = new String[configLocations.size()];
                    configLocations.toArray(configLocationArray);
                } else {
                    configLocationArray = EMPTY_LOCATION_ARRAY;
                }
            }

            Set<Resource> resources = ResourceUtils.getResourceSet(configLocationArray);
            Set<Resource> loadedResources = getResources();
            Set<Resource> newResources = null, removedResources = null;

            for (Resource resource : loadedResources) {
                if (!resources.contains(resource)) {
                    if (newResources == null) {
                        newResources = new LinkedHashSet<Resource>();
                    }
                    newResources.add(resource);
                }
            }

            for (Resource resource : resources) {
                if (!loadedResources.contains(resource)) {
                    if (removedResources == null) {
                        removedResources = new LinkedHashSet<Resource>();
                    }
                    removedResources.add(resource);
                }
            }

            if (removedResources != null) {
                configsChanged = true;
                Resource[] removedResourceArray = new Resource[removedResources.size()];
                removedResources.toArray(removedResourceArray);
                unloadConfigs(removedResourceArray);
            }

            if (newResources != null) {
                configsChanged = true;
                Resource[] newResourceArray = new Resource[newResources.size()];
                newResources.toArray(newResourceArray);
                loadConfigs(newResourceArray, false);
            }
        } catch (Exception e) {
            logger.error(e, e);
        }
        return configsChanged;
    }
}