1 /* Open Source Java Caching Service
2 * Copyright (C) 2002 Frank Karlstrøm
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 * The author can be contacted by email: fjankk@sourceforge.net
18 */
19 package org.fjank.jcache;
20
21 import java.io.Serializable;
22
23 import javax.util.jcache.Attributes;
24 import javax.util.jcache.CacheEventListener;
25 import javax.util.jcache.CacheLoader;
26 import javax.util.jcache.InvalidArgumentException;
27
28 /**
29 * This class defines the attributes an object in the cache can have.
30 */
31 public final class AttributesImpl implements Cloneable, Serializable, Attributes {
32 private static final int ONE_DAY = 24;
33 private static final int ONE_HOUR = 60;
34 private static final int ONE_MINUTE = 60;
35 /** the time the associated CacheObject was created. */
36 private long createTime = System.currentTimeMillis();
37 /** the default time the associated CacheObject should live in the cache */
38 private long defaultTTL = -1;
39 /**
40 * Is used to specify wich attributes should be set in the attributes
41 * object. The differnet attributes wich is valid is defined as public
42 * static variables in the {@link Attributes}class.
43 */
44 private long flags;
45 /** the time the associated CacheObject should be idle in the cache */
46 private long idleTime;
47 /** the CacheListener for the associated CacheObject */
48 private transient CacheEventListener listener;
49 /** the CacheLoader for the associated CacheObject */
50 private transient CacheLoader loader;
51 /** the size for the associated CacheObject */
52 private int size;
53 /** the time the associated CacheObject should be live the cache */
54 private long timeToLive = -1;
55 /** the version of the associated CacheObject */
56 private long version;
57
58 /**
59 * Creates new Attributes
60 */
61 public AttributesImpl() {
62 }
63
64 public AttributesImpl(Attributes attributes) {
65 this.defaultTTL = attributes.getDefaultTimeToLive();
66 this.idleTime = attributes.getIdleTime();
67
68 this.listener = attributes.getListener();
69 this.loader = attributes.getLoader();
70 this.size = attributes.getSize();
71 this.timeToLive = attributes.getTimeToLive();
72 this.version = attributes.getVersion();
73 long flags = 0;
74
75 if (attributes.isSet(Attributes.DISTRIBUTE)) {
76 flags |= Attributes.DISTRIBUTE;
77 }
78 if (attributes.isSet(Attributes.NOFLUSH)) {
79 flags |= Attributes.NOFLUSH;
80 }
81 if (attributes.isSet(Attributes.REPLY)) {
82 flags |= Attributes.REPLY;
83 }
84 if (attributes.isSet(Attributes.SYNCHRONIZE)) {
85 flags |= Attributes.SYNCHRONIZE;
86 }
87 if (attributes.isSet(Attributes.SPOOL)) {
88 flags |= Attributes.SPOOL;
89 }
90 if (attributes.isSet(Attributes.GROUP_TTL_DESTROY)) {
91 flags |= Attributes.GROUP_TTL_DESTROY;
92 }
93 if (attributes.isSet(Attributes.ORIGINAL)) {
94 flags |= Attributes.ORIGINAL;
95 }
96 this.flags = flags;
97 }
98
99 public void applyAttributes(Attributes attributes) {
100 this.idleTime = attributes.getIdleTime();
101 this.timeToLive = attributes.getTimeToLive();
102 this.defaultTTL = attributes.getDefaultTimeToLive();
103 CacheEventListener listener = attributes.getListener();
104 setListener(Attributes.INVALIDATE_EVENT, listener);
105 }
106
107 public boolean equals(Object arg0) {
108 if (arg0 instanceof AttributesImpl) {
109 AttributesImpl obj = (AttributesImpl) arg0;
110 if (defaultTTL != obj.defaultTTL)
111 return false;
112 if (flags != obj.flags)
113 return false;
114 if (listener != obj.listener)
115 return false;
116 if (loader != obj.loader)
117 return false;
118 if (size != obj.size)
119 return false;
120 if (timeToLive != obj.timeToLive)
121 return false;
122 if (version != obj.version)
123 return false;
124 return true;
125 }
126 return super.equals(arg0);
127 }
128
129 /**
130 * returns the time the object was loaded into the cache. The time is the
131 * number of milliseconds since midnight, January 1, 1970 (UTC).
132 *
133 * @return the time the object was loaded into the cache. The time is the
134 * number of milliseconds since midnight, January 1, 1970 (UTC).
135 */
136 public long getCreateTime() {
137 return createTime;
138 }
139
140 public long getDefaultTimeToLive() {
141 return defaultTTL;
142 }
143
144 /**
145 * returns the current value for the idle time interval.
146 *
147 * @return the current value for the idle time interval.
148 */
149 public long getIdleTime() {
150 return idleTime;
151 }
152
153 /**
154 * Gets the CacheEventListener.
155 *
156 * @author Philippe Fajeau
157 * @return The CacheEventListener.
158 */
159 public CacheEventListener getListener() {
160 return listener;
161 }
162
163 /**
164 * returns the {@link CacheLoader}attribute.
165 *
166 * @return the {@link CacheLoader}attribute.
167 */
168 public CacheLoader getLoader() {
169 return loader;
170 }
171
172 /**
173 * returns the size of the object. this size is set by the
174 * {@link #setSize(int)} method, or in the case of StreamAccess objects, the
175 * size is calculated by the cache.
176 *
177 * @todo create and implement an online size calculator.
178 * @return the size of the object, or 0 if the size has not been set.
179 */
180 public int getSize() {
181 return size;
182 }
183
184 /**
185 * returns the current value for the time to live interval.
186 *
187 * @return the current value for the time to live interval.
188 */
189 public long getTimeToLive() {
190 if (defaultTTL != -1 && timeToLive == -1) {
191 return defaultTTL;
192 }
193 return timeToLive;
194 }
195
196 /**
197 * returns the current value of version.
198 *
199 * @return the current value of version.
200 */
201 public long getVersion() {
202 return version;
203 }
204
205 /**
206 * Checks wether the flags are set or not.
207 *
208 * @param theFlags
209 * the flags to be checked. may be OR-ed together, for wich this
210 * method will return true only if all flags are set.
211 *
212 * @return true if the specified attribute is set, false otherwise.
213 */
214 public boolean isSet(final long theFlags) {
215 return ((this.flags | theFlags) ^ this.flags) == 0;
216 }
217
218 /**
219 * resets the Attributes to its default values. The attributes wich are
220 * reset are expiration time attributes, time to live, default time to live,
221 * idle time and event handlers.
222 *
223 * @todo This method should be package private, thus this class should be
224 * moved to org.fjank.jcache, an interface should be extracted, and
225 * that should be public, and in this package.
226 */
227 public void reset() {
228 AttributesImpl def = new AttributesImpl();
229 this.idleTime = def.idleTime;
230 this.timeToLive = def.timeToLive;
231 this.defaultTTL = def.defaultTTL;
232 this.listener = def.listener;
233 }
234
235 /**
236 * Sets the createTime.
237 *
238 * @param aCreateTime
239 * The createTime to set
240 */
241 public void setCreateTime(final long aCreateTime) {
242 if (aCreateTime < 0) {
243 return;
244 }
245 this.createTime = aCreateTime;
246 }
247
248 /**
249 * Will set the maximum time the associated cache object will stay in the
250 * cache before it is invalidated. For regions and groups, this will
251 * establish a default time to live that is applied individually to each
252 * member in the group or region. It will not cause the entire group or
253 * region to time out as a whole. For individual objects, the default time
254 * to live is equivalent with time to live. If both are set the default time
255 * to live is ignored. The time starts when the object is loaded into the
256 * cache(by the {@link CacheLoader}objector put by the
257 * {@link CacheAccess#replace(Object, Object)}) or when the time to live
258 * attribute is set by the
259 * {@link CacheLoader#setAttributes(Object,Attributes)} method.
260 *
261 * @param ttl
262 * the time to live in seconds. The
263 * {@link #timeToSeconds(int, int, int, int)} can be used to
264 * convert days, hours, minutes to secounds.
265 *
266 * @throws InvalidArgumentException
267 * if a negative value for ttl is supplied.
268 */
269 public void setDefaultTimeToLive(final long ttl) throws InvalidArgumentException {
270 if (ttl < 0) {
271 throw new InvalidArgumentException("Default time to live must be a positive number.");
272 }
273 this.defaultTTL = ttl;
274 }
275
276 /**
277 * Is used to specify wich attributes should be set in the attributes
278 * object. The different attributes wich is valid is defined as public
279 * static variables in the {@link Attributes}class.
280 *
281 * @param theFlags
282 * The attributes to set. the attributes may be OR-ed together.
283 * I.e. Attributes.DISTRIBUTE | Attributes.SYNCHRONIZE Invalid
284 * flags are silently ignored. To reset all flags you use 0 as a
285 * parameter. I.e. setFlags(0)
286 */
287 public void setFlags(final long theFlags) {
288 if (theFlags < 0) {
289 return;
290 }
291 this.flags = theFlags;
292 }
293
294 /**
295 * sets the maximum time the associated cache object will remain in the
296 * cache without being referenced before it is invalidated.
297 *
298 * @param idle
299 * is in seconds. The {@link #timeToSeconds(int, int, int,int)}
300 * can be used to convert days, hours, minutes to secounds.
301 *
302 * @throws InvalidArgumentException
303 * if a negative value for idle is supplied.
304 */
305 public void setIdleTime(final long idle) throws InvalidArgumentException {
306 if (idle < 0) {
307 throw new InvalidArgumentException("Idle time must be a positive number.");
308 }
309 this.idleTime = idle;
310 }
311
312 /**
313 * Register an event listener object to be executed when the specified event
314 * occurs with relationship to the associated object. Currently the only
315 * invalidate event being monitored is Attributes.INVALIDATE_EVENT. If
316 * invalid parameters are passed such as invalid events, or null as
317 * listener, this method silently returns without doing any changes to this
318 * object.
319 *
320 * @param event
321 * The event to listen for.
322 * @param aListener
323 * the listener to fire when the event occurs.
324 *
325 *@todo Should these Attributes only have one Listener, or should several
326 * be supported?
327 */
328 public void setListener(final int event, final CacheEventListener aListener) {
329 if ((event == INVALIDATE_EVENT) && (aListener != null)) {
330 this.listener = aListener;
331 }
332 }
333
334 /**
335 * Will associate a loader object with this object.
336 *
337 * @param aLoader
338 * The loader to set. This parameter can be null.
339 */
340 public void setLoader(final CacheLoader aLoader) {
341 this.loader = aLoader;
342 }
343
344 /**
345 * Is used to specify the size in bytes of the object being cached. This is
346 * used to determine when the cache capacity is reached. If the cache is not
347 * using object size to determine the capacity (It can also use object
348 * counts) this value is ignored.
349 *
350 * @param aSize
351 * the size to be set. if this parameter is smaller than zero,
352 * this method silently returns.
353 */
354 public void setSize(final int aSize) {
355 if (aSize < 0) {
356 return;
357 }
358 this.size = aSize;
359 }
360
361 /**
362 * Will set the maximum time the associated cache object will stay in the
363 * cache before it is invalidated. The time starts when the object is loaded
364 * into the cache(by the {@link CacheLoader}object or put by the
365 * {@link CacheAccess#replace(Object, Object)}) or when the time to live
366 * attribute is set by the
367 * {@link CacheLoader#setAttributes(Object, Attributes)} method.
368 *
369 * @param ttl
370 * the time to live in seconds. The
371 * {@link #timeToSeconds(int, int, int, int)} can be used to
372 * convert days, hours, minutes to seconds.
373 *
374 * @throws InvalidArgumentException
375 * if a negative value for ttl is supplied.
376 */
377 public void setTimeToLive(final long ttl) throws InvalidArgumentException {
378 if (ttl < 0) {
379 throw new InvalidArgumentException("Time to live must be a positive number.");
380 }
381 this.timeToLive = ttl;
382 }
383
384 /**
385 * Sets the version attribute. Is only maintained for user convenience. It
386 * is not used internally by the cache.
387 *
388 * @param aVersion
389 * the version number to set.
390 */
391 public void setVersion(final long aVersion) {
392 this.version = aVersion;
393 }
394
395 /**
396 * Will convert the time specified into seconds.
397 *
398 * @param days
399 * number of days.
400 * @param hours
401 * number of hours.
402 * @param minutes
403 * number of minutes.
404 * @param seconds
405 * number of seconds.
406 *
407 * @return the converted time in seconds.
408 *
409 * @throws InvalidArgumentException
410 * if any of the parameters are negative values.
411 */
412 public long timeToSeconds(final int days, final int hours, final int minutes, final int seconds) throws InvalidArgumentException {
413 if (days < 0) {
414 throw new InvalidArgumentException("Days must be larger than zero.");
415 }
416 if (hours < 0) {
417 throw new InvalidArgumentException("Hours must be larger than zero.");
418 }
419 if (minutes < 0) {
420 throw new InvalidArgumentException("Minutes must be larger than zero.");
421 }
422 if (seconds < 0) {
423 throw new InvalidArgumentException("Seconds must be larger than zero.");
424 }
425 return seconds + (ONE_MINUTE * minutes) + (ONE_MINUTE * ONE_HOUR * hours) + (ONE_MINUTE * ONE_HOUR * ONE_DAY * days);
426 }
427
428 /**
429 * returns these Attributes as a String.
430 *
431 * @return these Attributes as a String.
432 */
433 public String toString() {
434 return "Attributes {ttl:" + timeToLive + '}'; //$NON-NLS-1$
435 }
436 }