1 /***
2 * Copyright 2003-2010 Terracotta, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17
18 package net.sf.ehcache;
19
20
21 import net.sf.ehcache.config.CacheConfiguration;
22 import net.sf.ehcache.pool.sizeof.annotations.IgnoreSizeOf;
23 import net.sf.ehcache.util.TimeUtil;
24
25 import java.io.ByteArrayInputStream;
26 import java.io.ByteArrayOutputStream;
27 import java.io.IOException;
28 import java.io.NotSerializableException;
29 import java.io.ObjectInputStream;
30 import java.io.ObjectOutputStream;
31 import java.io.Serializable;
32 import java.util.concurrent.atomic.AtomicLongFieldUpdater;
33
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 /***
38 * A Cache Element, consisting of a key, value and attributes.
39 * <p/>
40 * From ehcache-1.2, Elements can have keys and values that are Serializable or Objects. To preserve backward
41 * compatibility, special accessor methods for Object keys and values are provided: {@link #getObjectKey()} and
42 * {@link #getObjectValue()}. If placing Objects in ehcache, developers must use the new getObject... methods to
43 * avoid CacheExceptions. The get... methods are reserved for Serializable keys and values.
44 *
45 * @author Greg Luck
46 * @version $Id: Element.html 13146 2011-08-01 17:12:39Z oletizi $
47 */
48 public class Element implements Serializable, Cloneable {
49
50 /***
51 * serial version
52 * Updated for version 1.2, 1.2.1 and 1.7
53 */
54 private static final long serialVersionUID = 1098572221246444544L;
55
56 private static final Logger LOG = LoggerFactory.getLogger(Element.class.getName());
57
58 private static final AtomicLongFieldUpdater<Element> HIT_COUNT_UPDATER = AtomicLongFieldUpdater.newUpdater(Element.class, "hitCount");
59
60 private static final boolean ELEMENT_VERSION_AUTO = Boolean.getBoolean("net.sf.ehcache.element.version.auto");
61
62 /***
63 * the cache key.
64 */
65 @IgnoreSizeOf
66 private final Object key;
67
68 /***
69 * the value.
70 */
71 private final Object value;
72
73 /***
74 * version of the element. System.currentTimeMillis() is used to compute version for updated elements. That
75 * way, the actual version of the updated element does not need to be checked.
76 */
77 private volatile long version;
78
79 /***
80 * The number of times the element was hit.
81 */
82 private volatile long hitCount;
83
84 /***
85 * The amount of time for the element to live, in seconds. 0 indicates unlimited.
86 */
87 private volatile int timeToLive = Integer.MIN_VALUE;
88
89 /***
90 * The amount of time for the element to idle, in seconds. 0 indicates unlimited.
91 */
92 private volatile int timeToIdle = Integer.MIN_VALUE;
93
94 /***
95 * Pluggable element eviction data instance
96 */
97 private transient volatile ElementEvictionData elementEvictionData;
98
99 /***
100 * If there is an Element in the Cache and it is replaced with a new Element for the same key,
101 * then both the version number and lastUpdateTime should be updated to reflect that. The creation time
102 * will be the creation time of the new Element, not the original one, so that TTL concepts still work.
103 */
104 private volatile long lastUpdateTime;
105
106 private volatile boolean cacheDefaultLifespan = true;
107
108 private volatile boolean pinned;
109
110 /***
111 * A full constructor.
112 * <p/>
113 * Creation time is set to the current time. Last Access Time is not set.
114 *
115 * @since .4
116 */
117 public Element(final Serializable key, final Serializable value, final long version) {
118 this((Object) key, (Object) value, version);
119
120 }
121
122 /***
123 * A full constructor.
124 * <p/>
125 * Creation time is set to the current time. Last Access Time and Previous To Last Access Time
126 * are not set.
127 *
128 * @since 1.2
129 */
130 public Element(final Object key, final Object value, final long version) {
131 this.key = key;
132 this.value = value;
133 this.version = version;
134 HIT_COUNT_UPDATER.set(this, 0);
135 this.elementEvictionData = new DefaultElementEvictionData(System.currentTimeMillis());
136 }
137
138 /***
139 * Constructor.
140 *
141 * @deprecated The {@code nextToLastAccessTime} field is unused since
142 * version 1.7, setting it will have no effect. Use
143 * #Element(Object, Object, long, long, long, long, long)
144 * instead
145 * @since 1.3
146 * @see #Element(Object, Object, long, long, long, long, long)
147 */
148 @Deprecated
149 public Element(final Object key, final Object value, final long version,
150 final long creationTime, final long lastAccessTime, final long nextToLastAccessTime,
151 final long lastUpdateTime, final long hitCount) {
152 this(key, value, version, creationTime, lastAccessTime, lastUpdateTime, hitCount);
153 }
154
155 /***
156 * Constructor.
157 *
158 * @since 1.7
159 */
160 public Element(final Object key, final Object value, final long version,
161 final long creationTime, final long lastAccessTime,
162 final long lastUpdateTime, final long hitCount) {
163 this.key = key;
164 this.value = value;
165 this.version = version;
166 this.lastUpdateTime = lastUpdateTime;
167 HIT_COUNT_UPDATER.set(this, hitCount);
168 this.elementEvictionData = new DefaultElementEvictionData(creationTime, lastAccessTime);
169 }
170
171 /***
172 * Constructor used by ElementData. Needs to be public since ElementData might be in another classloader
173 *
174 * @since 1.7
175 */
176 public Element(final Object key, final Object value, final long version, final long creationTime,
177 final long lastAccessTime, final long hitCount, final boolean cacheDefaultLifespan,
178 final int timeToLive, final int timeToIdle, final long lastUpdateTime) {
179 this.key = key;
180 this.value = value;
181 this.version = version;
182 HIT_COUNT_UPDATER.set(this, hitCount);
183 this.cacheDefaultLifespan = cacheDefaultLifespan;
184 this.timeToLive = timeToLive;
185 this.timeToIdle = timeToIdle;
186 this.lastUpdateTime = lastUpdateTime;
187 this.elementEvictionData = new DefaultElementEvictionData(creationTime, lastAccessTime);
188 }
189
190 /***
191 * @since 2.5
192 */
193 public Element(final Object key, final Object value, final long version, final long creationTime,
194 final long lastAccessTime, final long hitCount, final boolean cacheDefaultLifespan,
195 final int timeToLive, final int timeToIdle, final long lastUpdateTime, final boolean pinned) {
196 this.key = key;
197 this.value = value;
198 this.version = version;
199 HIT_COUNT_UPDATER.set(this, hitCount);
200 this.cacheDefaultLifespan = cacheDefaultLifespan;
201 this.timeToLive = timeToLive;
202 this.timeToIdle = timeToIdle;
203 this.lastUpdateTime = lastUpdateTime;
204 this.elementEvictionData = new DefaultElementEvictionData(creationTime, lastAccessTime);
205 this.pinned = pinned;
206 }
207
208
209 /***
210 * Constructor used by ehcache-server
211 *
212 * @param key any non null value
213 * @param value any value, including nulls
214 * @param eternal specify as non-null to override cache configuration
215 * @param timeToIdleSeconds specify as non-null to override cache configuration
216 * @param timeToLiveSeconds specify as non-null to override cache configuration
217 */
218 public Element(final Object key, final Object value,
219 final Boolean eternal, final Integer timeToIdleSeconds, final Integer timeToLiveSeconds) {
220 this.key = key;
221 this.value = value;
222 if (eternal != null) {
223 setEternal(eternal.booleanValue());
224 }
225 if (timeToIdleSeconds != null) {
226 setTimeToIdle(timeToIdleSeconds.intValue());
227 }
228 if (timeToLiveSeconds != null) {
229 setTimeToLive(timeToLiveSeconds.intValue());
230 }
231 this.elementEvictionData = new DefaultElementEvictionData(System.currentTimeMillis());
232 }
233
234 /***
235 * Constructor.
236 *
237 * @param key
238 * @param value
239 */
240 public Element(final Serializable key, final Serializable value) {
241 this((Object) key, (Object) value, 1L);
242 }
243
244 /***
245 * Constructor.
246 *
247 * @param key
248 * @param value
249 * @since 1.2
250 */
251 public Element(final Object key, final Object value) {
252 this(key, value, 1L);
253 }
254
255 /***
256 * Gets the key attribute of the Element object.
257 *
258 * @return The key value. If the key is not Serializable, null is returned and an info log message emitted
259 * @see #getObjectKey()
260 */
261 public final Serializable getKey() {
262 Serializable keyAsSerializable;
263 try {
264 keyAsSerializable = (Serializable) key;
265 } catch (Exception e) {
266 throw new CacheException("The key " + key + " is not Serializable. Consider using Element#getObjectKey()");
267 }
268 return keyAsSerializable;
269 }
270
271 /***
272 * Gets the key attribute of the Element object.
273 * <p/>
274 * This method is provided for those wishing to use ehcache as a memory only cache
275 * and enables retrieval of non-Serializable values from elements.
276 *
277 * @return The key as an Object. i.e no restriction is placed on it
278 * @see #getKey()
279 */
280 public final Object getObjectKey() {
281 return key;
282 }
283
284 /***
285 * Gets the value attribute of the Element object.
286 *
287 * @return The value which must be Serializable. If not use {@link #getObjectValue}. If the value is not Serializable, null is returned and an info log message emitted
288 * @see #getObjectValue()
289 */
290 public final Serializable getValue() {
291 Serializable valueAsSerializable;
292 try {
293 valueAsSerializable = (Serializable) value;
294 } catch (Exception e) {
295 throw new CacheException("The value " + value + " for key " + key +
296 " is not Serializable. Consider using Element#getObjectValue()");
297 }
298 return valueAsSerializable;
299 }
300
301 /***
302 * Gets the value attribute of the Element object as an Object.
303 * <p/>
304 * This method is provided for those wishing to use ehcache as a memory only cache
305 * and enables retrieval of non-Serializable values from elements.
306 *
307 * @return The value as an Object. i.e no restriction is placed on it
308 * @see #getValue()
309 * @since 1.2
310 */
311 public final Object getObjectValue() {
312 return value;
313 }
314
315 /***
316 * Equals comparison with another element, based on the key.
317 */
318 @Override
319 public final boolean equals(final Object object) {
320 if (object == null || !(object instanceof Element)) {
321 return false;
322 }
323
324 Element element = (Element) object;
325 if (key == null || element.getObjectKey() == null) {
326 return false;
327 }
328
329 return key.equals(element.getObjectKey());
330 }
331
332 /***
333 * Sets time to Live
334 *
335 * @param timeToLiveSeconds the number of seconds to live
336 */
337 public void setTimeToLive(final int timeToLiveSeconds) {
338 if (timeToLiveSeconds < 0) {
339 throw new IllegalArgumentException("timeToLive can't be negative");
340 }
341 this.cacheDefaultLifespan = false;
342 this.timeToLive = timeToLiveSeconds;
343 }
344
345 /***
346 * Sets time to idle
347 *
348 * @param timeToIdleSeconds the number of seconds to idle
349 */
350 public void setTimeToIdle(final int timeToIdleSeconds) {
351 if (timeToIdleSeconds < 0) {
352 throw new IllegalArgumentException("timeToIdle can't be negative");
353 }
354 this.cacheDefaultLifespan = false;
355 this.timeToIdle = timeToIdleSeconds;
356 }
357
358 /***
359 * Gets the hashcode, based on the key.
360 */
361 @Override
362 public final int hashCode() {
363 return key.hashCode();
364 }
365
366 /***
367 * Sets the version attribute of the ElementAttributes object.
368 *
369 * @param version The new version value
370 */
371 public final void setVersion(final long version) {
372 this.version = version;
373 }
374
375 /***
376 * Sets the creationTime attribute of the ElementAttributes object.
377 * <p>
378 * Note that in a Terracotta clustered environment, resetting the creation
379 * time will not have any effect.
380 *
381 * @deprecated Resetting the creation time is not recommended as of version
382 * 1.7
383 */
384 @Deprecated
385 public final void setCreateTime() {
386 this.elementEvictionData.setCreationTime(System.currentTimeMillis());
387 }
388
389 /***
390 * Gets the creationTime of the Element
391 *
392 * @return The creationTime value
393 */
394 public final long getCreationTime() {
395 return elementEvictionData.getCreationTime();
396 }
397
398 /***
399 * Calculates the latest of creation and update time
400 * @return if never updated, creation time is returned, otherwise updated time
401 */
402 public final long getLatestOfCreationAndUpdateTime() {
403 if (0 == lastUpdateTime) {
404 return elementEvictionData.getCreationTime();
405 } else {
406 return lastUpdateTime;
407 }
408 }
409
410 /***
411 * Gets the version attribute of the ElementAttributes object.
412 *
413 * @return The version value
414 */
415 public final long getVersion() {
416 return version;
417 }
418
419 /***
420 * Gets the last access time.
421 * Access means a get. So a newly created {@link Element}
422 * will have a last access time equal to its create time.
423 */
424 public final long getLastAccessTime() {
425 return elementEvictionData.getLastAccessTime();
426 }
427
428 /***
429 * Gets the next to last access time.
430 *
431 * @deprecated The {@code nextToLastAccessTime} field is unused since
432 * version 1.7, retrieving it will return the {@code
433 * lastAccessTime}. Use #getLastAccessTime() instead.
434 * @see #getLastAccessTime()
435 */
436 @Deprecated
437 public final long getNextToLastAccessTime() {
438 return getLastAccessTime();
439 }
440
441 /***
442 * Gets the hit count on this element.
443 */
444 public final long getHitCount() {
445 return hitCount;
446 }
447
448 /***
449 * Retrieves this element's eviction data instance.
450 *
451 * @return this element's eviction data instance
452 */
453 public ElementEvictionData getElementEvictionData() {
454 return elementEvictionData;
455 }
456
457 /***
458 * Sets this element's eviction data instance.
459 *
460 * @param elementEvictionData this element's eviction data
461 */
462 public void setElementEvictionData(ElementEvictionData elementEvictionData) {
463 this.elementEvictionData = elementEvictionData;
464 }
465
466 /***
467 * Resets the hit count to 0 and the last access time to now. Used when an Element is put into a cache.
468 */
469 public final void resetAccessStatistics() {
470 elementEvictionData.resetLastAccessTime(this);
471 HIT_COUNT_UPDATER.set(this, 0);
472 }
473
474 /***
475 * Sets the last access time to now and increase the hit count.
476 */
477 public final void updateAccessStatistics() {
478 elementEvictionData.updateLastAccessTime(System.currentTimeMillis(), this);
479 HIT_COUNT_UPDATER.incrementAndGet(this);
480 }
481
482 /***
483 * Sets the last access time to now without updating the hit count.
484 */
485 public final void updateUpdateStatistics() {
486 lastUpdateTime = System.currentTimeMillis();
487 if (ELEMENT_VERSION_AUTO) {
488 version = lastUpdateTime;
489 }
490 }
491
492
493 /***
494 * Returns a {@link String} representation of the {@link Element}.
495 */
496 @Override
497 public final String toString() {
498 StringBuilder sb = new StringBuilder();
499
500 sb.append("[ key = ").append(key)
501 .append(", value=").append(value)
502 .append(", version=").append(version)
503 .append(", hitCount=").append(hitCount)
504 .append(", CreationTime = ").append(this.getCreationTime())
505 .append(", LastAccessTime = ").append(this.getLastAccessTime())
506 .append(" ]");
507
508 return sb.toString();
509 }
510
511 /***
512 * Clones an Element. A completely new object is created, with no common references with the
513 * existing one.
514 * <p/>
515 * This method will not work unless the Object is Serializable
516 * <p/>
517 * Warning: This can be very slow on large object graphs. If you use this method
518 * you should write a performance test to verify suitability.
519 *
520 * @return a new {@link Element}, with exactly the same field values as the one it was cloned from.
521 * @throws CloneNotSupportedException
522 */
523 @Override
524 public final Object clone() throws CloneNotSupportedException {
525
526 super.clone();
527
528 try {
529 Element element = new Element(deepCopy(key), deepCopy(value), version);
530 element.elementEvictionData = elementEvictionData.clone();
531 HIT_COUNT_UPDATER.set(element, hitCount);
532 return element;
533 } catch (IOException e) {
534 LOG.error("Error cloning Element with key " + key
535 + " during serialization and deserialization of value");
536 throw new CloneNotSupportedException();
537 } catch (ClassNotFoundException e) {
538 LOG.error("Error cloning Element with key " + key
539 + " during serialization and deserialization of value");
540 throw new CloneNotSupportedException();
541 }
542 }
543
544 private static Object deepCopy(final Object oldValue) throws IOException, ClassNotFoundException {
545 Serializable newValue = null;
546 ByteArrayOutputStream bout = new ByteArrayOutputStream();
547 ObjectOutputStream oos = null;
548 ObjectInputStream ois = null;
549 try {
550 oos = new ObjectOutputStream(bout);
551 oos.writeObject(oldValue);
552 ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
553 ois = new ObjectInputStream(bin);
554 newValue = (Serializable) ois.readObject();
555 } finally {
556 try {
557 if (oos != null) {
558 oos.close();
559 }
560 if (ois != null) {
561 ois.close();
562 }
563 } catch (Exception e) {
564 LOG.error("Error closing Stream");
565 }
566 }
567 return newValue;
568 }
569
570 /***
571 * The size of this object in serialized form. This is not the same
572 * thing as the memory size, which is JVM dependent. Relative values should be meaningful,
573 * however.
574 * <p/>
575 * Warning: This method can be <b>very slow</b> for values which contain large object graphs.
576 * <p/>
577 * If the key or value of the Element is not Serializable, an error will be logged and 0 will be returned.
578 *
579 * @return The serialized size in bytes
580 */
581 public final long getSerializedSize() {
582
583 if (!isSerializable()) {
584 return 0;
585 }
586 long size = 0;
587 ByteArrayOutputStream bout = new ByteArrayOutputStream();
588 ObjectOutputStream oos = null;
589 try {
590 oos = new ObjectOutputStream(bout);
591 oos.writeObject(this);
592 size = bout.size();
593 return size;
594 } catch (IOException e) {
595 LOG.debug("Error measuring element size for element with key " + key + ". Cause was: " + e.getMessage());
596 } finally {
597 try {
598 if (oos != null) {
599 oos.close();
600 }
601 } catch (Exception e) {
602 LOG.error("Error closing ObjectOutputStream");
603 }
604 }
605
606 return size;
607 }
608
609 /***
610 * Whether the element may be Serialized.
611 * <p/>
612 * While Element implements Serializable, it is possible to create non Serializable elements
613 * for use in MemoryStores. This method checks that an instance of Element really is Serializable
614 * and will not throw a NonSerializableException if Serialized.
615 * <p/>
616 * This method was tweaked in 1.6 as it has been shown that Serializable classes can be serializaed as can
617 * null, regardless of what class it is a null of. ObjectOutputStream.write(null) works and ObjectInputStream.read()
618 * will read null back.
619 *
620 * @return true if the element is Serializable
621 * @since 1.2
622 */
623 public final boolean isSerializable() {
624 return isKeySerializable()
625 && (value instanceof Serializable || value == null)
626 && elementEvictionData.canParticipateInSerialization();
627 }
628
629 /***
630 * Whether the element's key may be Serialized.
631 * <p/>
632 * While Element implements Serializable, it is possible to create non Serializable elements and/or
633 * non Serializable keys for use in MemoryStores.
634 * <p/>
635 * This method checks that an instance of an Element's key really is Serializable
636 * and will not throw a NonSerializableException if Serialized.
637 *
638 * @return true if the element's key is Serializable
639 * @since 1.2
640 */
641 public final boolean isKeySerializable() {
642 return key instanceof Serializable || key == null;
643 }
644
645 /***
646 * If there is an Element in the Cache and it is replaced with a new Element for the same key,
647 * then both the version number and lastUpdateTime should be updated to reflect that. The creation time
648 * will be the creation time of the new Element, not the original one, so that TTL concepts still work.
649 *
650 * @return the time when the last update occured. If this is the original Element, the time will be null
651 */
652 public long getLastUpdateTime() {
653 return lastUpdateTime;
654 }
655
656 /***
657 * An element is expired if the expiration time as given by {@link #getExpirationTime()} is in the past.
658 *
659 * @return true if the Element is expired, otherwise false. If no lifespan has been set for the Element it is
660 * considered not able to expire.
661 * @see #getExpirationTime()
662 */
663 public boolean isExpired() {
664 if (!isLifespanSet() || isEternal()) {
665 return false;
666 }
667
668 long now = System.currentTimeMillis();
669 long expirationTime = getExpirationTime();
670
671 return now > expirationTime;
672 }
673
674 /***
675 * An element is expired if the expiration time as given by {@link #getExpirationTime()} is in the past.
676 * <p>
677 * This method in addition propogates the default TTI/TTL values of the supplied cache into this element.
678 *
679 * @param config config to take default parameters from
680 * @return true if the Element is expired, otherwise false. If no lifespan has been set for the Element it is
681 * considered not able to expire.
682 * @see #getExpirationTime()
683 */
684 public boolean isExpired(CacheConfiguration config) {
685 if (cacheDefaultLifespan) {
686 if (config.isEternal()) {
687 timeToIdle = 0;
688 timeToLive = 0;
689 } else {
690 timeToIdle = TimeUtil.convertTimeToInt(config.getTimeToIdleSeconds());
691 timeToLive = TimeUtil.convertTimeToInt(config.getTimeToLiveSeconds());
692 }
693 }
694 return isExpired();
695 }
696
697 /***
698 * Returns the expiration time based on time to live. If this element also has a time to idle setting, the expiry
699 * time will vary depending on whether the element is accessed.
700 *
701 * @return the time to expiration
702 */
703 public long getExpirationTime() {
704 if (!isLifespanSet() || isEternal()) {
705 return Long.MAX_VALUE;
706 }
707
708 long expirationTime = 0;
709 long ttlExpiry = elementEvictionData.getCreationTime() + TimeUtil.toMillis(getTimeToLive());
710
711 long mostRecentTime = Math.max(elementEvictionData.getCreationTime(), elementEvictionData.getLastAccessTime());
712 long ttiExpiry = mostRecentTime + TimeUtil.toMillis(getTimeToIdle());
713
714 if (getTimeToLive() != 0 && (getTimeToIdle() == 0 || elementEvictionData.getLastAccessTime() == 0)) {
715 expirationTime = ttlExpiry;
716 } else if (getTimeToLive() == 0) {
717 expirationTime = ttiExpiry;
718 } else {
719 expirationTime = Math.min(ttlExpiry, ttiExpiry);
720 }
721 return expirationTime;
722 }
723
724 /***
725 * @return true if the element is eternal
726 */
727 public boolean isEternal() {
728 return (0 == timeToIdle) && (0 == timeToLive);
729 }
730
731 /***
732 * Sets whether the element is eternal.
733 *
734 * @param eternal
735 */
736 public void setEternal(final boolean eternal) {
737 if (eternal) {
738 this.cacheDefaultLifespan = false;
739 this.timeToIdle = 0;
740 this.timeToLive = 0;
741 } else if (isEternal()) {
742 this.cacheDefaultLifespan = false;
743 this.timeToIdle = Integer.MIN_VALUE;
744 this.timeToLive = Integer.MIN_VALUE;
745 }
746 }
747
748 /***
749 * Whether any combination of eternal, TTL or TTI has been set.
750 *
751 * @return true if set.
752 */
753 public boolean isLifespanSet() {
754 return this.timeToIdle != Integer.MIN_VALUE || this.timeToLive != Integer.MIN_VALUE;
755 }
756
757 /***
758 * @return the time to live, in seconds
759 */
760 public int getTimeToLive() {
761 if (Integer.MIN_VALUE == timeToLive) {
762 return 0;
763 } else {
764 return timeToLive;
765 }
766 }
767
768 /***
769 * @return the time to idle, in seconds
770 */
771 public int getTimeToIdle() {
772 if (Integer.MIN_VALUE == timeToIdle) {
773 return 0;
774 } else {
775 return timeToIdle;
776 }
777 }
778
779 /***
780 * @return <code>false</code> if this Element has a custom lifespan
781 */
782 public boolean usesCacheDefaultLifespan() {
783 return cacheDefaultLifespan;
784 }
785
786 /***
787 * Mark the element as pinned or not
788 *
789 * @param pinned true if the element should be pinned, false otherwise
790 */
791 public void setPinned(boolean pinned) {
792 this.pinned = pinned;
793 }
794
795 /***
796 * Check if the element is pinned
797 *
798 * @return true if the element is pinned
799 */
800 public boolean isPinned() {
801 return pinned;
802 }
803
804 /***
805 * Set the default parameters of this element - those from its enclosing cache.
806 * @param tti TTI in seconds
807 * @param ttl TTL in seconds
808 * @param eternal <code>true</code> if the element is eternal.
809 */
810 protected void setLifespanDefaults(int tti, int ttl, boolean eternal) {
811 if (eternal) {
812 this.timeToIdle = 0;
813 this.timeToLive = 0;
814 } else if (isEternal()) {
815 this.timeToIdle = Integer.MIN_VALUE;
816 this.timeToLive = Integer.MIN_VALUE;
817 } else {
818 timeToIdle = tti;
819 timeToLive = ttl;
820 }
821 }
822
823 /***
824 * Custom serialization write logic
825 */
826 private void writeObject(ObjectOutputStream out) throws IOException {
827 if (!elementEvictionData.canParticipateInSerialization()) {
828 throw new NotSerializableException();
829 }
830 out.defaultWriteObject();
831 out.writeInt(TimeUtil.toSecs(elementEvictionData.getCreationTime()));
832 out.writeInt(TimeUtil.toSecs(elementEvictionData.getLastAccessTime()));
833 }
834
835 /***
836 * Custom serialization read logic
837 */
838 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
839 in.defaultReadObject();
840 elementEvictionData = new DefaultElementEvictionData(TimeUtil.toMillis(in.readInt()), TimeUtil.toMillis(in.readInt()));
841 }
842 }