/* * Copyright 2008-2009 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 net.hasor.core.environment; import net.hasor.core.Environment; import net.hasor.core.EventContext; import net.hasor.core.Settings; import net.hasor.core.XmlNode; import net.hasor.core.classcode.MoreClassLoader; import net.hasor.core.event.StandardEventManager; import net.hasor.core.setting.AbstractSettings; import net.hasor.core.setting.SettingValue; import net.hasor.core.setting.UpdateValue; import net.hasor.core.setting.xml.DefaultXmlNode; import net.hasor.core.utils.ResourcesUtils; import net.hasor.core.utils.ScanClassPath; import net.hasor.core.utils.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.*; import java.net.URL; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * {@link Environment}接口实现类,集成该类的子类需要调用{@link #initEnvironment(Map, Map)}方法以初始化。 * @version : 2013-4-9 * @author 赵永春 (zyc@hasor.net) */ public abstract class AbstractEnvironment implements Environment { protected Logger logger = LoggerFactory.getLogger(getClass()); private String workMode = null; private String[] spanPackage = null; private ScanClassPath scanUtils = null; private AbstractSettings settings = null; private Object context = null; private ClassLoader rootLosder = null; private EventContext eventManager = null; private Map<String, String> envMap = null; // /* --------------------------------------------------------------------------------- get/set */ public AbstractEnvironment(Object context, AbstractSettings settings) { this.settings = settings; this.context = context; this.rootLosder = new MoreClassLoader(); this.envMap = new ConcurrentHashMap<String, String>(); } @Override public Object getContext() { return this.context; } /**设置或更新 context */ public void setContext(final Object context) { this.context = context; } /**获取当创建Bean时使用的{@link ClassLoader}*/ public ClassLoader getClassLoader() { return this.rootLosder; } /**设置类加载器*/ public void setRootLosder(ClassLoader classLoader) { if (classLoader != null) { this.rootLosder = classLoader; } } /**设置扫描路径*/ public void setSpanPackage(final String[] spanPackage) { this.spanPackage = spanPackage; } @Override public String[] getSpanPackage() { return this.spanPackage; } @Override public String getWorkMode() { return this.workMode; } @Override public final EventContext getEventContext() { if (this.eventManager == null) { int eventThreadPoolSize = this.getSettings().getInteger("hasor.eventThreadPoolSize", 20); this.eventManager = createEventManager(eventThreadPoolSize); } return this.eventManager; } // // ------------------------------------------------------------------------------- findClass */ @Override public Set<Class<?>> findClass(final Class<?> featureType) { return this.findClass(featureType, this.spanPackage); } /** 在框架扫描包的范围内查找具有特征类集合。(特征可以是继承的类、标记某个注解的类) */ public Set<Class<?>> findClass(final Class<?> featureType, String[] loadPackages) { if (featureType == null) { return null; } if (loadPackages == null) { loadPackages = new String[] { "" }; } if (this.scanUtils == null) { this.scanUtils = ScanClassPath.newInstance(loadPackages); } return this.scanUtils.getClassSet(featureType); } /** 在框架扫描包的范围内查找具有特征类集合。(特征可以是继承的类、标记某个注解的类) */ public Set<Class<?>> findClass(final Class<?> featureType, String loadPackages) { if (featureType == null) { return null; } loadPackages = loadPackages == null ? "" : loadPackages; String[] spanPackage = loadPackages.split(","); return this.findClass(featureType, spanPackage); } @Override public AbstractSettings getSettings() { return this.settings; } /**创建事件管理器*/ protected EventContext createEventManager(int eventThreadPoolSize) { return new StandardEventManager(eventThreadPoolSize, "Hasor", this.getClassLoader()); } // /* ------------------------------------------------------------------------------------ Toos */ public String getPluginDir(Class<?> pluginType) { String subName = "_"; if (pluginType != null) { subName = pluginType.getPackage().getName(); } return evalString("%" + HASOR_PLUGIN_PATH + "%/" + subName + "/"); } public String getWorkSpaceDir() { return evalString("%" + WORK_HOME + "%/"); } // private String formatMap4log(final int colWidth, final Map<String, String> mapData) { /*输出系统环境变量日志*/ StringBuilder outLog = new StringBuilder(""); for (String key : mapData.keySet()) { String var = mapData.get(key); var = (var != null) ? (var.replace("\r", "\\r").replace("\n", "\\n")) : ""; outLog.append(StringUtils.fixedString(' ', colWidth - key.length())); outLog.append(String.format("%s = %s", key, var)); outLog.append('\n'); } if (outLog.length() > 1) { outLog.deleteCharAt(outLog.length() - 1); } return outLog.toString(); } // /* ------------------------------------------------------------------------------------- Env */ @Override public void addEnvVar(final String varName, final String value) { if (StringUtils.isBlank(varName)) { if (logger.isWarnEnabled()) { logger.warn(varName + "{} env, name is empty."); } return; } if (logger.isInfoEnabled()) { logger.info("var -> {} = {}.", varName, value); } this.envMap.put(varName.toUpperCase(), value); } @Override public void removeEnvVar(final String varName) { if (StringUtils.isBlank(varName)) { return; } this.envMap.remove(varName.toUpperCase()); if (logger.isInfoEnabled()) { logger.info(varName + " env removed."); } } @Override public String evalString(String evalString) { if (StringUtils.isBlank(evalString)) { return ""; } Pattern keyPattern = Pattern.compile("(?:%([\\w\\._-]+)%){1,1}");// (?:%([\w\._-]+)%) Matcher keyM = keyPattern.matcher(evalString); Map<String, String> data = new HashMap<String, String>(); while (keyM.find()) { String varKeyOri = keyM.group(1); String keyName = "%" + varKeyOri + "%"; String var = this.envMap.get(varKeyOri.toUpperCase()); if (var == null) { data.put(keyName, keyName); } else { data.put(keyName, evalString(var)); } } String newEvalString = evalString; for (String key : data.keySet()) { newEvalString = newEvalString.replace(key, data.get(key)); } if (logger.isInfoEnabled()) { logger.info("evalString '{}' eval to '{}'.", evalString, newEvalString); } return newEvalString; } // /* ------------------------------------------------------------------------------------ init */ /**初始化方法*/ protected final void initEnvironment(Map<String, String> frameworkEnvConfig, Map<String, String> customEnvConfig) throws IOException { // .load & init this.envMap = new ConcurrentHashMap<String, String>(); if (this.logger.isDebugEnabled()) { this.logger.debug("load envVars..."); } // .vars this.initEnvConfig(frameworkEnvConfig, customEnvConfig); this.refreshVariables(); // // .Packages String[] spanPackages = this.getSettings().getStringArray("hasor.loadPackages", "net.hasor.core.*,net.hasor.plugins.*"); Set<String> allPack = new HashSet<String>(); for (String packs : spanPackages) { if (StringUtils.isBlank(packs)) { continue; } String[] packArray = packs.split(","); for (String pack : packArray) { if (StringUtils.isBlank(packs)) { continue; } allPack.add(pack.trim()); } } ArrayList<String> spanPackagesArrays = new ArrayList<String>(allPack); Collections.sort(spanPackagesArrays); this.spanPackage = spanPackagesArrays.toArray(new String[spanPackagesArrays.size()]); if (this.logger.isInfoEnabled()) { StringBuilder packages = new StringBuilder(""); for (int i = 0; i < this.spanPackage.length; i++) { if (i > 0) { packages.append(", "); } packages.append(this.spanPackage[i]); } this.logger.info("loadPackages = " + packages); } // // .日志输出 if (this.logger.isInfoEnabled()) { int keyMaxSize = 0; for (String key : this.envMap.keySet()) { keyMaxSize = key.length() >= keyMaxSize ? key.length() : keyMaxSize; } keyMaxSize = keyMaxSize + 2; StringBuilder sb = new StringBuilder(); sb.append("EnvVars:"); if (!this.envMap.isEmpty()) { sb.append("\n").append(this.formatMap4log(keyMaxSize, this.envMap)); sb.append("\n").append(StringUtils.fixedString('-', 50)); } this.logger.info(sb.toString()); } this.workMode = this.evalString("%" + WORK_MODE + "%"); } /** * 1st,System.getProperties() * 2st,System.getenv() * 3st,配置文件"hasor.environmentVar" * 4st,传入的配置 * 5st,属性文件"env.config" * tips:如果指定了loadEnvConfig参数,那么将会忽略"env.config"配置文件。 */ private void initEnvConfig(Map<String, String> frameworkEnvConfig, Map<String, String> customEnvConfig) throws IOException { // // .1st,System.getProperties() if (this.logger.isDebugEnabled()) { this.logger.debug("envVars.reload -> System.getProperties()."); } Properties prop = System.getProperties(); for (Object propKey : prop.keySet()) { String k = propKey.toString(); Object v = prop.get(propKey); if (v != null) { this.envMap.put(k.toUpperCase(), v.toString()); } } // .2st,System.getenv() if (this.logger.isDebugEnabled()) { this.logger.debug("envVars.reload -> System.getenv()."); } Map<String, String> envMap = System.getenv(); for (String key : envMap.keySet()) { this.envMap.put(key.toUpperCase(), envMap.get(key)); } // .3st,配置文件"hasor.environmentVar" if (this.logger.isDebugEnabled()) { this.logger.debug("envVars.reload -> settings."); } Settings settings = getSettings(); XmlNode[] xmlPropArray = settings.getXmlNodeArray("hasor.environmentVar"); List<String> envNames = new ArrayList<String>();//用于收集环境变量名称 for (XmlNode xmlProp : xmlPropArray) { for (XmlNode envItem : xmlProp.getChildren()) { envNames.add(envItem.getName().toUpperCase()); } } for (String envItem : envNames) { if (this.envMap.containsKey(envItem)) { String val = this.envMap.get(envItem); if (StringUtils.isNotBlank(val)) { this.logger.warn("environmentVar {} is define, ignored. value is {}", envItem, val); continue; } } this.envMap.put(envItem.toUpperCase(), settings.getString("hasor.environmentVar." + envItem)); } // .4st,传入的配置 if (frameworkEnvConfig != null && !frameworkEnvConfig.isEmpty()) { this.logger.info("ignore 'env.config' use framework map, size = " + frameworkEnvConfig.size()); for (String name : frameworkEnvConfig.keySet()) { this.envMap.put(name.toUpperCase(), frameworkEnvConfig.get(name)); } } if (customEnvConfig != null && !customEnvConfig.isEmpty()) { this.logger.info("ignore 'env.config' use custom map, size = " + customEnvConfig.size()); for (String name : customEnvConfig.keySet()) { this.envMap.put(name.toUpperCase(), customEnvConfig.get(name)); } return; } // // .5st,外部属性文件"env.config" InputStream inStream = null; String workHome = this.evalString("%" + Environment.WORK_HOME + "%"); File envFile = new File(workHome, EVN_FILE_NAME); String envFileName = envFile.getAbsolutePath(); if (envFile.exists()) { if (envFile.isDirectory()) { this.logger.info("load 'env.config' failed(isDirectory) -> {}.", envFileName); } else if (!envFile.canRead()) { this.logger.info("load 'env.config' failed(can not read) -> {}.", envFileName); } else { inStream = new FileInputStream(envFile); this.logger.info("load 'env.config' form file -> {}.", envFileName); } } if (inStream == null) { URL inStreamURL = ResourcesUtils.getResource(EVN_FILE_NAME); this.logger.info("load 'env.config' use classpath -> {}.", (inStreamURL == null) ? "empty." : inStreamURL); if (inStreamURL != null) { inStream = ResourcesUtils.getResourceAsStream(inStreamURL); } } if (inStream != null) { Properties properties = new Properties(); properties.load(new InputStreamReader(inStream, Settings.DefaultCharset)); inStream.close(); for (String name : properties.stringPropertyNames()) { String argKey = name.toUpperCase(); String argVal = properties.getProperty(name); this.logger.info("load 'env.config' {} -> {}.", argKey, argVal); this.envMap.put(argKey, argVal); } } } // /* ------------------------------------------------------------------------------------ init */ @Override public void refreshVariables() { this.getSettings().resetValues(new UpdateValue() { @Override public void update(SettingValue oldValue, Settings context) { ArrayList<Object> varArrays = new ArrayList<Object>(oldValue.getVarList()); // for (int index = 0; index < varArrays.size(); index++) { Object var = varArrays.get(index); if (var instanceof DefaultXmlNode) { DefaultXmlNode xmlVar = (DefaultXmlNode) var; // .引用类型-直接更新引用对象的属性值。 String val = evalSettingString(xmlVar.getText()); xmlVar.setText(val);//引用类型 Map<String, String> attributeMap = xmlVar.getAttributeMap(); for (String attrKey : attributeMap.keySet()) { String newValue = evalSettingString(attributeMap.get(attrKey)); attributeMap.put(attrKey, newValue); } } else if (var instanceof CharSequence) { // .String类型-通过replace替换。 String oldVal = String.valueOf(var); String newVal = evalSettingString(oldVal); oldValue.replace(index, var, newVal);//值类型 } else { //TODO } } } }); } private String evalSettingString(String evalString) { if (StringUtils.isBlank(evalString)) { return ""; } Pattern keyPattern = Pattern.compile("(?:\\$\\{([\\w\\._-]+)\\}){1,1}");// (?:\$\{([\w\._-]+)\}){1,1} -> ${...} Matcher keyM = keyPattern.matcher(evalString); Map<String, String> data = new HashMap<String, String>(); while (keyM.find()) { String varKeyOri = keyM.group(1); String envKey = "%" + varKeyOri.toUpperCase() + "%"; String var = this.evalString(envKey); if (envKey.equalsIgnoreCase(var)) { data.put("${" + varKeyOri + "}", envKey); } else { data.put("${" + varKeyOri + "}", var); } } String newEvalString = evalString; for (String key : data.keySet()) { newEvalString = newEvalString.replace(key, data.get(key)); } if (this.logger.isInfoEnabled()) { if (!evalString.equalsIgnoreCase(newEvalString)) { this.logger.info("replace settingValue '{}' to '{}'.", evalString, newEvalString); } } return newEvalString; } // /* ----------------------------------------------------------------------------------- toos */ @Override public String getSystemProperty(String property) { try { return System.getProperty(property); } catch (SecurityException ex) { // we are not allowed to look at this property logger.error("Caught a SecurityException reading the system property '" + property + "'; the SystemUtils property value will default to null."); return null; } } }