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 }