Skip to content

Commit

Permalink
Fix alias and mandatory params
Browse files Browse the repository at this point in the history
AliasMap is no more a map, but instead comuptes an immutable map
  • Loading branch information
pith committed Mar 7, 2016
1 parent f7cfbdd commit fbe924c
Show file tree
Hide file tree
Showing 5 changed files with 302 additions and 53 deletions.
91 changes: 52 additions & 39 deletions core/src/main/java/io/nuun/kernel/core/internal/AliasMap.java
@@ -1,73 +1,86 @@
package io.nuun.kernel.core.internal;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import io.nuun.kernel.core.KernelException;

import java.util.*;

/**
*
*
* @author epo.jemba{@literal @}kametic.com
*/
public class AliasMap extends HashMap<String, String>
public class AliasMap
{
private static final long serialVersionUID = 1L;
Map<String, String> aliases = new HashMap<String, String>();
private Map<String, String> aliases = new HashMap<String, String>();
private Map<String, String> params = new HashMap<String, String>();

/**
* @param key
* the key to alias.
* @param alias
* the alias to give to the key.
* @return
* @param key the key to alias.
* @param alias the alias to give to the key.
* @return the previous alias corresponding the key
*/
public String putAlias(String key, String alias)
public String putAlias(String alias, String key)
{
if (super.containsKey(alias))
if (aliases.containsKey(key))
{
throw new IllegalArgumentException("alias " + alias + " already exists in map.");
throw new IllegalArgumentException("The key \"" + key + "\" to alias is already present in the kernel parameters.");
}
return aliases.put(alias, key);
return aliases.put(key, alias);
}

public String get(String key)
{
List<String> cache = new ArrayList<String>();
return getWithAlias(key, cache);
}

@Override
public String get(Object key)
private String getWithAlias(String key, List<String> cache)
{
String keyAlias = aliases.get(key);
if (keyAlias == null)
if (cache.contains(key))
{
return super.get(key);
throw new KernelException("Cycle detected in kernel parameter aliases.");
}
else
cache.add(key);
String alias = aliases.get(key);
if (alias == null)
{
return super.get(keyAlias);
return params.get(key);
} else
{
return getWithAlias(alias, cache);
}
}

public boolean containsAllKeys(Collection<String> computedMandatoryParams)
public String put(String key, String value)
{
HashSet<String> allKeys = new HashSet<String>();
allKeys.addAll(keySet());
allKeys.addAll(aliases.values());
return params.put(key, value);
}

Collection<String> trans = new HashSet<String>();
for (String s : computedMandatoryParams)
public Map<String, String> toMap()
{
Map<String, String> map = new HashMap<String, String>(params);
for (Map.Entry<String, String> entry : aliases.entrySet())
{
String string = aliases.get(s);
if (string != null)
String alias = entry.getKey();
String paramKey = entry.getValue();
map.put(alias, get(paramKey));
}
return Collections.unmodifiableMap(map);
}

public boolean containsAllKeys(Collection<String> keys)
{
for (String key : keys)
{
if (!containsKey(key))
{
trans.add(string);
return false;
}
}

return allKeys.containsAll(trans);
return true;
}

@Override
public boolean containsKey(Object key)
public boolean containsKey(String key)
{
return aliases.containsKey(key) ? true : super.containsKey(key);
return aliases.containsKey(key) || params.containsKey(key);
}

}
20 changes: 13 additions & 7 deletions core/src/main/java/io/nuun/kernel/core/internal/KernelCore.java
Expand Up @@ -73,7 +73,7 @@ public final class KernelCore implements Kernel
this.name = KERNEL_PREFIX_NAME + kernelIndex.getAndIncrement();
this.logger = LoggerFactory.getLogger(KernelCore.class.getName() + ' ' + name());
this.kernelConfig = kernelConfigurationInternal;
this.requestHandler = new RequestHandler(kernelConfig.kernelParams(), kernelConfig.getClasspathScanMode());
this.requestHandler = new RequestHandler(kernelConfig.kernelParams().toMap(), kernelConfig.getClasspathScanMode());
this.moduleHandler = new ModuleHandler(kernelConfig);
}

Expand All @@ -85,6 +85,7 @@ public synchronized void init()
throw new KernelException("Kernel is already initialized");
}
preparePlugins();
validateMandatoryParams();
fetchPackageRootsFromConfiguration();
extensionManager = new ExtensionManager(pluginRegistry.getPlugins(), Thread.currentThread().getContextClassLoader());
extensionManager.initializing();
Expand All @@ -102,12 +103,10 @@ public void preparePlugins()

round = new RoundInternal();
DependenciesSpecification dependenciesSpecification = new DependenciesSpecification(facetRegistry);
MandatoryParamsSpecification mandatoryParamsSpecification = new MandatoryParamsSpecification();
for (Plugin plugin : pluginRegistry.getPlugins())
{
plugin.provideRound(round);
dependenciesSpecification.isSatisfyBy(plugin);
mandatoryParamsSpecification.isSatisfiedBy(plugin, kernelConfig.kernelParams());
addAliasesToKernelParams(plugin);
fetchGlobalParametersFrom(plugin);
addPackageRootsToRequestHandler(plugin.pluginPackageRoot());
Expand Down Expand Up @@ -149,10 +148,10 @@ private void addAliasesToKernelParams(Plugin plugin)
{
for (Entry<String, String> entry : plugin.kernelParametersAliases().entrySet())
{
String keyToAlias = entry.getKey();
String alias = entry.getValue();
String alias = entry.getKey();
String keyToAlias = entry.getValue();
logger.info("Adding alias parameter \"{}\" to key \"{}\".", keyToAlias, alias);
kernelConfig.kernelParams().putAlias(keyToAlias, alias);
kernelConfig.kernelParams().putAlias(alias, keyToAlias);
}
}

Expand Down Expand Up @@ -211,6 +210,13 @@ private void addPackageRootsToRequestHandler(String pluginPackageRoots)
}
}

private void validateMandatoryParams() {
MandatoryParamsSpecification mandatoryParamsSpecification = new MandatoryParamsSpecification();
for (Plugin plugin : pluginRegistry.getPlugins()) {
mandatoryParamsSpecification.isSatisfiedBy(plugin, kernelConfig.kernelParams());
}
}

private void executeInitializationRounds()
{
logger.info("Initializing");
Expand All @@ -236,7 +242,7 @@ private List<Plugin> callPluginsInitMethod(final List<Plugin> plugins, int round
for (Plugin plugin : plugins)
{
logger.info(" * {} plugin", plugin.name());
InitContext initContext = new InitContextInternal(kernelConfig.kernelParams(), requestHandler, round, dependencyProvider, plugin.getClass());
InitContext initContext = new InitContextInternal(kernelConfig.kernelParams().toMap(), requestHandler, round, dependencyProvider, plugin.getClass());
if (plugin.init(initContext) != InitState.INITIALIZED)
{
nonInitializedPlugins.add(plugin);
Expand Down
Expand Up @@ -10,19 +10,23 @@

public class MandatoryParamsSpecification
{

public void isSatisfiedBy(Plugin plugin, AliasMap kernelParams) {
Collection<KernelParamsRequest> kernelParamsRequests = plugin.kernelParamsRequests();
Collection<String> computedMandatoryParams = new HashSet<String>();
Collection<KernelParamsRequest> requestedParams = plugin.kernelParamsRequests();
Collection<String> mandatoryParams = filterMandatoryParams(requestedParams);

if (!kernelParams.containsAllKeys(mandatoryParams)) {
throw new KernelException("Plugin " + plugin.name() + " misses parameter/s : " + requestedParams.toString());
}
}

private Collection<String> filterMandatoryParams(Collection<KernelParamsRequest> kernelParamsRequests)
{
Collection<String> computedMandatoryParams = new HashSet<String>();
for (KernelParamsRequest kernelParamsRequest : kernelParamsRequests) {
if (kernelParamsRequest.requestType == KernelParamsRequestType.MANDATORY) {
computedMandatoryParams.add(kernelParamsRequest.keyRequested);
}
}

if (!kernelParams.containsAllKeys(computedMandatoryParams)) {
throw new KernelException("Plugin " + plugin.name() + " misses parameter/s : " + kernelParamsRequests.toString());
}
return computedMandatoryParams;
}
}
129 changes: 129 additions & 0 deletions core/src/test/java/io/nuun/kernel/core/internal/AliasMapTest.java
@@ -0,0 +1,129 @@
package io.nuun.kernel.core.internal;

import com.google.common.collect.Lists;
import io.nuun.kernel.core.KernelException;
import org.assertj.core.api.Assertions;
import org.junit.Test;

import static org.assertj.core.data.MapEntry.entry;

/**
* @author Pierre THIROUIN (pierre.thirouin@ext.inetpsa.com)
*/
public class AliasMapTest
{
@Test
public void testAccessNormalParam() throws Exception
{
AliasMap aliasMap = new AliasMap();
aliasMap.put("param", "val1");

Assertions.assertThat(aliasMap.get("param")).isEqualTo("val1");
Assertions.assertThat(aliasMap.containsKey("param")).isTrue();
}

@Test
public void testAliasAKernelParam() throws Exception
{
AliasMap aliasMap = new AliasMap();
aliasMap.put("alias", "val1");
aliasMap.putAlias("alias", "param");

Assertions.assertThat(aliasMap.get("param")).isEqualTo("val1");
Assertions.assertThat(aliasMap.containsAllKeys(Lists.newArrayList("param", "alias"))).isTrue();
}

@Test
public void testCannotAliasAnExistingParameter() throws Exception
{
AliasMap aliasMap = new AliasMap();
try
{
aliasMap.put("param", "val1");
aliasMap.putAlias("alias", "param");
} catch (IllegalArgumentException e)
{
Assertions.assertThat(e).hasMessage("The key \"param\" to alias is already present in the kernel parameters.");

Assertions.assertThat(aliasMap.containsKey("param")).isTrue();
}
}

@Test
public void testContainsKey() throws Exception
{
AliasMap aliasMap = new AliasMap();
Assertions.assertThat(aliasMap.containsKey("foo")).isFalse();
Assertions.assertThat(aliasMap.containsAllKeys(Lists.newArrayList("foo", "bar"))).isFalse();
}

@Test
public void testComputedMapNotNull() throws Exception
{
Assertions.assertThat(new AliasMap().toMap()).isNotNull();
}

@Test
public void testComputedMapContainsParameters() throws Exception
{
final AliasMap aliasMap = new AliasMap();
aliasMap.put("param1", "val1");
aliasMap.put("param2", "val2");
Assertions.assertThat(aliasMap.toMap()).containsExactly(entry("param1", "val1"), entry("param2", "val2"));
}

@Test
public void testComputedMapContainsAlias() throws Exception
{
final AliasMap aliasMap = new AliasMap();
aliasMap.put("alias1", "val1");
aliasMap.put("alias2", "val2");
aliasMap.putAlias("alias1", "param1");
aliasMap.putAlias("alias2", "param2");
Assertions.assertThat(aliasMap.toMap())
.containsOnly(
entry("param1", "val1"),
entry("param2", "val2"),
entry("alias1", "val1"),
entry("alias2", "val2")
);
}

@Test
public void testMultipleAliasIndirection() throws Exception
{
final AliasMap aliasMap = new AliasMap();
aliasMap.put("alias2", "val1");
aliasMap.putAlias("alias1", "param1");
aliasMap.putAlias("alias2", "alias1");
Assertions.assertThat(aliasMap.toMap())
.containsOnly(
entry("param1", "val1"),
entry("alias1", "val1"),
entry("alias2", "val1")
);
}

@Test
public void testInfiniteIndirection() throws Exception
{
final AliasMap aliasMap = new AliasMap();
aliasMap.put("alias1", "val1");
aliasMap.putAlias("alias1", "param1");
aliasMap.putAlias("param1", "alias1");
try
{
aliasMap.toMap();
} catch (KernelException e)
{
Assertions.assertThat(e).hasMessage("Cycle detected in kernel parameter aliases.");
}
}

@Test(expected = UnsupportedOperationException.class)
public void testComputedMapIsImmutable() throws Exception
{
new AliasMap().toMap().put("foo", "bar");
Assertions.fail("The map should be immutable");
}
}

0 comments on commit fbe924c

Please sign in to comment.