package hu.sztaki.ilab.longneck; import hu.sztaki.ilab.longneck.process.kernel.KernelState; import hu.sztaki.ilab.longneck.process.constraint.CheckResult; import java.util.*; /** * A simple record implementation with providing basic functionality. * * @author Molnár Péter <molnarp@sztaki.mta.hu> */ abstract public class AbstractRecord implements Record { /** Record history stack. */ protected Stack<Map<String,Field>> history; /** Fields in the record. */ protected Map<String, Field> fields; /** The saved kernel state. */ protected KernelState kernelState; /** The list of constraint failures that occurred during processing. */ protected List<CheckResult> constraintFailures; protected Stack<Integer> constraintFailureHistory; public AbstractRecord() { fields = new HashMap<>(); constraintFailures = new ArrayList<>(); constraintFailureHistory = new Stack<>(); } @Override public Map<String, Field> getFields() { return fields; } @Override public void setFields(Map<String, Field> fields) { this.fields = fields; } @Override public boolean has(String fieldName) { return fields.containsKey(fieldName); } @Override public void add(Field field) { fields.put(field.getName(), field); } @Override public void remove(String fieldName) { fields.remove(fieldName); } @Override public Field get(String fieldName) { return fields.get(fieldName); } @Override public void saveState() { Map<String,Field> save = new HashMap<String,Field>(); // Copy fields for (Map.Entry<String, Field> entry : fields.entrySet()) { Field f = new Field(entry.getValue()); save.put(entry.getKey(), f); } // Create history if needed if (history == null) { history = new Stack<Map<String, Field>>(); } // Push current stack size history.push(save); constraintFailureHistory.push(constraintFailures.size()); } @Override public void restoreState() { fields = history.pop(); constraintFailures = constraintFailures.subList(0, constraintFailureHistory.pop()); } @Override public void removeState() { history.pop(); constraintFailureHistory.pop(); } @Override public void clearHistory() { history.empty(); constraintFailureHistory.empty(); } @Override public String toString() { StringBuilder result = new StringBuilder(); result.append("{ "); for (Map.Entry f : fields.entrySet()) { result.append(f.getValue().toString()); result.append(", "); } result.delete(result.length() - 2, result.length()); result.append("}"); return result.toString(); } @Override public List<CheckResult> getErrors() { return Collections.unmodifiableList(constraintFailures); } @Override public void addError(CheckResult error) { constraintFailures.add(error); } @Override public KernelState getKernelState() { return kernelState; } @Override public void setKernelState(KernelState kernelState) { this.kernelState = kernelState; } @Override public AbstractRecord clone() { AbstractRecord clone; try { clone = (AbstractRecord) super.clone(); } catch (CloneNotSupportedException ex) { throw new AssertionError(ex); } // Clone fields clone.fields = new HashMap<String, Field>(); if (fields != null) { for (Map.Entry<String, Field> entry : fields.entrySet()) { clone.add(new Field(entry.getValue())); } } // Clone errors clone.constraintFailures = new ArrayList<CheckResult>(); if (constraintFailures != null) { clone.constraintFailures.addAll(Collections.unmodifiableList(constraintFailures)); } // Clone the current kernel state if (kernelState != null) { KernelState cloneState = new KernelState(kernelState); clone.setKernelState(cloneState); } // Clone historys clone.constraintFailureHistory = (Stack<Integer>) constraintFailureHistory.clone(); if (history != null) { clone.history = new Stack<Map<String, Field>>(); for (Map<String, Field> map : history) { Map<String, Field> save = new HashMap<String, Field>(); for (Map.Entry<String, Field> entry : map.entrySet()) { Field f = new Field(entry.getValue()); save.put(entry.getKey(), f); } clone.history.push(save); } } return clone; } }