All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.java.ao.cache.RAMRelationsCache Maven / Gradle / Ivy

Go to download

This is the core library for Active Objects. It is generic and can be embedded in any environment. As such it is generic and won't contain all connection pooling, etc.

There is a newer version: 6.1.1
Show newest version
/*
 * Copyright 2007 Daniel Spiewak
 * 
 * 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
 * 
 *	    http://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 net.java.ao.cache;

import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import net.java.ao.RawEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author Daniel Spiewak
 */
public final class RAMRelationsCache implements RelationsCache {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

	private final Map[]> cache;
	private final Map>, Set> typeMap;
	private final Map> fieldMap;
	private final ReadWriteLock lock;

	public RAMRelationsCache() {
		cache = new HashMap[]>();
		typeMap = new HashMap>, Set>();
		fieldMap = new HashMap>();
		
		lock = new ReentrantReadWriteLock();
	}
	
	public void flush() {
		lock.writeLock().lock();
		try {
			cache.clear();
			typeMap.clear();
			fieldMap.clear();
            logger.debug("flush");
		} finally {
			lock.writeLock().unlock();
		}
	}

	public void put(RawEntity from, RawEntity[] through, Class> throughType, RawEntity[] to, Class> toType, String[] fields) {

		final CacheKey key = new CacheKey(from, toType, throughType, fields);
		lock.writeLock().lock();
		try {
			cache.put(key, to);
			
			Set keys = typeMap.get(key.getThroughType());
			if (keys == null) {
				keys = new HashSet();
				typeMap.put(key.getThroughType(), keys);
			}
			keys.add(key);
			
			for (String field : fields) {
				for (RawEntity entity : through) {
					MetaCacheKey metaKey = new MetaCacheKey(entity, field);
					
					keys = fieldMap.get(metaKey);
					if (keys == null) {
						keys = new HashSet();
						fieldMap.put(metaKey, keys);
					}
					keys.add(key);
				}
			}
            if (logger.isDebugEnabled())
            {
                logger.debug("put ( {}, {}, {}, {}, {}, {} )", new Object[]{from, through, throughType, to, toType, Arrays.toString(fields)});
            }
        } finally {
			lock.writeLock().unlock();
		}
	}

	public , K> T[] get(RawEntity from, Class toType, Class> throughType, String[] fields) {
		lock.readLock().lock();
		try {
            final T[] ts = (T[]) cache.get(new CacheKey(from, toType, throughType, fields));
            if (logger.isDebugEnabled())
            {
                logger.debug("get ( {}, {}, {}, {} ) : {}", new Object[]{from, toType, throughType, Arrays.toString(fields), Arrays.toString(ts)});
            }
            return ts;
		} finally {
			lock.readLock().unlock();
		}
	}
	
	public void remove(Class>... types) {
		lock.writeLock().lock();
		try {
			for (Class> type : types) {
				Set keys = typeMap.get(type);
				if (keys != null) {
					for (CacheKey key : keys) {
						cache.remove(key);
					}
		
					typeMap.remove(type);
				}
			}
            if (logger.isDebugEnabled())
            {
                logger.debug("remove ( {} )", Arrays.toString(types));
            }
        } finally {
			lock.writeLock().unlock();
		}
	}

	public void remove(RawEntity entity, String[] fields) {
		lock.writeLock().lock();
		try {
			for (String field : fields) {
				Set keys = fieldMap.get(new MetaCacheKey(entity, field));
				if (keys != null) {
					for (CacheKey key : keys) {
						cache.remove(key);
					}
				}
			}
            if (logger.isDebugEnabled())
            {
                logger.debug("remove ( {}, {} )", entity, Arrays.toString(fields));
            }
        } finally {
			lock.writeLock().unlock();
		}
	}

	private static final class CacheKey {
		private RawEntity from;
		private Class> toType;
		private Class> throughType;
		
		private String[] fields;
		
		public CacheKey(RawEntity from, Class> toType, 
				Class> throughType, String[] fields) {
			this.from = from;
			this.toType = toType;
			this.throughType = throughType;
			
			setFields(fields);
		}

		public RawEntity getFrom() {
			return from;
		}

		public void setFrom(RawEntity from) {
			this.from = from;
		}

		public Class> getToType() {
			return toType;
		}

		public void setToType(Class> toType) {
			this.toType = toType;
		}

		public String[] getFields() {
			return fields;
		}

		public void setFields(String[] fields) {
			Arrays.sort(fields);
			
			this.fields = fields;
		}
		
		public Class> getThroughType() {
			return throughType;
		}
		
		public void setThroughType(Class> throughType) {
			this.throughType = throughType;
		}
		
		@Override
		public String toString() {
			return '(' + from.toString() + "; to=" + toType.getName() + "; through=" + throughType.getName() + "; " + Arrays.toString(fields) + ')';
		}
		
		@Override
		public boolean equals(Object obj) {
			if (obj instanceof CacheKey) {
				CacheKey key = (CacheKey) obj;
				
				if (key.getFrom() != null) {
					if (!key.getFrom().equals(from)) {
						return false;
					}
				}
				if (key.getToType() != null) {
					if (!key.getToType().getName().equals(toType.getName())) {
						return false;
					}
				}
				if (key.getThroughType() != null) {
					if (!key.getThroughType().getName().equals(throughType.getName())) {
						return false;
					}
				}
				if (key.getFields() != null) {
					if (!Arrays.equals(key.getFields(), fields)) {
						return false;
					}
				}
				
				return true;
			}
			
			return super.equals(obj);
		}
		
		@Override
		public int hashCode() {
			int hashCode = 0;
			
			if (from != null) {
				hashCode += from.hashCode();
			}
			if (toType != null) {
				hashCode += toType.getName().hashCode();
			}
			if (throughType != null) {
				hashCode += throughType.getName().hashCode();
			}
			if (fields != null) {
				for (String field : fields) {
					hashCode += field.hashCode();
				}
			}
			hashCode %= 2 << 10;
			
			return hashCode;
		}
	}
	
	private static final class MetaCacheKey {
		private RawEntity entity;
		private String field;
		
		public MetaCacheKey(RawEntity entity, String field) {
			this.entity = entity;
			
			setField(field);
		}

		public RawEntity getEntity() {
			return entity;
		}

		public void setEntity(RawEntity entity) {
			this.entity = entity;
		}

		public String getField() {
			return field;
		}

		public void setField(String field) {
			this.field = field;
		}
		
		@Override
		public String toString() {
			return entity.toString() + "; " + field;
		}
		
		@Override
		public boolean equals(Object obj) {
			if (obj instanceof MetaCacheKey) {
				MetaCacheKey key = (MetaCacheKey) obj;
				
				if (key.getEntity() != null) {
					if (!key.getEntity().equals(entity)) {
						return false;
					}
				}
				if (key.getField() != null) {
					if (!key.getField().equals(field)) {
						return false;
					}
				}
				
				return true;
			}
			
			return super.equals(obj);
		}
		
		@Override
		public int hashCode() {
			int hashCode = 0;
			
			if (entity != null) {
				hashCode += entity.hashCode();
			}
			if (field != null) {
				hashCode += field.hashCode();
			}
			hashCode %= 2 << 15;
			
			return hashCode;
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy