This is an automated email from the ASF dual-hosted git repository. tv pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-jcs.git
commit f1c0edfbb6d0e5463365711e805bedab0c205e90 Author: Thomas Vandahl <[email protected]> AuthorDate: Sun Feb 8 22:26:17 2026 +0100 Make ElementAttributes (largely) immutable --- RECORDS_REFACTORING_EXAMPLE.md | 790 +++++++++++++++++++++ .../apache/commons/jcs4/admin/JCSAdminBean.java | 9 +- .../jcs4/auxiliary/disk/jdbc/JDBCDiskCache.java | 12 +- .../commons/jcs4/engine/ElementAttributes.java | 540 ++++++-------- .../jcs4/engine/behavior/IElementAttributes.java | 80 +-- .../jcs4/engine/control/CompositeCache.java | 28 +- .../engine/control/CompositeCacheConfigurator.java | 38 +- .../jcs4/engine/control/CompositeCacheManager.java | 2 +- .../engine/memory/shrinking/ShrinkerThread.java | 4 +- .../serialization/SerializationConversionUtil.java | 6 +- commons-jcs4-core/src/test/conf/cache.ccf | 2 +- commons-jcs4-core/src/test/conf/remote.cache.ccf | 2 +- .../jcs4/JCSCacheElementRetrievalUnitTest.java | 2 +- .../commons/jcs4/access/CacheAccessUnitTest.java | 22 +- .../commons/jcs4/access/TestCacheAccess.java | 2 +- .../disk/block/AbstractBlockDiskCacheUnitTest.java | 12 +- .../indexed/AbstractIndexDiskCacheUnitTest.java | 16 +- .../indexed/IndexedDiskCacheKeyStoreUnitTest.java | 12 +- .../remote/RemoteCacheListenerUnitTest.java | 12 +- .../jcs4/engine/ElementAttributesUtils.java | 5 +- .../control/event/SimpleEventHandlingUnitTest.java | 10 +- .../memory/shrinking/ShrinkerThreadUnitTest.java | 58 +- .../SerializationConversionUtilUnitTest.java | 20 +- .../src/test/test-conf/TestHSQLDiskCache.ccf | 2 +- .../test/test-conf/TestHSQLDiskCacheConcurrent.ccf | 2 +- .../src/test/test-conf/TestJDBCDiskCache.ccf | 2 +- .../test/test-conf/TestJDBCDiskCacheRemoval.ccf | 2 +- .../test/test-conf/TestJDBCDiskCacheSharedPool.ccf | 2 +- .../src/test/test-conf/TestJDBCDiskCacheShrink.ccf | 2 +- .../src/test/test-conf/TestMRUCache.ccf | 2 +- .../src/test/test-conf/TestMySQLDiskCache.ccf | 2 +- .../src/test/test-conf/TestRemoteClient.ccf | 2 +- .../src/test/test-conf/TestRemoteHttpCache.ccf | 2 +- .../src/test/test-conf/TestRemoteServer.ccf | 2 +- .../src/test/test-conf/TestSimpleEventHandling.ccf | 2 +- .../src/test/test-conf/TestSoftReferenceCache.ccf | 2 +- .../src/test/test-conf/TestZeroSizeCache.ccf | 2 +- .../org/apache/commons/jcs4/jcache/JCSCache.java | 52 +- .../commons/jcs4/jcache/JCSCachingManager.java | 2 +- xdocs/ElementAttributes.xml | 2 +- xdocs/IndexedDiskAuxCache.xml | 2 +- xdocs/JDBCDiskCache.xml | 6 +- xdocs/UpgradingFrom3x.xml | 11 +- xdocs/UsingJCSBasicWeb.xml | 4 +- xdocs/getting_started/intro.xml | 2 +- 45 files changed, 1235 insertions(+), 558 deletions(-) diff --git a/RECORDS_REFACTORING_EXAMPLE.md b/RECORDS_REFACTORING_EXAMPLE.md new file mode 100644 index 00000000..e2b49ae2 --- /dev/null +++ b/RECORDS_REFACTORING_EXAMPLE.md @@ -0,0 +1,790 @@ +<!--- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +# Refactoring PropertySetter Pattern to Java Records + +## Current Approach: PropertySetter with Reflection + +The current codebase uses `PropertySetter` (similar to log4j's implementation) to dynamically populate mutable objects from `Properties` using reflection and JavaBeans introspection. + +**Example at line 180 in CompositeCacheConfigurator:** +```java +AuxiliaryCacheAttributes auxAttr = ccm.registryAttrGet( auxName ); +auxAttr = auxAttr.clone(); +PropertySetter.setProperties( auxAttr, props, attrName + "." ); +auxAttr.setCacheName( regName ); +``` + +The pattern: +1. Create/clone a mutable object +2. Use reflection to introspect setter methods +3. Parse and convert property strings to target types +4. Invoke setters via reflection +5. Manual post-setup (e.g., `setCacheName()`) + +--- + +## Problems with Current Approach + +- **Boilerplate**: Each attribute class needs getters/setters for every property +- **No compile-time safety**: Property names and types are strings, discovered at runtime +- **Mutability**: Objects are mutable, making debugging harder +- **Performance**: Reflection overhead, introspection on every configuration load +- **Inheritance complexity**: Child classes override parent setters, must maintain parallel hierarchies +- **Cloning requirement**: Objects must be cloneable for reuse, adds complexity + +--- + +## Solution: Java Records + Builder Pattern + +Java Records (Java 14+, finalized in Java 16) provide immutable, compact data carriers. Combined with a builder pattern, they eliminate reflection while maintaining flexibility. + +### Approach 1: Simple Record + Static Builder + +**Before:** +```java +// CompositeCacheAttributes.java (current) +public class CompositeCacheAttributes implements ICompositeCacheAttributes { + private boolean useLateral = DEFAULT_USE_LATERAL; + private boolean useRemote = DEFAULT_USE_REMOTE; + private boolean useDisk = DEFAULT_USE_DISK; + private int maxObjs = DEFAULT_MAX_OBJECTS; + private long maxMemoryIdleTimeSeconds = DEFAULT_MAX_MEMORY_IDLE_TIME_SECONDS; + private String cacheName; + private String memoryCacheName; + // ... 15+ more properties + + public void setUseLateral(boolean val) { this.useLateral = val; } + public void setUseRemote(boolean val) { this.useRemote = val; } + public void setUseDisk(boolean val) { this.useDisk = val; } + // ... more setters +} +``` + +**After with Records:** +```java +public record CompositeCacheAttributes( + boolean useLateral, + boolean useRemote, + boolean useDisk, + boolean useMemoryShrinker, + int maxObjs, + long maxMemoryIdleTimeSeconds, + long shrinkerIntervalSeconds, + int maxSpoolPerRun, + String cacheName, + String memoryCacheName, + DiskUsagePattern diskUsagePattern +) implements ICompositeCacheAttributes { + + // Compact constructor for validation + public CompositeCacheAttributes { + // Add validation here if needed + } + + // Static factory with builder + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private boolean useLateral = DEFAULT_USE_LATERAL; + private boolean useRemote = DEFAULT_USE_REMOTE; + private boolean useDisk = DEFAULT_USE_DISK; + private boolean useMemoryShrinker = DEFAULT_USE_SHRINKER; + private int maxObjs = DEFAULT_MAX_OBJECTS; + private long maxMemoryIdleTimeSeconds = DEFAULT_MAX_MEMORY_IDLE_TIME_SECONDS; + private long shrinkerIntervalSeconds = DEFAULT_SHRINKER_INTERVAL_SECONDS; + private int maxSpoolPerRun = DEFAULT_MAX_SPOOL_PER_RUN; + private String cacheName; + private String memoryCacheName; + private DiskUsagePattern diskUsagePattern = DiskUsagePattern.SWAP; + + public Builder useLateral(boolean val) { this.useLateral = val; return this; } + public Builder useRemote(boolean val) { this.useRemote = val; return this; } + public Builder useDisk(boolean val) { this.useDisk = val; return this; } + public Builder useMemoryShrinker(boolean val) { this.useMemoryShrinker = val; return this; } + public Builder maxObjs(int val) { this.maxObjs = val; return this; } + public Builder maxMemoryIdleTimeSeconds(long val) { this.maxMemoryIdleTimeSeconds = val; return this; } + public Builder shrinkerIntervalSeconds(long val) { this.shrinkerIntervalSeconds = val; return this; } + public Builder maxSpoolPerRun(int val) { this.maxSpoolPerRun = val; return this; } + public Builder cacheName(String val) { this.cacheName = val; return this; } + public Builder memoryCacheName(String val) { this.memoryCacheName = val; return this; } + public Builder diskUsagePattern(DiskUsagePattern val) { this.diskUsagePattern = val; return this; } + + public CompositeCacheAttributes build() { + return new CompositeCacheAttributes( + useLateral, useRemote, useDisk, useMemoryShrinker, + maxObjs, maxMemoryIdleTimeSeconds, shrinkerIntervalSeconds, + maxSpoolPerRun, cacheName, memoryCacheName, diskUsagePattern + ); + } + } +} +``` + +### Usage Comparison + +**Current (PropertySetter with reflection):** +```java +ICompositeCacheAttributes ccAttr = new CompositeCacheAttributes(); +PropertySetter.setProperties(ccAttr, props, attrName + "."); +ccAttr.setCacheName(regName); +``` + +**New (Type-safe builder):** +```java +var builder = ICompositeCacheAttributes.builder(); +for (String key : props.stringPropertyNames()) { + if (key.startsWith(attrName + ".")) { + String propName = key.substring(attrName.length() + 1); + String value = props.getProperty(key); + builder.setPropertyByName(propName, value); // see below + } +} +ICompositeCacheAttributes ccAttr = builder.cacheName(regName).build(); +``` + +--- + +### Approach 2: Type-Safe Configuration Parser (Recommended) + +Instead of generic `PropertySetter`, create a **configuration parser** specific to each record type: + +```java +public record CompositeCacheAttributes(...) implements ICompositeCacheAttributes { + + public static class Parser { + private static final Map<String, BiConsumer<Builder, String>> PROPERTY_SETTERS = Map.ofEntries( + Map.entry("useLateral", (b, v) -> b.useLateral(Boolean.parseBoolean(v))), + Map.entry("useRemote", (b, v) -> b.useRemote(Boolean.parseBoolean(v))), + Map.entry("useDisk", (b, v) -> b.useDisk(Boolean.parseBoolean(v))), + Map.entry("useMemoryShrinker", (b, v) -> b.useMemoryShrinker(Boolean.parseBoolean(v))), + Map.entry("maxObjs", (b, v) -> b.maxObjs(Integer.parseInt(v))), + Map.entry("maxMemoryIdleTimeSeconds", (b, v) -> b.maxMemoryIdleTimeSeconds(Long.parseLong(v))), + Map.entry("shrinkerIntervalSeconds", (b, v) -> b.shrinkerIntervalSeconds(Long.parseLong(v))), + Map.entry("maxSpoolPerRun", (b, v) -> b.maxSpoolPerRun(Integer.parseInt(v))), + Map.entry("memoryCacheName", (b, v) -> b.memoryCacheName(v)), + Map.entry("diskUsagePattern", (b, v) -> b.diskUsagePattern(DiskUsagePattern.valueOf(v.toUpperCase()))) + ); + + public static CompositeCacheAttributes fromProperties( + Properties props, + String prefix, + String cacheName) { + var builder = CompositeCacheAttributes.builder(); + builder.cacheName(cacheName); + + final int prefixLen = prefix.length(); + for (String key : props.stringPropertyNames()) { + if (key.startsWith(prefix)) { + // Ignore nested properties (containing dots after prefix) + if (key.indexOf('.', prefixLen + 1) > 0) { + continue; + } + + String propName = key.substring(prefixLen); + String value = props.getProperty(key); + + var setter = PROPERTY_SETTERS.get(propName); + if (setter != null) { + try { + setter.accept(builder, value); + } catch (NumberFormatException | IllegalArgumentException e) { + log.warn("Failed to parse property {}: {}", key, e.getMessage()); + } + } else { + log.warn("Unknown property: {}", propName); + } + } + } + + return builder.build(); + } + } +} +``` + +**Usage:** +```java +ICompositeCacheAttributes ccAttr = CompositeCacheAttributes.Parser.fromProperties( + props, attrName + ".", regName +); +``` + +**Benefits:** +- ✅ Type-safe: Each property has explicit type conversion +- ✅ Compile-time safety: Property names are constants in the map +- ✅ No reflection: Direct method calls via `BiConsumer` +- ✅ Better error handling: Specific exception handling per property type +- ✅ Immutable: Records are immutable by default +- ✅ Performance: No introspection overhead +- ✅ IDE support: Auto-completion and refactoring work perfectly + +--- + +### Approach 3: Annotation-Based Configuration (Most Elegant) + +For a more scalable solution that reduces boilerplate, use annotations: + +#### Annotation Definition + +```java +package org.apache.commons.jcs4.utils.config; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Marks a record component as a configurable property that can be loaded from Properties. + * Applied to individual record components. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.RECORD_COMPONENT) +public @interface ConfigurableProperty { + + /** + * The property name in the configuration file. + * If not specified, defaults to the record component name. + */ + String name() default ""; + + /** + * The type of conversion needed: "boolean", "int", "long", "double", "string", "enum" + */ + String type(); + + /** + * Default value if property is not provided (as a string). + */ + String defaultValue() default ""; + + /** + * Whether this property is required (no default). + */ + boolean required() default false; + + /** + * For enum types, the enum class name (if type="enum"). + */ + String enumClass() default ""; +} + +/** + * Applied to record classes to enable configuration parsing. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface Configurable { + /** + * Optional description of what this configuration represents. + */ + String description() default ""; +} +``` + +#### Record Definition + +```java +@Configurable(description = "Composite cache region attributes") +public record CompositeCacheAttributes( + @ConfigurableProperty(name = "useLateral", type = "boolean", defaultValue = "true") + boolean useLateral, + + @ConfigurableProperty(name = "useRemote", type = "boolean", defaultValue = "true") + boolean useRemote, + + @ConfigurableProperty(name = "useDisk", type = "boolean", defaultValue = "true") + boolean useDisk, + + @ConfigurableProperty(name = "useMemoryShrinker", type = "boolean", defaultValue = "false") + boolean useMemoryShrinker, + + @ConfigurableProperty(name = "maxObjs", type = "int", defaultValue = "100") + int maxObjs, + + @ConfigurableProperty(name = "maxMemoryIdleTimeSeconds", type = "long", defaultValue = "7200") + long maxMemoryIdleTimeSeconds, + + @ConfigurableProperty(name = "shrinkerIntervalSeconds", type = "long", defaultValue = "30") + long shrinkerIntervalSeconds, + + @ConfigurableProperty(name = "maxSpoolPerRun", type = "int", defaultValue = "-1") + int maxSpoolPerRun, + + @ConfigurableProperty(name = "memoryCacheName", type = "string", + defaultValue = "org.apache.commons.jcs4.engine.memory.lru.LRUMemoryCache") + String memoryCacheName, + + @ConfigurableProperty(name = "diskUsagePattern", type = "enum", + enumClass = "org.apache.commons.jcs4.engine.DiskUsagePattern", + defaultValue = "SWAP") + DiskUsagePattern diskUsagePattern, + + // Not annotated - injected programmatically + String cacheName +) implements ICompositeCacheAttributes { + + public static CompositeCacheAttributes fromProperties( + Properties props, + String prefix, + String cacheName) { + return ConfigurationBuilder.create(CompositeCacheAttributes.class) + .fromProperties(props, prefix) + .set("cacheName", cacheName) + .build(); + } +} +``` + +#### Generic Configuration Builder + +```java +package org.apache.commons.jcs4.utils.config; + +import java.lang.reflect.Constructor; +import java.lang.reflect.RecordComponent; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +/** + * Generic builder for record types annotated with @Configurable. + * Automatically parses Properties and creates record instances. + */ +public class ConfigurationBuilder<T> { + + private static final Log log = Log.getLog(ConfigurationBuilder.class); + + private final Class<T> recordClass; + private final Map<String, Object> values = new HashMap<>(); + private final Map<String, String> errors = new HashMap<>(); + + private ConfigurationBuilder(Class<T> recordClass) { + if (!recordClass.isRecord()) { + throw new IllegalArgumentException(recordClass.getName() + " is not a record"); + } + this.recordClass = recordClass; + initializeDefaults(); + } + + /** + * Create a new builder for the given record class. + */ + public static <T> ConfigurationBuilder<T> create(Class<T> recordClass) { + return new ConfigurationBuilder<>(recordClass); + } + + /** + * Initialize default values from annotations. + */ + private void initializeDefaults() { + RecordComponent[] components = recordClass.getRecordComponents(); + for (RecordComponent component : components) { + ConfigurableProperty prop = component.getAnnotation(ConfigurableProperty.class); + if (prop != null && !prop.defaultValue().isEmpty()) { + Object value = parseValue(prop.defaultValue(), prop.type(), prop.enumClass()); + if (value != null) { + values.put(component.getName(), value); + } + } + } + } + + /** + * Load properties from a Properties object with a given prefix. + */ + public ConfigurationBuilder<T> fromProperties(Properties props, String prefix) { + if (props == null || props.isEmpty()) { + return this; + } + + RecordComponent[] components = recordClass.getRecordComponents(); + final int prefixLen = prefix.length(); + + for (RecordComponent component : components) { + ConfigurableProperty prop = component.getAnnotation(ConfigurableProperty.class); + if (prop == null) { + continue; + } + + String propName = prop.name().isEmpty() ? component.getName() : prop.name(); + String fullKey = prefix + propName; + String value = props.getProperty(fullKey); + + if (value != null) { + try { + Object parsed = parseValue(value, prop.type(), prop.enumClass()); + if (parsed != null) { + values.put(component.getName(), parsed); + log.debug("Loaded property {}: {}", fullKey, parsed); + } + } catch (Exception e) { + String errMsg = String.format( + "Failed to parse property '%s' with value '%s' as %s", + fullKey, value, prop.type() + ); + errors.put(component.getName(), errMsg); + log.warn("{}: {}", errMsg, e.getMessage()); + } + } else if (prop.required()) { + String errMsg = String.format("Required property '%s' not found", fullKey); + errors.put(component.getName(), errMsg); + log.error(errMsg); + } + } + + return this; + } + + /** + * Explicitly set a property value. + */ + public ConfigurationBuilder<T> set(String componentName, Object value) { + if (value != null) { + values.put(componentName, value); + } + return this; + } + + /** + * Explicitly set a property value from a string. + */ + public ConfigurationBuilder<T> setProperty(String componentName, String value) { + RecordComponent component = findComponent(componentName); + if (component == null) { + log.warn("No record component named: {}", componentName); + return this; + } + + ConfigurableProperty prop = component.getAnnotation(ConfigurableProperty.class); + if (prop != null) { + try { + Object parsed = parseValue(value, prop.type(), prop.enumClass()); + if (parsed != null) { + values.put(componentName, parsed); + } + } catch (Exception e) { + errors.put(componentName, e.getMessage()); + log.warn("Failed to set property {}: {}", componentName, e.getMessage()); + } + } else { + values.put(componentName, value); + } + + return this; + } + + /** + * Check if there were any errors during configuration. + */ + public boolean hasErrors() { + return !errors.isEmpty(); + } + + /** + * Get all configuration errors. + */ + public Map<String, String> getErrors() { + return new HashMap<>(errors); + } + + /** + * Build the record instance, throwing if any required properties are missing. + */ + public T build() { + // Validate all required properties are present + for (RecordComponent component : recordClass.getRecordComponents()) { + ConfigurableProperty prop = component.getAnnotation(ConfigurableProperty.class); + if (prop != null && prop.required() && !values.containsKey(component.getName())) { + throw new IllegalStateException( + "Required property missing: " + component.getName() + ); + } + } + + return createInstance(); + } + + /** + * Build the record instance, returning null if any errors occurred. + */ + public T buildSafely() { + if (hasErrors()) { + return null; + } + return createInstance(); + } + + /** + * Create the record instance using the canonical constructor. + */ + private T createInstance() { + try { + RecordComponent[] components = recordClass.getRecordComponents(); + Class<?>[] paramTypes = new Class<?>[components.length]; + Object[] params = new Object[components.length]; + + for (int i = 0; i < components.length; i++) { + paramTypes[i] = components[i].getType(); + Object value = values.get(components[i].getName()); + if (value == null) { + // Use null-safe defaults for primitives + value = getDefaultForType(components[i].getType()); + } + params[i] = value; + } + + Constructor<T> constructor = recordClass.getDeclaredConstructor(paramTypes); + T instance = constructor.newInstance(params); + log.debug("Created instance of {}", recordClass.getSimpleName()); + return instance; + + } catch (Exception e) { + throw new RuntimeException( + "Failed to create instance of " + recordClass.getName(), e + ); + } + } + + /** + * Parse a string value to the appropriate type. + */ + private Object parseValue(String value, String type, String enumClassName) { + if (value == null || value.trim().isEmpty()) { + return null; + } + + String trimmed = value.trim(); + + try { + return switch (type.toLowerCase()) { + case "boolean" -> Boolean.parseBoolean(trimmed); + case "int" -> Integer.parseInt(trimmed); + case "long" -> Long.parseLong(trimmed); + case "double" -> Double.parseDouble(trimmed); + case "string" -> value; + case "enum" -> parseEnum(trimmed, enumClassName); + default -> { + log.warn("Unknown type for conversion: {}", type); + yield value; + } + }; + } catch (Exception e) { + throw new RuntimeException( + String.format("Cannot convert '%s' to type %s", value, type), e + ); + } + } + + /** + * Parse an enum value. + */ + @SuppressWarnings("unchecked") + private Object parseEnum(String value, String enumClassName) throws Exception { + Class<? extends Enum> enumClass = (Class<? extends Enum>) Class.forName(enumClassName); + return Enum.valueOf(enumClass, value.toUpperCase()); + } + + /** + * Get default value for a primitive type. + */ + private Object getDefaultForType(Class<?> type) { + if (type == boolean.class) return false; + if (type == int.class) return 0; + if (type == long.class) return 0L; + if (type == double.class) return 0.0d; + if (type == float.class) return 0.0f; + return null; + } + + /** + * Find a record component by name. + */ + private RecordComponent findComponent(String name) { + for (RecordComponent component : recordClass.getRecordComponents()) { + if (component.getName().equals(name)) { + return component; + } + } + return null; + } +} +``` + +#### Usage Examples + +```java +// Simple case: load from properties +Properties props = new Properties(); +props.load(new FileInputStream("cache.properties")); +CompositeCacheAttributes attrs = ConfigurationBuilder + .create(CompositeCacheAttributes.class) + .fromProperties(props, "jcs.region.myregion.cacheattributes.") + .set("cacheName", "myregion") + .build(); + +// With error handling +var builder = ConfigurationBuilder.create(CompositeCacheAttributes.class) + .fromProperties(props, "jcs.region.myregion.cacheattributes.") + .set("cacheName", "myregion"); + +if (builder.hasErrors()) { + builder.getErrors().forEach((prop, error) -> + log.error("Configuration error in {}: {}", prop, error) + ); + return null; +} + +CompositeCacheAttributes attrs = builder.build(); + +// In CompositeCacheConfigurator.parseCompositeCacheAttributes() +protected ICompositeCacheAttributes parseCompositeCacheAttributes( + final Properties props, + final String regName, + final ICompositeCacheAttributes defaultCCAttr, + final String regionPrefix) { + + final String attrName = regionPrefix + regName + CACHE_ATTRIBUTE_PREFIX; + + try { + var builder = ConfigurationBuilder.create(CompositeCacheAttributes.class) + .fromProperties(props, attrName + "."); + + if (builder.hasErrors()) { + log.error("Configuration errors for region {}: {}", + regName, builder.getErrors()); + return defaultCCAttr; + } + + return builder.set("cacheName", regName).build(); + } catch (Exception e) { + log.error("Failed to parse cache attributes for region {}", regName, e); + return defaultCCAttr; + } +} + +// Works with other record types too (ElementAttributes, etc.) +ElementAttributes elemAttrs = ConfigurationBuilder + .create(ElementAttributes.class) + .fromProperties(props, "jcs.region.myregion.elementattributes.") + .build(); +``` + +#### Advantages of Annotation-Based Approach + +- **Single Source of Truth**: Metadata is embedded in the record definition +- **Type-Safe**: Compiler ensures properties exist and have correct types +- **Minimal Boilerplate**: No need to write parser classes for each record type +- **Reusable Infrastructure**: `ConfigurationBuilder` works for any `@Configurable` record +- **Runtime Flexibility**: Properties can be added without recompilation +- **Better IDE Support**: Annotations provide navigation and quick-fixes +- **Self-Documenting**: Annotations serve as documentation +- **Extensible**: Easy to add new annotation features (validation, transformation, etc.) +``` + +--- + +## Handling Inheritance (Child Types) + +If you have child attribute classes inheriting from parent classes, records handle this differently: + +**Current (with inheritance):** +```java +public abstract class AbstractAuxiliaryCacheAttributes { ... } +public class JDBCAuxiliaryCacheAttributes extends AbstractAuxiliaryCacheAttributes { ... } +``` + +**With Records (sealed types):** +```java +// Base record +public record AuxiliaryCacheAttributes( + String name, + int maxFailureWaitTimeSeconds, + long failureCountWaitTimeSeconds, + // common properties +) { } + +// Sealed type hierarchy (Java 17+) +public sealed record JDBCAuxiliaryCacheAttributes( + String name, + int maxFailureWaitTimeSeconds, + long failureCountWaitTimeSeconds, + String username, + String password, + String driver, + // JDBC-specific properties +) extends AuxiliaryCacheAttributes { } + +public sealed record RemoteAuxiliaryCacheAttributes( + String name, + int maxFailureWaitTimeSeconds, + long failureCountWaitTimeSeconds, + String remoteHost, + int remotePort, + // Remote-specific properties +) extends AuxiliaryCacheAttributes { } +``` + +--- + +## Migration Strategy + +1. **Phase 1**: Create new record classes alongside existing ones +2. **Phase 2**: Add parsers for records (Approach 2 above) +3. **Phase 3**: Update configurators to use new parsers +4. **Phase 4**: Gradually deprecate old attribute classes +5. **Phase 5**: Remove PropertySetter dependency + +**Example migration in CompositeCacheConfigurator:** + +```java +// OLD (lines 258-266) +protected ICompositeCacheAttributes parseCompositeCacheAttributes(...) { + ICompositeCacheAttributes ccAttr = new CompositeCacheAttributes(); + final String attrName = regionPrefix + regName + CACHE_ATTRIBUTE_PREFIX; + PropertySetter.setProperties(ccAttr, props, attrName + "."); + ccAttr.setCacheName(regName); + return ccAttr; +} + +// NEW +protected ICompositeCacheAttributes parseCompositeCacheAttributes(...) { + final String attrName = regionPrefix + regName + CACHE_ATTRIBUTE_PREFIX; + return CompositeCacheAttributes.Parser.fromProperties( + props, attrName + ".", regName + ); +} +``` + +--- + +## Summary + +| Aspect | PropertySetter | Record + Builder | Record + Parser | Record + Annotation | +|--------|---|---|---|---| +| Boilerplate | High | Medium | Low | Very Low | +| Type Safety | Low | High | High | High | +| Performance | Low (Reflection) | High | High | Medium | +| Error Handling | Generic | Better | Best | Good | +| IDE Support | Limited | Excellent | Excellent | Excellent | +| Maintenance | Difficult | Easier | Easy | Easiest | +| Learning Curve | Moderate | Low | Low | Medium | +| Immutability | No | Yes | Yes | Yes | + +**Recommendation**: Start with **Approach 2 (Type-Safe Parser)** for immediate benefits with minimal refactoring. Evolve to **Approach 3 (Annotation-Based)** if configuration complexity grows. diff --git a/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/admin/JCSAdminBean.java b/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/admin/JCSAdminBean.java index ef597cfb..17478d19 100644 --- a/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/admin/JCSAdminBean.java +++ b/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/admin/JCSAdminBean.java @@ -140,15 +140,14 @@ public class JCSAdminBean implements JCSJMXBean for (final Map.Entry<String, ?> key : keys.entrySet()) { final ICacheElement<?, ?> element = cache.getMemoryCache().getQuiet( key.getValue() ); - final IElementAttributes attributes = element.getElementAttributes(); final CacheElementInfo elementInfo = new CacheElementInfo( key.getKey(), - attributes.getIsEternal(), - format.format(new Date(attributes.getCreateTime())), - attributes.getMaxLife(), - (now - attributes.getCreateTime() - attributes.getMaxLife() * 1000 ) / -1000); + attributes.isEternal(), + format.format(new Date(attributes.createTime())), + attributes.maxLife(), + (now - attributes.createTime() - attributes.maxLife() * 1000 ) / -1000); records.add( elementInfo ); } diff --git a/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/auxiliary/disk/jdbc/JDBCDiskCache.java b/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/auxiliary/disk/jdbc/JDBCDiskCache.java index ee426604..38b57971 100644 --- a/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/auxiliary/disk/jdbc/JDBCDiskCache.java +++ b/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/auxiliary/disk/jdbc/JDBCDiskCache.java @@ -458,16 +458,16 @@ public class JDBCDiskCache<K, V> psInsert.setString( 1, ce.getKey().toString() ); psInsert.setString( 2, getCacheName() ); psInsert.setBytes( 3, element ); - psInsert.setLong( 4, ce.getElementAttributes().getMaxLife() ); - psInsert.setString( 5, ce.getElementAttributes().getIsEternal() ? "T" : "F" ); + psInsert.setLong( 4, ce.getElementAttributes().maxLife() ); + psInsert.setString( 5, ce.getElementAttributes().isEternal() ? "T" : "F" ); - final Timestamp createTime = new Timestamp( ce.getElementAttributes().getCreateTime() ); + final Timestamp createTime = new Timestamp( ce.getElementAttributes().createTime() ); psInsert.setTimestamp( 6, createTime ); final long now = System.currentTimeMillis() / 1000; psInsert.setLong( 7, now ); - final long expireTime = now + ce.getElementAttributes().getMaxLife(); + final long expireTime = now + ce.getElementAttributes().maxLife(); psInsert.setLong( 8, expireTime ); psInsert.execute(); @@ -508,13 +508,13 @@ public class JDBCDiskCache<K, V> { psUpdate.setBytes( 1, element ); - final Timestamp createTime = new Timestamp( ce.getElementAttributes().getCreateTime() ); + final Timestamp createTime = new Timestamp( ce.getElementAttributes().createTime() ); psUpdate.setTimestamp( 2, createTime ); final long now = System.currentTimeMillis() / 1000; psUpdate.setLong( 3, now ); - final long expireTime = now + ce.getElementAttributes().getMaxLife(); + final long expireTime = now + ce.getElementAttributes().maxLife(); psUpdate.setLong( 4, expireTime ); psUpdate.setString( 5, (String) ce.getKey() ); diff --git a/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/engine/ElementAttributes.java b/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/engine/ElementAttributes.java index 7cf67ab7..01a05c5f 100644 --- a/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/engine/ElementAttributes.java +++ b/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/engine/ElementAttributes.java @@ -21,245 +21,298 @@ package org.apache.commons.jcs4.engine; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.atomic.AtomicLong; import org.apache.commons.jcs4.engine.behavior.IElementAttributes; import org.apache.commons.jcs4.engine.control.event.behavior.IElementEventHandler; /** - * This it the element attribute descriptor class. Each element in the cache has an ElementAttribute + * This it the element attribute descriptor class. Each element in the cache has an ElementAttributes * object associated with it. An ElementAttributes object can be associated with an element in 3 * ways: * <ol> * <li>When the item is put into the cache, you can associate an element attributes object.</li> - * <li>If not attributes object is include when the element is put into the cache, then the default + * <li>If no attributes object is specified when the element is put into the cache, then the default * attributes for the region will be used.</li> * <li>The element attributes can be reset. This effectively results in a retrieval followed by a * put. Hence, this is the same as 1.</li> * </ol> */ -public class ElementAttributes - implements IElementAttributes +public record ElementAttributes( + /** Can this item be flushed to disk */ + boolean isSpool, + + /** Is this item laterally distributable */ + boolean isLateral, + + /** Can this item be sent to the remote cache */ + boolean isRemote, + + /** + * You can turn off expiration by setting this to true. This causes the cache to bypass both max + * life and idle time expiration. + */ + boolean isEternal, + + /** Max life seconds */ + long maxLife, + + /** + * The maximum time an entry can be idle. Setting this to -1 causes the idle time check to be + * ignored. + */ + long maxIdleTime, + + /** The byte size of the field. Must be manually set. */ + int size, + + /** The creation time. This is used to enforce the max life. */ + long createTime, + + /** The last access time. This is used to enforce the max idle time. */ + AtomicLong atomicLastAccessTime, + + /** The time factor to convert durations to milliseconds */ + long timeFactorForMilliseconds, + + /** + * The list of Event handlers to use. This is transient, since the event handlers cannot usually + * be serialized. This means that you cannot attach a post serialization event to an item. + * <p> + * TODO we need to check that when an item is passed to a non-local cache that if the local + * cache had a copy with event handlers, that those handlers are used. + */ + ArrayList<IElementEventHandler> elementEventHandlers +) implements IElementAttributes { /** Don't change. */ private static final long serialVersionUID = 7814990748035017441L; - /** Can this item be flushed to disk */ - private boolean IS_SPOOL = true; - - /** Is this item laterally distributable */ - private boolean IS_LATERAL = true; - - /** Can this item be sent to the remote cache */ - private boolean IS_REMOTE = true; - - /** - * You can turn off expiration by setting this to true. This causes the cache to bypass both max - * life and idle time expiration. - */ - private boolean IS_ETERNAL = true; - - /** Max life seconds */ - private long maxLife = -1; - - /** - * The maximum time an entry can be idle. Setting this to -1 causes the idle time check to be - * ignored. - */ - private long maxIdleTime = -1; - - /** The byte size of the field. Must be manually set. */ - private int size; - - /** The creation time. This is used to enforce the max life. */ - private long createTime; - - /** The last access time. This is used to enforce the max idel time. */ - private long lastAccessTime; + /** Default */ + private static final boolean DEFAULT_IS_SPOOL = true; + /** Default */ + private static final boolean DEFAULT_IS_LATERAL = true; + /** Default */ + private static final boolean DEFAULT_IS_REMOTE = true; + /** Default */ + private static final boolean DEFAULT_IS_ETERNAL = true; + /** Default */ + private static final long DEFAULT_MAX_LIFE = -1; + /** Default */ + private static final long DEFAULT_MAX_IDLE_TIME = -1; + /** Default */ + private static final long DEFAULT_TIME_FACTOR = 1000; + + /** Record with all defaults set */ + private static final ElementAttributes DEFAULT = new ElementAttributes( + DEFAULT_IS_SPOOL, + DEFAULT_IS_LATERAL, + DEFAULT_IS_REMOTE, + DEFAULT_IS_ETERNAL, + DEFAULT_MAX_LIFE, + DEFAULT_MAX_IDLE_TIME, + 0, + 0, + new AtomicLong(), + DEFAULT_TIME_FACTOR, + new ArrayList<>()); /** - * The list of Event handlers to use. This is transient, since the event handlers cannot usually - * be serialized. This means that you cannot attach a post serialization event to an item. - * <p> - * TODO we need to check that when an item is passed to a non-local cache that if the local - * cache had a copy with event handlers, that those handlers are used. - */ - private transient ArrayList<IElementEventHandler> eventHandlers; - - private long timeFactor = 1000; - - /** - * Constructor for the IElementAttributes object + * @return an object containing the default settings */ - public ElementAttributes() + public static ElementAttributes defaults() { - this.createTime = System.currentTimeMillis(); - this.lastAccessTime = this.createTime; + return DEFAULT; } /** - * Constructor for the IElementAttributes object - * - * @param attr + * Constructor for the ElementAttributes object */ - protected ElementAttributes( final ElementAttributes attr ) + public ElementAttributes() { - IS_ETERNAL = attr.IS_ETERNAL; - - // waterfall onto disk, for pure disk set memory to 0 - IS_SPOOL = attr.IS_SPOOL; - - // lateral - IS_LATERAL = attr.IS_LATERAL; - - // central rmi store - IS_REMOTE = attr.IS_REMOTE; - - maxLife = attr.maxLife; - // time-to-live - maxIdleTime = attr.maxIdleTime; - size = attr.size; + this(defaults()); + this.atomicLastAccessTime.set(createTime()); } /** - * Adds a ElementEventHandler. Handler's can be registered for multiple events. A registered - * handler will be called at every recognized event. - * <p> - * The alternative would be to register handlers for each event. Or maybe The handler interface - * should have a method to return whether it cares about certain events. - * - * @param eventHandler The ElementEventHandler to be added to the list. + * Copy constructor for the ElementAttributes object */ - @Override - public void addElementEventHandler( final IElementEventHandler eventHandler ) + public ElementAttributes(IElementAttributes from) { - // lazy here, no concurrency problems expected - if ( this.eventHandlers == null ) - { - this.eventHandlers = new ArrayList<>(); - } - this.eventHandlers.add( eventHandler ); + this(from.isSpool(), + from.isLateral(), + from.isRemote(), + from.isEternal(), + from.maxLife(), + from.maxIdleTime(), + from.size(), + System.currentTimeMillis(), + new AtomicLong(from.lastAccessTime()), + from.timeFactorForMilliseconds(), + new ArrayList<>(from.elementEventHandlers())); } /** - * Sets the eventHandlers of the IElementAttributes object. - * <p> - * This add the references to the local list. Subsequent changes in the caller's list will not - * be reflected. - * - * @param eventHandlers List of IElementEventHandler objects + * Constructor for the ElementAttributes object */ - @Override - public void addElementEventHandlers( final List<IElementEventHandler> eventHandlers ) + public ElementAttributes( + boolean isSpool, + boolean isLateral, + boolean isRemote, + boolean isEternal, + long maxLife, + long maxIdleTime, + long timeFactorForMilliseconds + ) { - if ( eventHandlers == null ) - { - return; - } + this(isSpool, isLateral, isRemote, isEternal, maxLife, maxIdleTime, 0, + System.currentTimeMillis(), new AtomicLong(), timeFactorForMilliseconds, + new ArrayList<>()); - for (final IElementEventHandler handler : eventHandlers) - { - addElementEventHandler(handler); - } + this.atomicLastAccessTime.set(createTime()); } /** - * @see Object#clone() + * Sets the isSpool attribute of the ElementAttributes object + * @param val The new isSpool value */ - @Override - public IElementAttributes clone() + public ElementAttributes withIsSpool( boolean val ) { - try - { - final ElementAttributes c = (ElementAttributes) super.clone(); - c.setCreateTime(); - return c; - } - catch (final CloneNotSupportedException e) - { - throw new IllegalStateException("Clone not supported. This should never happen.", e); - } + return new ElementAttributes( + val, + isLateral(), + isRemote(), + isEternal(), + maxLife(), + maxIdleTime(), + size(), + System.currentTimeMillis(), + new AtomicLong(lastAccessTime()), + timeFactorForMilliseconds(), + new ArrayList<>(elementEventHandlers())); } /** - * Gets the createTime attribute of the IAttributes object. - * <p> - * This should be the current time in milliseconds returned by the sysutem call when the element - * is put in the cache. - * <p> - * Putting an item in the cache overrides any existing items. - * @return The createTime value + * Sets the isEternal attribute of the ElementAttributes object + * @param val The new isEternal value */ - @Override - public long getCreateTime() + public ElementAttributes withIsEternal( boolean val ) { - return createTime; + return new ElementAttributes( + isSpool(), + isLateral(), + isRemote(), + val, + maxLife(), + maxIdleTime(), + size(), + System.currentTimeMillis(), + new AtomicLong(lastAccessTime()), + timeFactorForMilliseconds(), + new ArrayList<>(elementEventHandlers())); } /** - * Gets the elementEventHandlers. Returns null if none exist. Makes checking easy. + * Sets the maxLife attribute of the ElementAttributes object. * - * @return The elementEventHandlers List of IElementEventHandler objects + * @param mls The new MaxLifeSeconds value */ - @Override - public ArrayList<IElementEventHandler> getElementEventHandlers() + public ElementAttributes withMaxLife(long mls) { - return this.eventHandlers; + return new ElementAttributes( + isSpool(), + isLateral(), + isRemote(), + isEternal(), + mls, + maxIdleTime(), + size(), + System.currentTimeMillis(), + new AtomicLong(lastAccessTime()), + timeFactorForMilliseconds(), + new ArrayList<>(elementEventHandlers())); } /** - * Gets the idleTime attribute of the IAttributes object. - * - * @return The idleTime value + * Sets the idleTime attribute of the ElementAttributes object. This is the maximum time the item can + * be idle in the cache, that is not accessed. + * <p> + * If this is exceeded the element will not be returned, instead it will be removed. It will be + * removed on retrieval, or removed actively if the memory shrinker is turned on. + * @param idle The new idleTime value */ - @Override - public long getIdleTime() + public ElementAttributes withMaxIdleTime(long idle) { - return this.maxIdleTime; + return new ElementAttributes( + isSpool(), + isLateral(), + isRemote(), + isEternal(), + maxLife(), + idle, + size(), + System.currentTimeMillis(), + new AtomicLong(lastAccessTime()), + timeFactorForMilliseconds(), + new ArrayList<>(elementEventHandlers())); } /** - * You can turn off expiration by setting this to true. The max life value will be ignored. + * Sets the size attribute of the ElementAttributes object. * - * @return true if the item cannot expire. + * @param size The new size value */ - @Override - public boolean getIsEternal() + public ElementAttributes withSize(int size) { - return this.IS_ETERNAL; + return new ElementAttributes( + isSpool(), + isLateral(), + isRemote(), + isEternal(), + maxLife(), + maxIdleTime(), + size, + System.currentTimeMillis(), + new AtomicLong(lastAccessTime()), + timeFactorForMilliseconds(), + new ArrayList<>(elementEventHandlers())); } /** - * Is this item laterally distributable. Can it be sent to auxiliaries of type lateral. + * Adds a ElementEventHandler. Handler's can be registered for multiple events. A registered + * handler will be called at every recognized event. * <p> - * By default this is true. - * @return The isLateral value - */ - @Override - public boolean getIsLateral() - { - return this.IS_LATERAL; - } - - /** - * Can this item be sent to the remote cache - * @return true if the item can be sent to a remote auxiliary + * The alternative would be to register handlers for each event. Or maybe The handler interface + * should have a method to return whether it cares about certain events. + * + * @param eventHandler The ElementEventHandler to be added to the list. */ @Override - public boolean getIsRemote() + public void addElementEventHandler( final IElementEventHandler eventHandler ) { - return this.IS_REMOTE; + this.elementEventHandlers.add( eventHandler ); } /** - * Can this item be spooled to disk + * Sets the eventHandlers of the IElementAttributes object. * <p> - * By default this is true. - * @return The spoolable value + * This add the references to the local list. Subsequent changes in the caller's list will not + * be reflected. + * + * @param eventHandlers List of IElementEventHandler objects */ @Override - public boolean getIsSpool() + public void addElementEventHandlers( final List<IElementEventHandler> eventHandlers ) { - return this.IS_SPOOL; + if ( eventHandlers == null ) + { + return; + } + + for (final IElementEventHandler handler : eventHandlers) + { + addElementEventHandler(handler); + } } /** @@ -268,161 +321,30 @@ public class ElementAttributes * @return The LastAccess value. */ @Override - public long getLastAccessTime() - { - return this.lastAccessTime; - } - - /** - * Sets the maxLife attribute of the IAttributes object. How many seconds it can live after - * creation. - * <p> - * If this is exceeded the element will not be returned, instead it will be removed. It will be - * removed on retrieval, or removed actively if the memory shrinker is turned on. - * @return The MaxLifeSeconds value - */ - @Override - public long getMaxLife() + public long lastAccessTime() { - return this.maxLife; + return atomicLastAccessTime().get(); } /** - * Gets the size attribute of the IAttributes object - * - * @return The size value + * Sets the LastAccessTime as now of the IElementAttributes object */ @Override - public int getSize() - { - return size; - } - - @Override - public long getTimeFactorForMilliseconds() + public void setLastAccessTimeNow() { - return timeFactor; + this.atomicLastAccessTime.set(System.currentTimeMillis()); } /** - * Gets the time left to live of the IAttributes object. + * Gets the time left to live of the IElementAttributes object. * <p> * This is the (max life + create time) - current time. * @return The TimeToLiveSeconds value */ - @Override - public long getTimeToLiveSeconds() + private long getTimeToLiveSeconds() { final long now = System.currentTimeMillis(); - final long timeFactorForMilliseconds = getTimeFactorForMilliseconds(); - return ( getCreateTime() + getMaxLife() * timeFactorForMilliseconds - now ) / 1000; - } - - /** - * Sets the createTime attribute of the IElementAttributes object - */ - public void setCreateTime() - { - createTime = System.currentTimeMillis(); - } - - /** - * Sets the idleTime attribute of the IAttributes object. This is the maximum time the item can - * be idle in the cache, that is not accessed. - * <p> - * If this is exceeded the element will not be returned, instead it will be removed. It will be - * removed on retrieval, or removed actively if the memory shrinker is turned on. - * @param idle The new idleTime value - */ - public void setIdleTime( final long idle ) - { - this.maxIdleTime = idle; - } - - /** - * Sets the isEternal attribute of the ElementAttributes object. True means that the item should - * never expire. If can still be removed if it is the least recently used, and you are using the - * LRUMemory cache. it just will not be filtered for expiration by the cache hub. - * - * @param val The new isEternal value - */ - public void setIsEternal( final boolean val ) - { - this.IS_ETERNAL = val; - } - - /** - * Sets the isLateral attribute of the IElementAttributes object - * <p> - * By default this is true. - * @param val The new isLateral value - */ - public void setIsLateral( final boolean val ) - { - this.IS_LATERAL = val; - } - - /** - * Sets the isRemote attribute of the ElementAttributes object - * @param val The new isRemote value - */ - public void setIsRemote( final boolean val ) - { - this.IS_REMOTE = val; - } - - /** - * Sets the isSpool attribute of the IElementAttributes object - * <p> - * By default this is true. - * @param val The new isSpool value - */ - public void setIsSpool( final boolean val ) - { - this.IS_SPOOL = val; - } - - /** - * only for use from test code - */ - public void setLastAccessTime(final long time) - { - this.lastAccessTime = time; - } - - /** - * Sets the LastAccessTime as now of the IElementAttributes object - */ - @Override - public void setLastAccessTimeNow() - { - this.lastAccessTime = System.currentTimeMillis(); - } - - /** - * Sets the maxLife attribute of the IAttributes object. - * - * @param mls The new MaxLifeSeconds value - */ - public void setMaxLife(final long mls) - { - this.maxLife = mls; - } - - /** - * Size in bytes. This is not used except in the admin pages. It will be 0 by default - * and is only updated when the element is serialized. - * - * @param size The new size value - */ - public void setSize( final int size ) - { - this.size = size; - } - - public void setTimeFactorForMilliseconds(final long factor) - { - this.timeFactor = factor; + return ( createTime() + maxLife() * timeFactorForMilliseconds() - now ) / 1000; } /** @@ -435,16 +357,16 @@ public class ElementAttributes { final StringBuilder dump = new StringBuilder(); - dump.append( "[ IS_LATERAL = " ).append( IS_LATERAL ); - dump.append( ", IS_SPOOL = " ).append( IS_SPOOL ); - dump.append( ", IS_REMOTE = " ).append( IS_REMOTE ); - dump.append( ", IS_ETERNAL = " ).append( IS_ETERNAL ); - dump.append( ", MaxLifeSeconds = " ).append( getMaxLife() ); - dump.append( ", IdleTime = " ).append( getIdleTime() ); - dump.append( ", CreateTime = " ).append( getCreateTime() ); - dump.append( ", LastAccessTime = " ).append( getLastAccessTime() ); - dump.append( ", getTimeToLiveSeconds() = " ).append( String.valueOf( getTimeToLiveSeconds() ) ); - dump.append( ", createTime = " ).append( String.valueOf( createTime ) ).append( " ]" ); + dump.append( "[ isLateral = " ).append( isLateral() ); + dump.append( ", isSpool = " ).append( isSpool() ); + dump.append( ", isRemote = " ).append( isRemote() ); + dump.append( ", isEternal = " ).append( isEternal() ); + dump.append( ", MaxLifeSeconds = " ).append( maxLife() ); + dump.append( ", MaxIdleTime = " ).append( maxIdleTime() ); + dump.append( ", CreateTime = " ).append( createTime() ); + dump.append( ", LastAccessTime = " ).append( lastAccessTime() ); + dump.append( ", getTimeToLiveSeconds() = " ).append(getTimeToLiveSeconds()); + dump.append( " ]" ); return dump.toString(); } diff --git a/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/engine/behavior/IElementAttributes.java b/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/engine/behavior/IElementAttributes.java index e6c8ceee..aff279eb 100644 --- a/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/engine/behavior/IElementAttributes.java +++ b/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/engine/behavior/IElementAttributes.java @@ -30,7 +30,7 @@ import org.apache.commons.jcs4.engine.control.event.behavior.IElementEventHandle * element attributes object. It is used to track the life of the object as well as to restrict its * behavior. By default, elements get a clone of the region's attributes. */ -public interface IElementAttributes extends Serializable, Cloneable +public interface IElementAttributes extends Serializable { /** * Adds a ElementEventHandler. Handler's can be registered for multiple events. A registered @@ -46,9 +46,13 @@ public interface IElementAttributes extends Serializable, Cloneable void addElementEventHandlers( List<IElementEventHandler> eventHandlers ); /** - * Clone object + * Gets the elementEventHandlers. + * <p> + * Event handlers are transient. The only events defined are in memory events. All handlers are + * lost if the item goes to disk. + * @return The elementEventHandlers value, null if there are none */ - IElementAttributes clone(); + ArrayList<IElementEventHandler> elementEventHandlers(); /** * Gets the createTime attribute of the IAttributes object. @@ -59,28 +63,19 @@ public interface IElementAttributes extends Serializable, Cloneable * Putting an item in the cache overrides any existing items. * @return The createTime value */ - long getCreateTime(); - - /** - * Gets the elementEventHandlers. - * <p> - * Event handlers are transient. The only events defined are in memory events. All handlers are - * lost if the item goes to disk. - * @return The elementEventHandlers value, null if there are none - */ - ArrayList<IElementEventHandler> getElementEventHandlers(); + long createTime(); /** * Gets the idleTime attribute of the IAttributes object * @return The idleTime value */ - long getIdleTime(); + long maxIdleTime(); /** * This turns off expiration if it is true. * @return The IsEternal value */ - boolean getIsEternal(); + boolean isEternal(); /** * Is this item laterally distributable. Can it be sent to auxiliaries of type lateral. @@ -88,7 +83,7 @@ public interface IElementAttributes extends Serializable, Cloneable * By default this is true. * @return The isLateral value */ - boolean getIsLateral(); + boolean isLateral(); /** * Can this item be sent to the remote cache. @@ -96,7 +91,7 @@ public interface IElementAttributes extends Serializable, Cloneable * By default this is true. * @return The isRemote value */ - boolean getIsRemote(); + boolean isRemote(); /** * Can this item be spooled to disk @@ -104,14 +99,14 @@ public interface IElementAttributes extends Serializable, Cloneable * By default this is true. * @return The spoolable value */ - boolean getIsSpool(); + boolean isSpool(); /** * Gets the LastAccess attribute of the IAttributes object. * * @return The LastAccess value. */ - long getLastAccessTime(); + long lastAccessTime(); /** * Sets the maxLife attribute of the IAttributes object. How many seconds it can live after @@ -121,60 +116,23 @@ public interface IElementAttributes extends Serializable, Cloneable * removed on retrieval, or removed actively if the memory shrinker is turned on. * @return The MaxLifeSeconds value */ - long getMaxLife(); + long maxLife(); /** * Gets the size attribute of the IAttributes object * * @return The size value */ - int getSize(); - - long getTimeFactorForMilliseconds(); + int size(); /** - * Gets the time left to live of the IAttributes object. - * <p> - * This is the (max life + create time) - current time. - * @return The TimeToLiveSeconds value + * Get the time factor to convert durations to milliseconds + * @return The time factor to convert durations to milliseconds */ - long getTimeToLiveSeconds(); - - /** - * Sets the idleTime attribute of the IAttributes object. This is the maximum time the item can - * be idle in the cache, that is not accessed. - * <p> - * If this is exceeded the element will not be returned, instead it will be removed. It will be - * removed on retrieval, or removed actively if the memory shrinker is turned on. - * @param idle The new idleTime value - */ - void setIdleTime( long idle ); - - /** - * Sets the isEternal attribute of the IElementAttributes object - * @param val The new isEternal value - */ - void setIsEternal( boolean val ); + long timeFactorForMilliseconds(); /** * Sets the LastAccessTime as now of the IElementAttributes object */ void setLastAccessTimeNow(); - - /** - * Sets the maxLife attribute of the IAttributes object. - * - * @param mls The new MaxLifeSeconds value - */ - void setMaxLife(long mls); - - /** - * Size in bytes. This is not used except in the admin pages. It will be 0 by default - * and is only updated when the element is serialized. - * - * @param size The new size value - */ - void setSize( int size ); - - void setTimeFactorForMilliseconds(long factor); } diff --git a/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/engine/control/CompositeCache.java b/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/engine/control/CompositeCache.java index 78378940..dbd75c08 100644 --- a/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/engine/control/CompositeCache.java +++ b/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/engine/control/CompositeCache.java @@ -43,6 +43,7 @@ import org.apache.commons.jcs4.access.exception.CacheException; import org.apache.commons.jcs4.access.exception.ObjectNotFoundException; import org.apache.commons.jcs4.auxiliary.AuxiliaryCache; import org.apache.commons.jcs4.engine.CacheStatus; +import org.apache.commons.jcs4.engine.ElementAttributes; import org.apache.commons.jcs4.engine.behavior.ICache; import org.apache.commons.jcs4.engine.behavior.ICacheElement; import org.apache.commons.jcs4.engine.behavior.ICompositeCacheAttributes; @@ -508,7 +509,7 @@ public class CompositeCache<K, V> { if (attr != null) { - return attr.clone(); + return new ElementAttributes(attr); } return null; } @@ -966,7 +967,7 @@ public class CompositeCache<K, V> */ public void handleElementEvent(final ICacheElement<K, V> element, final ElementEventType eventType) { - final ArrayList<IElementEventHandler> eventHandlers = element.getElementAttributes().getElementEventHandlers(); + final ArrayList<IElementEventHandler> eventHandlers = element.getElementAttributes().elementEventHandlers(); if (eventHandlers != null) { log.debug("Element Handlers are registered. Create event type {0}", eventType); @@ -1019,13 +1020,12 @@ public class CompositeCache<K, V> { final IElementAttributes attributes = element.getElementAttributes(); - if (!attributes.getIsEternal()) + if (!attributes.isEternal()) { // Remove if maxLifeSeconds exceeded - final long maxLifeSeconds = attributes.getMaxLife(); - final long createTime = attributes.getCreateTime(); - - final long timeFactorForMilliseconds = attributes.getTimeFactorForMilliseconds(); + final long maxLifeSeconds = attributes.maxLife(); + final long createTime = attributes.createTime(); + final long timeFactorForMilliseconds = attributes.timeFactorForMilliseconds(); if (maxLifeSeconds != -1 && timestamp - createTime > maxLifeSeconds * timeFactorForMilliseconds) { @@ -1034,8 +1034,8 @@ public class CompositeCache<K, V> handleElementEvent(element, eventMaxlife); return true; } - final long idleTime = attributes.getIdleTime(); - final long lastAccessTime = attributes.getLastAccessTime(); + final long idleTime = attributes.maxIdleTime(); + final long lastAccessTime = attributes.lastAccessTime(); // Remove if maxIdleTime exceeded // If you have a 0 size memory cache, then the last access will @@ -1461,7 +1461,7 @@ public class CompositeCache<K, V> public void spoolToDisk(final ICacheElement<K, V> ce) { // if the item is not spoolable, return - if (!ce.getElementAttributes().getIsSpool()) + if (!ce.getElementAttributes().isSpool()) { // there is an event defined for this. handleElementEvent(ce, ElementEventType.SPOOLED_NOT_ALLOWED); @@ -1613,9 +1613,9 @@ public class CompositeCache<K, V> // SEND TO REMOTE STORE case REMOTE_CACHE: log.debug("ce.getElementAttributes().getIsRemote() = {0}", - cacheElement.getElementAttributes()::getIsRemote); + cacheElement.getElementAttributes()::isRemote); - if (cacheElement.getElementAttributes().getIsRemote() && !localOnly) + if (cacheElement.getElementAttributes().isRemote() && !localOnly) { try { @@ -1637,7 +1637,7 @@ public class CompositeCache<K, V> // lateral can't do the checking since it is dependent on the // cache region restrictions log.debug("lateralcache in aux list: cattr {0}", cacheAttr::useLateral); - if (cacheAttr.useLateral() && cacheElement.getElementAttributes().getIsLateral() && !localOnly) + if (cacheAttr.useLateral() && cacheElement.getElementAttributes().isLateral() && !localOnly) { // DISTRIBUTE LATERALLY // Currently always multicast even if the value is @@ -1652,7 +1652,7 @@ public class CompositeCache<K, V> log.debug("diskcache in aux list: cattr {0}", cacheAttr::useDisk); if (cacheAttr.useDisk() && cacheAttr.diskUsagePattern() == DiskUsagePattern.UPDATE - && cacheElement.getElementAttributes().getIsSpool()) + && cacheElement.getElementAttributes().isSpool()) { aux.update(cacheElement); log.debug("updated disk cache for {0}", cacheElement::getKey); diff --git a/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/engine/control/CompositeCacheConfigurator.java b/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/engine/control/CompositeCacheConfigurator.java index 079c3935..e2b8399e 100644 --- a/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/engine/control/CompositeCacheConfigurator.java +++ b/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/engine/control/CompositeCacheConfigurator.java @@ -28,6 +28,7 @@ import org.apache.commons.jcs4.auxiliary.AuxiliaryCacheAttributes; import org.apache.commons.jcs4.auxiliary.AuxiliaryCacheConfigurator; import org.apache.commons.jcs4.auxiliary.AuxiliaryCacheFactory; import org.apache.commons.jcs4.engine.CompositeCacheAttributes; +import org.apache.commons.jcs4.engine.ElementAttributes; import org.apache.commons.jcs4.engine.behavior.ICache; import org.apache.commons.jcs4.engine.behavior.ICompositeCacheAttributes; import org.apache.commons.jcs4.engine.behavior.IElementAttributes; @@ -285,30 +286,29 @@ public class CompositeCacheConfigurator protected IElementAttributes parseElementAttributes( final Properties props, final String regName, final IElementAttributes defaultEAttr, final String regionPrefix ) { - IElementAttributes eAttr; - - final String attrName = regionPrefix + regName + CompositeCacheConfigurator.ELEMENT_ATTRIBUTE_PREFIX; - - // auxFactory was not previously initialized. - // String prefix = regionPrefix + regName + ATTRIBUTE_PREFIX; - eAttr = OptionConverter.instantiateByKey( props, attrName, null ); - if ( eAttr == null ) + final String prefix = regionPrefix + regName + ELEMENT_ATTRIBUTE_PREFIX; + Class<? extends IElementAttributes> elementClass = OptionConverter.findClassByKey(props, prefix); + if (elementClass == null) { - log.info( "No special ElementAttribute class defined for key [{0}], " - + "using default class.", attrName ); - - eAttr = defaultEAttr; + if (defaultEAttr != null) + { + elementClass = defaultEAttr.getClass(); + } + else + { + elementClass = ElementAttributes.class; + } + log.debug("Using default element attributes class for region \"{0}\": {1}", + regName, elementClass.getName()); } - log.debug( "Parsing options for \"{0}\"", attrName ); + log.debug( "Parsing options for \"{0}\"", prefix ); - PropertySetter.setProperties( eAttr, props, attrName + "." ); - // eAttr.setCacheName( regName ); - - log.debug( "End of parsing for \"{0}\"", attrName ); + IElementAttributes eAttr = ConfigurationBuilder.create(elementClass, defaultEAttr) + .fromProperties(props, prefix) + .build(); - // GET CACHE FROM FACTORY WITH ATTRIBUTES - // eAttr.setCacheName( regName ); + log.debug( "End of parsing for \"{0}\"", prefix ); return eAttr; } diff --git a/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/engine/control/CompositeCacheManager.java b/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/engine/control/CompositeCacheManager.java index 7587d767..b139178a 100644 --- a/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/engine/control/CompositeCacheManager.java +++ b/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/engine/control/CompositeCacheManager.java @@ -613,7 +613,7 @@ public class CompositeCacheManager */ public IElementAttributes getDefaultElementAttributes() { - return this.defaultElementAttr.clone(); + return new ElementAttributes(this.defaultElementAttr); } /** diff --git a/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/engine/memory/shrinking/ShrinkerThread.java b/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/engine/memory/shrinking/ShrinkerThread.java index 43437d42..701a1d1c 100644 --- a/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/engine/memory/shrinking/ShrinkerThread.java +++ b/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/engine/memory/shrinking/ShrinkerThread.java @@ -133,7 +133,7 @@ public class ShrinkerThread<K, V> // If the element is not eternal, check if it should be // removed and remove it if so. - if ( !attributes.getIsEternal() ) + if ( !attributes.isEternal() ) { remove = cache.isExpired( cacheElement, now, ElementEventType.EXCEEDED_MAXLIFE_BACKGROUND, @@ -152,7 +152,7 @@ public class ShrinkerThread<K, V> { if ( !spoolLimit || spoolCount < this.maxSpoolPerRun ) { - final long lastAccessTime = attributes.getLastAccessTime(); + final long lastAccessTime = attributes.lastAccessTime(); if ( lastAccessTime + maxMemoryIdleTime < now ) { diff --git a/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/utils/serialization/SerializationConversionUtil.java b/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/utils/serialization/SerializationConversionUtil.java index 41a921e2..b057ab82 100644 --- a/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/utils/serialization/SerializationConversionUtil.java +++ b/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/utils/serialization/SerializationConversionUtil.java @@ -23,8 +23,10 @@ import java.io.IOException; import org.apache.commons.jcs4.engine.CacheElement; import org.apache.commons.jcs4.engine.CacheElementSerialized; +import org.apache.commons.jcs4.engine.ElementAttributes; import org.apache.commons.jcs4.engine.behavior.ICacheElement; import org.apache.commons.jcs4.engine.behavior.ICacheElementSerialized; +import org.apache.commons.jcs4.engine.behavior.IElementAttributes; import org.apache.commons.jcs4.engine.behavior.IElementSerializer; import org.apache.commons.jcs4.log.Log; @@ -115,7 +117,9 @@ public class SerializationConversionUtil serializedValue = elementSerializer.serialize(element.getVal()); // update size in bytes - element.getElementAttributes().setSize(serializedValue.length); + IElementAttributes copy = new ElementAttributes(element.getElementAttributes()) + .withSize(serializedValue.length); + element.setElementAttributes(copy); } catch ( final IOException e ) { diff --git a/commons-jcs4-core/src/test/conf/cache.ccf b/commons-jcs4-core/src/test/conf/cache.ccf index f5fbcb89..cfc3fc5e 100644 --- a/commons-jcs4-core/src/test/conf/cache.ccf +++ b/commons-jcs4-core/src/test/conf/cache.ccf @@ -27,7 +27,7 @@ jcs.default.cacheattributes.ShrinkerIntervalSeconds=60 jcs.default.elementattributes=org.apache.commons.jcs4.engine.ElementAttributes jcs.default.elementattributes.IsEternal=false jcs.default.elementattributes.MaxLife=700 -jcs.default.elementattributes.IdleTime=1800 +jcs.default.elementattributes.MaxIdleTime=1800 jcs.default.elementattributes.IsSpool=true jcs.default.elementattributes.IsRemote=true jcs.default.elementattributes.IsLateral=true diff --git a/commons-jcs4-core/src/test/conf/remote.cache.ccf b/commons-jcs4-core/src/test/conf/remote.cache.ccf index d051dc9a..987091bc 100644 --- a/commons-jcs4-core/src/test/conf/remote.cache.ccf +++ b/commons-jcs4-core/src/test/conf/remote.cache.ccf @@ -37,7 +37,7 @@ jcs.default.cacheattributes.ShrinkerIntervalSeconds=60 jcs.default.elementattributes=org.apache.commons.jcs4.engine.ElementAttributes jcs.default.elementattributes.IsEternal=false jcs.default.elementattributes.MaxLife=7000 -jcs.default.elementattributes.IdleTime=1800 +jcs.default.elementattributes.MaxIdleTime=1800 jcs.default.elementattributes.IsSpool=true jcs.default.elementattributes.IsRemote=true jcs.default.elementattributes.IsLateral=true diff --git a/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/JCSCacheElementRetrievalUnitTest.java b/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/JCSCacheElementRetrievalUnitTest.java index ac6a8ae6..b8da68d0 100644 --- a/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/JCSCacheElementRetrievalUnitTest.java +++ b/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/JCSCacheElementRetrievalUnitTest.java @@ -46,7 +46,7 @@ class JCSCacheElementRetrievalUnitTest final ICacheElement<String, String> elem = jcs.getCacheElement( "test_key" ); assertEquals( "testCache1", elem.getCacheName(), "Name wasn't right" ); - final long diff = now - elem.getElementAttributes().getCreateTime(); + final long diff = now - elem.getElementAttributes().createTime(); assertTrue( diff >= 0, "Create time should have been at or after the call" ); } diff --git a/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/access/CacheAccessUnitTest.java b/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/access/CacheAccessUnitTest.java index 4ad990e8..5bd4028d 100644 --- a/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/access/CacheAccessUnitTest.java +++ b/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/access/CacheAccessUnitTest.java @@ -114,8 +114,8 @@ class CacheAccessUnitTest .withMaxObjects(maxMemorySize); final long maxLife = 9876; - final ElementAttributes attr = new ElementAttributes(); - attr.setMaxLife(maxLife); + final ElementAttributes attr = ElementAttributes.defaults() + .withMaxLife(maxLife); final CacheAccess<String, Integer> access = JCS.getInstance( "testGetMatching_Normal", cattr, attr ); @@ -169,8 +169,8 @@ class CacheAccessUnitTest .withMaxObjects(maxMemorySize); final long maxLife = 9876; - final ElementAttributes attr = new ElementAttributes(); - attr.setMaxLife(maxLife); + final ElementAttributes attr = ElementAttributes.defaults() + .withMaxLife(maxLife); final CacheAccess<String, Integer> access = JCS.getInstance( "testGetMatching_Normal", cattr, attr ); @@ -334,8 +334,8 @@ class CacheAccessUnitTest .withMaxMemoryIdleTimeSeconds(maxIdleTime); final long maxLife = 9876; - final ElementAttributes attr = new ElementAttributes(); - attr.setMaxLife(maxLife); + final ElementAttributes attr = ElementAttributes.defaults() + .withMaxLife(maxLife); final CacheAccess<String, String> access = JCS.getInstance( "testRegionDefinitonWithAttributes", ca, attr ); assertNotNull( access, "We should have an access class" ); @@ -356,13 +356,13 @@ class CacheAccessUnitTest assertNotNull( access, "We should have an access class" ); final long maxLife = 9876; - final ElementAttributes attr = new ElementAttributes(); - attr.setMaxLife(maxLife); + final ElementAttributes attr = ElementAttributes.defaults() + .withMaxLife(maxLife); access.setDefaultElementAttributes( attr ); - assertEquals( attr.getMaxLife(), access.getDefaultElementAttributes() - .getMaxLife(), "Wrong element attributes." ); + assertEquals( attr.maxLife(), access.getDefaultElementAttributes() + .maxLife(), "Wrong element attributes." ); final String key = "mykey"; final String value = "myvalue"; @@ -372,6 +372,6 @@ class CacheAccessUnitTest final ICacheElement<String, String> element = access.getCacheElement( key ); assertEquals( maxLife, element.getElementAttributes() - .getMaxLife(), "Wrong max life. Should have the new value." ); + .maxLife(), "Wrong max life. Should have the new value." ); } } diff --git a/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/access/TestCacheAccess.java b/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/access/TestCacheAccess.java index be7ea21f..7ac9cf36 100644 --- a/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/access/TestCacheAccess.java +++ b/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/access/TestCacheAccess.java @@ -898,7 +898,7 @@ public class TestCacheAccess final long n_start = System.currentTimeMillis(); for ( int n = 0; n < num; n++ ) { - attrp.clone(); + new ElementAttributes(attrp); } final long n_end = System.currentTimeMillis(); p( "---cloned attr " + num + " in " + String.valueOf( n_end - n_start ) + " millis ---" ); diff --git a/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/auxiliary/disk/block/AbstractBlockDiskCacheUnitTest.java b/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/auxiliary/disk/block/AbstractBlockDiskCacheUnitTest.java index 71e7d59f..e5b2e636 100644 --- a/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/auxiliary/disk/block/AbstractBlockDiskCacheUnitTest.java +++ b/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/auxiliary/disk/block/AbstractBlockDiskCacheUnitTest.java @@ -336,8 +336,8 @@ public abstract class AbstractBlockDiskCacheUnitTest{ final CacheElement<GroupAttrName<String>, String> element = new CacheElement<>(cacheName, groupAttrName, "data:" + i); - final ElementAttributes eAttr = new ElementAttributes(); - eAttr.setIsSpool(true); + final ElementAttributes eAttr = ElementAttributes.defaults() + .withIsSpool(true); element.setElementAttributes(eAttr); disk.processUpdate(element); @@ -386,8 +386,8 @@ public abstract class AbstractBlockDiskCacheUnitTest{ final int cnt = 25; for (int i = 0; i < cnt; i++) { - final ElementAttributes eAttr = new ElementAttributes(); - eAttr.setIsSpool(true); + final ElementAttributes eAttr = ElementAttributes.defaults() + .withIsSpool(true); final ICacheElement<String, String> element = new CacheElement<>("testRemove_PartialKey", i + ":key", "data:" + i); element.setElementAttributes(eAttr); @@ -429,8 +429,8 @@ public abstract class AbstractBlockDiskCacheUnitTest{ final int cnt = 25; for (int i = 0; i < cnt; i++) { - final ElementAttributes eAttr = new ElementAttributes(); - eAttr.setIsSpool(true); + final ElementAttributes eAttr = ElementAttributes.defaults() + .withIsSpool(true); final ICacheElement<String, String> element = new CacheElement<>("testRemoveItems", "key:" + i, "data:" + i); element.setElementAttributes(eAttr); disk.processUpdate(element); diff --git a/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/auxiliary/disk/indexed/AbstractIndexDiskCacheUnitTest.java b/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/auxiliary/disk/indexed/AbstractIndexDiskCacheUnitTest.java index cb936df9..af3cc81a 100644 --- a/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/auxiliary/disk/indexed/AbstractIndexDiskCacheUnitTest.java +++ b/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/auxiliary/disk/indexed/AbstractIndexDiskCacheUnitTest.java @@ -704,8 +704,8 @@ public abstract class AbstractIndexDiskCacheUnitTest{ final CacheElement<GroupAttrName<String>, String> element = new CacheElement<>(cacheName, groupAttrName, "data:" + i); - final ElementAttributes eAttr = new ElementAttributes(); - eAttr.setIsSpool(true); + final ElementAttributes eAttr = ElementAttributes.defaults() + .withIsSpool(true); element.setElementAttributes(eAttr); disk.processUpdate(element); @@ -754,8 +754,8 @@ public abstract class AbstractIndexDiskCacheUnitTest{ final int cnt = 25; for (int i = 0; i < cnt; i++) { - final ElementAttributes eAttr = new ElementAttributes(); - eAttr.setIsSpool(true); + final ElementAttributes eAttr = ElementAttributes.defaults() + .withIsSpool(true); final ICacheElement<String, String> element = new CacheElement<>("testRemove_PartialKey", i + ":key", "data:" + i); element.setElementAttributes(eAttr); @@ -828,8 +828,8 @@ public abstract class AbstractIndexDiskCacheUnitTest{ final int cnt = 25; for (int i = 0; i < cnt; i++) { - final ElementAttributes eAttr = new ElementAttributes(); - eAttr.setIsSpool(true); + final ElementAttributes eAttr = ElementAttributes.defaults() + .withIsSpool(true); final ICacheElement<String, String> element = new CacheElement<>("testRemoveItems", "key:" + i, "data:" + i); element.setElementAttributes(eAttr); disk.processUpdate(element); @@ -863,8 +863,8 @@ public abstract class AbstractIndexDiskCacheUnitTest{ final int cnt = 999; for (int i = 0; i < cnt; i++) { - final ElementAttributes eAttr = new ElementAttributes(); - eAttr.setIsSpool(true); + final ElementAttributes eAttr = ElementAttributes.defaults() + .withIsSpool(true); final ICacheElement<String, String> element = new CacheElement<>("testSimplePutAndGet", "key:" + i, "data:" + i); element.setElementAttributes(eAttr); disk.processUpdate(element); diff --git a/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/auxiliary/disk/indexed/IndexedDiskCacheKeyStoreUnitTest.java b/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/auxiliary/disk/indexed/IndexedDiskCacheKeyStoreUnitTest.java index 01fd5636..6380c594 100644 --- a/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/auxiliary/disk/indexed/IndexedDiskCacheKeyStoreUnitTest.java +++ b/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/auxiliary/disk/indexed/IndexedDiskCacheKeyStoreUnitTest.java @@ -56,8 +56,8 @@ class IndexedDiskCacheKeyStoreUnitTest final int cnt = 25; for ( int i = 0; i < cnt; i++ ) { - final ElementAttributes eAttr = new ElementAttributes(); - eAttr.setIsSpool( true ); + final ElementAttributes eAttr = ElementAttributes.defaults() + .withIsSpool(true); final ICacheElement<String, String> element = new CacheElement<>( cattr.getCacheName(), "key:" + i, "data:" + i ); element.setElementAttributes( eAttr ); disk.processUpdate( element ); @@ -65,8 +65,8 @@ class IndexedDiskCacheKeyStoreUnitTest final long preAddRemoveSize = disk.getDataFileSize(); - final ElementAttributes eAttr = new ElementAttributes(); - eAttr.setIsSpool( true ); + final ElementAttributes eAttr = ElementAttributes.defaults() + .withIsSpool(true); final ICacheElement<String, String> elementSetup = new CacheElement<>( cattr.getCacheName(), "key:A", "data:A" ); elementSetup.setElementAttributes( eAttr ); disk.processUpdate( elementSetup ); @@ -115,8 +115,8 @@ class IndexedDiskCacheKeyStoreUnitTest final int cnt = 25; for ( int i = 0; i < cnt; i++ ) { - final ElementAttributes eAttr = new ElementAttributes(); - eAttr.setIsSpool( true ); + final ElementAttributes eAttr = ElementAttributes.defaults() + .withIsSpool(true); final ICacheElement<String, String> element = new CacheElement<>( cattr.getCacheName(), "key:" + i, "data:" + i ); element.setElementAttributes( eAttr ); disk.processUpdate( element ); diff --git a/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/auxiliary/remote/RemoteCacheListenerUnitTest.java b/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/auxiliary/remote/RemoteCacheListenerUnitTest.java index fa8383db..50ba4c51 100644 --- a/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/auxiliary/remote/RemoteCacheListenerUnitTest.java +++ b/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/auxiliary/remote/RemoteCacheListenerUnitTest.java @@ -59,8 +59,8 @@ class RemoteCacheListenerUnitTest final String cacheName = "testName"; final String key = "key"; final String value = "value fdsadf dsafdsa fdsaf dsafdsaf dsafdsaf dsaf dsaf dsaf dsafa dsaf dsaf dsafdsaf"; - final ElementAttributes attr = new ElementAttributes(); - attr.setMaxLife(34); + final ElementAttributes attr = ElementAttributes.defaults() + .withMaxLife(34); final IElementSerializer elementSerializer = new StandardSerializer(); @@ -77,8 +77,8 @@ class RemoteCacheListenerUnitTest assertNotNull( after, "Should have a deserialized object." ); assertEquals( value, after.getVal(), "Values should be the same." ); - assertEquals( attr.getMaxLife(), after - .getElementAttributes().getMaxLife(), "Attributes should be the same." ); + assertEquals( attr.maxLife(), after + .getElementAttributes().maxLife(), "Attributes should be the same." ); assertEquals( key, after.getKey(), "Keys should be the same." ); assertEquals( cacheName, after.getCacheName(), "Cache name should be the same." ); } @@ -103,8 +103,8 @@ class RemoteCacheListenerUnitTest final String cacheName = "testName"; final String key = "key"; final String value = "value fdsadf dsafdsa fdsaf dsafdsaf dsafdsaf dsaf dsaf dsaf dsafa dsaf dsaf dsafdsaf"; - final ElementAttributes attr = new ElementAttributes(); - attr.setMaxLife(34); + final ElementAttributes attr = ElementAttributes.defaults() + .withMaxLife(34); final IElementSerializer elementSerializer = new StandardSerializer(); diff --git a/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/engine/ElementAttributesUtils.java b/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/engine/ElementAttributesUtils.java index f12aeefe..e6671729 100644 --- a/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/engine/ElementAttributesUtils.java +++ b/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/engine/ElementAttributesUtils.java @@ -23,7 +23,8 @@ package org.apache.commons.jcs4.engine; * Allow test access to set last access time without exposing public method */ public class ElementAttributesUtils { - public static void setLastAccessTime(final ElementAttributes ea, final long time) { - ea.setLastAccessTime(time); + public static void setLastAccessTime(final ElementAttributes ea, final long time) + { + ea.atomicLastAccessTime().set(time); } } diff --git a/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/engine/control/event/SimpleEventHandlingUnitTest.java b/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/engine/control/event/SimpleEventHandlingUnitTest.java index 81bd81eb..5443c5cf 100644 --- a/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/engine/control/event/SimpleEventHandlingUnitTest.java +++ b/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/engine/control/event/SimpleEventHandlingUnitTest.java @@ -166,12 +166,12 @@ class SimpleEventHandlingUnitTest throws Exception { final ElementAttributes elem1 = new ElementAttributes(); - final long ctime1 = elem1.getCreateTime(); + final long ctime1 = elem1.createTime(); Thread.sleep(10); - final IElementAttributes elem2 = elem1.clone(); - final long ctime2 = elem2.getCreateTime(); + final IElementAttributes elem2 = new ElementAttributes(elem1); + final long ctime2 = elem2.createTime(); assertFalse( ctime1 == ctime2, "Creation times should be different" ); } @@ -204,7 +204,7 @@ class SimpleEventHandlingUnitTest } // wait a bit for the items to expire - Thread.sleep(attributes.getIdleTime() * 1000 + 100); + Thread.sleep(attributes.maxIdleTime() * 1000 + 100); for ( int i = 0; i < 200; i++ ) { @@ -242,7 +242,7 @@ class SimpleEventHandlingUnitTest } // wait a bit for the items to expire - Thread.sleep(attributes.getMaxLife() * 1000 + 100); + Thread.sleep(attributes.maxLife() * 1000 + 100); for ( int i = 0; i < 200; i++ ) { diff --git a/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/engine/memory/shrinking/ShrinkerThreadUnitTest.java b/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/engine/memory/shrinking/ShrinkerThreadUnitTest.java index 76fea7c1..6f50e06b 100644 --- a/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/engine/memory/shrinking/ShrinkerThreadUnitTest.java +++ b/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/engine/memory/shrinking/ShrinkerThreadUnitTest.java @@ -61,11 +61,10 @@ class ShrinkerThreadUnitTest final String key = "key"; final String value = "value"; - final ICacheElement<String, String> element = new CacheElement<>( "testRegion", key, value ); - final ElementAttributes elementAttr = new ElementAttributes(); - elementAttr.setIsEternal( false ); - elementAttr.setMaxLife(1); - element.setElementAttributes( elementAttr ); + final ICacheElement<String, String> element = new CacheElement<>( "testRegion", key, value, + new ElementAttributes() + .withIsEternal(false) + .withMaxLife(1)); long now = System.currentTimeMillis(); // add two seconds @@ -98,12 +97,11 @@ class ShrinkerThreadUnitTest final String key = "key"; final String value = "value"; - final ICacheElement<String, String> element = new CacheElement<>( "testRegion", key, value ); - final ElementAttributes elementAttr = new ElementAttributes(); - elementAttr.setIsEternal( false ); - elementAttr.setMaxLife(100); - elementAttr.setIdleTime(1); - element.setElementAttributes( elementAttr ); + final ICacheElement<String, String> element = new CacheElement<>( "testRegion", key, value, + new ElementAttributes() + .withIsEternal(false) + .withMaxLife(100) + .withMaxIdleTime(1)); long now = System.currentTimeMillis(); // add two seconds @@ -136,11 +134,10 @@ class ShrinkerThreadUnitTest final String key = "key"; final String value = "value"; - final ICacheElement<String, String> element = new CacheElement<>( "testRegion", key, value ); - final ElementAttributes elementAttr = new ElementAttributes(); - elementAttr.setIsEternal( false ); - elementAttr.setMaxLife(1); - element.setElementAttributes( elementAttr ); + final ICacheElement<String, String> element = new CacheElement<>( "testRegion", key, value, + new ElementAttributes() + .withIsEternal(false) + .withMaxLife(1)); long now = System.currentTimeMillis(); // subtract two seconds @@ -173,12 +170,11 @@ class ShrinkerThreadUnitTest final String key = "key"; final String value = "value"; - final ICacheElement<String, String> element = new CacheElement<>( "testRegion", key, value ); - final ElementAttributes elementAttr = new ElementAttributes(); - elementAttr.setIsEternal( false ); - elementAttr.setMaxLife(100); - elementAttr.setIdleTime(1); - element.setElementAttributes( elementAttr ); + final ICacheElement<String, String> element = new CacheElement<>( "testRegion", key, value, + new ElementAttributes() + .withIsEternal(false) + .withMaxLife(100) + .withMaxIdleTime(1)); long now = System.currentTimeMillis(); // subtract two seconds @@ -218,9 +214,9 @@ class ShrinkerThreadUnitTest final ICacheElement<String, String> element = new CacheElement<>( "testRegion", key, value ); - final ElementAttributes elementAttr = new ElementAttributes(); - elementAttr.setIsEternal( false ); - elementAttr.setMaxLife(1); + final ElementAttributes elementAttr = new ElementAttributes() + .withIsEternal(false) + .withMaxLife(1); element.setElementAttributes( elementAttr ); memory.update( element ); @@ -268,9 +264,9 @@ class ShrinkerThreadUnitTest final ICacheElement<String, String> element = new CacheElement<>( "testRegion", key, value ); - final ElementAttributes elementAttr = new ElementAttributes(); - elementAttr.setIsEternal( false ); - elementAttr.setMaxLife(1); + final ElementAttributes elementAttr = new ElementAttributes() + .withIsEternal(false) + .withMaxLife(1); element.setElementAttributes( elementAttr ); memory.update( element ); @@ -321,10 +317,10 @@ class ShrinkerThreadUnitTest final ICacheElement<String, String> element = new CacheElement<>( "testRegion", key, value ); - final ElementAttributes elementAttr = new ElementAttributes(); + final ElementAttributes elementAttr = new ElementAttributes() + .withIsEternal(false) + .withMaxLife(1); elementAttr.addElementEventHandler( handler ); - elementAttr.setIsEternal( false ); - elementAttr.setMaxLife(1); element.setElementAttributes( elementAttr ); memory.update( element ); diff --git a/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/utils/serialization/SerializationConversionUtilUnitTest.java b/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/utils/serialization/SerializationConversionUtilUnitTest.java index c2fc877e..002f1518 100644 --- a/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/utils/serialization/SerializationConversionUtilUnitTest.java +++ b/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/utils/serialization/SerializationConversionUtilUnitTest.java @@ -54,8 +54,8 @@ class SerializationConversionUtilUnitTest final IElementSerializer elementSerializer = new StandardSerializer(); - final ElementAttributes attr = new ElementAttributes(); - attr.setMaxLife(34); + final ElementAttributes attr = ElementAttributes.defaults() + .withMaxLife(34); final ICacheElement<String, String> before = new CacheElement<>( cacheName, key, value ); before.setElementAttributes( attr ); @@ -76,8 +76,8 @@ class SerializationConversionUtilUnitTest // VERIFY assertNotNull( after, "Should have a deserialized object." ); assertEquals( before.getVal(), after.getVal(), "Values should be the same." ); - assertEquals( before.getElementAttributes().getMaxLife(), after - .getElementAttributes().getMaxLife(), "Attributes should be the same." ); + assertEquals( before.getElementAttributes().maxLife(), after + .getElementAttributes().maxLife(), "Attributes should be the same." ); assertEquals( before.getKey(), after.getKey(), "Keys should be the same." ); assertEquals( before.getCacheName(), after.getCacheName(), "Cache name should be the same." ); } @@ -137,8 +137,8 @@ class SerializationConversionUtilUnitTest final IElementSerializer elementSerializer = null; // new StandardSerializer(); - final ElementAttributes attr = new ElementAttributes(); - attr.setMaxLife(34); + final ElementAttributes attr = ElementAttributes.defaults() + .withMaxLife(34); final ICacheElement<String, String> before = new CacheElement<>( cacheName, key, value ); before.setElementAttributes( attr ); @@ -173,8 +173,8 @@ class SerializationConversionUtilUnitTest final IElementSerializer elementSerializer = new StandardSerializer(); - final ElementAttributes attr = new ElementAttributes(); - attr.setMaxLife(34); + final ElementAttributes attr = ElementAttributes.defaults() + .withMaxLife(34); final ICacheElement<String, String> before = new CacheElement<>( cacheName, key, value ); before.setElementAttributes( attr ); @@ -193,8 +193,8 @@ class SerializationConversionUtilUnitTest // VERIFY assertNotNull( after, "Should have a deserialized object." ); assertEquals( before.getVal(), after.getVal(), "Values should be the same." ); - assertEquals( before.getElementAttributes().getMaxLife(), after - .getElementAttributes().getMaxLife(), "Attributes should be the same." ); + assertEquals( before.getElementAttributes().maxLife(), after + .getElementAttributes().maxLife(), "Attributes should be the same." ); assertEquals( before.getKey(), after.getKey(), "Keys should be the same." ); assertEquals( before.getCacheName(), after.getCacheName(), "Cache name should be the same." ); } diff --git a/commons-jcs4-core/src/test/test-conf/TestHSQLDiskCache.ccf b/commons-jcs4-core/src/test/test-conf/TestHSQLDiskCache.ccf index f71839bc..0340adbf 100644 --- a/commons-jcs4-core/src/test/test-conf/TestHSQLDiskCache.ccf +++ b/commons-jcs4-core/src/test/test-conf/TestHSQLDiskCache.ccf @@ -27,7 +27,7 @@ jcs.default.cacheattributes.ShrinkerIntervalSeconds=60 jcs.default.elementattributes=org.apache.commons.jcs4.engine.ElementAttributes jcs.default.elementattributes.IsEternal=false jcs.default.elementattributes.MaxLife=700 -jcs.default.elementattributes.IdleTime=1800 +jcs.default.elementattributes.MaxIdleTime=1800 jcs.default.elementattributes.IsSpool=true jcs.default.elementattributes.IsRemote=true jcs.default.elementattributes.IsLateral=true diff --git a/commons-jcs4-core/src/test/test-conf/TestHSQLDiskCacheConcurrent.ccf b/commons-jcs4-core/src/test/test-conf/TestHSQLDiskCacheConcurrent.ccf index 9f5efcc6..f022d427 100644 --- a/commons-jcs4-core/src/test/test-conf/TestHSQLDiskCacheConcurrent.ccf +++ b/commons-jcs4-core/src/test/test-conf/TestHSQLDiskCacheConcurrent.ccf @@ -27,7 +27,7 @@ jcs.default.cacheattributes.ShrinkerIntervalSeconds=60 jcs.default.elementattributes=org.apache.commons.jcs4.engine.ElementAttributes jcs.default.elementattributes.IsEternal=false jcs.default.elementattributes.MaxLife=700 -jcs.default.elementattributes.IdleTime=1800 +jcs.default.elementattributes.MaxIdleTime=1800 jcs.default.elementattributes.IsSpool=true jcs.default.elementattributes.IsRemote=true jcs.default.elementattributes.IsLateral=true diff --git a/commons-jcs4-core/src/test/test-conf/TestJDBCDiskCache.ccf b/commons-jcs4-core/src/test/test-conf/TestJDBCDiskCache.ccf index 42d3d6e7..235de35b 100644 --- a/commons-jcs4-core/src/test/test-conf/TestJDBCDiskCache.ccf +++ b/commons-jcs4-core/src/test/test-conf/TestJDBCDiskCache.ccf @@ -27,7 +27,7 @@ jcs.default.cacheattributes.ShrinkerIntervalSeconds=60 jcs.default.elementattributes=org.apache.commons.jcs4.engine.ElementAttributes jcs.default.elementattributes.IsEternal=false jcs.default.elementattributes.MaxLife=700 -jcs.default.elementattributes.IdleTime=1800 +jcs.default.elementattributes.MaxIdleTime=1800 jcs.default.elementattributes.IsSpool=true jcs.default.elementattributes.IsRemote=true jcs.default.elementattributes.IsLateral=true diff --git a/commons-jcs4-core/src/test/test-conf/TestJDBCDiskCacheRemoval.ccf b/commons-jcs4-core/src/test/test-conf/TestJDBCDiskCacheRemoval.ccf index 61a86e30..44709ac8 100644 --- a/commons-jcs4-core/src/test/test-conf/TestJDBCDiskCacheRemoval.ccf +++ b/commons-jcs4-core/src/test/test-conf/TestJDBCDiskCacheRemoval.ccf @@ -27,7 +27,7 @@ jcs.default.cacheattributes.ShrinkerIntervalSeconds=60 jcs.default.elementattributes=org.apache.commons.jcs4.engine.ElementAttributes jcs.default.elementattributes.IsEternal=false jcs.default.elementattributes.MaxLife=700 -jcs.default.elementattributes.IdleTime=1800 +jcs.default.elementattributes.MaxIdleTime=1800 jcs.default.elementattributes.IsSpool=true jcs.default.elementattributes.IsRemote=true jcs.default.elementattributes.IsLateral=true diff --git a/commons-jcs4-core/src/test/test-conf/TestJDBCDiskCacheSharedPool.ccf b/commons-jcs4-core/src/test/test-conf/TestJDBCDiskCacheSharedPool.ccf index 8b506c2d..c5b633e1 100644 --- a/commons-jcs4-core/src/test/test-conf/TestJDBCDiskCacheSharedPool.ccf +++ b/commons-jcs4-core/src/test/test-conf/TestJDBCDiskCacheSharedPool.ccf @@ -27,7 +27,7 @@ jcs.default.cacheattributes.ShrinkerIntervalSeconds=60 jcs.default.elementattributes=org.apache.commons.jcs4.engine.ElementAttributes jcs.default.elementattributes.IsEternal=false jcs.default.elementattributes.MaxLife=700 -jcs.default.elementattributes.IdleTime=1800 +jcs.default.elementattributes.MaxIdleTime=1800 jcs.default.elementattributes.IsSpool=true jcs.default.elementattributes.IsRemote=true jcs.default.elementattributes.IsLateral=true diff --git a/commons-jcs4-core/src/test/test-conf/TestJDBCDiskCacheShrink.ccf b/commons-jcs4-core/src/test/test-conf/TestJDBCDiskCacheShrink.ccf index 4e8b15b8..9dcaf7e3 100644 --- a/commons-jcs4-core/src/test/test-conf/TestJDBCDiskCacheShrink.ccf +++ b/commons-jcs4-core/src/test/test-conf/TestJDBCDiskCacheShrink.ccf @@ -27,7 +27,7 @@ jcs.default.cacheattributes.ShrinkerIntervalSeconds=60 jcs.default.elementattributes=org.apache.commons.jcs4.engine.ElementAttributes jcs.default.elementattributes.IsEternal=false jcs.default.elementattributes.MaxLife=700 -jcs.default.elementattributes.IdleTime=1800 +jcs.default.elementattributes.MaxIdleTime=1800 jcs.default.elementattributes.IsSpool=true jcs.default.elementattributes.IsRemote=true jcs.default.elementattributes.IsLateral=true diff --git a/commons-jcs4-core/src/test/test-conf/TestMRUCache.ccf b/commons-jcs4-core/src/test/test-conf/TestMRUCache.ccf index b6bb8271..617af6fc 100644 --- a/commons-jcs4-core/src/test/test-conf/TestMRUCache.ccf +++ b/commons-jcs4-core/src/test/test-conf/TestMRUCache.ccf @@ -27,7 +27,7 @@ jcs.default.cacheattributes.ShrinkerIntervalSeconds=1 jcs.default.elementattributes=org.apache.commons.jcs4.engine.ElementAttributes jcs.default.elementattributes.IsEternal=false jcs.default.elementattributes.MaxLife=600 -jcs.default.elementattributes.IdleTime=1800 +jcs.default.elementattributes.MaxIdleTime=1800 jcs.default.elementattributes.IsSpool=true jcs.default.elementattributes.IsRemote=true jcs.default.elementattributes.IsLateral=true diff --git a/commons-jcs4-core/src/test/test-conf/TestMySQLDiskCache.ccf b/commons-jcs4-core/src/test/test-conf/TestMySQLDiskCache.ccf index 027b6c77..a236f0ba 100644 --- a/commons-jcs4-core/src/test/test-conf/TestMySQLDiskCache.ccf +++ b/commons-jcs4-core/src/test/test-conf/TestMySQLDiskCache.ccf @@ -29,7 +29,7 @@ jcs.default.cacheattributes.ShrinkerIntervalSeconds=60 jcs.default.elementattributes=org.apache.commons.jcs4.engine.ElementAttributes jcs.default.elementattributes.IsEternal=false jcs.default.elementattributes.MaxLife=700 -jcs.default.elementattributes.IdleTime=1800 +jcs.default.elementattributes.MaxIdleTime=1800 jcs.default.elementattributes.IsSpool=true jcs.default.elementattributes.IsRemote=true jcs.default.elementattributes.IsLateral=true diff --git a/commons-jcs4-core/src/test/test-conf/TestRemoteClient.ccf b/commons-jcs4-core/src/test/test-conf/TestRemoteClient.ccf index 002e1c04..6ec3e7c6 100644 --- a/commons-jcs4-core/src/test/test-conf/TestRemoteClient.ccf +++ b/commons-jcs4-core/src/test/test-conf/TestRemoteClient.ccf @@ -27,7 +27,7 @@ jcs.default.cacheattributes.ShrinkerIntervalSeconds=60 jcs.default.elementattributes=org.apache.commons.jcs4.engine.ElementAttributes jcs.default.elementattributes.IsEternal=false jcs.default.elementattributes.MaxLife=700 -jcs.default.elementattributes.IdleTime=1800 +jcs.default.elementattributes.MaxIdleTime=1800 jcs.default.elementattributes.IsSpool=true jcs.default.elementattributes.IsRemote=true jcs.default.elementattributes.IsLateral=true diff --git a/commons-jcs4-core/src/test/test-conf/TestRemoteHttpCache.ccf b/commons-jcs4-core/src/test/test-conf/TestRemoteHttpCache.ccf index 496c4391..c14de962 100644 --- a/commons-jcs4-core/src/test/test-conf/TestRemoteHttpCache.ccf +++ b/commons-jcs4-core/src/test/test-conf/TestRemoteHttpCache.ccf @@ -27,7 +27,7 @@ jcs.default.cacheattributes.ShrinkerIntervalSeconds=60 jcs.default.elementattributes=org.apache.commons.jcs4.engine.ElementAttributes jcs.default.elementattributes.IsEternal=false jcs.default.elementattributes.MaxLife=700 -jcs.default.elementattributes.IdleTime=1800 +jcs.default.elementattributes.MaxIdleTime=1800 jcs.default.elementattributes.IsSpool=true jcs.default.elementattributes.IsRemote=true jcs.default.elementattributes.IsLateral=true diff --git a/commons-jcs4-core/src/test/test-conf/TestRemoteServer.ccf b/commons-jcs4-core/src/test/test-conf/TestRemoteServer.ccf index ad2a3785..22b8db6b 100644 --- a/commons-jcs4-core/src/test/test-conf/TestRemoteServer.ccf +++ b/commons-jcs4-core/src/test/test-conf/TestRemoteServer.ccf @@ -38,7 +38,7 @@ jcs.default.cacheattributes.ShrinkerIntervalSeconds=60 jcs.default.elementattributes=org.apache.commons.jcs4.engine.ElementAttributes jcs.default.elementattributes.IsEternal=false jcs.default.elementattributes.MaxLife=7000 -jcs.default.elementattributes.IdleTime=1800 +jcs.default.elementattributes.MaxIdleTime=1800 jcs.default.elementattributes.IsSpool=true jcs.default.elementattributes.IsRemote=true jcs.default.elementattributes.IsLateral=true diff --git a/commons-jcs4-core/src/test/test-conf/TestSimpleEventHandling.ccf b/commons-jcs4-core/src/test/test-conf/TestSimpleEventHandling.ccf index b8eef784..5f2aa90e 100644 --- a/commons-jcs4-core/src/test/test-conf/TestSimpleEventHandling.ccf +++ b/commons-jcs4-core/src/test/test-conf/TestSimpleEventHandling.ccf @@ -55,7 +55,7 @@ jcs.region.Idletime.cacheattributes.MaxObjects=200 jcs.region.Idletime.cacheattributes.MemoryCacheName=org.apache.commons.jcs4.engine.memory.lru.LRUMemoryCache jcs.region.Idletime.elementattributes.IsEternal=false jcs.region.Idletime.elementattributes.MaxLife=300 -jcs.region.Idletime.elementattributes.IdleTime=1 +jcs.region.Idletime.elementattributes.MaxIdleTime=1 # #### AUXILIARY CACHES # Indexed Disk Cache diff --git a/commons-jcs4-core/src/test/test-conf/TestSoftReferenceCache.ccf b/commons-jcs4-core/src/test/test-conf/TestSoftReferenceCache.ccf index 2d7995e3..7b4f1d85 100644 --- a/commons-jcs4-core/src/test/test-conf/TestSoftReferenceCache.ccf +++ b/commons-jcs4-core/src/test/test-conf/TestSoftReferenceCache.ccf @@ -25,7 +25,7 @@ jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600 jcs.default.elementattributes=org.apache.commons.jcs4.engine.ElementAttributes jcs.default.elementattributes.IsEternal=false jcs.default.elementattributes.MaxLife=600 -jcs.default.elementattributes.IdleTime=1800 +jcs.default.elementattributes.MaxIdleTime=1800 jcs.default.elementattributes.IsSpool=true jcs.default.elementattributes.IsRemote=true jcs.default.elementattributes.IsLateral=true diff --git a/commons-jcs4-core/src/test/test-conf/TestZeroSizeCache.ccf b/commons-jcs4-core/src/test/test-conf/TestZeroSizeCache.ccf index 92c724cb..44b9dd86 100644 --- a/commons-jcs4-core/src/test/test-conf/TestZeroSizeCache.ccf +++ b/commons-jcs4-core/src/test/test-conf/TestZeroSizeCache.ccf @@ -27,7 +27,7 @@ jcs.default.cacheattributes.ShrinkerIntervalSeconds=1 jcs.default.elementattributes=org.apache.commons.jcs4.engine.ElementAttributes jcs.default.elementattributes.IsEternal=false jcs.default.elementattributes.MaxLife=600 -jcs.default.elementattributes.IdleTime=1800 +jcs.default.elementattributes.MaxIdleTime=1800 jcs.default.elementattributes.IsSpool=true jcs.default.elementattributes.IsRemote=true jcs.default.elementattributes.IsLateral=true diff --git a/commons-jcs4-jcache/src/main/java/org/apache/commons/jcs4/jcache/JCSCache.java b/commons-jcs4-jcache/src/main/java/org/apache/commons/jcs4/jcache/JCSCache.java index 5a692b90..e8327ffe 100644 --- a/commons-jcs4-jcache/src/main/java/org/apache/commons/jcs4/jcache/JCSCache.java +++ b/commons-jcs4-jcache/src/main/java/org/apache/commons/jcs4/jcache/JCSCache.java @@ -323,7 +323,7 @@ public class JCSCache<K, V> implements Cache<K, V> { forceExpires(key); } - else if (expiryForAccess != null && (!elt.getElementAttributes().getIsEternal() || !expiryForAccess.isEternal())) + else if (expiryForAccess != null && (!elt.getElementAttributes().isEternal() || !expiryForAccess.isEternal())) { try { @@ -388,11 +388,7 @@ public class JCSCache<K, V> implements Cache<K, V> final Duration duration = update ? expiryPolicy.getExpiryForUpdate() : expiryPolicy.getExpiryForCreation(); if (isNotZero(duration)) { - final IElementAttributes clone = delegate.getElementAttributes().clone(); - if (ElementAttributes.class.isInstance(clone)) - { - ElementAttributes.class.cast(clone).setCreateTime(); - } + final IElementAttributes clone = new ElementAttributes(delegate.getElementAttributes()); final ICacheElement<K, V> element = updateElement(key, v, duration, clone); try { @@ -703,27 +699,31 @@ public class JCSCache<K, V> implements Cache<K, V> final K jcsKey = storeByValue ? copy(serializer, manager.getClassLoader(), key) : key; final ICacheElement<K, V> element = updateElement( // reuse it to create basic structure jcsKey, value, created ? null : duration, - oldElt != null ? oldElt.getElementAttributes() : delegate.getElementAttributes().clone()); + oldElt != null ? oldElt.getElementAttributes() : new ElementAttributes(delegate.getElementAttributes())); if (created && duration != null) { // set maxLife - final IElementAttributes copy = element.getElementAttributes(); - copy.setTimeFactorForMilliseconds(1); + final long timeFactorForMilliseconds = 1; final boolean eternal = duration.isEternal(); - copy.setIsEternal(eternal); - if (ElementAttributes.class.isInstance(copy)) { - ElementAttributes.class.cast(copy).setCreateTime(); - } + long maxIdleTime = element.getElementAttributes().maxIdleTime(); + long maxLife = element.getElementAttributes().maxLife(); if (!eternal) { - copy.setIsEternal(false); if (duration == expiryPolicy.getExpiryForAccess()) { - element.getElementAttributes().setIdleTime(duration.getTimeUnit().toMillis(duration.getDurationAmount())); + maxIdleTime = duration.getTimeUnit().toMillis(duration.getDurationAmount()); } else { - element.getElementAttributes().setMaxLife(duration.getTimeUnit().toMillis(duration.getDurationAmount())); + maxLife = duration.getTimeUnit().toMillis(duration.getDurationAmount()); } } + IElementAttributes copy = new ElementAttributes( + element.getElementAttributes().isSpool(), + element.getElementAttributes().isLateral(), + element.getElementAttributes().isRemote(), + eternal, + maxLife, + maxIdleTime, + timeFactorForMilliseconds); element.setElementAttributes(copy); } writer.write(new JCSEntry<>(jcsKey, value)); @@ -917,7 +917,7 @@ public class JCSCache<K, V> implements Cache<K, V> if (value != null) { final Duration expiryForAccess = expiryPolicy.getExpiryForAccess(); - if (expiryForAccess != null && (!elt.getElementAttributes().getIsEternal() || !expiryForAccess.isEternal())) + if (expiryForAccess != null && (!elt.getElementAttributes().isEternal() || !expiryForAccess.isEternal())) { try { @@ -970,19 +970,21 @@ public class JCSCache<K, V> implements Cache<K, V> private ICacheElement<K, V> updateElement(final K key, final V v, final Duration duration, final IElementAttributes attrs) { - final ICacheElement<K, V> element = new CacheElement<>(name, key, v); + final ICacheElement<K, V> element = new CacheElement<>(name, key, v, attrs); if (duration != null) { - attrs.setTimeFactorForMilliseconds(1); final boolean eternal = duration.isEternal(); - attrs.setIsEternal(eternal); - if (!eternal) - { - attrs.setLastAccessTimeNow(); - } // MaxLife = -1 to use IdleTime excepted if jcache.ccf asked for something else + IElementAttributes copy = new ElementAttributes( + attrs.isSpool(), + attrs.isLateral(), + attrs.isRemote(), + eternal, + attrs.maxLife(), + attrs.maxIdleTime(), + 1); + element.setElementAttributes(copy); } - element.setElementAttributes(attrs); return element; } } diff --git a/commons-jcs4-jcache/src/main/java/org/apache/commons/jcs4/jcache/JCSCachingManager.java b/commons-jcs4-jcache/src/main/java/org/apache/commons/jcs4/jcache/JCSCachingManager.java index 023afb6a..6980a43a 100644 --- a/commons-jcs4-jcache/src/main/java/org/apache/commons/jcs4/jcache/JCSCachingManager.java +++ b/commons-jcs4-jcache/src/main/java/org/apache/commons/jcs4/jcache/JCSCachingManager.java @@ -87,7 +87,7 @@ public class JCSCachingManager implements CacheManager jcs.default.elementattributes=org.apache.commons.jcs4.engine.ElementAttributes jcs.default.elementattributes.IsEternal=false jcs.default.elementattributes.MaxLife=700 - jcs.default.elementattributes.IdleTime=1800 + jcs.default.elementattributes.MaxIdleTime=1800 jcs.default.elementattributes.IsSpool=true jcs.default.elementattributes.IsRemote=true jcs.default.elementattributes.IsLateral=true diff --git a/xdocs/ElementAttributes.xml b/xdocs/ElementAttributes.xml index 3d101d7b..8332c53f 100644 --- a/xdocs/ElementAttributes.xml +++ b/xdocs/ElementAttributes.xml @@ -59,7 +59,7 @@ jcs.default.cacheattributes.ShrinkerIntervalSeconds=60 jcs.default.elementattributes=org.apache.commons.jcs4.engine.ElementAttributes jcs.default.elementattributes.IsEternal=false jcs.default.elementattributes.MaxLife=700 -jcs.default.elementattributes.IdleTime=1800 +jcs.default.elementattributes.MaxIdleTime=1800 jcs.default.elementattributes.IsSpool=true jcs.default.elementattributes.IsRemote=true jcs.default.elementattributes.IsLateral=true diff --git a/xdocs/IndexedDiskAuxCache.xml b/xdocs/IndexedDiskAuxCache.xml index 7fd61f41..75ebfa17 100644 --- a/xdocs/IndexedDiskAuxCache.xml +++ b/xdocs/IndexedDiskAuxCache.xml @@ -258,7 +258,7 @@ jcs.default.cacheattributes.ShrinkerIntervalSeconds=60 jcs.default.elementattributes=org.apache.commons.jcs4.engine.ElementAttributes jcs.default.elementattributes.IsEternal=false jcs.default.elementattributes.MaxLife=700 -jcs.default.elementattributes.IdleTime=1800 +jcs.default.elementattributes.MaxIdleTime=1800 jcs.default.elementattributes.IsSpool=true jcs.default.elementattributes.IsRemote=true jcs.default.elementattributes.IsLateral=true diff --git a/xdocs/JDBCDiskCache.xml b/xdocs/JDBCDiskCache.xml index 2c0ed021..bb972a28 100644 --- a/xdocs/JDBCDiskCache.xml +++ b/xdocs/JDBCDiskCache.xml @@ -47,7 +47,7 @@ jcs.default.cacheattributes.ShrinkerIntervalSeconds=60 jcs.default.elementattributes=org.apache.commons.jcs4.engine.ElementAttributes jcs.default.elementattributes.IsEternal=false jcs.default.elementattributes.MaxLife=14400 -jcs.default.elementattributes.IdleTime=14400 +jcs.default.elementattributes.MaxIdleTime=14400 jcs.default.elementattributes.IsSpool=true jcs.default.elementattributes.IsRemote=true jcs.default.elementattributes.IsLateral=true @@ -104,7 +104,7 @@ jcs.default.cacheattributes.ShrinkerIntervalSeconds=60 jcs.default.elementattributes=org.apache.commons.jcs4.engine.ElementAttributes jcs.default.elementattributes.IsEternal=false jcs.default.elementattributes.MaxLife=700 -jcs.default.elementattributes.IdleTime=1800 +jcs.default.elementattributes.MaxIdleTime=1800 jcs.default.elementattributes.IsSpool=true jcs.default.elementattributes.IsRemote=true jcs.default.elementattributes.IsLateral=true @@ -178,7 +178,7 @@ jcs.default.cacheattributes.ShrinkerIntervalSeconds=60 jcs.default.elementattributes=org.apache.commons.jcs4.engine.ElementAttributes jcs.default.elementattributes.IsEternal=false jcs.default.elementattributes.MaxLife=700 -jcs.default.elementattributes.IdleTime=1800 +jcs.default.elementattributes.MaxIdleTime=1800 jcs.default.elementattributes.IsSpool=true jcs.default.elementattributes.IsRemote=true jcs.default.elementattributes.IsLateral=true diff --git a/xdocs/UpgradingFrom3x.xml b/xdocs/UpgradingFrom3x.xml index 61fa52bd..d18d1bf2 100644 --- a/xdocs/UpgradingFrom3x.xml +++ b/xdocs/UpgradingFrom3x.xml @@ -115,15 +115,20 @@ jcs.default.cacheattributes=org.apache.commons.jcs4.engine.CompositeCacheAttribu <th>New Property Name</th> </tr> <tr> - <td>Region configuration (CompositeCacheAttributes)</td> + <td>Region configuration (cacheattributes)</td> <td>DiskUsagePatternName</td> <td>DiskUsagePattern</td> </tr> + <tr> + <td>Element configuration (elementattributes)</td> + <td>IdleTime</td> + <td>MaxIdleTime</td> + </tr> </table> </p> <p> - The documentation in the code always stated that region configurations inherit - values from the default region settings. This, however, was never implemented. + The documentation in the code always stated that region and element configurations + inherit values from the default region attributes. This, however, was never implemented. Note that the behavior has been fixed in JCS 4.0.0. This may have implications for your existing configurations. On the other hand, it makes the configuration much shorter. diff --git a/xdocs/UsingJCSBasicWeb.xml b/xdocs/UsingJCSBasicWeb.xml index 14eaee91..c44507de 100644 --- a/xdocs/UsingJCSBasicWeb.xml +++ b/xdocs/UsingJCSBasicWeb.xml @@ -369,7 +369,7 @@ jcs.default.cacheattributes.MemoryCacheName= org.apache.commons.jcs4.engine.memory.lru.LRUMemoryCache jcs.default.elementattributes.IsEternal=false jcs.default.elementattributes.MaxLife=3600 -jcs.default.elementattributes.IdleTime=1800 +jcs.default.elementattributes.MaxIdleTime=1800 jcs.default.elementattributes.IsSpool=true jcs.default.elementattributes.IsRemote=true jcs.default.elementattributes.IsLateral=true @@ -386,7 +386,7 @@ jcs.region.bookCache.cacheattributes.MemoryCacheName= org.apache.commons.jcs4.engine.memory.lru.LRUMemoryCache jcs.region.bookCache.elementattributes.IsEternal=false jcs.region.bookCache.elementattributes.MaxLife=7200 -jcs.region.bookCache.elementattributes.IdleTime=1800 +jcs.region.bookCache.elementattributes.MaxIdleTime=1800 jcs.region.bookCache.elementattributes.IsSpool=true jcs.region.bookCache.elementattributes.IsRemote=true jcs.region.bookCache.elementattributes.IsLateral=true diff --git a/xdocs/getting_started/intro.xml b/xdocs/getting_started/intro.xml index 9b7ebacc..70ad69ab 100644 --- a/xdocs/getting_started/intro.xml +++ b/xdocs/getting_started/intro.xml @@ -157,7 +157,7 @@ jcs.default.cacheattributes.ShrinkerIntervalSeconds=60 jcs.default.elementattributes=org.apache.commons.jcs4.engine.ElementAttributes jcs.default.elementattributes.IsEternal=false jcs.default.elementattributes.MaxLife=21600 -jcs.default.elementattributes.IdleTime=1800 +jcs.default.elementattributes.MaxIdleTime=1800 jcs.default.elementattributes.IsSpool=true jcs.default.elementattributes.IsRemote=true jcs.default.elementattributes.IsLateral=true
