001: /*
002: * JFox - The most lightweight Java EE Application Server!
003: * more details please visit http://www.huihoo.org/jfox or http://www.jfox.org.cn.
004: *
005: * JFox is licenced and re-distributable under GNU LGPL.
006: */
007: package org.jfox.framework.component;
008:
009: import java.io.File;
010: import java.io.IOException;
011: import java.lang.reflect.Modifier;
012: import java.net.MalformedURLException;
013: import java.net.URL;
014: import java.util.ArrayList;
015: import java.util.Collection;
016: import java.util.Collections;
017: import java.util.List;
018:
019: import org.apache.log4j.Logger;
020: import org.jfox.framework.ComponentId;
021: import org.jfox.framework.Constants;
022: import org.jfox.framework.Framework;
023: import org.jfox.framework.annotation.Exported;
024: import org.jfox.framework.annotation.Service;
025: import org.jfox.framework.event.ComponentLoadedEvent;
026: import org.jfox.framework.event.ComponentUnloadedEvent;
027: import org.jfox.framework.event.ModuleLoadedEvent;
028: import org.jfox.framework.event.ModuleLoadingEvent;
029: import org.jfox.framework.event.ModuleUnloadedEvent;
030: import org.jfox.util.FileFilterUtils;
031: import org.jfox.util.FileUtils;
032: import org.jfox.util.PlaceholderUtils;
033: import org.jfox.util.XMLUtils;
034: import org.w3c.dom.Document;
035: import org.w3c.dom.Element;
036:
037: /**
038: * @author <a href="mailto:jfox.young@gmail.com">Young Yang</a>
039: */
040: public class Module implements Comparable<Module> {
041:
042: protected final Logger logger = Logger.getLogger(this .getClass());
043:
044: protected Framework framework;
045:
046: /**
047: * 模�的文件,或者目录
048: */
049: protected File moduleDir;
050:
051: private URL descriptorURL;
052:
053: /**
054: * 模å?—å??称
055: */
056: private String name;
057:
058: private String description;
059:
060: private int priority = 50;
061: /**
062: * 该模�需�引用的模�
063: */
064: private String[] refModules;
065:
066: protected ModuleClassLoader classLoader;
067:
068: private Repository repo = Repository.getModuleComponentRepo(this );
069:
070: public static enum STATUS {
071: RESOLVED, STARTED, STOPPED
072: }
073:
074: public Module(Framework framework, File file)
075: throws ModuleResolvedFailedException {
076: this .framework = framework;
077: this .moduleDir = file;
078: this .classLoader = initModuleClassLoader();
079: this .resolve(); // 仅仅解� xml,并�load相关的类和component
080: }
081:
082: protected ModuleClassLoader initModuleClassLoader() {
083: return new ModuleClassLoader(this );
084: }
085:
086: public Framework getFramework() {
087: return framework;
088: }
089:
090: public File getModuleDir() {
091: return moduleDir;
092: }
093:
094: public ModuleClassLoader getModuleClassLoader() {
095: return classLoader;
096: }
097:
098: public ComponentMeta loadComponent(
099: Class<? extends Component> implementataionClass)
100: throws ComponentResolvedFailedException {
101: ComponentMeta meta = new ComponentMeta(this ,
102: implementataionClass);
103: registerComponent(meta);
104: getFramework().getEventManager().fireComponentEvent(
105: new ComponentLoadedEvent(meta.getComponentId()));
106: return meta;
107: }
108:
109: /**
110: * �载一个Component
111: *
112: * @param id component id
113: * @throws ComponentNotFoundException not found component
114: */
115: public boolean unloadComponent(ComponentId id)
116: throws ComponentNotFoundException {
117: logger.info("Unload component: " + id + ", Module: "
118: + getName());
119: boolean unloadSuccess = false;
120: if (isComponentLoaded(id)) {
121: try {
122: ComponentMeta meta = repo.getComponentMeta(id);
123: // 会从 Module ä¸åˆ 除,并回调 preUnregister postUnregister
124: unloadSuccess = meta.unload();
125: getFramework().getEventManager().fireComponentEvent(
126: new ComponentUnloadedEvent(id));
127: return unloadSuccess;
128: } catch (ComponentNotExportedException e) {
129: throw new ComponentNotFoundException(
130: "Failed to unload other module's component.", e);
131: }
132: } else {
133: throw new ComponentNotFoundException(id.toString());
134: }
135: }
136:
137: /**
138: * reload a component
139: *
140: * @param implementationClass component implementation class
141: */
142: public ComponentMeta reloadComponent(
143: Class<? extends Component> implementationClass) {
144: return null;
145: }
146:
147: private void registerComponent(ComponentMeta meta) {
148: // componentMetas.put(meta.getComponentId(), meta);
149: meta.getComponentId().setModuleName(getName());
150: if (repo.hasComponentMeta(meta.getComponentId())) {
151: throw new ComponentExistedException(meta.toString());
152: }
153: repo.addComponentMeta(meta);
154: }
155:
156: /**
157: * 由 ComponentMeta 回调
158: *
159: * @param id component id
160: * @throws ComponentNotFoundException if component not found
161: */
162: void unregisterComponent(ComponentId id)
163: throws ComponentNotFoundException {
164: // componentMetas.remove(id);
165: repo.removeComponentMeta(id);
166: }
167:
168: /**
169: * 获得模��置文件
170: *
171: * @return xml descriptor URL
172: */
173: public URL getDescriptorURL() {
174: if (descriptorURL == null) {
175: try {
176: File moduleDescriptorFile = new File(getModuleDir(),
177: Constants.MODULE_CONFIG_DIR + "/"
178: + Constants.MODULE_CONFIG_FILENAME);
179: if (moduleDescriptorFile.exists()) {
180: descriptorURL = moduleDescriptorFile.toURI()
181: .toURL();
182: }
183: } catch (IOException e) {
184: e.printStackTrace();
185: }
186: // ä¸?用 ClassLoader.getResourceï¼Œä¼šé€ æˆ?æ— æ³•é‡Šæ”¾èµ„æº?,而是 Web Application undeploy 失败
187: // descriptorURL = getModuleClassLoader().getResource(Constants.MODULE_CONFIG_FILENAME);
188: }
189: return descriptorURL;
190: }
191:
192: /**
193: * 获å?–所有è¦?åŠ å…¥åˆ° MODULE classpath çš„ url
194: *
195: * @return Module classpath urls
196: */
197: public URL[] getClasspathURLs() {
198: List<URL> classpathURLs = new ArrayList<URL>();
199:
200: File classesPath = new File(moduleDir,
201: Constants.MOUDULE_CLASS_OUTPUT_PATH);
202: File webClassesPath = new File(moduleDir,
203: Constants.MOUDULE_CLASS_WEB_OUTPUT_PATH);
204:
205: File configPath = new File(moduleDir,
206: Constants.MODULE_CONFIG_DIR);
207:
208: File libPath = new File(moduleDir, "lib");
209: File webLibPath = new File(moduleDir, "WEB-INF/lib");
210: try {
211: if (classesPath.exists()) {
212: classpathURLs.add(classesPath.toURI().toURL()); // add to top
213: }
214: if (webClassesPath.exists()) {
215: classpathURLs.add(webClassesPath.toURI().toURL()); // add to top
216: }
217: if (configPath.exists()) {
218: classpathURLs.add(configPath.toURI().toURL()); // add to top
219: }
220:
221: if (libPath.exists()) {
222: List<File> jars = FileUtils.listFiles(libPath,
223: FileFilterUtils.suffixFileFilter("jar", "zip"));
224: for (File jar : jars) {
225: classpathURLs.add(jar.toURI().toURL());
226: }
227: }
228: if (webLibPath.exists()) {
229: List<File> jars = FileUtils.listFiles(webLibPath,
230: FileFilterUtils.suffixFileFilter("jar", "zip"));
231: for (File jar : jars) {
232: classpathURLs.add(jar.toURI().toURL());
233: }
234: }
235: } catch (MalformedURLException e) {
236: logger.warn("Malformed URL!", e);
237: }
238: return classpathURLs.toArray(new URL[classpathURLs.size()]);
239: }
240:
241: public String getName() {
242: return name;
243: }
244:
245: protected void setName(String name) {
246: this .name = name;
247: }
248:
249: public String getDescription() {
250: return description;
251: }
252:
253: protected void setDescription(String description) {
254: this .description = description;
255: }
256:
257: public int getPriority() {
258: return priority;
259: }
260:
261: protected void setPriority(int priority) {
262: this .priority = priority;
263: }
264:
265: public String[] getRefModules() {
266: return refModules;
267: }
268:
269: /**
270: * �始化,only 装载�置文件,�解�
271: *
272: * @throws ModuleResolvedFailedException 解�失败,比如,XML�符�规范,抛出该异常
273: */
274: protected void resolve() throws ModuleResolvedFailedException {
275: URL descriptorURL = getDescriptorURL();
276: if (descriptorURL == null) {
277: logger
278: .warn("Could not find module XML configuration for Module "
279: + getModuleDir().toString()
280: + ", will use default config.");
281: setName(getModuleDir().getName());
282: setDescription(getModuleDir().toString());
283: } else {
284: logger.info("Resolving XML descriptor: " + descriptorURL);
285: Document doc;
286: try {
287: // 替æ?¢å? ä½?符
288: String xmlContent = PlaceholderUtils.getInstance()
289: .evaluate(descriptorURL);
290: doc = XMLUtils.loadDocument(xmlContent);
291: } catch (Exception e) {
292: logger
293: .error(
294: "Error to get XML Document of Module descriptor.",
295: e);
296: throw new ModuleResolvedFailedException(
297: "Error to get XML Document of Module descriptor.",
298: e);
299: }
300:
301: Element rootElement = doc.getDocumentElement();
302: String name = XMLUtils.getChildElementValueByTagName(
303: rootElement, "name");
304: if (name != null) {
305: setName(name);
306: } else {
307: // 使用模å?—的目录å??
308: setName(getModuleDir().getName());
309: }
310: setDescription(XMLUtils.getChildElementValueByTagName(
311: rootElement, "description"));
312: setPriority(Integer.parseInt(XMLUtils
313: .getChildElementValueByTagName(rootElement,
314: "priority")));
315: String _refModules = XMLUtils
316: .getChildElementValueByTagName(rootElement,
317: "ref-modules");
318: if (_refModules != null) {
319: this .refModules = _refModules.split(",");
320: } else {
321: this .refModules = new String[0];
322: }
323: }
324: }
325:
326: /**
327: * 解�模�,export class, 装载组件
328: *
329: * @throws Exception any exception
330: */
331: public void start() throws Exception {
332: logger.info("Starting module: " + getName());
333: Class[] deployComponents = getModuleClassLoader()
334: .findClassAnnotatedWith(Service.class);
335: for (Class<?> componentClass : deployComponents) {
336: if (componentClass.isInterface()
337: || !Modifier
338: .isPublic(componentClass.getModifiers())
339: || Modifier.isAbstract(componentClass
340: .getModifiers())) {
341: logger
342: .warn("Class "
343: + componentClass.getName()
344: + " is annotated with @"
345: + Service.class.getSimpleName()
346: + ", but not is not a public concrete class, ignored!");
347: continue;
348: }
349: if (!Component.class.isAssignableFrom(componentClass)) {
350: logger.warn("Class " + componentClass.getName()
351: + " is annotated with @"
352: + Service.class.getSimpleName()
353: + ", but not implements interface "
354: + Component.class.getName() + ", ignored!");
355: continue;
356: }
357: ComponentMeta meta = loadComponent(componentClass
358: .asSubclass(Component.class));
359: logger
360: .info("Component " + componentClass.getName()
361: + " loaded with id: "
362: + meta.getComponentId() + "!");
363: }
364: //需è¦?æ˜Žç¡®é¢„åŠ è½½çš„Component,以便能监å?¬ ModuleLoadingEvent
365: preActiveComponent();
366: getFramework().getEventManager().fireModuleEvent(
367: new ModuleLoadingEvent(this ));
368: // 实例化 not lazy components
369: instantiateActiveComponent();
370: getFramework().getEventManager().fireModuleEvent(
371: new ModuleLoadedEvent(this ));
372: }
373:
374: protected void preActiveComponent() {
375:
376: }
377:
378: protected void instantiateActiveComponent()
379: throws ComponentInstantiateException {
380: Collection<ComponentMeta> metas = repo
381: .getModuleComponentMetas();
382: // Collections.sort(metas);
383: for (ComponentMeta meta : metas) {
384: // 立�实例化
385: if (meta.isActive()) {
386: meta.getComponentInstance();
387: }
388: }
389: }
390:
391: public void stop() throws Exception {
392: //
393: }
394:
395: public void destroy() throws Exception {
396:
397: }
398:
399: /**
400: * 销�整个模�, unload all components
401: */
402: public void unload() {
403: List<ComponentMeta> metas = repo.getModuleComponentMetas();
404: // Collections.sort(metas);
405: Collections.reverse(metas);
406: for (ComponentMeta meta : metas) {
407: try {
408: unloadComponent(meta.getComponentId());
409: } catch (ComponentNotFoundException e) {
410: logger.warn("Unload component: "
411: + meta.getComponentId() + " failed.", e);
412: }
413: }
414: getFramework().getEventManager().fireModuleEvent(
415: new ModuleUnloadedEvent(this ));
416: }
417:
418: /**
419: * 获得该模�内的 Component 实例
420: *
421: * @param componentId componentId
422: * @throws ComponentNotFoundException if not found the component or component instantiate failed
423: * @throws ComponentNotExportedException if found component in other module, but it is not exported
424: */
425: public Component getComponent(ComponentId componentId)
426: throws ComponentNotFoundException,
427: ComponentNotExportedException {
428:
429: try {
430: ComponentMeta componentMeta = repo
431: .getComponentMeta(componentId);
432: return componentMeta.getComponentInstance();
433: } catch (ComponentInstantiateException e) {
434: throw new ComponentNotFoundException(
435: "Can not get component, id=" + componentId, e);
436: }
437: }
438:
439: public Component getComponent(String componentId)
440: throws ComponentNotFoundException,
441: ComponentNotExportedException {
442: return getComponent(new ComponentId(componentId));
443: }
444:
445: ComponentMeta getComponentMeta(ComponentId componentId)
446: throws ComponentNotFoundException,
447: ComponentNotExportedException {
448: return repo.getComponentMeta(componentId);
449: }
450:
451: public boolean isComponentLoaded(ComponentId id) {
452: return repo.hasComponentMeta(id);
453: }
454:
455: /**
456: * 组件是å?¦å¯¹å¤–å?‘布,使用了 @Expose æ??述的组件是å?¯å?‘布组件,以其接å?£å?‘布出æ?¥
457: *
458: * @param id component id
459: */
460: public boolean isComponentExported(ComponentId id) {
461: if (!isComponentLoaded(id)) {
462: return false;
463: } else {
464: try {
465: ComponentMeta meta = repo.getComponentMeta(id);
466: return meta.isExported();
467: } catch (ComponentNotExportedException e) {
468: return false;
469: } catch (ComponentNotFoundException e) {
470: return false;
471: }
472: }
473: }
474:
475: public Collection<ComponentMeta> getAllComponentMetas() {
476: return repo.getModuleComponentMetas();
477: }
478:
479: public <T extends Component> Collection<T> findComponentByInterface(
480: Class<T> interfaceClass) {
481: List<T> components = new ArrayList<T>();
482: List<ComponentMeta> searchScope = new ArrayList<ComponentMeta>();
483: if (!interfaceClass.isAnnotationPresent(Exported.class)) {
484: searchScope.addAll(repo.getModuleComponentMetas());
485: } else {
486: searchScope.addAll(repo.getAllComponentMetas());
487: }
488: for (ComponentMeta meta : searchScope) {
489: if (meta.isImplemented(interfaceClass)) {
490: try {
491: components.add((T) meta.getComponentInstance());
492: } catch (ComponentInstantiateException e) {
493: logger.warn("Component instantiate failed, id="
494: + meta.getComponentId(), e);
495: }
496: }
497: }
498: return Collections.unmodifiableCollection(components);
499: }
500:
501: public <T extends Component> Collection<T> findComponentByInterface(
502: Class<T> interfaceClass, String moduleName) {
503: List<T> components = new ArrayList<T>();
504: for (ComponentMeta meta : repo
505: .getModuleComponentMetas(moduleName)) {
506: if (meta.isImplemented(interfaceClass)) {
507: try {
508: components.add((T) meta.getComponentInstance());
509: } catch (ComponentInstantiateException e) {
510: logger.warn("Component instantiate failed, id="
511: + meta.getComponentId(), e);
512: }
513: }
514: }
515: return Collections.unmodifiableCollection(components);
516: }
517:
518: public int compareTo(Module o) {
519: int this Val = this .getPriority();
520: int anotherVal = o.getPriority();
521: return (this Val < anotherVal ? -1 : (this Val == anotherVal ? 0
522: : 1));
523: }
524:
525: public String toString() {
526: return "Module: " + getName();
527: }
528:
529: public static void main(String[] args) {
530:
531: }
532: }
|