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 full Active Objects library, if you don't know which one to use, you probably want this one.

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