001: /**
002: * Objective Database Abstraction Layer (ODAL)
003: * Copyright (c) 2004, The ODAL Development Group
004: * All rights reserved.
005: * For definition of the ODAL Development Group please refer to LICENCE.txt file
006: *
007: * Distributable under LGPL license.
008: * See terms of license at gnu.org.
009: */package com.completex.objective.components.cache.impl;
010:
011: import com.completex.objective.components.cache.Cache;
012:
013: import java.util.HashMap;
014: import java.util.Iterator;
015: import java.util.LinkedHashMap;
016: import java.util.Map;
017:
018: /**
019: * @author Andrew Suprun
020: * @author Gennady Krizhevsky
021: */
022: public class BasicCache implements Cache {
023:
024: private com.completex.objective.components.cache.CacheResourceFactory resourceFactory;
025: private int capacity;
026: private final Map contexts = new HashMap();
027:
028: public BasicCache(
029: com.completex.objective.components.cache.CacheResourceFactory resourceFactory,
030: int capacity) {
031: this .resourceFactory = resourceFactory;
032: this .capacity = capacity;
033: }
034:
035: public int getCapacity() {
036: return capacity;
037: }
038:
039: protected com.completex.objective.components.cache.CacheResourceFactory getResourceFactory() {
040: return resourceFactory;
041: }
042:
043: public Object acquire(Object context, Object key) {
044: Context ctx;
045: synchronized (contexts) {
046: ctx = (Context) contexts.get(context);
047: if (ctx == null) {
048: ctx = new Context();
049: contexts.put(context, ctx);
050: }
051: }
052: if (ctx.activeResources.size() == 0) {
053: ctx.activeThread = Thread.currentThread();
054: } else {
055: checkActiveThread(ctx);
056: }
057: Resource resource = (Resource) ctx.idleResources.remove(key);
058: if (resource == null) {
059: int capacity = getCapacity();
060: int activeSize = ctx.activeResources.size();
061: if (ctx.idleResources.size() + activeSize >= capacity) {
062: if (ctx.idleResources.size() > 0) {
063: Object oldKey = ctx.idleResources.keySet()
064: .iterator().next();
065: resource = (Resource) ctx.idleResources
066: .remove(oldKey);
067: resourceFactory.destroyResource(ctx,
068: resource.resource);
069: } else {
070: error(ctx,
071: "Number of active resources exceeded capacity: "
072: + capacity);
073: }
074: }
075: resource = new Resource(key, resourceFactory
076: .createResource(context, key));
077: }
078: ctx.activeResources.put(resource.resource, resource);
079: return resource.resource;
080: }
081:
082: public void release(Object context, Object res) {
083: Context ctx;
084: synchronized (contexts) {
085: ctx = (Context) contexts.get(context);
086: }
087: checkActiveThread(ctx);
088: Resource resource = (Resource) ctx.activeResources.remove(res);
089: ctx.idleResources.put(resource.key, resource);
090: }
091:
092: private void dumpActiveResources(Context context,
093: StringBuffer buffer) {
094: buffer.append("\nActive resources:");
095: int index = 0;
096: for (Iterator iterator = context.activeResources.entrySet()
097: .iterator(); iterator.hasNext(); index++) {
098: Map.Entry entry = (Map.Entry) iterator.next();
099: boolean withStackTrace = index == 0;
100: dumpResource(entry.getKey(), (Resource) entry.getValue(),
101: buffer, withStackTrace);
102: }
103: }
104:
105: private void dumpResource(Object key, Resource resource,
106: StringBuffer buffer, boolean withStackTrace) {
107: buffer.append("\nResource: ").append(key);
108: if (withStackTrace) {
109: buffer.append("\nStack Trace: ");
110: for (int i = 2; i < resource.stackTrace.length; i++) {
111: StackTraceElement element = resource.stackTrace[i];
112: buffer.append("\n at ").append(element.toString());
113: }
114: }
115: buffer.append("\n==============================");
116: }
117:
118: private void checkActiveThread(Context ctx) {
119: if (ctx.activeThread != Thread.currentThread()) {
120: error(ctx,
121: "Concurrent access to the cache context is not allowed."
122: + "\nCurrent thread: "
123: + Thread.currentThread()
124: + "\nPrevious thread: " + ctx.activeThread);
125: }
126: }
127:
128: private Object error(Context ctx, String message) {
129: StringBuffer buffer = new StringBuffer(message);
130: dumpActiveResources(ctx, buffer);
131: throw new RuntimeException(buffer.toString());
132: }
133:
134: private static class Context {
135:
136: private Thread activeThread = null;
137: private final Map activeResources = new LinkedHashMap();
138: private final Map idleResources = new LinkedHashMap();
139: }
140:
141: private static class Resource {
142:
143: Object key;
144: Object resource;
145: StackTraceElement[] stackTrace = new Exception()
146: .getStackTrace();
147:
148: public Resource(Object key, Object resource) {
149: this .key = key;
150: this .resource = resource;
151: }
152:
153: public String toString() {
154: return "[Resource [key " + key + "] [resource " + resource
155: + "]]";
156: }
157: }
158: }
|