2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017-2018 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=========================================================
20 package org.onap.policy.xacml.std.pap;
22 import java.io.FileInputStream;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.io.OutputStream;
26 import java.nio.file.FileVisitResult;
27 import java.nio.file.Files;
28 import java.nio.file.Path;
29 import java.nio.file.Paths;
30 import java.nio.file.SimpleFileVisitor;
31 import java.nio.file.attribute.BasicFileAttributes;
32 import java.util.ArrayList;
33 import java.util.Collections;
34 import java.util.Enumeration;
35 import java.util.HashSet;
36 import java.util.List;
37 import java.util.Properties;
39 import java.util.TreeSet;
41 import org.apache.commons.logging.Log;
42 import org.apache.commons.logging.LogFactory;
43 import org.onap.policy.common.logging.eelf.MessageCodes;
44 import org.onap.policy.common.logging.eelf.PolicyLogger;
45 import org.onap.policy.xacml.api.XACMLErrorConstants;
46 import org.onap.policy.xacml.api.pap.OnapPDP;
47 import org.onap.policy.xacml.api.pap.OnapPDPGroup;
48 import org.onap.policy.xacml.api.pap.PAPPolicyEngine;
50 import com.att.research.xacml.api.pap.PAPException;
51 import com.att.research.xacml.api.pap.PDP;
52 import com.att.research.xacml.api.pap.PDPGroup;
53 import com.att.research.xacml.api.pap.PDPPIPConfig;
54 import com.att.research.xacml.api.pap.PDPPolicy;
55 import com.att.research.xacml.api.pap.PDPStatus;
56 import com.att.research.xacml.util.XACMLProperties;
57 import com.google.common.base.Joiner;
58 import com.google.common.base.Splitter;
59 import com.google.common.collect.Sets;
62 * This is a simple PAP engine that uses some property files and a simple directory
63 * structure in the file system to manage a policy repository and set of PDP nodes.
67 public class StdEngine extends StdPDPItemSetChangeNotifier implements PAPPolicyEngine {
68 public static final String pipPropertyFile = "pip.properties";
70 private static final String addGroup = "addGroup ";
72 private static Log logger = LogFactory.getLog(StdEngine.class);
74 public static final String PROP_PAP_REPO = "xacml.pap.pdps";
75 public static final String PROP_PAP_GROUPS = "xacml.pap.groups";
76 public static final String PROP_PAP_GROUPS_DEFAULT = "xacml.pap.groups.default";
77 public static final String PROP_PAP_GROUPS_DEFAULT_NAME = "default";
78 //this value will be accessed from XacmlPapServlet so that we know if a default group did not exist
79 //and was just added. This way, we can add the new group to the database.
80 public boolean wasDefaultGroupJustAdded = false;
82 protected final Path repository;
83 protected Set<StdPDPGroup> groups;
85 public StdEngine() throws PAPException, IOException {
87 // Get the location in the file system of our repository
89 this.repository = Paths.get(XACMLProperties.getProperty(PROP_PAP_REPO));
96 public StdEngine(Properties properties) throws PAPException, IOException {
98 // Get the location in the file system of our repository
100 this.repository = Paths.get(properties.getProperty(PROP_PAP_REPO));
107 public StdEngine(Path repository) throws PAPException, IOException {
111 this.repository = repository;
118 private void intialize() throws PAPException, IOException {
120 // Sanity check the repository path
122 if (this.repository == null) {
123 throw new PAPException ("No repository specified.");
125 if (Files.notExists(this.repository)) {
126 Files.createDirectory(repository);
128 if (!Files.isDirectory(this.repository)) {
129 throw new PAPException ("Repository is NOT a directory: " + this.repository.toAbsolutePath());
131 if (!Files.isWritable(this.repository)) {
132 throw new PAPException ("Repository is NOT writable: " + this.repository.toAbsolutePath());
140 private void loadGroups() throws PAPException {
142 // Create a properties object
144 Properties properties = new Properties();
145 Path file = Paths.get(this.repository.toString(), XACMLProperties.XACML_PROPERTIES_NAME);
148 // Load the properties
150 try (InputStream is = new FileInputStream(file.toFile())) {
157 this.groups = this.readProperties(this.repository, properties);
158 } catch (IOException e) {
159 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "StdEngine", "Failed to load properties file");
160 this.groups = new HashSet<>();
163 // Initialize the default group
165 PDPGroup defaultGroup = this.initializeDefaultGroup(file, properties);
166 logger.info("Default group is: " + defaultGroup.getId() + "=" + defaultGroup.getName());
169 private PDPGroup initializeDefaultGroup(Path file, Properties properties) throws PAPException {
170 wasDefaultGroupJustAdded = false;
172 // Make sure we have the default group
174 PDPGroup group = this.getDefaultGroup();
176 wasDefaultGroupJustAdded = true;
180 // We don't have the default group, create it
182 String defaultId = properties.getProperty(PROP_PAP_GROUPS_DEFAULT, PROP_PAP_GROUPS_DEFAULT_NAME);
183 if(defaultId == null){
184 defaultId = PROP_PAP_GROUPS_DEFAULT_NAME;
186 if("".equals(defaultId)){
187 defaultId = PROP_PAP_GROUPS_DEFAULT_NAME;
189 //we're going to check one more time in case the PROP_PAP_GROUPS_DEFAULT_NAME doesn't exist
190 if(defaultId == null){
191 defaultId = "default";
193 if("".equals(defaultId)){
194 defaultId = "default";
196 logger.warn("Default group does NOT exist, creating " + defaultId);
197 Path defaultPath = Paths.get(this.repository.toString(), defaultId);
202 if (Files.notExists(defaultPath)) {
204 // Create its directory
206 Files.createDirectory(defaultPath);
208 // Create property files
211 Properties props = new Properties();
212 props.setProperty(XACMLProperties.PROP_REFERENCEDPOLICIES, "");
213 props.setProperty(XACMLProperties.PROP_ROOTPOLICIES, "");
214 Path policyPath = Paths.get(defaultPath.toAbsolutePath().toString(), "xacml.policy.properties");
215 Files.createFile(policyPath);
216 try (OutputStream os = Files.newOutputStream(policyPath)) {
218 } catch (IOException e) {
219 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "StdEngine", "Failed to write default policy properties");
223 Properties props = new Properties();
224 props = setPIPProperties(props);
225 Path pipPath = Paths.get(defaultPath.toAbsolutePath().toString(), "xacml.pip.properties");
226 Files.createFile(pipPath);
227 try (OutputStream os = Files.newOutputStream(pipPath)) {
229 } catch (IOException e) {
230 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "StdEngine", "Failed to write default pip properties");
235 // Create the default group
237 StdPDPGroup newDefault = new StdPDPGroup(defaultId, true, "default", "The default group where new PDP's are put.", defaultPath);
239 // Add it to our list
241 this.groups.add(newDefault);
243 // Save our properties out since we have
244 // a new default group.
246 StdEngine.setGroupProperties(newDefault, properties);
251 try (OutputStream os = Files.newOutputStream(file)) {
252 properties.store(os, "");
254 } catch (IOException e) {
255 PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, "StdEngine", "Failed to save properties with new default group information.");
260 wasDefaultGroupJustAdded = true;
262 } catch (IOException e) {
263 PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, "StdEngine", "Failed to create default group");
264 throw new PAPException("Failed to create default group");
269 public OnapPDPGroup getDefaultGroup() throws PAPException{
270 for (OnapPDPGroup group : this.groups) {
271 if (group.isDefaultGroup()) {
276 // Default group doesn't exist
282 public OnapPDPGroup getGroup(String id) throws PAPException {
283 for (OnapPDPGroup g: this.groups) {
284 if (g.getId().equals(id)) {
292 public void newGroup(String name, String description) throws PAPException, NullPointerException{
297 throw new NullPointerException();
300 // Do we already have this group?
302 for (PDPGroup group : this.groups) {
303 if (group.getName().equals(name)) {
304 throw new PAPException("Group with this name=" + name + " already exists.");
309 // create an Id that can be used as a file name and a properties file key.
310 // Ids must not contain \/:*?"<>|=,;
311 // The ID must also be unique within the current set of PDPGroups.
312 String id = createNewPDPGroupId(name);
316 // Construct the directory path
318 Path groupPath = Paths.get(this.repository.toString(), id);
320 // If it exists already
322 if (Files.exists(groupPath)) {
323 logger.warn(addGroup + id + " directory exists" + groupPath.toString());
327 // Create the directory
329 Files.createDirectory(groupPath);
330 } catch (IOException e) {
331 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "StdEngine", "Failed to create " + groupPath);
332 throw new PAPException("Failed to create " + id);
336 // Create the Policies
339 Path policyProperties = Paths.get(groupPath.toString(), "xacml.policy.properties");
340 if (Files.exists(policyProperties)) {
341 logger.warn(addGroup + id + " file exists: " + policyProperties.toString());
343 Properties props = new Properties();
344 props.setProperty(XACMLProperties.PROP_REFERENCEDPOLICIES, "");
345 props.setProperty(XACMLProperties.PROP_ROOTPOLICIES, "");
347 Files.createFile(policyProperties);
348 try (OutputStream os = Files.newOutputStream(policyProperties)) {
351 } catch (IOException e) {
352 PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, "StdEngine", "Failed to create " + policyProperties);
353 throw new PAPException("Failed to create " + id);
357 // Create the PIP config
359 Path pipProperties = Paths.get(groupPath.toString(), "xacml.pip.properties");
360 Properties props = new Properties();
361 if (Files.exists(pipProperties)) {
362 logger.warn(addGroup + id + " file exists: " + pipProperties.toString());
365 props = setPIPProperties(props);
366 Files.createFile(pipProperties);
367 try (OutputStream os = Files.newOutputStream(pipProperties)) {
370 } catch (IOException e) {
371 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "StdEngine", "Failed to create " + pipProperties);
372 throw new PAPException("Failed to create " + id);
379 StdPDPGroup newGroup = new StdPDPGroup(id, name, description, groupPath);
380 // Add the default PIP configuration.
381 String list = props.getProperty(XACMLProperties.PROP_PIP_ENGINES);
382 if (list != null && list.length() > 0) {
383 Set<PDPPIPConfig> pipConfigs = new HashSet<>();
384 for (String pipID : list.split("[,]")) {
385 StdPDPPIPConfig config = new StdPDPPIPConfig(pipID, props);
386 if (config.isConfigured()) {
387 pipConfigs.add(config);
390 newGroup.setPipConfigs(pipConfigs);
392 if (this.groups.add(newGroup)) {
393 // save the new group in our properties and notify any listeners of the change
394 groupChanged(newGroup);
403 * Helper to create a new Group ID.
404 * Use the Name field to create the Id.
405 * The Name is expected to not be null; if it is then this method throws an exception.
406 * The name is supposed to be unique within the current set of groups,
407 * so creating the ID based on the name will create a unique string.
412 private String createNewPDPGroupId(String name) {
414 // replace "bad" characters with sequences that will be ok for file names and properties keys.
415 id = id.replace(" ", "_sp_");
416 id = id.replace("\t", "_tab_");
417 id = id.replace("\\", "_bksl_");
418 id = id.replace("/", "_sl_");
419 id = id.replace(":", "_col_");
420 id = id.replace("*", "_ast_");
421 id = id.replace("?", "_q_");
422 id = id.replace("\"", "_quo_");
423 id = id.replace("<", "_lt_");
424 id = id.replace(">", "_gt_");
425 id = id.replace("|", "_bar_");
426 id = id.replace("=", "_eq_");
427 id = id.replace(",", "_com_");
428 id = id.replace(";", "_scom_");
435 public OnapPDP getPDP(String pdpId) throws PAPException {
436 for (OnapPDPGroup group : this.groups) {
437 for (OnapPDP pdp : group.getOnapPdps()) {
438 if (pdp.getId().equals(pdpId)) {
448 public void movePDP(OnapPDP pdp, OnapPDPGroup newGroup) throws PAPException {
449 if (newGroup == null) {
450 throw new NullPointerException("You must specify which group the PDP will belong to.");
452 PDPGroup currentGroup = this.getPDPGroup(pdp);
453 if (currentGroup == null) {
454 throw new PAPException("PDP must already belong to a group.");
456 if (currentGroup.equals(newGroup)) {
457 logger.warn("Already in that group.");
460 if (currentGroup instanceof StdPDPGroup && newGroup instanceof StdPDPGroup) {
461 if (((StdPDPGroup) currentGroup).removePDP(pdp)) {
462 boolean result = ((StdPDPGroup) newGroup).addPDP(pdp);
465 // Save the configuration
469 PolicyLogger.error("Failed to add to new group, putting back into original group.");
470 if (!((StdPDPGroup) currentGroup).removePDP(pdp)) {
471 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE + "Failed to put PDP back into original group.");
476 String message = "Unknown PDP group class: " + newGroup.getClass().getCanonicalName() + " and " + currentGroup.getClass().getCanonicalName();
477 logger.warn(message);
478 throw new PAPException(message);
484 public void updatePDP(OnapPDP pdp) throws PAPException {
485 PDP currentPDP = this.getPDP(pdp.getId());
486 if (currentPDP == null) {
487 String message = "Unknown PDP id '" + pdp.getId() + "'";
488 logger.warn(message);
489 throw new PAPException(message);
492 // the only things that the user can change are name and description
493 currentPDP.setDescription(pdp.getDescription());
494 currentPDP.setName(pdp.getName());
495 if (currentPDP instanceof OnapPDP) {
496 ((OnapPDP)currentPDP).setJmxPort(pdp.getJmxPort());
502 public void removePDP(OnapPDP pdp) throws PAPException {
503 PDPGroup group = this.getPDPGroup(pdp);
505 throw new NullPointerException();
507 if (group instanceof StdPDPGroup) {
508 boolean result = ((StdPDPGroup) group).removePDP(pdp);
514 String message = "Unknown PDP group class: " + group.getClass().getCanonicalName();
515 logger.warn(message);
516 throw new PAPException(message);
522 * Should never be called - Detailed status is held on the PDP, not the PAP
524 public PDPStatus getStatus(OnapPDP pdp) throws PAPException {
525 return getPDP(pdp.getId()).getStatus();
529 public void publishPolicy(String id, String name, boolean isRoot, InputStream policy, OnapPDPGroup group) throws PAPException {
531 throw new NullPointerException();
533 if (group instanceof StdPDPGroup && this.groups.contains(group)) {
534 ((StdPDPGroup) group).publishPolicy(id, name, isRoot, policy);
537 logger.warn("unknown PDP Group: " + group);
538 throw new PAPException("Unknown PDP Group: " + group.getId());
543 public void copyPolicy(PDPPolicy policy, OnapPDPGroup group)
544 throws PAPException {
546 // Currently not used on the PAP side. This is done by ((StdPDPGroup) group).copyPolicyToFile
552 public void removePolicy(PDPPolicy policy, OnapPDPGroup group) throws PAPException {
554 throw new NullPointerException();
556 if (group instanceof StdPDPGroup && this.groups.contains(group)) {
557 ((StdPDPGroup) group).removePolicy(policy);
560 logger.warn("unknown PDP Group: " + group);
561 throw new PAPException("Unknown PDP Group: " + group.getId());
569 private Set<StdPDPGroup> readProperties(Path repository, Properties properties) throws PAPException {
570 Set<StdPDPGroup> pdpGroups = new HashSet<>();
572 // See if there is a groups property
574 String groupList = properties.getProperty(PROP_PAP_GROUPS, "");
575 if (groupList == null) {
576 logger.warn("null group list " + PROP_PAP_GROUPS);
579 if (logger.isDebugEnabled()) {
580 logger.debug("group list: " + groupList);
583 // Iterate the groups, converting to a set ensures we have unique groups.
585 for (String id : Splitter.on(',').trimResults().omitEmptyStrings().split(groupList)) {
587 // Add our Group Object
589 StdPDPGroup g = new StdPDPGroup(id.trim(),
590 id.equals(properties.getProperty(PROP_PAP_GROUPS_DEFAULT, PROP_PAP_GROUPS_DEFAULT_NAME)),
592 Paths.get(repository.toString(), id));
602 if (logger.isDebugEnabled()) {
603 logger.debug("PDP Group List: " + pdpGroups.toString());
608 private void saveConfiguration() throws PAPException, IOException {
610 // Create our properties object
612 Properties properties = new Properties() {
613 private static final long serialVersionUID = 1L;
614 // For Debugging it is helpful for the file to be in a sorted order,
615 // any by returning the keys in the natural Alpha order for strings we get close enough.
616 // TreeSet is sorted, and this just overrides the normal Properties method to get the keys.
618 public synchronized Enumeration<Object> keys() {
619 return Collections.enumeration(new TreeSet<Object>(super.keySet()));
623 // Iterate our groups
625 List<String> ids = new ArrayList<>();
626 for (PDPGroup group : this.groups) {
627 ids.add(group.getId());
628 properties.setProperty(group.getId() + ".name", group.getName() == null ? "" : group.getName());
629 properties.setProperty(group.getId() + ".description", group.getDescription() == null ? "" : group.getDescription());
633 List<String> pdps = new ArrayList<>();
634 for (PDP pdp : group.getPdps()) {
635 pdps.add(pdp.getId());
636 properties.setProperty(pdp.getId() + ".name", pdp.getName() == null ? "" : pdp.getName());
637 properties.setProperty(pdp.getId() + ".description", pdp.getDescription() == null ? "" : pdp.getDescription());
638 if (pdp instanceof OnapPDP) {
639 properties.setProperty(pdp.getId() + ".jmxport", (((OnapPDP)pdp).getJmxPort()==0 ? "" : ((OnapPDP)pdp).getJmxPort()).toString());
643 if (pdps.size() == 1) {
644 pdpList = pdps.get(0);
645 } else if (pdps.size() > 1) {
646 pdpList = Joiner.on(',').skipNulls().join(pdps);
648 if (logger.isDebugEnabled()) {
649 logger.debug("Group " + group.getId() + " PDPS: " + pdpList);
651 properties.setProperty(group.getId() + ".pdps", pdpList);
654 throw new PAPException("Inconsistency - we have NO groups. We should have at least one.");
656 String groupList = "";
657 if (ids.size() == 1) {
658 groupList = ids.get(0);
659 } else if (ids.size() > 1){
660 groupList = Joiner.on(',').skipNulls().join(ids);
662 logger.info("New Group List: " + groupList);
664 properties.setProperty(PROP_PAP_GROUPS, groupList);
666 // Get the default group
668 PDPGroup defaultGroup = this.getDefaultGroup();
669 if (defaultGroup == null) {
670 throw new PAPException("Invalid state - no default group.");
672 properties.setProperty(PROP_PAP_GROUPS_DEFAULT, defaultGroup.getId());
674 // Now we can save the file
676 Path file = Paths.get(this.repository.toString(), "xacml.properties");
677 try (OutputStream os = Files.newOutputStream(file)) {
678 properties.store(os, "");
682 public static void removeGroupProperties(String id, Properties properties) {
683 for (Object key : properties.keySet()) {
684 if (key.toString().startsWith(id + ".")) {
685 properties.remove(key);
690 public static void setGroupProperties(PDPGroup group, Properties properties) {
692 // make sure its in the list of groups
694 Iterable<String> groups = Splitter.on(',').trimResults().omitEmptyStrings().split( properties.getProperty(PROP_PAP_GROUPS, ""));
695 boolean inList = false;
696 for (String g : groups) {
697 if (g.equals(group.getId())) {
702 Set<String> grps = Sets.newHashSet(groups);
703 grps.add(group.getId());
705 if (grps.size() == 1) {
706 newGroupList = grps.iterator().next();
707 } else if (grps.size() > 1) {
708 newGroupList = Joiner.on(',').skipNulls().join(grps);
712 logger.info("New Group List: " + newGroupList);
713 properties.setProperty(PROP_PAP_GROUPS, newGroupList);
716 // Set its properties
718 properties.setProperty(group.getId() + ".name", group.getName());
719 properties.setProperty(group.getId() + ".description", group.getDescription());
723 if (!group.getPdps().isEmpty()) {
725 if (group.getPdps().size() == 1) {
726 pdpList = group.getPdps().iterator().next().getId();
727 } else if (group.getPdps().size() > 1) {
728 Set<String> ids = new HashSet<>();
729 for (PDP pdp : group.getPdps()) {
730 ids.add(pdp.getId());
732 pdpList = Joiner.on(',').skipNulls().join(ids);
734 properties.setProperty(group.getId() + ".pdps", pdpList);
736 properties.setProperty(group.getId() + ".pdps", "");
741 public void changed() {
742 if (logger.isDebugEnabled()) {
743 logger.debug("changed");
749 public void groupChanged(OnapPDPGroup group) {
750 if (logger.isDebugEnabled()) {
751 logger.debug("groupChanged: " + group);
754 this.firePDPGroupChanged(group);
758 public void pdpChanged(OnapPDP pdp) {
759 if (logger.isDebugEnabled()) {
760 logger.debug("pdpChanged: " + pdp);
763 this.firePDPChanged(pdp);
766 private void doSave() {
769 // Save the configuration
771 this.saveConfiguration();
772 } catch (IOException|PAPException e) {
773 PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, e, "StdEngine", "Failed to save configuration");
777 private Properties setPIPProperties(Properties props){
778 props.setProperty(XACMLProperties.PROP_PIP_ENGINES, "AAF");
779 props.setProperty("AAF.name", "AAFEngine");
780 props.setProperty("AAF.description", "AAFEngine to communicate with AAF to take decisions");
781 props.setProperty("AAF.classname","org.onap.policy.xacml.std.pip.engines.aaf.AAFEngine");
782 // read from PIP properties file.
783 Path file = Paths.get(pipPropertyFile);
784 if (!Files.notExists(file)) {
786 Properties prop = new Properties();
788 in = new FileInputStream(file.toFile());
790 } catch (IOException e) {
791 PolicyLogger.error(XACMLErrorConstants.ERROR_SYSTEM_ERROR + "can not load the pip properties from file" +e);
800 public Set<OnapPDPGroup> getOnapPDPGroups() throws PAPException {
801 final Set<OnapPDPGroup> grps = new HashSet<>();
802 for (OnapPDPGroup g : this.groups) {
805 return Collections.unmodifiableSet(grps);
809 public OnapPDPGroup getPDPGroup(OnapPDP pdp) throws PAPException {
810 for (OnapPDPGroup group : this.groups) {
811 if (group.getPdps().contains(pdp)) {
819 public void setDefaultGroup(OnapPDPGroup group) throws PAPException {
820 boolean changesMade = false;
821 for (OnapPDPGroup aGroup : groups) {
822 if (aGroup.getId().equals(group.getId())) {
823 if ( ! aGroup.isDefaultGroup()) {
824 if (aGroup instanceof StdPDPGroup) {
825 ((StdPDPGroup) aGroup).setDefault(true);
828 throw new IllegalArgumentException("Group in groups of unknown type '" + aGroup.getClass().getName() + "'");
832 // not the new default group
833 if (aGroup.isDefaultGroup()) {
834 if (aGroup instanceof StdPDPGroup) {
835 ((StdPDPGroup) aGroup).setDefault(false);
838 throw new IllegalArgumentException("Group in groups of unknown type '" + aGroup.getClass().getName() + "'");
852 public void newPDP(String id, OnapPDPGroup group, String name, String description, int jmxport)
853 throws PAPException, NullPointerException {
855 throw new PAPException("You must specify which group the PDP will belong to.");
857 if (!this.groups.contains(group)) {
858 throw new PAPException("Unknown group, not in our list.");
860 for (OnapPDP p : group.getOnapPdps()) {
861 if (p.getId().equals(id)) {
862 throw new PAPException("A PDP with this ID exists.");
865 if (group instanceof StdPDPGroup) {
866 StdPDP pdp = new StdPDP(id, name, description, jmxport);
867 if (((StdPDPGroup) group).addPDP(pdp)) {
869 // Save the properties and notify any listeners
880 public void updateGroup(OnapPDPGroup group) throws PAPException {
881 if (group == null || group.getId() == null) {
882 throw new PAPException("Group or id is null");
884 if (group.getName() == null || group.getName().trim().length() == 0) {
885 throw new PAPException("New name for group cannot be null or blank");
887 StdPDPGroup existingGroup = (StdPDPGroup)getGroup(group.getId());
888 if (existingGroup == null) {
889 throw new PAPException("Update found no existing group with id '" + group.getId() + "'");
893 // We do dramatically different things when the Name changes
894 // 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.
895 if (group.getName().equals(existingGroup.getName())) {
899 ((StdPDPGroup)group).saveGroupConfiguration();
900 } catch (IOException e) {
901 throw new PAPException("Unable to save new configuration for '" + group.getName() + "': " + e.getMessage(), e);
903 // update the group in the set by simply replacing the old instance with the new one
904 this.groups.remove(existingGroup);
905 this.groups.add((StdPDPGroup)group);
908 // the name/identity of the group has changed
909 // generate the new id
910 String newId = createNewPDPGroupId(group.getName());
912 // make sure no other group uses the new id
913 for (OnapPDPGroup g : groups) {
914 if (g.getId().equals(newId)) {
915 throw new PAPException("Replacement name maps to ID '" + newId + "' which is already in use");
918 ((StdPDPGroup)group).setId(newId);
920 // rename the existing directory to the new id
921 Path oldPath = existingGroup.getDirectory();
922 Path newPath = Paths.get(oldPath.getParent().toString(), newId);
923 ((StdPDPGroup)group).setDirectory(newPath);
926 boolean success = oldPath.toFile().renameTo(newPath.toFile());
928 throw new PAPException("Unable to rename directory; reason unknown");
930 } catch (Exception e) {
931 PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, e, "StdEngine", "Unable to rename directory");
932 throw new PAPException("Unable to move directory from '" + oldPath + "' to '" + newPath + "': " + e.getMessage(),e);
936 ((StdPDPGroup)group).saveGroupConfiguration();
937 } catch (IOException e) {
938 throw new PAPException("Unable to save new configuration for '" + group.getName() + "': " + e.getMessage(), e);
941 // save the new group into the Set
942 groups.remove(existingGroup);
943 groups.add((StdPDPGroup)group);
947 // perhaps only the group changed, but if the name/id changed it may look to a listener like more than one group
954 public void removeGroup(OnapPDPGroup group, OnapPDPGroup newGroup) throws PAPException, NullPointerException {
956 throw new NullPointerException();
959 // Does this group exist?
961 if (!this.groups.contains(group)) {
962 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE + "This group doesn't exist.");
963 throw new PAPException("The group '" + group.getId() + "' does not exist");
966 // Is it the default group?
968 if (group.isDefaultGroup()) {
969 throw new PAPException("You cannot delete the default group.");
971 Set<OnapPDP> pdps = group.getOnapPdps();
973 // Are there PDPs? If so, then we need a target group
975 if (!pdps.isEmpty() && newGroup == null) {
976 throw new NullPointerException("Group targeted for deletion has PDPs, you must provide a new group for them.");
981 if (!pdps.isEmpty()) {
982 if (! (newGroup instanceof StdPDPGroup)) {
983 throw new PAPException("Unexpected class for newGroup: " + newGroup.getClass().getCanonicalName());
985 // The movePDP function will modify the set of PDPs in the group.
986 // To avoid concurrent modification exceptions we need to duplicate the list before calling that function.
987 List<OnapPDP> pdpList = new ArrayList<>();
988 for (OnapPDP pdp : pdps) {
991 // now we can use the PDPs from the list without having ConcurrentAccessExceptions
992 for (OnapPDP pdp : pdpList) {
993 this.movePDP(pdp, newGroup);
997 // remove the directory for the group
999 String id = group.getId();
1000 Path groupPath = Paths.get(this.repository.toString(), id);
1002 // If it exists already
1004 if ( ! Files.exists(groupPath)) {
1005 logger.warn("removeGroup " + id + " directory does not exist" + groupPath.toString());
1008 Files.walkFileTree(groupPath, new SimpleFileVisitor<Path>() {
1011 public FileVisitResult visitFile(Path file,
1012 BasicFileAttributes attrs) throws IOException {
1014 return super.visitFile(file, attrs);
1019 // delete the directory
1021 Files.delete(groupPath);
1022 } catch (IOException e) {
1023 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "StdEngine", "Failed to delete " + groupPath);
1024 throw new PAPException("Failed to delete " + id);
1028 // remove the group from the set of all groups
1029 groups.remove(group);