001package org.apache.commons.jcs.engine;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *   http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import java.util.ArrayList;
023import java.util.List;
024
025import org.apache.commons.jcs.engine.behavior.IElementAttributes;
026import org.apache.commons.jcs.engine.control.event.behavior.IElementEventHandler;
027
028/**
029 * This it the element attribute descriptor class. Each element in the cache has an ElementAttribute
030 * object associated with it. An ElementAttributes object can be associated with an element in 3
031 * ways:
032 * <ol>
033 * <li>When the item is put into the cache, you can associate an element attributes object.</li>
034 * <li>If not attributes object is include when the element is put into the cache, then the default
035 * attributes for the region will be used.</li>
036 * <li>The element attributes can be reset. This effectively results in a retrieval followed by a
037 * put. Hence, this is the same as 1.</li>
038 * </ol>
039 */
040public class ElementAttributes
041    implements IElementAttributes
042{
043    /** Don't change. */
044    private static final long serialVersionUID = 7814990748035017441L;
045
046    /** Can this item be flushed to disk */
047    private boolean IS_SPOOL = true;
048
049    /** Is this item laterally distributable */
050    private boolean IS_LATERAL = true;
051
052    /** Can this item be sent to the remote cache */
053    private boolean IS_REMOTE = true;
054
055    /**
056     * You can turn off expiration by setting this to true. This causes the cache to bypass both max
057     * life and idle time expiration.
058     */
059    private boolean IS_ETERNAL = true;
060
061    /** Max life seconds */
062    private long maxLife = -1;
063
064    /**
065     * The maximum time an entry can be idle. Setting this to -1 causes the idle time check to be
066     * ignored.
067     */
068    private long maxIdleTime = -1;
069
070    /** The byte size of the field. Must be manually set. */
071    private int size = 0;
072
073    /** The creation time. This is used to enforce the max life. */
074    private long createTime = 0;
075
076    /** The last access time. This is used to enforce the max idel time. */
077    private long lastAccessTime = 0;
078
079    /**
080     * The list of Event handlers to use. This is transient, since the event handlers cannot usually
081     * be serialized. This means that you cannot attach a post serialization event to an item.
082     * <p>
083     * TODO we need to check that when an item is passed to a non-local cache that if the local
084     * cache had a copy with event handlers, that those handlers are used.
085     */
086    private transient ArrayList<IElementEventHandler> eventHandlers;
087
088    private long timeFactor = 1000;
089
090    /**
091     * Constructor for the IElementAttributes object
092     */
093    public ElementAttributes()
094    {
095        this.createTime = System.currentTimeMillis();
096        this.lastAccessTime = this.createTime;
097    }
098
099    /**
100     * Constructor for the IElementAttributes object
101     * <p>
102     * @param attr
103     */
104    protected ElementAttributes( ElementAttributes attr )
105    {
106        IS_ETERNAL = attr.IS_ETERNAL;
107
108        // waterfall onto disk, for pure disk set memory to 0
109        IS_SPOOL = attr.IS_SPOOL;
110
111        // lateral
112        IS_LATERAL = attr.IS_LATERAL;
113
114        // central rmi store
115        IS_REMOTE = attr.IS_REMOTE;
116
117        maxLife = attr.maxLife;
118        // time-to-live
119        maxIdleTime = attr.maxIdleTime;
120        size = attr.size;
121    }
122
123    /**
124     * Sets the maxLife attribute of the IAttributes object.
125     * <p>
126     * @param mls The new MaxLifeSeconds value
127     */
128    @Override
129    public void setMaxLife(long mls)
130    {
131        this.maxLife = mls;
132    }
133
134    /**
135     * Sets the maxLife attribute of the IAttributes object. How many seconds it can live after
136     * creation.
137     * <p>
138     * If this is exceeded the element will not be returned, instead it will be removed. It will be
139     * removed on retrieval, or removed actively if the memory shrinker is turned on.
140     * @return The MaxLifeSeconds value
141     */
142    @Override
143    public long getMaxLife()
144    {
145        return this.maxLife;
146    }
147
148    /**
149     * Sets the idleTime attribute of the IAttributes object. This is the maximum time the item can
150     * be idle in the cache, that is not accessed.
151     * <p>
152     * If this is exceeded the element will not be returned, instead it will be removed. It will be
153     * removed on retrieval, or removed actively if the memory shrinker is turned on.
154     * @param idle The new idleTime value
155     */
156    @Override
157    public void setIdleTime( long idle )
158    {
159        this.maxIdleTime = idle;
160    }
161
162    /**
163     * Size in bytes. This is not used except in the admin pages. It will be -1 by default.
164     * <p>
165     * @param size The new size value
166     */
167    @Override
168    public void setSize( int size )
169    {
170        this.size = size;
171    }
172
173    /**
174     * Gets the size attribute of the IAttributes object
175     * <p>
176     * @return The size value
177     */
178    @Override
179    public int getSize()
180    {
181        return size;
182    }
183
184    /**
185     * Gets the createTime attribute of the IAttributes object.
186     * <p>
187     * This should be the current time in milliseconds returned by the sysutem call when the element
188     * is put in the cache.
189     * <p>
190     * Putting an item in the cache overrides any existing items.
191     * @return The createTime value
192     */
193    @Override
194    public long getCreateTime()
195    {
196        return createTime;
197    }
198
199    /**
200     * Sets the createTime attribute of the IElementAttributes object
201     */
202    public void setCreateTime()
203    {
204        createTime = System.currentTimeMillis();
205    }
206
207    /**
208     * Gets the idleTime attribute of the IAttributes object.
209     * <p>
210     * @return The idleTime value
211     */
212    @Override
213    public long getIdleTime()
214    {
215        return this.maxIdleTime;
216    }
217
218    /**
219     * Gets the time left to live of the IAttributes object.
220     * <p>
221     * This is the (max life + create time) - current time.
222     * @return The TimeToLiveSeconds value
223     */
224    @Override
225    public long getTimeToLiveSeconds()
226    {
227        final long now = System.currentTimeMillis();
228        final long timeFactorForMilliseconds = getTimeFactorForMilliseconds();
229        return ( this.getCreateTime() + this.getMaxLife() * timeFactorForMilliseconds - now ) / 1000;
230    }
231
232    /**
233     * Gets the LastAccess attribute of the IAttributes object.
234     * <p>
235     * @return The LastAccess value.
236     */
237    @Override
238    public long getLastAccessTime()
239    {
240        return this.lastAccessTime;
241    }
242
243    /**
244     * Sets the LastAccessTime as now of the IElementAttributes object
245     */
246    @Override
247    public void setLastAccessTimeNow()
248    {
249        this.lastAccessTime = System.currentTimeMillis();
250    }
251
252    /**
253     * only for use from test code
254     */
255    public void setLastAccessTime(long time)
256    {
257        this.lastAccessTime = time;
258    }
259
260    /**
261     * Can this item be spooled to disk
262     * <p>
263     * By default this is true.
264     * @return The spoolable value
265     */
266    @Override
267    public boolean getIsSpool()
268    {
269        return this.IS_SPOOL;
270    }
271
272    /**
273     * Sets the isSpool attribute of the IElementAttributes object
274     * <p>
275     * By default this is true.
276     * @param val The new isSpool value
277     */
278    @Override
279    public void setIsSpool( boolean val )
280    {
281        this.IS_SPOOL = val;
282    }
283
284    /**
285     * Is this item laterally distributable. Can it be sent to auxiliaries of type lateral.
286     * <p>
287     * By default this is true.
288     * @return The isLateral value
289     */
290    @Override
291    public boolean getIsLateral()
292    {
293        return this.IS_LATERAL;
294    }
295
296    /**
297     * Sets the isLateral attribute of the IElementAttributes object
298     * <p>
299     * By default this is true.
300     * @param val The new isLateral value
301     */
302    @Override
303    public void setIsLateral( boolean val )
304    {
305        this.IS_LATERAL = val;
306    }
307
308    /**
309     * Can this item be sent to the remote cache
310     * @return true if the item can be sent to a remote auxiliary
311     */
312    @Override
313    public boolean getIsRemote()
314    {
315        return this.IS_REMOTE;
316    }
317
318    /**
319     * Sets the isRemote attribute of the ElementAttributes object
320     * @param val The new isRemote value
321     */
322    @Override
323    public void setIsRemote( boolean val )
324    {
325        this.IS_REMOTE = val;
326    }
327
328    /**
329     * You can turn off expiration by setting this to true. The max life value will be ignored.
330     * <p>
331     * @return true if the item cannot expire.
332     */
333    @Override
334    public boolean getIsEternal()
335    {
336        return this.IS_ETERNAL;
337    }
338
339    /**
340     * Sets the isEternal attribute of the ElementAttributes object. True means that the item should
341     * never expire. If can still be removed if it is the least recently used, and you are using the
342     * LRUMemory cache. it just will not be filtered for expiration by the cache hub.
343     * <p>
344     * @param val The new isEternal value
345     */
346    @Override
347    public void setIsEternal( boolean val )
348    {
349        this.IS_ETERNAL = val;
350    }
351
352    /**
353     * Adds a ElementEventHandler. Handler's can be registered for multiple events. A registered
354     * handler will be called at every recognized event.
355     * <p>
356     * The alternative would be to register handlers for each event. Or maybe The handler interface
357     * should have a method to return whether it cares about certain events.
358     * <p>
359     * @param eventHandler The ElementEventHandler to be added to the list.
360     */
361    @Override
362    public void addElementEventHandler( IElementEventHandler eventHandler )
363    {
364        // lazy here, no concurrency problems expected
365        if ( this.eventHandlers == null )
366        {
367            this.eventHandlers = new ArrayList<IElementEventHandler>();
368        }
369        this.eventHandlers.add( eventHandler );
370    }
371
372    /**
373     * Sets the eventHandlers of the IElementAttributes object.
374     * <p>
375     * This add the references to the local list. Subsequent changes in the caller's list will not
376     * be reflected.
377     * <p>
378     * @param eventHandlers List of IElementEventHandler objects
379     */
380    @Override
381    public void addElementEventHandlers( List<IElementEventHandler> eventHandlers )
382    {
383        if ( eventHandlers == null )
384        {
385            return;
386        }
387
388        for (IElementEventHandler handler : eventHandlers)
389        {
390            addElementEventHandler(handler);
391        }
392    }
393
394    @Override
395    public long getTimeFactorForMilliseconds()
396    {
397        return timeFactor;
398    }
399
400    @Override
401    public void setTimeFactorForMilliseconds(long factor)
402    {
403        this.timeFactor = factor;
404    }
405
406    /**
407     * Gets the elementEventHandlers. Returns null if none exist. Makes checking easy.
408     * <p>
409     * @return The elementEventHandlers List of IElementEventHandler objects
410     */
411    @Override
412    public ArrayList<IElementEventHandler> getElementEventHandlers()
413    {
414        return this.eventHandlers;
415    }
416
417    /**
418     * For logging and debugging the element IElementAttributes.
419     * <p>
420     * @return String info about the values.
421     */
422    @Override
423    public String toString()
424    {
425        StringBuilder dump = new StringBuilder();
426
427        dump.append( "[ IS_LATERAL = " ).append( IS_LATERAL );
428        dump.append( ", IS_SPOOL = " ).append( IS_SPOOL );
429        dump.append( ", IS_REMOTE = " ).append( IS_REMOTE );
430        dump.append( ", IS_ETERNAL = " ).append( IS_ETERNAL );
431        dump.append( ", MaxLifeSeconds = " ).append( this.getMaxLife() );
432        dump.append( ", IdleTime = " ).append( this.getIdleTime() );
433        dump.append( ", CreateTime = " ).append( this.getCreateTime() );
434        dump.append( ", LastAccessTime = " ).append( this.getLastAccessTime() );
435        dump.append( ", getTimeToLiveSeconds() = " ).append( String.valueOf( getTimeToLiveSeconds() ) );
436        dump.append( ", createTime = " ).append( String.valueOf( createTime ) ).append( " ]" );
437
438        return dump.toString();
439    }
440
441    /**
442     * @see java.lang.Object#clone()
443     */
444    @Override
445    public IElementAttributes clone()
446    {
447        try
448        {
449                ElementAttributes c = (ElementAttributes) super.clone();
450                c.setCreateTime();
451            return c;
452        }
453        catch (CloneNotSupportedException e)
454        {
455            throw new RuntimeException("Clone not supported. This should never happen.", e);
456        }
457    }
458}