Sonar cleanup and remove duplicate code
[policy/engine.git] / ONAP-XACML / src / main / java / org / onap / policy / xacml / std / pap / StdPDPGroup.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP-XACML
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
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
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=========================================================
19  */
20
21 package org.onap.policy.xacml.std.pap;
22
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.PDPGroupStatus;
26 import com.att.research.xacml.api.pap.PDPGroupStatus.Status;
27 import com.att.research.xacml.api.pap.PDPPIPConfig;
28 import com.att.research.xacml.api.pap.PDPPolicy;
29 import com.att.research.xacml.util.XACMLProperties;
30 import com.fasterxml.jackson.annotation.JsonIgnore;
31 import com.google.common.base.Joiner;
32 import com.google.common.base.Splitter;
33 import com.google.common.io.ByteStreams;
34
35 import java.io.FileInputStream;
36 import java.io.IOException;
37 import java.io.InputStream;
38 import java.io.OutputStream;
39 import java.io.Serializable;
40 import java.nio.file.Files;
41 import java.nio.file.Path;
42 import java.nio.file.Paths;
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;
49 import java.util.Set;
50 import java.util.TreeSet;
51 import lombok.EqualsAndHashCode;
52 import lombok.ToString;
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.std.pap.StdPDPItemSetChangeNotifier.StdItemSetChangeListener;
61
62 @EqualsAndHashCode(callSuper = false)
63 @ToString
64 public class StdPDPGroup extends StdPDPItemSetChangeNotifier
65         implements OnapPDPGroup, StdItemSetChangeListener, Comparable<Object>, Serializable {
66
67     private static final long serialVersionUID = 1L;
68     private static final String MSG_GROUPNOTEXIST = "Group directory does NOT exist";
69     private static final String MSG_LOADFAILURE = "Failed to load group policy properties file: ";
70     private static final String STR_APPEND_NAME = ".name";
71     private static final String STR_APPEND_DESCRIPTION = ".description";
72     private static final String STR_APPEND_PDPS = ".pdps";
73     private static final String STR_CLASS = "StdPDPGroup";
74     private static final String PROPS_POLICY = "xacml.policy.properties";
75     private static final String PROPS_PIP = "xacml.pip.properties";
76
77     private static Log logger = LogFactory.getLog(StdPDPGroup.class);
78
79     private String id;
80
81     private boolean isDefault = false;
82
83     private String name;
84
85     private String description;
86
87     private transient StdPDPGroupStatus status = new StdPDPGroupStatus(Status.UNKNOWN);
88
89     private transient Set<OnapPDP> pdps = new HashSet<>();
90
91     private transient Set<PDPPolicy> policies = new HashSet<>();
92
93     private transient Set<PDPPolicy> selectedPolicies = new HashSet<>();
94
95     private transient Set<PDPPIPConfig> pipConfigs = new HashSet<>();
96
97     private String operation;
98
99     @JsonIgnore
100     private transient Path directory;
101
102     @JsonIgnore
103     private Integer jmxport;
104
105     public StdPDPGroup() {
106         //
107         // Methods needed for JSON deserialization
108         //
109     }
110
111     /**
112      * StdPDPGroup constructor.
113      *
114      * @param group OnapPDPGroup
115      */
116     public StdPDPGroup(OnapPDPGroup group) {
117         this.id = group.getId();
118         this.name = group.getName();
119         this.description = group.getDescription();
120         this.isDefault = group.isDefaultGroup();
121         this.pdps = group.getOnapPdps();
122         this.policies = group.getPolicies();
123         this.pipConfigs = group.getPipConfigs();
124     }
125
126     public StdPDPGroup(String id, Path directory) {
127         this.id = id;
128         this.directory = directory;
129     }
130
131     public StdPDPGroup(String id, boolean isDefault, Path directory) {
132         this(id, directory);
133         this.isDefault = isDefault;
134     }
135
136     /**
137      * StdPDPGroup.
138      *
139      * @param id String
140      * @param isDefault boolean
141      * @param name String
142      * @param description String
143      * @param directory Path
144      */
145     public StdPDPGroup(String id, boolean isDefault, String name, String description, Path directory) {
146         this(id, isDefault, directory);
147         this.name = name;
148         // force all policies to have a name
149         if (name == null) {
150             this.name = id;
151         }
152         this.description = description;
153     }
154
155     public StdPDPGroup(String id, String name, String description, Path directory) {
156         this(id, false, name, description, directory);
157         this.resetStatus();
158     }
159
160     /**
161      * StdPDPGroup.
162      *
163      * @param id String
164      * @param isDefault boolean
165      * @param properties Properties
166      * @param directory Path
167      * @throws PAPException PAPException
168      */
169     public StdPDPGroup(String id, boolean isDefault, Properties properties, Path directory) throws PAPException {
170         this(id, isDefault, directory);
171         this.initialize(properties, directory);
172         this.resetStatus();
173     }
174
175     private void initialize(Properties properties, Path directory) throws PAPException {
176         if (this.id == null || this.id.length() == 0) {
177             logger.warn("Cannot initialize with a null or zero length id");
178             return;
179         }
180         //
181         // Pull the group's properties
182         //
183         for (Object key : properties.keySet()) {
184             if (key.toString().startsWith(this.id + ".")) {
185                 if (key.toString().endsWith(STR_APPEND_NAME)) {
186                     this.name = properties.getProperty(key.toString());
187                 } else if (key.toString().endsWith(STR_APPEND_DESCRIPTION)) {
188                     this.description = properties.getProperty(key.toString());
189                 } else if (key.toString().endsWith(STR_APPEND_PDPS)) {
190                     String pdpList = properties.getProperty(key.toString());
191                     if (pdpList != null && pdpList.length() > 0) {
192                         for (String pdpId : Splitter.on(',').omitEmptyStrings().trimResults().split(pdpList)) {
193                             StdPDP pdp = new StdPDP(pdpId, properties);
194                             pdp.addItemSetChangeListener(this);
195                             this.pdps.add(pdp);
196                         }
197                     }
198                 }
199             }
200             // force all policies to have a name
201             if (this.name == null) {
202                 this.name = this.id;
203             }
204         }
205         //
206         // Validate our directory
207         //
208         if (! directory.toFile().exists()) {
209             logger.warn("Group directory does NOT exist: " + directory.toString());
210             try {
211                 Files.createDirectory(directory);
212                 this.status.addLoadWarning(MSG_GROUPNOTEXIST);
213             } catch (IOException e) {
214                 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, STR_CLASS, MSG_GROUPNOTEXIST);
215                 this.status.addLoadError(MSG_GROUPNOTEXIST);
216                 this.status.setStatus(PDPGroupStatus.Status.LOAD_ERRORS);
217             }
218         }
219         //
220         // Parse policies
221         //
222         this.loadPolicies(Paths.get(directory.toString(), PROPS_POLICY));
223         //
224         // Parse pip config
225         //
226         this.loadPIPConfig(Paths.get(directory.toString(), PROPS_PIP));
227     }
228
229     /**
230      * loadPolicies.
231      *
232      * @param file Path
233      * @throws PAPException PAPException
234      */
235     public void loadPolicies(Path file) throws PAPException {
236         //
237         // Read the Groups Policies
238         //
239         Properties policyProperties = new Properties();
240         if (!file.toFile().exists()) {
241             // need to create the properties file with default values
242             policyProperties.setProperty(XACMLProperties.PROP_ROOTPOLICIES, "");
243             policyProperties.setProperty(XACMLProperties.PROP_REFERENCEDPOLICIES, "");
244             // save properties to file
245             try (OutputStream os = Files.newOutputStream(file)) {
246                 policyProperties.store(os, "");
247             } catch (Exception e) {
248                 throw new PAPException("Failed to create new default policy properties file '" + file + "'", e);
249             }
250         } else {
251             // load previously existing file
252             try {
253                 //
254                 // Load the properties
255                 //
256                 try (InputStream is = Files.newInputStream(file)) {
257                     policyProperties.load(is);
258                 }
259                 //
260                 // Parse the policies
261                 //
262                 this.readPolicyProperties(directory, policyProperties);
263             } catch (IOException e) {
264                 logger.warn(MSG_LOADFAILURE + file, e);
265                 this.status.addLoadError("Not policy properties defined");
266                 this.status.setStatus(Status.LOAD_ERRORS);
267                 throw new PAPException(MSG_LOADFAILURE + file);
268             }
269         }
270     }
271
272     /**
273      * loadPIPConfig.
274      *
275      * @param file Path
276      * @throws PAPException PAPException
277      */
278     public void loadPIPConfig(Path file) throws PAPException {
279         //
280         // Read the Groups' PIP configuration
281         //
282         Properties pipProperties = new Properties();
283         if (!file.toFile().exists()) {
284             // need to create the properties file with no values
285             pipProperties = setPipProperties(pipProperties);
286             // save properties to file
287             try {
288                 try (OutputStream os = Files.newOutputStream(file)) {
289                     pipProperties.store(os, "");
290                 }
291             } catch (Exception e) {
292                 throw new PAPException("Failed to create new default pip properties file '" + file + "'", e);
293             }
294             // Even if we create a new pip file, we still need to parse and load the properties
295             try {
296                 this.readPipProperties(pipProperties);
297             } catch (Exception e) {
298                 throw new PAPException("Failed to load the new pip properties file", e);
299             }
300         } else {
301             try {
302                 //
303                 // Load the properties
304                 //
305                 try (InputStream is = Files.newInputStream(file)) {
306                     pipProperties.load(is);
307                 }
308                 // For all old PIP config's modify to the new PIP Configuration.
309                 // If PIP is empty add the new values and save it.
310                 if ("".equals(pipProperties.get(XACMLProperties.PROP_PIP_ENGINES).toString().trim())) {
311                     pipProperties = setPipProperties(pipProperties);
312                     try (OutputStream os = Files.newOutputStream(file)) {
313                         pipProperties.store(os, "");
314                     }
315                 }
316                 //
317                 // Parse the pips
318                 //
319                 this.readPipProperties(pipProperties);
320             } catch (IOException e) {
321                 logger.warn("Failed to open group PIP Config properties file: " + file, e);
322                 this.status.addLoadError("Not PIP config properties defined");
323                 this.status.setStatus(Status.LOAD_ERRORS);
324                 throw new PAPException(MSG_LOADFAILURE + file);
325
326             }
327         }
328     }
329
330     /**
331      * resetStatus.
332      */
333     public void resetStatus() {
334         //
335         // Reset our status object
336         //
337         this.status.reset();
338         //
339         // Determine our status
340         //
341         for (PDP pdp : this.pdps) {
342             switch (pdp.getStatus().getStatus()) {
343                 case OUT_OF_SYNCH:
344                     this.status.addOutOfSynchPDP(pdp);
345                     break;
346                 case LAST_UPDATE_FAILED:
347                     this.status.addLastUpdateFailedPDP(pdp);
348                     break;
349                 case LOAD_ERRORS:
350                     this.status.addFailedPDP(pdp);
351                     break;
352                 case UPDATING_CONFIGURATION:
353                     this.status.addUpdatingPDP(pdp);
354                     break;
355                 case UP_TO_DATE:
356                     this.status.addInSynchPDP(pdp);
357                     break;
358                 case UNKNOWN:
359                 case CANNOT_CONNECT:
360                 case NO_SUCH_HOST:
361                 default:
362                     this.status.addUnknownPDP(pdp);
363                     break;
364             }
365         }
366
367         // priority is worst-cast to best case
368         if (!this.status.getUnknownPDPs().isEmpty()) {
369             this.status.setStatus(Status.UNKNOWN);
370         } else if (!this.status.getFailedPDPs().isEmpty() || !this.status.getLastUpdateFailedPDPs().isEmpty()) {
371             this.status.setStatus(Status.LOAD_ERRORS);
372         } else if (!this.status.getOutOfSynchPDPs().isEmpty()) {
373             this.status.setStatus(Status.OUT_OF_SYNCH);
374         } else if (!this.status.getUpdatingPDPs().isEmpty()) {
375             this.status.setStatus(Status.UPDATING_CONFIGURATION);
376         } else {
377             this.status.setStatus(Status.OK);
378         }
379     }
380
381     @Override
382     public String getId() {
383         return this.id;
384     }
385
386     public void setId(String id) {
387         this.id = id;
388     }
389
390     @Override
391     public boolean isDefaultGroup() {
392         return this.isDefault;
393     }
394
395     /**
396      * setDefaultGroup.
397      *
398      * @param isDefault boolean
399      */
400     public void setDefaultGroup(boolean isDefault) {
401         this.isDefault = isDefault;
402         //
403         // Cannot fire this because 2 operations have
404         // to occur: 1) old default=false (don't want to fire) and
405         // then 2) new default=true (yes fire - but we'll have to do that
406         // elsewhere.
407     }
408
409     @Override
410     public String getName() {
411         return name;
412     }
413
414     @Override
415     public void setName(String groupName) {
416         this.name = groupName;
417         this.firePDPGroupChanged(this);
418     }
419
420     @Override
421     public String getDescription() {
422         return this.description;
423     }
424
425     @Override
426     public void setDescription(String groupDescription) {
427         this.description = groupDescription;
428         this.firePDPGroupChanged(this);
429     }
430
431     public Path getDirectory() {
432         return this.directory;
433     }
434
435     public void setDirectory(Path groupDirectory) {
436         this.directory = groupDirectory;
437         // this is used only for transmission on the RESTful interface, so no need to fire group changed?
438     }
439
440     @Override
441     public PDPGroupStatus getStatus() {
442         return this.status;
443     }
444
445     @Override
446     public Set<PDPPolicy> getSelectedPolicies() {
447         return this.selectedPolicies;
448     }
449
450     @Override
451     public String getOperation() {
452         return this.operation;
453     }
454
455     @Override
456     public Set<PDP> getPdps() {
457         return Collections.unmodifiableSet(pdps);
458     }
459
460     public void setOnapPdps(Set<OnapPDP> pdps) {
461         this.pdps = pdps;
462     }
463
464     @Override
465     public Set<OnapPDP> getOnapPdps() {
466         return Collections.unmodifiableSet(pdps);
467     }
468
469     public boolean addPDP(OnapPDP pdp) {
470         return this.pdps.add(pdp);
471     }
472
473     public boolean removePDP(PDP pdp) {
474         return this.pdps.remove(pdp);
475     }
476
477     @Override
478     public Set<PDPPolicy> getPolicies() {
479         return Collections.unmodifiableSet(this.policies);
480     }
481
482     @Override
483     public PDPPolicy getPolicy(String id) {
484         for (PDPPolicy policy : this.policies) {
485             if (policy.getId().equals(id)) {
486                 return policy;
487             }
488         }
489         return null;
490     }
491
492     @Override
493     public Properties getPolicyProperties() {
494         Properties properties = new Properties() {
495             private static final long serialVersionUID = 1L;
496
497             // For Debugging it is helpful for the file to be in a sorted order,
498             // any by returning the keys in the natural Alpha order for strings we get close enough.
499             // TreeSet is sorted, and this just overrides the normal Properties method to get the keys.
500             @Override
501             public synchronized Enumeration<Object> keys() {
502                 return Collections.enumeration(new TreeSet<Object>(super.keySet()));
503             }
504         };
505         List<String> roots = new ArrayList<>();
506         List<String> refs = new ArrayList<>();
507
508         for (PDPPolicy policy : this.policies) {
509             // for all policies need to tell PDP the "name", which is the base name for the file id
510             if (policy.getName() != null) {
511                 properties.setProperty(policy.getId() + STR_APPEND_NAME, policy.getName());
512             }
513             // put the policy on the correct list
514             if (policy.isRoot()) {
515                 roots.add(policy.getId());
516             } else {
517                 refs.add(policy.getId());
518             }
519         }
520
521         properties.setProperty(XACMLProperties.PROP_ROOTPOLICIES, Joiner.on(',').join(roots));
522         properties.setProperty(XACMLProperties.PROP_REFERENCEDPOLICIES, Joiner.on(',').join(refs));
523
524         return properties;
525     }
526
527     /**
528      * publishPolicy.
529      *
530      * @param id String
531      * @param name String
532      * @param isRoot boolean
533      * @param policy InputStream
534      * @return PDPPolicy
535      * @throws PAPException PAPException
536      */
537     public PDPPolicy publishPolicy(String id, String name, boolean isRoot, InputStream policy) throws PAPException {
538         //
539         // Does it exist already?
540         //
541         if (this.getPolicy(id) != null) {
542             throw new PAPException("Policy with id " + id + " already exists - unpublish it first.");
543         }
544         Path tempFile = null;
545         try {
546             //
547             // Copy the policy over
548             //
549             tempFile = Files.createFile(Paths.get(this.directory.toAbsolutePath().toString(), id));
550             long num;
551             try (OutputStream os = Files.newOutputStream(tempFile)) {
552                 num = ByteStreams.copy(policy, os);
553             }
554             logger.info("Copied " + num + " bytes for policy " + name);
555
556             StdPDPPolicy tempRootPolicy = new StdPDPPolicy(id, isRoot, name, tempFile.toUri());
557             if (!tempRootPolicy.isValid()) {
558                 try {
559                     Files.delete(tempFile);
560                 } catch (Exception ee) {
561                     PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, ee, STR_CLASS,
562                             "Policy was invalid, could NOT delete it.");
563                 }
564                 throw new PAPException("Policy is invalid");
565             }
566             //
567             // Add it in
568             //
569             this.policies.add(tempRootPolicy);
570             //
571             // We are changed
572             //
573             this.firePDPGroupChanged(this);
574             //
575             // Return our new object.
576             //
577             return tempRootPolicy;
578         } catch (IOException e) {
579             PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, e, STR_CLASS, "Failed to publishPolicy");
580         }
581         return null;
582     }
583
584     /**
585      * Copy one policy file into the Group's directory but do not change the configuration.
586      * This is one part of a multi-step process of publishing policies.
587      * There may be multiple changes in the group (adding multiple policies, deleting policies, changine
588      * root<->referenced)
589      * that must be done all at once, so we just copy the file in preparation for a later "update whole group"
590      * operation.
591      *
592      * @param id String
593      * @param policy InputStream
594      * @throws PAPException PAPException
595      */
596     public void copyPolicyToFile(String id, InputStream policy) throws PAPException {
597         copyPolicyToFile(id, this.name, policy);
598     }
599
600     /**
601      * Policy Engine API Copy one policy file into the Group's directory but do not change the configuration.
602      *
603      * @param id String
604      * @param fileName String
605      * @param policy InputStream
606      * @throws PAPException PAPException
607      */
608     public void copyPolicyToFile(String id, String fileName, InputStream policy) throws PAPException {
609         try {
610             //
611             // Copy the policy over
612             //
613             long num;
614             Path policyFilePath = Paths.get(this.directory.toAbsolutePath().toString(), id);
615
616             Path policyFile;
617             if (policyFilePath.toFile().exists()) {
618                 policyFile = policyFilePath;
619             } else {
620                 policyFile = Files.createFile(policyFilePath);
621             }
622
623             try (OutputStream os = Files.newOutputStream(policyFile)) {
624                 num = ByteStreams.copy(policy, os);
625             }
626
627             logger.info("Copied " + num + " bytes for policy " + fileName);
628             for (PDPPolicy p : policies) {
629                 if (p.getId().equals(id)) {
630                     // we just re-copied/refreshed/updated the policy file for a policy that already exists in this
631                     // group
632                     logger.info("Policy '" + id + "' already exists in group '" + getId() + "'");
633                     return;
634                 }
635             }
636
637             // policy is new to this group
638             StdPDPPolicy tempRootPolicy = new StdPDPPolicy(id, true, fileName, policyFile.toUri());
639             if (!tempRootPolicy.isValid()) {
640                 try {
641                     Files.delete(policyFile);
642                 } catch (Exception ee) {
643                     PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, ee, STR_CLASS,
644                             "Policy was invalid, could NOT delete it.");
645                 }
646                 throw new PAPException("Policy is invalid");
647             }
648             //
649             // Add it in
650             //
651             this.policies.add(tempRootPolicy);
652             //
653             // We are changed
654             //
655             this.firePDPGroupChanged(this);
656
657         } catch (IOException e) {
658             PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, STR_CLASS, "Failed to copyPolicyToFile");
659             throw new PAPException("Failed to copy policy to file: " + e);
660         }
661     }
662
663     /**
664      * removePolicyFromGroup.
665      *
666      * @param policy PDPPolicy
667      * @return boolean
668      */
669     public boolean removePolicyFromGroup(PDPPolicy policy) {
670         PolicyLogger.info("policy: " + policy.getId());
671         PolicyLogger.info("Policy ID:" + policy.getPolicyId());
672         PolicyLogger.info("Policy Version: " + policy.getVersion());
673         PolicyLogger.info("StdPDPPolicy Class cast: " + this.getPolicy(policy.getId()).toString());
674         StdPDPPolicy currentPolicy = (StdPDPPolicy) this.getPolicy(policy.getId());
675         if (currentPolicy == null) {
676             PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE + "Policy " + policy.getId() + " does not exist.");
677             return false;
678         }
679         try {
680             //
681             // Remove it from our list
682             //
683             this.policies.remove(currentPolicy);
684             //
685             // We are changed
686             //
687             this.firePDPGroupChanged(this);
688             return true;
689         } catch (Exception e) {
690             PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, STR_CLASS, "Failed to delete policy");
691         }
692         return false;
693     }
694
695     /**
696      * removePolicy.
697      *
698      * @param policy PDPPolicy
699      * @return boolean
700      */
701     public boolean removePolicy(PDPPolicy policy) {
702         PDPPolicy currentPolicy = this.getPolicy(policy.getId());
703         if (currentPolicy == null) {
704             PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE + "Policy " + policy.getId() + " does not exist.");
705             return false;
706         }
707         try {
708             //
709             // Delete it on disk
710             //
711             Files.delete(Paths.get(currentPolicy.getLocation()));
712             //
713             // Remove it from our list
714             //
715             this.policies.remove(currentPolicy);
716             //
717             // We are changed
718             //
719             this.firePDPGroupChanged(this);
720             return true;
721         } catch (Exception e) {
722             PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, STR_CLASS, "Failed to delete policy " + policy);
723         }
724         return false;
725     }
726
727     @Override
728     public Set<PDPPIPConfig> getPipConfigs() {
729         return Collections.unmodifiableSet(this.pipConfigs);
730     }
731
732     @Override
733     public PDPPIPConfig getPipConfig(String id) {
734         for (PDPPIPConfig config : this.pipConfigs) {
735             if (config.getId().equals(id)) {
736                 return config;
737             }
738         }
739         return null;
740     }
741
742     public void setPipConfigs(Set<PDPPIPConfig> pipConfigs) {
743         this.pipConfigs = pipConfigs;
744         this.firePDPGroupChanged(this);
745     }
746
747     public void removeAllPIPConfigs() {
748         this.pipConfigs.clear();
749         this.firePDPGroupChanged(this);
750     }
751
752     @Override
753     public Properties getPipConfigProperties() {
754         Properties properties = new Properties();
755         List<String> configs = new ArrayList<>();
756
757         for (PDPPIPConfig config : this.pipConfigs) {
758             configs.add(config.getId());
759             properties.putAll(config.getConfiguration());
760         }
761
762         properties.setProperty(XACMLProperties.PROP_PIP_ENGINES, Joiner.on(',').join(configs));
763
764         return properties;
765     }
766
767     @Override
768     public void repair() {
769         //
770         // Reset the status object
771         //
772         this.status.reset();
773         //
774         // Validate our directory
775         //
776         boolean fire = false;
777         if (! directory.toFile().exists()) {
778             logger.warn("Group directory does NOT exist: " + directory.toString());
779             try {
780                 Files.createDirectory(directory);
781                 fire = true;
782                 this.status.addLoadWarning("Created missing group directory");
783             } catch (IOException e) {
784                 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, STR_CLASS,
785                         "Failed to create missing Group directory.");
786                 this.status.addLoadError("Failed to create missing Group directory.");
787                 this.status.setStatus(PDPGroupStatus.Status.LOAD_ERRORS);
788             }
789         }
790         //
791         // Validate our PIP config file
792         //
793         Path pipPropertiesFile = Paths.get(directory.toString(), PROPS_PIP);
794         if (! pipPropertiesFile.toFile().exists()) {
795             try {
796                 Files.createFile(pipPropertiesFile);
797                 fire = true;
798                 this.status.addLoadWarning("Created missing PIP properties file");
799             } catch (IOException e) {
800                 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, STR_CLASS,
801                         "Failed to create missing PIP properties file");
802                 this.status.addLoadError("Failed to create missing PIP properties file");
803                 this.status.setStatus(PDPGroupStatus.Status.LOAD_ERRORS);
804             }
805         }
806         //
807         // Valid our policy properties file
808         //
809         Path policyPropertiesFile = Paths.get(directory.toString(), PROPS_POLICY);
810         if (! policyPropertiesFile.toFile().exists()) {
811             try {
812                 Files.createFile(policyPropertiesFile);
813                 fire = true;
814                 this.status.addLoadWarning("Created missing Policy properties file");
815             } catch (IOException e) {
816                 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, STR_CLASS,
817                         "Failed to create missing Policy properties file");
818                 this.status.addLoadError("Failed to create missing Policy properties file");
819                 this.status.setStatus(PDPGroupStatus.Status.LOAD_ERRORS);
820             }
821         }
822         this.resetStatus();
823         if (fire) {
824             this.fireChanged();
825         }
826     }
827
828     private void readPolicyProperties(Path directory, Properties properties) {
829         //
830         // There are 2 property values that hold policies, root and referenced
831         //
832         String[] lists = new String[2];
833         lists[0] = properties.getProperty(XACMLProperties.PROP_ROOTPOLICIES);
834         lists[1] = properties.getProperty(XACMLProperties.PROP_REFERENCEDPOLICIES);
835         //
836         // Iterate each policy list
837         //
838         boolean isRoot = true;
839         for (String list : lists) {
840             //
841             // Was there actually a property?
842             //
843             if (list == null || list.length() == 0) {
844                 isRoot = false;
845                 continue;
846             }
847             //
848             // Parse it out
849             //
850             Iterable<String> policyList = Splitter.on(',').trimResults().omitEmptyStrings().split(list);
851             //
852             // Was there actually a list
853             //
854             if (policyList == null) {
855                 isRoot = false;
856                 continue;
857             }
858             for (String policyId : policyList) {
859                 //
860                 // Construct the policy filename
861                 //
862                 Path policyPath = Paths.get(directory.toString(), policyId);
863                 //
864                 // Create the Policy Object
865                 //
866                 StdPDPPolicy policy;
867                 try {
868                     policy = new StdPDPPolicy(id, isRoot, policyPath.toUri(), properties);
869                 } catch (IOException e) {
870                     PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, STR_CLASS,
871                             "Failed to create policy object");
872                     policy = null;
873                 }
874                 //
875                 // Is it valid?
876                 //
877                 if (policy != null && policy.isValid()) {
878                     this.policies.add(policy);
879                     this.status.addLoadedPolicy(policy);
880                 } else {
881                     this.status.addFailedPolicy(policy);
882                     this.status.setStatus(Status.LOAD_ERRORS);
883                 }
884                 // force all policies to have a name
885                 if (policy != null && policy.getName() == null) {
886                     policy.setName(policy.getId());
887                 }
888             }
889             isRoot = false;
890         }
891     }
892
893     private void readPipProperties(Properties properties) {
894         String list = properties.getProperty(XACMLProperties.PROP_PIP_ENGINES);
895         if (list == null || list.length() == 0) {
896             return;
897         }
898         for (String pipId : list.split("[,]")) {
899             StdPDPPIPConfig config = new StdPDPPIPConfig(pipId, properties);
900             if (config.isConfigured()) {
901                 this.pipConfigs.add(config);
902                 this.status.addLoadedPipConfig(config);
903             } else {
904                 this.status.addFailedPipConfig(config);
905                 this.status.setStatus(Status.LOAD_ERRORS);
906             }
907         }
908     }
909
910     @Override
911     public void changed() {
912
913         // save the (changed) properties
914         try {
915             saveGroupConfiguration();
916         } catch (PAPException | IOException e) {
917             PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, e, STR_CLASS,
918                     "Unable to save group configuration change");
919             // don't notify other things of change if we cannot save it???
920             return;
921         }
922
923         this.firePDPGroupChanged(this);
924
925     }
926
927     @Override
928     public void groupChanged(OnapPDPGroup group) {
929         this.changed();
930     }
931
932     @Override
933     public void pdpChanged(OnapPDP pdp) {
934         //
935         // If one of the group's PDP's changed, then the group changed
936         //
937         this.changed();
938     }
939
940     public boolean isDefault() {
941         return isDefault;
942     }
943
944     public void setDefault(boolean isDefault) {
945         this.isDefault = isDefault;
946     }
947
948     public void setStatus(PDPGroupStatus status) {
949         this.status = new StdPDPGroupStatus(status);
950     }
951
952     public void setPolicies(Set<PDPPolicy> policies) {
953         this.policies = policies;
954     }
955
956     public void setSelectedPolicies(Set<PDPPolicy> selectedPolicies) {
957         this.selectedPolicies = selectedPolicies;
958     }
959
960     public void setOperation(String operation) {
961         this.operation = operation;
962     }
963
964     /**
965      * saveGroupConfiguration.
966      *
967      * @throws PAPException PAPException
968      * @throws IOException IOException
969      */
970     public void saveGroupConfiguration() throws PAPException, IOException {
971
972         // First save the Policy properties
973
974         // save the lists of policies
975         Properties policyProperties = this.getPolicyProperties();
976
977         // save info about each policy
978         for (PDPPolicy policy : this.policies) {
979             policyProperties.put(policy.getId() + STR_APPEND_NAME, policy.getName());
980         }
981
982         //
983         // Now we can save the file
984         //
985         Path file = Paths.get(this.directory.toString(), PROPS_POLICY);
986         try (OutputStream os = Files.newOutputStream(file)) {
987             policyProperties.store(os, "");
988         } catch (Exception e) {
989             PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, "STdPDPGroup", "Group Policies Config save failed");
990             throw new PAPException("Failed to save policy properties file '" + file + "'");
991         }
992
993         // Now save the PIP Config properties
994         Properties pipProperties = this.getPipConfigProperties();
995
996         //
997         // Now we can save the file
998         //
999         file = Paths.get(this.directory.toString(), PROPS_PIP);
1000         try (OutputStream os = Files.newOutputStream(file)) {
1001             pipProperties.store(os, "");
1002         } catch (Exception e) {
1003             PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE, e, STR_CLASS, "Group PIP Config save failed");
1004             throw new PAPException("Failed to save pip properties file '" + file + "'");
1005         }
1006     }
1007
1008     //
1009     // Comparable Interface
1010     //
1011     @Override
1012     public int compareTo(Object arg0) {
1013         if (arg0 == null) {
1014             return -1;
1015         }
1016         if (!(arg0 instanceof StdPDPGroup)) {
1017             return -1;
1018         }
1019         if (((StdPDPGroup) arg0).name == null) {
1020             return -1;
1021         }
1022         if (name == null) {
1023             return 1;
1024         }
1025
1026         return name.compareTo(((StdPDPGroup) arg0).name);
1027     }
1028
1029     // Adding Default PIP engine(s) while Loading initially. We don't want
1030     // Programmer intervention with the PIP engines.
1031     private Properties setPipProperties(Properties props) {
1032         props.setProperty("AAF.name", "AAFEngine");
1033         props.setProperty("AAF.description", "AAFEngine to communicate with AAF to take decisions");
1034         props.setProperty("AAF.classname", "org.onap.policy.xacml.std.pip.engines.aaf.AAFEngine");
1035         props.setProperty(XACMLProperties.PROP_PIP_ENGINES, "AAF");
1036         // read from PIP properties file.
1037         Path file = Paths.get(StdEngine.PIP_PROPERTY_FILE);
1038         if (file.toFile().exists()) {
1039             InputStream in;
1040             Properties prop = new Properties();
1041             try {
1042                 in = new FileInputStream(file.toFile());
1043                 prop.load(in);
1044             } catch (IOException e) {
1045                 PolicyLogger.error(
1046                         XACMLErrorConstants.ERROR_SYSTEM_ERROR + "can not load the pip properties from file" + e);
1047             }
1048             props = prop;
1049         }
1050         return props;
1051     }
1052
1053 }