/*=============================================================================*
* 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.axis.components.logger.LogFactory;
import org.apache.commons.logging.Log;
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.MetadataConfig;
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.MetadataConfigDocument;
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 javax.naming.Context;
import javax.naming.InitialContext;
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.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
/** 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
extends JNDIUtils
{
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";
/**
* Singleton instance of the JNDI Context.
*/
private static Context m_initialContext;
/**
* The file name of the jndi-config file.
*/
public static final String JNDI_CONFIG_FILENAME = "jndi-config.xml";
private static DefaultParameters s_defaultProperties;
private static final String PROP_FACTORY = "factory";
private static final String PROP_RESOURCE_KEY_NAME = "resourceKeyName";
private static final String PROP_RESOURCE_KEY_CLASS_NAME = "resourceKeyClassName";
/**
* Configure JNDI with the Apache Tomcat naming service classes and create
* the comp and env contexts
*
* @return The initial context
* @throws Exception
*/
public static Context initJNDI( )
throws Exception
{
LOG.debug("Initializing JNDI.");
Context result = null;
Context compContext = null;
// set up naming
String value = APACHE_URL_PKG_PREFIX;
String oldValue = System.getProperty( Context.URL_PKG_PREFIXES );
if ( oldValue != null )
{
if ( oldValue.startsWith( value + ":" ) )
{
value = oldValue;
}
else
{
value = value + ":" + oldValue;
}
}
System.setProperty( Context.URL_PKG_PREFIXES, value );
value = System.getProperty( Context.INITIAL_CONTEXT_FACTORY );
if ( value == null )
{
System.setProperty( Context.INITIAL_CONTEXT_FACTORY, APACHE_INITIAL_CONTEXT_FACTORY );
}
else
{
LOG.debug( "initialContextFactorySet " + value );
}
result = new InitialContext( );
try
{
result.lookup( JndiConstants.CONTEXT_NAME_SERVICES );
}
catch ( NameNotFoundException e )
{
LOG.debug("Creating SubContext: " + JndiConstants.CONTEXT_NAME_BASE);
compContext = result.createSubcontext( JndiConstants.CONTEXT_NAME_BASE );
LOG.debug("Creating SubContext: " + JndiConstants.CONTEXT_SERVICES_BASE);
compContext.createSubcontext( JndiConstants.CONTEXT_SERVICES_BASE );
LOG.debug("Creating SubContext: " + JndiConstants.CONTEXT_GLOBAL_BASE);
compContext.createSubcontext( JndiConstants.CONTEXT_GLOBAL_BASE );
}
return result;
}
/**
* Initializes JNDI from a directory tree which contains the
* jndi-config.xml files....
*
* @param configDir
* @return
* @throws Exception
*/
public static synchronized Context initializeDir( String configDir )
throws Exception
{
LOG.debug("Initializing JNDI from root directory: " + configDir);
if ( m_initialContext == null )
{
Context context = 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( context, dirs[i], JNDI_CONFIG_FILENAME );
}
m_initialContext = context;
}
return m_initialContext;
}
/**
* Initializes JNDI given a File name which will attempt
* to be loaded.
*
* @param configFilename
* @return
* @throws Exception
*/
public static synchronized Context initializeFile( String configFilename )
throws Exception
{
LOG.debug("Initializing JNDI from file: " + configFilename);
if ( m_initialContext == null )
{
Context context = 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 = JNDIUtils.class.getClassLoader( ).getResourceAsStream( configFilename );
if ( configInput == null )
{
throw new IOException( "jndiConfigNotFound" );
}
}
parseJNDIConfig( context, configInput );
m_initialContext = context;
}
return m_initialContext;
}
/**
* Initializes JNDI from a given InputStream to a jndi-config.xml file.
*
* @param inputStream
* @return JNDI Context
* @throws Exception
*/
public static synchronized Context initializeFromInputStream( InputStream inputStream )
throws Exception
{
if ( m_initialContext == null )
{
Context context = initJNDI( );
LOG.debug( "Trying to load JNDI configuration from inputstream" );
parseJNDIConfig( context, inputStream );
m_initialContext = context;
}
return m_initialContext;
}
/**
* Called via parseJNDIConfig(InputStream)
* <p/>
* Parse the given JNDI configuration and populate the JNDI registry using
* the parsed configuration
*
* @param configInput The configuration stream to parse
* @throws Exception
*/
public static void parseJNDIConfig( Context initContext,
InputStream configInput )
throws Exception
{
if ( configInput == 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
JndiConfigDocument configObj = (JndiConfigDocument) XmlObject.Factory.parse( configInput );
JndiConfigDocument.JndiConfig jndiConfig = configObj.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 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 ResourceParameters getParameters( 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 void validateParameterValues( ResourceParameters params )
{
checkValueIsNonEmpty( params, PROP_FACTORY );
}
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 void setDefaultParameterValues( ResourceParameters params )
{
if ( params.getParameter( PROP_FACTORY ) == null )
{
params.addParameter( PROP_FACTORY, s_defaultProperties.getFactory() );
}
if ( params.getParameter( PROP_RESOURCE_KEY_CLASS_NAME ) == null )
{
params.addParameter( PROP_RESOURCE_KEY_CLASS_NAME, s_defaultProperties.getResourceKeyClassName() );
}
}
private static Resource[] getResourceArray(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)
{
try
{
Class metaConfigClass = Class.forName(resourceDoc.getType());
Constructor constructor = metaConfigClass.getClass().getConstructor(new Class[]{metadataConfig.getClass()});
MetadataConfig metaConfig = (MetadataConfig) constructor.newInstance(new Object[]{metadataConfig});
String contextName = null;
if (name != null)
{
namingContext.getContext().createSubcontext(name); //add subcontext
contextName = name + "/";
}
contextName = contextName + resourceDoc.getName();
namingContext.bind(contextName, metaConfig);
continue;
}
catch (Exception e)
{
LOG.error("Unable to find constructor which takes: " + metadataConfig.getClass().getName() +
", in MetadataConfig object: " + resourceDoc.getType() + ". The metadata will be ignored! Cause:" + e);
}
}
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( getParameters( resourceDoc.getResourceParams( ) ) );
resources.add( resource );
}
}
return (Resource[]) resources.toArray( new Resource[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) throws NamingException
{
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 = getResourceArray( 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_defaultProperties = 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 = getResourceArray( 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 processJNDIFile( Context context,
File dir,
String configFile )
throws Exception
{
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 e )
{
}
}
}
}
private static DefaultParameters setupDefaultParams( ResourceDocument.Resource defaultConfig )
throws ClassNotFoundException,
IllegalAccessException,
InstantiationException
{
DefaultParameters defaults = null;
if ( defaultConfig != null )
{
Object defaultConf = Class.forName( defaultConfig.getType( ) ).newInstance( );
if ( defaultConf instanceof DefaultParameters )
{
defaults = (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 ) )
{
defaults.setFactory( value );
}
else if ( PROP_RESOURCE_KEY_CLASS_NAME.equals( name ) )
{
defaults.setResourceKeyClassName( value );
}
}
}
}
}
return defaults;
}
}