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;
34 import java.io.FileInputStream;
35 import java.io.IOException;
36 import java.io.InputStream;
37 import java.io.OutputStream;
38 import java.nio.file.FileVisitResult;
39 import java.nio.file.Files;
40 import java.nio.file.Path;
41 import java.nio.file.Paths;
42 import java.nio.file.SimpleFileVisitor;
43 import java.nio.file.attribute.BasicFileAttributes;
44 import java.util.ArrayList;
45 import java.util.Collections;
46 import java.util.Enumeration;
47 import java.util.HashSet;
48 import java.util.List;
49 import java.util.Properties;
51 import java.util.TreeSet;
53 import org.apache.commons.logging.Log;
54 import org.apache.commons.logging.LogFactory;
55 import org.onap.policy.common.logging.eelf.MessageCodes;
56 import org.onap.policy.common.logging.eelf.PolicyLogger;
57 import org.onap.policy.xacml.api.XACMLErrorConstants;
58 import org.onap.policy.xacml.api.pap.OnapPDP;
59 import org.onap.policy.xacml.api.pap.OnapPDPGroup;
60 import org.onap.policy.xacml.api.pap.PAPPolicyEngine;
63 * This is a simple PAP engine that uses some property files and a simple directory structure in the file system to
64 * manage a policy repository and set of PDP nodes.
68 public class StdEngine extends StdPDPItemSetChangeNotifier implements PAPPolicyEngine {
69 public static final String PIP_PROPERTY_FILE = "pip.properties";
71 private static final String STR_ADDGROUP = "addGroup ";
72 private static final String STR_CLASS = "StdEngine";
73 private static final String STR_APPEND_NAME = ".name";
74 private static final String STR_APPEND_DESCRIPTION = ".description";
75 private static final String STR_APPEND_PDPS = ".pdps";
77 private static Log logger = LogFactory.getLog(StdEngine.class);
79 public static final String PROP_PAP_REPO = "xacml.pap.pdps";
80 public static final String PROP_PAP_GROUPS = "xacml.pap.groups";
81 public static final String PROP_PAP_GROUPS_DEFAULT = "xacml.pap.groups.default";
82 public static final String PROP_PAP_GROUPS_DEFAULT_NAME = "default";
83 // this value will be accessed from XacmlPapServlet so that we know if a default group did not exist
84 // and was just added. This way, we can add the new group to the database.
85 public boolean wasDefaultGroupJustAdded = false;
87 protected final Path repository;
88 protected Set<StdPDPGroup> groups;
91 * StdEngine constructor.
93 * @throws PAPException PAPException
94 * @throws IOException IOException
96 public StdEngine() throws PAPException, IOException {
98 // Get the location in the file system of our repository
100 this.repository = Paths.get(XACMLProperties.getProperty(PROP_PAP_REPO));
108 * StdEngine constructor.
110 * @param properties Properties
111 * @throws PAPException PAPException
112 * @throws IOException IOException
114 public StdEngine(Properties properties) throws PAPException, IOException {
116 // Get the location in the file system of our repository
118 this.repository = Paths.get(properties.getProperty(PROP_PAP_REPO));
126 * StdEngine constructor.
128 * @param repository Path
129 * @throws PAPException PAPException
130 * @throws IOException IOException
132 public StdEngine(Path repository) throws PAPException, IOException {
136 this.repository = repository;
143 private void intialize() throws PAPException, IOException {
145 // Sanity check the repository path
147 if (this.repository == null) {
148 throw new PAPException("No repository specified.");
150 if (! this.repository.toFile().exists()) {
151 Files.createDirectory(repository);
153 if (! this.repository.toFile().isDirectory()) {
154 throw new PAPException("Repository is NOT a directory: " + this.repository.toAbsolutePath());
156 if (! this.repository.toFile().canWrite()) {
157 throw new PAPException("Repository is NOT writable: " + this.repository.toAbsolutePath());
165 private void loadGroups() throws PAPException {
167 // Create a properties object
169 Properties properties = new Properties();
170 Path file = Paths.get(this.repository.toString(), XACMLProperties.XACML_PROPERTIES_NAME);
173 // Load the properties
175 try (InputStream is = new FileInputStream(file.toFile())) {
182 this.groups = this.readProperties(this.repository, properties);
183 } catch (IOException e) {
184 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, STR_CLASS, "Failed to load properties file");
185 this.groups = new HashSet<>();
188 // Initialize the default group
190 PDPGroup defaultGroup = this.initializeDefaultGroup(file, properties);
191 logger.info("Default group is: " + defaultGroup.getId() + "=" + defaultGroup.getName());
194 private PDPGroup initializeDefaultGroup(Path file, Properties properties) throws PAPException {
195 wasDefaultGroupJustAdded = false;
197 // Make sure we have the default group
199 PDPGroup group = this.getDefaultGroup();
201 wasDefaultGroupJustAdded = true;
205 // We don't have the default group, create it
207 String defaultId = properties.getProperty(PROP_PAP_GROUPS_DEFAULT, PROP_PAP_GROUPS_DEFAULT_NAME);
208 if ("".equals(defaultId)) {
209 defaultId = PROP_PAP_GROUPS_DEFAULT_NAME;
211 logger.warn("Default group does NOT exist, creating " + defaultId);
212 Path defaultPath = Paths.get(this.repository.toString(), defaultId);
217 if (! defaultPath.toFile().exists()) {
219 // Create its directory
221 Files.createDirectory(defaultPath);
223 // Create property files
226 Properties props = new Properties();
227 props.setProperty(XACMLProperties.PROP_REFERENCEDPOLICIES, "");
228 props.setProperty(XACMLProperties.PROP_ROOTPOLICIES, "");
229 Path policyPath = Paths.get(defaultPath.toAbsolutePath().toString(), "xacml.policy.properties");
230 Files.createFile(policyPath);
231 try (OutputStream os = Files.newOutputStream(policyPath)) {
233 } catch (IOException e) {
234 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, STR_CLASS,
235 "Failed to write default policy properties");
239 Properties props = new Properties();
240 props = setPipProperties(props);
241 Path pipPath = Paths.get(defaultPath.toAbsolutePath().toString(), "xacml.pip.properties");
242 Files.createFile(pipPath);
243 try (OutputStream os = Files.newOutputStream(pipPath)) {
245 } catch (IOException e) {
246 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, STR_CLASS,
247 "Failed to write default pip properties");
252 // Create the default group
254 StdPDPGroup newDefault = new StdPDPGroup(defaultId, true, PROP_PAP_GROUPS_DEFAULT_NAME,
255 "The default group where new PDP's are put.", defaultPath);
257 // Add it to our list
259 this.groups.add(newDefault);
261 // Save our properties out since we have
262 // a new default group.
264 StdEngine.setGroupProperties(newDefault, properties);
269 try (OutputStream os = Files.newOutputStream(file)) {
270 properties.store(os, "");
272 } catch (IOException e) {
273 PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, STR_CLASS,
274 "Failed to save properties with new default group information.");
279 wasDefaultGroupJustAdded = true;
281 } catch (IOException e) {
282 PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, STR_CLASS, "Failed to create default group");
283 throw new PAPException("Failed to create default group");
288 public OnapPDPGroup getDefaultGroup() throws PAPException {
289 for (OnapPDPGroup group : this.groups) {
290 if (group.isDefaultGroup()) {
295 // Default group doesn't exist
301 public OnapPDPGroup getGroup(String id) throws PAPException {
302 for (OnapPDPGroup g : this.groups) {
303 if (g.getId().equals(id)) {
311 public void newGroup(String name, String description) throws PAPException {
316 throw new NullPointerException();
319 // Do we already have this group?
321 for (PDPGroup group : this.groups) {
322 if (group.getName().equals(name)) {
323 throw new PAPException("Group with this name=" + name + " already exists.");
327 // create an Id that can be used as a file name and a properties file key.
328 // Ids must not contain \/:*?"<>|=,;
329 // The ID must also be unique within the current set of PDPGroups.
330 String id = createNewPdpGroupId(name);
333 // Construct the directory path
335 Path groupPath = Paths.get(this.repository.toString(), id);
337 // If it exists already
339 if (Files.exists(groupPath)) {
340 logger.warn(STR_ADDGROUP + id + " directory exists");
344 // Create the directory
346 Files.createDirectory(groupPath);
347 } catch (IOException e) {
348 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, STR_CLASS, "Failed to create " + groupPath);
349 throw new PAPException("Failed to create " + id);
353 // Create the Policies
356 Path policyProperties = Paths.get(groupPath.toString(), "xacml.policy.properties");
357 if (policyProperties.toFile().exists()) {
358 logger.warn(STR_ADDGROUP + id + " file exists");
360 Properties props = new Properties();
361 props.setProperty(XACMLProperties.PROP_REFERENCEDPOLICIES, "");
362 props.setProperty(XACMLProperties.PROP_ROOTPOLICIES, "");
364 Files.createFile(policyProperties);
365 try (OutputStream os = Files.newOutputStream(policyProperties)) {
368 } catch (IOException e) {
369 PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, STR_CLASS, "Failed to create policyProperties");
370 throw new PAPException("Failed to create " + id);
374 // Create the PIP config
376 Path pipProperties = Paths.get(groupPath.toString(), "xacml.pip.properties");
377 Properties props = new Properties();
378 if (pipProperties.toFile().exists()) {
379 logger.warn(STR_ADDGROUP + id + " file exists.");
382 props = setPipProperties(props);
383 Files.createFile(pipProperties);
384 try (OutputStream os = Files.newOutputStream(pipProperties)) {
387 } catch (IOException e) {
388 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, STR_CLASS, "Failed to create pipProperties");
389 throw new PAPException("Failed to create " + id);
396 StdPDPGroup newGroup = new StdPDPGroup(id, name, description, groupPath);
397 // Add the default PIP configuration.
398 String list = props.getProperty(XACMLProperties.PROP_PIP_ENGINES);
399 if (list != null && list.length() > 0) {
400 Set<PDPPIPConfig> pipConfigs = new HashSet<>();
401 for (String pipID : list.split("[,]")) {
402 StdPDPPIPConfig config = new StdPDPPIPConfig(pipID, props);
403 if (config.isConfigured()) {
404 pipConfigs.add(config);
407 newGroup.setPipConfigs(pipConfigs);
409 if (this.groups.add(newGroup)) {
410 // save the new group in our properties and notify any listeners of the change
411 groupChanged(newGroup);
417 * 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
418 * is then this method throws an exception. The name is supposed to be unique within the current set of groups, so
419 * creating the ID based on the name will create a unique string.
424 private String createNewPdpGroupId(String name) {
426 // replace "bad" characters with sequences that will be ok for file names and properties keys.
427 id = id.replace(" ", "_sp_");
428 id = id.replace("\t", "_tab_");
429 id = id.replace("\\", "_bksl_");
430 id = id.replace("/", "_sl_");
431 id = id.replace(":", "_col_");
432 id = id.replace("*", "_ast_");
433 id = id.replace("?", "_q_");
434 id = id.replace("\"", "_quo_");
435 id = id.replace("<", "_lt_");
436 id = id.replace(">", "_gt_");
437 id = id.replace("|", "_bar_");
438 id = id.replace("=", "_eq_");
439 id = id.replace(",", "_com_");
440 id = id.replace(";", "_scom_");
446 public OnapPDP getPDP(String pdpId) throws PAPException {
447 for (OnapPDPGroup group : this.groups) {
448 for (OnapPDP pdp : group.getOnapPdps()) {
449 if (pdp.getId().equals(pdpId)) {
458 public void movePDP(OnapPDP pdp, OnapPDPGroup newGroup) throws PAPException {
459 if (newGroup == null) {
460 throw new NullPointerException("You must specify which group the PDP will belong to.");
462 PDPGroup currentGroup = this.getPDPGroup(pdp);
463 if (currentGroup == null) {
464 throw new PAPException("PDP must already belong to a group.");
466 if (currentGroup.equals(newGroup)) {
467 logger.warn("Already in that group.");
470 if (currentGroup instanceof StdPDPGroup && newGroup instanceof StdPDPGroup) {
471 if (((StdPDPGroup) currentGroup).removePDP(pdp)) {
472 boolean result = ((StdPDPGroup) newGroup).addPDP(pdp);
475 // Save the configuration
479 PolicyLogger.error("Failed to add to new group, putting back into original group.");
480 if (!((StdPDPGroup) currentGroup).removePDP(pdp)) {
482 .error(MessageCodes.ERROR_DATA_ISSUE + "Failed to put PDP back into original group.");
487 String message = "Unknown PDP group class: " + newGroup.getClass().getCanonicalName() + " and "
488 + currentGroup.getClass().getCanonicalName();
489 logger.warn(message);
490 throw new PAPException(message);
495 public void updatePDP(OnapPDP pdp) throws PAPException {
496 PDP currentPdp = this.getPDP(pdp.getId());
497 if (currentPdp == null) {
498 String message = "Unknown PDP id '" + pdp.getId() + "'";
499 logger.warn(message);
500 throw new PAPException(message);
503 // the only things that the user can change are name and description
504 currentPdp.setDescription(pdp.getDescription());
505 currentPdp.setName(pdp.getName());
506 if (currentPdp instanceof OnapPDP) {
507 ((OnapPDP) currentPdp).setJmxPort(pdp.getJmxPort());
513 public void removePDP(OnapPDP pdp) throws PAPException {
514 PDPGroup group = this.getPDPGroup(pdp);
516 throw new NullPointerException();
518 if (group instanceof StdPDPGroup) {
519 boolean result = ((StdPDPGroup) group).removePDP(pdp);
525 String message = "Unknown PDP group class: " + group.getClass().getCanonicalName();
526 logger.warn(message);
527 throw new PAPException(message);
532 * Should never be called - Detailed status is held on the PDP, not the PAP
534 public PDPStatus getStatus(OnapPDP pdp) throws PAPException {
535 return getPDP(pdp.getId()).getStatus();
539 public void publishPolicy(String id, String name, boolean isRoot, InputStream policy, OnapPDPGroup group)
540 throws PAPException {
542 throw new NullPointerException();
544 if (group instanceof StdPDPGroup && this.groups.contains(group)) {
545 ((StdPDPGroup) group).publishPolicy(id, name, isRoot, policy);
548 logger.warn("unknown PDP Group: " + group);
549 throw new PAPException("Unknown PDP Group: " + group.getId());
553 public void copyPolicy(PDPPolicy policy, OnapPDPGroup group, String userId) throws PAPException {
555 // Currently not used on the PAP side. This is done by ((StdPDPGroup) group).copyPolicyToFile
560 public void removePolicy(PDPPolicy policy, OnapPDPGroup group) throws PAPException {
562 throw new NullPointerException();
564 if (group instanceof StdPDPGroup && this.groups.contains(group)) {
565 ((StdPDPGroup) group).removePolicy(policy);
568 logger.warn("unknown PDP Group: " + group);
569 throw new PAPException("Unknown PDP Group: " + group.getId());
576 private Set<StdPDPGroup> readProperties(Path repository, Properties properties) throws PAPException {
577 Set<StdPDPGroup> pdpGroups = new HashSet<>();
579 // See if there is a groups property
581 String groupList = properties.getProperty(PROP_PAP_GROUPS, "");
582 if (groupList == null) {
583 logger.warn("null group list " + PROP_PAP_GROUPS);
586 if (logger.isDebugEnabled()) {
587 logger.debug("group list: " + groupList);
590 // Iterate the groups, converting to a set ensures we have unique groups.
592 for (String id : Splitter.on(',').trimResults().omitEmptyStrings().split(groupList)) {
594 // Add our Group Object
596 StdPDPGroup newGroup = new StdPDPGroup(id.trim(),
597 id.equals(properties.getProperty(PROP_PAP_GROUPS_DEFAULT, PROP_PAP_GROUPS_DEFAULT_NAME)),
598 properties, Paths.get(repository.toString(), id));
603 pdpGroups.add(newGroup);
608 if (logger.isDebugEnabled()) {
609 logger.debug("PDP Group List: " + pdpGroups.toString());
614 private void saveConfiguration() throws PAPException, IOException {
616 // Create our properties object
618 Properties properties = new Properties() {
619 private static final long serialVersionUID = 1L;
621 // For Debugging it is helpful for the file to be in a sorted order,
622 // any by returning the keys in the natural Alpha order for strings we get close enough.
623 // TreeSet is sorted, and this just overrides the normal Properties method to get the keys.
625 public synchronized Enumeration<Object> keys() {
626 return Collections.enumeration(new TreeSet<Object>(super.keySet()));
630 // Iterate our groups
632 List<String> ids = new ArrayList<>();
633 for (PDPGroup group : this.groups) {
634 ids.add(group.getId());
635 properties.setProperty(group.getId() + STR_APPEND_NAME, group.getName() == null ? "" : group.getName());
636 properties.setProperty(group.getId() + STR_APPEND_DESCRIPTION,
637 group.getDescription() == null ? "" : group.getDescription());
641 List<String> pdps = new ArrayList<>();
642 for (PDP pdp : group.getPdps()) {
643 pdps.add(pdp.getId());
644 properties.setProperty(pdp.getId() + STR_APPEND_NAME, pdp.getName() == null ? "" : pdp.getName());
645 properties.setProperty(pdp.getId() + STR_APPEND_DESCRIPTION,
646 pdp.getDescription() == null ? "" : pdp.getDescription());
647 if (pdp instanceof OnapPDP) {
648 properties.setProperty(pdp.getId() + ".jmxport",
649 (((OnapPDP) pdp).getJmxPort() == 0 ? "" : ((OnapPDP) pdp).getJmxPort()).toString());
653 if (pdps.size() == 1) {
654 pdpList = pdps.get(0);
655 } else if (pdps.size() > 1) {
656 pdpList = Joiner.on(',').skipNulls().join(pdps);
658 if (logger.isDebugEnabled()) {
659 logger.debug("Group " + group.getId() + " PDPS: " + pdpList);
661 properties.setProperty(group.getId() + STR_APPEND_PDPS, pdpList);
664 throw new PAPException("Inconsistency - we have NO groups. We should have at least one.");
666 String groupList = "";
667 if (ids.size() == 1) {
668 groupList = ids.get(0);
669 } else if (ids.size() > 1) {
670 groupList = Joiner.on(',').skipNulls().join(ids);
672 logger.info("New Group List: " + groupList);
674 properties.setProperty(PROP_PAP_GROUPS, groupList);
676 // Get the default group
678 PDPGroup defaultGroup = this.getDefaultGroup();
679 if (defaultGroup == null) {
680 throw new PAPException("Invalid state - no default group.");
682 properties.setProperty(PROP_PAP_GROUPS_DEFAULT, defaultGroup.getId());
684 // Now we can save the file
686 Path file = Paths.get(this.repository.toString(), "xacml.properties");
687 try (OutputStream os = Files.newOutputStream(file)) {
688 properties.store(os, "");
693 * setGroupProperties.
695 * @param group PDPGroup
696 * @param properties Properties
698 public static void setGroupProperties(PDPGroup group, Properties properties) {
700 // make sure its in the list of groups
702 Iterable<String> groups =
703 Splitter.on(',').trimResults().omitEmptyStrings().split(properties.getProperty(PROP_PAP_GROUPS, ""));
704 boolean inList = false;
705 for (String g : groups) {
706 if (g.equals(group.getId())) {
711 Set<String> grps = Sets.newHashSet(groups);
712 grps.add(group.getId());
714 if (grps.size() == 1) {
715 newGroupList = grps.iterator().next();
716 } else if (grps.size() > 1) {
717 newGroupList = Joiner.on(',').skipNulls().join(grps);
721 logger.info("New Group List: " + newGroupList);
722 properties.setProperty(PROP_PAP_GROUPS, newGroupList);
725 // Set its properties
727 properties.setProperty(group.getId() + STR_APPEND_NAME, group.getName());
728 properties.setProperty(group.getId() + STR_APPEND_DESCRIPTION, group.getDescription());
732 if (!group.getPdps().isEmpty()) {
734 if (group.getPdps().size() == 1) {
735 pdpList = group.getPdps().iterator().next().getId();
736 } else if (group.getPdps().size() > 1) {
737 Set<String> ids = new HashSet<>();
738 for (PDP pdp : group.getPdps()) {
739 ids.add(pdp.getId());
741 pdpList = Joiner.on(',').skipNulls().join(ids);
743 properties.setProperty(group.getId() + STR_APPEND_PDPS, pdpList);
745 properties.setProperty(group.getId() + STR_APPEND_PDPS, "");
752 public void changed() {
753 if (logger.isDebugEnabled()) {
754 logger.debug("changed");
763 * @param group OnapPDPGroup
765 public void groupChanged(OnapPDPGroup group) {
766 if (logger.isDebugEnabled()) {
767 logger.debug("groupChanged: " + group);
770 this.firePDPGroupChanged(group);
778 public void pdpChanged(OnapPDP pdp) {
779 if (logger.isDebugEnabled()) {
780 logger.debug("pdpChanged: " + pdp);
783 this.firePDPChanged(pdp);
786 private void doSave() {
789 // Save the configuration
791 this.saveConfiguration();
792 } catch (IOException | PAPException e) {
793 PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, e, STR_CLASS, "Failed to save configuration");
797 private Properties setPipProperties(Properties props) {
798 props.setProperty(XACMLProperties.PROP_PIP_ENGINES, "AAF");
799 props.setProperty("AAF.name", "AAFEngine");
800 props.setProperty("AAF.description", "AAFEngine to communicate with AAF to take decisions");
801 props.setProperty("AAF.classname", "org.onap.policy.xacml.std.pip.engines.aaf.AAFEngine");
802 // read from PIP properties file.
803 Path file = Paths.get(PIP_PROPERTY_FILE);
804 if (file.toFile().exists()) {
806 Properties prop = new Properties();
808 in = new FileInputStream(file.toFile());
810 } catch (IOException e) {
812 XACMLErrorConstants.ERROR_SYSTEM_ERROR + "can not load the pip properties from file" + e);
820 public Set<OnapPDPGroup> getOnapPDPGroups() throws PAPException {
821 final Set<OnapPDPGroup> grps = new HashSet<>();
822 for (OnapPDPGroup g : this.groups) {
825 return Collections.unmodifiableSet(grps);
829 public OnapPDPGroup getPDPGroup(OnapPDP pdp) throws PAPException {
830 for (OnapPDPGroup group : this.groups) {
831 if (group.getPdps().contains(pdp)) {
839 public void setDefaultGroup(OnapPDPGroup group) throws PAPException {
840 boolean changesMade = false;
841 for (OnapPDPGroup theGroup : groups) {
842 if (theGroup.getId().equals(group.getId())) {
843 if (!theGroup.isDefaultGroup()) {
844 if (theGroup instanceof StdPDPGroup) {
845 ((StdPDPGroup) theGroup).setDefault(true);
848 throw new IllegalArgumentException(
849 "Group in groups of unknown type '" + theGroup.getClass().getName() + "'");
853 // not the new default group
854 if (theGroup.isDefaultGroup()) {
855 if (theGroup instanceof StdPDPGroup) {
856 ((StdPDPGroup) theGroup).setDefault(false);
859 throw new IllegalArgumentException(
860 "Group in groups of unknown type '" + theGroup.getClass().getName() + "'");
871 public void newPDP(String id, OnapPDPGroup group, String name, String description, int jmxport)
872 throws PAPException {
874 throw new PAPException("You must specify which group the PDP will belong to.");
876 if (!this.groups.contains(group)) {
877 throw new PAPException("Unknown group, not in our list.");
879 for (OnapPDP p : group.getOnapPdps()) {
880 if (p.getId().equals(id)) {
881 throw new PAPException("A PDP with this ID exists.");
884 if (group instanceof StdPDPGroup) {
885 StdPDP pdp = new StdPDP(id, name, description, jmxport);
886 if (((StdPDPGroup) group).addPDP(pdp)) {
888 // Save the properties and notify any listeners
896 public void updateGroup(OnapPDPGroup group, String userName) throws PAPException {
897 // To pass the userId for PDP Audit log maintenance.
902 public void updateGroup(OnapPDPGroup group) throws PAPException {
903 if (group == null || group.getId() == null) {
904 throw new PAPException("Group or id is null");
906 if (group.getName() == null || group.getName().trim().length() == 0) {
907 throw new PAPException("New name for group cannot be null or blank");
909 StdPDPGroup existingGroup = (StdPDPGroup) getGroup(group.getId());
910 if (existingGroup == null) {
911 throw new PAPException("Update found no existing group with id '" + group.getId() + "'");
914 // We do dramatically different things when the Name changes
915 // because the Name is essentially the identity of the group (as the User knows it) so when the Identity changes
916 // we have to change the group ID.
917 if (group.getName().equals(existingGroup.getName())) {
921 ((StdPDPGroup) group).saveGroupConfiguration();
922 } catch (IOException e) {
923 throw new PAPException(
924 "Unable to save new configuration for '" + group.getName() + "': " + e.getMessage(), e);
926 // update the group in the set by simply replacing the old instance with the new one
927 this.groups.remove(existingGroup);
928 this.groups.add((StdPDPGroup) group);
931 // the name/identity of the group has changed
932 // generate the new id
933 String newId = createNewPdpGroupId(group.getName());
935 // make sure no other group uses the new id
936 for (OnapPDPGroup g : groups) {
937 if (g.getId().equals(newId)) {
938 throw new PAPException("Replacement name maps to ID '" + newId + "' which is already in use");
941 ((StdPDPGroup) group).setId(newId);
943 // rename the existing directory to the new id
944 Path oldPath = existingGroup.getDirectory();
945 Path newPath = Paths.get(oldPath.getParent().toString(), newId);
946 ((StdPDPGroup) group).setDirectory(newPath);
949 boolean success = oldPath.toFile().renameTo(newPath.toFile());
951 throw new PAPException("Unable to rename directory; reason unknown");
953 } catch (Exception e) {
954 PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, e, STR_CLASS, "Unable to rename directory");
955 throw new PAPException(
956 "Unable to move directory from '" + oldPath + "' to '" + newPath + "': " + e.getMessage(), e);
960 ((StdPDPGroup) group).saveGroupConfiguration();
961 } catch (IOException e) {
962 throw new PAPException(
963 "Unable to save new configuration for '" + group.getName() + "': " + e.getMessage(), e);
966 // save the new group into the Set
967 groups.remove(existingGroup);
968 groups.add((StdPDPGroup) group);
972 // perhaps only the group changed, but if the name/id changed it may look to a listener like more than one group
978 public void removeGroup(OnapPDPGroup group, OnapPDPGroup newGroup) throws PAPException {
980 throw new NullPointerException();
983 // Does this group exist?
985 if (!this.groups.contains(group)) {
986 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE + "This group doesn't exist.");
987 throw new PAPException("The group '" + group.getId() + "' does not exist");
990 // Is it the default group?
992 if (group.isDefaultGroup()) {
993 throw new PAPException("You cannot delete the default group.");
995 Set<OnapPDP> pdps = group.getOnapPdps();
997 // Are there PDPs? If so, then we need a target group
999 if (!pdps.isEmpty() && newGroup == null) {
1000 throw new NullPointerException(
1001 "Group targeted for deletion has PDPs, you must provide a new group for them.");
1006 if (!pdps.isEmpty()) {
1007 if (!(newGroup instanceof StdPDPGroup)) {
1008 throw new PAPException("Unexpected class for newGroup: " + newGroup.getClass().getCanonicalName());
1010 // The movePDP function will modify the set of PDPs in the group.
1011 // To avoid concurrent modification exceptions we need to duplicate the list before calling that function.
1012 List<OnapPDP> pdpList = new ArrayList<>();
1013 for (OnapPDP pdp : pdps) {
1016 // now we can use the PDPs from the list without having ConcurrentAccessExceptions
1017 for (OnapPDP pdp : pdpList) {
1018 this.movePDP(pdp, newGroup);
1022 // remove the directory for the group
1024 String id = group.getId();
1025 Path groupPath = Paths.get(this.repository.toString(), id);
1027 // If it exists already
1029 if (! groupPath.toFile().exists()) {
1030 logger.warn("removeGroup " + id + " directory does not exist" + groupPath.toString());
1033 Files.walkFileTree(groupPath, new SimpleFileVisitor<Path>() {
1036 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
1038 return super.visitFile(file, attrs);
1043 // delete the directory
1045 Files.delete(groupPath);
1046 } catch (IOException e) {
1047 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, STR_CLASS, "Failed to delete " + groupPath);
1048 throw new PAPException("Failed to delete " + id);
1052 // remove the group from the set of all groups
1053 groups.remove(group);