KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > sape > carbon > services > config > jar > JarConfigurationDocument


1 /*
2  * The contents of this file are subject to the Sapient Public License
3  * Version 1.0 (the "License"); you may not use this file except in compliance
4  * with the License. You may obtain a copy of the License at
5  * http://carbon.sf.net/License.html.
6  *
7  * Software distributed under the License is distributed on an "AS IS" basis,
8  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
9  * the specific language governing rights and limitations under the License.
10  *
11  * The Original Code is The Carbon Component Framework.
12  *
13  * The Initial Developer of the Original Code is Sapient Corporation
14  *
15  * Copyright (C) 2003 Sapient Corporation. All Rights Reserved.
16  */

17
18 package org.sape.carbon.services.config.jar;
19
20 import java.io.File JavaDoc;
21 import java.io.IOException JavaDoc;
22 import java.io.InputStream JavaDoc;
23 import java.io.OutputStream JavaDoc;
24 import java.util.jar.JarEntry JavaDoc;
25
26 import org.sape.carbon.core.config.format.ConfigurationFormatService;
27 import org.sape.carbon.core.config.node.AbstractConfigurationDocument;
28 import org.sape.carbon.core.config.node.Node;
29 import org.sape.carbon.core.config.node.NodeRemovalException;
30 import org.sape.carbon.core.exception.IllegalStateException;
31 import org.sape.carbon.core.exception.InvalidParameterException;
32 import org.sape.carbon.core.util.jar.EnhancedJarFile;
33 import org.sape.carbon.core.util.thread.ReadWriteLock;
34
35 import org.apache.commons.logging.Log;
36 import org.apache.commons.logging.LogFactory;
37
38 /**
39  * <p>Implementation of ConfigurationDocument using entries within jar files
40  * as the backing datastore.</p>
41  *
42  * <p>This implementation does not maintain an open jar file. It will open
43  * the jar file only when it needs to read or write and close it when it is
44  * done.</p>
45  *
46  * Copyright 2002 Sapient
47  * @since carbon 1.0
48  * @author Douglas Voet, April 2002
49  * @version $Revision: 1.2 $($Author: dvoet $ / $Date: 2003/05/05 21:21:09 $)
50  */

51 public class JarConfigurationDocument
52     extends AbstractConfigurationDocument {
53
54     /**
55      * Provides a handle to Apache-commons logger
56      */

57     private Log log = LogFactory.getLog(this.getClass());
58
59     /** Holds the simple reference to the jar file. */
60     private File JavaDoc jarFile;
61
62     /** Name of the jar entry. */
63     private String JavaDoc jarEntryName;
64
65     /** Holds the enhanced jar being wrapped. */
66     private EnhancedJarFile currentOpenJar = null;
67
68     /** flags if the jar is open for read. */
69     private boolean jarOpenForRead;
70
71     /** Holds a read/write lock for this jar. */
72     private final ReadWriteLock readWriteLock;
73
74     /**
75      * Constructor for JarConfigurationDocument.
76      *
77      * @param parent the parent node of the configuration document
78      * @param name name of the configuration document
79      * @param formatter formatter to use on the document
80      * @param readWriteLock lock for the document
81      * @param jarFile jarfile the document is wrapping
82      * @param jarEntryName entry inside the jarfile
83      */

84     public JarConfigurationDocument(
85         Node parent,
86         String JavaDoc name,
87         ConfigurationFormatService formatter,
88         ReadWriteLock readWriteLock,
89         File JavaDoc jarFile,
90         String JavaDoc jarEntryName) {
91
92         super(parent, name, formatter);
93
94         // validate parameters and set member attributes
95
if (jarFile != null) {
96             this.jarFile = jarFile;
97         } else {
98             throw new InvalidParameterException(
99                 this.getClass(),
100                 "The ["
101                     + getAbsoluteName()
102                     + "] JarConfigurationDocument "
103                     + "node jarFile reference cannot be null");
104         }
105
106         if (jarEntryName != null) {
107             this.jarEntryName = jarEntryName;
108         } else {
109             throw new InvalidParameterException(
110                 this.getClass(),
111                 "The ["
112                     + getAbsoluteName()
113                     + "] JarConfigurationDocument "
114                     + "node jarEntryName cannot be null");
115         }
116
117         if (readWriteLock != null) {
118             this.readWriteLock = readWriteLock;
119         } else {
120             throw new InvalidParameterException(
121                 this.getClass(),
122                 "The ["
123                     + getAbsoluteName()
124                     + "] JarConfigurationDocument "
125                     + "node readWriteLock reference cannot be null");
126         }
127     }
128
129     /**
130      * @see AbstractConfigurationDocument#openInputStream()
131      */

132     protected InputStream JavaDoc openInputStream() throws IOException JavaDoc {
133
134         EnhancedJarFile jar = openJar(true);
135
136         JarEntry JavaDoc jarEntry = (JarEntry JavaDoc) jar.getEntry(this.jarEntryName);
137         if (jarEntry == null) {
138             closeJar();
139             throw new IllegalStateException JavaDoc(
140                 this.getClass(),
141                 "JarEntry [" + this.jarEntryName
142                     + "] was not found in the jar ["
143                     + jarFile.getAbsolutePath() + "]");
144         }
145
146         return jar.getInputStream(jarEntry);
147     }
148
149     /**
150      * @see AbstractConfigurationDocument#closeInputStream(InputStream)
151      */

152     protected void closeInputStream(InputStream JavaDoc in) throws IOException JavaDoc {
153
154         // NG (Bug 371) closeJar moved in finally block so that it is called
155
// even if there is an IOException in in.close().
156
try {
157             in.close();
158         } catch (IOException JavaDoc ioe) {
159             throw ioe;
160         } finally {
161             closeJar();
162         }
163     }
164
165     /**
166      * @see AbstractConfigurationDocument#openOutputStream()
167      */

168     protected OutputStream JavaDoc openOutputStream() throws IOException JavaDoc {
169         EnhancedJarFile jar = openJar(false);
170         return jar.getEntryOutputStream(this.jarEntryName);
171     }
172
173     /**
174      * @see AbstractConfigurationDocument#closeOutputStream(OutputStream)
175      */

176     protected void closeOutputStream(OutputStream JavaDoc out)
177         throws IOException JavaDoc {
178
179         // NG (Bug 371) closeJar moved in finally block so that it is called
180
// even if there is an IOException in in.close().
181
try {
182             out.close();
183         } catch (IOException JavaDoc ioe) {
184             throw ioe;
185         } finally {
186             closeJar();
187         }
188     }
189
190     /**
191      * @see org.sape.carbon.core.config.node.AbstractNode#destroyBackingData()
192      */

193     protected void destroyBackingData() throws NodeRemovalException {
194         EnhancedJarFile jar = null;
195         try {
196
197             jar = openJar(false);
198             jar.removeEntry((JarEntry JavaDoc) jar.getEntry(this.jarEntryName));
199
200         } catch (IOException JavaDoc ioe) {
201             throw new NodeRemovalException(
202                 this.getClass(), this, ioe);
203
204         } finally {
205             if (jar != null) {
206                 // close jar
207
try {
208                     closeJar();
209                 } catch (IOException JavaDoc ioe) {
210                     // log it and eat it
211
if (log.isWarnEnabled()) {
212                         log.warn("Could not closr jar ["
213                             + currentOpenJar.getName() + "]");
214                     }
215                 }
216             }
217         }
218     }
219
220     /**
221      * @see org.sape.carbon.core.config.node.AbstractConfigurationDocument#backingDataExists()
222      */

223     protected boolean backingDataExists() {
224         if (!this.jarFile.exists() || this.jarFile.isDirectory()) {
225             return false;
226         }
227
228         try {
229             EnhancedJarFile jar = openJar(true);
230             JarEntry JavaDoc entry = jar.getJarEntry(this.jarEntryName);
231             return (entry != null && !entry.isDirectory());
232
233         } catch (IOException JavaDoc ioe) {
234             return false;
235
236         } finally {
237             try {
238                 closeJar();
239             } catch (IOException JavaDoc e) {
240                 // log it and eat it
241
if (log.isWarnEnabled()) {
242                     log.warn("Could not close jar ["
243                         + currentOpenJar.getName() + "]");
244                 }
245             }
246         }
247     }
248
249     /**
250      * Opens the jar file. Based on the boolean value of forRead, a
251      * read or a write lock will be acquired.
252      *
253      * @param forRead if true a read lock will be acquired, if false,
254      * a write lock will be acquired
255      * @return the opened jar file
256      * @throws IOException indicates an error opening the jar
257      */

258     private EnhancedJarFile openJar(boolean forRead) throws IOException JavaDoc {
259
260         if (this.currentOpenJar != null) {
261             // if the jar is already open, don't open a new one, but
262
// log it as a warning since we should not maintain open jars
263
if (log.isWarnEnabled()) {
264                 log.warn("Jar file [" + currentOpenJar.getName()
265                     + "] has not been closed");
266             }
267         } else {
268             // get the monitor for reading or writing
269
try {
270                 if (forRead) {
271                     this.readWriteLock.readLock().acquire();
272                     this.jarOpenForRead = true;
273                 } else {
274                     this.readWriteLock.writeLock().acquire();
275                     this.jarOpenForRead = false;
276                 }
277             } catch (InterruptedException JavaDoc ie) {
278                 Thread.currentThread().interrupt();
279                 throw new IllegalStateException JavaDoc(
280                     this.getClass(),
281                     "Caught interupt exception before acquiring jar monitor",
282                     ie);
283             }
284             // open the jar
285
this.currentOpenJar = new EnhancedJarFile(this.jarFile);
286         }
287
288         return this.currentOpenJar;
289     }
290
291     /**
292      * Closes the jar file if it is open, releasing the lock based upon how
293      * it was opened.
294      *
295      * @throws IOException indicates an error closing the jar
296      */

297     private void closeJar() throws IOException JavaDoc {
298         if (this.currentOpenJar != null) {
299
300             // NG (Bug 371) Make sured that the read/write lock is released
301
// under any circumstances.
302
try {
303                 this.currentOpenJar.close();
304             } catch (IOException JavaDoc ioe) {
305                 // simply throw the exception.
306
throw ioe;
307             } finally {
308                 this.currentOpenJar = null;
309                 if (this.jarOpenForRead) {
310                     this.readWriteLock.readLock().release();
311                 } else {
312                     this.readWriteLock.writeLock().release();
313                 }
314             }
315         }
316     }
317 }
318
Popular Tags