/*=============================================================================*
* Copyright 2004 The Apache Software 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.
*=============================================================================*/
package org.apache.ws.util.jndi;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ws.resource.JndiConstants;
import org.apache.ws.util.jndi.tools.ConfigContext;
import org.apache.ws.util.jndi.tools.Environment;
import org.apache.ws.util.jndi.tools.Resource;
import org.apache.ws.util.jndi.tools.ResourceLink;
import org.apache.ws.util.jndi.tools.ResourceParameters;
import org.apache.wsfx.wsrf.jndi.config.EnvironmentDocument;
import org.apache.wsfx.wsrf.jndi.config.GlobalDocument;
import org.apache.wsfx.wsrf.jndi.config.JndiConfigDocument;
import org.apache.wsfx.wsrf.jndi.config.ParameterDocument;
import org.apache.wsfx.wsrf.jndi.config.ResourceDocument;
import org.apache.wsfx.wsrf.jndi.config.ResourceLinkDocument;
import org.apache.wsfx.wsrf.jndi.config.ResourceParamsDocument;
import org.apache.wsfx.wsrf.jndi.config.ServiceDocument;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlOptions;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NameAlreadyBoundException;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;
/**
* LOG-DONE JNDI Utiltiy methods for use with an XmlBean-generated JNDI-Config file. This class handles the initial
* setup of JNDI, it loads the JNDI config file and registers instances of services.
*
* @author Sal Campana
*/
public class XmlBeanJndiUtils
{
private static Log LOG = LogFactory.getLog( XmlBeanJndiUtils.class.getName( ) );
/**
* Apache JNDI URL Package Prefix
*/
public static final String APACHE_URL_PKG_PREFIX = "org.apache.naming";
/**
* Apache JNDI Initial Context Factory Prefix
*/
public static final String APACHE_INITIAL_CONTEXT_FACTORY = "org.apache.naming.java.javaURLContextFactory";
/**
* The file name of the jndi-config file.
*/
public static final String JNDI_CONFIG_FILENAME = "jndi-config.xml";
private static final String PROP_FACTORY = "factory";
private static boolean s_configLoaded;
private static boolean s_jndiInitialized;
private static DefaultParameters s_defaultParams;
/**
* Create all intermediate subcontexts.
*/
public static Context createSubcontexts( Context currentContext,
String name )
throws NamingException
{
StringTokenizer tokenizer = new StringTokenizer( name, "/" );
while ( tokenizer.hasMoreTokens( ) )
{
String token = tokenizer.nextToken( );
if ( ( !token.equals( "" ) ) && ( tokenizer.hasMoreTokens( ) ) )
{
try
{
currentContext = currentContext.createSubcontext( token );
}
catch ( NameAlreadyBoundException e )
{
// Silent catch. Probably an object is already bound in
// the context.
currentContext = (Context) currentContext.lookup( token );
}
}
}
return currentContext;
}
/**
* Initializes JNDI from a directory tree which contains the jndi-config.xml files....
*
* @param configDir
* @return
* @throws Exception
*/
public static synchronized Context initFromDir( String configDir )
throws Exception
{
if ( !s_configLoaded )
{
LOG.debug( "Initializing JNDI from config directory: " + configDir + " ..." );
initJNDI( );
File fDir = new File( configDir );
File[] dirs =
fDir.listFiles( new FileFilter( )
{
public boolean accept( File path )
{
return path.isDirectory( );
}
} );
for ( int i = 0; i < dirs.length; i++ )
{
processJNDIFile( dirs[i], JNDI_CONFIG_FILENAME );
}
s_configLoaded = true;
}
return new InitialContext( );
}
/**
* Initializes JNDI given a File name which will attempt to be loaded.
*
* @param configFilename
* @return
* @throws Exception
*/
public static synchronized Context initFromFile( String configFilename )
throws Exception
{
LOG.debug( "Initializing JNDI from file: " + configFilename );
if ( !s_configLoaded )
{
initJNDI( );
InputStream configInput;
try
{
LOG.debug( "Trying to load JNDI configuration from file: " + configFilename );
configInput = new FileInputStream( configFilename );
}
catch ( FileNotFoundException fnfe )
{
LOG.debug( "Trying to load JNDI configuration from classloader resource: " + configFilename );
configInput = XmlBeanJndiUtils.class.getClassLoader( ).getResourceAsStream( configFilename );
if ( configInput == null )
{
throw new IOException( "jndiConfigNotFound" );
}
}
Context context = new InitialContext( );
parseJNDIConfig( context, configInput );
s_configLoaded = true;
}
return new InitialContext( );
}
/**
* Initializes JNDI from a given InputStream to a jndi-config.xml file.
*
* @param inputStream
* @return JNDI Context
* @throws Exception
*/
public static synchronized Context initFromInputStream( InputStream inputStream )
throws Exception
{
if ( !s_configLoaded )
{
initJNDI( );
LOG.debug( "Trying to load JNDI configuration from inputstream" );
parseJNDIConfig( new InitialContext( ),
inputStream );
s_configLoaded = true;
}
return new InitialContext( );
}
/**
* Configure JNDI with the Apache Tomcat naming service classes and
* create the WSRF context.
*
* @return the WSRF context
* @throws Exception
*/
public static synchronized Context initJNDI( )
throws Exception
{
if ( !s_jndiInitialized )
{
initJndiImpl( );
initWsrfContext( );
s_jndiInitialized = true;
}
return new InitialContext( );
}
/**
* DOCUMENT_ME
*
* @return DOCUMENT_ME
*
* @throws NamingException DOCUMENT_ME
*/
public static Context initWsrfContext( )
throws NamingException
{
Context wsrfContext;
InitialContext initialContext = new InitialContext( );
try
{
wsrfContext = (Context) initialContext.lookup( JndiConstants.CONTEXT_NAME_WSRF );
}
catch ( NameNotFoundException nnfe )
{
LOG.debug( "Initializing WSRF JNDI context..." );
LOG.debug( "Creating JNDI subcontext: " + JndiConstants.CONTEXT_NAME_WSRF + " ..." );
wsrfContext = initialContext.createSubcontext( JndiConstants.CONTEXT_NAME_WSRF );
LOG.debug( "Creating JNDI subcontext: " + JndiConstants.ATOMIC_NAME_SERVICES + " ..." );
wsrfContext.createSubcontext( JndiConstants.ATOMIC_NAME_SERVICES );
LOG.debug( "Creating JNDI subcontext: " + JndiConstants.ATOMIC_NAME_GLOBAL + " ..." );
wsrfContext.createSubcontext( JndiConstants.ATOMIC_NAME_GLOBAL );
}
return wsrfContext;
}
/**
* Retrieves the named object on the specified context. The object returned must be of assignable from the type
* specified.
*
* @param context the context to perform lookup on
* @param name the name of the object to lookup
* @param type the expected type of the object returned
*/
public static Object lookup( Context context,
String name,
Class type )
throws NamingException
{
if ( context == null )
{
throw new IllegalArgumentException( "nullArgument:context" );
}
if ( type == null )
{
throw new IllegalArgumentException( "nullArgument:type" );
}
Object tmp = context.lookup( name );
if ( type.isAssignableFrom( tmp.getClass( ) ) )
{
return tmp;
}
else
{
throw new NamingException( "expectedType " + type.getName( ) );
}
}
/**
* Called via parseJNDIConfig(InputStream)
* <p/>
* Parse the given JNDI configuration and populate the JNDI registry using the parsed configuration
*
* @param configStream The configuration stream to parse
* @throws Exception
*/
public static void parseJNDIConfig( Context initContext,
InputStream configStream )
throws Exception
{
if ( configStream == null )
{
throw new IllegalArgumentException( "nullJNDIConfigInput" );
}
if ( initContext == null )
{
throw new IllegalArgumentException( );
}
//get the global context
Context envContext = (Context) initContext.lookup( JndiConstants.CONTEXT_NAME_GLOBAL );
XmlBeanNamingContext namingContext = new XmlBeanNamingContext( envContext );
//load the config file
XmlOptions options = new XmlOptions( );
options.setLoadStripWhitespace( );
JndiConfigDocument jndiConfigDoc = (JndiConfigDocument) XmlObject.Factory.parse( configStream, options );
validateJndiConfig( jndiConfigDoc );
JndiConfigDocument.JndiConfig jndiConfig = jndiConfigDoc.getJndiConfig( );
GlobalDocument.Global global = jndiConfig.getGlobal( );
//setup the global jndi elements
addGlobalElements( namingContext, global );
//get the service context
envContext = (Context) initContext.lookup( JndiConstants.CONTEXT_NAME_SERVICES );
namingContext = new XmlBeanNamingContext( envContext );
//setup the service jndi elements
ServiceDocument.Service[] serviceArray = jndiConfig.getServiceArray( );
addServiceElements( namingContext, serviceArray );
}
private static void setDefaultParameterValues( ResourceParameters params )
{
if ( params.getParameter( PROP_FACTORY ) == null )
{
params.addParameter( PROP_FACTORY,
s_defaultParams.getFactory( ) );
}
}
private static DefaultParameters getDefaultProperties( GlobalDocument.Global global )
throws IllegalAccessException,
InstantiationException,
ClassNotFoundException
{
ResourceDocument.Resource defaultConfig = null;
ResourceDocument.Resource[] resourceArray = global.getResourceArray( );
for ( int i = 0; i < resourceArray.length; i++ )
{
ResourceDocument.Resource resource = resourceArray[i];
if ( DefaultParameters.class.getName( ).equals( resource.getType( ) ) )
{
defaultConfig = resource;
break;
}
}
return setupDefaultParams( defaultConfig );
}
private static Environment[] getEnvironmentArray( EnvironmentDocument.Environment[] environmentArray )
{
List envList = new ArrayList( );
if ( environmentArray != null )
{
for ( int i = 0; i < environmentArray.length; i++ )
{
EnvironmentDocument.Environment environment = environmentArray[i];
Environment env = new Environment( );
env.setDescription( environment.getDescription( ) );
env.setName( environment.getName( ) );
env.setType( environment.getType( ) );
env.setValue( environment.getValue( ) );
envList.add( env );
}
}
return (Environment[]) envList.toArray( new Environment[0] );
}
private static ResourceLink[] getResourceLinkArray( ResourceLinkDocument.ResourceLink[] resourceLinkArray )
{
List resourceLinks = new ArrayList( );
if ( resourceLinkArray != null )
{
for ( int i = 0; i < resourceLinkArray.length; i++ )
{
ResourceLinkDocument.ResourceLink resourceLink = resourceLinkArray[i];
ResourceLink link = new ResourceLink( );
link.setName( resourceLink.getName( ) );
link.setTarget( resourceLink.getTarget( ) );
resourceLinks.add( link );
}
}
return (ResourceLink[]) resourceLinks.toArray( new ResourceLink[0] );
}
private static ConfigContext[] getServiceArray( ServiceDocument.Service[] serviceArray,
XmlBeanNamingContext namingContext )
{
List services = new ArrayList( );
if ( serviceArray != null )
{
for ( int i = 0; i < serviceArray.length; i++ )
{
ServiceDocument.Service service = serviceArray[i];
ConfigContext context = new ConfigContext( );
context.setName( service.getName( ) );
Environment[] environmentArray = getEnvironmentArray( service.getEnvironmentArray( ) );
for ( int j = 0; j < environmentArray.length; j++ )
{
context.addEnvironment( environmentArray[j] );
}
Resource[] resourceArray =
createResources( service.getResourceArray( ),
service.getName( ),
namingContext );
for ( int j = 0; j < resourceArray.length; j++ )
{
Resource resource = resourceArray[j];
ResourceParameters params = resource.getParameters( );
setDefaultParameterValues( params );
validateParameterValues( params );
}
for ( int j = 0; j < resourceArray.length; j++ )
{
context.addResource( resourceArray[j] );
}
ResourceLink[] resourceLinkArray = getResourceLinkArray( service.getResourceLinkArray( ) );
for ( int j = 0; j < resourceLinkArray.length; j++ )
{
context.addResourceLink( resourceLinkArray[j] );
}
services.add( context );
}
}
return (ConfigContext[]) services.toArray( new ConfigContext[0] );
}
private static ConfigContext[] getServiceSubContextArray( ConfigContext service )
{
List subContexts = new ArrayList( );
if ( service != null )
{
Set subContextNames = service.getSubContextNames( );
Iterator iterator = subContextNames.iterator( );
while ( iterator.hasNext( ) )
{
subContexts.add( service.getSubContext( (String) iterator.next( ) ) );
}
}
return (ConfigContext[]) subContexts.toArray( new ConfigContext[0] );
}
private static void addGlobalElements( XmlBeanNamingContext namingContext,
GlobalDocument.Global global )
throws NamingException,
IllegalAccessException,
ClassNotFoundException,
InstantiationException
{
if ( global != null )
{
s_defaultParams = getDefaultProperties( global );
Environment[] environmentArray = getEnvironmentArray( global.getEnvironmentArray( ) );
for ( int i = 0; i < environmentArray.length; i++ )
{
namingContext.addEnvironment( environmentArray[i] );
}
ConfigContext[] subContext = getServiceArray( global.getServiceArray( ),
namingContext );
for ( int i = 0; i < subContext.length; i++ )
{
namingContext.addSubContext( subContext[i] );
}
Resource[] resourceArray = createResources( global.getResourceArray( ),
null,
namingContext );
for ( int i = 0; i < resourceArray.length; i++ )
{
namingContext.addResource( resourceArray[i] );
}
ResourceLink[] resourceLinkArray = getResourceLinkArray( global.getResourceLinkArray( ) );
for ( int i = 0; i < resourceLinkArray.length; i++ )
{
namingContext.addResourceLink( resourceLinkArray[i] );
}
}
}
private static void addServiceElements( XmlBeanNamingContext namingContext,
ServiceDocument.Service[] serviceArray )
throws NamingException
{
if ( serviceArray != null )
{
ConfigContext[] services = getServiceArray( serviceArray, namingContext );
for ( int i = 0; i < services.length; i++ )
{
ConfigContext service = services[i];
namingContext.addService( service );
ConfigContext[] serviceSubContextArray = getServiceSubContextArray( service );
for ( int j = 0; j < serviceSubContextArray.length; j++ )
{ //todo not sure if defaults bubble down here...
namingContext.addSubContext( serviceSubContextArray[j] );
}
}
}
}
private static void checkValueIsNonEmpty( ResourceParameters params,
String paramName )
{
String paramValue = params.getParameter( paramName );
if ( paramValue.trim( ).equals( "" ) )
{
throw new RuntimeException( paramName + " parameter must have a non-empty value!" );
}
}
private static ResourceParameters createResourceParameters( ResourceParamsDocument.ResourceParams resourceParams )
{
ResourceParameters params = new ResourceParameters( );
if ( resourceParams != null )
{
ParameterDocument.Parameter[] parameterArray = resourceParams.getParameterArray( );
for ( int i = 0; i < parameterArray.length; i++ )
{
ParameterDocument.Parameter parameter = parameterArray[i];
params.addParameter( parameter.getName( ),
parameter.getValue( ) );
}
}
return params;
}
private static Resource[] createResources( ResourceDocument.Resource[] resourceArray,
String name,
XmlBeanNamingContext namingContext )
{
List resources = new ArrayList( );
if ( resourceArray != null )
{
for ( int i = 0; i < resourceArray.length; i++ )
{
ResourceDocument.Resource resourceDoc = resourceArray[i];
/* //special type of resource....metatdata...handle differently....
MetadataConfigDocument.MetadataConfig metadataConfig = resourceDoc.getMetadataConfig();
if (metadataConfig != null)
{
Constructor constructor = null;
MetadataConfig metaConfig = null;
try
{
Class metaConfigClass = Class.forName(resourceDoc.getType());
constructor =
metaConfigClass.getConstructor(new Class[]
{
MetadataConfigDocument.MetadataConfig.class
});
metaConfig =
(MetadataConfig) constructor.newInstance(new Object[]
{
metadataConfig
});
}
catch (Exception e)
{
LOG.error("Unable to find constructor which takes: " + metadataConfig.getClass().getName()
+ ", in MetadataConfig object: " + resourceDoc.getType()
+ ". The metadata will be ignored!", e);
}
if (metaConfig != null)
{
String contextName = null;
if (name != null)
{
try
{
createSubcontexts(namingContext.getContext(), name); //add subcontext
contextName = contextName + resourceDoc.getName();
namingContext.bind(contextName, metaConfig);
}
catch (NamingException e)
{
LOG.error("A NamingException occurred when creating sbucontexts for the Metadataconfig.", e);
}
contextName = name + "/";
}
}
continue;
}
*/
Resource resource = new Resource( );
resource.setName( resourceDoc.getName( ) );
resource.setAuth( resourceDoc.getAuth( ) );
resource.setDescription( resourceDoc.getDescription( ) );
resource.setType( resourceDoc.getType( ) );
resource.setScope( resourceDoc.getScope( ) );
resource.setParameters( createResourceParameters( resourceDoc.getResourceParams( ) ) );
resources.add( resource );
}
}
return (Resource[]) resources.toArray( new Resource[0] );
}
private static void initJndiImpl( )
{
String apacheUrlPrefix = APACHE_URL_PKG_PREFIX;
String systemUrlPrefix = System.getProperty( Context.URL_PKG_PREFIXES );
String systemContextFactory = System.getProperty( Context.INITIAL_CONTEXT_FACTORY );
if ( ( systemContextFactory == null ) && ( systemUrlPrefix == null ) )
{
System.setProperty( Context.URL_PKG_PREFIXES, apacheUrlPrefix );
System.setProperty( Context.INITIAL_CONTEXT_FACTORY, APACHE_INITIAL_CONTEXT_FACTORY );
}
}
private static void processJNDIFile( File dir,
String configFile )
throws Exception
{
Context context = new InitialContext( );
File file = new File( dir, configFile );
if ( !file.exists( ) )
{
return;
}
LOG.debug( "Loading JNDI configuration from file: " + file + " ..." );
InputStream in = null;
try
{
in = new FileInputStream( file );
parseJNDIConfig( context, in );
}
finally
{
if ( in != null )
{
try
{
in.close( );
}
catch ( IOException ioe )
{
// ignore
}
}
}
}
private static DefaultParameters setupDefaultParams( ResourceDocument.Resource defaultConfig )
throws ClassNotFoundException,
IllegalAccessException,
InstantiationException
{
DefaultParameters defaultParams = null;
if ( defaultConfig != null )
{
Object defaultConf = Class.forName( defaultConfig.getType( ) ).newInstance( );
if ( defaultConf instanceof DefaultParameters )
{
defaultParams = (DefaultParameters) defaultConf;
ResourceParamsDocument.ResourceParams resourceParams = defaultConfig.getResourceParams( );
ParameterDocument.Parameter[] parameterArray = resourceParams.getParameterArray( );
for ( int i = 0; i < parameterArray.length; i++ )
{
ParameterDocument.Parameter parameter = parameterArray[i];
String name = parameter.getName( );
String value = parameter.getValue( );
if ( ( value != null ) && !value.equals( "" ) )
{
if ( PROP_FACTORY.equals( name ) )
{
defaultParams.setFactory( value );
}
}
}
}
}
return defaultParams;
}
private static void validateJndiConfig( XmlObject requestXBean )
{
XmlOptions validateOptions = new XmlOptions( );
List errorList = new ArrayList( );
validateOptions.setErrorListener( errorList );
boolean isValid = requestXBean.validate( validateOptions );
if ( !isValid )
{
StringBuffer strBuf = new StringBuffer( "jndi-config.xml is not valid as per its schema: \n\n" );
for ( int i = 0; i < errorList.size( ); i++ )
{
strBuf.append( "\t\t" );
strBuf.append( i + 1 );
strBuf.append( ") " );
strBuf.append( errorList.get( i ) );
strBuf.append( "\n" );
}
strBuf.append( "\n" );
LOG.fatal( strBuf.toString( ) );
}
}
private static void validateParameterValues( ResourceParameters params )
{
checkValueIsNonEmpty( params, PROP_FACTORY );
}
}