/*
* JBoss, Home of Professional Open Source
* Copyright 2006, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.metadata.plugins.context;
import java.lang.annotation.Annotation;
import java.util.Collections;
import java.util.List;
import org.jboss.metadata.plugins.cache.Cache;
import org.jboss.metadata.plugins.cache.CacheFactory;
import org.jboss.metadata.plugins.cache.CacheItem;
import org.jboss.metadata.plugins.cache.DefaultCacheFactory;
import org.jboss.metadata.spi.context.MetaDataContext;
import org.jboss.metadata.spi.retrieval.AnnotationItem;
import org.jboss.metadata.spi.retrieval.AnnotationsItem;
import org.jboss.metadata.spi.retrieval.MetaDataItem;
import org.jboss.metadata.spi.retrieval.MetaDataRetrieval;
import org.jboss.metadata.spi.retrieval.MetaDatasItem;
import org.jboss.metadata.spi.scope.ScopeLevel;
import org.jboss.metadata.spi.signature.Signature;
/**
* CachingMetaDataContext.
*
* @author <a href="adrian@jboss.com">Adrian Brock</a>
* @author <a href="ales.justin@jboss.com">Ales Justin</a>
* @version $Revision: 76136 $
*/
public class CachingMetaDataContext extends AbstractMetaDataContext
{
/** The annotations */
@SuppressWarnings("unchecked")
private volatile Cache<String, AnnotationItem> annotations;
/** MetaData by name */
@SuppressWarnings("unchecked")
private volatile Cache<String, MetaDataItem> metaDataByName;
/** All annotations */
private volatile CacheItem<AnnotationsItem> cachedAnnotationsItem;
/** All meta data */
private volatile CacheItem<MetaDatasItem> cachedMetaDatasItem;
/** Cached components */
private volatile Cache<Signature, MetaDataRetrieval> cachedComponents;
/** The valid time */
private volatile long validTime;
/** Is empty */
private volatile Boolean empty;
/** Scoped contexs */
private volatile Cache<ScopeLevel, MetaDataRetrieval> cachedScopedRetrievals;
/** The cache factory */
private CacheFactory factory;
/** The fqn */
private String fqn;
/**
* Create a new CachingMetaDataContext.
*
* @param retrieval the retrieval
*/
public CachingMetaDataContext(MetaDataRetrieval retrieval)
{
this(null, retrieval);
}
/**
* Create a new CachingMetaDataContext.
*
* @param retrieval the retrieval
* @param factory the cache factory
*/
public CachingMetaDataContext(MetaDataRetrieval retrieval, CacheFactory factory)
{
this(null, retrieval, factory);
}
/**
* Create a new CachingMetaDataContext.
*
* @param parent the parent
* @param retrieval the retrieval
*/
public CachingMetaDataContext(MetaDataContext parent, MetaDataRetrieval retrieval)
{
this(parent, Collections.singletonList(retrieval));
}
/**
* Create a new CachingMetaDataContext.
*
* @param parent the parent
* @param retrieval the retrieval
* @param factory the cache factory
*/
public CachingMetaDataContext(MetaDataContext parent, MetaDataRetrieval retrieval, CacheFactory factory)
{
this(parent, Collections.singletonList(retrieval), factory);
}
/**
* Create a new CachingMetaDataContext.
*
* @param parent the parent
* @param retrievals the retrievals
*/
public CachingMetaDataContext(MetaDataContext parent, List<MetaDataRetrieval> retrievals)
{
this(parent, retrievals, null);
}
/**
* Create a new CachingMetaDataContext.
*
* @param parent the parent
* @param retrievals the retrievals
* @param factory the cache factory
*/
public CachingMetaDataContext(MetaDataContext parent, List<MetaDataRetrieval> retrievals, CacheFactory factory)
{
super(parent, retrievals);
if (factory == null)
factory = new DefaultCacheFactory();
validTime = getValidTime().getValidTime();
this.factory = factory;
this.fqn = factory.createFqn(this);
}
/**
* Get fqn for this instance.
*
* @return the instance's fqn
*/
protected String getFqn()
{
return fqn;
}
public AnnotationsItem retrieveAnnotations()
{
if (cachedAnnotationsItem == null)
cachedAnnotationsItem = factory.createCacheItem(AnnotationsItem.class, getFqn());
AnnotationsItem item = cachedAnnotationsItem.get();
if (item == null)
{
item = super.retrieveAnnotations();
cachedAnnotationsItem.put(item);
}
return item;
}
@SuppressWarnings("unchecked")
public <T extends Annotation> AnnotationItem<T> retrieveAnnotation(Class<T> annotationType)
{
if (annotationType == null)
throw new IllegalArgumentException("Null annotationType");
String annotationName = annotationType.getName();
long newValidTime = getValidTime().getValidTime();
if (validTime < newValidTime)
{
clearCache(annotations);
clearCache(metaDataByName);
validTime = newValidTime;
}
if (annotations != null)
{
AnnotationItem<T> result = annotations.get(annotationName);
if (result != null)
{
if (result.isValid())
return result;
annotations.remove(annotationName);
}
}
AnnotationItem result = super.retrieveAnnotation(annotationType);
if (result != null && result.isCachable())
{
if (annotations == null)
annotations = factory.createCache(String.class, AnnotationItem.class, getFqn());
annotations.put(annotationName, result);
}
return result;
}
public MetaDatasItem retrieveMetaData()
{
if (cachedMetaDatasItem == null)
cachedMetaDatasItem = factory.createCacheItem(MetaDatasItem.class, getFqn());
MetaDatasItem item = cachedMetaDatasItem.get();
if (item == null)
{
item = super.retrieveMetaData();
cachedMetaDatasItem.put(item);
}
return item;
}
@SuppressWarnings("unchecked")
public <T> MetaDataItem<T> retrieveMetaData(Class<T> type)
{
if (type == null)
throw new IllegalArgumentException("Null type");
String name = type.getName();
long newValidTime = getValidTime().getValidTime();
if (validTime < newValidTime)
{
clearCache(annotations);
clearCache(metaDataByName);
validTime = newValidTime;
}
if (metaDataByName != null)
{
MetaDataItem<T> result = metaDataByName.get(name);
if (result != null)
{
if (result.isValid())
return result;
metaDataByName.remove(name);
}
}
MetaDataItem<T> result = super.retrieveMetaData(type);
if (result != null && result.isCachable())
{
if (metaDataByName == null)
metaDataByName = factory.createCache(String.class, MetaDataItem.class, getFqn());
metaDataByName.put(name, result);
}
return result;
}
public MetaDataItem<?> retrieveMetaData(String name)
{
if (name == null)
throw new IllegalArgumentException("Null name");
long newValidTime = getValidTime().getValidTime();
if (validTime < newValidTime)
{
clearCache(annotations);
clearCache(metaDataByName);
validTime = newValidTime;
}
if (metaDataByName != null)
{
MetaDataItem<?> result = metaDataByName.get(name);
if (result != null)
{
if (result.isValid())
return result;
metaDataByName.remove(name);
}
}
MetaDataItem<?> result = super.retrieveMetaData(name);
if (result != null && result.isCachable())
{
if (metaDataByName == null)
metaDataByName = factory.createCache(String.class, MetaDataItem.class, getFqn());
metaDataByName.put(name, result);
}
return result;
}
public void append(MetaDataRetrieval retrieval)
{
super.append(retrieval);
clearCache(cachedComponents);
clearCache(cachedScopedRetrievals);
empty = null;
}
public void prepend(MetaDataRetrieval retrieval)
{
super.prepend(retrieval);
clearCache(cachedComponents);
clearCache(cachedScopedRetrievals);
empty = null;
}
public void remove(MetaDataRetrieval retrieval)
{
super.remove(retrieval);
clearCache(cachedComponents);
clearCache(cachedScopedRetrievals);
empty = null;
}
public MetaDataRetrieval getComponentMetaDataRetrieval(Signature signature)
{
if (signature == null)
return null;
if (cachedComponents != null)
{
MetaDataRetrieval retrieval = cachedComponents.get(signature);
if (retrieval != null)
return retrieval;
}
MetaDataRetrieval retrieval = super.getComponentMetaDataRetrieval(signature);
if (retrieval != null)
{
if (cachedComponents == null)
cachedComponents = factory.createCache(Signature.class, MetaDataRetrieval.class, getFqn());
cachedComponents.put(signature, retrieval);
}
return retrieval;
}
public boolean isEmpty()
{
if (empty == null)
empty = super.isEmpty();
return empty;
}
public MetaDataRetrieval getScopedRetrieval(ScopeLevel level)
{
if (level == null)
return null;
if (cachedScopedRetrievals != null)
{
MetaDataRetrieval retrieval = cachedScopedRetrievals.get(level);
if (retrieval != null)
return retrieval;
}
MetaDataRetrieval retrieval = super.getScopedRetrieval(level);
if (retrieval != null)
{
if (cachedScopedRetrievals == null)
cachedScopedRetrievals = factory.createCache(ScopeLevel.class, MetaDataRetrieval.class, getFqn());
cachedScopedRetrievals.put(level, retrieval);
}
return retrieval;
}
/**
* Clear cache.
*
* @param cache the cache to clear
*/
protected void clearCache(Cache<?, ?> cache)
{
if (cache != null)
cache.clear();
}
}