From 91d04c64771832a0b8815ffbe1f0f9920320d94d Mon Sep 17 00:00:00 2001 From: Pamela Dragosh Date: Tue, 14 Feb 2017 19:41:00 -0500 Subject: Initial OpenECOMP policy/engine commit Change-Id: I7dbff37733b661643dd4d1caefa3d7dccc361b6e Signed-off-by: Pamela Dragosh --- .../openecomp/policy/xacml/std/pap/StdEngine.java | 1087 ++++++++++++++++++++ 1 file changed, 1087 insertions(+) create mode 100644 ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pap/StdEngine.java (limited to 'ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pap/StdEngine.java') diff --git a/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pap/StdEngine.java b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pap/StdEngine.java new file mode 100644 index 000000000..397f763f2 --- /dev/null +++ b/ECOMP-XACML/src/main/java/org/openecomp/policy/xacml/std/pap/StdEngine.java @@ -0,0 +1,1087 @@ +/*- + * ============LICENSE_START======================================================= + * ECOMP-XACML + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.openecomp.policy.xacml.std.pap; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.List; +import java.util.Properties; +import java.util.Set; +import java.util.TreeSet; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.openecomp.policy.xacml.api.pap.EcompPDP; +import org.openecomp.policy.xacml.api.pap.EcompPDPGroup; +import org.openecomp.policy.xacml.api.pap.PAPPolicyEngine; +import org.openecomp.policy.common.logging.eelf.MessageCodes; +import org.openecomp.policy.common.logging.eelf.PolicyLogger; +import com.att.research.xacml.api.pap.PAPException; +import com.att.research.xacml.api.pap.PDP; +import com.att.research.xacml.api.pap.PDPGroup; +import com.att.research.xacml.api.pap.PDPPolicy; +import com.att.research.xacml.api.pap.PDPStatus; +import com.att.research.xacml.util.XACMLProperties; +import com.google.common.base.Joiner; +import com.google.common.base.Splitter; +import com.google.common.collect.Sets; + +/** + * This is a simple PAP engine that uses some property files and a simple directory + * structure in the file system to manage a policy repository and set of PDP nodes. + * + * + */ +public class StdEngine extends StdPDPItemSetChangeNotifier implements PAPPolicyEngine { + private static Log logger = LogFactory.getLog(StdEngine.class); + + public static String PROP_PAP_REPO = "xacml.pap.pdps"; + public static String PROP_PAP_GROUPS = "xacml.pap.groups"; + public static String PROP_PAP_GROUPS_DEFAULT = "xacml.pap.groups.default"; + public static String PROP_PAP_GROUPS_DEFAULT_NAME = "default"; + //this value will be accessed from XacmlPapServlet so that we know if a default group did not exist + //and was just added. This way, we can add the new group to the database. + public boolean wasDefaultGroupJustAdded = false; + + protected final Path repository; + protected Set groups; + + public StdEngine() throws PAPException, IOException { + // + // Get the location in the file system of our repository + // + this.repository = Paths.get(XACMLProperties.getProperty(PROP_PAP_REPO)); + // + // Initialize + // + this.intialize(); + } + + public StdEngine(Properties properties) throws PAPException, IOException { + // + // Get the location in the file system of our repository + // + this.repository = Paths.get(properties.getProperty(PROP_PAP_REPO)); + // + // Initialize + // + this.intialize(); + } + + public StdEngine(Path repository) throws PAPException, IOException { + // + // Save our location + // + this.repository = repository; + // + // Initialize + // + this.intialize(); + } + + private void intialize() throws PAPException, IOException { + // + // Sanity check the repository path + // + if (this.repository == null) { + throw new PAPException ("No repository specified."); + } + if (Files.notExists(this.repository)) { + Files.createDirectory(repository); + } + if (Files.isDirectory(this.repository) == false) { + throw new PAPException ("Repository is NOT a directory: " + this.repository.toAbsolutePath()); + } + if (Files.isWritable(this.repository) == false) { + throw new PAPException ("Repository is NOT writable: " + this.repository.toAbsolutePath()); + } + // + // Load our groups + // + this.loadGroups(); + } + + private void loadGroups() throws PAPException { + // + // Create a properties object + // + Properties properties = new Properties(); + Path file = Paths.get(this.repository.toString(), XACMLProperties.XACML_PROPERTIES_NAME); + try { + // + // Load the properties + // + try (InputStream is = new FileInputStream(file.toFile())) { + properties.load(is); + } + + // + // Parse it + // + this.groups = this.readProperties(this.repository, properties); + } catch (IOException e) { + //TODO:EELF Cleanup - Remove logger + //logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Failed to load " + file.toAbsolutePath().toString()); + PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "StdEngine", "Failed to load properties file"); + this.groups = new HashSet(); + } + // + // Initialize the default group + // + PDPGroup defaultGroup = this.initializeDefaultGroup(file, properties); + logger.info("Default group is: " + defaultGroup.getId() + "=" + defaultGroup.getName()); + } + + private PDPGroup initializeDefaultGroup(Path file, Properties properties) throws PAPException { + wasDefaultGroupJustAdded = false; + // + // Make sure we have the default group + // + PDPGroup group = this.getDefaultGroup(); + if (group != null) { + return group; + } + // + // We don't have the default group, create it + // + String defaultId = properties.getProperty(PROP_PAP_GROUPS_DEFAULT, PROP_PAP_GROUPS_DEFAULT_NAME); + if(defaultId == null){ + defaultId = PROP_PAP_GROUPS_DEFAULT_NAME; + } + if(defaultId.equals("")){ + defaultId = PROP_PAP_GROUPS_DEFAULT_NAME; + } + //we're going to check one more time in case the PROP_PAP_GROUPS_DEFAULT_NAME doesn't exist + if(defaultId == null){ + defaultId = "default"; + } + if(defaultId.equals("")){ + defaultId = "default"; + } + logger.warn("Default group does NOT exist, creating " + defaultId); + Path defaultPath = Paths.get(this.repository.toString(), defaultId); + try { + // + // Does it exist? + // + if (Files.notExists(defaultPath)) { + // + // Create its directory + // + Files.createDirectory(defaultPath); + // + // Create property files + // + { + Properties props = new Properties(); + props.setProperty(XACMLProperties.PROP_REFERENCEDPOLICIES, ""); + props.setProperty(XACMLProperties.PROP_ROOTPOLICIES, ""); + Path policyPath = Paths.get(defaultPath.toAbsolutePath().toString(), "xacml.policy.properties"); + Files.createFile(policyPath); + try (OutputStream os = Files.newOutputStream(policyPath)) { + props.store(os, ""); + } catch (IOException e) { + //TODO:EELF Cleanup - Remove logger + //logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Failed to write default policy properties", e); + PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "StdEngine", "Failed to write default policy properties"); + } + } + { + Properties props = new Properties(); + props = setPIPProperties(props); + Path pipPath = Paths.get(defaultPath.toAbsolutePath().toString(), "xacml.pip.properties"); + Files.createFile(pipPath); + try (OutputStream os = Files.newOutputStream(pipPath)) { + props.store(os, ""); + } catch (IOException e) { + //TODO:EELF Cleanup - Remove logger + //logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Failed to write default pip properties", e); + PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "StdEngine", "Failed to write default pip properties"); + } + } + } + // + // Create the default group + // + StdPDPGroup newDefault = new StdPDPGroup(defaultId, true, "default", "The default group where new PDP's are put.", defaultPath); + // + // Add it to our list + // + this.groups.add(newDefault); + // + // Save our properties out since we have + // a new default group. + // + StdEngine.setGroupProperties(newDefault, properties); + // + // Save it to disk + // + try { + try (OutputStream os = Files.newOutputStream(file)) { + properties.store(os, ""); + } + } catch (IOException e) { + //TODO:EELF Cleanup - Remove logger + //logger.error("Failed to save properties with new default group information.", e); + PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, "StdEngine", "Failed to save properties with new default group information."); + } + // + // Return it + // + wasDefaultGroupJustAdded = true; + return newDefault; + } catch (IOException e) { + //TODO:EELF Cleanup - Remove logger + //logger.error("Failed to create default group: " + defaultId, e); + PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, "StdEngine", "Failed to create default group"); + throw new PAPException("Failed to create default group"); + } + } + + + + + @Override + public EcompPDPGroup getDefaultGroup() throws PAPException + { + for (EcompPDPGroup group : this.groups) { + if (group.isDefaultGroup()) { + return group; + } + } + // + // Default group doesn't exist + // + return null; + } + + /*@Override + public void SetDefaultGroup(PDPGroup group) throws PAPException { + + boolean changesMade = false; + for (PDPGroup aGroup : groups) { + if (aGroup.getId().equals(group.getId())) { + if ( ! aGroup.isDefaultGroup()) { +//TODO - since the original code checked for type we do also. + if (aGroup instanceof StdPDPGroup) { + ((StdPDPGroup) aGroup).setDefault(true); + changesMade = true; + } else { + throw new IllegalArgumentException("Group in groups of unknown type '" + aGroup.getClass().getName() + "'"); + } + } + } else { + // not the new default group + if (aGroup.isDefaultGroup()) { +//TODO - since the original code checked for type we do also. + if (aGroup instanceof StdPDPGroup) { + ((StdPDPGroup) aGroup).setDefault(false); + changesMade = true; + } else { + throw new IllegalArgumentException("Group in groups of unknown type '" + aGroup.getClass().getName() + "'"); + } + } + } + } + if (changesMade) { + this.doSave(); + } + + return; + }*/ + + /*@Override + public Set getPDPGroups() throws PAPException { + final Set grps = new HashSet(); + for (PDPGroup g : this.groups) { + grps.add(g); + } + return Collections.unmodifiableSet(grps); + }*/ + + @Override + public EcompPDPGroup getGroup(String id) throws PAPException { + for (EcompPDPGroup g: this.groups) { + if (g.getId().equals(id)) { + return g; + } + } + return null; + } + + @Override + public void newGroup(String name, String description) throws PAPException, NullPointerException + { + // + // Null check + // + if (name == null) { + throw new NullPointerException(); + } + // + // Do we already have this group? + // + for (PDPGroup group : this.groups) { + if (group.getName().equals(name)) { + throw new PAPException("Group with this name=" + name + " already exists."); + } + } + + + // create an Id that can be used as a file name and a properties file key. + // Ids must not contain \/:*?"<>|=,; + // The ID must also be unique within the current set of PDPGroups. + String id = createNewPDPGroupId(name); + + + // + // Construct the directory path + // + Path groupPath = Paths.get(this.repository.toString(), id); + // + // If it exists already + // + if (Files.exists(groupPath)) { + logger.warn("addGroup " + id + " directory exists" + groupPath.toString()); + } else { + try { + // + // Create the directory + // + Files.createDirectory(groupPath); + } catch (IOException e) { + //TODO:EELF Cleanup - Remove logger + //logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Failed to create " + groupPath); + PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "StdEngine", "Failed to create " + groupPath); + throw new PAPException("Failed to create " + id); + } + } + // + // Create the Policies + // + + Path policyProperties = Paths.get(groupPath.toString(), "xacml.policy.properties"); + if (Files.exists(policyProperties)) { + logger.warn("addGroup " + id + " file exists: " + policyProperties.toString()); + } else { + Properties props = new Properties(); + props.setProperty(XACMLProperties.PROP_REFERENCEDPOLICIES, ""); + props.setProperty(XACMLProperties.PROP_ROOTPOLICIES, ""); + try { + Files.createFile(policyProperties); + try (OutputStream os = Files.newOutputStream(policyProperties)) { + props.store(os, ""); + } + } catch (IOException e) { + //TODO:EELF Cleanup - Remove logger + //logger.error("Failed to create " + policyProperties); + PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, "StdEngine", "Failed to create " + policyProperties); + throw new PAPException("Failed to create " + id); + } + } + // + // Create the PIP config + // + Path pipProperties = Paths.get(groupPath.toString(), "xacml.pip.properties"); + if (Files.exists(pipProperties)) { + logger.warn("addGroup " + id + " file exists: " + pipProperties.toString()); + } else { + try { + Properties props = new Properties(); + props = setPIPProperties(props); + Files.createFile(pipProperties); + try (OutputStream os = Files.newOutputStream(pipProperties)) { + props.store(os, ""); + } + } catch (IOException e) { + //TODO:EELF Cleanup - Remove logger + //logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Failed to create " + pipProperties); + PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "StdEngine", "Failed to create " + pipProperties); + throw new PAPException("Failed to create " + id); + } + + } + // + // Ok now add it + // + StdPDPGroup newGroup = new StdPDPGroup(id, name, description, groupPath); + if (this.groups.add(newGroup)) { + // save the new group in our properties and notify any listeners of the change + groupChanged(newGroup); + } + + } + + + + + /** + * Helper to create a new Group ID. + * Use the Name field to create the Id. + * The Name is expected to not be null; if it is then this method throws an exception. + * The name is supposed to be unique within the current set of groups, + * so creating the ID based on the name will create a unique string. + * + * @param name + * @return + */ + private String createNewPDPGroupId(String name) { + String id = name; + // replace "bad" characters with sequences that will be ok for file names and properties keys. + id = id.replace(" ", "_sp_"); + id = id.replace("\t", "_tab_"); + id = id.replace("\\", "_bksl_"); + id = id.replace("/", "_sl_"); + id = id.replace(":", "_col_"); + id = id.replace("*", "_ast_"); + id = id.replace("?", "_q_"); + id = id.replace("\"", "_quo_"); + id = id.replace("<", "_lt_"); + id = id.replace(">", "_gt_"); + id = id.replace("|", "_bar_"); + id = id.replace("=", "_eq_"); + id = id.replace(",", "_com_"); + id = id.replace(";", "_scom_"); + + return id; + } + + + @Override + public EcompPDP getPDP(String pdpId) throws PAPException { + for (EcompPDPGroup group : this.groups) { + for (EcompPDP pdp : group.getEcompPdps()) { + if (pdp.getId().equals(pdpId)) { + return pdp; + } + } + } + return null; + } + + + @Override + public void movePDP(EcompPDP pdp, EcompPDPGroup newGroup) throws PAPException { + if (newGroup == null) { + throw new NullPointerException("You must specify which group the PDP will belong to."); + } + PDPGroup currentGroup = this.getPDPGroup(pdp); + if (currentGroup == null) { + throw new PAPException("PDP must already belong to a group."); + } + if (currentGroup.equals(newGroup)) { + logger.warn("Already in that group."); + return; + } + if (currentGroup instanceof StdPDPGroup && newGroup instanceof StdPDPGroup) { + if (((StdPDPGroup) currentGroup).removePDP(pdp)) { + boolean result = ((StdPDPGroup) newGroup).addPDP(pdp); + if (result) { + // + // Save the configuration + // + this.doSave(); + } else { + //TODO:EELF Cleanup - Remove logger + //logger.error("Failed to add to new group, putting back into original group."); + PolicyLogger.error("Failed to add to new group, putting back into original group."); + if (((StdPDPGroup) currentGroup).removePDP(pdp) == false) { + //TODO:EELF Cleanup - Remove logger + //logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Failed to put PDP back into original group."); + PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE + "Failed to put PDP back into original group."); + } + } + } + } else { + String message = "Unknown PDP group class: " + newGroup.getClass().getCanonicalName() + " and " + currentGroup.getClass().getCanonicalName(); + logger.warn(message); + throw new PAPException(message); + } + } + + + @Override + public void updatePDP(EcompPDP pdp) throws PAPException { + PDP currentPDP = this.getPDP(pdp.getId()); + if (currentPDP == null) { + String message = "Unknown PDP id '" + pdp.getId() + "'"; + logger.warn(message); + throw new PAPException(message); + } + + // the only things that the user can change are name and description + currentPDP.setDescription(pdp.getDescription()); + currentPDP.setName(pdp.getName()); + if (currentPDP instanceof EcompPDP && pdp instanceof EcompPDP) { + ((EcompPDP)currentPDP).setJmxPort(((EcompPDP)pdp).getJmxPort()); + } + this.doSave(); + } + + @Override + public void removePDP(EcompPDP pdp) throws PAPException { + PDPGroup group = this.getPDPGroup(pdp); + if (group == null) { + throw new NullPointerException(); + } + if (group instanceof StdPDPGroup) { + boolean result = ((StdPDPGroup) group).removePDP(pdp); + if (result) { + this.doSave(); + } + return; + } + String message = "Unknown PDP group class: " + group.getClass().getCanonicalName(); + logger.warn(message); + throw new PAPException(message); + } + + + @Override + /** + * Should never be called - Detailed status is held on the PDP, not the PAP + */ + public PDPStatus getStatus(EcompPDP pdp) throws PAPException { + return getPDP(pdp.getId()).getStatus(); + } + + @Override + public void publishPolicy(String id, String name, boolean isRoot, InputStream policy, EcompPDPGroup group) throws PAPException { + if (group == null) { + throw new NullPointerException(); + } + if (group instanceof StdPDPGroup && this.groups.contains(group)) { + ((StdPDPGroup) group).publishPolicy(id, name, isRoot, policy); + return; + } + logger.warn("unknown PDP Group: " + group); + throw new PAPException("Unknown PDP Group: " + group.getId()); + } + + // Currently not used on the PAP side. This is done by ((StdPDPGroup) group).copyPolicyToFile + @Override + public void copyPolicy(PDPPolicy policy, EcompPDPGroup group) + throws PAPException { + } + + + @Override + public void removePolicy(PDPPolicy policy, EcompPDPGroup group) throws PAPException { + if (group == null) { + throw new NullPointerException(); + } + if (group instanceof StdPDPGroup && this.groups.contains(group)) { + ((StdPDPGroup) group).removePolicy(policy); + return; + } + logger.warn("unknown PDP Group: " + group); + throw new PAPException("Unknown PDP Group: " + group.getId()); + } + + + // + // HELPER methods + // + + private Set readProperties(Path repository, Properties properties) throws PAPException { + Set groups = new HashSet(); + // + // See if there is a groups property + // + String groupList = properties.getProperty(PROP_PAP_GROUPS, ""); + if (groupList == null) { + logger.warn("null group list " + PROP_PAP_GROUPS); + groupList = ""; + } + if (logger.isDebugEnabled()) { + logger.debug("group list: " + groupList); + } + // + // Iterate the groups, converting to a set ensures we have unique groups. + // + for (String id : Splitter.on(',').trimResults().omitEmptyStrings().split(groupList)) { + // + // Add our Group Object + // + StdPDPGroup g = new StdPDPGroup(id.trim(), + id.equals(properties.getProperty(PROP_PAP_GROUPS_DEFAULT, PROP_PAP_GROUPS_DEFAULT_NAME)), + properties, + Paths.get(repository.toString(), id)); + + // + // Add it in + // + groups.add(g); + } + // + // Dump what we got + // + if (logger.isDebugEnabled()) { + logger.debug("PDP Group List: " + groups.toString()); + } + return groups; + } + + private void saveConfiguration() throws PAPException, IOException { + // + // Create our properties object + // + Properties properties = new Properties() { + private static final long serialVersionUID = 1L; + // For Debugging it is helpful for the file to be in a sorted order, + // any by returning the keys in the natural Alpha order for strings we get close enough. + // TreeSet is sorted, and this just overrides the normal Properties method to get the keys. + @Override + public synchronized Enumeration keys() { + return Collections.enumeration(new TreeSet(super.keySet())); + } + }; + // + // Iterate our groups + // + List ids = new ArrayList(); + for (PDPGroup group : this.groups) { + ids.add(group.getId()); + properties.setProperty(group.getId() + ".name", (group.getName() == null ? "" : group.getName())); + properties.setProperty(group.getId() + ".description", (group.getDescription() == null ? "" : group.getDescription())); + // + // Iterate its PDPs + // + List pdps = new ArrayList(); + for (PDP pdp : group.getPdps()) { + pdps.add(pdp.getId()); + properties.setProperty(pdp.getId() + ".name", (pdp.getName() == null ? "" : pdp.getName())); + properties.setProperty(pdp.getId() + ".description", (pdp.getDescription() == null ? "" : pdp.getDescription())); + if (pdp instanceof EcompPDP) { + properties.setProperty(pdp.getId() + ".jmxport", (((EcompPDP)pdp).getJmxPort()==0 ? "" : ((EcompPDP)pdp).getJmxPort()).toString()); + } + } + String pdpList = ""; + if (pdps.size() == 1) { + pdpList = pdps.get(0); + } else if (pdps.size() > 1) { + pdpList = Joiner.on(',').skipNulls().join(pdps); + } + if (logger.isDebugEnabled()) { + logger.debug("Group " + group.getId() + " PDPS: " + pdpList); + } + properties.setProperty(group.getId() + ".pdps", pdpList); + } + if (ids.isEmpty()) { + throw new PAPException("Inconsistency - we have NO groups. We should have at least one."); + } + String groupList = ""; + if (ids.size() == 1) { + groupList = ids.get(0); + } else if (ids.size() > 1){ + groupList = Joiner.on(',').skipNulls().join(ids); + } + logger.info("New Group List: " + groupList); + + properties.setProperty(PROP_PAP_GROUPS, groupList); + // + // Get the default group + // + PDPGroup defaultGroup = this.getDefaultGroup(); + if (defaultGroup == null) { + throw new PAPException("Invalid state - no default group."); + } + properties.setProperty(PROP_PAP_GROUPS_DEFAULT, defaultGroup.getId()); + // + // Now we can save the file + // + Path file = Paths.get(this.repository.toString(), "xacml.properties"); + try (OutputStream os = Files.newOutputStream(file)) { + properties.store(os, ""); + } + } + + public static void removeGroupProperties(String id, Properties properties) { + for (Object key : properties.keySet()) { + if (key.toString().startsWith(id + ".")) { + properties.remove(key); + } + } + } + + public static void setGroupProperties(PDPGroup group, Properties properties) { + // + // make sure its in the list of groups + // + Iterable groups = Splitter.on(',').trimResults().omitEmptyStrings().split( properties.getProperty(PROP_PAP_GROUPS, "")); + boolean inList = false; + for (String g : groups) { + if (g.equals(group.getId())) { + inList = true; + } + } + if (inList == false) { + Set grps = Sets.newHashSet(groups); + grps.add(group.getId()); + String newGroupList = "";; + if (grps.size() == 1) { + newGroupList = grps.iterator().next(); + } else if (grps.size() > 1) { + newGroupList = Joiner.on(',').skipNulls().join(grps); + } + logger.info("New Group List: " + newGroupList); + properties.setProperty(PROP_PAP_GROUPS, newGroupList); + } + // + // Set its properties + // + properties.setProperty(group.getId() + ".name", group.getName()); + properties.setProperty(group.getId() + ".description", group.getDescription()); + // + // Set its PDP list + // + if (group.getPdps().size() > 0) { + String pdpList = ""; + if (group.getPdps().size() == 1) { + pdpList = group.getPdps().iterator().next().getId(); + } else if (group.getPdps().size() > 1) { + Set ids = new HashSet(); + for (PDP pdp : group.getPdps()) { + ids.add(pdp.getId()); + } + pdpList = Joiner.on(',').skipNulls().join(ids); + } + properties.setProperty(group.getId() + ".pdps", pdpList); + } else { + properties.setProperty(group.getId() + ".pdps", ""); + } + } + + + public void changed() { + if (logger.isDebugEnabled()) { + logger.debug("changed"); + } + this.doSave(); + this.fireChanged(); + } + + public void groupChanged(EcompPDPGroup group) { + if (logger.isDebugEnabled()) { + logger.debug("groupChanged: " + group); + } + this.doSave(); + this.firePDPGroupChanged(group); + } + + + public void pdpChanged(EcompPDP pdp) { + if (logger.isDebugEnabled()) { + logger.debug("pdpChanged: " + pdp); + } + this.doSave(); + this.firePDPChanged(pdp); + } + + private void doSave() { + try { + // + // Save the configuration + // + this.saveConfiguration(); + } catch (IOException e) { + //TODO:EELF Cleanup - Remove logger + //logger.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + "Failed to save configuration", e); + PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, e, "StdEngine", "Failed to save configuration"); + } catch (PAPException e) { + //TODO:EELF Cleanup - Remove logger + //logger.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + "Failed to save configuration", e); + PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, e, "StdEngine", "Failed to save configuration"); + } + } + + // TODO: Adding Default PIP engine(s) while Loading initially. We don't want + // Programmer intervention with the PIP engines. + private Properties setPIPProperties(Properties props){ + props.setProperty(XACMLProperties.PROP_PIP_ENGINES, "AAF"); + props.setProperty("AAF.name", "AAFEngine"); + props.setProperty("AAF.description", "AAFEngine to communicate with AAF to take decisions"); + props.setProperty("AAF.classname","org.openecomp.policy.xacml.std.pip.engines.aaf.AAFEngine"); + return props; + } + + + @Override + public Set getEcompPDPGroups() throws PAPException { + final Set grps = new HashSet(); + for (EcompPDPGroup g : this.groups) { + grps.add(g); + } + return Collections.unmodifiableSet(grps); + } + + @Override + public EcompPDPGroup getPDPGroup(EcompPDP pdp) throws PAPException { + for (EcompPDPGroup group : this.groups) { + if (group.getPdps().contains(pdp)) { + return group; + } + } + return null; + } + + @Override + public void SetDefaultGroup(EcompPDPGroup group) throws PAPException { + boolean changesMade = false; + for (EcompPDPGroup aGroup : groups) { + if (aGroup.getId().equals(group.getId())) { + if ( ! aGroup.isDefaultGroup()) { +//TODO - since the original code checked for type we do also. + if (aGroup instanceof StdPDPGroup) { + ((StdPDPGroup) aGroup).setDefault(true); + changesMade = true; + } else { + throw new IllegalArgumentException("Group in groups of unknown type '" + aGroup.getClass().getName() + "'"); + } + } + } else { + // not the new default group + if (aGroup.isDefaultGroup()) { +//TODO - since the original code checked for type we do also. + if (aGroup instanceof StdPDPGroup) { + ((StdPDPGroup) aGroup).setDefault(false); + changesMade = true; + } else { + throw new IllegalArgumentException("Group in groups of unknown type '" + aGroup.getClass().getName() + "'"); + } + } + } + } + if (changesMade) { + this.doSave(); + } + + return; + + } + + @Override + public void newPDP(String id, EcompPDPGroup group, String name, String description, int jmxport) + throws PAPException, NullPointerException { + if (group == null) { + throw new PAPException("You must specify which group the PDP will belong to."); + } + if (this.groups.contains(group) == false) { + throw new PAPException("Unknown group, not in our list."); + } + for (EcompPDP p : group.getEcompPdps()) { + if (p.getId().equals(id)) { + throw new PAPException("A PDP with this ID exists."); + } + } + if (group instanceof StdPDPGroup) { + StdPDP pdp = new StdPDP(id, name, description, jmxport); + if (((StdPDPGroup) group).addPDP(pdp)) { + // + // Save the properties and notify any listeners + // + pdpChanged(pdp); + return; + } + } + return; + + } + + @Override + public void updateGroup(EcompPDPGroup group) throws PAPException { + if (group == null || group.getId() == null) { + throw new PAPException("Group or id is null"); + } + if (group.getName() == null || group.getName().trim().length() == 0) { + throw new PAPException("New name for group cannot be null or blank"); + } + StdPDPGroup existingGroup = (StdPDPGroup)getGroup(group.getId()); + if (existingGroup == null) { + throw new PAPException("Update found no existing group with id '" + group.getId() + "'"); + } + + + // We do dramatically different things when the Name changes + // because the Name is essentially the identity of the group (as the User knows it) so when the Identity changes we have to change the group ID. + if (group.getName().equals(existingGroup.getName())) { + + // update the disk + try { + ((StdPDPGroup)group).saveGroupConfiguration(); + } catch (IOException e) { + throw new PAPException("Unable to save new configuration for '" + group.getName() + "': " + e.getMessage()); + } + // update the group in the set by simply replacing the old instance with the new one + this.groups.remove(existingGroup); + this.groups.add((StdPDPGroup)group); + + } else { + // the name/identity of the group has changed + // generate the new id + String newId = createNewPDPGroupId(group.getName()); + + // make sure no other group uses the new id + for (EcompPDPGroup g : groups) { + if (g.getId().equals(newId)) { + throw new PAPException("Replacement name maps to ID '" + newId + "' which is already in use"); + } + } + ((StdPDPGroup)group).setId(newId); + + // rename the existing directory to the new id + Path oldPath = existingGroup.getDirectory(); + Path newPath = Paths.get(oldPath.getParent().toString(), newId); + ((StdPDPGroup)group).setDirectory(newPath); + + try { + boolean success = oldPath.toFile().renameTo(newPath.toFile()); + if ( ! success) { + throw new PAPException("Unable to rename directory; reason unknown"); + } + } catch (Exception e) { + //TODO:EELF Cleanup - Remove logger + //logger.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + "Move '" + oldPath + "' to '" + newPath + "': " + e.getMessage(), e); + PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, e, "StdEngine", "Unable to rename directory"); + throw new PAPException("Unable to move directory from '" + oldPath + "' to '" + newPath + "': " + e.getMessage()); + } + // update the disk + try { + ((StdPDPGroup)group).saveGroupConfiguration(); + } catch (IOException e) { + throw new PAPException("Unable to save new configuration for '" + group.getName() + "': " + e.getMessage()); + } + + // save the new group into the Set + groups.remove(existingGroup); + groups.add((StdPDPGroup)group); + + } + + // perhaps only the group changed, but if the name/id changed it may look to a listener like more than one group + changed(); + + + } + + @Override + public void removeGroup(EcompPDPGroup group, EcompPDPGroup newGroup) throws PAPException, NullPointerException { + if (group == null) { + throw new NullPointerException(); + } + // + // Does this group exist? + // + if (this.groups.contains(group) == false) { + //TODO:EELF Cleanup - Remove logger + //logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "This group doesn't exist."); + PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE + "This group doesn't exist."); + throw new PAPException("The group '" + group.getId() + "' does not exist"); + } + // + // Is it the default group? + // + if (group.isDefaultGroup()) { + throw new PAPException("You cannot delete the default group."); + } + Set pdps = group.getEcompPdps(); + // + // Are there PDPs? If so, then we need a target group + // + if (pdps.isEmpty() == false && newGroup == null) { + throw new NullPointerException("Group targeted for deletion has PDPs, you must provide a new group for them."); + } + // + // Move the PDPs + // + if (pdps.isEmpty() == false) { + if (! (newGroup instanceof StdPDPGroup)) { + throw new PAPException("Unexpected class for newGroup: " + newGroup.getClass().getCanonicalName()); + } + // The movePDP function will modify the set of PDPs in the group. + // To avoid concurrent modification exceptions we need to duplicate the list before calling that function. + List pdpList = new ArrayList(); + for (EcompPDP pdp : pdps) { + pdpList.add(pdp); + } + // now we can use the PDPs from the list without having ConcurrentAccessExceptions + for (EcompPDP pdp : pdpList) { + this.movePDP(pdp, newGroup); + } + } + // + // remove the directory for the group + // + String id = group.getId(); + Path groupPath = Paths.get(this.repository.toString(), id); + // + // If it exists already + // + if ( ! Files.exists(groupPath)) { + logger.warn("removeGroup " + id + " directory does not exist" + groupPath.toString()); + } else { + try { + Files.walkFileTree(groupPath, new SimpleFileVisitor() { + + @Override + public FileVisitResult visitFile(Path file, + BasicFileAttributes attrs) throws IOException { + Files.delete(file); + return super.visitFile(file, attrs); + } + + }); + // + // delete the directory + // + Files.delete(groupPath); + } catch (IOException e) { + //TODO:EELF Cleanup - Remove logger + //logger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + "Failed to delete " + groupPath + ": " +e); + PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "StdEngine", "Failed to delete " + groupPath); + throw new PAPException("Failed to delete " + id); + } + } + + // remove the group from the set of all groups + groups.remove(group); + + // + // Save changes + // + changed(); + this.doSave(); + return; + + } + +} -- cgit 1.2.3-korg