Java tutorial
/* * 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; } }