2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.onap.policy.xacml.std.pap;
23 import com.att.research.xacml.api.pap.PAPException;
24 import com.att.research.xacml.api.pap.PDP;
25 import com.att.research.xacml.api.pap.PDPGroup;
26 import com.att.research.xacml.api.pap.PDPPIPConfig;
27 import com.att.research.xacml.api.pap.PDPPolicy;
28 import com.att.research.xacml.api.pap.PDPStatus;
29 import com.att.research.xacml.util.XACMLProperties;
30 import com.google.common.base.Joiner;
31 import com.google.common.base.Splitter;
32 import com.google.common.collect.Sets;
33 import java.io.FileInputStream;
34 import java.io.IOException;
35 import java.io.InputStream;
36 import java.io.OutputStream;
37 import java.nio.file.FileVisitResult;
38 import java.nio.file.Files;
39 import java.nio.file.Path;
40 import java.nio.file.Paths;
41 import java.nio.file.SimpleFileVisitor;
42 import java.nio.file.attribute.BasicFileAttributes;
43 import java.util.ArrayList;
44 import java.util.Collections;
45 import java.util.Enumeration;
46 import java.util.HashSet;
47 import java.util.List;
48 import java.util.Properties;
50 import java.util.TreeSet;
51 import org.apache.commons.logging.Log;
52 import org.apache.commons.logging.LogFactory;
53 import org.onap.policy.common.logging.eelf.MessageCodes;
54 import org.onap.policy.common.logging.eelf.PolicyLogger;
55 import org.onap.policy.xacml.api.XACMLErrorConstants;
56 import org.onap.policy.xacml.api.pap.OnapPDP;
57 import org.onap.policy.xacml.api.pap.OnapPDPGroup;
58 import org.onap.policy.xacml.api.pap.PAPPolicyEngine;
61 * This is a simple PAP engine that uses some property files and a simple directory structure in the file system to
62 * manage a policy repository and set of PDP nodes.
66 public class StdEngine extends StdPDPItemSetChangeNotifier implements PAPPolicyEngine {
67 public static final String pipPropertyFile = "pip.properties";
69 private static final String addGroup = "addGroup ";
71 private static Log logger = LogFactory.getLog(StdEngine.class);
73 public static final String PROP_PAP_REPO = "xacml.pap.pdps";
74 public static final String PROP_PAP_GROUPS = "xacml.pap.groups";
75 public static final String PROP_PAP_GROUPS_DEFAULT = "xacml.pap.groups.default";
76 public static final String PROP_PAP_GROUPS_DEFAULT_NAME = "default";
77 // this value will be accessed from XacmlPapServlet so that we know if a default group did not exist
78 // and was just added. This way, we can add the new group to the database.
79 public boolean wasDefaultGroupJustAdded = false;
81 protected final Path repository;
82 protected Set<StdPDPGroup> groups;
84 public StdEngine() throws PAPException, IOException {
86 // Get the location in the file system of our repository
88 this.repository = Paths.get(XACMLProperties.getProperty(PROP_PAP_REPO));
95 public StdEngine(Properties properties) throws PAPException, IOException {
97 // Get the location in the file system of our repository
99 this.repository = Paths.get(properties.getProperty(PROP_PAP_REPO));
106 public StdEngine(Path repository) throws PAPException, IOException {
110 this.repository = repository;
117 private void intialize() throws PAPException, IOException {
119 // Sanity check the repository path
121 if (this.repository == null) {
122 throw new PAPException("No repository specified.");
124 if (Files.notExists(this.repository)) {
125 Files.createDirectory(repository);
127 if (!Files.isDirectory(this.repository)) {
128 throw new PAPException("Repository is NOT a directory: " + this.repository.toAbsolutePath());
130 if (!Files.isWritable(this.repository)) {
131 throw new PAPException("Repository is NOT writable: " + this.repository.toAbsolutePath());
139 private void loadGroups() throws PAPException {
141 // Create a properties object
143 Properties properties = new Properties();
144 Path file = Paths.get(this.repository.toString(), XACMLProperties.XACML_PROPERTIES_NAME);
147 // Load the properties
149 try (InputStream is = new FileInputStream(file.toFile())) {
156 this.groups = this.readProperties(this.repository, properties);
157 } catch (IOException e) {
158 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "StdEngine", "Failed to load properties file");
159 this.groups = new HashSet<>();
162 // Initialize the default group
164 PDPGroup defaultGroup = this.initializeDefaultGroup(file, properties);
165 logger.info("Default group is: " + defaultGroup.getId() + "=" + defaultGroup.getName());
168 private PDPGroup initializeDefaultGroup(Path file, Properties properties) throws PAPException {
169 wasDefaultGroupJustAdded = false;
171 // Make sure we have the default group
173 PDPGroup group = this.getDefaultGroup();
175 wasDefaultGroupJustAdded = true;
179 // We don't have the default group, create it
181 String defaultId = properties.getProperty(PROP_PAP_GROUPS_DEFAULT, PROP_PAP_GROUPS_DEFAULT_NAME);
182 if ("".equals(defaultId)) {
183 defaultId = PROP_PAP_GROUPS_DEFAULT_NAME;
185 logger.warn("Default group does NOT exist, creating " + defaultId);
186 Path defaultPath = Paths.get(this.repository.toString(), defaultId);
191 if (Files.notExists(defaultPath)) {
193 // Create its directory
195 Files.createDirectory(defaultPath);
197 // Create property files
200 Properties props = new Properties();
201 props.setProperty(XACMLProperties.PROP_REFERENCEDPOLICIES, "");
202 props.setProperty(XACMLProperties.PROP_ROOTPOLICIES, "");
203 Path policyPath = Paths.get(defaultPath.toAbsolutePath().toString(), "xacml.policy.properties");
204 Files.createFile(policyPath);
205 try (OutputStream os = Files.newOutputStream(policyPath)) {
207 } catch (IOException e) {
208 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "StdEngine",
209 "Failed to write default policy properties");
213 Properties props = new Properties();
214 props = setPIPProperties(props);
215 Path pipPath = Paths.get(defaultPath.toAbsolutePath().toString(), "xacml.pip.properties");
216 Files.createFile(pipPath);
217 try (OutputStream os = Files.newOutputStream(pipPath)) {
219 } catch (IOException e) {
220 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "StdEngine",
221 "Failed to write default pip properties");
226 // Create the default group
228 StdPDPGroup newDefault = new StdPDPGroup(defaultId, true, "default",
229 "The default group where new PDP's are put.", defaultPath);
231 // Add it to our list
233 this.groups.add(newDefault);
235 // Save our properties out since we have
236 // a new default group.
238 StdEngine.setGroupProperties(newDefault, properties);
243 try (OutputStream os = Files.newOutputStream(file)) {
244 properties.store(os, "");
246 } catch (IOException e) {
247 PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, "StdEngine",
248 "Failed to save properties with new default group information.");
253 wasDefaultGroupJustAdded = true;
255 } catch (IOException e) {
256 PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, "StdEngine", "Failed to create default group");
257 throw new PAPException("Failed to create default group");
262 public OnapPDPGroup getDefaultGroup() throws PAPException {
263 for (OnapPDPGroup group : this.groups) {
264 if (group.isDefaultGroup()) {
269 // Default group doesn't exist
275 public OnapPDPGroup getGroup(String id) throws PAPException {
276 for (OnapPDPGroup g : this.groups) {
277 if (g.getId().equals(id)) {
285 public void newGroup(String name, String description) throws PAPException, NullPointerException {
290 throw new NullPointerException();
293 // Do we already have this group?
295 for (PDPGroup group : this.groups) {
296 if (group.getName().equals(name)) {
297 throw new PAPException("Group with this name=" + name + " already exists.");
302 // create an Id that can be used as a file name and a properties file key.
303 // Ids must not contain \/:*?"<>|=,;
304 // The ID must also be unique within the current set of PDPGroups.
305 String id = createNewPDPGroupId(name);
309 // Construct the directory path
311 Path groupPath = Paths.get(this.repository.toString(), id);
313 // If it exists already
315 if (Files.exists(groupPath)) {
316 logger.warn(addGroup + id + " directory exists");
320 // Create the directory
322 Files.createDirectory(groupPath);
323 } catch (IOException e) {
324 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "StdEngine", "Failed to create " + groupPath);
325 throw new PAPException("Failed to create " + id);
329 // Create the Policies
332 Path policyProperties = Paths.get(groupPath.toString(), "xacml.policy.properties");
333 if (Files.exists(policyProperties)) {
334 logger.warn(addGroup + id + " file exists");
336 Properties props = new Properties();
337 props.setProperty(XACMLProperties.PROP_REFERENCEDPOLICIES, "");
338 props.setProperty(XACMLProperties.PROP_ROOTPOLICIES, "");
340 Files.createFile(policyProperties);
341 try (OutputStream os = Files.newOutputStream(policyProperties)) {
344 } catch (IOException e) {
345 PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, "StdEngine", "Failed to create policyProperties");
346 throw new PAPException("Failed to create " + id);
350 // Create the PIP config
352 Path pipProperties = Paths.get(groupPath.toString(), "xacml.pip.properties");
353 Properties props = new Properties();
354 if (Files.exists(pipProperties)) {
355 logger.warn(addGroup + id + " file exists.");
358 props = setPIPProperties(props);
359 Files.createFile(pipProperties);
360 try (OutputStream os = Files.newOutputStream(pipProperties)) {
363 } catch (IOException e) {
364 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "StdEngine", "Failed to create pipProperties");
365 throw new PAPException("Failed to create " + id);
372 StdPDPGroup newGroup = new StdPDPGroup(id, name, description, groupPath);
373 // Add the default PIP configuration.
374 String list = props.getProperty(XACMLProperties.PROP_PIP_ENGINES);
375 if (list != null && list.length() > 0) {
376 Set<PDPPIPConfig> pipConfigs = new HashSet<>();
377 for (String pipID : list.split("[,]")) {
378 StdPDPPIPConfig config = new StdPDPPIPConfig(pipID, props);
379 if (config.isConfigured()) {
380 pipConfigs.add(config);
383 newGroup.setPipConfigs(pipConfigs);
385 if (this.groups.add(newGroup)) {
386 // save the new group in our properties and notify any listeners of the change
387 groupChanged(newGroup);
395 * 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
396 * is then this method throws an exception. The name is supposed to be unique within the current set of groups, so
397 * creating the ID based on the name will create a unique string.
402 private String createNewPDPGroupId(String name) {
404 // replace "bad" characters with sequences that will be ok for file names and properties keys.
405 id = id.replace(" ", "_sp_");
406 id = id.replace("\t", "_tab_");
407 id = id.replace("\\", "_bksl_");
408 id = id.replace("/", "_sl_");
409 id = id.replace(":", "_col_");
410 id = id.replace("*", "_ast_");
411 id = id.replace("?", "_q_");
412 id = id.replace("\"", "_quo_");
413 id = id.replace("<", "_lt_");
414 id = id.replace(">", "_gt_");
415 id = id.replace("|", "_bar_");
416 id = id.replace("=", "_eq_");
417 id = id.replace(",", "_com_");
418 id = id.replace(";", "_scom_");
425 public OnapPDP getPDP(String pdpId) throws PAPException {
426 for (OnapPDPGroup group : this.groups) {
427 for (OnapPDP pdp : group.getOnapPdps()) {
428 if (pdp.getId().equals(pdpId)) {
438 public void movePDP(OnapPDP pdp, OnapPDPGroup newGroup) throws PAPException {
439 if (newGroup == null) {
440 throw new NullPointerException("You must specify which group the PDP will belong to.");
442 PDPGroup currentGroup = this.getPDPGroup(pdp);
443 if (currentGroup == null) {
444 throw new PAPException("PDP must already belong to a group.");
446 if (currentGroup.equals(newGroup)) {
447 logger.warn("Already in that group.");
450 if (currentGroup instanceof StdPDPGroup && newGroup instanceof StdPDPGroup) {
451 if (((StdPDPGroup) currentGroup).removePDP(pdp)) {
452 boolean result = ((StdPDPGroup) newGroup).addPDP(pdp);
455 // Save the configuration
459 PolicyLogger.error("Failed to add to new group, putting back into original group.");
460 if (!((StdPDPGroup) currentGroup).removePDP(pdp)) {
462 .error(MessageCodes.ERROR_DATA_ISSUE + "Failed to put PDP back into original group.");
467 String message = "Unknown PDP group class: " + newGroup.getClass().getCanonicalName() + " and "
468 + currentGroup.getClass().getCanonicalName();
469 logger.warn(message);
470 throw new PAPException(message);
476 public void updatePDP(OnapPDP pdp) throws PAPException {
477 PDP currentPDP = this.getPDP(pdp.getId());
478 if (currentPDP == null) {
479 String message = "Unknown PDP id '" + pdp.getId() + "'";
480 logger.warn(message);
481 throw new PAPException(message);
484 // the only things that the user can change are name and description
485 currentPDP.setDescription(pdp.getDescription());
486 currentPDP.setName(pdp.getName());
487 if (currentPDP instanceof OnapPDP) {
488 ((OnapPDP) currentPDP).setJmxPort(pdp.getJmxPort());
494 public void removePDP(OnapPDP pdp) throws PAPException {
495 PDPGroup group = this.getPDPGroup(pdp);
497 throw new NullPointerException();
499 if (group instanceof StdPDPGroup) {
500 boolean result = ((StdPDPGroup) group).removePDP(pdp);
506 String message = "Unknown PDP group class: " + group.getClass().getCanonicalName();
507 logger.warn(message);
508 throw new PAPException(message);
514 * Should never be called - Detailed status is held on the PDP, not the PAP
516 public PDPStatus getStatus(OnapPDP pdp) throws PAPException {
517 return getPDP(pdp.getId()).getStatus();
521 public void publishPolicy(String id, String name, boolean isRoot, InputStream policy, OnapPDPGroup group)
522 throws PAPException {
524 throw new NullPointerException();
526 if (group instanceof StdPDPGroup && this.groups.contains(group)) {
527 ((StdPDPGroup) group).publishPolicy(id, name, isRoot, policy);
530 logger.warn("unknown PDP Group: " + group);
531 throw new PAPException("Unknown PDP Group: " + group.getId());
536 public void copyPolicy(PDPPolicy policy, OnapPDPGroup group) throws PAPException {
538 // Currently not used on the PAP side. This is done by ((StdPDPGroup) group).copyPolicyToFile
544 public void removePolicy(PDPPolicy policy, OnapPDPGroup group) throws PAPException {
546 throw new NullPointerException();
548 if (group instanceof StdPDPGroup && this.groups.contains(group)) {
549 ((StdPDPGroup) group).removePolicy(policy);
552 logger.warn("unknown PDP Group: " + group);
553 throw new PAPException("Unknown PDP Group: " + group.getId());
561 private Set<StdPDPGroup> readProperties(Path repository, Properties properties) throws PAPException {
562 Set<StdPDPGroup> pdpGroups = new HashSet<>();
564 // See if there is a groups property
566 String groupList = properties.getProperty(PROP_PAP_GROUPS, "");
567 if (groupList == null) {
568 logger.warn("null group list " + PROP_PAP_GROUPS);
571 if (logger.isDebugEnabled()) {
572 logger.debug("group list: " + groupList);
575 // Iterate the groups, converting to a set ensures we have unique groups.
577 for (String id : Splitter.on(',').trimResults().omitEmptyStrings().split(groupList)) {
579 // Add our Group Object
581 StdPDPGroup g = new StdPDPGroup(id.trim(),
582 id.equals(properties.getProperty(PROP_PAP_GROUPS_DEFAULT, PROP_PAP_GROUPS_DEFAULT_NAME)),
583 properties, Paths.get(repository.toString(), id));
593 if (logger.isDebugEnabled()) {
594 logger.debug("PDP Group List: " + pdpGroups.toString());
599 private void saveConfiguration() throws PAPException, IOException {
601 // Create our properties object
603 Properties properties = new Properties() {
604 private static final long serialVersionUID = 1L;
606 // For Debugging it is helpful for the file to be in a sorted order,
607 // any by returning the keys in the natural Alpha order for strings we get close enough.
608 // TreeSet is sorted, and this just overrides the normal Properties method to get the keys.
610 public synchronized Enumeration<Object> keys() {
611 return Collections.enumeration(new TreeSet<Object>(super.keySet()));
615 // Iterate our groups
617 List<String> ids = new ArrayList<>();
618 for (PDPGroup group : this.groups) {
619 ids.add(group.getId());
620 properties.setProperty(group.getId() + ".name", group.getName() == null ? "" : group.getName());
621 properties.setProperty(group.getId() + ".description",
622 group.getDescription() == null ? "" : group.getDescription());
626 List<String> pdps = new ArrayList<>();
627 for (PDP pdp : group.getPdps()) {
628 pdps.add(pdp.getId());
629 properties.setProperty(pdp.getId() + ".name", pdp.getName() == null ? "" : pdp.getName());
630 properties.setProperty(pdp.getId() + ".description",
631 pdp.getDescription() == null ? "" : pdp.getDescription());
632 if (pdp instanceof OnapPDP) {
633 properties.setProperty(pdp.getId() + ".jmxport",
634 (((OnapPDP) pdp).getJmxPort() == 0 ? "" : ((OnapPDP) pdp).getJmxPort()).toString());
638 if (pdps.size() == 1) {
639 pdpList = pdps.get(0);
640 } else if (pdps.size() > 1) {
641 pdpList = Joiner.on(',').skipNulls().join(pdps);
643 if (logger.isDebugEnabled()) {
644 logger.debug("Group " + group.getId() + " PDPS: " + pdpList);
646 properties.setProperty(group.getId() + ".pdps", pdpList);
649 throw new PAPException("Inconsistency - we have NO groups. We should have at least one.");
651 String groupList = "";
652 if (ids.size() == 1) {
653 groupList = ids.get(0);
654 } else if (ids.size() > 1) {
655 groupList = Joiner.on(',').skipNulls().join(ids);
657 logger.info("New Group List: " + groupList);
659 properties.setProperty(PROP_PAP_GROUPS, groupList);
661 // Get the default group
663 PDPGroup defaultGroup = this.getDefaultGroup();
664 if (defaultGroup == null) {
665 throw new PAPException("Invalid state - no default group.");
667 properties.setProperty(PROP_PAP_GROUPS_DEFAULT, defaultGroup.getId());
669 // Now we can save the file
671 Path file = Paths.get(this.repository.toString(), "xacml.properties");
672 try (OutputStream os = Files.newOutputStream(file)) {
673 properties.store(os, "");
677 public static void removeGroupProperties(String id, Properties properties) {
678 for (Object key : properties.keySet()) {
679 if (key.toString().startsWith(id + ".")) {
680 properties.remove(key);
685 public static void setGroupProperties(PDPGroup group, Properties properties) {
687 // make sure its in the list of groups
689 Iterable<String> groups =
690 Splitter.on(',').trimResults().omitEmptyStrings().split(properties.getProperty(PROP_PAP_GROUPS, ""));
691 boolean inList = false;
692 for (String g : groups) {
693 if (g.equals(group.getId())) {
698 Set<String> grps = Sets.newHashSet(groups);
699 grps.add(group.getId());
701 if (grps.size() == 1) {
702 newGroupList = grps.iterator().next();
703 } else if (grps.size() > 1) {
704 newGroupList = Joiner.on(',').skipNulls().join(grps);
708 logger.info("New Group List: " + newGroupList);
709 properties.setProperty(PROP_PAP_GROUPS, newGroupList);
712 // Set its properties
714 properties.setProperty(group.getId() + ".name", group.getName());
715 properties.setProperty(group.getId() + ".description", group.getDescription());
719 if (!group.getPdps().isEmpty()) {
721 if (group.getPdps().size() == 1) {
722 pdpList = group.getPdps().iterator().next().getId();
723 } else if (group.getPdps().size() > 1) {
724 Set<String> ids = new HashSet<>();
725 for (PDP pdp : group.getPdps()) {
726 ids.add(pdp.getId());
728 pdpList = Joiner.on(',').skipNulls().join(ids);
730 properties.setProperty(group.getId() + ".pdps", pdpList);
732 properties.setProperty(group.getId() + ".pdps", "");
737 public void changed() {
738 if (logger.isDebugEnabled()) {
739 logger.debug("changed");
745 public void groupChanged(OnapPDPGroup group) {
746 if (logger.isDebugEnabled()) {
747 logger.debug("groupChanged: " + group);
750 this.firePDPGroupChanged(group);
754 public void pdpChanged(OnapPDP pdp) {
755 if (logger.isDebugEnabled()) {
756 logger.debug("pdpChanged: " + pdp);
759 this.firePDPChanged(pdp);
762 private void doSave() {
765 // Save the configuration
767 this.saveConfiguration();
768 } catch (IOException | PAPException e) {
769 PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, e, "StdEngine", "Failed to save configuration");
773 private Properties setPIPProperties(Properties props) {
774 props.setProperty(XACMLProperties.PROP_PIP_ENGINES, "AAF");
775 props.setProperty("AAF.name", "AAFEngine");
776 props.setProperty("AAF.description", "AAFEngine to communicate with AAF to take decisions");
777 props.setProperty("AAF.classname", "org.onap.policy.xacml.std.pip.engines.aaf.AAFEngine");
778 // read from PIP properties file.
779 Path file = Paths.get(pipPropertyFile);
780 if (!Files.notExists(file)) {
782 Properties prop = new Properties();
784 in = new FileInputStream(file.toFile());
786 } catch (IOException e) {
788 XACMLErrorConstants.ERROR_SYSTEM_ERROR + "can not load the pip properties from file" + e);
797 public Set<OnapPDPGroup> getOnapPDPGroups() throws PAPException {
798 final Set<OnapPDPGroup> grps = new HashSet<>();
799 for (OnapPDPGroup g : this.groups) {
802 return Collections.unmodifiableSet(grps);
806 public OnapPDPGroup getPDPGroup(OnapPDP pdp) throws PAPException {
807 for (OnapPDPGroup group : this.groups) {
808 if (group.getPdps().contains(pdp)) {
816 public void setDefaultGroup(OnapPDPGroup group) throws PAPException {
817 boolean changesMade = false;
818 for (OnapPDPGroup aGroup : groups) {
819 if (aGroup.getId().equals(group.getId())) {
820 if (!aGroup.isDefaultGroup()) {
821 if (aGroup instanceof StdPDPGroup) {
822 ((StdPDPGroup) aGroup).setDefault(true);
825 throw new IllegalArgumentException(
826 "Group in groups of unknown type '" + aGroup.getClass().getName() + "'");
830 // not the new default group
831 if (aGroup.isDefaultGroup()) {
832 if (aGroup instanceof StdPDPGroup) {
833 ((StdPDPGroup) aGroup).setDefault(false);
836 throw new IllegalArgumentException(
837 "Group in groups of unknown type '" + aGroup.getClass().getName() + "'");
851 public void newPDP(String id, OnapPDPGroup group, String name, String description, int jmxport)
852 throws PAPException, NullPointerException {
854 throw new PAPException("You must specify which group the PDP will belong to.");
856 if (!this.groups.contains(group)) {
857 throw new PAPException("Unknown group, not in our list.");
859 for (OnapPDP p : group.getOnapPdps()) {
860 if (p.getId().equals(id)) {
861 throw new PAPException("A PDP with this ID exists.");
864 if (group instanceof StdPDPGroup) {
865 StdPDP pdp = new StdPDP(id, name, description, jmxport);
866 if (((StdPDPGroup) group).addPDP(pdp)) {
868 // Save the properties and notify any listeners
879 public void updateGroup(OnapPDPGroup group) throws PAPException {
880 if (group == null || group.getId() == null) {
881 throw new PAPException("Group or id is null");
883 if (group.getName() == null || group.getName().trim().length() == 0) {
884 throw new PAPException("New name for group cannot be null or blank");
886 StdPDPGroup existingGroup = (StdPDPGroup) getGroup(group.getId());
887 if (existingGroup == null) {
888 throw new PAPException("Update found no existing group with id '" + group.getId() + "'");
892 // We do dramatically different things when the Name changes
893 // because the Name is essentially the identity of the group (as the User knows it) so when the Identity changes
894 // we have to change the group ID.
895 if (group.getName().equals(existingGroup.getName())) {
899 ((StdPDPGroup) group).saveGroupConfiguration();
900 } catch (IOException e) {
901 throw new PAPException(
902 "Unable to save new configuration for '" + group.getName() + "': " + e.getMessage(), e);
904 // update the group in the set by simply replacing the old instance with the new one
905 this.groups.remove(existingGroup);
906 this.groups.add((StdPDPGroup) group);
909 // the name/identity of the group has changed
910 // generate the new id
911 String newId = createNewPDPGroupId(group.getName());
913 // make sure no other group uses the new id
914 for (OnapPDPGroup g : groups) {
915 if (g.getId().equals(newId)) {
916 throw new PAPException("Replacement name maps to ID '" + newId + "' which is already in use");
919 ((StdPDPGroup) group).setId(newId);
921 // rename the existing directory to the new id
922 Path oldPath = existingGroup.getDirectory();
923 Path newPath = Paths.get(oldPath.getParent().toString(), newId);
924 ((StdPDPGroup) group).setDirectory(newPath);
927 boolean success = oldPath.toFile().renameTo(newPath.toFile());
929 throw new PAPException("Unable to rename directory; reason unknown");
931 } catch (Exception e) {
932 PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, e, "StdEngine", "Unable to rename directory");
933 throw new PAPException(
934 "Unable to move directory from '" + oldPath + "' to '" + newPath + "': " + e.getMessage(), e);
938 ((StdPDPGroup) group).saveGroupConfiguration();
939 } catch (IOException e) {
940 throw new PAPException(
941 "Unable to save new configuration for '" + group.getName() + "': " + e.getMessage(), e);
944 // save the new group into the Set
945 groups.remove(existingGroup);
946 groups.add((StdPDPGroup) group);
950 // perhaps only the group changed, but if the name/id changed it may look to a listener like more than one group
957 public void removeGroup(OnapPDPGroup group, OnapPDPGroup newGroup) throws PAPException, NullPointerException {
959 throw new NullPointerException();
962 // Does this group exist?
964 if (!this.groups.contains(group)) {
965 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE + "This group doesn't exist.");
966 throw new PAPException("The group '" + group.getId() + "' does not exist");
969 // Is it the default group?
971 if (group.isDefaultGroup()) {
972 throw new PAPException("You cannot delete the default group.");
974 Set<OnapPDP> pdps = group.getOnapPdps();
976 // Are there PDPs? If so, then we need a target group
978 if (!pdps.isEmpty() && newGroup == null) {
979 throw new NullPointerException(
980 "Group targeted for deletion has PDPs, you must provide a new group for them.");
985 if (!pdps.isEmpty()) {
986 if (!(newGroup instanceof StdPDPGroup)) {
987 throw new PAPException("Unexpected class for newGroup: " + newGroup.getClass().getCanonicalName());
989 // The movePDP function will modify the set of PDPs in the group.
990 // To avoid concurrent modification exceptions we need to duplicate the list before calling that function.
991 List<OnapPDP> pdpList = new ArrayList<>();
992 for (OnapPDP pdp : pdps) {
995 // now we can use the PDPs from the list without having ConcurrentAccessExceptions
996 for (OnapPDP pdp : pdpList) {
997 this.movePDP(pdp, newGroup);
1001 // remove the directory for the group
1003 String id = group.getId();
1004 Path groupPath = Paths.get(this.repository.toString(), id);
1006 // If it exists already
1008 if (!Files.exists(groupPath)) {
1009 logger.warn("removeGroup " + id + " directory does not exist" + groupPath.toString());
1012 Files.walkFileTree(groupPath, new SimpleFileVisitor<Path>() {
1015 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
1017 return super.visitFile(file, attrs);
1022 // delete the directory
1024 Files.delete(groupPath);
1025 } catch (IOException e) {
1026 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "StdEngine", "Failed to delete " + groupPath);
1027 throw new PAPException("Failed to delete " + id);
1031 // remove the group from the set of all groups
1032 groups.remove(group);
1044 public void updateGroup(OnapPDPGroup group, String userName) throws PAPException {
1045 // To pass the userId for PDP Audit log maintenance.