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