View Javadoc

1   /***
2    * Redistribution  and use  in source  and binary  forms, with  or without
3    * modification, are permitted provided  that the following conditions are
4    * met :
5    *
6    * . Redistributions  of  source  code  must  retain  the  above copyright
7    *   notice, this list of conditions and the following disclaimer.
8    *
9    * . Redistributions in  binary form  must reproduce  the above  copyright
10   *   notice, this list of conditions  and the following disclaimer in  the
11   *   documentation and/or other materials provided with the distribution.
12   *
13   * . The name of the author may not be used to endorse or promote products
14   *   derived from this software without specific prior written permission.
15   *
16   * THIS SOFTWARE IS  PROVIDED BY THE  AUTHOR ``AS IS''  AND ANY EXPRESS  OR
17   * IMPLIED  WARRANTIES,  INCLUDING,  BUT   NOT  LIMITED  TO,  THE   IMPLIED
18   * WARRANTIES OF MERCHANTABILITY AND  FITNESS FOR A PARTICULAR  PURPOSE ARE
19   * DISCLAIMED.  IN NO  EVENT SHALL  THE AUTHOR  BE LIABLE  FOR ANY  DIRECT,
20   * INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR  CONSEQUENTIAL  DAMAGES
21   * (INCLUDING,  BUT  NOT LIMITED  TO,  PROCUREMENT OF  SUBSTITUTE  GOODS OR
22   * SERVICES;  LOSS  OF USE,  DATA,  OR PROFITS;  OR  BUSINESS INTERRUPTION)
23   * HOWEVER CAUSED  AND ON  ANY THEORY  OF LIABILITY,  WHETHER IN  CONTRACT,
24   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25   * ANY  WAY  OUT OF  THE  USE OF  THIS  SOFTWARE, EVEN  IF  ADVISED OF  THE
26   * POSSIBILITY OF SUCH DAMAGE.
27   *
28   * $Id$
29   */
30  
31  package palmed.edit.text;
32  
33  import java.io.IOException;
34  import java.io.InputStream;
35  import java.io.OutputStream;
36  import java.util.Enumeration;
37  import java.util.NoSuchElementException;
38  import java.util.Vector;
39  import palmed.io.IRecord;
40  import palmed.io.IRecordFactory;
41  
42  /***
43   * This class implements a cache based on records.
44   *
45   * @author Mathieu Champlon
46   * @version $Revision$ $Date$
47   */
48  public final class Cache implements ICache
49  {
50      /***
51       * The record factory.
52       */
53      private final IRecordFactory factory_;
54      /***
55       * The maximum number of elements in cache at a time.
56       */
57      private final int threshold_;
58      /***
59       * The cachable elements.
60       */
61      private final Vector elements_;
62      /***
63       * The records of the cachable elements.
64       */
65      private final Vector records_;
66      /***
67       * The elements in cache.
68       */
69      private final Vector awake_;
70  
71      /***
72       * Create a cache.
73       *
74       * @param factory the record factory
75       * @param threshold the maximum number of elements in cache at a time
76       */
77      public Cache( final IRecordFactory factory, final int threshold )
78      {
79          if( factory == null )
80              throw new IllegalArgumentException( "parameter 'factory' is null" );
81          if( threshold <= 0 )
82              throw new IllegalArgumentException( "parameter 'threshold' must be > 0" );
83          factory_ = factory;
84          threshold_ = threshold;
85          awake_ = new Vector();
86          records_ = new Vector();
87          elements_ = new Vector();
88      }
89  
90      /***
91       * {@inheritDoc}
92       */
93      public Enumeration elements()
94      {
95          return elements_.elements();
96      }
97  
98      /***
99       * {@inheritDoc}
100      */
101     public void add( final ICachable cachable )
102     {
103         if( cachable == null )
104             throw new IllegalArgumentException( "parameter 'cachable' is null" );
105         elements_.addElement( cachable );
106         records_.addElement( factory_.createRecord( cachable ) );
107         awake_.addElement( cachable );
108         sleep();
109     }
110 
111     /***
112      * {@inheritDoc}
113      */
114     public void wake( final ICachable cachable )
115     {
116         if( cachable == null )
117             return;
118         if( !awake_.removeElement( cachable ) )
119         {
120             final int index = elements_.indexOf( cachable );
121             if( index == -1 )
122                 throw new NoSuchElementException();
123             final IRecord record = (IRecord)records_.elementAt( index );
124             record.restore();
125         }
126         awake_.addElement( cachable );
127         sleep();
128     }
129 
130     private void sleep()
131     {
132         if( awake_.size() > threshold_ )
133         {
134             final ICachable cachable = (ICachable)awake_.firstElement();
135             awake_.removeElementAt( 0 );
136             final int index = elements_.indexOf( cachable );
137             ((IRecord)records_.elementAt( index )).persist();
138             cachable.sleep();
139         }
140     }
141 
142     /***
143      * {@inheritDoc}
144      */
145     public void clear()
146     {
147         elements_.removeAllElements();
148         awake_.removeAllElements();
149         records_.removeAllElements();
150     }
151 
152     /***
153      * {@inheritDoc}
154      */
155     public void unmarshall( final InputStream stream ) throws IOException
156     {
157         clear();
158         do
159         {
160             final ICachable cachable = new Chunk( this );
161             final IRecord record = factory_.createRecord( cachable );
162             record.unmarshall( stream );
163             elements_.addElement( cachable );
164             records_.addElement( record );
165             wake( cachable );
166         }
167         while( stream.available() > 0 );
168     }
169 
170     /***
171      * {@inheritDoc}
172      */
173     public void marshall( final OutputStream stream ) throws IOException
174     {
175         final Enumeration records = records_.elements();
176         while( records.hasMoreElements() )
177         {
178             final IRecord record = (IRecord)records.nextElement();
179             record.persist();
180             record.marshall( stream );
181         }
182     }
183 
184     /***
185      * {@inheritDoc}
186      */
187     public void delete()
188     {
189         final Enumeration records = records_.elements();
190         while( records.hasMoreElements() )
191             ((IRecord)records.nextElement()).delete();
192         clear();
193     }
194 }