001: /*
002: * The contents of this file are subject to the Sapient Public License
003: * Version 1.0 (the "License"); you may not use this file except in compliance
004: * with the License. You may obtain a copy of the License at
005: * http://carbon.sf.net/License.html.
006: *
007: * Software distributed under the License is distributed on an "AS IS" basis,
008: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
009: * the specific language governing rights and limitations under the License.
010: *
011: * The Original Code is The Carbon Component Framework.
012: *
013: * The Initial Developer of the Original Code is Sapient Corporation
014: *
015: * Copyright (C) 2003 Sapient Corporation. All Rights Reserved.
016: */
017:
018: package org.sape.carbon.core.bootstrap;
019:
020: import java.io.ByteArrayInputStream;
021: import java.io.FileInputStream;
022: import java.io.IOException;
023: import java.io.InputStream;
024: import java.net.URL;
025:
026: import org.sape.carbon.core.config.Configuration;
027: import org.sape.carbon.core.config.format.ConfigurationFormatException;
028: import org.sape.carbon.core.config.format.ConfigurationFormatService;
029: import org.sape.carbon.core.config.format.DefaultConfigurationFormatService;
030: import org.sape.carbon.core.config.node.ConfigurationDocument;
031: import org.sape.carbon.core.config.node.Node;
032: import org.sape.carbon.core.config.node.NodeCreationException;
033: import org.sape.carbon.core.config.node.NodeFactory;
034: import org.sape.carbon.core.config.node.NodeIOException;
035: import org.sape.carbon.core.config.node.NodeNotFoundException;
036: import org.sape.carbon.core.config.node.NodeRemovalException;
037: import org.sape.carbon.core.config.node.event.NodeEventListener;
038: import org.sape.carbon.core.config.node.link.LinkNodeConfiguration;
039:
040: import org.apache.commons.logging.Log;
041: import org.apache.commons.logging.LogFactory;
042:
043: /**
044: * <p>An implementation of <code>ConfigurationDocument</code> that provides
045: * functionality specific to retrieving the configuration required to boot
046: * the Carbon Core. This <code>ConfigurationDocument</code> is read-only.
047: * Calls to writeConfiguration or remove will throw an
048: * <code>UnsupportedOperationException</code>.</p>
049: *
050: * <p>
051: * package protected because this implementation need not be visible outside
052: * of bootstrap, it can be referenced by its interface.</p>
053: *
054: * Copyright 2002 Sapient
055: * @since carbon 1.0
056: * @author Douglas Voet, March 2002
057: * @version $Revision: 1.29 $($Author: dvoet $ / $Date: 2003/10/17 14:40:55 $)
058: */
059: class BootConfigurationDocument implements ConfigurationDocument {
060:
061: /** The handle to Apache-commons logger */
062: private Log log = LogFactory.getLog(this .getClass());
063:
064: /**
065: * Config property for the root link.
066: */
067: private static final String ROOT_LINK_PROPERTY_NAME = "carbon.config.RootLink";
068:
069: /**
070: * Contains a complete Xml Configuration file. Used as the default root
071: * link if none can be found.
072: */
073: private static final String DEFAULT_ROOT_LINK = "<Configuration ConfigurationInterface=\"org.sape.carbon.core.config.node.file.FileLinkNodeConfiguration\"><LinkNodeFactoryClass>org.sape.carbon.core.config.node.file.FileLinkNodeFactory</LinkNodeFactoryClass><LinkToPath>{carbon.config.Path}</LinkToPath></Configuration>";
074:
075: /**
076: * The name of the resource that contains the information for the link
077: * to the root of the configuration servie
078: */
079: public static final String ROOT_LINK_RESOURCE_NAME = "CarbonConfigRoot.link";
080: /** The system property key used to define the name of the
081:
082: /** internal configuration object */
083: private LinkNodeConfiguration config;
084:
085: /** the default configuration formatter service. */
086: private ConfigurationFormatService formatter = new DefaultConfigurationFormatService();
087:
088: /**
089: * This constructor loads the <code>BootStrapperConfiguration</code>
090: * for the system. If the system property defined by
091: * <code>BOOT_CONFIG_PROPERTY</code> is specified on the command line,
092: * its value is used as a path to a file that contains the configuration
093: * information. If the system property is not specified, the first
094: * instance of the file named by <code>BOOT_CONFIG_FILE_NAME</code> found
095: * in the classpath is used.
096: * <p>
097: * package protected because only the bootstrap subsystem
098: * should instantiate it
099: */
100: BootConfigurationDocument() {
101:
102: InputStream rootLinkConfigInputStream = null;
103:
104: try {
105: rootLinkConfigInputStream = getRootLinkInputStream();
106:
107: this .config = (LinkNodeConfiguration) this .formatter
108: .readConfigurationStream("",
109: rootLinkConfigInputStream);
110:
111: } catch (ConfigurationFormatException cfe) {
112: throw new BootStrapException(
113: this .getClass(),
114: "Exception reading configuration root link document",
115: cfe);
116:
117: } catch (ClassCastException cce) {
118: throw new BootStrapException(this .getClass(),
119: "Configuration root link object must be of type "
120: + LinkNodeConfiguration.class.getName(),
121: cce);
122: } finally {
123: // close configRootLinkInputStream if it was openned
124: if (rootLinkConfigInputStream != null) {
125: try {
126: rootLinkConfigInputStream.close();
127: } catch (IOException ioe) {
128: // eat it, just wanted to make sure the stream is closed
129: }
130: }
131: }
132: }
133:
134: /**
135: * Gets the configuration object loaded in the constructor
136: *
137: * @return the <code>Configuration</code> object representing the
138: * configurable information required by the bootstrap subsystem.
139: * @throws NodeIOException when there is an exception in dealing
140: * with the configuration backing store
141: * @throws ConfigurationFormatException when the configuration document
142: * to be read has an invalid format or inproper data
143: */
144: public Configuration readConfiguration() throws NodeIOException,
145: ConfigurationFormatException {
146:
147: return this .config;
148: }
149:
150: /**
151: * Not supported by this implementation
152: *
153: * @param config not supported
154: * @throws NodeIOException not supported
155: * @throws ConfigurationFormatException not supported
156: */
157: public void writeConfiguration(Configuration config)
158: throws NodeIOException, ConfigurationFormatException {
159:
160: throw new UnsupportedOperationException(this .getClass()
161: .getName());
162: }
163:
164: /**
165: * This implementation does not support children
166: *
167: * @return false always
168: */
169: public boolean getAllowsChildren() {
170: return false;
171: }
172:
173: /**
174: * Not supported by this implementation
175: *
176: * @throws NodeRemovalException not supported
177: * @return not supported
178: */
179: public int remove() throws NodeRemovalException {
180: throw new UnsupportedOperationException(this .getClass()
181: .getName());
182: }
183:
184: /**
185: * This implementation cannot be refreshed
186: *
187: * @see Node#refresh()
188: */
189: public void refresh() {
190: throw new UnsupportedOperationException(this .getClass()
191: .getName());
192: }
193:
194: /**
195: * @see org.sape.carbon.core.config.node.ConfigurationDocument#addNestedConfigurationDocument
196: */
197: public ConfigurationDocument addNestedConfigurationDocument(
198: String name, Configuration config)
199: throws NodeCreationException {
200: throw new UnsupportedOperationException(this .getClass()
201: .getName());
202: }
203:
204: /**
205: * @see org.sape.carbon.core.config.node.Node#containsChild(String)
206: */
207: public boolean containsChild(String childName) {
208: return false;
209: }
210:
211: /**
212: * @see org.sape.carbon.core.config.node.Node#fetchChild(String)
213: */
214: public Node fetchChild(String childName)
215: throws NodeNotFoundException {
216: throw new NodeNotFoundException(this .getClass(), childName);
217: }
218:
219: /**
220: * @see org.sape.carbon.core.config.node.Node#fetchChildren()
221: */
222: public Node[] fetchChildren() {
223: return new Node[0];
224: }
225:
226: /**
227: * @see org.sape.carbon.core.config.node.Node#getAbsoluteName()
228: */
229: public String getAbsoluteName() {
230: return "";
231: }
232:
233: /**
234: * @see org.sape.carbon.core.config.node.Node#getName()
235: */
236: public String getName() {
237: return "";
238: }
239:
240: /**
241: * @see org.sape.carbon.core.config.node.Node#getParent()
242: */
243: public Node getParent() {
244: return null;
245: }
246:
247: /**
248: * @see org.sape.carbon.core.config.node.Node#isRemoved()
249: */
250: public boolean isRemoved() {
251: return false;
252: }
253:
254: /**
255: * @see org.sape.carbon.core.config.node.ConfigurationDocument#getFormatService()
256: */
257: public ConfigurationFormatService getFormatService() {
258: return this .formatter;
259: }
260:
261: /**
262: * @see org.sape.carbon.core.config.node.Node#addNodeListener(NodeEventListener)
263: */
264: public void addNodeListener(NodeEventListener listener) {
265: // this node cannot change, so listeners will never be notified
266: }
267:
268: /**
269: * Loads the configuration root link. The configuration root link
270: * is located in the following order
271: * <ol>
272: * <ul>
273: * Load the config root link specifed in the deployment property
274: * carbon.config.RootLink
275: * </ul>
276: * <ul>
277: * Load the config root link CarbonConfigRoot.link from the classloader
278: * </ul>
279: * <ul>
280: * if everything fails load the deault config root link specified
281: * in this document
282: * </ul>
283: * </ol>
284: *
285: * @return input stream to the root link document
286: */
287: private InputStream getRootLinkInputStream() {
288:
289: InputStream rootLinkInputStream = null;
290:
291: //1. get config root link from deployment property carbon.
292: // config.RootLink
293: try {
294: if (log.isDebugEnabled()) {
295: log.debug("Attempting to load configuration root link "
296: + "by using deployment property "
297: + ROOT_LINK_PROPERTY_NAME);
298: }
299:
300: String rootLinkFileName = BootStrapper.getInstance()
301: .getDeploymentProperty(ROOT_LINK_PROPERTY_NAME);
302:
303: if (rootLinkFileName != null) {
304: // file name exists in deployment properties,
305: // get link from there
306: if (log.isInfoEnabled()) {
307: log
308: .info("Using file to load configuration root link"
309: + ": file name ["
310: + rootLinkFileName + "]");
311: }
312:
313: rootLinkInputStream = new FileInputStream(
314: rootLinkFileName);
315: }
316: } catch (IOException ioe) {
317: if (log.isInfoEnabled()) {
318: log.info(
319: "Attempted to get configuration root link from file "
320: + "but caught IOException", ioe);
321: }
322:
323: // ensure that rootLinkInputStream is null and
324: // continue to other options
325: rootLinkInputStream = null;
326: }
327:
328: //2. get config root link by loading ROOT_LINK_RESOURCE_NAME
329: // from classloader
330: try {
331: if (rootLinkInputStream == null) {
332: if (log.isDebugEnabled()) {
333: log.debug("Attempting to load configuration root "
334: + "link resource ["
335: + ROOT_LINK_RESOURCE_NAME
336: + "] from the class loader ");
337: }
338:
339: // get from ClassLoader
340: // This will always load the file from the same Classpath,
341: // using the same ClassLoader as was used to load this class.
342: ClassLoader classLoader = this .getClass()
343: .getClassLoader();
344: URL rootLinkURL = classLoader
345: .getResource(ROOT_LINK_RESOURCE_NAME);
346:
347: if (rootLinkURL != null) {
348: if (log.isInfoEnabled()) {
349: log
350: .info("Using ClassLoader to load configuration "
351: + "root link: resource ["
352: + rootLinkURL.getPath() + "]");
353: }
354:
355: rootLinkInputStream = rootLinkURL.openStream();
356: }
357: }
358: } catch (IOException ioe) {
359: if (log.isInfoEnabled()) {
360: log.info("Attempted to get configuration root link "
361: + "from ClassLoader but caught IOException",
362: ioe);
363: }
364:
365: // ensure that rootLinkInputStream is null and
366: // continue to other options
367: rootLinkInputStream = null;
368: }
369:
370: //3. finally if nothing works, load the default config
371: // root link specified in the boot configuration document
372: if (rootLinkInputStream == null) {
373: if (log.isInfoEnabled()) {
374: log.info("Configuration root link wasnt located, "
375: + "Using default config root link");
376: }
377:
378: // ensure that rootLinkInputStream is null and
379: // continue to other options
380: rootLinkInputStream = new ByteArrayInputStream(
381: DEFAULT_ROOT_LINK.getBytes());
382: }
383:
384: return rootLinkInputStream;
385: }
386:
387: /**
388: * @see org.sape.carbon.core.config.node.ConfigurationDocument#getNestedNodeFactory()
389: */
390: public NodeFactory getNestedNodeFactory() {
391: return null;
392: }
393:
394: }
|