package org.safehaus.penrose.mapping;
import org.safehaus.penrose.interpreter.Interpreter;
import org.safehaus.penrose.ldap.Attributes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
/**
* @author Endi Sukma Dewata
*/
public class Mapping {
public Logger log = LoggerFactory.getLogger(getClass());
public final static List<MappingRule> EMPTY = new LinkedList<MappingRule>();
private MappingConfig mappingConfig;
private MappingContext mappingContext;
protected List<MappingRule> rules = new LinkedList<MappingRule>();
protected Map<String,List<MappingRule>> rulesByName = new TreeMap<String,List<MappingRule>>();
public Mapping() {
}
public String getName() {
return mappingConfig.getName();
}
public void init(
MappingConfig mappingConfig,
MappingContext mappingContext
) throws Exception {
log.debug("Starting "+mappingConfig.getName()+" mapping.");
this.mappingConfig = mappingConfig;
this.mappingContext = mappingContext;
for (MappingRuleConfig ruleConfig : mappingConfig.getRuleConfigs()) {
MappingRule rule = new MappingRule(ruleConfig);
addRule(rule);
}
init();
}
public void init() throws Exception {
}
public void destroy() throws Exception {
}
public Collection<String> getRuleNames() {
Collection<String> list = new ArrayList<String>();
for (MappingRule rule : rules) {
list.add(rule.getName());
}
return list;
}
public List<MappingRule> getRules() {
return rules;
}
public void removeRules() {
rules.clear();
rulesByName.clear();
}
public void addRule(MappingRule rule) {
String name = rule.getName().toLowerCase();
rules.add(rule);
List<MappingRule> list = rulesByName.get(name);
if (list == null) {
list = new LinkedList<MappingRule>();
rulesByName.put(name, list);
}
list.add(rule);
}
public void addRule(int index, MappingRule rule) {
String name = rule.getName().toLowerCase();
rules.add(index, rule);
List<MappingRule> list = rulesByName.get(name);
if (list == null) {
list = new LinkedList<MappingRule>();
rulesByName.put(name, list);
}
if (list.isEmpty()) {
list.add(rule);
} else {
for (MappingRule fc : list) {
int i = rules.indexOf(fc);
if (i < index) continue;
list.add(i, rule);
}
}
}
public int getRuleIndex(MappingRule rule) {
return rules.indexOf(rule);
}
public List<MappingRule> getRules(String name) {
List<MappingRule> list = rulesByName.get(name.toLowerCase());
if (list == null) return EMPTY;
return list;
}
public List<MappingRule> removeRules(String name) {
return rulesByName.remove(name.toLowerCase());
}
public void removeRule(MappingRule rule) {
String name = rule.getName().toLowerCase();
rules.remove(rule);
Collection<MappingRule> list = rulesByName.get(name);
if (list == null) return;
list.remove(rule);
if (list.isEmpty()) rulesByName.remove(name);
}
public Attributes map(String prefix, Attributes input) throws Exception {
Attributes output = new Attributes();
Interpreter interpreter = mappingContext.getPartition().newInterpreter();
interpreter.set(prefix, input);
map(interpreter, output);
return output;
}
public void map(Interpreter interpreter, Attributes output) throws Exception {
boolean debug = log.isDebugEnabled();
if (debug) log.debug("Executing "+mappingConfig.getName()+" mapping:");
String preMapping = mappingConfig.getPreScript();
if (preMapping != null) {
if (debug) log.debug(" - Executing pre-script");
interpreter.eval(preMapping);
}
for (MappingRule rule : getRules()) {
String name = rule.getName();
boolean required = rule.isRequired();
if (!required) {
Object value = interpreter.get(name);
if (value != null) {
//if (debug) log.debug(" - Skipping "+name+": value has been set");
continue;
}
}
String variable = rule.getVariable();
if (variable != null) {
Object variableValue = interpreter.get(variable);
if (variableValue == null) {
//if (debug) log.debug(" - Skipping "+name+": "+variable+" is undefined");
continue;
}
}
String condition = rule.getCondition();
if (condition != null) {
Object conditionValue = interpreter.eval(condition);
if (!(conditionValue instanceof Boolean && (Boolean) conditionValue)) {
if (debug) {
//String className = conditionValue == null ? "" : " ("+conditionValue.getClass().getName()+")";
//log.debug(" - Skipping "+name+": condition is "+ conditionValue);
}
continue;
}
}
Object newValue = interpreter.eval(rule);
if (newValue == null) {
//if (debug) log.debug(" - Skipping "+name+": value is null");
continue;
}
Object oldValue = interpreter.get(name);
//if (debug) {
// String className = oldValue == null ? "" : " ("+oldValue.getClass().getName()+")";
// log.debug(" Old value: "+oldValue+className);
//}
boolean add = MappingRuleConfig.ADD.equals(rule.getAction());
if (debug) {
if (add) {
log.debug(" - Adding "+name+": "+newValue+" ("+newValue.getClass().getName()+")");
} else {
log.debug(" - Replacing "+name+": "+newValue+" ("+newValue.getClass().getName()+")");
}
}
if (oldValue == newValue) {
// skip
} else if (oldValue == null) {
interpreter.set(name, newValue);
} else if (oldValue instanceof Collection) {
Collection<Object> list = (Collection<Object>)oldValue;
if (!add) list.clear();
if (newValue instanceof Collection) {
list.addAll((Collection<Object>)newValue);
} else {
list.add(newValue);
}
} else if (oldValue.equals(newValue)) {
// skip
} else if (add) {
Collection<Object> list = new LinkedHashSet<Object>();
list.add(oldValue);
if (newValue instanceof Collection) {
list.addAll((Collection<Object>)newValue);
} else {
list.add(newValue);
}
interpreter.set(name, list);
} else { // replace
interpreter.set(name, newValue);
}
}
String postMapping = mappingConfig.getPostScript();
if (postMapping != null) {
if (debug) log.debug(" - Executing post-script");
interpreter.eval(postMapping);
}
//if (debug) log.debug(" - Storing mapping results");
for (String name : getRuleNames()) {
Object value = interpreter.get(name);
//if (debug) log.debug(" - "+name+": "+value);
if (value == null) continue;
if (value instanceof Collection) {
Collection<Object> list = (Collection<Object>)value;
output.setValues(name, list);
} else {
output.setValue(name, value);
}
}
}
public MappingConfig getMappingConfig() {
return mappingConfig;
}
public void setMappingConfig(MappingConfig mappingConfig) {
this.mappingConfig = mappingConfig;
}
public MappingContext getMappingContext() {
return mappingContext;
}
public void setMappingContext(MappingContext mappingContext) {
this.mappingContext = mappingContext;
}
public String getDescription() {
return mappingConfig.getDescription();
}
public String getParameter(String name) {
return mappingConfig.getParameter(name);
}
public Map<String,String> getParameters() {
return mappingConfig.getParameters();
}
public Collection<String> getParameterNames() {
return mappingConfig.getParameterNames();
}
public String removeParameter(String name) {
return mappingConfig.removeParameter(name);
}
}