package org.jboss.windup.config.parameters;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;
import org.jboss.forge.furnace.util.Iterators;
import org.jboss.windup.config.GraphRewrite;
import org.jboss.windup.config.Variables;
import org.jboss.windup.config.condition.GraphCondition;
import org.jboss.windup.graph.model.WindupVertexFrame;
import org.jboss.windup.util.Logging;
import org.jboss.windup.util.exception.WindupException;
import org.ocpsoft.rewrite.context.EvaluationContext;
import org.ocpsoft.rewrite.param.DefaultParameterValueStore;
import org.ocpsoft.rewrite.param.ParameterValueStore;
import org.ocpsoft.rewrite.param.Parameterized;
public abstract class ParameterizedGraphCondition extends GraphCondition implements Parameterized
{
private static final Logger LOG = Logging.get(ParameterizedGraphCondition.class);
static final String PARAM_VALUE_STORE_MAP_KEY = ParameterizedGraphCondition.class.getName()
+ "_parameterValueStoreMap";
static final String RESULT_VALUE_STORE_MAP_KEY = ParameterizedGraphCondition.class.getName()
+ "_resultParameterValueStoreMap";
protected abstract String getVarname();
protected abstract boolean evaluateWithValueStore(GraphRewrite event, EvaluationContext context, FrameContext frame);
protected abstract boolean evaluateAndPopulateValueStores(GraphRewrite event, EvaluationContext context,
FrameCreationContext frameCreationContext);
@Override
public final boolean evaluate(GraphRewrite event, final EvaluationContext context)
{
final Map<ParameterValueStore, Map<String, Iterable<? extends WindupVertexFrame>>> valueStores = getParameterValueStoreMap(context);
Map<WindupVertexFrame, ParameterValueStore> resultSetStores = getResultValueStoreMap(context);
ParameterValueStore previousValueStore = DefaultParameterValueStore.getInstance(context);
try
{
if (valueStores.isEmpty() || getRequiredParameterNames().isEmpty())
{
FrameCreationContext frameCreationContext = new FrameCreationContext()
{
private ParameterValueStore current;
private final DefaultParameterValueStore original = (DefaultParameterValueStore) DefaultParameterValueStore
.getInstance(context);
@Override
public void beginNew(Map<String, Iterable<? extends WindupVertexFrame>> variables)
{
if (valueStores != null && current != null && valueStores.get(current) != null && valueStores.get(current).isEmpty())
{
// clean previous if nothing was submitted in the valuestore
rollback();
}
ParameterValueStore clone = clone(original);
this.current = clone;
context.put(ParameterValueStore.class, clone);
if (variables == null)
variables = new LinkedHashMap<>();
valueStores.put(clone, variables);
}
private ParameterValueStore clone(DefaultParameterValueStore instance)
{
DefaultParameterValueStore clone = new DefaultParameterValueStore(instance);
return clone;
}
@Override
public void rollback()
{
if (current != null)
valueStores.remove(current);
}
};
try
{
return evaluateAndPopulateValueStores(event, context, frameCreationContext);
}
finally
{
for (Entry<ParameterValueStore, Map<String, Iterable<? extends WindupVertexFrame>>> entry : valueStores
.entrySet())
{
ParameterValueStore valueStore = entry.getKey();
Map<String, Iterable<? extends WindupVertexFrame>> layer = entry.getValue();
if (layer == null)
{
throw new WindupException("Value store with no associated variables frame. This should not happen");
}
Iterable<? extends WindupVertexFrame> variable = layer.get(getVarname());
if (variable != null)
{
for (WindupVertexFrame frame : variable)
{
ParameterValueStore last = resultSetStores.put(frame, valueStore);
if (last != null)
{
// WHY DOES THIS HAPPEN?
LOG.warning("DOES THIS STILL HAPPEN?");
}
}
}
}
}
}
else
{
Set<WindupVertexFrame> resultSet = new LinkedHashSet<>();
boolean result = false;
DefaultParameterValueStore original = (DefaultParameterValueStore) DefaultParameterValueStore
.getInstance(context);
for (Entry<ParameterValueStore, Map<String, Iterable<? extends WindupVertexFrame>>> entry : valueStores
.entrySet())
{
ParameterValueStore valueStore = entry.getKey();
Map<String, Iterable<? extends WindupVertexFrame>> variables = entry.getValue();
try
{
Variables.instance(event).push(variables);
final AtomicBoolean rejected = new AtomicBoolean(false);
FrameContext frameContext = new FrameContext()
{
@Override
public void reject()
{
rejected.set(true);
}
};
try
{
context.put(ParameterValueStore.class, valueStore);
/*
* Each ValueStore must correspond with the variables map which which it was created.
*/
if (evaluateWithValueStore(event, context, frameContext))
result = true;
if (rejected.get())
valueStores.remove(valueStore);
}
finally
{
context.put(ParameterValueStore.class, original);
}
}
finally
{
Iterable<? extends WindupVertexFrame> variable = Variables.instance(event).findVariable(getVarname());
if (variable != null)
{
resultSet.addAll(Iterators.asSet(variable));
for (WindupVertexFrame frame : variable)
{
ParameterValueStore last = resultSetStores.put(frame, valueStore);
if (last != null)
{
// TODO is this a valid scenario?
}
}
}
Variables.instance(event).pop();
}
}
Variables.instance(event).setVariable(getVarname(), resultSet);
return result;
}
}
finally
{
context.put(ParameterValueStore.class, previousValueStore);
context.put(PARAM_VALUE_STORE_MAP_KEY, valueStores);
context.put(RESULT_VALUE_STORE_MAP_KEY, resultSetStores);
}
}
@SuppressWarnings("unchecked")
static Map<ParameterValueStore, Map<String, Iterable<? extends WindupVertexFrame>>> getParameterValueStoreMap(
final EvaluationContext context)
{
Map<ParameterValueStore, Map<String, Iterable<? extends WindupVertexFrame>>> cachedStores = (Map<ParameterValueStore, Map<String, Iterable<? extends WindupVertexFrame>>>) context
.get(PARAM_VALUE_STORE_MAP_KEY);
Map<ParameterValueStore, Map<String, Iterable<? extends WindupVertexFrame>>> valueStores = cachedStores;
if (valueStores == null)
valueStores = new ConcurrentHashMap<>();
return valueStores;
}
@SuppressWarnings("unchecked")
static Map<WindupVertexFrame, ParameterValueStore> getResultValueStoreMap(EvaluationContext context)
{
Map<WindupVertexFrame, ParameterValueStore> result = (Map<WindupVertexFrame, ParameterValueStore>) context
.get(RESULT_VALUE_STORE_MAP_KEY);
if (result == null)
{
result = new LinkedHashMap<>();
}
return result;
}
}