package org.codehaus.plexus.context;
/*
* Copyright 2001-2006 Codehaus Foundation.
*
* 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.
*/
import java.util.Collections;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Default implementation of Context.
*
* This implementation is a static hierarchial store. It has the normal <code>get()</code>
* and <code>put</code> methods. The <code>hide</code> method will hide a property. When
* a property has been hidden the containerContext will not search in the parent containerContext for the value.
*
* @author <a href="mailto:dev@avalon.codehaus.org">Avalon Development Team</a>
* @version $Id$
*/
public class DefaultContext
implements Context
{
/**
* Context data.
*/
private final ConcurrentMap<Object, Object> contextData = new ConcurrentHashMap<Object, Object>();
/**
* Is the containerContext read only.
*/
private final AtomicBoolean readOnly = new AtomicBoolean(false);
/**
* Create an empty Context.
*/
public DefaultContext()
{
}
/**
* Create a Context with specified data. The specified data is copied into the context so any subsequent updates
* to supplied map are not reflected in this context. Additionally, changes to this context are not reflected in
* the specified map.
*
* @param contextData the containerContext data
*/
public DefaultContext( Map<Object, Object> contextData )
{
if ( contextData == null )
{
throw new NullPointerException( "contextData is null" );
}
// check for nulls in key and value
for ( Entry<Object, Object> entry : contextData.entrySet() )
{
Object key = entry.getKey();
Object value = entry.getValue();
if ( key == null )
{
throw new IllegalArgumentException( "Key is null" );
}
if ( value != null )
{
this.contextData.put( key, value );
}
}
}
public boolean contains( Object key )
{
Object data = contextData.get( key );
return data != null;
}
public Object get( Object key )
throws ContextException
{
Object data = contextData.get( key );
if ( data == null )
{
// There is no data for the key
throw new ContextException( "Unable to resolve context key: " + key );
}
return data;
}
public void put( Object key, Object value )
throws IllegalStateException
{
checkWriteable();
// check for a null key
if (key == null)
{
throw new IllegalArgumentException("Key is null");
}
if ( value == null )
{
contextData.remove( key );
}
else
{
contextData.put( key, value );
}
}
public void hide( Object key )
throws IllegalStateException
{
checkWriteable();
contextData.remove( key );
}
/**
* Utility method to retrieve containerContext data
*
* @return the containerContext data
*/
public Map getContextData()
{
return Collections.unmodifiableMap( contextData );
}
/**
* Make the containerContext read-only.
* Any attempt to write to the containerContext via put()
* will result in an IllegalStateException.
*/
public void makeReadOnly()
{
readOnly.set( true );
}
/**
* Utility method to check if containerContext is writeable and if not throw exception.
*
* @throws java.lang.IllegalStateException if containerContext is read only
*/
protected void checkWriteable()
throws IllegalStateException
{
if ( readOnly.get() )
{
throw new IllegalStateException( "Context is read only and can not be modified" );
}
}
public String toString()
{
return contextData.toString();
}
}