View Javadoc
1   /**
2    * Copyright By Grandsoft Company Limited.  
3    * 2012-11-22 下午04:05:40
4    */
5   package gboat2.base.bridge.debug;
6   
7   import gboat2.base.bridge.util.FileUtil;
8   
9   import java.io.File;
10  import java.io.FileInputStream;
11  import java.io.IOException;
12  import java.io.InputStream;
13  import java.util.Arrays;
14  import java.util.HashSet;
15  import java.util.LinkedHashMap;
16  import java.util.Map;
17  import java.util.Properties;
18  import java.util.Set;
19  
20  import org.apache.commons.lang3.StringUtils;
21  import org.apache.commons.lang3.SystemUtils;
22  import org.slf4j.Logger;
23  import org.slf4j.LoggerFactory;
24  
25  import com.opensymphony.xwork2.util.TextParseUtil;
26  
27  /**
28   * 调试模式时使用的钩子类
29   * @date 2012-11-22
30   * @author tanxw
31   * @since 1.0
32   */
33  public abstract class AbstractDebugHook {
34  	
35  	private static Logger logger = LoggerFactory.getLogger(AbstractDebugHook.class);
36  	
37      /** 调试模式的配置文件路径:{@value} */
38      public static final String CONFIG_FILE = "WEB-INF/config/debug.properties";
39  
40      /** 是否开启调试模式的 key: {@value} */
41      public static final String PROPERTY_RESOURCE_FILE_DEV_MODE = "resource.file.devMode";
42      
43  	/** 所有开启调试模式的 Bundle 源代码的根路径 key: {@value} */
44  	public static final String PROPERTY_PROJECTS_ROOT_PATH = "projects.root.path";
45  	
46  	/** 开启调试模式的 Bundle 的 key: {@value} */
47  	public static final String PROPERTY_DEBUG_BUNDLES = "debug.bundles";
48  	
49  	/** Bundle 名称规则与其源码路径的映射关系的 key: {@value} */
50  	public static final String PROPERTY_BUNDLE_NAME_PATH_MAPPING_RULES = "bundleName.path.mapping.rules";
51  	
52  	
53  	/** 资源文件的相对路径 */
54  	public static final String RESOURCES_CONTEXT_PATH_IN_PROJECT = "/src/main/resources";
55  	
56  	/** 配置文件 {@value #CONFIG_FILE} 中配置项 {@value #PROPERTY_RESOURCE_FILE_DEV_MODE} 对应的值 */
57      public boolean devMode = false;
58      
59  	/** 配置文件 {@value #CONFIG_FILE} 中配置项 {@value #PROPERTY_PROJECTS_ROOT_PATH} 对应的值 */
60  	protected static String rootPath;
61  	
62  	/** 开启调试的 bundle 的名称集合 */
63  	protected static Set<String> includeBundles = new HashSet<String>();
64  	
65  	/** bunlde 位置规则映射集合,规则集的迭代顺序应该与解析到的顺序保持一致 */
66  	protected static Map<String, String> bundlePathMappingRules = new LinkedHashMap<String, String>();
67  	
68  
69      /** eclipse 插件生成的配置文件的位置,为 用户目录/gboat2.eclipse.debug.properties,如:C:/Users/Administrator/gboat2.eclipse.debug.properties */
70      public static final String ECLIPSE_PLUGIN_CONFIG_FILE = SystemUtils.USER_HOME + File.separator + "gboat2.eclipse.debug.properties";
71      
72  	/** bundle 及其位置的映射,供 eclipse 插件使用,优先级比使用规则匹配高,格式:key:bundlename,value:e:/project1 */
73  	protected static Properties bundlePathMapFromEclipsePlugin = new Properties();
74  	
75  	/**
76  	 * 初始化调试模式的配置项
77  	 * @param configFile .properties 文件的输入流
78  	 * @return .properties 文件对应的 Properties 实例
79  	 */
80  	protected Properties initConfig(InputStream configFile) {
81  		Properties prop = new Properties();
82  		try {
83  			prop.load(configFile);
84  			
85  			// 解析调试模式
86  			devMode = "true".equals(prop.getProperty(PROPERTY_RESOURCE_FILE_DEV_MODE).trim());
87  			
88  			// 解析要调试的bundles
89  			String bundlesStr = StringUtils.trimToEmpty(prop.getProperty(PROPERTY_DEBUG_BUNDLES));
90  			Set<String> bundles = TextParseUtil.commaDelimitedStringToSet(bundlesStr);
91  			for (String bundle : bundles) {
92  				includeBundles.add(bundle.toLowerCase());
93  			}
94  			logger.debug("开启调试模式的bundle有:{}", includeBundles);
95  			
96  			// 解析入口跟路径
97  			rootPath = prop.getProperty(PROPERTY_PROJECTS_ROOT_PATH, "").replace('\\', '/');
98  			rootPath = StringUtils.removeEnd(rootPath, "/"); // 去掉最后的 '/'
99  			logger.debug("项目调试根路径为:{}",  rootPath);
100 			
101 			if (devMode && !(new File(rootPath)).exists()) {// 如果指定的调试路径中,有任意一个路径不存在,则不启动调试模式
102 				logger.warn("配置文件 {} 中,属性 {} 所指的目录 {} 不存在, 将关闭调试模式!", CONFIG_FILE, PROPERTY_PROJECTS_ROOT_PATH, rootPath);
103 				devMode = false;
104 			}
105 			
106 			// 解析规则
107 			String rules = prop.getProperty(PROPERTY_BUNDLE_NAME_PATH_MAPPING_RULES, "");
108 			Set<String> rulesArr = TextParseUtil.commaDelimitedStringToSet(rules);
109 			String separator ="@";
110 			for (String rule : rulesArr) {
111 				String key = StringUtils.substringBefore(rule, separator);
112 				String value = StringUtils.substringAfter(rule, separator);
113 				bundlePathMappingRules.put(key.trim(), value.trim());
114 			}
115 			logger.debug("调试bundle名称与路径的映射规则为:{}", bundlePathMappingRules);
116 		} catch (Exception e) {
117 			logger.warn("调试配置文件 {} 读取出错:{}", CONFIG_FILE, Arrays.deepToString(e.getStackTrace()));
118 		}
119 		
120 		logger.debug("资源文件调试模式状态为:devMode={}", devMode);
121 		return prop;
122 	}
123 	
124 	/**
125 	 * 判断当前 bundle 的元数据调试模式是否打开
126 	 * @param bundle Bundle 的名称
127 	 * @return 如果当前的 devMode 为 true,且当前 bundle 在调试列表中,则返回 true;否则返回false。
128 	 */
129     public boolean isBundleDebugEnabled(String bundle) {
130         if (!devMode) { // 优先级1
131             return false;
132         }
133 
134         loadConfigFromEclipsePlugin();
135         if (bundlePathMapFromEclipsePlugin.containsKey(bundle.toLowerCase())) {// 优先级2
136             return true;
137         }
138 
139         if (includeBundles.contains(bundle.toLowerCase())) {// 优先级3
140             return true;
141         }
142 
143         return false;
144     }
145 	
146     /**
147      * 加载 Gboat 平台的 Eclipse 调试插件的配置文件
148      */
149     private void loadConfigFromEclipsePlugin() {
150         try {
151             bundlePathMapFromEclipsePlugin.clear();
152             if ((new File(ECLIPSE_PLUGIN_CONFIG_FILE)).exists()) {
153                 Properties p = new Properties();
154                 p.load(new FileInputStream(ECLIPSE_PLUGIN_CONFIG_FILE));
155                 for (Map.Entry<?, ?> entry : p.entrySet()) {
156                     bundlePathMapFromEclipsePlugin.setProperty(((String) entry.getKey()).toLowerCase(), ((String) entry.getValue()));
157                 }
158             }
159         } catch (IOException e) {
160             logger.warn("调试配置文件" + ECLIPSE_PLUGIN_CONFIG_FILE + "读取出错", e);
161         }
162     }
163 
164     /**
165      * 读取 Bundle 资源文件源码所在路径
166      * @param bundle Bundle 名称
167      * @return Bundle 如:D:/workspace/trunk/gboat2.web/src/main/resources,如果没有找到对应的路径,则返回 ""
168      */
169     public String getResourcesAbsolutPath(String bundle) {
170         String projectPath = getProjectFullpathFromEclipsePlugin(bundle); // 优先级1
171         if (StringUtils.isEmpty(projectPath)) {
172             projectPath = getBundleProjectFullpath(bundle); // 优先级2
173         }
174         if (null == projectPath) {
175             return "";
176         }
177 
178         return projectPath + RESOURCES_CONTEXT_PATH_IN_PROJECT;
179     }
180 	
181 	/**
182 	 * 从eclipse 插件中读取配置映射
183 	 * @param bundle Bundle 的名称
184 	 * @return 在 Eclipse 插件中设置的源码路径
185 	 */
186 	private String getProjectFullpathFromEclipsePlugin(String bundle) {
187 		return bundlePathMapFromEclipsePlugin.getProperty(bundle.toLowerCase());
188 	}
189 
190 	/**
191 	 * 取得项目根路径的位置
192 	 * 
193 	 * @param bundle Bundle 名称
194 	 * @return
195 	 */
196     public String getBundleProjectFullpath(String bundle) {
197         String contextPath = "/";
198         for (Map.Entry<String, String> entry : bundlePathMappingRules.entrySet()) {
199             if (bundle.matches(entry.getKey())) { // 如果bundle名称与指定正则匹配
200                 if (StringUtils.isNotEmpty(entry.getValue())) {
201                     contextPath += entry.getValue() + "/";
202                 }
203                 break;
204             }
205         }
206         
207         // contextPath后直接是bundle主路径
208         String fullpath = rootPath + contextPath + bundle;
209         if(!FileUtil.exists(fullpath)){
210         	// contextPath后是trunk然后是bundle主路径
211         	fullpath = rootPath + contextPath +"trunk/" + bundle;
212         }
213         
214         // bundle名直接作为项目的根目录,如 E:/workspace/somefolder/gboat2.web
215         if (FileUtil.exists(fullpath + "/src")) {
216             return fullpath;
217         }
218         // bundle 名目录下有分支,如 E:/workspace/somefolder/gboat2.web/trunk
219         if (FileUtil.exists(fullpath + "/trunk/src")) {
220             return fullpath + "/trunk";
221         }
222 
223         // 尝试使用老规则
224         int firstPointPos = bundle.indexOf('.');
225         if (firstPointPos >= 0) {
226             fullpath = rootPath + contextPath + bundle.substring(firstPointPos + 1);
227             // glodon.gbmp.base 项目的根目录,如 E:/workspace/somefolder/gbmp.base
228             if (FileUtil.exists(fullpath + "/src")) {
229                 return fullpath;
230             }
231 
232             // glodon.gbmp.base 项目目录,如 E:/workspace/somefolder/gbmp.base/trunk
233             if (FileUtil.exists(fullpath + "/trunk/src")) {
234                 return fullpath + "/trunk";
235             }
236         }
237 
238         return null;
239     }
240 	
241 }