/*
* Copyright (C) The Spice Group. All rights reserved.
*
* This software is published under the terms of the Spice
* Software License version 1.1, a copy of which has been included
* with this distribution in the LICENSE.txt file.
*/
package org.realityforge.spice.jndikit;
import java.io.IOException;
import java.io.Serializable;
import java.rmi.MarshalledObject;
import java.util.Hashtable;
import java.util.Map.Entry;
import javax.naming.Binding;
import javax.naming.CommunicationException;
import javax.naming.ConfigurationException;
import javax.naming.Context;
import javax.naming.InvalidNameException;
import javax.naming.Name;
import javax.naming.NameClassPair;
import javax.naming.NameParser;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.Referenceable;
/**
* Context that hooks up to a remote source.
*/
@SuppressWarnings( "unchecked" )
public class RemoteContext
extends AbstractContext
implements Serializable
{
public static final String NAMESPACE = "org.realityforge.spice.jndikit.Namespace";
public static final String NAMING_PROVIDER = "org.realityforge.spice.jndikit.NamingProvider";
private transient NamingProvider m_provider;
private transient NameParser m_nameParser;
private transient Namespace m_namespace;
private Name m_baseName;
//for deserialisation
@SuppressWarnings( "UnusedDeclaration" )
public RemoteContext()
{
}
public RemoteContext( final Hashtable environment, final Name baseName )
throws NamingException
{
super( environment );
m_baseName = baseName;
}
/**
* Helper method to bind
*/
protected void bind( final Name name, Object object, final boolean rebind )
throws NamingException
{
if ( isSelf( name ) )
{
throw new InvalidNameException( "Failed to bind self" );
}
String className;
object = getNamespace().getStateToBind( object, name, this, getRawEnvironment() );
if ( object instanceof Reference )
{
className = ( (Reference) object ).getClassName();
}
else if ( object instanceof Referenceable )
{
object = ( (Referenceable) object ).getReference();
className = ( (Reference) object ).getClassName();
}
else
{
className = object.getClass().getName();
try
{
object = new MarshalledObject( object );
}
catch ( final IOException ioe )
{
throw new NamingException( "Only Reference, Referenceables and " +
"Serializable objects can be bound " +
"to context" );
}
}
try
{
if ( rebind )
{
getProvider().rebind( getAbsoluteName( name ), className, object );
}
else
{
getProvider().bind( getAbsoluteName( name ), className, object );
}
}
catch ( final Exception e )
{
throw handleException( e );
}
}
/**
* Release resources associated with context.
*/
public void close()
{
super.close();
m_namespace = null;
m_provider = null;
}
/**
* Create a Subcontext.
*
* @param name the name of subcontext
* @return the created context
* @throws NamingException if an error occurs
* (ie context exists, badly formated name etc)
*/
public Context createSubcontext( final Name name )
throws NamingException
{
if ( isSelf( name ) )
{
throw new InvalidNameException( "Failed to create null subcontext" );
}
Context result;
try
{
result = getProvider().createSubcontext( getAbsoluteName( name ) );
}
catch ( final Exception e )
{
throw handleException( e );
}
fillInContext( result );
return result;
}
public void destroySubcontext( final Name name )
throws NamingException
{
if ( isSelf( name ) )
{
throw new InvalidNameException( "Failed to destroy self" );
}
try
{
getProvider().destroySubcontext( getAbsoluteName( name ) );
}
catch ( final Exception e )
{
throw handleException( e );
}
}
public String getNameInNamespace()
throws NamingException
{
return getAbsoluteName( getNameParser().parse( "" ) ).toString();
}
/**
* Enumerates the names bound in the named context.
*
* @param name the name of the context
* @return the enumeration
* @throws javax.naming.NamingException if an error occurs
*/
public NamingEnumeration list( final Name name )
throws NamingException
{
try
{
final NameClassPair[] result = getProvider().list( getAbsoluteName( name ) );
return new ArrayNamingEnumeration( this, getNamespace(), result );
}
catch ( final Exception e )
{
throw handleException( e );
}
}
/**
* Enumerates the names bound in the named context, along with the objects bound to them.
*
* @param name the name of the context
* @return the enumeration
* @throws javax.naming.NamingException if an error occurs
*/
public NamingEnumeration listBindings( final Name name )
throws NamingException
{
try
{
final Binding[] results = getProvider().listBindings( getAbsoluteName( name ) );
for ( final Binding result : results )
{
final Object object = result.getObject();
if ( object instanceof Context )
{
fillInContext( (Context) object );
}
else if ( object instanceof MarshalledObject )
{
result.setObject( ( (MarshalledObject) object ).get() );
}
}
return new ArrayNamingEnumeration( this, getNamespace(), results );
}
catch ( final Exception e )
{
throw handleException( e );
}
}
/**
* Get the object named.
*
* @param name the name
* @return the object
* @throws NamingException if an error occurs
* (ie object name is inavlid or unbound)
*/
public Object lookup( final Name name )
throws NamingException
{
if ( isSelf( name ) )
{
return new RemoteContext( getRawEnvironment(), m_baseName );
}
//actually do a real-lookup
Object object;
try
{
object = getProvider().lookup( getAbsoluteName( name ) );
if ( object instanceof MarshalledObject )
{
object = ( (MarshalledObject) object ).get();
}
object = getNamespace().getObjectInstance( object, name, this, getRawEnvironment() );
if ( object instanceof Context )
{
fillInContext( (Context) object );
}
}
catch ( final Exception e )
{
throw handleException( e );
}
return object;
}
/**
* Unbind a object from a name.
*
* @param name the name
* @throws javax.naming.NamingException if an error occurs
*/
public void unbind( final Name name )
throws NamingException
{
if ( isSelf( name ) )
{
throw new InvalidNameException( "Failed to unbind self" );
}
try
{
getProvider().unbind( getAbsoluteName( name ) );
}
catch ( final Exception e )
{
throw handleException( e );
}
}
protected void fillInContext( final Context object )
throws NamingException
{
final Hashtable<String, Object> environment = getRawEnvironment();
for ( final Entry<String, Object> entry : environment.entrySet() )
{
object.addToEnvironment( entry.getKey(), entry.getValue() );
}
}
protected Namespace getNamespace()
throws NamingException
{
if ( null == m_namespace )
{
final Object object = getRawEnvironment().get( RemoteContext.NAMESPACE );
if ( !( object instanceof Namespace ) )
{
throw new ConfigurationException( "Context does not contain Namespace" );
}
else
{
m_namespace = (Namespace) object;
}
}
return m_namespace;
}
protected NamingProvider getProvider()
throws NamingException
{
if ( null == m_provider )
{
final Object object = getRawEnvironment().get( RemoteContext.NAMING_PROVIDER );
if ( !( object instanceof NamingProvider ) )
{
throw new ConfigurationException( "Context does not contain provider" );
}
else
{
m_provider = (NamingProvider) object;
}
}
return m_provider;
}
protected NameParser getNameParser()
throws NamingException
{
if ( null == m_nameParser )
{
//Make sure provider is valid and returns name parser
try
{
m_nameParser = getProvider().getNameParser();
}
catch ( final Exception e )
{
throw handleException( e );
}
}
return m_nameParser;
}
protected Name getAbsoluteName( final Name name )
throws NamingException
{
return composeName( name, m_baseName );
}
protected NamingException handleException( final Exception e )
{
if ( e instanceof NamingException )
{
return (NamingException) e;
}
else
{
return new CommunicationException( e.toString() );
}
}
}