From bc5c175a229b6576886ecc7f23e49f4cc2c6d695 Mon Sep 17 00:00:00 2001 From: wuwen Date: Fri, 18 Nov 2016 15:42:46 +0800 Subject: [PATCH] refactor cache decorator --- .../apache/ibatis/cache/CacheDecorator.java | 72 +++++++++++++++++++ .../cache/decorators/BlockingCache.java | 29 ++------ .../ibatis/cache/decorators/FifoCache.java | 28 +++----- .../ibatis/cache/decorators/LoggingCache.java | 39 ++-------- .../ibatis/cache/decorators/LruCache.java | 28 +++----- .../cache/decorators/ScheduledCache.java | 27 +++---- .../cache/decorators/SerializedCache.java | 37 +++------- .../ibatis/cache/decorators/SoftCache.java | 25 +++---- .../cache/decorators/SynchronizedCache.java | 25 +++---- .../cache/decorators/TransactionalCache.java | 28 +++----- .../ibatis/cache/decorators/WeakCache.java | 25 +++---- .../ibatis/cache/CacheDecoratorTest.java | 60 ++++++++++++++++ .../ibatis/mapping/CacheBuilderTest.java | 20 +----- .../ibatis/submitted/cache/CacheTest.java | 19 +---- .../submitted/global_variables/BaseTest.java | 19 +---- .../SupportClasses.java | 19 +---- 16 files changed, 234 insertions(+), 266 deletions(-) create mode 100644 src/main/java/org/apache/ibatis/cache/CacheDecorator.java create mode 100644 src/test/java/org/apache/ibatis/cache/CacheDecoratorTest.java diff --git a/src/main/java/org/apache/ibatis/cache/CacheDecorator.java b/src/main/java/org/apache/ibatis/cache/CacheDecorator.java new file mode 100644 index 00000000000..d7f4149a25f --- /dev/null +++ b/src/main/java/org/apache/ibatis/cache/CacheDecorator.java @@ -0,0 +1,72 @@ +/* + * Copyright 2009-2024 the original author or authors. + * + * Licensed 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. + */ +package org.apache.ibatis.cache; + +import java.util.concurrent.locks.ReadWriteLock; + +/** + * abstract cache decorator. + * + * @author wuwen + */ +public abstract class CacheDecorator implements Cache { + + private final Cache delegate; + + public CacheDecorator(Cache cache) { + this.delegate = cache; + } + + @Override + public String getId() { + return delegate.getId(); + } + + @Override + public void putObject(Object key, Object value) { + delegate.putObject(key, value); + } + + @Override + public Object getObject(Object key) { + return delegate.getObject(key); + } + + @Override + public Object removeObject(Object key) { + return delegate.removeObject(key); + } + + @Override + public void clear() { + delegate.clear(); + } + + @Override + public int getSize() { + return delegate.getSize(); + } + + @Override + public ReadWriteLock getReadWriteLock() { + return delegate.getReadWriteLock(); + } + + public Cache getDelegate() { + return delegate; + } + +} diff --git a/src/main/java/org/apache/ibatis/cache/decorators/BlockingCache.java b/src/main/java/org/apache/ibatis/cache/decorators/BlockingCache.java index b70fc0c61f8..0002c3323ec 100644 --- a/src/main/java/org/apache/ibatis/cache/decorators/BlockingCache.java +++ b/src/main/java/org/apache/ibatis/cache/decorators/BlockingCache.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2023 the original author or authors. + * Copyright 2009-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import java.util.concurrent.TimeUnit; import org.apache.ibatis.cache.Cache; +import org.apache.ibatis.cache.CacheDecorator; import org.apache.ibatis.cache.CacheException; /** @@ -34,31 +35,20 @@ * * @author Eduardo Macarron */ -public class BlockingCache implements Cache { +public class BlockingCache extends CacheDecorator { private long timeout; - private final Cache delegate; private final ConcurrentHashMap locks; public BlockingCache(Cache delegate) { - this.delegate = delegate; + super(delegate); this.locks = new ConcurrentHashMap<>(); } - @Override - public String getId() { - return delegate.getId(); - } - - @Override - public int getSize() { - return delegate.getSize(); - } - @Override public void putObject(Object key, Object value) { try { - delegate.putObject(key, value); + super.putObject(key, value); } finally { releaseLock(key); } @@ -67,7 +57,7 @@ public void putObject(Object key, Object value) { @Override public Object getObject(Object key) { acquireLock(key); - Object value = delegate.getObject(key); + Object value = super.getObject(key); if (value != null) { releaseLock(key); } @@ -81,11 +71,6 @@ public Object removeObject(Object key) { return null; } - @Override - public void clear() { - delegate.clear(); - } - private void acquireLock(Object key) { CountDownLatch newLatch = new CountDownLatch(1); while (true) { @@ -98,7 +83,7 @@ private void acquireLock(Object key) { boolean acquired = latch.await(timeout, TimeUnit.MILLISECONDS); if (!acquired) { throw new CacheException( - "Couldn't get a lock in " + timeout + " for the key " + key + " at the cache " + delegate.getId()); + "Couldn't get a lock in " + timeout + " for the key " + key + " at the cache " + super.getId()); } } else { latch.await(); diff --git a/src/main/java/org/apache/ibatis/cache/decorators/FifoCache.java b/src/main/java/org/apache/ibatis/cache/decorators/FifoCache.java index 9fc9c2f0f4c..28ddebaf14d 100644 --- a/src/main/java/org/apache/ibatis/cache/decorators/FifoCache.java +++ b/src/main/java/org/apache/ibatis/cache/decorators/FifoCache.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2023 the original author or authors. + * Copyright 2009-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,34 +19,24 @@ import java.util.LinkedList; import org.apache.ibatis.cache.Cache; +import org.apache.ibatis.cache.CacheDecorator; /** * FIFO (first in, first out) cache decorator. * * @author Clinton Begin */ -public class FifoCache implements Cache { +public class FifoCache extends CacheDecorator { - private final Cache delegate; private final Deque keyList; private int size; public FifoCache(Cache delegate) { - this.delegate = delegate; + super(delegate); this.keyList = new LinkedList<>(); this.size = 1024; } - @Override - public String getId() { - return delegate.getId(); - } - - @Override - public int getSize() { - return delegate.getSize(); - } - public void setSize(int size) { this.size = size; } @@ -54,23 +44,23 @@ public void setSize(int size) { @Override public void putObject(Object key, Object value) { cycleKeyList(key); - delegate.putObject(key, value); + super.putObject(key, value); } @Override public Object getObject(Object key) { - return delegate.getObject(key); + return super.getObject(key); } @Override public Object removeObject(Object key) { keyList.remove(key); - return delegate.removeObject(key); + return super.removeObject(key); } @Override public void clear() { - delegate.clear(); + super.clear(); keyList.clear(); } @@ -78,7 +68,7 @@ private void cycleKeyList(Object key) { keyList.addLast(key); if (keyList.size() > size) { Object oldestKey = keyList.removeFirst(); - delegate.removeObject(oldestKey); + super.removeObject(oldestKey); } } diff --git a/src/main/java/org/apache/ibatis/cache/decorators/LoggingCache.java b/src/main/java/org/apache/ibatis/cache/decorators/LoggingCache.java index 6ff00cb2e06..cf7e4ff25c5 100644 --- a/src/main/java/org/apache/ibatis/cache/decorators/LoggingCache.java +++ b/src/main/java/org/apache/ibatis/cache/decorators/LoggingCache.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2023 the original author or authors. + * Copyright 2009-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,43 +16,28 @@ package org.apache.ibatis.cache.decorators; import org.apache.ibatis.cache.Cache; +import org.apache.ibatis.cache.CacheDecorator; import org.apache.ibatis.logging.Log; import org.apache.ibatis.logging.LogFactory; /** * @author Clinton Begin */ -public class LoggingCache implements Cache { +public class LoggingCache extends CacheDecorator { private final Log log; - private final Cache delegate; protected int requests; protected int hits; public LoggingCache(Cache delegate) { - this.delegate = delegate; + super(delegate); this.log = LogFactory.getLog(getId()); } - @Override - public String getId() { - return delegate.getId(); - } - - @Override - public int getSize() { - return delegate.getSize(); - } - - @Override - public void putObject(Object key, Object object) { - delegate.putObject(key, object); - } - @Override public Object getObject(Object key) { requests++; - final Object value = delegate.getObject(key); + final Object value = super.getObject(key); if (value != null) { hits++; } @@ -62,24 +47,14 @@ public Object getObject(Object key) { return value; } - @Override - public Object removeObject(Object key) { - return delegate.removeObject(key); - } - - @Override - public void clear() { - delegate.clear(); - } - @Override public int hashCode() { - return delegate.hashCode(); + return getDelegate().hashCode(); } @Override public boolean equals(Object obj) { - return delegate.equals(obj); + return getDelegate().equals(obj); } private double getHitRatio() { diff --git a/src/main/java/org/apache/ibatis/cache/decorators/LruCache.java b/src/main/java/org/apache/ibatis/cache/decorators/LruCache.java index ad8738cfd51..d3f6cf3d283 100644 --- a/src/main/java/org/apache/ibatis/cache/decorators/LruCache.java +++ b/src/main/java/org/apache/ibatis/cache/decorators/LruCache.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2023 the original author or authors. + * Copyright 2009-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,33 +19,23 @@ import java.util.Map; import org.apache.ibatis.cache.Cache; +import org.apache.ibatis.cache.CacheDecorator; /** * Lru (least recently used) cache decorator. * * @author Clinton Begin */ -public class LruCache implements Cache { +public class LruCache extends CacheDecorator { - private final Cache delegate; private Map keyMap; private Object eldestKey; public LruCache(Cache delegate) { - this.delegate = delegate; + super(delegate); setSize(1024); } - @Override - public String getId() { - return delegate.getId(); - } - - @Override - public int getSize() { - return delegate.getSize(); - } - public void setSize(final int size) { keyMap = new LinkedHashMap(size, .75F, true) { private static final long serialVersionUID = 4267176411845948333L; @@ -63,32 +53,32 @@ protected boolean removeEldestEntry(Map.Entry eldest) { @Override public void putObject(Object key, Object value) { - delegate.putObject(key, value); + super.putObject(key, value); cycleKeyList(key); } @Override public Object getObject(Object key) { keyMap.get(key); // touch - return delegate.getObject(key); + return super.getObject(key); } @Override public Object removeObject(Object key) { keyMap.remove(key); - return delegate.removeObject(key); + return super.removeObject(key); } @Override public void clear() { - delegate.clear(); + super.clear(); keyMap.clear(); } private void cycleKeyList(Object key) { keyMap.put(key, key); if (eldestKey != null) { - delegate.removeObject(eldestKey); + super.removeObject(eldestKey); eldestKey = null; } } diff --git a/src/main/java/org/apache/ibatis/cache/decorators/ScheduledCache.java b/src/main/java/org/apache/ibatis/cache/decorators/ScheduledCache.java index 2fb059da846..270be113008 100644 --- a/src/main/java/org/apache/ibatis/cache/decorators/ScheduledCache.java +++ b/src/main/java/org/apache/ibatis/cache/decorators/ScheduledCache.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2022 the original author or authors. + * Copyright 2009-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,18 +18,18 @@ import java.util.concurrent.TimeUnit; import org.apache.ibatis.cache.Cache; +import org.apache.ibatis.cache.CacheDecorator; /** * @author Clinton Begin */ -public class ScheduledCache implements Cache { +public class ScheduledCache extends CacheDecorator { - private final Cache delegate; protected long clearInterval; protected long lastClear; public ScheduledCache(Cache delegate) { - this.delegate = delegate; + super(delegate); this.clearInterval = TimeUnit.HOURS.toMillis(1); this.lastClear = System.currentTimeMillis(); } @@ -38,48 +38,43 @@ public void setClearInterval(long clearInterval) { this.clearInterval = clearInterval; } - @Override - public String getId() { - return delegate.getId(); - } - @Override public int getSize() { clearWhenStale(); - return delegate.getSize(); + return super.getSize(); } @Override public void putObject(Object key, Object object) { clearWhenStale(); - delegate.putObject(key, object); + super.putObject(key, object); } @Override public Object getObject(Object key) { - return clearWhenStale() ? null : delegate.getObject(key); + return clearWhenStale() ? null : super.getObject(key); } @Override public Object removeObject(Object key) { clearWhenStale(); - return delegate.removeObject(key); + return super.removeObject(key); } @Override public void clear() { lastClear = System.currentTimeMillis(); - delegate.clear(); + super.clear(); } @Override public int hashCode() { - return delegate.hashCode(); + return getDelegate().hashCode(); } @Override public boolean equals(Object obj) { - return delegate.equals(obj); + return getDelegate().equals(obj); } private boolean clearWhenStale() { diff --git a/src/main/java/org/apache/ibatis/cache/decorators/SerializedCache.java b/src/main/java/org/apache/ibatis/cache/decorators/SerializedCache.java index 5726c8d2556..7be067650b7 100644 --- a/src/main/java/org/apache/ibatis/cache/decorators/SerializedCache.java +++ b/src/main/java/org/apache/ibatis/cache/decorators/SerializedCache.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2023 the original author or authors. + * Copyright 2009-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +25,7 @@ import java.io.Serializable; import org.apache.ibatis.cache.Cache; +import org.apache.ibatis.cache.CacheDecorator; import org.apache.ibatis.cache.CacheException; import org.apache.ibatis.io.Resources; import org.apache.ibatis.io.SerialFilterChecker; @@ -32,22 +33,10 @@ /** * @author Clinton Begin */ -public class SerializedCache implements Cache { - - private final Cache delegate; +public class SerializedCache extends CacheDecorator { public SerializedCache(Cache delegate) { - this.delegate = delegate; - } - - @Override - public String getId() { - return delegate.getId(); - } - - @Override - public int getSize() { - return delegate.getSize(); + super(delegate); } @Override @@ -55,33 +44,23 @@ public void putObject(Object key, Object object) { if ((object != null) && !(object instanceof Serializable)) { throw new CacheException("SharedCache failed to make a copy of a non-serializable object: " + object); } - delegate.putObject(key, serialize((Serializable) object)); + super.putObject(key, serialize((Serializable) object)); } @Override public Object getObject(Object key) { - Object object = delegate.getObject(key); + Object object = super.getObject(key); return object == null ? null : deserialize((byte[]) object); } - @Override - public Object removeObject(Object key) { - return delegate.removeObject(key); - } - - @Override - public void clear() { - delegate.clear(); - } - @Override public int hashCode() { - return delegate.hashCode(); + return getDelegate().hashCode(); } @Override public boolean equals(Object obj) { - return delegate.equals(obj); + return getDelegate().equals(obj); } private byte[] serialize(Serializable value) { diff --git a/src/main/java/org/apache/ibatis/cache/decorators/SoftCache.java b/src/main/java/org/apache/ibatis/cache/decorators/SoftCache.java index 271bbe4a224..f2488d4c1d9 100644 --- a/src/main/java/org/apache/ibatis/cache/decorators/SoftCache.java +++ b/src/main/java/org/apache/ibatis/cache/decorators/SoftCache.java @@ -22,6 +22,7 @@ import java.util.concurrent.locks.ReentrantLock; import org.apache.ibatis.cache.Cache; +import org.apache.ibatis.cache.CacheDecorator; /** * Soft Reference cache decorator. @@ -30,29 +31,23 @@ * * @author Clinton Begin */ -public class SoftCache implements Cache { +public class SoftCache extends CacheDecorator { private final Deque hardLinksToAvoidGarbageCollection; private final ReferenceQueue queueOfGarbageCollectedEntries; - private final Cache delegate; private int numberOfHardLinks; private final ReentrantLock lock = new ReentrantLock(); public SoftCache(Cache delegate) { - this.delegate = delegate; + super(delegate); this.numberOfHardLinks = 256; this.hardLinksToAvoidGarbageCollection = new LinkedList<>(); this.queueOfGarbageCollectedEntries = new ReferenceQueue<>(); } - @Override - public String getId() { - return delegate.getId(); - } - @Override public int getSize() { removeGarbageCollectedItems(); - return delegate.getSize(); + return super.getSize(); } public void setSize(int size) { @@ -62,18 +57,18 @@ public void setSize(int size) { @Override public void putObject(Object key, Object value) { removeGarbageCollectedItems(); - delegate.putObject(key, new SoftEntry(key, value, queueOfGarbageCollectedEntries)); + super.putObject(key, new SoftEntry(key, value, queueOfGarbageCollectedEntries)); } @Override public Object getObject(Object key) { Object result = null; @SuppressWarnings("unchecked") // assumed delegate cache is totally managed by this cache - SoftReference softReference = (SoftReference) delegate.getObject(key); + SoftReference softReference = (SoftReference) super.getObject(key); if (softReference != null) { result = softReference.get(); if (result == null) { - delegate.removeObject(key); + super.removeObject(key); } else { // See #586 (and #335) modifications need more than a read lock lock.lock(); @@ -94,7 +89,7 @@ public Object getObject(Object key) { public Object removeObject(Object key) { removeGarbageCollectedItems(); @SuppressWarnings("unchecked") - SoftReference softReference = (SoftReference) delegate.removeObject(key); + SoftReference softReference = (SoftReference) super.removeObject(key); return softReference == null ? null : softReference.get(); } @@ -107,13 +102,13 @@ public void clear() { lock.unlock(); } removeGarbageCollectedItems(); - delegate.clear(); + super.clear(); } private void removeGarbageCollectedItems() { SoftEntry sv; while ((sv = (SoftEntry) queueOfGarbageCollectedEntries.poll()) != null) { - delegate.removeObject(sv.key); + super.removeObject(sv.key); } } diff --git a/src/main/java/org/apache/ibatis/cache/decorators/SynchronizedCache.java b/src/main/java/org/apache/ibatis/cache/decorators/SynchronizedCache.java index 13076bd4d60..cce47a78052 100644 --- a/src/main/java/org/apache/ibatis/cache/decorators/SynchronizedCache.java +++ b/src/main/java/org/apache/ibatis/cache/decorators/SynchronizedCache.java @@ -18,29 +18,24 @@ import java.util.concurrent.locks.ReentrantLock; import org.apache.ibatis.cache.Cache; +import org.apache.ibatis.cache.CacheDecorator; /** * @author Clinton Begin */ -public class SynchronizedCache implements Cache { +public class SynchronizedCache extends CacheDecorator { private final ReentrantLock lock = new ReentrantLock(); - private final Cache delegate; public SynchronizedCache(Cache delegate) { - this.delegate = delegate; - } - - @Override - public String getId() { - return delegate.getId(); + super(delegate); } @Override public int getSize() { lock.lock(); try { - return delegate.getSize(); + return super.getSize(); } finally { lock.unlock(); } @@ -50,7 +45,7 @@ public int getSize() { public void putObject(Object key, Object object) { lock.lock(); try { - delegate.putObject(key, object); + super.putObject(key, object); } finally { lock.unlock(); } @@ -60,7 +55,7 @@ public void putObject(Object key, Object object) { public Object getObject(Object key) { lock.lock(); try { - return delegate.getObject(key); + return super.getObject(key); } finally { lock.unlock(); } @@ -70,7 +65,7 @@ public Object getObject(Object key) { public Object removeObject(Object key) { lock.lock(); try { - return delegate.removeObject(key); + return super.removeObject(key); } finally { lock.unlock(); } @@ -80,7 +75,7 @@ public Object removeObject(Object key) { public void clear() { lock.lock(); try { - delegate.clear(); + super.clear(); } finally { lock.unlock(); } @@ -88,12 +83,12 @@ public void clear() { @Override public int hashCode() { - return delegate.hashCode(); + return getDelegate().hashCode(); } @Override public boolean equals(Object obj) { - return delegate.equals(obj); + return getDelegate().equals(obj); } } diff --git a/src/main/java/org/apache/ibatis/cache/decorators/TransactionalCache.java b/src/main/java/org/apache/ibatis/cache/decorators/TransactionalCache.java index cb022484854..c190b920be3 100644 --- a/src/main/java/org/apache/ibatis/cache/decorators/TransactionalCache.java +++ b/src/main/java/org/apache/ibatis/cache/decorators/TransactionalCache.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2023 the original author or authors. + * Copyright 2009-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ import java.util.Set; import org.apache.ibatis.cache.Cache; +import org.apache.ibatis.cache.CacheDecorator; import org.apache.ibatis.logging.Log; import org.apache.ibatis.logging.LogFactory; @@ -35,36 +36,25 @@ * @author Clinton Begin * @author Eduardo Macarron */ -public class TransactionalCache implements Cache { +public class TransactionalCache extends CacheDecorator { private static final Log log = LogFactory.getLog(TransactionalCache.class); - private final Cache delegate; private boolean clearOnCommit; private final Map entriesToAddOnCommit; private final Set entriesMissedInCache; public TransactionalCache(Cache delegate) { - this.delegate = delegate; + super(delegate); this.clearOnCommit = false; this.entriesToAddOnCommit = new HashMap<>(); this.entriesMissedInCache = new HashSet<>(); } - @Override - public String getId() { - return delegate.getId(); - } - - @Override - public int getSize() { - return delegate.getSize(); - } - @Override public Object getObject(Object key) { // issue #116 - Object object = delegate.getObject(key); + Object object = super.getObject(key); if (object == null) { entriesMissedInCache.add(key); } @@ -93,7 +83,7 @@ public void clear() { public void commit() { if (clearOnCommit) { - delegate.clear(); + super.clear(); } flushPendingEntries(); reset(); @@ -112,11 +102,11 @@ private void reset() { private void flushPendingEntries() { for (Map.Entry entry : entriesToAddOnCommit.entrySet()) { - delegate.putObject(entry.getKey(), entry.getValue()); + super.putObject(entry.getKey(), entry.getValue()); } for (Object entry : entriesMissedInCache) { if (!entriesToAddOnCommit.containsKey(entry)) { - delegate.putObject(entry, null); + super.putObject(entry, null); } } } @@ -124,7 +114,7 @@ private void flushPendingEntries() { private void unlockMissedEntries() { for (Object entry : entriesMissedInCache) { try { - delegate.removeObject(entry); + super.removeObject(entry); } catch (Exception e) { log.warn("Unexpected exception while notifying a rollback to the cache adapter. " + "Consider upgrading your cache adapter to the latest version. Cause: " + e); diff --git a/src/main/java/org/apache/ibatis/cache/decorators/WeakCache.java b/src/main/java/org/apache/ibatis/cache/decorators/WeakCache.java index 772cdbafbed..01039e5ba63 100644 --- a/src/main/java/org/apache/ibatis/cache/decorators/WeakCache.java +++ b/src/main/java/org/apache/ibatis/cache/decorators/WeakCache.java @@ -22,6 +22,7 @@ import java.util.concurrent.locks.ReentrantLock; import org.apache.ibatis.cache.Cache; +import org.apache.ibatis.cache.CacheDecorator; /** * Weak Reference cache decorator. @@ -30,29 +31,23 @@ * * @author Clinton Begin */ -public class WeakCache implements Cache { +public class WeakCache extends CacheDecorator { private final Deque hardLinksToAvoidGarbageCollection; private final ReferenceQueue queueOfGarbageCollectedEntries; - private final Cache delegate; private int numberOfHardLinks; private final ReentrantLock lock = new ReentrantLock(); public WeakCache(Cache delegate) { - this.delegate = delegate; + super(delegate); this.numberOfHardLinks = 256; this.hardLinksToAvoidGarbageCollection = new LinkedList<>(); this.queueOfGarbageCollectedEntries = new ReferenceQueue<>(); } - @Override - public String getId() { - return delegate.getId(); - } - @Override public int getSize() { removeGarbageCollectedItems(); - return delegate.getSize(); + return super.getSize(); } public void setSize(int size) { @@ -62,18 +57,18 @@ public void setSize(int size) { @Override public void putObject(Object key, Object value) { removeGarbageCollectedItems(); - delegate.putObject(key, new WeakEntry(key, value, queueOfGarbageCollectedEntries)); + super.putObject(key, new WeakEntry(key, value, queueOfGarbageCollectedEntries)); } @Override public Object getObject(Object key) { Object result = null; @SuppressWarnings("unchecked") // assumed delegate cache is totally managed by this cache - WeakReference weakReference = (WeakReference) delegate.getObject(key); + WeakReference weakReference = (WeakReference) super.getObject(key); if (weakReference != null) { result = weakReference.get(); if (result == null) { - delegate.removeObject(key); + super.removeObject(key); } else { lock.lock(); try { @@ -93,7 +88,7 @@ public Object getObject(Object key) { public Object removeObject(Object key) { removeGarbageCollectedItems(); @SuppressWarnings("unchecked") - WeakReference weakReference = (WeakReference) delegate.removeObject(key); + WeakReference weakReference = (WeakReference) super.removeObject(key); return weakReference == null ? null : weakReference.get(); } @@ -106,13 +101,13 @@ public void clear() { lock.unlock(); } removeGarbageCollectedItems(); - delegate.clear(); + super.clear(); } private void removeGarbageCollectedItems() { WeakEntry sv; while ((sv = (WeakEntry) queueOfGarbageCollectedEntries.poll()) != null) { - delegate.removeObject(sv.key); + super.removeObject(sv.key); } } diff --git a/src/test/java/org/apache/ibatis/cache/CacheDecoratorTest.java b/src/test/java/org/apache/ibatis/cache/CacheDecoratorTest.java new file mode 100644 index 00000000000..644420deb9c --- /dev/null +++ b/src/test/java/org/apache/ibatis/cache/CacheDecoratorTest.java @@ -0,0 +1,60 @@ +/* + * Copyright 2009-2024 the original author or authors. + * + * Licensed 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. + */ +package org.apache.ibatis.cache; + +import static org.junit.Assert.assertNotNull; + +import org.apache.ibatis.cache.decorators.LoggingCache; +import org.apache.ibatis.cache.decorators.LruCache; +import org.apache.ibatis.cache.decorators.SynchronizedCache; +import org.apache.ibatis.cache.impl.PerpetualCache; +import org.junit.Test; + +/** + * @author wuwen + */ +public class CacheDecoratorTest { + + @Test + public void getSpecifiedDecorator() { + Cache cache = new PerpetualCache("default"); + cache = new LruCache(cache); + cache = new LoggingCache(cache); + cache = new SynchronizedCache(cache); + + cache.putObject("hello", System.currentTimeMillis()); + + cache.getObject("hello"); + + LoggingCache loggingCache = findCacheDecorator((CacheDecorator) cache, LoggingCache.class); + + assertNotNull(loggingCache); + + } + + private T findCacheDecorator(CacheDecorator cache, Class type) { + Cache delegate = cache.getDelegate(); + + if (delegate.getClass().equals(type)) { + return (T) delegate; + } else if (delegate instanceof CacheDecorator) { + return findCacheDecorator((CacheDecorator) delegate, type); + } + + return null; + } + +} diff --git a/src/test/java/org/apache/ibatis/mapping/CacheBuilderTest.java b/src/test/java/org/apache/ibatis/mapping/CacheBuilderTest.java index bbaf3e2e526..18d9a775df2 100644 --- a/src/test/java/org/apache/ibatis/mapping/CacheBuilderTest.java +++ b/src/test/java/org/apache/ibatis/mapping/CacheBuilderTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2023 the original author or authors. + * Copyright 2009-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,10 +19,9 @@ import static com.googlecode.catchexception.apis.BDDCatchException.when; import static org.assertj.core.api.BDDAssertions.then; -import java.lang.reflect.Field; - import org.apache.ibatis.builder.InitializingObject; import org.apache.ibatis.cache.Cache; +import org.apache.ibatis.cache.CacheDecorator; import org.apache.ibatis.cache.CacheException; import org.apache.ibatis.cache.impl.PerpetualCache; import org.assertj.core.api.Assertions; @@ -46,20 +45,7 @@ void testInitializingFailure() { @SuppressWarnings("unchecked") private T unwrap(Cache cache) { - Field field; - try { - field = cache.getClass().getDeclaredField("delegate"); - } catch (NoSuchFieldException e) { - throw new IllegalStateException(e); - } - try { - field.setAccessible(true); - return (T) field.get(cache); - } catch (IllegalAccessException e) { - throw new IllegalStateException(e); - } finally { - field.setAccessible(false); - } + return (T) ((CacheDecorator) cache).getDelegate(); } private static class InitializingCache extends PerpetualCache implements InitializingObject { diff --git a/src/test/java/org/apache/ibatis/submitted/cache/CacheTest.java b/src/test/java/org/apache/ibatis/submitted/cache/CacheTest.java index adc3cd5ca46..abc148435a2 100644 --- a/src/test/java/org/apache/ibatis/submitted/cache/CacheTest.java +++ b/src/test/java/org/apache/ibatis/submitted/cache/CacheTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2023 the original author or authors. + * Copyright 2009-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,6 @@ import static org.assertj.core.api.BDDAssertions.then; import java.io.Reader; -import java.lang.reflect.Field; import org.apache.ibatis.BaseDataTest; import org.apache.ibatis.annotations.CacheNamespace; @@ -28,6 +27,7 @@ import org.apache.ibatis.annotations.Property; import org.apache.ibatis.builder.BuilderException; import org.apache.ibatis.cache.Cache; +import org.apache.ibatis.cache.CacheDecorator; import org.apache.ibatis.cache.CacheException; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; @@ -323,20 +323,7 @@ void shouldErrorInvalidCacheNamespaceRefAttributesIsEmpty() { } private CustomCache unwrap(Cache cache) { - Field field; - try { - field = cache.getClass().getDeclaredField("delegate"); - } catch (NoSuchFieldException e) { - throw new IllegalStateException(e); - } - try { - field.setAccessible(true); - return (CustomCache) field.get(cache); - } catch (IllegalAccessException e) { - throw new IllegalStateException(e); - } finally { - field.setAccessible(false); - } + return (CustomCache) ((CacheDecorator) cache).getDelegate(); } // @formatter:off diff --git a/src/test/java/org/apache/ibatis/submitted/global_variables/BaseTest.java b/src/test/java/org/apache/ibatis/submitted/global_variables/BaseTest.java index e6e6c74cb12..49b433efca1 100644 --- a/src/test/java/org/apache/ibatis/submitted/global_variables/BaseTest.java +++ b/src/test/java/org/apache/ibatis/submitted/global_variables/BaseTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2023 the original author or authors. + * Copyright 2009-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,10 +16,10 @@ package org.apache.ibatis.submitted.global_variables; import java.io.Reader; -import java.lang.reflect.Field; import org.apache.ibatis.BaseDataTest; import org.apache.ibatis.cache.Cache; +import org.apache.ibatis.cache.CacheDecorator; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; @@ -72,20 +72,7 @@ void shouldGetAUserFromAnnotation() { } private CustomCache unwrap(Cache cache) { - Field field; - try { - field = cache.getClass().getDeclaredField("delegate"); - } catch (NoSuchFieldException e) { - throw new IllegalStateException(e); - } - try { - field.setAccessible(true); - return (CustomCache) field.get(cache); - } catch (IllegalAccessException e) { - throw new IllegalStateException(e); - } finally { - field.setAccessible(false); - } + return (CustomCache) ((CacheDecorator) cache).getDelegate(); } } diff --git a/src/test/java/org/apache/ibatis/submitted/global_variables_defaults/SupportClasses.java b/src/test/java/org/apache/ibatis/submitted/global_variables_defaults/SupportClasses.java index 9aa12c073ca..e48ebee6178 100644 --- a/src/test/java/org/apache/ibatis/submitted/global_variables_defaults/SupportClasses.java +++ b/src/test/java/org/apache/ibatis/submitted/global_variables_defaults/SupportClasses.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2023 the original author or authors. + * Copyright 2009-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,10 +15,10 @@ */ package org.apache.ibatis.submitted.global_variables_defaults; -import java.lang.reflect.Field; import java.util.Properties; import org.apache.ibatis.cache.Cache; +import org.apache.ibatis.cache.CacheDecorator; import org.apache.ibatis.cache.impl.PerpetualCache; import org.apache.ibatis.reflection.factory.DefaultObjectFactory; @@ -56,20 +56,7 @@ public void setName(String name) { static class Utils { static SupportClasses.CustomCache unwrap(Cache cache) { - Field field; - try { - field = cache.getClass().getDeclaredField("delegate"); - } catch (NoSuchFieldException e) { - throw new IllegalStateException(e); - } - try { - field.setAccessible(true); - return (SupportClasses.CustomCache) field.get(cache); - } catch (IllegalAccessException e) { - throw new IllegalStateException(e); - } finally { - field.setAccessible(false); - } + return (SupportClasses.CustomCache) ((CacheDecorator) cache).getDelegate(); } private Utils() {