KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > outerj > daisy > books > store > impl > CommonBookInstance


1 /*
2  * Copyright 2004 Outerthought bvba and Schaubroeck nv
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.outerj.daisy.books.store.impl;
17
18 import org.outerj.daisy.books.store.*;
19 import org.outerj.daisy.xmlutil.LocalSAXParserFactory;
20 import org.apache.xmlbeans.XmlOptions;
21 import org.apache.xmlbeans.XmlObject;
22 import org.outerx.daisy.x10Bookstoremeta.ResourcePropertiesDocument;
23
24 import java.io.*;
25 import java.net.URI JavaDoc;
26 import java.util.Date JavaDoc;
27 import java.util.Collection JavaDoc;
28 import java.util.List JavaDoc;
29 import java.util.ArrayList JavaDoc;
30
31 /**
32  * A book instance. Instances of this object can be used by multiple users/thread, this
33  * object is wrapped inside a {@link UserBookInstance} by the {@link CommonBookStore}
34  * before returning it to a particular user.
35  */

36 public class CommonBookInstance implements BookInstance {
37     private final File bookInstanceDirectory;
38     private final AclResource aclResource;
39     private final PublicationsInfoResource publicationsInfoResource;
40     private final MetaDataResource metaDataResource;
41     private final CommonBookStore owner;
42
43     private static final int BUFFER_SIZE = 32768;
44     static final String JavaDoc ACL_FILENAME = "acl.xml";
45     static final String JavaDoc PUBLICATIONS_INFO_FILENAME = "publications_info.xml";
46     static final String JavaDoc METADATA_FILENAME = "metadata.xml";
47     static final String JavaDoc[] META_FILES = {ACL_FILENAME, PUBLICATIONS_INFO_FILENAME, METADATA_FILENAME};
48     static final String JavaDoc LOCK_FILE_NAME = "lock";
49
50     protected CommonBookInstance(File bookInstanceDirectory, CommonBookStore owner) {
51         this.bookInstanceDirectory = bookInstanceDirectory;
52         this.owner = owner;
53         this.aclResource = new AclResource(new File(bookInstanceDirectory, ACL_FILENAME));
54         this.publicationsInfoResource = new PublicationsInfoResource(new File(bookInstanceDirectory, PUBLICATIONS_INFO_FILENAME));
55         this.metaDataResource = new MetaDataResource(new File(bookInstanceDirectory, METADATA_FILENAME));
56     }
57
58     File getDirectory() {
59         return bookInstanceDirectory;
60     }
61
62     public String JavaDoc getName() {
63         return bookInstanceDirectory.getName();
64     }
65
66     public InputStream getResource(String JavaDoc path) {
67         File file = getFile(path);
68
69         FileInputStream fis;
70         try {
71             fis = new FileInputStream(file);
72         } catch (FileNotFoundException e) {
73             throw new BookResourceNotFoundException("Resource not found: " + path);
74         }
75         return new BufferedInputStream(fis);
76     }
77
78     public ResourcePropertiesDocument getResourceProperties(String JavaDoc path) {
79         String JavaDoc metaFileName = path + ".meta.xml";
80         File metaFile = getFile(metaFileName);
81         if (metaFile.exists()) {
82             try {
83                 XmlOptions xmlOptions = new XmlOptions().setLoadUseXMLReader(LocalSAXParserFactory.newXmlReader());
84                 ResourcePropertiesDocument propertiesDocument = ResourcePropertiesDocument.Factory.parse(metaFile, xmlOptions);
85                 return propertiesDocument;
86             } catch (Exception JavaDoc e) {
87                 throw new RuntimeException JavaDoc("Error reading resource properties.", e);
88             }
89         }
90         return null;
91     }
92
93     public void storeResourceProperties(String JavaDoc path, ResourcePropertiesDocument resourcePropertiesDocument) {
94         XmlOptions xmlOptions = new XmlOptions();
95         xmlOptions.setSavePrettyPrint();
96         xmlOptions.setUseDefaultNamespace();
97         storeResource(path + ".meta.xml", resourcePropertiesDocument.newInputStream(xmlOptions));
98     }
99
100     public void storeResource(String JavaDoc path, InputStream is) {
101         BookStoreException exception = null;
102         try {
103             File file = getFileForStorage(path);
104             FileOutputStream fos = null;
105             try {
106                 try {
107                     fos = new FileOutputStream(file);
108                     BufferedOutputStream bos = new BufferedOutputStream(fos);
109                     byte[] buffer = new byte[BUFFER_SIZE];
110                     int read;
111                     while ((read = is.read(buffer)) != -1) {
112                         bos.write(buffer, 0, read);
113                     }
114                     bos.flush();
115                     fos.getFD().sync();
116                 } finally {
117                     if (fos != null)
118                         fos.close();
119                 }
120             } catch (IOException e) {
121                 exception = new BookStoreException("Error storing resource in book instance.", e);
122                 throw exception;
123             }
124         } finally {
125             try {
126                 is.close();
127             } catch (IOException e) {
128                 if (exception != null) {
129                     // don't hide original exception
130
throw new BookStoreException("Error closing input stream, but also got an earlier exception.", exception);
131                 } else {
132                     throw new BookStoreException("Error closing input stream.", e);
133                 }
134             }
135         }
136     }
137
138     public OutputStream getResourceOutputStream(String JavaDoc path) throws IOException {
139         File file = getFileForStorage(path);
140         return new BufferedOutputStream(new FileOutputStream(file));
141     }
142
143     public boolean rename(String JavaDoc path, String JavaDoc newName) {
144         if (path == null)
145             throw new IllegalArgumentException JavaDoc("path argument cannot be null");
146         if (newName == null)
147             throw new IllegalArgumentException JavaDoc("newName argument cannot be null");
148         if (newName.indexOf(System.getProperty("file.separator")) != -1)
149             throw new IllegalArgumentException JavaDoc("New name may not contain a slash.");
150
151         File file = new File(bookInstanceDirectory, path);
152         if (!BookUtil.isWithin(bookInstanceDirectory, file))
153             throw new BookStoreException("It is not allowed to access a file outside of the book instance directory.");
154
155         return file.renameTo(new File(file.getParent(), newName));
156     }
157
158     private File getFileForStorage(String JavaDoc path) {
159         File file = new File(bookInstanceDirectory, path);
160         if (!BookUtil.isWithin(bookInstanceDirectory, file))
161             throw new BookStoreException("It is not allowed to write a file outside of the book instance directory.");
162
163         File parentDir = file.getParentFile();
164         if (!parentDir.exists())
165             parentDir.mkdirs();
166
167         return file;
168     }
169
170     public boolean exists(String JavaDoc path) {
171         return getFile(path).exists();
172     }
173
174     public long getLastModified(String JavaDoc path) {
175         return getFile(path).lastModified();
176     }
177
178     public long getContentLength(String JavaDoc path) {
179         return getFile(path).length();
180     }
181
182     private File getFile(String JavaDoc path) {
183         File file = new File(bookInstanceDirectory, path);
184         if (!BookUtil.isWithin(bookInstanceDirectory, file))
185             throw new BookStoreException("It is not allowed to access a file outside of the book instance directory.");
186         return file;
187     }
188
189     boolean isLocked() {
190         File lockFile = new File(getDirectory(), CommonBookInstance.LOCK_FILE_NAME);
191         return lockFile.exists();
192     }
193
194     public void lock() {
195         throw new BookStoreException("This method should never be called.");
196     }
197
198     public void unlock() {
199         throw new BookStoreException("This method should never be called.");
200     }
201
202     public boolean canManage() {
203         throw new BookStoreException("This method should never be called.");
204     }
205
206     public BookAcl getAcl() {
207         return aclResource.get();
208     }
209
210     public void setAcl(BookAcl bookAcl) {
211         aclResource.store(bookAcl);
212     }
213
214     public PublicationsInfo getPublicationsInfo() {
215         return publicationsInfoResource.get();
216     }
217
218     public void addPublication(PublicationInfo publicationInfo) {
219         PublicationInfo[] infos = getPublicationsInfo().getInfos();
220         PublicationInfo[] newInfos = new PublicationInfo[infos.length + 1];
221         System.arraycopy(infos, 0, newInfos, 0, infos.length);
222         newInfos[newInfos.length - 1] = publicationInfo;
223         publicationsInfoResource.store(new PublicationsInfo(newInfos));
224     }
225
226     public void setPublications(PublicationsInfo publicationsInfo) {
227         publicationsInfoResource.store(publicationsInfo);
228     }
229
230     public BookInstanceMetaData getMetaData() {
231         return (BookInstanceMetaData)metaDataResource.get().clone();
232     }
233
234     public void setMetaData(BookInstanceMetaData metaData) {
235         metaDataResource.store((BookInstanceMetaData)metaData.clone());
236     }
237
238     public URI JavaDoc getResourceURI(String JavaDoc path) {
239         return getFile(path).toURI();
240     }
241
242     public String JavaDoc[] getDescendantPaths(String JavaDoc path) {
243         File file = getFile(path);
244         if (!file.isDirectory()) {
245             throw new RuntimeException JavaDoc("path is not a directory: " + path);
246         }
247
248         List JavaDoc result = new ArrayList JavaDoc();
249         collectPaths(file.listFiles(), result, bookInstanceDirectory.getAbsolutePath());
250         return (String JavaDoc[])result.toArray(new String JavaDoc[result.size()]);
251     }
252
253     private void collectPaths(File[] files, Collection JavaDoc result, String JavaDoc refPath) {
254         for (int i = 0; i < files.length; i++) {
255             if (files[i].isDirectory()) {
256                 collectPaths(files[i].listFiles(), result, refPath);
257             } else {
258                 String JavaDoc path = files[i].getAbsolutePath();
259                 if (!path.startsWith(refPath))
260                     throw new RuntimeException JavaDoc("Assertion error: path does not start with refPath");
261                 result.add(path.substring(refPath.length()));
262             }
263         }
264     }
265
266     /**
267      * Method to be called upon initial creation of the book instance.
268      */

269     void initialize(String JavaDoc label, BookAcl initialAcl, long creator) {
270         BookInstanceMetaData metaData = new BookInstanceMetaData(label, new Date JavaDoc(), creator);
271         // First write a lock file, before writing the other meta files, so that no other user can get a lock on the book instance
272
try {
273             new File(bookInstanceDirectory, LOCK_FILE_NAME).createNewFile();
274         } catch (IOException e) {
275             throw new BookStoreException("Error locking newly created book instance.", e);
276         }
277         metaDataResource.store(metaData);
278         publicationsInfoResource.store(new PublicationsInfo(new PublicationInfo[0]));
279         aclResource.store(initialAcl);
280     }
281
282     private static XmlOptions getMetaXmlOptions() {
283         XmlOptions xmlOptions = new XmlOptions();
284         xmlOptions.setSavePrettyPrint();
285         xmlOptions.setUseDefaultNamespace();
286         return xmlOptions;
287     }
288
289     abstract class RefreshableResource {
290         private final File file;
291         private long lastModifed;
292         private Object JavaDoc object;
293         private final String JavaDoc what;
294
295         public RefreshableResource(File file, String JavaDoc what) {
296             this.file = file;
297             this.what = what;
298         }
299
300         protected Object JavaDoc getObject() {
301             if (object == null || (lastModifed != file.lastModified()))
302                 loadObject();
303             return object;
304         }
305
306         protected void loadObject() {
307             synchronized(file) {
308                 long lastModified = file.lastModified();
309                 Object JavaDoc object;
310                 try {
311                     object = create(new BufferedInputStream(new FileInputStream(file)));
312                 } catch (FileNotFoundException e) {
313                     owner.notifyBookInstanceDeleted(CommonBookInstance.this);
314                     throw new NonExistingBookInstanceException(getName());
315                 } catch (Exception JavaDoc e) {
316                     throw new BookStoreException("Error loading book " + what, e);
317                 }
318                 this.object = object;
319                 this.lastModifed = lastModified;
320             }
321         }
322
323         protected abstract Object JavaDoc create(InputStream is) throws Exception JavaDoc;
324
325         protected void store(Object JavaDoc object, XmlObject xmlObject) {
326             synchronized(file) {
327                 try {
328                     OutputStream os = null;
329                     try {
330                         os = new BufferedOutputStream(new FileOutputStream(file));
331                         xmlObject.save(os, getMetaXmlOptions());
332                     } finally {
333                         if (os != null)
334                             os.close();
335                     }
336                 } catch (Exception JavaDoc e) {
337                     throw new BookStoreException("Error storing book ACL.", e);
338                 }
339                 this.object = object;
340                 this.lastModifed = file.lastModified();
341             }
342         }
343     }
344
345     class AclResource extends RefreshableResource {
346         public AclResource(File file) {
347             super(file, "ACL");
348         }
349
350         protected Object JavaDoc create(InputStream is) throws Exception JavaDoc {
351             return BookAclBuilder.build(is);
352         }
353
354         public BookAcl get() {
355             return (BookAcl)getObject();
356         }
357
358         public void store(BookAcl bookAcl) {
359             store(bookAcl, bookAcl.getXml());
360         }
361     }
362
363     class PublicationsInfoResource extends RefreshableResource {
364         public PublicationsInfoResource(File file) {
365             super(file, "publications info");
366         }
367
368         protected Object JavaDoc create(InputStream is) throws Exception JavaDoc {
369             return PublicationsInfoBuilder.build(is);
370         }
371
372         PublicationsInfo get() {
373             return (PublicationsInfo)getObject();
374         }
375
376         void store(PublicationsInfo publicationsInfo) {
377             store(publicationsInfo, publicationsInfo.getXml());
378         }
379     }
380
381     class MetaDataResource extends RefreshableResource {
382         public MetaDataResource(File file) {
383             super(file, "meta data");
384         }
385
386         protected Object JavaDoc create(InputStream is) throws Exception JavaDoc {
387             return BookInstanceMetaDataBuilder.build(is);
388         }
389
390         public BookInstanceMetaData get() {
391             return (BookInstanceMetaData)getObject();
392         }
393
394         public void store(BookInstanceMetaData metaData) {
395             store(metaData, metaData.getXml());
396         }
397     }
398 }
399
Popular Tags