/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.deltaspike.core.impl.util;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.enterprise.inject.Typed;
import javax.naming.InitialContext;
import javax.naming.Name;
import javax.naming.NameClassPair;
import javax.naming.NameParser;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import org.apache.deltaspike.core.util.ClassUtils;
import org.apache.deltaspike.core.util.ExceptionUtils;
/**
* This is the internal helper class for low level access to JNDI
*/
@Typed()
public abstract class JndiUtils
{
private static final Logger LOG = Logger.getLogger(JndiUtils.class.getName());
private static InitialContext initialContext = null;
static
{
try
{
initialContext = new InitialContext();
}
catch (Exception e)
{
throw new ExceptionInInitializerError(e);
}
}
private JndiUtils()
{
// prevent instantiation
}
/**
* Resolves an instance for the given name.
*
* @param name current name
* @param targetType target type
* @param <T> type
* @return the found instance, null otherwise
*/
public static <T> T lookup(Name name, Class<? extends T> targetType)
{
try
{
return verifyLookupResult(initialContext.lookup(name), name.toString(), targetType);
}
catch (NamingException e)
{
throw ExceptionUtils.throwAsRuntimeException(e);
}
}
/**
* Resolves an instance for the given name.
*
* @param name current name
* @param targetType target type
* @param <T> type
* @return the found instance, null otherwise
*/
public static <T> T lookup(String name, Class<? extends T> targetType)
{
try
{
return verifyLookupResult(initialContext.lookup(name), name, targetType);
}
catch (NamingException e)
{
throw ExceptionUtils.throwAsRuntimeException(e);
}
}
/**
* Does a checks on given instance looked up previously from JNDI.
*
* @param name current name
* @param targetType target type
* @param <T> type
* @return the found instance, null otherwise
*/
@SuppressWarnings("unchecked")
private static <T> T verifyLookupResult(Object result, String name, Class<? extends T> targetType)
{
if (result != null)
{
if (targetType.isAssignableFrom(result.getClass()))
{
// we have a value and the type fits
return (T) result;
}
else if (result instanceof String) //but the target type != String
{
// lookedUp might be a class name
try
{
Class<?> classOfResult = ClassUtils.loadClassForName((String) result);
if (targetType.isAssignableFrom(classOfResult))
{
try
{
return (T) classOfResult.newInstance();
}
catch (Exception e)
{
// could not create instance
LOG.log(Level.SEVERE, "Class " + classOfResult + " from JNDI lookup for name "
+ name + " could not be instantiated", e);
}
}
else
{
// lookedUpClass does not extend/implement expectedClass
LOG.log(Level.SEVERE, "JNDI lookup for key " + name
+ " returned class " + classOfResult.getName()
+ " which does not implement/extend the expected class"
+ targetType.getName());
}
}
catch (ClassNotFoundException cnfe)
{
// could not find class
LOG.log(Level.SEVERE, "Could not find Class " + result
+ " from JNDI lookup for name " + name, cnfe);
}
}
else
{
// we have a value, but the value does not fit
LOG.log(Level.SEVERE, "JNDI lookup for key " + name + " should return a value of "
+ targetType + ", but returned " + result);
}
}
return null;
}
/**
* Resolves an instances for the given naming context.
*
* @param name context name
* @param type target type
* @param <T> type
* @return the found instances, null otherwise
*/
public static <T> Map<String, T> list(String name, Class<T> type)
{
Map<String, T> result = new HashMap<String, T>();
try
{
NameParser nameParser = initialContext.getNameParser(name);
NamingEnumeration<NameClassPair> enumeration = initialContext.list(name);
while (enumeration.hasMoreElements())
{
try
{
NameClassPair binding = enumeration.nextElement();
Name bindingName = nameParser.parse(name).add(binding.getName());
result.put(binding.getName(), lookup(bindingName, type));
}
catch (NamingException e)
{
if (LOG.isLoggable(Level.FINEST))
{
// this is expected if there is no entry in JNDI for the requested name or type
// so finest level is ok, if devs want to see it they can enable this logger level.
LOG.log(Level.FINEST, "InitialContext#list failed!", e);
}
}
}
}
catch (NamingException e)
{
// this is fine at this point, since the individual lines will be caught currently.
LOG.log(Level.WARNING,"Problem reading the name of the JNDI location " + name
+ " or failuring listing pairs.",e);
}
return result;
}
}