/*
* RHQ Management Platform
* Copyright (C) 2005-2012 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.rhq.enterprise.server.naming;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Set;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.spi.InitialContextFactory;
import org.rhq.enterprise.server.naming.context.ContextDecorator;
import org.rhq.enterprise.server.naming.util.DecoratingInvocationHandler;
import org.rhq.enterprise.server.naming.util.DecoratorPicker;
/**
* This class implements an initial context factory that decorates the contexts
* returned from a "wrapped" initial factory passed to this class in the constructor.
* <p>
* The contexts returned from the wrapped initial factory are hidden behind a proxy
* that implements the intersection of interfaces from the <code>supportedContextInterfaces</code>
* constructor parameter and the actual interfaces the wrapped context implements.
* <p>
* The proxy method calls are handled using the {@link DecoratingInvocationHandler} which is initialized
* with the list of {@link DecoratorPicker pickers} that are used to intercept the method
* calls on the wrapped context.
*
* @see DecoratorPicker
* @see DecoratingInvocationHandler
*
* @author Lukas Krejci
*/
public class DecoratingInitialContextFactory implements InitialContextFactory {
List<DecoratorPicker<Context, ContextDecorator>> pickers;
private InitialContextFactory factory;
private Set<Class<? extends Context>> supportedContextInterfaces;
public DecoratingInitialContextFactory(InitialContextFactory factory, List<DecoratorPicker<Context, ContextDecorator>> decoratorPickers) {
this.factory = factory;
this.pickers = decoratorPickers;
this.supportedContextInterfaces = new HashSet<Class<? extends Context>>();
for(DecoratorPicker<Context, ContextDecorator> picker : pickers) {
supportedContextInterfaces.addAll(picker.getContext().getSupportedInterfaces());
}
}
public Context getInitialContext(Hashtable<?, ?> environment) throws NamingException {
Context ctx = factory.getInitialContext(environment);
Set<Class<?>> implementedIfaces = getAllImplementedInterfaces(ctx.getClass());
Class<?>[] ii = new Class<?>[implementedIfaces.size()];
implementedIfaces.toArray(ii);
return (Context) Proxy.newProxyInstance(ctx.getClass().getClassLoader(), ii, new DecoratingInvocationHandler<Context, ContextDecorator>(pickers, ctx));
}
private Set<Class<?>> getAllImplementedInterfaces(Class<?> cls) {
HashSet<Class<?>> ret = new HashSet<Class<?>>();
getAllImplementedInterfaces(cls, ret);
ret.retainAll(supportedContextInterfaces);
return ret;
}
private static void getAllImplementedInterfaces(Class<?> cls, Set<Class<?>> output) {
Class<?>[] ifaces = cls.getInterfaces();
for (Class<?> iface : Arrays.asList(ifaces)) {
output.add(iface);
getAllImplementedInterfaces(iface, output);
}
if (cls.getSuperclass() != null) {
getAllImplementedInterfaces(cls.getSuperclass(), output);
}
}
@Override
public int hashCode() {
return factory.hashCode();
}
@Override
public boolean equals(Object o) {
return factory.equals(o);
}
}