001: /*
002:
003: This software is OSI Certified Open Source Software.
004: OSI Certified is a certification mark of the Open Source Initiative.
005:
006: The license (Mozilla version 1.0) can be read at the MMBase site.
007: See http://www.MMBase.org/license
008:
009: */
010: package org.mmbase.framework;
011:
012: import java.util.*;
013: import org.w3c.dom.*;
014: import org.mmbase.util.*;
015: import org.mmbase.util.xml.Instantiator;
016:
017: import org.mmbase.util.logging.Logger;
018: import org.mmbase.util.logging.Logging;
019:
020: /**
021: * This (singleton) class maintains all compoments which are registered in the current MMBase.
022: *
023: * @author Michiel Meeuwissen
024: * @version $Id: ComponentRepository.java,v 1.30 2008/02/22 14:30:35 michiel Exp $
025: * @since MMBase-1.9
026: */
027: public class ComponentRepository {
028:
029: public static final String XSD_COMPONENT = "component.xsd";
030: public static final String NAMESPACE_COMPONENT = "http://www.mmbase.org/xmlns/component";
031:
032: public static final String XSD_FRAMEWORK = "framework.xsd";
033: public static final String NAMESPACE_FRAMEWORK = "http://www.mmbase.org/xmlns/framework";
034: static {
035: XMLEntityResolver.registerSystemID(
036: NAMESPACE_COMPONENT + ".xsd", XSD_COMPONENT,
037: ComponentRepository.class);
038: XMLEntityResolver.registerSystemID(
039: NAMESPACE_FRAMEWORK + ".xsd", XSD_FRAMEWORK,
040: ComponentRepository.class);
041: }
042:
043: private static final Logger log = Logging
044: .getLoggerInstance(ComponentRepository.class);
045:
046: private static final ComponentRepository repository = new ComponentRepository();
047:
048: public static ComponentRepository getInstance() {
049: return repository;
050: }
051:
052: static {
053: ResourceWatcher rw = new ResourceWatcher() {
054: public void onChange(String r) {
055: getInstance().readConfiguration(r);
056: }
057: };
058: rw.add("components");
059: rw.onChange();
060: rw.setDelay(2 * 1000); // 2 s
061: rw.start();
062:
063: }
064:
065: private final Map<String, Component> rep = new HashMap<String, Component>();
066: private final List<Component> failed = new ArrayList<Component>();
067:
068: private ComponentRepository() {
069: }
070:
071: /**
072: * @javadoc
073: */
074: public Block.Type[] getBlockClassification(String id) {
075: if (id == null) {
076: return new Block.Type[] { Block.Type.ROOT };
077: } else {
078: return Block.Type.getClassification(id, false);
079: }
080:
081: }
082:
083: /**
084: * The available components.
085: */
086: public Collection<Component> getComponents() {
087: return Collections.unmodifiableCollection(rep.values());
088: }
089:
090: /**
091: * The components which could not be instantiated or configured, due to some
092: * misconfiguration.
093: */
094: public Collection<Component> getFailedComponents() {
095: return Collections.unmodifiableCollection(failed);
096: }
097:
098: /**
099: * Acquires the component with given name, or <code>null</code> if no such component.
100: */
101: public Component getComponent(String name) {
102: return rep.get(name);
103: }
104:
105: public Block getBlock(String componentName, String blockName) {
106: Component component = getComponent(componentName);
107: if (component == null)
108: throw new IllegalArgumentException(
109: "No component with name '" + componentName + "'");
110: return component.getBlock(blockName);
111: }
112:
113: protected boolean resolve() {
114: int unsatisfied = 0;
115: for (Component comp : getComponents()) {
116: for (VirtualComponent virtual : comp
117: .getUnsatisfiedDependencies()) {
118: Component proposed = getComponent(virtual.getName());
119: if (proposed != null) {
120: if (proposed.getVersion() >= virtual.getVersion()) {
121: comp.resolve(virtual, proposed);
122: } else {
123: unsatisfied++;
124: log.warn("" + comp + " depends on " + virtual
125: + " but the version of " + proposed
126: + " is only " + proposed.getVersion());
127: }
128: } else {
129: unsatisfied++;
130: log.warn("" + comp + " depends on " + virtual
131: + " but no such component.");
132: }
133: }
134: }
135:
136: return unsatisfied == 0;
137: }
138:
139: public void shutdown() {
140: clear();
141: }
142:
143: protected void clear() {
144: Block.Type.ROOT.subs.clear();
145: Block.Type.ROOT.blocks.clear();
146: Block.Type.NO.subs.clear();
147: Block.Type.NO.blocks.clear();
148: rep.clear();
149: failed.clear();
150: }
151:
152: /**
153: * Reads all component xmls
154: */
155: protected void readConfiguration(String child) {
156: clear();
157: ResourceLoader loader = ResourceLoader.getConfigurationRoot()
158: .getChildResourceLoader(child);
159: Collection<String> components = loader.getResourcePaths(
160: ResourceLoader.XML_PATTERN, true /* recursive*/);
161: log.info("In " + loader
162: + " the following components XML's were found "
163: + components);
164: for (String file : components) {
165: try {
166: Document doc = loader.getDocument(file, true,
167: getClass());
168: String namespace = doc.getDocumentElement()
169: .getNamespaceURI();
170: String name = doc.getDocumentElement().getAttribute(
171: "name");
172: String fileName = ResourceLoader.getName(file);
173: if (!fileName.equals(name)) {
174: log.warn("Component " + name
175: + " is defined in resource with name "
176: + file);
177: } else {
178: log.service("Instantiating component '" + name
179: + "' " + namespace);
180: }
181: if (rep.containsKey(name)) {
182: failed.add(getComponent(name, doc));
183: Component org = rep.get(name);
184: log
185: .error("There is already a component with name '"
186: + name
187: + "' ("
188: + org.getUri()
189: + "), "
190: + doc.getDocumentURI()
191: + " defines another one, which is now ignored");
192: } else {
193: rep.put(name, getComponent(name, doc));
194: }
195: } catch (Exception e) {
196: log.error("For " + loader.getResource(file) + ": "
197: + e.getMessage(), e);
198: }
199: }
200: if (!resolve()) {
201: log
202: .error("Not all components satisfied their dependencies");
203: }
204: log.info("Found the following components " + getComponents());
205:
206: }
207:
208: /**
209: * Given an XML, creates and configures one component.
210: */
211: protected Component getComponent(String name, Document doc)
212: throws org.xml.sax.SAXException, ClassNotFoundException,
213: NoSuchMethodException, InstantiationException,
214: IllegalAccessException,
215: java.lang.reflect.InvocationTargetException {
216:
217: Component component = (Component) Instantiator
218: .getInstanceWithSubElement(doc.getDocumentElement(),
219: name);
220: if (component == null) {
221: component = new BasicComponent(name);
222: }
223: component.configure(doc.getDocumentElement());
224: return component;
225: }
226:
227: }
|