/**
* Copyright (C) 2013 Kametic <epo.jemba@kametic.com>
*
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE, Version 3, 29 June 2007;
* or any later version
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.gnu.org/licenses/lgpl-3.0.txt
*
* 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.nuunframework.kernel.context;
import static com.google.common.base.Predicates.not;
import java.lang.annotation.Annotation;
import java.net.URL;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.nuunframework.kernel.Kernel;
import org.nuunframework.kernel.KernelException;
import org.nuunframework.kernel.annotations.KernelModule;
import org.nuunframework.kernel.commons.specification.Specification;
import org.nuunframework.kernel.commons.specification.reflect.DescendantOfSpecification;
import org.nuunframework.kernel.internal.scanner.ClasspathScanner;
import org.nuunframework.kernel.internal.scanner.ClasspathScanner.Callback;
import org.nuunframework.kernel.internal.scanner.ClasspathScanner.CallbackResources;
import org.nuunframework.kernel.internal.scanner.ClasspathScannerFactory;
import org.nuunframework.kernel.internal.scanner.ClasspathStrategy;
import org.nuunframework.kernel.plugin.Plugin;
import org.nuunframework.kernel.plugin.request.RequestType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.FluentIterable;
import com.google.inject.Module;
import com.google.inject.Scopes;
@SuppressWarnings("rawtypes")
public class InitContextInternal implements InitContext
{
private Logger logger = LoggerFactory.getLogger(InitContextInternal.class);
ClasspathScanner classpathScanner;
private List<Class<?>> parentTypesClassesToScan;
private List<Class<?>> ancestorTypesClassesToScan;
private List<Class<?>> typesClassesToScan;
private List<String> typesRegexToScan;
private List<Specification<Class<?>>> specificationsToScan;
private List<String> resourcesRegexToScan;
private List<String> parentTypesRegexToScan;
private List<Class<? extends Annotation>> annotationTypesToScan;
private List<String> annotationRegexToScan;
private List<Class<?>> parentTypesClassesToBind;
private List<Class<?>> ancestorTypesClassesToBind;
private List<String> parentTypesRegexToBind;
private List<Specification<Class<?>>> specificationsToBind;
private Map<Key , Object> mapOfScopes;
private List<Class<? extends Annotation>> annotationTypesToBind;
private List<Class<? extends Annotation>> metaAnnotationTypesToBind;
private List<String> annotationRegexToBind;
private List<String> metaAnnotationRegexToBind;
private List<String> propertiesPrefix;
private List<Module> childModules;
private List<Module> childOverridingModules;
private List<String> packageRoots;
private Set<URL> additionalClasspathScan;
private ClasspathStrategy classpathStrategy;
private Set<Class<?>> classesToBind;
private Map<Class<?> , Object> classesWithScopes;
private Collection<String> propertiesFiles;
private Map<String, String> kernelParams;
private Collection<Class<?>> scanClasspathForSubType;
private Collection<Class<?>> scanClasspathForAncestorType;
private Collection<Class<?>> bindClasspathForSubType;
private Collection<Class<?>> bindClasspathForAncestorType;
private Map<Class<?>, Collection<Class<?>>> mapSubTypes;
private Map<Class<?>, Collection<Class<?>>> mapAncestorTypes;
private Map<String, Collection<Class<?>>> mapSubTypesByName;
private Map<String, Collection<Class<?>>> mapTypesByName;
private Map<Specification, Collection<Class<?>>> mapTypesBySpecification;
private Map<Class<? extends Annotation>, Collection<Class<?>>> mapAnnotationTypes;
private Map<String, Collection<Class<?>>> mapAnnotationTypesByName;
private Map<String, Collection<String>> mapPropertiesFiles;
private Map<String, Collection<String>> mapResourcesByRegex;
private String initialPropertiesPrefix;
private int roundNumber = 0;
/**
* @param inPackageRoots
*/
public InitContextInternal(String initialPropertiesPrefix, Map<String, String> kernelParams)
{
String classpathStrategyNameParam = kernelParams.get(Kernel.NUUN_CP_STRATEGY_NAME);
String classpathStrategyAdditionalParam = kernelParams.get(Kernel.NUUN_CP_STRATEGY_ADD);
this.classpathStrategy = new ClasspathStrategy(
classpathStrategyNameParam == null ? ClasspathStrategy.Strategy.ALL : ClasspathStrategy.Strategy.valueOf(classpathStrategyNameParam.toUpperCase()),
classpathStrategyAdditionalParam == null ? true : Boolean.parseBoolean(classpathStrategyAdditionalParam));
this.packageRoots = new LinkedList<String>();
this.initialPropertiesPrefix = initialPropertiesPrefix;
this.kernelParams = kernelParams;
this.childModules = new LinkedList<Module>();
this.childOverridingModules = new LinkedList<Module>();
classesToBind = new HashSet<Class<?>>();
classesWithScopes = new HashMap<Class<?>, Object>();
reset();
}
public void reset()
{
this.mapSubTypes = new HashMap<Class<?>, Collection<Class<?>>>();
this.mapAncestorTypes = new HashMap<Class<?>, Collection<Class<?>>>();
this.mapSubTypesByName = new HashMap<String, Collection<Class<?>>>();
this.mapTypesByName = new HashMap<String, Collection<Class<?>>>();
this.mapTypesBySpecification = new HashMap<Specification, Collection<Class<?>>>();
this.mapAnnotationTypes = new HashMap<Class<? extends Annotation>, Collection<Class<?>>>();
this.mapAnnotationTypesByName = new HashMap<String, Collection<Class<?>>>();
this.mapPropertiesFiles = new HashMap<String, Collection<String>>();
this.mapResourcesByRegex = new HashMap<String, Collection<String>>();
this.annotationTypesToScan = new LinkedList<Class<? extends Annotation>>();
this.parentTypesClassesToScan = new LinkedList<Class<?>>();
this.ancestorTypesClassesToScan = new LinkedList<Class<?>>();
this.typesClassesToScan = new LinkedList<Class<?>>();
this.typesRegexToScan = new LinkedList<String>();
this.specificationsToScan = new LinkedList<Specification<Class<?>>>();
this.resourcesRegexToScan = new LinkedList<String>();
this.parentTypesRegexToScan = new LinkedList<String>();
this.annotationRegexToScan = new LinkedList<String>();
this.annotationTypesToBind = new LinkedList<Class<? extends Annotation>>();
this.metaAnnotationTypesToBind = new LinkedList<Class<? extends Annotation>>();
this.parentTypesClassesToBind = new LinkedList<Class<?>>();
this.ancestorTypesClassesToBind = new LinkedList<Class<?>>();
this.parentTypesRegexToBind = new LinkedList<String>();
this.specificationsToBind = new LinkedList<Specification<Class<?>>>();
this.mapOfScopes = new HashMap<Key, Object>();
this.annotationRegexToBind = new LinkedList<String>();
this.metaAnnotationRegexToBind = new LinkedList<String>();
this.propertiesPrefix = new LinkedList<String>();
this.propertiesPrefix.add(initialPropertiesPrefix);
this.additionalClasspathScan = new HashSet<URL>();
}
private void initScanner()
{
String[] rawArrays = new String[this.packageRoots.size()];
this.packageRoots.toArray(rawArrays);
this.classpathScanner = new ClasspathScannerFactory().create(this.classpathStrategy, this.additionalClasspathScan , rawArrays);
}
class IsModuleOverriding implements Predicate<Class<? extends Module>>
{
@Override
public boolean apply(Class<? extends Module> input)
{
KernelModule annotation = input.getAnnotation(KernelModule.class);
return annotation.overriding();
}
}
class ModuleClass2Instance implements Function<Class<? extends Module>, Module>
{
/*
* (non-Javadoc)
* @see com.google.common.base.Function#apply(java.lang.Object)
*/
@Override
public Module apply(Class<? extends Module> classpathClass)
{
try
{
return (Module) classpathClass.newInstance();
}
catch (InstantiationException e)
{
logger.warn("Error when instantiating module " + classpathClass, e);
}
catch (IllegalAccessException e)
{
logger.warn("Error when instantiating module " + classpathClass, e);
}
return null;
}
}
public void executeRequests()
{
initScanner();
{ // bind modules
Callback callback = new Callback()
{ // executed only after the classpath scan occurs
@Override
public void callback(Collection<Class<? >> scanResult)
{
Collection<Class<? extends Module>> scanResult2 = (Collection) scanResult;
FluentIterable<Module> nominals = FluentIterable.from(scanResult2).filter( not(new IsModuleOverriding()) ).transform(new ModuleClass2Instance());
FluentIterable<Module> overriders = FluentIterable.from(scanResult2).filter( new IsModuleOverriding() ).transform(new ModuleClass2Instance());
childModules.addAll(nominals.toImmutableSet());
childOverridingModules.addAll(overriders.toImmutableSet());
}
};
this.classpathScanner.scanClasspathForAnnotation(KernelModule.class , callback); // OK
}
// CLASSES TO SCAN
for (final Class<?> parentType : this.parentTypesClassesToScan)
{
Callback callback = new Callback()
{ // executed only after the classpath scan occurs
@Override
public void callback(Collection<Class<?>> scanResult)
{
mapSubTypes.put(parentType, scanResult);
}
};
this.classpathScanner.scanClasspathForSubTypeClass(parentType , callback); // OK
}
for (final Class<?> parentType : this.ancestorTypesClassesToScan)
{
Callback callback = new Callback()
{ // executed only after the classpath scan occurs
@Override
public void callback(Collection<Class<?>> scanResult)
{
mapAncestorTypes.put(parentType, scanResult);
}
};
this.classpathScanner.scanClasspathForSpecification(new DescendantOfSpecification(parentType) , callback); // ok
}
// for (Class<?> type : this.typesClassesToScan)
// {
// scanClasspathForSubType = this.classpathScanner.scanClasspathForTypeClass(type);
// // clässes.addAll(scanClasspathForSubType);
// this.mapTypes.put(type, scanClasspathForSubType);
// }
for (final String typeName : this.parentTypesRegexToScan)
{
Callback callback = new Callback()
{ // executed only after the classpath scan occurs
@Override
public void callback(Collection<Class<?>> scanResult)
{
mapSubTypesByName.put(typeName, scanResult);
}
};
this.classpathScanner.scanClasspathForSubTypeRegex(typeName, callback); // OK
}
for (final String typeName : this.typesRegexToScan)
{
Callback callback = new Callback()
{ // executed only after the classpath scan occurs
@Override
public void callback(Collection<Class<?>> scanResult)
{
mapTypesByName.put(typeName, scanResult);
}
};
this.classpathScanner.scanClasspathForTypeRegex(typeName, callback); // OK
}
for (final Specification<Class<?>> spec : this.specificationsToScan)
{
Callback callback = new Callback()
{ // executed only after the classpath scan occurs
@Override
public void callback(Collection<Class<?>> scanResult)
{
mapTypesBySpecification.put(spec, scanResult);
}
};
this.classpathScanner.scanClasspathForSpecification(spec, callback); // OK
}
for (final Class<? extends Annotation> annotationType : this.annotationTypesToScan)
{
Callback callback = new Callback()
{ // executed only after the classpath scan occurs
@Override
public void callback(Collection<Class<?>> scanResult)
{
mapAnnotationTypes.put(annotationType, scanResult);
}
};
this.classpathScanner.scanClasspathForAnnotation(annotationType , callback);// ok
}
for (final String annotationName : this.annotationRegexToScan)
{
Callback callback = new Callback()
{ // executed only after the classpath scan occurs
@Override
public void callback(Collection<Class<?>> scanResult)
{
mapAnnotationTypesByName.put(annotationName, scanResult);
}
};
this.classpathScanner.scanClasspathForAnnotationRegex(annotationName,callback); // ok
}
// CLASSES TO BIND
// ===============
for (final Class<?> parentType : this.parentTypesClassesToBind)
{
Callback callback = new Callback()
{ // executed only after the classpath scan occurs
@Override
public void callback(Collection<Class<?>> scanResult)
{
RequestType requestType = RequestType.SUBTYPE_OF_BY_CLASS;
addScopeToClasses( scanResult , scope(requestType , parentType ) , classesWithScopes);
classesToBind.addAll(scanResult);
}
};
this.classpathScanner.scanClasspathForSubTypeClass(parentType , callback); // OK
}
for (final Class<?> ancestorType : this.ancestorTypesClassesToBind)
{
Callback callback = new Callback()
{ // executed only after the classpath scan occurs
@Override
public void callback(Collection<Class<?>> scanResult)
{
RequestType requestType = RequestType.SUBTYPE_OF_BY_TYPE_DEEP;
addScopeToClasses( scanResult , scope(requestType , ancestorType ) , classesWithScopes);
classesToBind.addAll(scanResult);
}
};
this.classpathScanner.scanClasspathForSpecification(new DescendantOfSpecification(ancestorType) , callback); // OK
}
// TODO vérifier si ok parent types vs type. si ok changer de nom
for (final String typeName : this.parentTypesRegexToBind)
{
Callback callback = new Callback()
{ // executed only after the classpath scan occurs
@Override
public void callback(Collection<Class<?>> scanResult)
{
RequestType requestType = RequestType.SUBTYPE_OF_BY_REGEX_MATCH;
addScopeToClasses( scanResult , scope(requestType , typeName ) , classesWithScopes);
classesToBind.addAll(scanResult);
}
};
this.classpathScanner.scanClasspathForTypeRegex(typeName,callback); // ok
}
for (final Specification<Class<?>> spec : this.specificationsToBind)
{
Callback callback = new Callback()
{ // executed only after the classpath scan occurs
@Override
public void callback(Collection<Class<?>> scanResult)
{
RequestType requestType = RequestType.VIA_SPECIFICATION;
addScopeToClasses(scanResult, scope(requestType , spec ) , classesWithScopes);
classesToBind.addAll(scanResult);
}
};
this.classpathScanner.scanClasspathForSpecification(spec,callback); // ok
}
for (final Class<? extends Annotation> annotationType : this.annotationTypesToBind)
{
Callback callback = new Callback()
{ // executed only after the classpath scan occurs
@Override
public void callback(Collection<Class<?>> scanResult)
{
RequestType requestType = RequestType.ANNOTATION_TYPE;
addScopeToClasses( scanResult , scope(requestType , annotationType ) , classesWithScopes);
classesToBind.addAll(scanResult);
}
};
this.classpathScanner.scanClasspathForAnnotation(annotationType,callback); // OK
}
for (final Class<? extends Annotation> metaAnnotationType : this.metaAnnotationTypesToBind)
{
Callback callback = new Callback()
{ // executed only after the classpath scan occurs
@Override
public void callback(Collection<Class<?>> scanResult)
{
RequestType requestType = RequestType.META_ANNOTATION_TYPE;
addScopeToClasses( scanResult , scope(requestType , metaAnnotationType ) , classesWithScopes);
classesToBind.addAll(scanResult);
}
};
this.classpathScanner.scanClasspathForMetaAnnotation(metaAnnotationType,callback); // ok
}
for (final String annotationNameRegex : this.annotationRegexToBind)
{
Callback callback = new Callback()
{ // executed only after the classpath scan occurs
@Override
public void callback(Collection<Class<?>> scanResult)
{
RequestType requestType = RequestType.ANNOTATION_REGEX_MATCH;
addScopeToClasses( scanResult , scope(requestType , annotationNameRegex ) , classesWithScopes);
classesToBind.addAll(scanResult);
}
};
this.classpathScanner.scanClasspathForAnnotationRegex(annotationNameRegex,callback); // ok
}
for (final String metaAnnotationNameRegex : this.metaAnnotationRegexToBind)
{
Callback callback = new Callback()
{ // executed only after the classpath scan occurs
@Override
public void callback(Collection<Class<?>> scanResult)
{
RequestType requestType = RequestType.META_ANNOTATION_REGEX_MATCH;
addScopeToClasses( scanResult , scope(requestType , metaAnnotationNameRegex ) , classesWithScopes);
classesToBind.addAll(scanResult);
}
};
this.classpathScanner.scanClasspathForMetaAnnotationRegex(metaAnnotationNameRegex,callback); // ok
}
// Resources to scan
for (final String regex : this.resourcesRegexToScan)
{
CallbackResources callback = new CallbackResources()
{
@Override
public void callback(Collection<String> scanResult)
{
mapResourcesByRegex.put(regex, scanResult);
}
};
this.classpathScanner.scanClasspathForResource(regex , callback); // OK
}
// PROPERTIES TO FETCH
propertiesFiles = new HashSet<String>();
for (final String prefix : this.propertiesPrefix)
{
CallbackResources callback = new CallbackResources()
{ // executed only after the classpath scan occurs
@Override
public void callback(Collection<String> scanResult)
{
propertiesFiles.addAll(scanResult);
mapPropertiesFiles.put(prefix, scanResult);
}
};
this.classpathScanner.scanClasspathForResource(prefix + ".*\\.properties" , callback); // OK
}
// ACTUALLY LAUNCH THE SEARCH
this.classpathScanner.doClasspathScan();
}
private Object scope( RequestType requestType , Object spec)
{
Object scope = this.mapOfScopes.get( key( requestType , spec));
if (null == scope) scope = Scopes.NO_SCOPE;
return scope;
}
private void addScopeToClasses(Collection<Class<?>> classes , Object scope, Map<Class<?>, Object> inClassesWithScopes)
{
for (Class<?> klass : classes)
{
if (!inClassesWithScopes.containsKey(klass) && scope != null )
{
inClassesWithScopes.put(klass, scope);
}
else
{
Object insideScope = inClassesWithScopes.get(klass);
if ( ! insideScope.equals(scope))
{
String format = String.format("Class %s is already associated with scope %s but %s", klass.getName() , insideScope , scope );
logger.error(format);
throw new KernelException(format);
}
}
}
}
public void addClasspathsToScan(Set<URL> paths)
{
if (paths != null && paths.size() > 0)
{
this.additionalClasspathScan.addAll( paths );
}
}
public void addClasspathToScan(URL path)
{
if (path != null )
{
this.additionalClasspathScan.add( path );
}
}
@Override
public Map<Class<?>, Collection<Class<?>>> scannedSubTypesByParentClass()
{
return Collections.unmodifiableMap(this.mapSubTypes);
}
@Override
public Map<Class<?>, Collection<Class<?>>> scannedSubTypesByAncestorClass()
{
return Collections.unmodifiableMap(this.mapAncestorTypes);
}
@Override
public Map<String, Collection<Class<?>>> scannedSubTypesByParentRegex()
{
return Collections.unmodifiableMap(this.mapSubTypesByName);
}
@Override
public Map<String, Collection<Class<?>>> scannedTypesByRegex()
{
return Collections.unmodifiableMap(this.mapTypesByName);
}
@Override
public Map<Specification, Collection<Class<?>>> scannedTypesBySpecification()
{
return Collections.unmodifiableMap(this.mapTypesBySpecification);
}
@Override
public Map<Class<? extends Annotation>, Collection<Class<?>>> scannedClassesByAnnotationClass()
{
return Collections.unmodifiableMap(this.mapAnnotationTypes);
}
@Override
public Map<String, Collection<Class<?>>> scannedClassesByAnnotationRegex()
{
return Collections.unmodifiableMap(this.mapAnnotationTypesByName);
}
@Override
public Map<String, Collection<String>> mapPropertiesFilesByPrefix()
{
return Collections.unmodifiableMap(this.mapPropertiesFiles);
}
@Override
public Map<String, Collection<String>> mapResourcesByRegex()
{
return Collections.unmodifiableMap(this.mapResourcesByRegex);
}
public void addPropertiesPrefix(String prefix)
{
this.propertiesPrefix.add(prefix);
}
public void addPackageRoot(String root)
{
this.packageRoots.add(root);
}
public void addParentTypeClassToScan(Class<?> type)
{
this.parentTypesClassesToScan.add(type);
}
public void addAncestorTypeClassToScan(Class<?> type)
{
this.ancestorTypesClassesToScan.add(type);
}
public void addResourcesRegexToScan(String regex)
{
this.resourcesRegexToScan.add(regex);
}
public void addTypeClassToScan(Class<?> type)
{
this.typesClassesToScan.add(type);
}
private Key key(RequestType type , Object key)
{
return new Key(type, key);
}
public void addParentTypeClassToBind(Class<?> type , Object scope)
{
updateScope(key ( RequestType.SUBTYPE_OF_BY_CLASS , type), scope);
this.parentTypesClassesToBind.add(type);
}
public void addAncestorTypeClassToBind(Class<?> type , Object scope)
{
updateScope(key ( RequestType.SUBTYPE_OF_BY_TYPE_DEEP , type), scope);
this.ancestorTypesClassesToBind.add(type);
}
public void addTypeRegexesToScan(String type)
{
this.typesRegexToScan.add(type);
}
public void addSpecificationToScan(Specification<Class<?>> specification)
{
this.specificationsToScan.add(specification);
}
public void addParentTypeRegexesToScan(String type)
{
this.parentTypesRegexToScan.add(type);
}
public void addTypeRegexesToBind(String type , Object scope)
{
updateScope(key ( RequestType.TYPE_OF_BY_REGEX_MATCH, type), scope);
this.parentTypesRegexToBind.add(type);
}
/**
* @category bind
* @param specification
*/
// public void addSpecificationToBind(Specification<Class<?>> specification)
// {
// this.specificationsToBind.add(specification);
// this.mapSpecificationScope.put(specification, Scopes.NO_SCOPE);
// }
private void updateScope ( Key key , Object scope)
{
if (scope != null)
{
this.mapOfScopes.put(key, scope);
}
else
{
this.mapOfScopes.put(key, Scopes.NO_SCOPE);
}
}
public void addSpecificationToBind(Specification<Class<?>> specification , Object scope)
{
this.specificationsToBind.add(specification);
updateScope(key ( RequestType.VIA_SPECIFICATION , specification), scope);
}
public void addAnnotationTypesToScan(Class<? extends Annotation> types)
{
this.annotationTypesToScan.add(types);
}
public void addAnnotationTypesToBind(Class<? extends Annotation> types , Object scope)
{
this.annotationTypesToBind.add(types);
updateScope(key ( RequestType.ANNOTATION_TYPE , types), scope);
}
public void addMetaAnnotationTypesToBind(Class<? extends Annotation> types , Object scope)
{
this.metaAnnotationTypesToBind.add(types);
updateScope(key ( RequestType.META_ANNOTATION_TYPE , types), scope);
}
public void addAnnotationRegexesToScan(String names)
{
this.annotationRegexToScan.add(names);
}
public void addAnnotationRegexesToBind(String names, Object scope)
{
this.annotationRegexToBind.add(names);
updateScope(key ( RequestType.ANNOTATION_REGEX_MATCH , names), scope);
}
public void addMetaAnnotationRegexesToBind(String names, Object scope)
{
this.metaAnnotationRegexToBind.add(names);
updateScope(key ( RequestType.META_ANNOTATION_REGEX_MATCH, names), scope);
}
public void addChildModule(Module module)
{
this.childModules.add(module);
}
public void addChildOverridingModule(Module module)
{
this.childOverridingModules.add(module);
}
// public void setContainerContext(Object containerContext)
// {
// this.containerContext = containerContext;
// }
// INTERFACE KERNEL PARAM USED BY PLUGIN IN INIT //
// public Object containerContext()
// {
// return this.containerContext;
// }
@Override
public String getKernelParam(String key)
{
return kernelParams.get(key);
}
@Override
@SuppressWarnings({
"unchecked"
})
public Collection<Class<?>> classesToBind()
{
return (Collection) Collections.unmodifiableSet(this.classesToBind);
}
@SuppressWarnings({"unchecked"})
public Map<Class<?> , Object> classesWithScopes ()
{
return (Map) Collections.unmodifiableMap(classesWithScopes );
}
@Override
@SuppressWarnings({
"unchecked"
})
public List<Module> moduleResults()
{
return (List) Collections.unmodifiableList(this.childModules);
}
@Override
@SuppressWarnings({
"unchecked"
})
public List<Module> moduleOverridingResults()
{
return (List) Collections.unmodifiableList(this.childOverridingModules);
}
@SuppressWarnings({
"unchecked"
})
@Override
public Collection<String> propertiesFiles()
{
return (Collection) Collections.unmodifiableCollection(this.propertiesFiles);
}
@Override
public Collection<? extends Plugin> pluginsRequired()
{
return Collections.emptySet();
}
public Collection<? extends Plugin> dependentPlugins ()
{
return Collections.emptySet();
}
@Override
public int roundNumber()
{
return this.roundNumber;
}
public void roundNumber(int roundNumber)
{
this.roundNumber = roundNumber;
}
static class Key
{
private final RequestType type;
private final Object key;
public Key(RequestType type , Object key)
{
this.type = type;
this.key = key;
}
@Override
public boolean equals(Object obj)
{
Key key2 = (Key)obj;
return new EqualsBuilder().append(this.type, key2.type ).append( this.key, key2.key).isEquals() ;
}
@Override
public int hashCode()
{
return new HashCodeBuilder().append(this.type).append( this.key).toHashCode();
}
}
}