001package org.apache.commons.jcs3.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.jcs3.engine.behavior.IElementAttributes;
026import org.apache.commons.jcs3.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;
072
073    /** The creation time. This is used to enforce the max life. */
074    private long createTime;
075
076    /** The last access time. This is used to enforce the max idel time. */
077    private long lastAccessTime;
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( final 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(final 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( final 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 0 by default
164     * and is only updated when the element is serialized.
165     * <p>
166     * @param size The new size value
167     */
168    @Override
169    public void setSize( final int size )
170    {
171        this.size = size;
172    }
173
174    /**
175     * Gets the size attribute of the IAttributes object
176     * <p>
177     * @return The size value
178     */
179    @Override
180    public int getSize()
181    {
182        return size;
183    }
184
185    /**
186     * Gets the createTime attribute of the IAttributes object.
187     * <p>
188     * This should be the current time in milliseconds returned by the sysutem call when the element
189     * is put in the cache.
190     * <p>
191     * Putting an item in the cache overrides any existing items.
192     * @return The createTime value
193     */
194    @Override
195    public long getCreateTime()
196    {
197        return createTime;
198    }
199
200    /**
201     * Sets the createTime attribute of the IElementAttributes object
202     */
203    public void setCreateTime()
204    {
205        createTime = System.currentTimeMillis();
206    }
207
208    /**
209     * Gets the idleTime attribute of the IAttributes object.
210     * <p>
211     * @return The idleTime value
212     */
213    @Override
214    public long getIdleTime()
215    {
216        return this.maxIdleTime;
217    }
218
219    /**
220     * Gets the time left to live of the IAttributes object.
221     * <p>
222     * This is the (max life + create time) - current time.
223     * @return The TimeToLiveSeconds value
224     */
225    @Override
226    public long getTimeToLiveSeconds()
227    {
228        final long now = System.currentTimeMillis();
229        final long timeFactorForMilliseconds = getTimeFactorForMilliseconds();
230        return ( this.getCreateTime() + this.getMaxLife() * timeFactorForMilliseconds - now ) / 1000;
231    }
232
233    /**
234     * Gets the LastAccess attribute of the IAttributes object.
235     * <p>
236     * @return The LastAccess value.
237     */
238    @Override
239    public long getLastAccessTime()
240    {
241        return this.lastAccessTime;
242    }
243
244    /**
245     * Sets the LastAccessTime as now of the IElementAttributes object
246     */
247    @Override
248    public void setLastAccessTimeNow()
249    {
250        this.lastAccessTime = System.currentTimeMillis();
251    }
252
253    /**
254     * only for use from test code
255     */
256    public void setLastAccessTime(final long time)
257    {
258        this.lastAccessTime = time;
259    }
260
261    /**
262     * Can this item be spooled to disk
263     * <p>
264     * By default this is true.
265     * @return The spoolable value
266     */
267    @Override
268    public boolean getIsSpool()
269    {
270        return this.IS_SPOOL;
271    }
272
273    /**
274     * Sets the isSpool attribute of the IElementAttributes object
275     * <p>
276     * By default this is true.
277     * @param val The new isSpool value
278     */
279    @Override
280    public void setIsSpool( final boolean val )
281    {
282        this.IS_SPOOL = val;
283    }
284
285    /**
286     * Is this item laterally distributable. Can it be sent to auxiliaries of type lateral.
287     * <p>
288     * By default this is true.
289     * @return The isLateral value
290     */
291    @Override
292    public boolean getIsLateral()
293    {
294        return this.IS_LATERAL;
295    }
296
297    /**
298     * Sets the isLateral attribute of the IElementAttributes object
299     * <p>
300     * By default this is true.
301     * @param val The new isLateral value
302     */
303    @Override
304    public void setIsLateral( final boolean val )
305    {
306        this.IS_LATERAL = val;
307    }
308
309    /**
310     * Can this item be sent to the remote cache
311     * @return true if the item can be sent to a remote auxiliary
312     */
313    @Override
314    public boolean getIsRemote()
315    {
316        return this.IS_REMOTE;
317    }
318
319    /**
320     * Sets the isRemote attribute of the ElementAttributes object
321     * @param val The new isRemote value
322     */
323    @Override
324    public void setIsRemote( final boolean val )
325    {
326        this.IS_REMOTE = val;
327    }
328
329    /**
330     * You can turn off expiration by setting this to true. The max life value will be ignored.
331     * <p>
332     * @return true if the item cannot expire.
333     */
334    @Override
335    public boolean getIsEternal()
336    {
337        return this.IS_ETERNAL;
338    }
339
340    /**
341     * Sets the isEternal attribute of the ElementAttributes object. True means that the item should
342     * never expire. If can still be removed if it is the least recently used, and you are using the
343     * LRUMemory cache. it just will not be filtered for expiration by the cache hub.
344     * <p>
345     * @param val The new isEternal value
346     */
347    @Override
348    public void setIsEternal( final boolean val )
349    {
350        this.IS_ETERNAL = val;
351    }
352
353    /**
354     * Adds a ElementEventHandler. Handler's can be registered for multiple events. A registered
355     * handler will be called at every recognized event.
356     * <p>
357     * The alternative would be to register handlers for each event. Or maybe The handler interface
358     * should have a method to return whether it cares about certain events.
359     * <p>
360     * @param eventHandler The ElementEventHandler to be added to the list.
361     */
362    @Override
363    public void addElementEventHandler( final IElementEventHandler eventHandler )
364    {
365        // lazy here, no concurrency problems expected
366        if ( this.eventHandlers == null )
367        {
368            this.eventHandlers = new ArrayList<>();
369        }
370        this.eventHandlers.add( eventHandler );
371    }
372
373    /**
374     * Sets the eventHandlers of the IElementAttributes object.
375     * <p>
376     * This add the references to the local list. Subsequent changes in the caller's list will not
377     * be reflected.
378     * <p>
379     * @param eventHandlers List of IElementEventHandler objects
380     */
381    @Override
382    public void addElementEventHandlers( final List<IElementEventHandler> eventHandlers )
383    {
384        if ( eventHandlers == null )
385        {
386            return;
387        }
388
389        for (final IElementEventHandler handler : eventHandlers)
390        {
391            addElementEventHandler(handler);
392        }
393    }
394
395    @Override
396    public long getTimeFactorForMilliseconds()
397    {
398        return timeFactor;
399    }
400
401    @Override
402    public void setTimeFactorForMilliseconds(final long factor)
403    {
404        this.timeFactor = factor;
405    }
406
407    /**
408     * Gets the elementEventHandlers. Returns null if none exist. Makes checking easy.
409     * <p>
410     * @return The elementEventHandlers List of IElementEventHandler objects
411     */
412    @Override
413    public ArrayList<IElementEventHandler> getElementEventHandlers()
414    {
415        return this.eventHandlers;
416    }
417
418    /**
419     * For logging and debugging the element IElementAttributes.
420     * <p>
421     * @return String info about the values.
422     */
423    @Override
424    public String toString()
425    {
426        final StringBuilder dump = new StringBuilder();
427
428        dump.append( "[ IS_LATERAL = " ).append( IS_LATERAL );
429        dump.append( ", IS_SPOOL = " ).append( IS_SPOOL );
430        dump.append( ", IS_REMOTE = " ).append( IS_REMOTE );
431        dump.append( ", IS_ETERNAL = " ).append( IS_ETERNAL );
432        dump.append( ", MaxLifeSeconds = " ).append( this.getMaxLife() );
433        dump.append( ", IdleTime = " ).append( this.getIdleTime() );
434        dump.append( ", CreateTime = " ).append( this.getCreateTime() );
435        dump.append( ", LastAccessTime = " ).append( this.getLastAccessTime() );
436        dump.append( ", getTimeToLiveSeconds() = " ).append( String.valueOf( getTimeToLiveSeconds() ) );
437        dump.append( ", createTime = " ).append( String.valueOf( createTime ) ).append( " ]" );
438
439        return dump.toString();
440    }
441
442    /**
443     * @see Object#clone()
444     */
445    @Override
446    public IElementAttributes clone()
447    {
448        try
449        {
450                final ElementAttributes c = (ElementAttributes) super.clone();
451                c.setCreateTime();
452            return c;
453        }
454        catch (final CloneNotSupportedException e)
455        {
456            throw new RuntimeException("Clone not supported. This should never happen.", e);
457        }
458    }
459}