/*
* 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.loader.memory;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.jboss.metadata.plugins.loader.AbstractMutableComponentMetaDataLoader;
import org.jboss.metadata.spi.retrieval.AnnotationItem;
import org.jboss.metadata.spi.retrieval.AnnotationsItem;
import org.jboss.metadata.spi.retrieval.Item;
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.retrieval.basic.BasicAnnotationItem;
import org.jboss.metadata.spi.retrieval.basic.BasicAnnotationsItem;
import org.jboss.metadata.spi.retrieval.basic.BasicMetaDataItem;
import org.jboss.metadata.spi.retrieval.basic.BasicMetaDatasItem;
import org.jboss.metadata.spi.scope.ScopeKey;
import org.jboss.metadata.spi.signature.Signature;
/**
* MemoryMetaDataLoader.
*
* @author <a href="adrian@jboss.com">Adrian Brock</a>
* @version $Revision: 69888 $
*/
public class MemoryMetaDataLoader extends AbstractMutableComponentMetaDataLoader
{
/** The annotations */
private volatile Map<String, BasicAnnotationItem<? extends Annotation>> annotations;
/** MetaData by name */
private volatile Map<String, BasicMetaDataItem<?>> metaDataByName;
/** All annotations */
private volatile BasicAnnotationsItem cachedAnnotationsItem;
/** All meta data */
private volatile BasicMetaDatasItem cachedMetaDatasItem;
/** Whether we should cache items */
private final boolean cachable;
/**
* Create a new MemoryMetaDataLoader.
*/
public MemoryMetaDataLoader()
{
this(true, false);
}
/**
* Create a new MemoryMetaDataLoader.
*
* @param cachable whether items produced should be cachable
* @param restricted whether restricted items are allowed
*/
public MemoryMetaDataLoader(boolean cachable, boolean restricted)
{
super(restricted);
this.cachable = cachable;
}
/**
* Create a new MemoryMetaDataLoader.
*
* @param scope the scope key
*/
public MemoryMetaDataLoader(ScopeKey scope)
{
this(scope, true, false);
}
/**
* Create a new MemoryMetaDataLoader.
*
* @param scope the scope key
* @param cachable whether items produced should be cachable
* @param restricted whether restricted items are allowed
*/
public MemoryMetaDataLoader(ScopeKey scope, boolean cachable, boolean restricted)
{
super(scope, restricted);
this.cachable = cachable;
}
public <T> boolean isCachable(Item<T> item)
{
return cachable;
}
@SuppressWarnings("unchecked")
public AnnotationsItem retrieveAnnotations()
{
BasicAnnotationsItem result = cachedAnnotationsItem;
if (result != null && result.isValid())
return result;
Map<String, BasicAnnotationItem<? extends Annotation>> temp = annotations;
if (temp == null)
return noAnnotations();
Collection<BasicAnnotationItem<? extends Annotation>> values = temp.values();
if (values.isEmpty())
return noAnnotations();
AnnotationItem<? extends Annotation>[] items = values.toArray(new AnnotationItem[values.size()]);
result = new BasicAnnotationsItem(this, items);
cachedAnnotationsItem = result;
return result;
}
@SuppressWarnings("unchecked")
public <T extends Annotation> AnnotationItem<T> retrieveAnnotation(Class<T> annotationType)
{
Map<String, BasicAnnotationItem<? extends Annotation>> temp = annotations;
if (temp == null)
return null;
return (AnnotationItem) temp.get(annotationType.getName());
}
@SuppressWarnings("unchecked")
public <T extends Annotation> T addAnnotation(T annotation)
{
if (annotation == null)
throw new IllegalArgumentException("Null annotation");
checkRestricted(annotation);
synchronized (this)
{
if (annotations == null)
annotations = new ConcurrentHashMap<String, BasicAnnotationItem<? extends Annotation>>();
}
T result = null;
Class<? extends Annotation> annotationType = annotation.annotationType();
BasicAnnotationItem<T> old = (BasicAnnotationItem) annotations.get(annotationType.getName());
if (old != null)
{
result = old.getAnnotation();
if (result == annotation)
return result;
old.invalidate();
}
BasicAnnotationItem<T> item = new BasicAnnotationItem<T>(this, annotation);
annotations.put(annotationType.getName(), item);
invalidateAnnotationsItem();
invalidateMetaDatasItem();
invalidate();
return result;
}
@SuppressWarnings("unchecked")
public <T extends Annotation> T removeAnnotation(Class<T> annotationType)
{
if (annotations == null)
return null;
BasicAnnotationItem<T> annotation = (BasicAnnotationItem) annotations.remove(annotationType.getName());
if (annotation == null)
return null;
annotation.invalidate();
invalidateAnnotationsItem();
invalidateMetaDatasItem();
return annotation.getAnnotation();
}
public MetaDatasItem retrieveMetaData()
{
BasicMetaDatasItem result = cachedMetaDatasItem;
if (result != null && result.isValid())
return result;
Collection<BasicMetaDataItem<?>> all = null;
Map<String, BasicAnnotationItem<? extends Annotation>> temp1 = annotations;
if (temp1 != null && temp1.size() > 0)
{
all = new ArrayList<BasicMetaDataItem<?>>();
Collection<BasicAnnotationItem<?>> values = temp1.values();
all.addAll(values);
}
Map<String, BasicMetaDataItem<?>> temp2 = metaDataByName;
if (temp2 != null && temp2.size() > 0)
{
if (all == null)
all = new ArrayList<BasicMetaDataItem<?>>();
Collection<BasicMetaDataItem<?>> values = temp2.values();
all.addAll(values);
}
if (all == null)
return noMetaDatas();
MetaDataItem<?>[] metaDataItems = all.toArray(new MetaDataItem[all.size()]);
result = new BasicMetaDatasItem(this, metaDataItems);
cachedMetaDatasItem = result;
return result;
}
@SuppressWarnings("unchecked")
public <T> MetaDataItem<T> retrieveMetaData(Class<T> type)
{
MetaDataItem<T> result = super.retrieveMetaData(type);
if (result != null)
return result;
Map temp = metaDataByName;
if (temp == null)
return null;
return (MetaDataItem<T>) temp.get(type.getName());
}
public MetaDataItem<?> retrieveMetaData(String name)
{
Map<String, BasicMetaDataItem<?>> temp = metaDataByName;
if (temp != null)
{
MetaDataItem<?> result = temp.get(name);
if (result != null)
return result;
}
Map<String, BasicAnnotationItem<? extends Annotation>> temp2 = annotations;
if (temp2 != null)
return temp2.get(name);
return null;
}
@SuppressWarnings("unchecked")
public <T> T addMetaData(T metaData, Class<T> type)
{
if (metaData == null)
throw new IllegalArgumentException("Null metaData");
if (type == null)
throw new IllegalArgumentException("Null type");
if (metaData instanceof Annotation)
return (T) addAnnotation((Annotation) metaData);
checkRestricted(type);
synchronized (this)
{
if (metaDataByName == null)
metaDataByName = new ConcurrentHashMap<String, BasicMetaDataItem<?>>();
}
T result = null;
BasicMetaDataItem<T> old = (BasicMetaDataItem) metaDataByName.get(type.getName());
if (old != null)
{
result = old.getValue();
if (result == metaData)
return result;
old.invalidate();
}
BasicMetaDataItem<T> item = new BasicMetaDataItem<T>(this, type.getName(), metaData);
metaDataByName.put(type.getName(), item);
invalidateMetaDatasItem();
invalidate();
return result;
}
@SuppressWarnings("unchecked")
public <T> T removeMetaData(Class<T> type)
{
if (type == null)
throw new IllegalArgumentException("Null type");
if (type.isAnnotation())
return (T) removeAnnotation((Class<Annotation>) type);
if (metaDataByName == null)
return null;
BasicMetaDataItem<T> result = (BasicMetaDataItem) metaDataByName.remove(type.getName());
if (result == null)
return null;
result.invalidate();
invalidateMetaDatasItem();
return result.getValue();
}
@SuppressWarnings("unchecked")
public <T> T addMetaData(String name, T metaData, Class<T> type)
{
if (name == null)
throw new IllegalArgumentException("Null name");
if (metaData == null)
throw new IllegalArgumentException("Null metaData");
if (type == null)
throw new IllegalArgumentException("Null type");
checkRestricted(type);
synchronized (this)
{
if (metaDataByName == null)
metaDataByName = new ConcurrentHashMap<String, BasicMetaDataItem<?>>();
}
T result = null;
BasicMetaDataItem<T> old = (BasicMetaDataItem) metaDataByName.get(name);
if (old != null)
{
result = old.getValue();
if (result == metaData)
return result;
old.invalidate();
}
BasicMetaDataItem<T> item = new BasicMetaDataItem<T>(this, name, metaData);
metaDataByName.put(name, item);
invalidateMetaDatasItem();
invalidate();
return result;
}
@SuppressWarnings("unchecked")
public <T> T removeMetaData(String name, Class<T> type)
{
if (name == null)
throw new IllegalArgumentException("Null name");
Map<String, BasicMetaDataItem<?>> temp = metaDataByName;
if (temp == null)
return null;
BasicMetaDataItem<T> result = (BasicMetaDataItem) temp.remove(name);
if (result == null)
return null;
result.invalidate();
invalidateMetaDatasItem();
return result.getValue();
}
public boolean isEmpty()
{
return isNullOrEmpty(annotations) && isNullOrEmpty(metaDataByName) && super.isEmpty();
}
/**
* Invalidate the annotations item
*/
protected void invalidateAnnotationsItem()
{
BasicAnnotationsItem temp = cachedAnnotationsItem;
if (temp != null)
{
temp.invalidate();
cachedAnnotationsItem = null;
}
}
/**
* Set no annotations
*
* @return no annotations
*/
protected BasicAnnotationsItem noAnnotations()
{
BasicAnnotationsItem result = new BasicAnnotationsItem(this, BasicAnnotationsItem.NO_ANNOTATION_ITEMS);
cachedAnnotationsItem = result;
return result;
}
/**
* Invalidate the metaDatas item
*/
protected void invalidateMetaDatasItem()
{
BasicMetaDatasItem temp = cachedMetaDatasItem;
if (temp != null)
{
temp.invalidate();
cachedMetaDatasItem = null;
}
}
/**
* Set no meta data
*
* @return no meta data
*/
protected BasicMetaDatasItem noMetaDatas()
{
BasicMetaDatasItem result = new BasicMetaDatasItem(this, BasicMetaDatasItem.NO_META_DATA_ITEMS);
cachedMetaDatasItem = result;
return result;
}
@Override
protected MetaDataRetrieval initComponentRetrieval(Signature signature)
{
return new MemoryMetaDataLoader();
}
}