001: package de.webman.util.registry;
002:
003: import java.util.HashMap;
004: import java.io.IOException;
005: import javax.xml.parsers.DocumentBuilderFactory;
006: import javax.xml.parsers.DocumentBuilder;
007: import javax.xml.parsers.ParserConfigurationException;
008: import org.w3c.dom.Node;
009: import org.w3c.dom.Document;
010: import org.w3c.dom.Element;
011: import org.xml.sax.SAXException;
012: import org.xml.sax.InputSource;
013: import java.io.File;
014: import java.io.IOException;
015: import java.io.InputStream;
016: import java.io.FileInputStream;
017: import java.io.BufferedInputStream;
018: import org.apache.log4j.Category;
019:
020: /**
021: * The central registry class. Implemented as singleton.<p>
022: *
023: * The normal way to use managers in webman is to request an instance of
024: * the Registry, using the {@link #getInstance()} method, and looking up
025: * the Manager from the resulting instance using the manager's id. For
026: * example:<p>
027: *
028: * <code><pre>
029: * MyManager reg = (MyManager)Registry.getInstance().lookup("acl");
030: * Boolean authgrp = (Boolean)reg.get("AUTH_GROUP", Boolean.FALSE);
031: * </pre></code>
032: *
033: * Since webman is a (kind of) webapplication and webapplications live in
034: * hostile environment (at least from the point of configuration at start
035: * up time), the configuration of the Registry is a bit weird. It is done
036: * using a xml file read in the very first time, the Registry is
037: * configured. Any following tries to configure it are simply ignored (see
038: * {@link #setConfiguration()}). The structure of the xml config file is
039: * as follows:<p>
040: *
041: * <code><pre>
042: * <!ELEMENT registry (factories?)>
043: * <!ELEMENT factories (registry*)>
044: * <!ELEMENT manager #EMPTY>
045: * <!ATTLIST manager load-scheme (start|lazy) "lazy"
046: * factory-class CDATA #REQUIRED>
047: * </pre></code>
048: *
049: * Example:<p>
050: *
051: * <code><pre>
052: * <registry>
053: * <factories>
054: * <manager load-scheme="start" factory-class="de.webman.acl.AclMgrFactory"/>
055: * <manager load-scheme="lazy" factory-class="de.webman.sync.SyncMgrFactory"/>
056: * <factories>
057: * </registry>
058: * </pre></code>
059: *
060: * @author <a href="mailto:gregor@webman.de">Gregor Klinke</a>
061: * @version $Revision: 1.2 $
062: **/
063: public class Registry {
064: /* $Id: Registry.java,v 1.2 2002/04/12 12:30:24 gregor Exp $ */
065:
066: /**
067: * the loggin facility
068: **/
069: private static Category cat = Category.getInstance(Registry.class);
070:
071: /**
072: * denotes a manager load on start
073: **/
074: public static final String START_LOAD_SCHEME = "start";
075:
076: /**
077: * denotes a lazy manager load
078: **/
079: public static final String LAZY_LOAD_SCHEME = "lazy";
080:
081: /**
082: * the singleton instance
083: **/
084: private static Registry singleton = null;
085:
086: /**
087: * the cache of yet loaded managers. (contains {@link
088: * de.webman.util.registry.Manager} instances)
089: **/
090: private HashMap instMgrs = new HashMap();
091:
092: /**
093: * the list of known manager factories. This maps manager ids to
094: * {@link de.webman.util.registry.ManagerFactory} instances. This
095: * classes are used to created Manager instances, which are cached in
096: * {@link #instMgrs}.
097: **/
098: private HashMap managers = new HashMap();
099:
100: /**
101: * the base directory of the application
102: **/
103: private String basedir = "/";
104:
105: /**
106: * is the mgr been configured yet?
107: **/
108: private boolean configuredYet = false;
109:
110: /* ----------------------------------------------------------------------
111: creating and returning the singleton instance
112: ---------------------------------------------------------------------- */
113: /**
114: * private constructor, only to be used by getInstance
115: **/
116: private Registry() {
117: }
118:
119: /**
120: * returns the singleton instance
121: * @return never <code>null</code>
122: **/
123: public static Registry getInstance() {
124: if (singleton == null)
125: singleton = new Registry();
126: return singleton;
127: }
128:
129: /* ----------------------------------------------------------------------
130: configuration
131: ---------------------------------------------------------------------- */
132: /**
133: * sets the configuration file of the instance. This is can be done only once.
134: * @param _basedir the absolute directory path to the base directory of
135: * the application
136: * @param _cfg the path to the configuration file relative to _basedir
137: *
138: * @return return <code>true</code> if the manager has not been
139: * configured before, and <code>false</code>, if it has (the
140: * configuration attempt) has been ignored).
141: *
142: * @throws IOException if the XML config file could not be read
143: **/
144: public boolean setConfiguration(String _basedir, String _cfg)
145: throws IOException, RegistryException {
146: if (!configuredYet) {
147: basedir = _basedir;
148: readXMLStream(new BufferedInputStream(new FileInputStream(
149: new File(_basedir, _cfg))));
150: configuredYet = true;
151: return true;
152: }
153: return false;
154: }
155:
156: /**
157: * reads a xml config file. for the xml structure see above
158: **/
159: private void readXMLStream(BufferedInputStream in)
160: throws IOException, RegistryException {
161: DocumentBuilderFactory factory = DocumentBuilderFactory
162: .newInstance();
163: factory.setNamespaceAware(false);
164: factory.setValidating(false);
165:
166: Document doc = null;
167: try {
168: DocumentBuilder builder = factory.newDocumentBuilder();
169: doc = builder.parse(new InputSource(in));
170: } catch (ParserConfigurationException pce) {
171: throw new RegistryException(pce);
172: } catch (SAXException se) {
173: throw new RegistryException(se);
174: }
175:
176: Node nd = doc.getDocumentElement();
177: if (!("registry".equals(nd.getNodeName())))
178: throw new RegistryException("bad root element '"
179: + nd.getNodeName() + "'");
180:
181: for (Node c1 = nd.getFirstChild(); c1 != null; c1 = c1
182: .getNextSibling()) {
183: if (c1.getNodeType() == Node.ELEMENT_NODE) {
184: if ("factories".equals(c1.getNodeName())) {
185: for (Node c2 = c1.getFirstChild(); c2 != null; c2 = c2
186: .getNextSibling()) {
187: if (c2.getNodeType() == Node.ELEMENT_NODE) {
188: if ("manager".equals(c2.getNodeName())) {
189: String load_scheme = ((Element) c2)
190: .getAttribute("load-scheme");
191: String factory_class = ((Element) c2)
192: .getAttribute("factory-class");
193:
194: registerFactoryClass(load_scheme,
195: factory_class);
196: } else
197: throw new RegistryException(
198: "unknown element: '"
199: + c2.getNodeName()
200: + "'");
201: }
202: }
203: } else
204: throw new RegistryException("unknown element: '"
205: + c1.getNodeName() + "'");
206: }
207: }
208: }
209:
210: /**
211: * returns the first text element below a context node
212: **/
213: private String getTextData(Node cntx) {
214: cntx.normalize();
215:
216: for (Node n = cntx.getFirstChild(); n != null; n = n
217: .getNextSibling()) {
218: if (n.getNodeType() == Node.TEXT_NODE) {
219: return n.getNodeValue();
220: } else if (n.getNodeType() == Node.CDATA_SECTION_NODE) {
221: return n.getNodeValue();
222: }
223: }
224: return null;
225: }
226:
227: /**
228: * loads and registers a manager class. If the load scheme of the
229: * manager is set to <b>start</b>, a manager instance is requested
230: * from the factory, initialized and registered with the cache; all
231: * other managers are handled lazy (they are only initialized and
232: * loaded when requested).
233: *
234: * @param load_scheme the load scheme, <b>lazy</b> means, creates and
235: * register a manager only when needed; <b>start</b> means, create the
236: * manager when loaded.
237: * @param factory_class the fully qualified class name for the manager
238: * factory class
239: **/
240: private void registerFactoryClass(String load_scheme,
241: String factory_class) {
242: try {
243: Class factclass = Class.forName(factory_class);
244:
245: ManagerFactory fact = (ManagerFactory) factclass
246: .newInstance();
247: String mgrid = fact.getID();
248:
249: if (START_LOAD_SCHEME.equals(load_scheme)) {
250: try {
251: instAndRegisterManager(fact);
252: managers.put(mgrid, fact);
253: cat.debug("Loading manager factory '"
254: + fact.getID() + "': success");
255: } catch (RegistryException re) {
256: cat.error("Manager could not be instanciated: "
257: + re);
258: /* don't register the factory, since creating an
259: instance failed! */
260: }
261: } else if (LAZY_LOAD_SCHEME.equals(load_scheme)) {
262: cat.debug("Loading manager factory '" + fact.getID()
263: + "': success");
264: managers.put(mgrid, fact);
265: } else {
266: cat.debug("Loading manager factory '" + fact.getID()
267: + "': success");
268: managers.put(mgrid, fact);
269: }
270: } catch (ClassNotFoundException cnfe) {
271: cat.error("Class not found: '" + cnfe + "'");
272: } catch (IllegalAccessException iae) {
273: cat.error("Class could not be instantiated: " + iae);
274: } catch (InstantiationException ie) {
275: cat.error("Class could not be instantiated: " + ie);
276: } catch (ClassCastException cce) {
277: cat
278: .error("Class does not implement ManagerFactory: "
279: + cce);
280: }
281: }
282:
283: /* ----------------------------------------------------------------------
284: looking up managers
285: ---------------------------------------------------------------------- */
286: /**
287: * lookup a manager using the registry id. The manager is allocated
288: * newly (if not done yet), otherwise the cached instance of the
289: * manager is returned.
290: *
291: * @param mgrid the manager id
292: * @return the found manager or <code>null</code> if no such manager
293: * is known
294: *
295: * @throws RegistryException if anything fails
296: **/
297: public Manager lookup(String mgrid) throws RegistryException {
298: Manager mgr = (Manager) instMgrs.get(mgrid);
299:
300: if (mgr == null) {
301: ManagerFactory fact = (ManagerFactory) managers.get(mgrid);
302: if (fact != null)
303: mgr = instAndRegisterManager(fact);
304: }
305:
306: return mgr;
307: }
308:
309: /**
310: * instanciates and registers a manager from a manager factory
311: **/
312: private Manager instAndRegisterManager(ManagerFactory mgrfact)
313: throws RegistryException {
314: Manager mgr = mgrfact.newManager(basedir);
315: instMgrs.put(mgrfact.getID(), mgr);
316: return mgr;
317: }
318: }
|