package com.getperka.flatpack.policy.visitors;
/*
* #%L
* FlatPack Security Policy
* %%
* Copyright (C) 2012 - 2013 Perka Inc.
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
* #L%
*/
import static com.getperka.flatpack.util.FlatPackCollections.listForAny;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
import com.getperka.flatpack.policy.pst.ActionDefinition;
import com.getperka.flatpack.policy.pst.AllowBlock;
import com.getperka.flatpack.policy.pst.AllowRule;
import com.getperka.flatpack.policy.pst.GroupBlock;
import com.getperka.flatpack.policy.pst.GroupDefinition;
import com.getperka.flatpack.policy.pst.Ident;
import com.getperka.flatpack.policy.pst.PackagePolicy;
import com.getperka.flatpack.policy.pst.PolicyFile;
import com.getperka.flatpack.policy.pst.PolicyNode;
import com.getperka.flatpack.policy.pst.PropertyList;
import com.getperka.flatpack.policy.pst.PropertyPolicy;
import com.getperka.flatpack.policy.pst.TypePolicy;
/**
* Creates clones of {@link PolicyNode} instances.
*/
public class PolicyCloner extends PolicyVisitor {
/**
* Each visit method should push its cloned node onto the stack.
*/
private static class Cloner extends PolicyVisitor {
private final Deque<Object> stack = new ArrayDeque<Object>();
@Override
public boolean visit(ActionDefinition x) {
ActionDefinition n = new ActionDefinition();
n.setActions(clone(x.getActions()));
n.setName(clone(x.getName()));
stack.push(n);
return false;
}
@Override
public boolean visit(AllowBlock x) {
AllowBlock n = new AllowBlock();
n.setAclRules(clone(x.getAclRules()));
n.setInheritFrom(clone(x.getInheritFrom()));
n.setOnly(x.isOnly());
stack.push(n);
return false;
}
@Override
public boolean visit(AllowRule x) {
AllowRule n = new AllowRule();
n.setGroupName(clone(x.getGroupName()));
n.setSecurityActions(clone(x.getSecurityActions()));
stack.push(n);
return false;
}
@Override
public boolean visit(GroupBlock x) {
GroupBlock n = new GroupBlock();
n.setDefinitions(clone(x.getDefinitions()));
n.setInheritFrom(clone(x.getInheritFrom()));
stack.push(n);
return false;
}
@Override
public boolean visit(GroupDefinition x) {
GroupDefinition n = new GroupDefinition();
n.setName(clone(x.getName()));
n.setPaths(clone(x.getPaths()));
stack.push(n);
return false;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public boolean visit(Ident<?> x) {
Ident n;
if (x.isCompound()) {
n = new Ident(x.getReferentType(), x.getCompoundName());
} else if (x.isSimple()) {
n = new Ident(x.getReferentType(), x.getSimpleName());
} else {
throw new UnsupportedOperationException();
}
n.setReferent(x.getReferent());
stack.push(n);
return false;
}
@Override
public boolean visit(PackagePolicy x) {
PackagePolicy n = new PackagePolicy();
n.setAllows(clone(x.getAllows()));
n.setName(clone(x.getName()));
n.setPackagePolicies(clone(x.getPackagePolicies()));
n.setTypePolicies(clone(x.getTypePolicies()));
n.setVerbs(clone(x.getVerbs()));
stack.push(n);
return false;
}
@Override
public boolean visit(PolicyFile x) {
PolicyFile n = new PolicyFile();
n.setAllows(clone(x.getAllows()));
n.setPackagePolicies(clone(x.getPackagePolicies()));
n.setTypePolicies(clone(x.getTypePolicies()));
n.setVerbs(clone(x.getVerbs()));
stack.push(n);
return false;
}
@Override
public boolean visit(PropertyList x) {
PropertyList n = new PropertyList();
n.setPropertyNames(clone(x.getPropertyNames()));
stack.push(n);
return false;
}
@Override
public boolean visit(PropertyPolicy x) {
PropertyPolicy n = new PropertyPolicy();
n.setAllows(clone(x.getAllows()));
n.setName(clone(x.getName()));
n.setPropertyLists(clone(x.getPropertyLists()));
stack.push(n);
return false;
}
@Override
public boolean visit(TypePolicy x) {
TypePolicy n = new TypePolicy();
n.setAllows(clone(x.getAllows()));
n.setGroups(clone(x.getGroups()));
n.setName(clone(x.getName()));
n.setPolicies(clone(x.getPolicies()));
n.setVerbs(clone(x.getVerbs()));
stack.push(n);
return false;
}
/**
* Fail definitively if a new node type is introduced.
*/
@Override
protected boolean defaultVisit() {
throw new UnsupportedOperationException("Missing visit() method for unexpected node type");
}
private <T extends PolicyNode> List<T> clone(List<T> toClone) {
if (toClone == null) {
return null;
}
List<T> toReturn = listForAny();
for (T node : toClone) {
toReturn.add(clone(node));
}
return toReturn;
}
@SuppressWarnings("unchecked")
private <T extends PolicyNode> T clone(T toClone) {
if (toClone == null) {
return null;
}
traverse(toClone);
T toReturn = (T) stack.pop();
toReturn.setLineNumber(toClone.getLineNumber());
return toReturn;
}
}
public <T extends PolicyNode> List<T> clone(List<T> nodes) {
return new Cloner().clone(nodes);
}
public <T extends PolicyNode> T clone(T node) {
return new Cloner().clone(node);
}
}