Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/virtuosotechnologies/asaph/xmldatabase/IndexedDatabaseFactoryImpl.java


1   /*
2   ================================================================================
3   
4     FILE:  IndexedDatabaseFactoryImpl.java
5     
6     PROJECT:
7     
8       Asaph
9     
10    CONTENTS:
11    
12      Implementation of IndexedDatabaseFactory
13    
14    PROGRAMMERS:
15    
16      Daniel Azuma (DA)  <dazuma@kagi.com>
17    
18    COPYRIGHT:
19    
20      Copyright (C) 2003  Daniel Azuma  (dazuma@kagi.com)
21      
22      This program is free software; you can redistribute it and/or
23      modify it under the terms of the GNU General Public License as
24      published by the Free Software Foundation; either version 2
25      of the License, or (at your option) any later version.
26      
27      This program is distributed in the hope that it will be useful,
28      but WITHOUT ANY WARRANTY; without even the implied warranty of
29      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30      GNU General Public License for more details.
31      
32      You should have received a copy of the GNU General Public
33      License along with this program; if not, write to
34        Free Software Foundation, Inc.
35        59 Temple Place, Suite 330
36        Boston, MA 02111-1307 USA
37  
38  ================================================================================
39  */
40  
41  
42  package com.virtuosotechnologies.asaph.xmldatabase;
43  
44  
45  import java.io.IOException;
46  import java.io.FileNotFoundException;
47  import java.io.File;
48  import java.io.FilenameFilter;
49  import java.io.OutputStream;
50  import java.io.FileOutputStream;
51  import java.io.InputStream;
52  import java.io.FileInputStream;
53  import java.net.URL;
54  import javax.xml.parsers.SAXParserFactory;
55  import javax.xml.parsers.SAXParser;
56  import javax.xml.parsers.ParserConfigurationException;
57  import org.xml.sax.SAXException;
58  import org.xml.sax.ErrorHandler;
59  
60  import com.virtuosotechnologies.lib.util.FileUtils;
61  import com.virtuosotechnologies.lib.util.StringID;
62  import com.virtuosotechnologies.lib.xml.XMLDocumentUnparser;
63  import com.virtuosotechnologies.lib.xml.ZeroToleranceErrorHandler;
64  
65  import com.virtuosotechnologies.asaph.model.Song;
66  import com.virtuosotechnologies.asaph.model.SongID;
67  import com.virtuosotechnologies.asaph.model.SongDatabase;
68  import com.virtuosotechnologies.asaph.modelutils.SongUtils;
69  import com.virtuosotechnologies.asaph.standardmodel.StandardModelFactory;
70  
71  
72  /**
73   * Implementation of IndexedDatabaseFactory
74   */
75  /*package*/ class IndexedDatabaseFactoryImpl
76  implements
77    IndexedDatabaseFactory
78  {
79    private static final String DTD_FILENAME = "databaseindex.dtd";
80    private static final String STR_PreferredCharacterEncoding =
81      ResourceAccess.Strings.buildString("PreferredCharacterEncoding");
82    
83    private SAXParserFactory parserFactory_;
84    private SongUtils songUtils_;
85    private StandardModelFactory modelFactory_;
86    private String dtdString_;
87    
88    
89    /**
90     * Constructor
91     */
92    /*package*/ IndexedDatabaseFactoryImpl(
93      SongUtils songUtils,
94      StandardModelFactory modelFactory)
95    throws
96      IOException
97    {
98      songUtils_ = songUtils;
99      modelFactory_ = modelFactory;
100     parserFactory_ = SAXParserFactory.newInstance();
101     parserFactory_.setValidating(true);
102     parserFactory_.setNamespaceAware(true);
103     dtdString_ = FileUtils.readResourceCompletely(getClass(), DTD_FILENAME);
104   }
105   
106   
107   /**
108    * Create a new mutable indexed database rooted at the given directory.
109    *
110    * @param directory directory to create
111    * @return database created
112    * @exception IOException fatal error
113    * @exception SAXException fatal error
114    */
115   public SongDatabase createIndexedDatabase(
116     File directory)
117   throws
118     IOException,
119     SAXException
120   {
121     if (directory.exists())
122     {
123       throw new IOException(ResourceAccess.Strings.buildString(
124         "err_DirExists", directory));
125     }
126     if (!directory.mkdirs())
127     {
128       throw new IOException(ResourceAccess.Strings.buildString(
129         "err_CantCreateDir", directory));
130     }
131     File indexFile = new File(directory, IndexConstants.INDEX_FILENAME);
132     OutputStream stream = new FileOutputStream(indexFile);
133     try
134     {
135       XMLDocumentUnparser unparser = XMLDocumentUnparser.create(stream, STR_PreferredCharacterEncoding,
136         IndexConstants.XMLDATABASEINDEX_DTD, IndexConstants.INDEXROOT_ELEMENT);
137       unparser.addAttribute("xmlns", IndexConstants.XMLDATABASEINDEX_NAMESPACE);
138       unparser.startMultiLineElement(IndexConstants.INDEX_ELEMENT);
139       unparser.addAttribute(IndexConstants.INDEX_LASTID_ATTRIBUTE, "");
140       unparser.endElement(IndexConstants.INDEX_ELEMENT);
141       unparser.finishDocument(IndexConstants.INDEXROOT_ELEMENT);
142     }
143     finally
144     {
145       try
146       {
147         stream.close();
148       }
149       catch (IOException ex)
150       {
151       }
152     }
153     return openIndexedDatabase(directory);
154   }
155   
156   
157   /**
158    * Open a mutable indexed database backed by the filesystem at the given directory.
159    *
160    * @param directory indexed database to open
161    * @return database opened
162    * @exception IOException fatal error
163    * @exception SAXException fatal error
164    */
165   public SongDatabase openIndexedDatabase(
166     File directory)
167   throws
168     IOException,
169     SAXException
170   {
171     if (!directory.isDirectory())
172     {
173       throw new IOException(ResourceAccess.Strings.buildString(
174         "err_NotDir", directory));
175     }
176     try
177     {
178       SAXParser parser = parserFactory_.newSAXParser();
179       return new IndexedSongDatabase(songUtils_, modelFactory_, directory,
180         parser, dtdString_);
181     }
182     catch (ParserConfigurationException ex)
183     {
184       throw new IOException(ResourceAccess.Strings.buildString(
185         "err_UnexpectedException", ex));
186     }
187   }
188   
189   
190   /**
191    * Open an immutable indexed database backed by the given URL.
192    *
193    * @param url indexed database to open
194    * @param errorHandler handler for errors parsing the index file
195    * @return database opened
196    * @exception IOException fatal error
197    * @exception SAXException fatal error
198    */
199   public SongDatabase openIndexedDatabase(
200     URL url,
201     ErrorHandler errorHandler)
202   throws
203     IOException,
204     SAXException
205   {
206     String urlStr = url.toExternalForm();
207     if (urlStr.charAt(urlStr.length()-1) != '/')
208     {
209       urlStr += '/';
210     }
211     url = new URL(urlStr);
212     try
213     {
214       SAXParser parser = parserFactory_.newSAXParser();
215       return new IndexedSongDatabase(songUtils_, modelFactory_, url, parser,
216         dtdString_, errorHandler);
217     }
218     catch (ParserConfigurationException ex)
219     {
220       throw new IOException(ResourceAccess.Strings.buildString(
221         "err_UnexpectedException", ex));
222     }
223   }
224   
225   
226   /**
227    * Is the given database an indexed database?
228    *
229    * @param database database to check
230    * @return true if it is an indexed database
231    */
232   public boolean isIndexedDatabase(
233     SongDatabase database)
234   {
235     return database instanceof IndexedSongDatabase;
236   }
237   
238   
239   /**
240    * Update a filesystem indexed database from version 0.3 to version 0.4.
241    *
242    * @param directory indexed database to update
243    * @exception IOException fatal error
244    * @exception SAXException fatal error
245    */
246   public void updateDatabase04(
247     File directory)
248   throws
249     IOException,
250     SAXException
251   {
252     String[] contents = directory.list(
253       new FilenameFilter()
254       {
255         public boolean accept(
256           File dir,
257           String name)
258         {
259           if (!name.startsWith(IndexConstants.SONG_PREFIX) ||
260             !name.endsWith(IndexConstants.SONG_SUFFIX_OLD))
261           {
262             return false;
263           }
264           name = name.substring(IndexConstants.SONG_PREFIX.length(),
265             name.length()-IndexConstants.SONG_SUFFIX_OLD.length());
266           return StringID.isWellFormed(name);
267         }
268       });
269     if (contents == null)
270     {
271       throw new FileNotFoundException();
272     }
273     
274     for (int i=0; i<contents.length; ++i)
275     {
276       File file = new File(directory, contents[i]);
277       String idStr = contents[i].substring(IndexConstants.SONG_PREFIX.length(),
278         contents[i].length()-IndexConstants.SONG_SUFFIX_OLD.length());
279       InputStream is = null;
280       OutputStream os = null;
281       try
282       {
283         SongID songID = new DummySongIDImpl(new StringID(idStr));
284         is = new FileInputStream(file);
285         Song song = modelFactory_.parseSong(FileUtils.createUTFReader(is),
286           songID, new ZeroToleranceErrorHandler());
287         is.close();
288         is = null;
289         String versionStr = modelFactory_.getSongVersion(song).getValue();
290         File file2 = new File(directory, IndexConstants.SONG_PREFIX+idStr+
291           IndexConstants.SONG_INTER+versionStr+IndexConstants.SONG_SUFFIX);
292         os = new FileOutputStream(file2);
293         modelFactory_.unparseSong(song, os, STR_PreferredCharacterEncoding);
294         os.close();
295         os = null;
296         file.delete();
297       }
298       finally
299       {
300         try
301         {
302           if (is != null)
303           {
304             is.close();
305           }
306           if (os != null)
307           {
308             os.close();
309           }
310         }
311         catch (IOException ex)
312         {
313         }
314       }
315     }
316     
317     new File(directory, IndexConstants.INDEX_FILENAME_OLD).delete();
318   }
319   
320   
321   /**
322    * Dummy implementation of SongID
323    */
324   /*package*/ class DummySongIDImpl
325   implements SongID
326   {
327     private StringID id_;
328     
329     /*package*/ DummySongIDImpl(
330       StringID id)
331     {
332       id_ = id;
333     }
334     
335     public SongDatabase getDatabase()
336     {
337       return null;
338     }
339     
340     public String getStringRepresentation()
341     {
342       return id_.getValue();
343     }
344     
345     public boolean equals(
346       Object obj)
347     {
348       if (obj instanceof DummySongIDImpl)
349       {
350         DummySongIDImpl ssid = (DummySongIDImpl)obj;
351         return ssid.id_.equals(id_);
352       }
353       return false;
354     }
355     
356     public int hashCode()
357     {
358       return id_.hashCode();
359     }
360   }
361 }