/*
* XAdES4j - A Java library for generation and verification of XAdES signatures.
* Copyright (C) 2010 Luis Goncalves.
*
* XAdES4j is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 3 of the License, or any later version.
*
* XAdES4j 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 Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with XAdES4j. If not, see <http://www.gnu.org/licenses/>.
*/
package xades4j.utils;
import com.google.inject.Binder;
import com.google.inject.Guice;
import com.google.inject.Key;
import com.google.inject.Module;
import com.google.inject.TypeLiteral;
import com.google.inject.multibindings.MapBinder;
import com.google.inject.multibindings.Multibinder;
import com.google.inject.util.Modules;
import com.google.inject.util.Types;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
/**
* Helper class that implements the core logic of profile resolution based on a series
* of dependencies. Profile resultion is based on Google's dependency container
* (Guice).
* @see xades4j.production.XadesSigningProfile
* @see xades4j.verification.XadesVerificationProfile
* @see xades4j.production.XadesFormatExtenderProfile
* @author Luís
*/
public final class XadesProfileCore
{
private static interface BindingAction
{
void bind(Binder b);
}
/**/
private final Collection<BindingAction> bindings;
public XadesProfileCore()
{
this.bindings = new ArrayList<BindingAction>();
}
/**
* @throws NullPointerException if {@code from} or {@code to} are null
*/
public <T> void addBinding(final Class<T> from, final Class<? extends T> to)
{
if (null == from || null == to)
throw new NullPointerException();
this.bindings.add(new BindingAction()
{
@Override
public void bind(Binder b)
{
b.bind(from).to(to);
}
});
}
/**
* @throws NullPointerException if {@code from} or {@code to} are null
*/
public <T> void addBinding(final Class<T> from, final T to)
{
if (null == from || null == to)
throw new NullPointerException();
this.bindings.add(new BindingAction()
{
@Override
public void bind(Binder b)
{
b.bind(from).toInstance(to);
}
});
}
public void addGenericBinding(
final Type genericClass,
final Class to,
final Type... genericClassParams)
{
if (ObjectUtils.anyNull(genericClass, genericClassParams, to))
throw new NullPointerException();
this.bindings.add(new BindingAction()
{
@Override
public void bind(Binder b)
{
ParameterizedType pt = Types.newParameterizedType(genericClass, genericClassParams);
Key k = Key.get(TypeLiteral.get(pt));
b.bind(k).to(to);
}
});
}
public void addGenericBinding(
final Type genericClass,
final Object to,
final Type... genericClassParams)
{
if (ObjectUtils.anyNull(genericClass, genericClassParams, to))
throw new NullPointerException();
this.bindings.add(new BindingAction()
{
@Override
public void bind(Binder b)
{
ParameterizedType pt = Types.newParameterizedType(genericClass, genericClassParams);
Key k = Key.get(TypeLiteral.get(pt));
b.bind(k).toInstance(to);
}
});
}
public <T> void addMultibinding(final Class<T> from, final Class<? extends T> to)
{
if (null == from || null == to)
throw new NullPointerException();
this.bindings.add(new BindingAction()
{
@Override
public void bind(Binder b)
{
Multibinder multibinder = Multibinder.newSetBinder(b, from);
multibinder.addBinding().to(to);
}
});
}
public <T> void addMultibinding(final Class<T> from, final T to)
{
if (null == from || null == to)
throw new NullPointerException();
this.bindings.add(new BindingAction()
{
@Override
public void bind(Binder b)
{
Multibinder multibinder = Multibinder.newSetBinder(b, from);
multibinder.addBinding().toInstance(to);
}
});
}
public <T, TV extends T> void addMapBinding(final Class<T> valueClass, final Object key, final TV value)
{
if (null == key || null == value)
throw new NullPointerException();
this.bindings.add(new BindingAction()
{
@Override
public void bind(Binder b)
{
MapBinder mapBinder = MapBinder.newMapBinder(b, key.getClass(), valueClass);
mapBinder.addBinding(key).toInstance(value);
}
});
}
public <T> void addMapBinding(final Class<T> valueClass, final Object key, final Class<? extends T> to)
{
if (null == key || null == to)
throw new NullPointerException();
this.bindings.add(new BindingAction()
{
@Override
public void bind(Binder b)
{
MapBinder mapBinder = MapBinder.newMapBinder(b, key.getClass(), valueClass);
mapBinder.addBinding(key).to(to);
}
});
}
public <T> T getInstance(
Class<T> clazz,
Module[] overridableModules,
Module[] sealedModules) throws XadesProfileResolutionException
{
Module userBindingsModule = new Module()
{
@Override
public void configure(Binder b)
{
for (BindingAction ba : bindings)
{
ba.bind(b);
}
}
};
Module overridesModule = Modules.override(overridableModules).with(userBindingsModule);
// Concat sealed modules with overrides module
Module[] finalModules = Arrays.copyOf(sealedModules, sealedModules.length + 1);
finalModules[finalModules.length - 1] = overridesModule;
try
{
return Guice.createInjector(finalModules).getInstance(clazz);
}
catch (RuntimeException ex)
{
throw new XadesProfileResolutionException(ex.getMessage(), ex);
}
}
}