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.config.node;
019:
020: import org.sape.carbon.core.config.Configuration;
021: import org.sape.carbon.core.config.InvalidConfigurationException;
022: import org.sape.carbon.core.config.format.ConfigurationFormatException;
023: import org.sape.carbon.core.config.node.link.LinkNode;
024: import org.sape.carbon.core.config.node.link.LinkNodeConfiguration;
025: import org.sape.carbon.core.config.node.link.LinkNodeFactory;
026: import org.sape.carbon.core.exception.InvalidParameterException;
027:
028: /**
029: * This implementation of the <code>Folder</code> interface caches its
030: * children as they are requested. This implementation interfaces with the
031: * backing data store through sub-classes implementing the methods
032: * <code>loadChild</code> and <code>getAllChildNames</code>.
033: *
034: * Copyright 2002 Sapient
035: * @since carbon 1.0
036: * @author Douglas Voet, February 2002
037: * @version $Revision: 1.32 $($Author: dvoet $ / $Date: 2003/10/16 20:57:29 $)
038: */
039: public abstract class AbstractFolder extends AbstractNode implements
040: Folder {
041:
042: /**
043: * Factory used to construct all Folders within this folder. Final
044: * because the reference to the factory should never change.
045: */
046: private final NodeFactory subFolderFactory;
047:
048: /**
049: * factory used to construct all ConfigurationDocuments within this
050: * folder. Final because the reference to the factory should never change.
051: */
052: private final NodeFactory configurationDocumentFactory;
053:
054: /**
055: * factory used to construct all LinkNodes within this
056: * folder. Final because the reference to the factory should never change.
057: */
058: private final NodeFactory linkNodeFactory;
059:
060: /**
061: * Constructor for AbstractFolder.
062: *
063: * @param parent the node's parent
064: * @param name the node's name
065: * @param subFolderFactory factory to use for sub folders
066: * @param configurationDocumentFactory factory to use for
067: * creating configuration documents
068: * @param linkNodeFactory factory to use for creating link nodes.
069: *
070: * @throws InvalidParameterException if name, subFolderFactory, or
071: * configurationDocumentFactory is null
072: */
073: public AbstractFolder(Node parent, String name,
074: Object readOrAlterNodeLock, Object addOrLoadChildLock,
075: NodeFactory subFolderFactory,
076: NodeFactory configurationDocumentFactory,
077: NodeFactory linkNodeFactory) {
078:
079: super (parent, name, readOrAlterNodeLock, addOrLoadChildLock);
080:
081: // parameter check
082: if (subFolderFactory == null) {
083: throw new InvalidParameterException(this .getClass(),
084: "subFolderFactory parameter cannot be null");
085: }
086: if (configurationDocumentFactory == null) {
087: throw new InvalidParameterException(this .getClass(),
088: "configurationDocumentFactory parameter cannot be null");
089: }
090: if (linkNodeFactory == null) {
091: throw new InvalidParameterException(this .getClass(),
092: "linkNodeFactory parameter cannot be null");
093: }
094:
095: this .subFolderFactory = subFolderFactory;
096: this .configurationDocumentFactory = configurationDocumentFactory;
097: this .linkNodeFactory = linkNodeFactory;
098: }
099:
100: /**
101: * Constructor for AbstractFolder.
102: *
103: * @param parent the node's parent
104: * @param name the node's name
105: * @param subFolderFactory factory to use for sub folders
106: * @param configurationDocumentFactory factory to use for
107: * creating configuration documents
108: * @param linkNodeFactory factory to use for creating link nodes.
109: *
110: * @throws InvalidParameterException if name, subFolderFactory, or
111: * configurationDocumentFactory is null
112: */
113: public AbstractFolder(Node parent, String name,
114: NodeFactory subFolderFactory,
115: NodeFactory configurationDocumentFactory,
116: NodeFactory linkNodeFactory) {
117:
118: super (parent, name);
119:
120: // parameter check
121: if (subFolderFactory == null) {
122: throw new InvalidParameterException(this .getClass(),
123: "subFolderFactory parameter cannot be null");
124: }
125: if (configurationDocumentFactory == null) {
126: throw new InvalidParameterException(this .getClass(),
127: "configurationDocumentFactory parameter cannot be null");
128: }
129: if (linkNodeFactory == null) {
130: throw new InvalidParameterException(this .getClass(),
131: "linkNodeFactory parameter cannot be null");
132: }
133:
134: this .subFolderFactory = subFolderFactory;
135: this .configurationDocumentFactory = configurationDocumentFactory;
136: this .linkNodeFactory = linkNodeFactory;
137: }
138:
139: /**
140: * @see Folder#addConfigurationDocument
141: *
142: * synchronized to ensure no one is fetching or removing children while
143: * this method is removing them
144: */
145: public ConfigurationDocument addConfigurationDocument(String name,
146: Configuration config) throws NodeCreationException {
147:
148: if (isRemoved()) {
149: throw new NodeRemovedException(this .getClass(), this );
150: }
151:
152: ConfigurationDocument newDocument = createNewConfigurationDocument(
153: name, config);
154:
155: return newDocument;
156: }
157:
158: /**
159: * @see Folder#addSubFolder(String)
160: *
161: * synchronized to ensure no one is fetching or removing children while
162: * this method is removing them
163: */
164: public Folder addSubFolder(String name)
165: throws NodeCreationException {
166:
167: if (isRemoved()) {
168: throw new NodeRemovedException(this .getClass(), this );
169: }
170:
171: Folder newFolder = createNewFolder(name);
172:
173: return newFolder;
174: }
175:
176: /**
177: * @see Folder#addLink
178: */
179: public LinkNode addLink(String name,
180: LinkNodeConfiguration linkConfiguration)
181: throws NodeCreationException {
182:
183: if (isRemoved()) {
184: throw new NodeRemovedException(this .getClass(), this );
185: }
186:
187: try {
188: synchronized (getAddOrLoadChildLock()) {
189:
190: // note that the call to the linkNodeFactory is not within
191: // the sync on this. this is because getInstance could possibly
192: // require other locks and maintaining a lock on this object while
193: // requiring a lock on another object opens us up to deadlock
194: ConfigurationDocument linkConfigurationDoc = (ConfigurationDocument) this .linkNodeFactory
195: .getInstance(this , name);
196:
197: synchronized (getReadOrAlterNodeLock()) {
198: if (containsChild(name)) {
199: throw new NodeCreationException(
200: this .getClass(), this , name,
201: "Node already exists");
202: }
203:
204: linkConfigurationDoc
205: .writeConfiguration(linkConfiguration);
206: }
207:
208: LinkNodeFactory linkFactory = (LinkNodeFactory) linkConfiguration
209: .getLinkNodeFactoryClass().newInstance();
210:
211: LinkNode newLink = linkFactory.getInstance(this , name,
212: linkConfigurationDoc);
213:
214: synchronized (getReadOrAlterNodeLock()) {
215: this .childNodes.put(name, newLink);
216: }
217:
218: return newLink;
219: }
220:
221: } catch (NodeIOException nioe) {
222: throw new NodeCreationException(this .getClass(), this ,
223: name, "Could not write link configuration", nioe);
224:
225: } catch (ConfigurationFormatException cfe) {
226: throw new NodeCreationException(this .getClass(), this ,
227: name, "Could not write link configuration", cfe);
228:
229: } catch (ClassCastException cce) {
230: throw new InvalidConfigurationException(this .getClass(),
231: this .getAbsoluteName() + Node.DELIMITER + name,
232: "LinkNodeFactoryClass",
233: "Class is not an instance of LinkNodeFactory", cce);
234:
235: } catch (InstantiationException ie) {
236: throw new InvalidConfigurationException(this .getClass(),
237: this .getAbsoluteName() + Node.DELIMITER + name,
238: "LinkNodeFactoryClass", "Could instantiate class",
239: ie);
240:
241: } catch (IllegalAccessException iae) {
242: throw new InvalidConfigurationException(this .getClass(),
243: this .getAbsoluteName() + Node.DELIMITER + name,
244: "LinkNodeFactoryClass", "Could instantiate class",
245: iae);
246: }
247: }
248:
249: /**
250: * @see Folder#getConfigurationDocumentFactory()
251: */
252: public NodeFactory getConfigurationDocumentFactory() {
253: return this .configurationDocumentFactory;
254: }
255:
256: /**
257: * @see Folder#getSubFolderFactory()
258: */
259: public NodeFactory getSubFolderFactory() {
260: return this .subFolderFactory;
261: }
262:
263: /**
264: * Uses the subFolderFactory to create a child <code>Folder</code> and
265: * adds it to childNodes
266: *
267: * @param name name of the <code>Folder</code>
268: * @return Folder the new child
269: *
270: * @throws NodeCreationException if the child could not be created for
271: * any reason
272: */
273: protected Folder createNewFolder(String name)
274: throws NodeCreationException {
275:
276: synchronized (getAddOrLoadChildLock()) {
277: if (containsChild(name)) {
278: throw new NodeCreationException(this .getClass(), this ,
279: name, "Node already exists");
280: }
281:
282: // note that the call to the subFolderFactory is not within
283: // the sync on this. this is because getInstance could possibly
284: // require other locks and maintaining a lock on this object while
285: // requiring a lock on another object opens us up to deadlock
286: Folder newFolder = (Folder) this .subFolderFactory
287: .getInstance(this , name);
288:
289: synchronized (getReadOrAlterNodeLock()) {
290: this .childNodes.put(name, newFolder);
291: }
292:
293: return newFolder;
294: }
295:
296: }
297:
298: /**
299: * Uses the configurationDocumentFactory to create a child
300: * <code>ConfigurationDocument</code> and adds it to childNodes.
301: *
302: * @param name name of the <code>ConfigurationDocument</code>
303: * @param config the new config to write
304: * @return ConfigurationDocument the new child
305: *
306: * @throws NodeCreationException if the child could not be created for
307: * any reason
308: */
309: protected ConfigurationDocument createNewConfigurationDocument(
310: String name, Configuration config)
311: throws NodeCreationException {
312:
313: synchronized (getReadOrAlterNodeLock()) {
314: // note that the call to the configurationDocumentFactory is not
315: // within the sync on this. this is because getInstance could possibly
316: // require other locks and maintaining a lock on this object while
317: // requiring a lock on another object opens us up to deadlock
318: ConfigurationDocument newDoc = (ConfigurationDocument) this .configurationDocumentFactory
319: .getInstance(this , name);
320:
321: synchronized (getReadOrAlterNodeLock()) {
322: if (containsChild(name)) {
323: throw new NodeCreationException(this .getClass(),
324: this , name, "Node already exists");
325: }
326:
327: try {
328: // write to the new docuemnt
329: // note that this synchronizes on newDoc but that is OK
330: // because no one else has access to newDoc yet.
331: newDoc.writeConfiguration(config);
332: } catch (NodeIOException nioe) {
333: throw new NodeCreationException(
334: this .getClass(),
335: this ,
336: name,
337: "Could not write to new ConfigurationDocument",
338: nioe);
339:
340: } catch (ConfigurationFormatException cfe) {
341: throw new NodeCreationException(
342: this .getClass(),
343: this ,
344: name,
345: "Could not write to new ConfigurationDocument",
346: cfe);
347: }
348:
349: this .childNodes.put(name, newDoc);
350:
351: return newDoc;
352: }
353: }
354: }
355:
356: /**
357: * @see Folder#getSubFolderFactory()
358: */
359: public NodeFactory getLinkNodeFactory() {
360: return this.linkNodeFactory;
361: }
362: }
|