Merge "XACML Platform Enhancements"
[policy/engine.git] / ONAP-PAP-REST / src / main / java / org / onap / policy / pap / xacml / rest / components / PolicyDBDao.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP-PAP-REST
4  * ================================================================================
5  * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
6  * Modified Copyright (C) 2018 Samsung Electronics Co., Ltd.
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.policy.pap.xacml.rest.components;
23
24 import java.io.ByteArrayInputStream;
25 import java.io.File;
26 import java.io.FileInputStream;
27 import java.io.FileNotFoundException;
28 import java.io.FileWriter;
29 import java.io.IOException;
30 import java.io.InputStream;
31 import java.io.StringReader;
32 import java.net.HttpURLConnection;
33 import java.net.MalformedURLException;
34 import java.net.ProtocolException;
35 import java.net.URI;
36 import java.net.URL;
37 import java.nio.charset.StandardCharsets;
38 import java.nio.file.Files;
39 import java.nio.file.InvalidPathException;
40 import java.nio.file.Path;
41 import java.nio.file.Paths;
42 import java.util.Base64;
43 import java.util.Date;
44 import java.util.HashMap;
45 import java.util.HashSet;
46 import java.util.Iterator;
47 import java.util.LinkedList;
48 import java.util.List;
49 import java.util.Map;
50 import java.util.Set;
51 import java.util.UUID;
52 import javax.persistence.EntityManager;
53 import javax.persistence.EntityManagerFactory;
54 import javax.persistence.LockModeType;
55 import javax.persistence.PersistenceException;
56 import javax.persistence.Query;
57 import javax.persistence.RollbackException;
58 import javax.xml.parsers.DocumentBuilder;
59 import javax.xml.parsers.DocumentBuilderFactory;
60 import javax.xml.xpath.XPath;
61 import javax.xml.xpath.XPathFactory;
62 import org.apache.commons.io.FilenameUtils;
63 import org.apache.commons.io.IOUtils;
64 import org.onap.policy.common.logging.eelf.MessageCodes;
65 import org.onap.policy.common.logging.eelf.PolicyLogger;
66 import org.onap.policy.common.logging.flexlogger.FlexLogger;
67 import org.onap.policy.common.logging.flexlogger.Logger;
68 import org.onap.policy.pap.xacml.rest.XACMLPapServlet;
69 import org.onap.policy.rest.XACMLRestProperties;
70 import org.onap.policy.rest.adapter.PolicyRestAdapter;
71 import org.onap.policy.rest.dao.PolicyDBException;
72 import org.onap.policy.rest.jpa.ActionBodyEntity;
73 import org.onap.policy.rest.jpa.ConfigurationDataEntity;
74 import org.onap.policy.rest.jpa.DatabaseLockEntity;
75 import org.onap.policy.rest.jpa.GroupEntity;
76 import org.onap.policy.rest.jpa.PdpEntity;
77 import org.onap.policy.rest.jpa.PolicyDBDaoEntity;
78 import org.onap.policy.rest.jpa.PolicyEntity;
79 import org.onap.policy.utils.CryptoUtils;
80 import org.onap.policy.xacml.api.pap.OnapPDP;
81 import org.onap.policy.xacml.api.pap.OnapPDPGroup;
82 import org.onap.policy.xacml.api.pap.PAPPolicyEngine;
83 import org.onap.policy.xacml.std.pap.StdPDPGroup;
84 import org.onap.policy.xacml.std.pap.StdPDPPolicy;
85 import org.onap.policy.xacml.util.XACMLPolicyWriter;
86 import org.w3c.dom.Document;
87 import org.xml.sax.InputSource;
88 import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicySetType;
89 import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType;
90 import com.att.research.xacml.api.pap.PAPException;
91 import com.att.research.xacml.api.pap.PDP;
92 import com.att.research.xacml.api.pap.PDPPolicy;
93 import com.att.research.xacml.util.XACMLProperties;
94
95 public class PolicyDBDao {
96     private static final Logger logger = FlexLogger.getLogger(PolicyDBDao.class);
97     private List<?> otherServers;
98     private EntityManagerFactory emf;
99     private static PolicyDBDao currentInstance = null;
100     private PAPPolicyEngine papEngine;
101
102     private static final String JSON_CONFIG = "JSON";
103     private static final String XML_CONFIG = "XML";
104     private static final String PROPERTIES_CONFIG = "PROPERTIES";
105     private static final String OTHER_CONFIG = "OTHER";
106
107     // Declared to static variables which were repeating multiple times across the PolicyDBDao
108     public static final String config = "Config";
109     public static final String action = "Action";
110     private static final String groupIdVar = "groupId";
111     private static final String deletedVar = "deleted";
112     private static final String groupEntitySelectQuery =
113             "SELECT g FROM GroupEntity g WHERE g.groupId=:groupId AND g.deleted=:deleted";
114     private static final String pdpEntitySelectQuery =
115             "SELECT p FROM PdpEntity p WHERE p.pdpId=:pdpId AND p.deleted=:deleted";
116     private static final String groupCannotBeFound = "The group could not be found with id ";
117     private static final String foundInDBNotDeleted = " were found in the database that are not deleted";
118     private static final String moreThanOnePDP = "Somehow, more than one pdp with the same id ";
119     private static final String deletedStatusFound = " and deleted status were found in the database";
120     private static final String duplicateGroupId = "Somehow, more than one group with the same id ";
121     private static final String pdpIdVariable = "pdpId";
122     private static final String queryFailedToCheckExisting = "Query failed trying to check for existing group";
123     private static final String queryFailedToGetGroup = "Query failed trying to get group ";
124     public static final String scope = "scope";
125     private static final String policyDBDaoVar = "PolicyDBDao";
126     private static final String duplicatePolicyId = "Somehow, more than one policy with the id ";
127     private static final String foundInDB = " were found in the database";
128
129     private static boolean isJunit = false;
130
131     public static void setJunit(boolean isJunit) {
132         PolicyDBDao.isJunit = isJunit;
133     }
134
135     /**
136      * Get an instance of a PolicyDBDao. It creates one if it does not exist. Only one instance is allowed to be created
137      * per server.
138      *
139      * @param emf The EntityFactoryManager to be used for database connections
140      * @return The new instance of PolicyDBDao or throw exception if the given emf is null.
141      * @throws IllegalStateException if a PolicyDBDao has already been constructed. Call getPolicyDBDaoInstance() to get
142      *         this.
143      */
144     public static PolicyDBDao getPolicyDBDaoInstance(EntityManagerFactory emf) {
145         logger.debug("getPolicyDBDaoInstance(EntityManagerFactory emf) as getPolicyDBDaoInstance(" + emf + ") called");
146         if (currentInstance == null) {
147             if (emf != null) {
148                 currentInstance = new PolicyDBDao(emf);
149                 return currentInstance;
150             }
151             throw new IllegalStateException("The EntityManagerFactory is Null");
152         }
153         return currentInstance;
154     }
155
156     /**
157      * Gets the current instance of PolicyDBDao.
158      *
159      * @return The instance of PolicyDBDao or throws exception if the given instance is null.
160      * @throws IllegalStateException if a PolicyDBDao instance is null. Call createPolicyDBDaoInstance
161      *         (EntityManagerFactory emf) to get this.
162      */
163     public static PolicyDBDao getPolicyDBDaoInstance() {
164         logger.debug("getPolicyDBDaoInstance() as getPolicyDBDaoInstance() called");
165         if (currentInstance != null) {
166             return currentInstance;
167         }
168         throw new IllegalStateException(
169                 "The PolicyDBDao.currentInstance is Null.  Use getPolicyDBDao(EntityManagerFactory emf)");
170     }
171
172     public void setPapEngine(PAPPolicyEngine papEngine2) {
173         this.papEngine = papEngine2;
174     }
175
176     private PolicyDBDao(EntityManagerFactory emf) {
177         logger.debug("PolicyDBDao(EntityManagerFactory emf) as PolicyDBDao(" + emf + ") called");
178         this.emf = emf;
179
180         // not needed in this release
181         if (!register()) {
182             PolicyLogger
183                     .error("This server's PolicyDBDao instance could not be registered and may not reveive updates");
184         }
185
186         otherServers = getRemotePolicyDBDaoList();
187         if (logger.isDebugEnabled()) {
188             logger.debug("Number of remote PolicyDBDao instances: " + otherServers.size());
189         }
190         if (otherServers.isEmpty()) {
191             logger.warn("List of PolicyDBDao servers is empty or could not be retrieved");
192         }
193     }
194
195     // not static because we are going to be using the instance's emf
196     // waitTime in ms to wait for lock, or -1 to wait forever (no)
197     private void startTransactionSynced(EntityManager entityMgr, int waitTime) {
198         logger.debug("\n\nstartTransactionSynced(EntityManager entityMgr,int waitTime) as "
199                 + "\n   startTransactionSynced(" + entityMgr + "," + waitTime + ") called\n\n");
200         DatabaseLockEntity lock = null;
201
202         entityMgr.setProperty("javax.persistence.query.timeout", waitTime);
203         entityMgr.getTransaction().begin();
204
205         if (logger.isDebugEnabled()) {
206             Map<String, Object> properties = entityMgr.getProperties();
207             logger.debug(
208                     "\n\nstartTransactionSynced():" + "\n   entityManager.getProperties() = " + properties + "\n\n");
209         }
210         try {
211             if (logger.isDebugEnabled()) {
212                 logger.debug("\n\nstartTransactionSynced():" + "\n   ATTEMPT to get the DB lock" + "\n\n");
213             }
214             lock = entityMgr.find(DatabaseLockEntity.class, 1, LockModeType.PESSIMISTIC_WRITE);
215             if (logger.isDebugEnabled()) {
216                 logger.debug("\n\nstartTransactionSynced():" + "\n   GOT the DB lock" + "\n\n");
217             }
218         } catch (Exception e) {
219             System.out.println("Could not get lock entity");
220             logger.error("Exception Occured" + e);
221         }
222         if (lock == null) {
223             throw new IllegalStateException(
224                     "The lock row does not exist in the table. Please create a primary key with value = 1.");
225         }
226
227     }
228
229     /**
230      * Gets the list of other registered PolicyDBDaos from the database
231      *
232      * @return List (type PolicyDBDaoEntity) of other PolicyDBDaos
233      */
234     private List<?> getRemotePolicyDBDaoList() {
235         logger.debug("getRemotePolicyDBDaoList() as getRemotePolicyDBDaoList() called");
236         List<?> policyDBDaoEntityList = new LinkedList<>();
237         EntityManager em = emf.createEntityManager();
238         startTransactionSynced(em, 1000);
239         try {
240             Query getPolicyDBDaoEntityQuery = em.createNamedQuery("PolicyDBDaoEntity.findAll");
241             policyDBDaoEntityList = getPolicyDBDaoEntityQuery.getResultList();
242
243         } catch (Exception e) {
244             PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
245                     "Exception querying for other registered PolicyDBDaos");
246             logger.warn("List of remote PolicyDBDaos will be empty", e);
247         }
248         try {
249             em.getTransaction().commit();
250         } catch (Exception e) {
251             logger.warn("List of remote PolicyDBDaos will be empty", e);
252             try {
253                 em.getTransaction().rollback();
254             } catch (Exception e2) {
255                 logger.debug("List of remote PolicyDBDaos will be empty", e2);
256             }
257         }
258         em.close();
259         return policyDBDaoEntityList;
260     }
261
262     public PolicyDBDaoTransaction getNewTransaction() {
263         logger.debug("getNewTransaction() as getNewTransaction() called");
264         return new PolicyDBDaoTransactionInstance();
265     }
266
267     /*
268      * Because the normal transactions are not used in audits, we can use the same transaction mechanism to get a
269      * transaction and obtain the emlock and the DB lock. We just need to provide different transaction timeout values
270      * in ms because the audit will run longer than normal transactions.
271      */
272     public PolicyDBDaoTransaction getNewAuditTransaction() {
273         logger.debug("getNewAuditTransaction() as getNewAuditTransaction() called");
274         // Use the standard transaction wait time in ms
275         int auditWaitMs = Integer.parseInt(XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_TRANS_WAIT));
276         // Use the (extended) audit timeout time in ms
277         int auditTimeoutMs = Integer.parseInt(XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_AUDIT_TIMEOUT));
278         return new PolicyDBDaoTransactionInstance(auditTimeoutMs, auditWaitMs);
279     }
280
281
282     /**
283      * Checks if two strings are equal. Null strings ARE allowed.
284      *
285      * @param one A String or null to compare
286      * @param two A String or null to compare
287      */
288     private static boolean stringEquals(String one, String two) {
289         logger.debug("stringEquals(String one, String two) as stringEquals(" + one + ", " + two + ") called");
290         if (one == null && two == null) {
291             return true;
292         }
293         if (one == null || two == null) {
294             return false;
295         }
296         return one.equals(two);
297     }
298
299     /**
300      * Returns the url of this local pap server, removing the username and password, if they are present
301      *
302      * @return The url of this local pap server
303      */
304     private String[] getPapUrlUserPass() {
305         logger.debug("getPapUrl() as getPapUrl() called");
306         String url = XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_URL);
307         if (url == null) {
308             return null;
309         }
310         return splitPapUrlUserPass(url);
311     }
312
313     private String[] splitPapUrlUserPass(String url) {
314         String[] urlUserPass = new String[3];
315         String[] commaSplit = url.split(",");
316         urlUserPass[0] = commaSplit[0];
317         if (commaSplit.length > 2) {
318             urlUserPass[1] = commaSplit[1];
319             urlUserPass[2] = commaSplit[2];
320         }
321         if (urlUserPass[1] == null || "".equals(urlUserPass[1])) {
322             String usernamePropertyValue = XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_USERID);
323             if (usernamePropertyValue != null) {
324                 urlUserPass[1] = usernamePropertyValue;
325             }
326         }
327         if (urlUserPass[2] == null || "".equals(urlUserPass[2])) {
328             String passwordPropertyValue = XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_PASS);
329             if (passwordPropertyValue != null) {
330                 urlUserPass[2] = passwordPropertyValue;
331             }
332         }
333         // if there is no comma, for some reason there is no username and password, so don't try to cut them off
334         return urlUserPass;
335     }
336
337     /**
338      * Register the PolicyDBDao instance in the PolicyDBDaoEntity table
339      *
340      * @return Boolean, were we able to register?
341      */
342     private boolean register() {
343         logger.debug("register() as register() called");
344         String[] url = getPapUrlUserPass();
345         // --- check URL length
346         if (url == null || url.length < 3) {
347             return false;
348         }
349         EntityManager em = emf.createEntityManager();
350         try {
351             startTransactionSynced(em, 1000);
352         } catch (IllegalStateException e) {
353             logger.debug("\nPolicyDBDao.register() caught an IllegalStateException: \n" + e + "\n");
354             DatabaseLockEntity lock;
355             lock = em.find(DatabaseLockEntity.class, 1);
356             if (lock == null) {
357                 lock = new DatabaseLockEntity();
358                 em.persist(lock);
359                 lock.setKey(1);
360                 try {
361                     em.flush();
362                     em.getTransaction().commit();
363                     em.close();
364                 } catch (Exception e2) {
365                     PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e2, policyDBDaoVar,
366                             "COULD NOT CREATE DATABASELOCK ROW.  WILL TRY ONE MORE TIME");
367                 }
368
369                 em = emf.createEntityManager();
370                 try {
371                     startTransactionSynced(em, 1000);
372                 } catch (Exception e3) {
373                     String msg = "DATABASE LOCKING NOT WORKING. CONCURRENCY CONTROL NOT WORKING";
374                     PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e3, policyDBDaoVar, msg);
375                     throw new IllegalStateException("msg" + "\n" + e3);
376                 }
377             }
378         }
379         logger.debug("\nPolicyDBDao.register. Database locking and concurrency control is initialized\n");
380         PolicyDBDaoEntity foundPolicyDBDaoEntity = em.find(PolicyDBDaoEntity.class, url[0]);
381         Query getPolicyDBDaoEntityQuery =
382                 em.createQuery("SELECT e FROM PolicyDBDaoEntity e WHERE e.policyDBDaoUrl=:url");
383         getPolicyDBDaoEntityQuery.setParameter("url", url[0]);
384         // encrypt the password
385         String txt = null;
386         try {
387             txt = CryptoUtils.encryptTxt(url[2].getBytes(StandardCharsets.UTF_8));
388         } catch (Exception e) {
389             logger.debug(e);
390             PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar, "Could not encrypt PAP password");
391         }
392         if (foundPolicyDBDaoEntity == null) {
393             PolicyDBDaoEntity newPolicyDBDaoEntity = new PolicyDBDaoEntity();
394             em.persist(newPolicyDBDaoEntity);
395             newPolicyDBDaoEntity.setPolicyDBDaoUrl(url[0]);
396             newPolicyDBDaoEntity.setDescription("PAP server at " + url[0]);
397             newPolicyDBDaoEntity.setUsername(url[1]);
398             newPolicyDBDaoEntity.setPassword(txt);
399             try {
400                 em.getTransaction().commit();
401             } catch (Exception e) {
402                 logger.debug(e);
403                 try {
404                     em.getTransaction().rollback();
405                 } catch (Exception e2) {
406                     logger.debug(e2);
407                     PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e2, policyDBDaoVar,
408                             "Could not add new PolicyDBDao to the database");
409                 }
410             }
411         } else {
412             // just want to update in order to change modified date
413             if (url[1] != null && !stringEquals(url[1], foundPolicyDBDaoEntity.getUsername())) {
414                 foundPolicyDBDaoEntity.setUsername(url[1]);
415             }
416             if (txt != null && !stringEquals(txt, foundPolicyDBDaoEntity.getPassword())) {
417                 foundPolicyDBDaoEntity.setPassword(txt);
418             }
419             foundPolicyDBDaoEntity.preUpdate();
420             try {
421                 em.getTransaction().commit();
422             } catch (Exception e) {
423                 logger.debug(e);
424                 try {
425                     em.getTransaction().rollback();
426                 } catch (Exception e2) {
427                     logger.debug(e2);
428                     PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e2, policyDBDaoVar,
429                             "Could not update PolicyDBDao in the database");
430                 }
431             }
432         }
433         em.close();
434         logger.debug("\nPolicyDBDao.register(). Success!!\n");
435         return true;
436     }
437
438     private class NotifyOtherThread implements Runnable {
439         public NotifyOtherThread(Object obj, long entityId, String entityType, String newGroupId) {
440             this.obj = obj;
441             this.entityId = entityId;
442             this.entityType = entityType;
443             this.newGroupId = newGroupId;
444         }
445
446         private Object obj;
447         private long entityId;
448         private String entityType;
449         private String newGroupId;
450
451         @Override
452         public void run() {
453             // naming of 'o' is for backwards compatibility with the rest of the function
454             PolicyDBDaoEntity dbdEntity = (PolicyDBDaoEntity) obj;
455             String o = dbdEntity.getPolicyDBDaoUrl();
456             String username = dbdEntity.getUsername();
457             String txt;
458             try {
459                 txt = new String(CryptoUtils.decryptTxt(dbdEntity.getPassword()), StandardCharsets.UTF_8);
460             } catch (Exception e) {
461                 logger.debug(e);
462                 // if we can't decrypt, might as well try it anyway
463                 txt = dbdEntity.getPassword();
464             }
465             Base64.Encoder encoder = Base64.getEncoder();
466             String encoding = encoder.encodeToString((username + ":" + txt).getBytes(StandardCharsets.UTF_8));
467             HttpURLConnection connection = null;
468             UUID requestID = UUID.randomUUID();
469             URL url;
470             String papUrl;
471             try {
472                 String[] papUrlUserPass = getPapUrlUserPass();
473                 if (papUrlUserPass == null) {
474                     papUrl = "undefined";
475                 } else {
476                     papUrl = papUrlUserPass[0];
477                 }
478                 logger.debug("We are going to try to notify " + o);
479                 // is this our own url?
480                 String ourUrl = o;
481                 try {
482                     ourUrl = splitPapUrlUserPass((String) o)[0];
483                 } catch (Exception e) {
484                     logger.debug(e);
485                 }
486                 if (o == null) {
487                     o = "undefined";
488                 }
489                 if (papUrl.equals(ourUrl)) {
490                     logger.debug(o + " is our url, skipping notify");
491                     return;
492                 }
493                 if (newGroupId == null) {
494                     url = new URL(
495                             o + "?policydbdaourl=" + papUrl + "&entityid=" + entityId + "&entitytype=" + entityType);
496                 } else {
497                     url = new URL(o + "?policydbdaourl=" + papUrl + "&entityid=" + entityId + "&entitytype="
498                             + entityType + "&extradata=" + newGroupId);
499                 }
500             } catch (MalformedURLException e) {
501                 logger.warn("Caught MalformedURLException on: new URL()", e);
502                 return;
503             }
504             //
505             // Open up the connection
506             //
507             logger.info("PolicyDBDao: NotifyOtherThread: notifying other PAPs of an update");
508             logger.info("Connecting with url: " + url);
509             try {
510                 connection = (HttpURLConnection) url.openConnection();
511             } catch (Exception e) {
512                 logger.warn("Caught exception on: url.openConnection()", e);
513                 return;
514             }
515             //
516             // Setup our method and headers
517             //
518             try {
519                 connection.setRequestMethod("PUT");
520             } catch (ProtocolException e) {
521                 // why would this error ever occur?
522                 logger.warn("Caught ProtocolException on connection.setRequestMethod(\"PUT\");", e);
523                 return;
524             }
525             connection.setRequestProperty("Authorization", "Basic " + encoding);
526             connection.setRequestProperty("Accept", "text/x-java-properties");
527             connection.setRequestProperty("Content-Type", "text/x-java-properties");
528             connection.setRequestProperty("requestID", requestID.toString());
529             int readTimeout;
530             try {
531                 readTimeout =
532                         Integer.parseInt(XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_NOTIFY_TIMEOUT));
533             } catch (Exception e) {
534                 logger.error("xacml.rest.pap.notify.timeoutms property not set, using a default.", e);
535                 readTimeout = 10000;
536             }
537             connection.setReadTimeout(readTimeout);
538             connection.setConnectTimeout(readTimeout);
539             connection.setUseCaches(false);
540             //
541             // Adding this in. It seems the HttpUrlConnection class does NOT
542             // properly forward our headers for POST re-direction. It does so
543             // for a GET re-direction.
544             //
545             // So we need to handle this ourselves.
546             //
547             connection.setInstanceFollowRedirects(false);
548             connection.setDoOutput(true);
549             connection.setDoInput(true);
550             try {
551                 connection.connect();
552             } catch (Exception e) {
553                 logger.warn("Caught exception on: connection.connect()", e);
554                 return;
555             }
556             try {
557                 if (connection.getResponseCode() == 200) {
558                     logger.info("PolicyDBDao: NotifyOtherThread received response 200 from pap server on notify");
559                 } else {
560                     logger.warn("PolicyDBDao: NotifyOtherThread connection response code not 200, received: "
561                             + connection.getResponseCode());
562                 }
563             } catch (Exception e) {
564                 logger.warn("Caught Exception on: connection.getResponseCode() ", e);
565             }
566
567             connection.disconnect();
568         }
569     }
570
571     private static String evaluateXPath(String expression, String xml) {
572         InputSource source = new InputSource(new StringReader(xml));
573
574         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
575         String description = "";
576         try {
577             DocumentBuilder db = dbf.newDocumentBuilder();
578             Document document = db.parse(source);
579
580             XPathFactory xpathFactory = XPathFactory.newInstance();
581             XPath xpath = xpathFactory.newXPath();
582
583             description = xpath.evaluate(expression, document);
584         } catch (Exception e) {
585             logger.error("Exception Occured while evaluating path" + e);
586         }
587         return description;
588     }
589
590     private static final String POLICY_NOTIFICATION = "policy";
591     private static final String PDP_NOTIFICATION = "pdp";
592     private static final String GROUP_NOTIFICATION = "group";
593
594     public void handleIncomingHttpNotification(String url, String entityId, String entityType, String extraData,
595             XACMLPapServlet xacmlPapServlet) {
596         logger.info("DBDao url: " + url + " has reported an update on " + entityType + " entity " + entityId);
597         PolicyDBDaoTransaction transaction = this.getNewTransaction();
598         // although its named retries, this is the total number of tries
599         int retries;
600         try {
601             retries = Integer
602                     .parseInt(XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_INCOMINGNOTIFICATION_TRIES));
603         } catch (Exception e) {
604             logger.error("xacml.rest.pap.incomingnotification.tries property not set, using a default of 3." + e);
605             retries = 3;
606         }
607         // if someone sets it to some dumb value, we need to make sure it will try at least once
608         if (retries < 1) {
609             retries = 1;
610         }
611         int pauseBetweenRetries = 1000;
612         switch (entityType) {
613
614             case POLICY_NOTIFICATION:
615                 for (int i = 0; i < retries; i++) {
616                     try {
617                         handleIncomingPolicyChange(entityId);
618                         break;
619                     } catch (Exception e) {
620                         logger.debug(e);
621                         PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
622                                 "Caught exception on handleIncomingPolicyChange(" + url + ", " + entityId + ", "
623                                         + extraData + ")");
624                     }
625                     try {
626                         Thread.sleep(pauseBetweenRetries);
627                     } catch (InterruptedException ie) {
628                         Thread.currentThread().interrupt();
629                         break;
630                     }
631                 }
632                 break;
633             case PDP_NOTIFICATION:
634                 for (int i = 0; i < retries; i++) {
635                     try {
636                         handleIncomingPdpChange(entityId, transaction);
637                         break;
638                     } catch (Exception e) {
639                         logger.debug(e);
640                         PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
641                                 "Caught exception on handleIncomingPdpChange(" + url + ", " + entityId + ", "
642                                         + transaction + ")");
643                     }
644                     try {
645                         Thread.sleep(pauseBetweenRetries);
646                     } catch (InterruptedException ie) {
647                         Thread.currentThread().interrupt();
648                         break;
649                     }
650                 }
651                 break;
652             case GROUP_NOTIFICATION:
653                 for (int i = 0; i < retries; i++) {
654                     try {
655                         handleIncomingGroupChange(entityId, extraData, transaction);
656                         break;
657                     } catch (Exception e) {
658                         logger.debug(e);
659                         PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
660                                 "Caught exception on handleIncomingGroupChange(" + url + ", " + entityId + ", "
661                                         + extraData + ", " + transaction + ", " + xacmlPapServlet + ")");
662                     }
663                     try {
664                         Thread.sleep(pauseBetweenRetries);
665                     } catch (InterruptedException ie) {
666                         Thread.currentThread().interrupt();
667                         break;
668                     }
669                 }
670                 break;
671         }
672         // no changes should be being made in this function, we still need to close
673         transaction.rollbackTransaction();
674     }
675
676     private void handleIncomingGroupChange(String groupId, String extraData, PolicyDBDaoTransaction transaction)
677             throws PAPException, PolicyDBException {
678         GroupEntity groupRecord = null;
679         long groupIdLong = -1;
680         try {
681             groupIdLong = Long.parseLong(groupId);
682         } catch (NumberFormatException e) {
683             throw new IllegalArgumentException("groupId " + groupId + " cannot be parsed into a long");
684         }
685         try {
686             groupRecord = transaction.getGroup(groupIdLong);
687         } catch (Exception e) {
688             PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
689                     "Caught Exception trying to get pdp group record with transaction.getGroup(" + groupIdLong + ");");
690             throw new PAPException("Could not get local group " + groupIdLong);
691         }
692         if (groupRecord == null) {
693             throw new PersistenceException("The group record returned is null");
694         }
695         // compare to local fs
696         // does group folder exist
697         OnapPDPGroup localGroup = null;
698         try {
699             localGroup = papEngine.getGroup(groupRecord.getGroupId());
700         } catch (Exception e) {
701             logger.warn("Caught PAPException trying to get local pdp group with papEngine.getGroup(" + groupId + ");",
702                     e);
703         }
704         if (localGroup == null && extraData != null) {
705             // here we can try to load an old group id from the extraData
706             try {
707                 localGroup = papEngine.getGroup(extraData);
708             } catch (Exception e) {
709                 logger.warn(
710                         "Caught PAPException trying to get local pdp group with papEngine.getGroup(" + extraData + ");",
711                         e);
712             }
713         }
714         if (localGroup != null && groupRecord.isDeleted()) {
715             OnapPDPGroup newLocalGroup = null;
716             if (extraData != null) {
717                 try {
718                     newLocalGroup = papEngine.getGroup(extraData);
719                 } catch (PAPException e) {
720                     PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
721                             "Caught PAPException trying to get new pdp group with papEngine.getGroup(" + extraData
722                                     + ");");
723                 }
724             }
725             try {
726                 papEngine.removeGroup(localGroup, newLocalGroup);
727             } catch (NullPointerException | PAPException e) {
728                 PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
729                         "Caught PAPException trying to get remove pdp group with papEngine.removeGroup(" + localGroup
730                                 + ", " + newLocalGroup + ");");
731                 throw new PAPException("Could not remove group " + groupId);
732             }
733         } else if (localGroup == null) {
734             // creating a new group
735             try {
736                 papEngine.newGroup(groupRecord.getgroupName(), groupRecord.getDescription());
737             } catch (NullPointerException | PAPException e) {
738                 PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
739                         "Caught PAPException trying to create pdp group with papEngine.newGroup(groupRecord"
740                                 + ".getgroupName(), groupRecord.getDescription());");
741                 throw new PAPException("Could not create group " + groupRecord);
742             }
743             try {
744                 localGroup = papEngine.getGroup(groupRecord.getGroupId());
745             } catch (PAPException e1) {
746                 PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e1, policyDBDaoVar,
747                         "Caught PAPException trying to get pdp group we just created with papEngine.getGroup"
748                                 + "(groupRecord.getGroupId());\nAny PDPs or policies in the new group may not have been added");
749                 return;
750             }
751             // add possible pdps to group
752             List<?> pdpsInGroup = transaction.getPdpsInGroup(Long.parseLong(groupRecord.getGroupId()));
753             for (Object pdpO : pdpsInGroup) {
754                 PdpEntity pdp = (PdpEntity) pdpO;
755                 try {
756                     papEngine.newPDP(pdp.getPdpId(), localGroup, pdp.getPdpName(), pdp.getDescription(),
757                             pdp.getJmxPort());
758                 } catch (NullPointerException | PAPException e) {
759                     PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
760                             "Caught PAPException trying to get create pdp with papEngine.newPDP(pdp.getPdpId(), "
761                                     + "localGroup, pdp.getPdpName(), pdp.getDescription(), pdp.getJmxPort());");
762                     throw new PAPException("Could not create pdp " + pdp);
763                 }
764             }
765             // add possible policies to group (filesystem only, apparently)
766         } else {
767             if (!(localGroup instanceof StdPDPGroup)) {
768                 throw new PAPException("group is not a StdPDPGroup");
769             }
770             // clone the object
771             // because it will be comparing the new group to its own version
772             StdPDPGroup localGroupClone = new StdPDPGroup(localGroup.getId(), localGroup.isDefaultGroup(),
773                     localGroup.getName(), localGroup.getDescription(), ((StdPDPGroup) localGroup).getDirectory());
774             localGroupClone.setOnapPdps(localGroup.getOnapPdps());
775             localGroupClone.setPipConfigs(localGroup.getPipConfigs());
776             localGroupClone.setStatus(localGroup.getStatus());
777             // we are updating a group or adding a policy or changing default
778             // set default if it should be
779             if (!localGroupClone.isDefaultGroup() && groupRecord.isDefaultGroup()) {
780                 try {
781                     papEngine.setDefaultGroup(localGroup);
782                     return;
783                 } catch (PAPException e) {
784                     PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
785                             "Caught PAPException trying to set default group with papEngine.SetDefaultGroup("
786                                     + localGroupClone + ");");
787                     throw new PAPException("Could not set default group to " + localGroupClone);
788                 }
789             }
790             boolean needToUpdate = false;
791             if (updateGroupPoliciesInFileSystem(localGroupClone, localGroup, groupRecord, transaction)) {
792                 needToUpdate = true;
793             }
794             if (!stringEquals(localGroupClone.getId(), groupRecord.getGroupId())
795                     || !stringEquals(localGroupClone.getName(), groupRecord.getgroupName())) {
796                 // changing ids
797                 // we do not want to change the id, the papEngine will do this for us, it needs to know the old id
798                 localGroupClone.setName(groupRecord.getgroupName());
799                 needToUpdate = true;
800             }
801             if (!stringEquals(localGroupClone.getDescription(), groupRecord.getDescription())) {
802                 localGroupClone.setDescription(groupRecord.getDescription());
803                 needToUpdate = true;
804             }
805             if (needToUpdate) {
806                 try {
807                     papEngine.updateGroup(localGroupClone);
808                 } catch (PAPException e) {
809                     PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
810                             "Caught PAPException trying to update group with papEngine.updateGroup(" + localGroupClone
811                                     + ");");
812                     throw new PAPException("Could not update group " + localGroupClone);
813                 }
814             }
815         }
816     }
817
818     // this will also handle removes, since incoming pdpGroup has no policies internally, we are just going to add
819     // them all in from the db
820     private boolean updateGroupPoliciesInFileSystem(OnapPDPGroup pdpGroup, OnapPDPGroup oldPdpGroup,
821             GroupEntity groupRecord, PolicyDBDaoTransaction transaction) throws PAPException, PolicyDBException {
822         if (!(pdpGroup instanceof StdPDPGroup)) {
823             throw new PAPException("group is not a StdPDPGroup");
824         }
825         StdPDPGroup group = (StdPDPGroup) pdpGroup;
826         // this must always be true since we don't explicitly know when a delete is occuring
827         boolean didUpdate = true;
828         HashMap<String, PDPPolicy> currentPolicySet = new HashMap<>(oldPdpGroup.getPolicies().size());
829         HashSet<PDPPolicy> newPolicySet = new HashSet<>();
830         for (PDPPolicy pdpPolicy : oldPdpGroup.getPolicies()) {
831             currentPolicySet.put(pdpPolicy.getId(), pdpPolicy);
832         }
833         for (PolicyEntity policy : groupRecord.getPolicies()) {
834             String pdpPolicyName = getPdpPolicyName(policy.getPolicyName(), policy.getScope());
835             if (group.getPolicy(pdpPolicyName) == null) {
836                 didUpdate = true;
837                 if (currentPolicySet.containsKey(pdpPolicyName)) {
838                     newPolicySet.add(currentPolicySet.get(pdpPolicyName));
839                 } else {
840                     logger.info(
841                             "PolicyDBDao: Adding the new policy to the PDP group after notification: " + pdpPolicyName);
842                     InputStream policyStream = new ByteArrayInputStream(policy.getPolicyData().getBytes());
843                     group.copyPolicyToFile(pdpPolicyName, policyStream);
844                     ((StdPDPPolicy) (group.getPolicy(pdpPolicyName)))
845                             .setName(removeExtensionAndVersionFromPolicyName(pdpPolicyName));
846                     try {
847                         policyStream.close();
848                     } catch (IOException e) {
849                         didUpdate = false;
850                         PolicyLogger.error(e.getMessage() + e);
851                     }
852                 }
853             }
854         }
855         logger.info("PolicyDBDao: Adding updated policies to group after notification.");
856         if (didUpdate) {
857             newPolicySet.addAll(group.getPolicies());
858             group.setPolicies(newPolicySet);
859         }
860         return didUpdate;
861     }
862
863     /*
864      * This method is called during all pushPolicy transactions and makes sure the file system group is in sync with the
865      * database groupentity
866      */
867     private StdPDPGroup synchronizeGroupPoliciesInFileSystem(StdPDPGroup pdpGroup, GroupEntity groupentity)
868             throws PAPException, PolicyDBException {
869
870         HashMap<String, PDPPolicy> currentPolicyMap = new HashMap<>();
871         HashSet<String> newPolicyIdSet = new HashSet<>();
872         HashSet<PDPPolicy> newPolicySet = new HashSet<>();
873
874         for (PDPPolicy pdpPolicy : pdpGroup.getPolicies()) {
875             currentPolicyMap.put(pdpPolicy.getId(), pdpPolicy);
876         }
877
878         for (PolicyEntity policy : groupentity.getPolicies()) {
879             String pdpPolicyId = getPdpPolicyName(policy.getPolicyName(), policy.getScope());
880             newPolicyIdSet.add(pdpPolicyId);
881
882             if (currentPolicyMap.containsKey(pdpPolicyId)) {
883                 newPolicySet.add(currentPolicyMap.get(pdpPolicyId));
884             } else {
885                 // convert PolicyEntity object to PDPPolicy
886                 String name = pdpPolicyId.replace(".xml", "");
887                 name = name.substring(0, name.lastIndexOf('.'));
888                 InputStream policyStream = new ByteArrayInputStream(policy.getPolicyData().getBytes());
889                 pdpGroup.copyPolicyToFile(pdpPolicyId, name, policyStream);
890                 URI location = Paths.get(pdpGroup.getDirectory().toAbsolutePath().toString(), pdpPolicyId).toUri();
891                 StdPDPPolicy newPolicy = null;
892                 try {
893                     newPolicy = new StdPDPPolicy(pdpPolicyId, true,
894                             removeExtensionAndVersionFromPolicyName(pdpPolicyId), location);
895                     newPolicySet.add(newPolicy);
896                 } catch (Exception e) {
897                     logger.debug(e);
898                     PolicyLogger
899                             .error("PolicyDBDao: Exception occurred while creating the StdPDPPolicy newPolicy object "
900                                     + e.getMessage());
901                 }
902             }
903         }
904
905         for (String id : currentPolicyMap.keySet()) {
906             if (!newPolicyIdSet.contains(id)) {
907                 try {
908                     Files.delete(Paths.get(currentPolicyMap.get(id).getLocation()));
909                 } catch (Exception e) {
910                     logger.debug(e);
911                     PolicyLogger
912                             .error("PolicyDBDao: Exception occurred while attempting to delete the old version of the"
913                                     + " policy file from the group. " + e.getMessage());
914                 }
915             }
916         }
917
918         logger.info("PolicyDBDao: Adding new policy set to group to keep filesystem and DB in sync");
919         pdpGroup.setPolicies(newPolicySet);
920
921         return pdpGroup;
922     }
923
924     private String removeExtensionAndVersionFromPolicyName(String originalPolicyName) throws PolicyDBException {
925         return getPolicyNameAndVersionFromPolicyFileName(originalPolicyName)[0];
926     }
927
928     /**
929      * Splits apart the policy name and version from a policy file path
930      *
931      * @param originalPolicyName: a policy file name ex: Config_policy.2.xml
932      * @return An array [0]: The policy name, [1]: the policy version, as a string
933      */
934     private String[] getPolicyNameAndVersionFromPolicyFileName(String originalPolicyName) throws PolicyDBException {
935         String policyName = originalPolicyName;
936         String[] nameAndVersion = new String[2];
937         try {
938             policyName = removeFileExtension(policyName);
939             nameAndVersion[0] = policyName.substring(0, policyName.lastIndexOf('.'));
940             if (isNullOrEmpty(nameAndVersion[0])) {
941                 throw new PolicyDBException();
942             }
943         } catch (Exception e) {
944             nameAndVersion[0] = originalPolicyName;
945             logger.debug(e);
946         }
947         try {
948             nameAndVersion[1] = policyName.substring(policyName.lastIndexOf('.') + 1);
949             if (isNullOrEmpty(nameAndVersion[1])) {
950                 throw new PolicyDBException();
951             }
952         } catch (Exception e) {
953             nameAndVersion[1] = "1";
954             logger.debug(e);
955         }
956         return nameAndVersion;
957     }
958
959     private void handleIncomingPdpChange(String pdpId, PolicyDBDaoTransaction transaction) throws PAPException {
960         // get pdp
961         long pdpIdLong = -1;
962         try {
963             pdpIdLong = Long.parseLong(pdpId);
964         } catch (NumberFormatException e) {
965             throw new IllegalArgumentException("pdpId " + pdpId + " cannot be parsed into a long");
966         }
967         PdpEntity pdpRecord = null;
968         try {
969             pdpRecord = transaction.getPdp(pdpIdLong);
970         } catch (Exception e) {
971             PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
972                     "Caught Exception trying to get pdp record with transaction.getPdp(" + pdpIdLong + ");");
973             throw new PAPException("Could not get local pdp " + pdpIdLong);
974         }
975         if (pdpRecord == null) {
976             throw new PersistenceException("The pdpRecord returned is null");
977         }
978         PDP localPdp = null;
979         try {
980             localPdp = papEngine.getPDP(pdpRecord.getPdpId());
981         } catch (PAPException e) {
982             logger.warn("Caught PAPException trying to get local pdp  with papEngine.getPDP(" + pdpId + ");", e);
983         }
984         if (localPdp != null && pdpRecord.isDeleted()) {
985             try {
986                 papEngine.removePDP((OnapPDP) localPdp);
987             } catch (PAPException e) {
988                 PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
989                         "Caught PAPException trying to get remove pdp with papEngine.removePDP(" + localPdp + ");");
990                 throw new PAPException("Could not remove pdp " + pdpId);
991             }
992         } else if (localPdp == null) {
993             // add new pdp
994             // get group
995             OnapPDPGroup localGroup = null;
996             try {
997                 localGroup = papEngine.getGroup(pdpRecord.getGroup().getGroupId());
998             } catch (PAPException e1) {
999                 PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e1, policyDBDaoVar,
1000                         "Caught PAPException trying to get local group to add pdp to with papEngine.getGroup"
1001                                 + "(pdpRecord.getGroup().getGroupId());");
1002                 throw new PAPException("Could not get local group");
1003             }
1004             try {
1005                 papEngine.newPDP(pdpRecord.getPdpId(), localGroup, pdpRecord.getPdpName(), pdpRecord.getDescription(),
1006                         pdpRecord.getJmxPort());
1007             } catch (NullPointerException | PAPException e) {
1008                 PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
1009                         "Caught PAPException trying to create pdp with papEngine.newPDP(" + pdpRecord.getPdpId() + ", "
1010                                 + localGroup + ", " + pdpRecord.getPdpName() + ", " + pdpRecord.getDescription() + ", "
1011                                 + pdpRecord.getJmxPort() + ");");
1012                 throw new PAPException("Could not create pdp " + pdpRecord);
1013             }
1014         } else {
1015             boolean needToUpdate = false;
1016             if (!stringEquals(localPdp.getId(), pdpRecord.getPdpId())
1017                     || !stringEquals(localPdp.getName(), pdpRecord.getPdpName())) {
1018                 // again, we don't want to change the id, the papEngine will do this
1019                 localPdp.setName(pdpRecord.getPdpName());
1020                 needToUpdate = true;
1021             }
1022             if (!stringEquals(localPdp.getDescription(), pdpRecord.getDescription())) {
1023                 localPdp.setDescription(pdpRecord.getDescription());
1024                 needToUpdate = true;
1025             }
1026             String localPdpGroupId = null;
1027             try {
1028                 localPdpGroupId = papEngine.getPDPGroup((OnapPDP) localPdp).getId();
1029             } catch (PAPException e) {
1030                 // could be null or something, just warn at this point
1031                 logger.warn("Caught PAPException trying to get id of local group that pdp is in with localPdpGroupId = "
1032                         + "papEngine.getPDPGroup(localPdp).getId();", e);
1033             }
1034             if (!stringEquals(localPdpGroupId, pdpRecord.getGroup().getGroupId())) {
1035                 OnapPDPGroup newPdpGroup = null;
1036                 try {
1037                     newPdpGroup = papEngine.getGroup(pdpRecord.getGroup().getGroupId());
1038                 } catch (PAPException e) {
1039                     // ok, now we have an issue. Time to stop things
1040                     PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
1041                             "Caught PAPException trying to get id of local group to move pdp to with papEngine"
1042                                     + ".getGroup(pdpRecord.getGroup().getGroupId());");
1043                     throw new PAPException("Could not get local group");
1044                 }
1045                 try {
1046                     papEngine.movePDP((OnapPDP) localPdp, newPdpGroup);
1047                 } catch (PAPException e) {
1048                     PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
1049                             "Caught PAPException trying to move pdp with papEngine.movePDP(localPdp, newPdpGroup);");
1050                     throw new PAPException("Could not move pdp " + localPdp);
1051                 }
1052             }
1053             if (((PdpEntity) localPdp).getJmxPort() != pdpRecord.getJmxPort()) {
1054                 ((PdpEntity) localPdp).setJmxPort(pdpRecord.getJmxPort());
1055                 needToUpdate = true;
1056             }
1057             if (needToUpdate) {
1058                 try {
1059                     papEngine.updatePDP((OnapPDP) localPdp);
1060                 } catch (PAPException e) {
1061                     PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
1062                             "Caught PAPException trying to update pdp with papEngine.updatePdp(" + localPdp + ");");
1063                     throw new PAPException("Could not update pdp " + localPdp);
1064                 }
1065             }
1066         }
1067         // compare to local situation
1068         // call command to update
1069     }
1070
1071     private void handleIncomingPolicyChange(String policyId) {
1072         String policyName = null;
1073         EntityManager em = emf.createEntityManager();
1074         Query getPolicyEntityQuery = em.createNamedQuery("PolicyEntity.FindById");
1075         getPolicyEntityQuery.setParameter("id", Long.valueOf(policyId));
1076
1077         @SuppressWarnings("unchecked")
1078         List<PolicyEntity> policies = getPolicyEntityQuery.getResultList();
1079         PolicyEntity policy = null;
1080         if (!policies.isEmpty()) {
1081             policy = policies.get(0);
1082         }
1083         String action = "unknown action";
1084         try {
1085             if (policy != null) {
1086                 policyName = policy.getPolicyName();
1087                 logger.info("Deleting old Policy Config File for " + policy.getPolicyName());
1088                 action = "delete";
1089                 Path subFile = null;
1090
1091                 if (policy.getConfigurationData() != null) {
1092                     subFile = getPolicySubFile(policy.getConfigurationData().getConfigurationName(), config);
1093                 } else if (policy.getActionBodyEntity() != null) {
1094                     subFile = getPolicySubFile(policy.getActionBodyEntity().getActionBodyName(), action);
1095                 }
1096
1097                 if (subFile != null) {
1098                     Files.deleteIfExists(subFile);
1099                 }
1100                 if (policy.getConfigurationData() != null) {
1101                     writePolicySubFile(policy, config);
1102                 } else if (policy.getActionBodyEntity() != null) {
1103                     writePolicySubFile(policy, action);
1104                 }
1105             }
1106         } catch (IOException e1) {
1107             PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e1, policyDBDaoVar,
1108                     "Error occurred while performing [" + action + "] of Policy File: " + policyName);
1109         }
1110     }
1111
1112     private String getPdpPolicyName(String name, String scope) {
1113         String finalName = "";
1114         finalName += scope;
1115         finalName += ".";
1116         finalName += removeFileExtension(name);
1117         finalName += ".xml";
1118         return finalName;
1119     }
1120
1121     private String removeFileExtension(String fileName) {
1122         return fileName.substring(0, fileName.lastIndexOf('.'));
1123     }
1124
1125     private Path getPolicySubFile(String inputFileName, String subFileType) {
1126         String filename = inputFileName;
1127         logger.info("getPolicySubFile(" + filename + ", " + subFileType + ")");
1128         Path filePath = Paths.get(XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_WEBAPPS), subFileType);
1129         File file = null;
1130
1131         filename = FilenameUtils.removeExtension(filename);
1132
1133         for (File tmpFile : filePath.toFile().listFiles()) {
1134             if (FilenameUtils.removeExtension(tmpFile.getName()).equals(filename)) {
1135                 file = tmpFile;
1136             }
1137         }
1138
1139         Path finalPath = null;
1140         if (file != null) {
1141             finalPath = Paths.get(file.getAbsolutePath());
1142         }
1143
1144         logger.info("end of getPolicySubFile: " + finalPath);
1145         return finalPath;
1146     }
1147
1148     private boolean writePolicySubFile(PolicyEntity policy, String policyType) {
1149         logger.info("writePolicySubFile with policyName[" + policy.getPolicyName() + "] and policyType[" + policyType
1150                 + "]");
1151         String type = null;
1152         String subTypeName = null;
1153         String subTypeBody = null;
1154         if (config.equalsIgnoreCase(policyType)) {
1155             type = config;
1156             subTypeName = FilenameUtils.removeExtension(policy.getConfigurationData().getConfigurationName());
1157             subTypeBody = policy.getConfigurationData().getConfigBody();
1158
1159             String configType = policy.getConfigurationData().getConfigType();
1160
1161             if (configType != null) {
1162                 if (configType.equals(JSON_CONFIG)) {
1163                     subTypeName = subTypeName + ".json";
1164                 }
1165                 if (configType.equals(XML_CONFIG)) {
1166                     subTypeName = subTypeName + ".xml";
1167                 }
1168                 if (configType.equals(PROPERTIES_CONFIG)) {
1169                     subTypeName = subTypeName + ".properties";
1170                 }
1171                 if (configType.equals(OTHER_CONFIG)) {
1172                     subTypeName = subTypeName + ".txt";
1173                 }
1174             }
1175         } else if (action.equalsIgnoreCase(policyType)) {
1176             type = action;
1177             subTypeName = policy.getActionBodyEntity().getActionBodyName();
1178             subTypeBody = policy.getActionBodyEntity().getActionBody();
1179         }
1180         Path filePath = Paths.get(XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_WEBAPPS).toString(), type);
1181
1182         if (subTypeBody == null) {
1183             subTypeBody = "";
1184         }
1185         boolean success = false;
1186         try {
1187             Files.deleteIfExists(Paths.get(filePath.toString(), subTypeName));
1188             File file = Paths.get(filePath.toString(), subTypeName).toFile();
1189             boolean value = file.createNewFile();
1190             logger.debug("New file created successfully" + value);
1191             try (FileWriter fileWriter = new FileWriter(file, false)) {
1192                 // false to overwrite
1193                 fileWriter.write(subTypeBody);
1194                 fileWriter.close();
1195                 success = true;
1196             }
1197         } catch (Exception e) {
1198             PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
1199                     "Exception occured while creating Configuration File for Policy : " + policy.getPolicyName());
1200         }
1201         return success;
1202     }
1203
1204     public void auditLocalDatabase(PAPPolicyEngine papEngine2) {
1205         logger.debug("PolicyDBDao.auditLocalDatabase() is called");
1206         try {
1207             deleteAllGroupTables();
1208             auditGroups(papEngine2);
1209         } catch (Exception e) {
1210             PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar, "auditLocalDatabase() error");
1211             logger.error("Exception Occured" + e);
1212         }
1213     }
1214
1215
1216     public StdPDPGroup auditLocalFileSystem(StdPDPGroup group) {
1217
1218         logger.info("Starting Local File System group audit");
1219         EntityManager em = emf.createEntityManager();
1220         em.getTransaction().begin();
1221
1222         StdPDPGroup updatedGroup = null;
1223         try {
1224             Query groupQuery = em.createQuery(groupEntitySelectQuery);
1225             groupQuery.setParameter(groupIdVar, group.getId());
1226             groupQuery.setParameter(deletedVar, false);
1227             List<?> groupQueryList = groupQuery.getResultList();
1228             if (groupQueryList != null && !groupQueryList.isEmpty()) {
1229                 GroupEntity dbgroup = (GroupEntity) groupQueryList.get(0);
1230                 updatedGroup = synchronizeGroupPoliciesInFileSystem(group, dbgroup);
1231                 logger.info("Group was updated during file system audit: " + updatedGroup.toString());
1232             }
1233         } catch (PAPException | PolicyDBException e) {
1234             logger.error(e);
1235         } catch (Exception e) {
1236             logger.error(e);
1237             PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
1238                     "Caught Exception trying to check if group exists groupQuery.getResultList()");
1239             throw new PersistenceException("Query failed trying to check if group " + group.getId() + " exists");
1240         }
1241
1242         em.getTransaction().commit();
1243         em.close();
1244
1245         return updatedGroup;
1246
1247     }
1248
1249     public void deleteAllGroupTables() {
1250         logger.debug("PolicyDBDao.deleteAllGroupTables() called");
1251         EntityManager em = emf.createEntityManager();
1252         em.getTransaction().begin();
1253
1254         Query deletePdpEntityEntityTableUpdate = em.createNamedQuery("PdpEntity.deleteAll");
1255         deletePdpEntityEntityTableUpdate.executeUpdate();
1256
1257         Query deleteGroupEntityTableUpdate = em.createNamedQuery("GroupEntity.deleteAll");
1258         deleteGroupEntityTableUpdate.executeUpdate();
1259
1260         em.getTransaction().commit();
1261         em.close();
1262     }
1263
1264     @SuppressWarnings("unchecked")
1265     public void auditGroups(PAPPolicyEngine papEngine2) {
1266         logger.debug("PolicyDBDao.auditGroups() called");
1267
1268         EntityManager em = emf.createEntityManager();
1269         em.getTransaction().begin();
1270         final String AUDIT_STR = "Audit";
1271         try {
1272
1273             Set<OnapPDPGroup> groups = papEngine2.getOnapPDPGroups();
1274
1275             for (OnapPDPGroup grp : groups) {
1276                 try {
1277                     GroupEntity groupEntity = new GroupEntity();
1278                     em.persist(groupEntity);
1279                     groupEntity.setGroupName(grp.getName());
1280                     groupEntity.setDescription(grp.getDescription());
1281                     groupEntity.setDefaultGroup(grp.isDefaultGroup());
1282                     groupEntity.setCreatedBy(AUDIT_STR);
1283                     groupEntity.setGroupId(createNewPDPGroupId(grp.getId()));
1284                     groupEntity.setModifiedBy(AUDIT_STR);
1285                     Set<OnapPDP> pdps = grp.getOnapPdps();
1286
1287                     for (OnapPDP pdp : pdps) {
1288                         PdpEntity pdpEntity = new PdpEntity();
1289                         em.persist(pdpEntity);
1290                         pdpEntity.setGroup(groupEntity);
1291                         pdpEntity.setJmxPort(pdp.getJmxPort());
1292                         pdpEntity.setPdpId(pdp.getId());
1293                         pdpEntity.setPdpName(pdp.getName());
1294                         pdpEntity.setModifiedBy(AUDIT_STR);
1295                         pdpEntity.setCreatedBy(AUDIT_STR);
1296
1297                     }
1298
1299                     Set<PDPPolicy> policies = grp.getPolicies();
1300
1301                     for (PDPPolicy policy : policies) {
1302                         try {
1303                             String[] stringArray = getNameScopeAndVersionFromPdpPolicy(policy.getId());
1304                             if (stringArray == null) {
1305                                 throw new IllegalArgumentException(
1306                                         "Invalid input - policyID must contain name, scope and version");
1307                             }
1308                             List<PolicyEntity> policyEntityList;
1309                             Query getPolicyEntitiesQuery = em.createNamedQuery("PolicyEntity.findByNameAndScope");
1310                             getPolicyEntitiesQuery.setParameter("name", stringArray[0]);
1311                             getPolicyEntitiesQuery.setParameter(scope, stringArray[1]);
1312
1313                             policyEntityList = getPolicyEntitiesQuery.getResultList();
1314                             PolicyEntity policyEntity = null;
1315                             if (!policyEntityList.isEmpty()) {
1316                                 policyEntity = policyEntityList.get(0);
1317                             }
1318                             if (policyEntity != null) {
1319                                 groupEntity.addPolicyToGroup(policyEntity);
1320                             }
1321                         } catch (Exception e2) {
1322                             PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e2, policyDBDaoVar,
1323                                     "Exception auditGroups inner catch");
1324                         }
1325                     }
1326                 } catch (Exception e1) {
1327                     PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e1, policyDBDaoVar,
1328                             "Exception auditGroups middle catch");
1329                 }
1330             }
1331         } catch (Exception e) {
1332             em.getTransaction().rollback();
1333             PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar, "Exception auditGroups outer catch");
1334             em.close();
1335             return;
1336         }
1337
1338         em.getTransaction().commit();
1339         em.close();
1340
1341     }
1342
1343     private String getConfigFile(String filename, PolicyRestAdapter policy) {
1344         if (policy == null) {
1345             return getConfigFile(filename, (String) null);
1346         }
1347         return getConfigFile(filename, policy.getConfigType());
1348     }
1349
1350     // copied from ConfigPolicy.java and modified
1351     // Here we are adding the extension for the configurations file based on the
1352     // config type selection for saving.
1353     private String getConfigFile(String inputFilename, String configType) {
1354         String filename = inputFilename;
1355         logger.debug("getConfigFile(String filename, String scope, String configType) as getConfigFile(" + filename
1356                 + ", " + configType + ") called");
1357         filename = FilenameUtils.removeExtension(filename);
1358         String id = configType;
1359
1360         if (id != null) {
1361             if (id.equals(ConfigPolicy.JSON_CONFIG) || id.contains("Firewall")) {
1362                 filename = filename + ".json";
1363             }
1364             if (id.equals(ConfigPolicy.XML_CONFIG)) {
1365                 filename = filename + ".xml";
1366             }
1367             if (id.equals(ConfigPolicy.PROPERTIES_CONFIG)) {
1368                 filename = filename + ".properties";
1369             }
1370             if (id.equals(ConfigPolicy.OTHER_CONFIG)) {
1371                 filename = filename + ".txt";
1372             }
1373         }
1374         return filename;
1375     }
1376
1377     private String[] getNameScopeAndVersionFromPdpPolicy(String fileName) {
1378         String[] splitByDots = fileName.split("\\.");
1379         if (splitByDots.length < 3) {
1380             return null;
1381         }
1382         String policyName = splitByDots[splitByDots.length - 3];
1383         String version = splitByDots[splitByDots.length - 2];
1384         // policy names now include version
1385         String scope = "";
1386         for (int i = 0; i < splitByDots.length - 3; i++) {
1387             scope += ".".concat(splitByDots[i]);
1388         }
1389         // remove the first dot
1390         if (scope.length() > 0) {
1391             scope = scope.substring(1);
1392         }
1393         String[] returnArray = new String[3];
1394         returnArray[0] = policyName + "." + version + ".xml";
1395         returnArray[2] = version;
1396         returnArray[1] = scope;
1397         return returnArray;
1398     }
1399
1400     public static String createNewPDPGroupId(String name) {
1401         String id = name;
1402         // replace "bad" characters with sequences that will be ok for file names and properties keys.
1403         id = id.replace(" ", "_sp_");
1404         id = id.replace("\t", "_tab_");
1405         id = id.replace("\\", "_bksl_");
1406         id = id.replace("/", "_sl_");
1407         id = id.replace(":", "_col_");
1408         id = id.replace("*", "_ast_");
1409         id = id.replace("?", "_q_");
1410         id = id.replace("\"", "_quo_");
1411         id = id.replace("<", "_lt_");
1412         id = id.replace(">", "_gt_");
1413         id = id.replace("|", "_bar_");
1414         id = id.replace("=", "_eq_");
1415         id = id.replace(",", "_com_");
1416         id = id.replace(";", "_scom_");
1417
1418         return id;
1419     }
1420
1421     /**
1422      * Checks if any of the given strings are empty or null
1423      *
1424      * @param strings One or more Strings (or nulls) to check if they are null or empty
1425      * @return true if one or more of the given strings are empty or null
1426      */
1427     public static boolean isNullOrEmpty(String... strings) {
1428         for (String s : strings) {
1429             if (s == null || "".equals(s)) {
1430                 return true;
1431             }
1432         }
1433         return false;
1434     }
1435
1436
1437     private class PolicyDBDaoTransactionInstance implements PolicyDBDaoTransaction {
1438         private EntityManager em;
1439         private final Object emLock = new Object();
1440         long policyId;
1441         long groupId;
1442         long pdpId;
1443         String newGroupId;
1444         private boolean operationRun = false;
1445         private final Thread transactionTimer;
1446
1447         private PolicyDBDaoTransactionInstance() {
1448             // call the constructor with arguments
1449             this(Integer.parseInt(XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_TRANS_TIMEOUT)),
1450                     Integer.parseInt(XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_TRANS_WAIT)));
1451         }
1452
1453         // timeout is how long the transaction can sit before rolling back
1454         // wait time is how long to wait for the transaction to start before throwing an exception
1455         private PolicyDBDaoTransactionInstance(int transactionTimeout, int transactionWaitTime) {
1456             if (logger.isDebugEnabled()) {
1457                 logger.debug("\n\nPolicyDBDaoTransactionInstance() as PolicyDBDaoTransactionInstance() called:"
1458                         + "\n   transactionTimeout = " + transactionTimeout + "\n   transactionWaitTime = "
1459                         + transactionWaitTime + "\n\n");
1460             }
1461             this.em = emf.createEntityManager();
1462             policyId = -1;
1463             groupId = -1;
1464             pdpId = -1;
1465             newGroupId = null;
1466             synchronized (emLock) {
1467                 try {
1468                     startTransactionSynced(this.em, transactionWaitTime);
1469                 } catch (Exception e) {
1470                     logger.debug(e);
1471                     throw new PersistenceException(
1472                             "Could not lock transaction within " + transactionWaitTime + " milliseconds");
1473                 }
1474             }
1475             class TransactionTimer implements Runnable {
1476
1477                 private int sleepTime;
1478
1479                 public TransactionTimer(int timeout) {
1480                     this.sleepTime = timeout;
1481                 }
1482
1483                 @Override
1484                 public void run() {
1485                     if (logger.isDebugEnabled()) {
1486                         Date date = new java.util.Date();
1487                         logger.debug("\n\nTransactionTimer.run() - SLEEPING: " + "\n   sleepTime (ms) = " + sleepTime
1488                                 + "\n   TimeStamp = " + date.getTime() + "\n\n");
1489                     }
1490                     try {
1491                         Thread.sleep(sleepTime);
1492                     } catch (InterruptedException e) {
1493                         // probably, the transaction was completed, the last thing we want to do is roll back
1494                         if (logger.isDebugEnabled()) {
1495                             Date date = new java.util.Date();
1496                             logger.debug("\n\nTransactionTimer.run() - WAKE Interrupt: " + "\n   TimeStamp = "
1497                                     + date.getTime() + "\n\n");
1498                         }
1499                         Thread.currentThread().interrupt();
1500                         return;
1501                     }
1502                     if (logger.isDebugEnabled()) {
1503                         Date date = new java.util.Date();
1504                         logger.debug("\n\nTransactionTimer.run() - WAKE Timeout: " + "\n   TimeStamp = "
1505                                 + date.getTime() + "\n\n");
1506                     }
1507                     rollbackTransaction();
1508                 }
1509
1510             }
1511
1512             transactionTimer = new Thread(new TransactionTimer(transactionTimeout), "transactionTimerThread");
1513             transactionTimer.start();
1514
1515
1516         }
1517
1518         private void checkBeforeOperationRun() {
1519             checkBeforeOperationRun(false);
1520         }
1521
1522         private void checkBeforeOperationRun(boolean justCheckOpen) {
1523             if (!isTransactionOpen()) {
1524                 PolicyLogger.error("There is no transaction currently open");
1525                 throw new IllegalStateException("There is no transaction currently open");
1526             }
1527             if (operationRun && !justCheckOpen) {
1528                 PolicyLogger.error(
1529                         "An operation has already been performed and the current transaction should be " + "committed");
1530                 throw new IllegalStateException(
1531                         "An operation has already been performed and the current transaction should be committed");
1532             }
1533             operationRun = true;
1534         }
1535
1536         @Override
1537         public void commitTransaction() {
1538             synchronized (emLock) {
1539                 logger.debug("commitTransaction() as commitTransaction() called");
1540                 if (!isTransactionOpen()) {
1541                     logger.warn("There is no open transaction to commit");
1542                     try {
1543                         em.close();
1544                     } catch (Exception e) {
1545                         logger.error("Exception Occured" + e);
1546                     }
1547                     return;
1548                 }
1549                 try {
1550                     em.getTransaction().commit();
1551                 } catch (RollbackException e) {
1552                     PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
1553                             "Caught RollbackException on em.getTransaction().commit()");
1554                     throw new PersistenceException("The commit failed. Message:\n" + e.getMessage());
1555                 }
1556                 em.close();
1557                 // need to revisit
1558                 if (policyId >= 0) {
1559                     if (newGroupId != null) {
1560                         try {
1561                             notifyOthers(policyId, POLICY_NOTIFICATION, newGroupId);
1562                         } catch (Exception e) {
1563                             PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
1564                                     "Caught Exception on notifyOthers(" + policyId + "," + POLICY_NOTIFICATION + ","
1565                                             + newGroupId + ")");
1566                         }
1567                     } else {
1568                         try {
1569                             notifyOthers(policyId, POLICY_NOTIFICATION);
1570                         } catch (Exception e) {
1571                             PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
1572                                     "Caught Exception on notifyOthers(" + policyId + "," + POLICY_NOTIFICATION + ")");
1573                         }
1574                     }
1575                 }
1576                 if (groupId >= 0) {
1577                     // we don't want commit to fail just because this does
1578                     if (newGroupId != null) {
1579                         try {
1580                             notifyOthers(groupId, GROUP_NOTIFICATION, newGroupId);
1581                         } catch (Exception e) {
1582                             PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
1583                                     "Caught Exception on notifyOthers(" + groupId + "," + GROUP_NOTIFICATION + ","
1584                                             + newGroupId + ")");
1585                         }
1586                     } else {
1587                         try {
1588                             notifyOthers(groupId, GROUP_NOTIFICATION);
1589                         } catch (Exception e) {
1590                             PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
1591                                     "Caught Exception on notifyOthers(" + groupId + "," + GROUP_NOTIFICATION + ")");
1592                         }
1593                     }
1594                 }
1595                 if (pdpId >= 0) {
1596                     // we don't want commit to fail just because this does
1597                     try {
1598                         notifyOthers(pdpId, PDP_NOTIFICATION);
1599                     } catch (Exception e) {
1600                         PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
1601                                 "Caught Exception on notifyOthers(" + pdpId + "," + PDP_NOTIFICATION + ")");
1602                     }
1603                 }
1604             }
1605             if (transactionTimer != null) {
1606                 transactionTimer.interrupt();
1607             }
1608         }
1609
1610         @Override
1611         public void rollbackTransaction() {
1612             logger.debug("rollbackTransaction() as rollbackTransaction() called");
1613             synchronized (emLock) {
1614                 if (isTransactionOpen()) {
1615
1616                     try {
1617                         em.getTransaction().rollback();
1618                     } catch (Exception e) {
1619                         PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
1620                                 "Could not rollback transaction");
1621                     }
1622                     try {
1623                         em.close();
1624                     } catch (Exception e) {
1625                         PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
1626                                 "Could not close EntityManager");
1627                     }
1628
1629                 } else {
1630                     try {
1631                         em.close();
1632                     } catch (Exception e) {
1633                         logger.warn("Could not close already closed transaction", e);
1634                     }
1635                 }
1636
1637             }
1638             if (transactionTimer != null) {
1639                 transactionTimer.interrupt();
1640             }
1641         }
1642
1643         private void createPolicy(PolicyRestAdapter policy, String username, String policyScope, String inputPolicyName,
1644                 String policyDataString) {
1645             String policyName = inputPolicyName;
1646             logger.debug(
1647                     "createPolicy(PolicyRestAdapter policy, String username, String policyScope, String policyName, "
1648                             + "String policyDataString) as createPolicy(" + policy + ", " + username + ", "
1649                             + policyScope + ", " + policyName + ", " + policyDataString + ") called");
1650             synchronized (emLock) {
1651                 checkBeforeOperationRun();
1652                 String configName = policyName;
1653                 if (policyName.contains("Config_")) {
1654                     policyName = policyName.replace(".Config_", ":Config_");
1655                 } else if (policyName.contains("Action_")) {
1656                     policyName = policyName.replace(".Action_", ":Action_");
1657                 } else if (policyName.contains("Decision_")) {
1658                     policyName = policyName.replace(".Decision_", ":Decision_");
1659                 }
1660                 policyName = policyName.split(":")[1];
1661                 Query createPolicyQuery = em
1662                         .createQuery("SELECT p FROM PolicyEntity p WHERE p.scope=:scope AND p.policyName=:policyName");
1663                 createPolicyQuery.setParameter(scope, policyScope);
1664                 createPolicyQuery.setParameter("policyName", policyName);
1665                 List<?> createPolicyQueryList = createPolicyQuery.getResultList();
1666                 PolicyEntity newPolicyEntity;
1667                 boolean update;
1668                 if (createPolicyQueryList.isEmpty()) {
1669                     newPolicyEntity = new PolicyEntity();
1670                     update = false;
1671                 } else if (createPolicyQueryList.size() > 1) {
1672                     PolicyLogger
1673                             .error("Somehow, more than one policy with the same scope, name, and deleted status were "
1674                                     + "found in the database");
1675                     throw new PersistenceException(
1676                             "Somehow, more than one policy with the same scope, name, and deleted status were found "
1677                                     + "in the database");
1678                 } else {
1679                     newPolicyEntity = (PolicyEntity) createPolicyQueryList.get(0);
1680                     update = true;
1681                 }
1682
1683                 ActionBodyEntity newActionBodyEntity = null;
1684                 if (policy.getPolicyType().equals(action)) {
1685                     boolean abupdate = false;
1686                     if (newPolicyEntity.getActionBodyEntity() == null) {
1687                         newActionBodyEntity = new ActionBodyEntity();
1688                     } else {
1689                         newActionBodyEntity = em.find(ActionBodyEntity.class,
1690                                 newPolicyEntity.getActionBodyEntity().getActionBodyId());
1691                         abupdate = true;
1692                     }
1693
1694                     if (newActionBodyEntity != null) {
1695                         if (!abupdate) {
1696                             em.persist(newActionBodyEntity);
1697                         }
1698                         // build the file path
1699                         // trim the .xml off the end
1700                         String policyNameClean = FilenameUtils.removeExtension(configName);
1701                         String actionBodyName = policyNameClean + ".json";
1702
1703                         // get the action body
1704                         String actionBodyString = policy.getActionBody();
1705                         if (actionBodyString == null) {
1706                             actionBodyString = "{}";
1707                         }
1708                         newActionBodyEntity.setActionBody(actionBodyString);
1709                         newActionBodyEntity.setActionBodyName(actionBodyName);
1710                         newActionBodyEntity.setModifiedBy("PolicyDBDao.createPolicy()");
1711                         newActionBodyEntity.setDeleted(false);
1712                         if (!abupdate) {
1713                             newActionBodyEntity.setCreatedBy("PolicyDBDao.createPolicy()");
1714                         }
1715                         if (logger.isDebugEnabled()) {
1716                             logger.debug("\nPolicyDBDao.createPolicy" + "\n   newActionBodyEntity.getActionBody() = "
1717                                     + newActionBodyEntity.getActionBody()
1718                                     + "\n   newActionBodyEntity.getActionBodyName() = "
1719                                     + newActionBodyEntity.getActionBodyName()
1720                                     + "\n   newActionBodyEntity.getModifiedBy() = "
1721                                     + newActionBodyEntity.getModifiedBy() + "\n   newActionBodyEntity.getCreatedBy() = "
1722                                     + newActionBodyEntity.getCreatedBy() + "\n   newActionBodyEntity.isDeleted() = "
1723                                     + newActionBodyEntity.isDeleted() + "\n   FLUSHING to DB");
1724                         }
1725                         // push the actionBodyEntity to the DB
1726                         em.flush();
1727                     } else {
1728                         // newActionBodyEntity == null
1729                         // We have a actionBody in the policy but we found no actionBody in the DB
1730                         String msg = "\n\nPolicyDBDao.createPolicy - Incoming Action policy had an "
1731                                 + "actionBody, but it could not be found in the DB for update." + "\n  policyScope = "
1732                                 + policyScope + "\n  policyName = " + policyName + "\n\n";
1733                         PolicyLogger
1734                                 .error("PolicyDBDao.createPolicy - Incoming Action policy had an actionBody, but it "
1735                                         + "could not be found in the DB for update: policyName = " + policyName);
1736                         throw new IllegalArgumentException(msg);
1737                     }
1738                 }
1739
1740                 ConfigurationDataEntity newConfigurationDataEntity;
1741                 if (policy.getPolicyType().equals(config)) {
1742                     boolean configUpdate;
1743                     if (newPolicyEntity.getConfigurationData() == null) {
1744                         newConfigurationDataEntity = new ConfigurationDataEntity();
1745                         configUpdate = false;
1746                     } else {
1747                         newConfigurationDataEntity = em.find(ConfigurationDataEntity.class,
1748                                 newPolicyEntity.getConfigurationData().getConfigurationDataId());
1749                         configUpdate = true;
1750                     }
1751
1752                     if (newConfigurationDataEntity != null) {
1753                         if (!configUpdate) {
1754                             em.persist(newConfigurationDataEntity);
1755                         }
1756                         if (!stringEquals(newConfigurationDataEntity.getConfigurationName(),
1757                                 getConfigFile(configName, policy))) {
1758                             newConfigurationDataEntity.setConfigurationName(getConfigFile(configName, policy));
1759                         }
1760                         if (newConfigurationDataEntity.getConfigType() == null
1761                                 || !newConfigurationDataEntity.getConfigType().equals(policy.getConfigType())) {
1762                             newConfigurationDataEntity.setConfigType(policy.getConfigType());
1763                         }
1764                         if (!configUpdate) {
1765                             newConfigurationDataEntity.setCreatedBy(username);
1766                         }
1767                         if (newConfigurationDataEntity.getModifiedBy() == null
1768                                 || !newConfigurationDataEntity.getModifiedBy().equals(username)) {
1769                             newConfigurationDataEntity.setModifiedBy(username);
1770                         }
1771                         if (newConfigurationDataEntity.getDescription() == null
1772                                 || !newConfigurationDataEntity.getDescription().equals("")) {
1773                             newConfigurationDataEntity.setDescription("");
1774                         }
1775                         if (newConfigurationDataEntity.getConfigBody() == null
1776                                 || newConfigurationDataEntity.getConfigBody().isEmpty()
1777                                 || (!newConfigurationDataEntity.getConfigBody().equals(policy.getConfigBodyData()))) {
1778                             // hopefully one of these won't be null
1779                             if (policy.getConfigBodyData() == null || policy.getConfigBodyData().isEmpty()) {
1780                                 newConfigurationDataEntity.setConfigBody(policy.getJsonBody());
1781                             } else {
1782                                 newConfigurationDataEntity.setConfigBody(policy.getConfigBodyData());
1783                             }
1784                         }
1785                         if (newConfigurationDataEntity.isDeleted()) {
1786                             newConfigurationDataEntity.setDeleted(false);
1787                         }
1788
1789                         em.flush();
1790                     } else {
1791                         // We have a configurationData body in the policy but we found no configurationData body in
1792                         // the DB
1793                         String msg = "\n\nPolicyDBDao.createPolicy - Incoming Config policy had a "
1794                                 + "configurationData body, but it could not be found in the DB for update."
1795                                 + "\n  policyScope = " + policyScope + "\n  policyName = " + policyName + "\n\n";
1796                         PolicyLogger.error("PolicyDBDao.createPolicy - Incoming Config policy had a configurationData "
1797                                 + "body, but it could not be found in the DB for update: policyName = " + policyName);
1798                         throw new IllegalArgumentException(msg);
1799                     }
1800
1801                 } else {
1802                     newConfigurationDataEntity = null;
1803                 }
1804                 if (!update) {
1805                     em.persist(newPolicyEntity);
1806                 }
1807
1808                 policyId = newPolicyEntity.getPolicyId();
1809
1810                 if (!stringEquals(newPolicyEntity.getPolicyName(), policyName)) {
1811                     newPolicyEntity.setPolicyName(policyName);
1812                 }
1813                 if (!stringEquals(newPolicyEntity.getCreatedBy(), username)) {
1814                     newPolicyEntity.setCreatedBy(username);
1815                 }
1816                 if (!stringEquals(newPolicyEntity.getDescription(), policy.getPolicyDescription())) {
1817                     newPolicyEntity.setDescription(policy.getPolicyDescription());
1818                 }
1819                 if (!stringEquals(newPolicyEntity.getModifiedBy(), username)) {
1820                     newPolicyEntity.setModifiedBy(username);
1821                 }
1822                 if (!stringEquals(newPolicyEntity.getPolicyData(), policyDataString)) {
1823                     newPolicyEntity.setPolicyData(policyDataString);
1824                 }
1825                 if (!stringEquals(newPolicyEntity.getScope(), policyScope)) {
1826                     newPolicyEntity.setScope(policyScope);
1827                 }
1828                 if (newPolicyEntity.isDeleted() == true) {
1829                     newPolicyEntity.setDeleted(false);
1830                 }
1831                 newPolicyEntity.setConfigurationData(newConfigurationDataEntity);
1832                 newPolicyEntity.setActionBodyEntity(newActionBodyEntity);
1833
1834                 em.flush();
1835                 this.policyId = newPolicyEntity.getPolicyId();
1836             }
1837         }
1838
1839         @SuppressWarnings("unused")
1840         public PolicyEntity getPolicy(int policyID) {
1841             return getPolicy(policyID, null, null);
1842         }
1843
1844         public PolicyEntity getPolicy(String policyName, String scope) {
1845             return getPolicy(-1, policyName, scope);
1846         }
1847
1848         private PolicyEntity getPolicy(int policyID, String policyName, String scope) {
1849             logger.debug("getPolicy(int policyId, String policyName) as getPolicy(" + policyID + "," + policyName
1850                     + ") called");
1851             if (policyID < 0 && isNullOrEmpty(policyName, scope)) {
1852                 throw new IllegalArgumentException(
1853                         "policyID must be at least 0 or policyName must be not null or blank");
1854             }
1855
1856             synchronized (emLock) {
1857                 checkBeforeOperationRun(true);
1858                 // check if group exists
1859                 String policyId;
1860                 Query policyQuery;
1861                 if (!isNullOrEmpty(policyName, scope)) {
1862                     policyId = policyName;
1863                     policyQuery =
1864                             em.createQuery("SELECT p FROM PolicyEntity p WHERE p.policyName=:name AND p.scope=:scope");
1865                     policyQuery.setParameter("name", policyId);
1866                     policyQuery.setParameter("scope", scope);
1867                 } else {
1868                     policyId = String.valueOf(policyID);
1869                     policyQuery = em.createNamedQuery("PolicyEntity.FindById");
1870                     policyQuery.setParameter("id", policyId);
1871                 }
1872                 List<?> policyQueryList;
1873                 try {
1874                     policyQueryList = policyQuery.getResultList();
1875                 } catch (Exception e) {
1876                     PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
1877                             "Caught Exception trying to get policy with policyQuery.getResultList()");
1878                     throw new PersistenceException("Query failed trying to get policy " + policyId);
1879                 }
1880                 if (policyQueryList.isEmpty()) {
1881                     PolicyLogger.error("Policy does not exist with id " + policyId);
1882                     throw new PersistenceException("Group policy is being added to does not exist with id " + policyId);
1883                 } else if (policyQueryList.size() > 1) {
1884                     PolicyLogger.error(duplicatePolicyId + policyId + foundInDB);
1885                     throw new PersistenceException(duplicatePolicyId + policyId + foundInDB);
1886                 }
1887                 return (PolicyEntity) policyQueryList.get(0);
1888             }
1889         }
1890
1891         @Override
1892         public GroupEntity getGroup(long groupKey) {
1893             logger.debug("getGroup(int groupKey) as getGroup(" + groupKey + ") called");
1894             if (groupKey < 0) {
1895                 throw new IllegalArgumentException("groupKey must be at least 0");
1896             }
1897             synchronized (emLock) {
1898                 checkBeforeOperationRun(true);
1899                 // check if group exists
1900                 Query groupQuery = em.createQuery("SELECT g FROM GroupEntity g WHERE g.groupKey=:groupKey");
1901                 groupQuery.setParameter("groupKey", groupKey);
1902                 List<?> groupQueryList;
1903                 try {
1904                     groupQueryList = groupQuery.getResultList();
1905                 } catch (Exception e) {
1906                     PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
1907                             "Caught Exception trying to get group with groupQuery.getResultList()");
1908                     throw new PersistenceException(queryFailedToGetGroup + groupKey);
1909                 }
1910                 if (groupQueryList.isEmpty()) {
1911                     PolicyLogger.error("Group does not exist with groupKey " + groupKey);
1912                     throw new PersistenceException("Group does not exist with groupKey " + groupKey);
1913                 } else if (groupQueryList.size() > 1) {
1914                     PolicyLogger.error("Somehow, more than one group with the groupKey " + groupKey + foundInDB);
1915                     throw new PersistenceException(
1916                             "Somehow, more than one group with the groupKey " + groupKey + foundInDB);
1917                 }
1918                 return (GroupEntity) groupQueryList.get(0);
1919             }
1920         }
1921
1922         @Override
1923         public GroupEntity getGroup(String groupId) {
1924             logger.debug("getGroup(String groupId) as getGroup(" + groupId + ") called");
1925             if (isNullOrEmpty(groupId)) {
1926                 throw new IllegalArgumentException("groupId must not be null or empty");
1927             }
1928             synchronized (emLock) {
1929                 checkBeforeOperationRun(true);
1930                 // check if group exists
1931                 Query groupQuery = em.createQuery("SELECT g FROM GroupEntity g WHERE g.groupId=:groupId");
1932                 groupQuery.setParameter(groupIdVar, groupId);
1933                 List<?> groupQueryList;
1934                 try {
1935                     groupQueryList = groupQuery.getResultList();
1936                 } catch (Exception e) {
1937                     PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
1938                             "Caught Exception trying to get group with groupQuery.getResultList()");
1939                     throw new PersistenceException(queryFailedToGetGroup + groupId);
1940                 }
1941                 if (groupQueryList.isEmpty()) {
1942                     PolicyLogger.error("Group does not exist with id " + groupId);
1943                     throw new PersistenceException("Group does not exist with id " + groupId);
1944                 } else if (groupQueryList.size() > 1) {
1945                     PolicyLogger.error(duplicateGroupId + groupId + foundInDB);
1946                     throw new PersistenceException(duplicateGroupId + groupId + foundInDB);
1947                 }
1948                 return (GroupEntity) groupQueryList.get(0);
1949             }
1950         }
1951
1952         @Override
1953         public List<?> getPdpsInGroup(long groupKey) {
1954             logger.debug("getPdpsInGroup(int groupKey) as getPdpsInGroup(" + groupKey + ") called");
1955             if (groupKey < 0) {
1956                 throw new IllegalArgumentException("groupId must not be < 0");
1957             }
1958             synchronized (emLock) {
1959                 checkBeforeOperationRun(true);
1960                 Query pdpsQuery = em.createQuery("SELECT p FROM PdpEntity p WHERE p.groupEntity=:group");
1961                 pdpsQuery.setParameter("group", getGroup(groupKey));
1962                 return pdpsQuery.getResultList();
1963             }
1964         }
1965
1966         @Override
1967         public PdpEntity getPdp(long pdpKey) {
1968             logger.debug("getPdp(int pdpKey) as getPdp(" + pdpKey + ") called");
1969             if (pdpKey < 0) {
1970                 throw new IllegalArgumentException("pdpKey must be at least 0");
1971             }
1972             synchronized (emLock) {
1973                 checkBeforeOperationRun(true);
1974                 // check if group exists
1975                 Query pdpQuery = em.createQuery("SELECT p FROM PdpEntity p WHERE p.pdpKey=:pdpKey");
1976                 pdpQuery.setParameter("pdpKey", pdpKey);
1977                 List<?> pdpQueryList;
1978                 try {
1979                     pdpQueryList = pdpQuery.getResultList();
1980                 } catch (Exception e) {
1981                     PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
1982                             "Caught Exception trying to get pdp with pdpQuery.getResultList()");
1983                     throw new PersistenceException("Query failed trying to get pdp " + pdpKey);
1984                 }
1985                 if (pdpQueryList.isEmpty()) {
1986                     PolicyLogger.error("Pdp does not exist with pdpKey " + pdpKey);
1987                     throw new PersistenceException("Pdp does not exist with pdpKey " + pdpKey);
1988                 } else if (pdpQueryList.size() > 1) {
1989                     PolicyLogger.error("Somehow, more than one pdp with the pdpKey " + pdpKey + foundInDB);
1990                     throw new PersistenceException("Somehow, more than one pdp with the pdpKey " + pdpKey + foundInDB);
1991                 }
1992                 return (PdpEntity) pdpQueryList.get(0);
1993             }
1994         }
1995
1996         @Override
1997         public boolean isTransactionOpen() {
1998             logger.debug("isTransactionOpen() as isTransactionOpen() called");
1999             synchronized (emLock) {
2000                 return em.isOpen() && em.getTransaction().isActive();
2001             }
2002         }
2003
2004         private String processConfigPath(String inputConfigPath) {
2005             String configPath = inputConfigPath;
2006             String webappsPath = XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_WEBAPPS);
2007             if (webappsPath == null) {
2008                 logger.error("Webapps property does not exist");
2009                 throw new IllegalArgumentException("Webapps property does not exist");
2010             }
2011             configPath = configPath.replace("$URL", webappsPath);
2012             // make sure the correct slashes are in
2013             try {
2014                 configPath = Paths.get(configPath).toString();
2015             } catch (InvalidPathException e) {
2016                 logger.error("Invalid config path: " + configPath, e);
2017                 throw new IllegalArgumentException("Invalid config path: " + configPath);
2018             }
2019             return configPath;
2020         }
2021
2022         private String readConfigFile(String configPath) {
2023             String configDataString = null;
2024             try (InputStream configContentStream = new FileInputStream(configPath);) {
2025                 configDataString = IOUtils.toString(configContentStream);
2026             } catch (FileNotFoundException e) {
2027                 logger.error("Caught FileNotFoundException on new FileInputStream(" + configPath + ")", e);
2028                 throw new IllegalArgumentException("The config file path does not exist");
2029             } catch (IOException e2) {
2030                 logger.error("Caught IOException on newIOUtils.toString(configContentStream)", e2);
2031                 throw new IllegalArgumentException("The config file path cannot be read");
2032             }
2033             if (configDataString == null) {
2034                 throw new IllegalArgumentException("The config file path cannot be read");
2035             }
2036             return configDataString;
2037         }
2038
2039         @Override
2040         public void createPolicy(Policy policy, String username) {
2041
2042             try {
2043                 logger.debug("createPolicy(PolicyRestAdapter policy, String username) as createPolicy(" + policy + ","
2044                         + username + ") called");
2045                 String policyScope = policy.policyAdapter.getDomainDir().replace(File.separator, ".");
2046                 // Does not need to be XACMLPolicyWriterWithPapNotify since it is already in the PAP
2047                 // and this transaction is intercepted up stream.
2048
2049                 String policyDataString = getPolicyDataString(policy);
2050                 if (isJunit) {
2051                     // Using parentPath object to set policy data.
2052                     policyDataString = policy.policyAdapter.getParentPath();
2053                 }
2054                 String configPath = "";
2055                 if (policy.policyAdapter.getPolicyType().equalsIgnoreCase(config)) {
2056                     configPath = evaluateXPath(
2057                             "/Policy/Rule/AdviceExpressions/AdviceExpression[contains(@AdviceId,'ID')"
2058                                     + "]/AttributeAssignmentExpression[@AttributeId='URLID']/AttributeValue/text()",
2059                             policyDataString);
2060                 } else if (policy.policyAdapter.getPolicyType().equalsIgnoreCase(action)) {
2061                     configPath = evaluateXPath(
2062                             "/Policy/Rule/ObligationExpressions/ObligationExpression[contains(@ObligationId, "
2063                                     + policy.policyAdapter.getActionAttribute()
2064                                     + ")]/AttributeAssignmentExpression[@AttributeId='body']/AttributeValue/text()",
2065                             policyDataString);
2066                 }
2067
2068                 String prefix = null;
2069                 if (policy.policyAdapter.getPolicyType().equalsIgnoreCase(config)) {
2070
2071                     prefix = configPath.substring(
2072                             configPath.indexOf(policyScope + ".") + policyScope.concat(".").length(),
2073                             configPath.lastIndexOf(policy.policyAdapter.getPolicyName()));
2074                     if (isNullOrEmpty(policy.policyAdapter.getConfigBodyData())) {
2075                         policy.policyAdapter.setConfigBodyData(getConfigData(configPath));
2076                     }
2077                 } else if (action.equalsIgnoreCase(policy.policyAdapter.getPolicyType())) {
2078                     prefix = "Action_";
2079                 } else if ("Decision".equalsIgnoreCase(policy.policyAdapter.getPolicyType())) {
2080                     prefix = "Decision_";
2081                 }
2082
2083                 if (!(policy.policyAdapter.getData() instanceof PolicyType)
2084                         && !(policy.policyAdapter.getData() instanceof PolicySetType)) {
2085                     PolicyLogger.error("The data field is not an instance of PolicyType or PolicySetType");
2086                     throw new IllegalArgumentException(
2087                             "The data field is not an instance of PolicyType or PolicySetType");
2088                 }
2089                 String finalName = policyScope + "." + prefix + policy.policyAdapter.getPolicyName() + "."
2090                         + policy.policyAdapter.getHighestVersion() + ".xml";
2091                 if (policy.policyAdapter.getConfigType() == null || "".equals(policy.policyAdapter.getConfigType())) {
2092                     // get the config file extension
2093                     String ext = "";
2094                     if (configPath != null && !"".equalsIgnoreCase(configPath)) {
2095                         ext = configPath.substring(configPath.lastIndexOf('.'), configPath.length());;
2096                     }
2097
2098                     if (ext.contains("txt")) {
2099                         policy.policyAdapter.setConfigType(OTHER_CONFIG);
2100                     } else if (ext.contains("json")) {
2101                         policy.policyAdapter.setConfigType(JSON_CONFIG);
2102                     } else if (ext.contains("xml")) {
2103                         policy.policyAdapter.setConfigType(XML_CONFIG);
2104                     } else if (ext.contains("properties")) {
2105                         policy.policyAdapter.setConfigType(PROPERTIES_CONFIG);
2106                     } else {
2107                         if (policy.policyAdapter.getPolicyType().equalsIgnoreCase(action)) {
2108                             policy.policyAdapter.setConfigType(JSON_CONFIG);
2109                         }
2110                     }
2111                 }
2112                 createPolicy(policy.policyAdapter, username, policyScope, finalName, policyDataString);
2113             } catch (Exception e) {
2114                 logger.error("Could not create policy for " + policy, e);
2115                 throw e;
2116             }
2117         }
2118
2119         private String getConfigData(String configPath) {
2120             String configData = "";
2121             try {
2122                 configData = getConfigPath(configPath);
2123             } catch (Exception e) {
2124                 logger.error("Could not read config body data for " + configPath, e);
2125             }
2126             return configData;
2127         }
2128
2129         private String getConfigPath(String configPath) {
2130             try {
2131                 String newConfigPath = processConfigPath(configPath);
2132                 return readConfigFile(newConfigPath);
2133             } catch (IllegalArgumentException e2) {
2134                 logger.error("Could not process config path: " + configPath, e2);
2135             }
2136             return "";
2137         }
2138
2139
2140         /**
2141          * @param policy input policy Object.
2142          * @return read the stream and return policy xml data.
2143          */
2144         private String getPolicyDataString(Policy policy) {
2145             try (InputStream policyXmlStream =
2146                     XACMLPolicyWriter.getXmlAsInputStream(policy.getCorrectPolicyDataObject())) {
2147                 return IOUtils.toString(policyXmlStream);
2148             } catch (IOException e) {
2149                 PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
2150                         "Caught IOException on reading Policy Data.");
2151                 throw new IllegalArgumentException("Cannot parse the policy xml from the PolicyRestAdapter.");
2152             }
2153         }
2154
2155         @Override
2156         public void close() {
2157             synchronized (emLock) {
2158                 if (em.isOpen()) {
2159                     if (em.getTransaction().isActive()) {
2160                         em.getTransaction().rollback();
2161                     }
2162                     em.close();
2163                 }
2164                 if (transactionTimer != null) {
2165                     transactionTimer.interrupt();
2166                 }
2167             }
2168         }
2169
2170         @Override
2171         public void createGroup(String groupId, String groupName, String inputGroupDescription, String username) {
2172             String groupDescription = inputGroupDescription;
2173             logger.debug("deletePolicy(String policyToDeletes) as createGroup(" + groupId + ", " + groupName + ", "
2174                     + groupDescription + ") called");
2175             if (isNullOrEmpty(groupId, groupName, username)) {
2176                 throw new IllegalArgumentException("groupId, groupName, and username must not be null or empty");
2177             }
2178             if (groupDescription == null) {
2179                 groupDescription = "";
2180             }
2181
2182             synchronized (emLock) {
2183                 checkBeforeOperationRun();
2184                 Query checkGroupQuery = em.createQuery(groupEntitySelectQuery);
2185                 checkGroupQuery.setParameter(groupIdVar, groupId);
2186                 checkGroupQuery.setParameter(deletedVar, false);
2187                 List<?> checkGroupQueryList;
2188                 try {
2189                     checkGroupQueryList = checkGroupQuery.getResultList();
2190                 } catch (Exception e) {
2191                     PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
2192                             "Caught Exception on checkGroupQuery.getResultList()");
2193                     throw new PersistenceException(queryFailedToCheckExisting);
2194                 }
2195                 if (!checkGroupQueryList.isEmpty()) {
2196                     PolicyLogger.error("The group being added already exists with id " + groupId);
2197                     throw new PersistenceException("The group being added already exists with id " + groupId);
2198                 }
2199                 GroupEntity newGroup = new GroupEntity();
2200                 em.persist(newGroup);
2201                 newGroup.setCreatedBy(username);
2202                 newGroup.setModifiedBy(username);
2203                 newGroup.setGroupName(groupName);
2204                 newGroup.setGroupId(groupId);
2205                 newGroup.setDescription(groupDescription);
2206
2207                 em.flush();
2208                 this.groupId = newGroup.getGroupKey();
2209             }
2210         }
2211
2212         @Override
2213         public void updateGroup(OnapPDPGroup group, String username) {
2214             logger.info(
2215                     "PolicyDBDao: updateGroup(PDPGroup group) as updateGroup(" + group + "," + username + ") called");
2216             if (group == null) {
2217                 throw new IllegalArgumentException("PDPGroup group must not be null");
2218             }
2219             if (isNullOrEmpty(group.getId(), username)) {
2220                 throw new IllegalArgumentException("group.getId() and username must not be null or empty");
2221             }
2222
2223             synchronized (emLock) {
2224                 checkBeforeOperationRun();
2225                 Query getGroupQuery = em.createQuery(groupEntitySelectQuery);
2226                 getGroupQuery.setParameter(groupIdVar, group.getId());
2227                 getGroupQuery.setParameter(deletedVar, false);
2228                 List<?> getGroupQueryList;
2229                 try {
2230                     getGroupQueryList = getGroupQuery.getResultList();
2231                 } catch (Exception e) {
2232                     PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
2233                             "Caught Exception on getGroupQuery.getResultList()");
2234                     throw new PersistenceException(queryFailedToGetGroup + group.getId() + " for editing");
2235                 }
2236                 if (getGroupQueryList.isEmpty()) {
2237                     PolicyLogger.error("The group cannot be found to update with id " + group.getId());
2238                     throw new PersistenceException("The group cannot be found to update with id " + group.getId());
2239                 } else if (getGroupQueryList.size() > 1) {
2240                     PolicyLogger.error(duplicateGroupId + group.getId() + deletedStatusFound);
2241                     throw new PersistenceException(duplicateGroupId + group.getId() + deletedStatusFound);
2242                 }
2243                 GroupEntity groupToUpdateInDB = (GroupEntity) getGroupQueryList.get(0);
2244                 if (!stringEquals(groupToUpdateInDB.getModifiedBy(), username)) {
2245                     groupToUpdateInDB.setModifiedBy(username);
2246                 }
2247                 if (group.getDescription() != null
2248                         && !stringEquals(group.getDescription(), groupToUpdateInDB.getDescription())) {
2249                     groupToUpdateInDB.setDescription(group.getDescription());
2250                 }
2251                 // let's find out what policies have been deleted
2252                 StdPDPGroup oldGroup = null;
2253                 try {
2254                     oldGroup = (StdPDPGroup) papEngine.getGroup(group.getId());
2255                 } catch (PAPException e1) {
2256                     PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e1, policyDBDaoVar,
2257                             "We cannot get the group from the papEngine to delete policies");
2258                 }
2259                 if (oldGroup == null) {
2260                     PolicyLogger.error("We cannot get the group from the papEngine to delete policies");
2261                 } else {
2262                     Set<String> newPolicySet = new HashSet<>(group.getPolicies().size());
2263                     // a multiple of n runtime is faster than n^2, so I am using a hashset to do the comparison
2264                     for (PDPPolicy pol : group.getPolicies()) {
2265                         newPolicySet.add(pol.getId());
2266                     }
2267                     for (PDPPolicy pol : oldGroup.getPolicies()) {
2268                         // should be fast since getPolicies uses a HashSet in StdPDPGroup
2269                         if (!newPolicySet.contains(pol.getId())) {
2270                             String[] scopeAndName = getNameScopeAndVersionFromPdpPolicy(pol.getId());
2271                             deletePolicyInScope(username, groupToUpdateInDB, pol, scopeAndName);
2272                         }
2273                     }
2274                 }
2275
2276                 if (group.getName() != null && !stringEquals(group.getName(), groupToUpdateInDB.getgroupName())) {
2277                     // we need to check if the new id exists in the database
2278                     String newGroupId = createNewPDPGroupId(group.getName());
2279                     Query checkGroupQuery = em.createQuery(groupEntitySelectQuery);
2280                     checkGroupQuery.setParameter(groupIdVar, newGroupId);
2281                     checkGroupQuery.setParameter(deletedVar, false);
2282                     List<?> checkGroupQueryList;
2283                     try {
2284                         checkGroupQueryList = checkGroupQuery.getResultList();
2285                     } catch (Exception e) {
2286                         PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
2287                                 "Caught Exception on checkGroupQuery.getResultList()");
2288                         throw new PersistenceException(queryFailedToCheckExisting);
2289                     }
2290                     if (!checkGroupQueryList.isEmpty()) {
2291                         PolicyLogger.error("The new group name already exists, group id " + newGroupId);
2292                         throw new PersistenceException("The new group name already exists, group id " + newGroupId);
2293                     }
2294                     groupToUpdateInDB.setGroupId(newGroupId);
2295                     groupToUpdateInDB.setGroupName(group.getName());
2296                     this.newGroupId = group.getId();
2297                 }
2298                 em.flush();
2299                 this.groupId = groupToUpdateInDB.getGroupKey();
2300             }
2301         }
2302
2303         private void deletePolicyInScope(String username, GroupEntity groupToUpdateInDB, PDPPolicy pol,
2304                 String[] scopeAndName) {
2305             PolicyEntity policyToDelete;
2306             if (scopeAndName == null) {
2307                 return;
2308             }
2309             try {
2310                 policyToDelete = getPolicy(scopeAndName[0], scopeAndName[1]);
2311                 if ("XACMLPapServlet.doDelete".equals(username)) {
2312                     Iterator<PolicyEntity> dbPolicyIt = groupToUpdateInDB.getPolicies().iterator();
2313                     String policyName = getPolicyNameAndVersionFromPolicyFileName(policyToDelete.getPolicyName())[0];
2314
2315                     logger.info("PolicyDBDao: delete policy from GroupEntity");
2316                     deletePolicyFromGroupEntity(groupToUpdateInDB, policyToDelete, dbPolicyIt, policyName);
2317                 }
2318             } catch (Exception e) {
2319                 PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
2320                         "Could not get policy to remove: " + pol.getId());
2321                 throw new PersistenceException("Could not get policy to remove: " + pol.getId());
2322             }
2323         }
2324
2325         private void deletePolicyFromGroupEntity(GroupEntity groupToUpdateInDB, PolicyEntity policyToDelete,
2326                 Iterator<PolicyEntity> dbPolicyIt, String policyName) {
2327             try {
2328                 while (dbPolicyIt.hasNext()) {
2329                     PolicyEntity dbpolicy = dbPolicyIt.next();
2330                     if (policyToDelete.getScope().equals(dbpolicy.getScope())
2331                             && getPolicyNameAndVersionFromPolicyFileName(dbpolicy.getPolicyName())[0]
2332                                     .equals(policyName)) {
2333                         dbPolicyIt.remove();
2334
2335                         logger.info("PolicyDBDao: deleting policy from the existing group:\n " + "policyName is "
2336                                 + policyToDelete.getScope() + "." + policyToDelete.getPolicyName() + "\n" + "group is "
2337                                 + groupToUpdateInDB.getGroupId());
2338                     }
2339                 }
2340             } catch (Exception e) {
2341                 logger.debug(e);
2342                 PolicyLogger.error("Could not delete policy with name: " + policyToDelete.getScope() + "."
2343                         + policyToDelete.getPolicyName() + "\n ID: " + policyToDelete.getPolicyId());
2344             }
2345         }
2346
2347         @Override
2348         public void addPdpToGroup(String pdpID, String groupID, String pdpName, String pdpDescription, int pdpJmxPort,
2349                 String username) {
2350             logger.debug("addPdpToGroup(String pdpID, String groupID, String pdpName, String pdpDescription, int "
2351                     + "pdpJmxPort, String username) as addPdpToGroup(" + pdpID + ", " + groupID + ", " + pdpName + ", "
2352                     + pdpDescription + ", " + pdpJmxPort + ", " + username + ") called");
2353             if (isNullOrEmpty(pdpID, groupID, pdpName, username)) {
2354                 throw new IllegalArgumentException("pdpID, groupID, pdpName, and username must not be null or empty");
2355             }
2356             synchronized (emLock) {
2357                 checkBeforeOperationRun();
2358                 Query checkGroupQuery = em.createQuery(groupEntitySelectQuery);
2359                 checkGroupQuery.setParameter(groupIdVar, groupID);
2360                 checkGroupQuery.setParameter(deletedVar, false);
2361                 List<?> checkGroupQueryList;
2362                 try {
2363                     checkGroupQueryList = checkGroupQuery.getResultList();
2364                 } catch (Exception e) {
2365                     PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
2366                             "Caught Exception trying to check for existing group on checkGroupQuery.getResultList()");
2367                     throw new PersistenceException(queryFailedToCheckExisting);
2368                 }
2369                 if (checkGroupQueryList.size() != 1) {
2370                     PolicyLogger.error("The group does not exist");
2371                     throw new PersistenceException("The group does not exist");
2372                 }
2373                 Query checkDuplicateQuery = em.createQuery(pdpEntitySelectQuery);
2374                 checkDuplicateQuery.setParameter(pdpIdVariable, pdpID);
2375                 checkDuplicateQuery.setParameter(deletedVar, false);
2376                 List<?> checkDuplicateList;
2377                 try {
2378                     checkDuplicateList = checkDuplicateQuery.getResultList();
2379                 } catch (Exception e) {
2380                     PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
2381                             "Caught Exception trying to check for duplicate PDP " + pdpID
2382                                     + " on checkDuplicateQuery.getResultList()");
2383                     throw new PersistenceException("Query failed trying to check for duplicate PDP " + pdpID);
2384                 }
2385                 PdpEntity newPdp;
2386                 if (!checkDuplicateList.isEmpty()) {
2387                     logger.warn("PDP already exists with id " + pdpID);
2388                     newPdp = (PdpEntity) checkDuplicateList.get(0);
2389                 } else {
2390                     newPdp = new PdpEntity();
2391                     em.persist(newPdp);
2392                 }
2393
2394                 newPdp.setCreatedBy(username);
2395                 newPdp.setDeleted(false);
2396                 newPdp.setDescription(pdpDescription);
2397                 newPdp.setGroup((GroupEntity) checkGroupQueryList.get(0));
2398                 newPdp.setJmxPort(pdpJmxPort);
2399                 newPdp.setModifiedBy(username);
2400                 newPdp.setPdpId(pdpID);
2401                 newPdp.setPdpName(pdpName);
2402
2403                 em.flush();
2404                 this.pdpId = newPdp.getPdpKey();
2405             }
2406         }
2407
2408
2409         @Override
2410         public void updatePdp(OnapPDP pdp, String username) {
2411             logger.debug("updatePdp(PDP pdp, String username) as updatePdp(" + pdp + "," + username + ") called");
2412             if (pdp == null) {
2413                 throw new IllegalArgumentException("PDP pdp must not be null");
2414             }
2415             if (isNullOrEmpty(pdp.getId(), username)) {
2416                 throw new IllegalArgumentException("pdp.getId() and username must not be null or empty");
2417             }
2418
2419             synchronized (emLock) {
2420                 checkBeforeOperationRun();
2421                 Query getPdpQuery = em.createQuery(pdpEntitySelectQuery);
2422                 getPdpQuery.setParameter(pdpIdVariable, pdp.getId());
2423                 getPdpQuery.setParameter(deletedVar, false);
2424                 List<?> getPdpQueryList;
2425                 try {
2426                     getPdpQueryList = getPdpQuery.getResultList();
2427                 } catch (Exception e) {
2428                     PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
2429                             "Caught Exception on getPdpQuery.getResultList()");
2430                     throw new PersistenceException("Query failed trying to get PDP " + pdp.getId());
2431                 }
2432                 if (getPdpQueryList.isEmpty()) {
2433                     PolicyLogger.error("The pdp cannot be found to update with id " + pdp.getId());
2434                     throw new PersistenceException("The pdp cannot be found to update with id " + pdp.getId());
2435                 } else if (getPdpQueryList.size() > 1) {
2436                     PolicyLogger.error(moreThanOnePDP + pdp.getId() + deletedStatusFound);
2437                     throw new PersistenceException(moreThanOnePDP + pdp.getId() + deletedStatusFound);
2438                 }
2439                 PdpEntity pdpToUpdate = (PdpEntity) getPdpQueryList.get(0);
2440                 if (!stringEquals(pdpToUpdate.getModifiedBy(), username)) {
2441                     pdpToUpdate.setModifiedBy(username);
2442                 }
2443                 if (pdp.getDescription() != null && !stringEquals(pdp.getDescription(), pdpToUpdate.getDescription())) {
2444                     pdpToUpdate.setDescription(pdp.getDescription());
2445                 }
2446                 if (pdp.getName() != null && !stringEquals(pdp.getName(), pdpToUpdate.getPdpName())) {
2447                     pdpToUpdate.setPdpName(pdp.getName());
2448                 }
2449                 if (pdp.getJmxPort() != null && !pdp.getJmxPort().equals(pdpToUpdate.getJmxPort())) {
2450                     pdpToUpdate.setJmxPort(pdp.getJmxPort());
2451                 }
2452
2453                 em.flush();
2454                 this.pdpId = pdpToUpdate.getPdpKey();
2455             }
2456         }
2457
2458         @Override
2459         public void movePdp(OnapPDP pdp, OnapPDPGroup group, String username) {
2460             logger.debug("movePdp(PDP pdp, PDPGroup group, String username) as movePdp(" + pdp + "," + group + ","
2461                     + username + ") called");
2462             if (pdp == null || group == null) {
2463                 throw new IllegalArgumentException("PDP pdp and PDPGroup group must not be null");
2464             }
2465             if (isNullOrEmpty(username, pdp.getId(), group.getId())) {
2466                 throw new IllegalArgumentException(
2467                         "pdp.getId(), group.getId(), and username must not be null or empty");
2468             }
2469
2470             synchronized (emLock) {
2471                 checkBeforeOperationRun();
2472                 // check if pdp exists
2473                 Query getPdpQuery = em.createQuery(pdpEntitySelectQuery);
2474                 getPdpQuery.setParameter(pdpIdVariable, pdp.getId());
2475                 getPdpQuery.setParameter(deletedVar, false);
2476                 List<?> getPdpQueryList;
2477                 try {
2478                     getPdpQueryList = getPdpQuery.getResultList();
2479                 } catch (Exception e) {
2480                     PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
2481                             "Caught Exception on getPdpQuery.getResultList()");
2482                     throw new PersistenceException("Query failed trying to get pdp to move with id " + pdp.getId());
2483                 }
2484                 if (getPdpQueryList.isEmpty()) {
2485                     PolicyLogger.error("The pdp cannot be found to move with id " + pdp.getId());
2486                     throw new PersistenceException("The pdp cannot be found to move with id " + pdp.getId());
2487                 } else if (getPdpQueryList.size() > 1) {
2488                     PolicyLogger.error(moreThanOnePDP + pdp.getId() + deletedStatusFound);
2489                     throw new PersistenceException(moreThanOnePDP + pdp.getId() + deletedStatusFound);
2490                 }
2491
2492                 // check if new group exists
2493                 Query checkGroupQuery = em.createQuery(groupEntitySelectQuery);
2494                 checkGroupQuery.setParameter(groupIdVar, group.getId());
2495                 checkGroupQuery.setParameter(deletedVar, false);
2496                 List<?> checkGroupQueryList;
2497                 try {
2498                     checkGroupQueryList = checkGroupQuery.getResultList();
2499                 } catch (Exception e) {
2500                     PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
2501                             "Caught Exception trying to get group on checkGroupQuery.getResultList()");
2502                     throw new PersistenceException("Query failed trying to get new group " + group.getId());
2503                 }
2504                 if (checkGroupQueryList.size() != 1) {
2505                     PolicyLogger.error("The group " + group.getId() + " does not exist");
2506                     throw new PersistenceException("The group " + group.getId() + " does not exist");
2507                 }
2508                 GroupEntity groupToMoveInto = (GroupEntity) checkGroupQueryList.get(0);
2509                 PdpEntity pdpToUpdate = (PdpEntity) getPdpQueryList.get(0);
2510                 pdpToUpdate.setGroup(groupToMoveInto);
2511                 if (!stringEquals(pdpToUpdate.getModifiedBy(), username)) {
2512                     pdpToUpdate.setModifiedBy(username);
2513                 }
2514
2515                 em.flush();
2516                 this.pdpId = pdpToUpdate.getPdpKey();
2517             }
2518         }
2519
2520         @Override
2521         public void changeDefaultGroup(OnapPDPGroup group, String username) {
2522             logger.debug("changeDefaultGroup(PDPGroup group, String username) as changeDefaultGroup(" + group + ","
2523                     + username + ") called");
2524             if (group == null) {
2525                 throw new IllegalArgumentException("PDPGroup group must not be null");
2526             }
2527             if (isNullOrEmpty(group.getId(), username)) {
2528                 throw new IllegalArgumentException("group.getId() and username must not be null or empty");
2529             }
2530
2531             synchronized (emLock) {
2532                 checkBeforeOperationRun();
2533                 Query getGroupQuery = em.createQuery(groupEntitySelectQuery);
2534                 getGroupQuery.setParameter(groupIdVar, group.getId());
2535                 getGroupQuery.setParameter(deletedVar, false);
2536                 List<?> getGroupQueryList;
2537                 try {
2538                     getGroupQueryList = getGroupQuery.getResultList();
2539                 } catch (Exception e) {
2540                     PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
2541                             "Caught Exception on getGroupQuery.getResultList()");
2542                     throw new PersistenceException(queryFailedToGetGroup + group.getId());
2543                 }
2544                 if (getGroupQueryList.isEmpty()) {
2545                     PolicyLogger.error("The group cannot be found to set default with id " + group.getId());
2546                     throw new PersistenceException("The group cannot be found to set default with id " + group.getId());
2547                 } else if (getGroupQueryList.size() > 1) {
2548                     PolicyLogger.error(duplicateGroupId + group.getId() + deletedStatusFound);
2549                     throw new PersistenceException(duplicateGroupId + group.getId() + deletedStatusFound);
2550                 }
2551                 GroupEntity newDefaultGroup = (GroupEntity) getGroupQueryList.get(0);
2552                 newDefaultGroup.setDefaultGroup(true);
2553                 if (!stringEquals(newDefaultGroup.getModifiedBy(), username)) {
2554                     newDefaultGroup.setModifiedBy(username);
2555                 }
2556
2557                 em.flush();
2558                 this.groupId = newDefaultGroup.getGroupKey();
2559                 Query setAllGroupsNotDefault = em.createQuery(
2560                         "UPDATE GroupEntity g SET g.defaultGroup=:defaultGroup WHERE g.deleted=:deleted AND g"
2561                                 + ".groupKey<>:groupKey");
2562                 // not going to set modified by for all groups
2563                 setAllGroupsNotDefault.setParameter("defaultGroup", false);
2564                 setAllGroupsNotDefault.setParameter(deletedVar, false);
2565                 setAllGroupsNotDefault.setParameter("groupKey", newDefaultGroup.getGroupKey());
2566                 try {
2567                     logger.info("set " + setAllGroupsNotDefault.executeUpdate() + " groups as not default");
2568                 } catch (Exception e) {
2569                     PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
2570                             "Caught Exception on setAllGroupsNotDefault.executeUpdate()");
2571                     throw new PersistenceException("Could not set all other groups default to false");
2572                 }
2573                 em.flush();
2574             }
2575         }
2576
2577
2578         @Override
2579         public void deleteGroup(OnapPDPGroup group, OnapPDPGroup moveToGroup, String username)
2580                 throws PolicyDBException {
2581             logger.debug("deleteGroup(PDPGroup group, PDPGroup moveToGroup, String username) as deleteGroup(" + group
2582                     + ", " + moveToGroup + "," + username + ") called");
2583             if (group == null) {
2584                 throw new IllegalArgumentException("PDPGroup group cannot be null");
2585             }
2586             if (isNullOrEmpty(username, group.getId())) {
2587                 throw new IllegalArgumentException("group.getId() and and username must not be null or empty");
2588             }
2589
2590             if (group.isDefaultGroup()) {
2591                 PolicyLogger
2592                         .error("The default group " + group.getId() + " was attempted to be deleted. It cannot be.");
2593                 throw new PolicyDBException("You cannot delete the default group.");
2594             }
2595             synchronized (emLock) {
2596                 checkBeforeOperationRun();
2597                 Query deleteGroupQuery = em.createQuery(groupEntitySelectQuery);
2598                 deleteGroupQuery.setParameter(groupIdVar, group.getId());
2599                 deleteGroupQuery.setParameter(deletedVar, false);
2600                 List<?> deleteGroupQueryList;
2601                 try {
2602                     deleteGroupQueryList = deleteGroupQuery.getResultList();
2603                 } catch (Exception e) {
2604                     PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
2605                             "Caught Exception trying to check if group exists deleteGroupQuery.getResultList()");
2606                     throw new PersistenceException("Query failed trying to check if group exists");
2607                 }
2608                 if (deleteGroupQueryList.isEmpty()) {
2609                     logger.warn(groupCannotBeFound + group.getId());
2610                     return;
2611                 } else if (deleteGroupQueryList.size() > 1) {
2612                     PolicyLogger.error(duplicateGroupId + group.getId() + foundInDBNotDeleted);
2613                     throw new PersistenceException(duplicateGroupId + group.getId() + foundInDBNotDeleted);
2614                 }
2615
2616                 Query pdpsInGroupQuery =
2617                         em.createQuery("SELECT p FROM PdpEntity p WHERE p.groupEntity=:group and p.deleted=:deleted");
2618                 pdpsInGroupQuery.setParameter("group", ((GroupEntity) deleteGroupQueryList.get(0)));
2619                 pdpsInGroupQuery.setParameter(deletedVar, false);
2620                 List<?> pdpsInGroupList;
2621                 try {
2622                     pdpsInGroupList = pdpsInGroupQuery.getResultList();
2623                 } catch (Exception e) {
2624                     PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
2625                             "Caught Exception trying to get PDPs in group on pdpsInGroupQuery.getResultList()");
2626                     throw new PersistenceException("Query failed trying to get PDPs in group");
2627                 }
2628                 if (!pdpsInGroupList.isEmpty()) {
2629                     if (moveToGroup != null) {
2630                         Query checkMoveToGroupQuery = em.createQuery(
2631                                 "SELECT o FROM GroupEntity o WHERE o.groupId=:groupId AND o.deleted=:deleted");
2632                         checkMoveToGroupQuery.setParameter(groupIdVar, moveToGroup.getId());
2633                         checkMoveToGroupQuery.setParameter(deletedVar, false);
2634                         List<?> checkMoveToGroupList;
2635                         try {
2636                             checkMoveToGroupList = checkMoveToGroupQuery.getResultList();
2637                         } catch (Exception e) {
2638                             PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
2639                                     "Caught Exception trying to check if group exists checkMoveToGroupQuery"
2640                                             + ".getResultList()");
2641                             throw new PersistenceException("Query failed trying to check if group exists");
2642                         }
2643                         if (checkMoveToGroupList.isEmpty()) {
2644                             PolicyLogger.error(groupCannotBeFound + moveToGroup.getId());
2645                             throw new PersistenceException(groupCannotBeFound + moveToGroup.getId());
2646                         } else if (checkMoveToGroupList.size() > 1) {
2647                             PolicyLogger.error(duplicateGroupId + moveToGroup.getId() + foundInDBNotDeleted);
2648                             throw new PersistenceException(
2649                                     duplicateGroupId + moveToGroup.getId() + foundInDBNotDeleted);
2650                         } else {
2651                             GroupEntity newGroup = (GroupEntity) checkMoveToGroupList.get(0);
2652                             for (Object pdpObject : pdpsInGroupList) {
2653                                 PdpEntity pdp = (PdpEntity) pdpObject;
2654                                 pdp.setGroup(newGroup);
2655                                 if (!stringEquals(pdp.getModifiedBy(), username)) {
2656                                     pdp.setModifiedBy(username);
2657                                 }
2658                                 try {
2659                                     em.flush();
2660                                     this.newGroupId = newGroup.getGroupId();
2661                                 } catch (PersistenceException e) {
2662                                     PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
2663                                             "Caught PersistenceException trying to set pdp group to null on em.flush"
2664                                                     + "()");
2665                                     throw new PersistenceException("Query failed trying to set pdp group to ");
2666                                 }
2667                             }
2668                         }
2669                     } else {
2670                         PolicyLogger.error("Group " + group.getId()
2671                                 + " is trying to be delted with PDPs. No group was provided to move them to");
2672                         throw new PolicyDBException("Group has PDPs. Must provide a group for them to move to");
2673                     }
2674                 }
2675
2676                 // delete group here
2677                 GroupEntity groupToDelete = (GroupEntity) deleteGroupQueryList.get(0);
2678                 groupToDelete.setDeleted(true);
2679                 if (!stringEquals(groupToDelete.getModifiedBy(), username)) {
2680                     groupToDelete.setModifiedBy(username);
2681                 }
2682                 em.flush();
2683                 this.groupId = groupToDelete.getGroupKey();
2684             }
2685         }
2686
2687         @Override
2688         public StdPDPGroup addPolicyToGroup(String groupID, String policyID, String username) throws PolicyDBException {
2689             logger.info("PolicyDBDao: addPolicyToGroup(String groupID, String policyID, String username) as "
2690                     + "addPolicyToGroup(" + groupID + ", " + policyID + "," + username + ") called");
2691             if (isNullOrEmpty(groupID, policyID, username)) {
2692                 throw new IllegalArgumentException("groupID, policyID, and username must not be null or empty");
2693             }
2694             synchronized (emLock) {
2695                 checkBeforeOperationRun();
2696                 // check if group exists
2697                 Query groupQuery = em.createQuery(groupEntitySelectQuery);
2698                 groupQuery.setParameter(groupIdVar, groupID);
2699                 groupQuery.setParameter(deletedVar, false);
2700                 List<?> groupQueryList;
2701                 try {
2702                     groupQueryList = groupQuery.getResultList();
2703                 } catch (Exception e) {
2704                     PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
2705                             "Caught Exception trying to check if group exists groupQuery.getResultList()");
2706                     throw new PersistenceException("Query failed trying to check if group " + groupID + " exists");
2707                 }
2708                 if (groupQueryList.isEmpty()) {
2709                     PolicyLogger.error("Group policy is being added to does not exist with id " + groupID);
2710                     throw new PersistenceException("Group policy is being added to does not exist with id " + groupID);
2711                 } else if (groupQueryList.size() > 1) {
2712                     PolicyLogger.error(duplicateGroupId + groupID + foundInDBNotDeleted);
2713                     throw new PersistenceException(duplicateGroupId + groupID + foundInDBNotDeleted);
2714                 }
2715
2716                 // we need to convert the form of the policy id that is used groups into the form that is used
2717                 // for the database. (com.Config_mypol.1.xml) to (Config_mypol.xml)
2718                 String[] policyNameScopeAndVersion = getNameScopeAndVersionFromPdpPolicy(policyID);
2719                 if (policyNameScopeAndVersion == null) {
2720                     throw new IllegalArgumentException("Invalid input - policyID must contain name, scope and version");
2721                 }
2722                 Query policyQuery = em.createQuery(
2723                         "SELECT p FROM PolicyEntity p WHERE p.policyName=:policyName AND p.scope=:scope AND p"
2724                                 + ".deleted=:deleted");
2725                 policyQuery.setParameter("policyName", policyNameScopeAndVersion[0]);
2726                 policyQuery.setParameter(scope, policyNameScopeAndVersion[1]);
2727                 policyQuery.setParameter(deletedVar, false);
2728                 List<?> policyQueryList;
2729                 try {
2730                     policyQueryList = policyQuery.getResultList();
2731                 } catch (Exception e) {
2732                     logger.debug(e);
2733                     PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
2734                             "Caught Exception trying to check if policy exists policyQuery.getResultList()");
2735                     throw new PersistenceException(
2736                             "Query failed trying to check if policy " + policyNameScopeAndVersion[0] + " exists");
2737                 }
2738                 if (policyQueryList.isEmpty()) {
2739                     PolicyLogger.error("Policy being added to the group does not exist with policy id "
2740                             + policyNameScopeAndVersion[0]);
2741                     throw new PersistenceException("Policy being added to the group does not exist with policy id "
2742                             + policyNameScopeAndVersion[0]);
2743                 } else if (policyQueryList.size() > 1) {
2744                     PolicyLogger.error(duplicatePolicyId + policyNameScopeAndVersion[0] + foundInDBNotDeleted);
2745                     throw new PersistenceException(
2746                             duplicateGroupId + policyNameScopeAndVersion[0] + foundInDBNotDeleted);
2747                 }
2748                 logger.info("PolicyDBDao: Getting group and policy from database");
2749                 GroupEntity group = (GroupEntity) groupQueryList.get(0);
2750                 PolicyEntity policy = (PolicyEntity) policyQueryList.get(0);
2751                 Iterator<PolicyEntity> policyIt = group.getPolicies().iterator();
2752                 String policyName = getPolicyNameAndVersionFromPolicyFileName(policy.getPolicyName())[0];
2753
2754                 logger.info("PolicyDBDao: policyName retrieved is " + policyName);
2755                 try {
2756                     while (policyIt.hasNext()) {
2757                         PolicyEntity pol = policyIt.next();
2758                         if (policy.getScope().equals(pol.getScope())
2759                                 && getPolicyNameAndVersionFromPolicyFileName(pol.getPolicyName())[0]
2760                                         .equals(policyName)) {
2761                             policyIt.remove();
2762                         }
2763                     }
2764                 } catch (Exception e) {
2765                     logger.debug(e);
2766                     PolicyLogger.error("Could not delete old versions for policy " + policy.getPolicyName() + ", ID: "
2767                             + policy.getPolicyId());
2768                 }
2769                 group.addPolicyToGroup(policy);
2770                 em.flush();
2771
2772                 // After adding policy to the db group we need to make sure the filesytem group is in sync with the db
2773                 // group
2774                 try {
2775                     StdPDPGroup pdpGroup = (StdPDPGroup) papEngine.getGroup(group.getGroupId());
2776                     return synchronizeGroupPoliciesInFileSystem(pdpGroup, group);
2777                 } catch (PAPException e) {
2778                     logger.debug(e);
2779                     PolicyLogger
2780                             .error("PolicyDBDao: Could not synchronize the filesystem group with the database group. "
2781                                     + e.getMessage());
2782                 }
2783                 return null;
2784             }
2785         }
2786
2787         // this means delete pdp not just remove from group
2788         @Override
2789         public void removePdpFromGroup(String pdpID, String username) {
2790             logger.debug("removePdpFromGroup(String pdpID, String username) as removePdpFromGroup(" + pdpID + ","
2791                     + username + ") called");
2792             if (isNullOrEmpty(pdpID, username)) {
2793                 throw new IllegalArgumentException("pdpID and username must not be null or empty");
2794             }
2795             synchronized (emLock) {
2796                 checkBeforeOperationRun();
2797                 Query pdpQuery = em.createQuery(pdpEntitySelectQuery);
2798                 pdpQuery.setParameter(pdpIdVariable, pdpID);
2799                 pdpQuery.setParameter(deletedVar, false);
2800                 List<?> pdpList;
2801                 try {
2802                     pdpList = pdpQuery.getResultList();
2803                 } catch (Exception e) {
2804                     PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, policyDBDaoVar,
2805                             "Caught Exception trying to check if pdp exists  pdpQuery.getResultList()");
2806                     throw new PersistenceException("Query failed trying to check if pdp " + pdpID + " exists");
2807                 }
2808                 if (pdpList.size() > 1) {
2809                     PolicyLogger.error("Somehow, more than one pdp with the id " + pdpID + foundInDBNotDeleted);
2810                     throw new PersistenceException(
2811                             "Somehow, more than one pdp with the id " + pdpID + foundInDBNotDeleted);
2812                 } else if (pdpList.isEmpty()) {
2813                     PolicyLogger.error("Pdp being removed does not exist with id " + pdpID);
2814                     return;
2815                 }
2816                 PdpEntity pdp = (PdpEntity) pdpList.get(0);
2817                 pdp.setGroup(null);
2818                 if (!stringEquals(pdp.getModifiedBy(), username)) {
2819                     pdp.setModifiedBy(username);
2820                 }
2821                 pdp.setDeleted(true);
2822
2823                 em.flush();
2824                 this.pdpId = pdp.getPdpKey();
2825             }
2826         }
2827
2828         private void notifyOthers(long entityId, String entityType) {
2829             notifyOthers(entityId, entityType, null);
2830         }
2831
2832         private void notifyOthers(long entityId, String entityType, String newGroupId) {
2833             logger.debug("notifyOthers(long entityId, String entityType, long newGroupId) as notifyOthers(" + entityId
2834                     + "," + entityType + "," + newGroupId + ") called");
2835             LinkedList<Thread> notifyThreads = new LinkedList<>();
2836
2837             // we're going to run notifications in parallel threads to speed things up
2838             for (Object obj : otherServers) {
2839                 Thread newNotifyThread = new Thread(new NotifyOtherThread(obj, entityId, entityType, newGroupId));
2840                 newNotifyThread.start();
2841                 notifyThreads.add(newNotifyThread);
2842             }
2843             // we want to wait for all notifications to complete or timeout before we unlock the interface and allow
2844             // more changes
2845             for (Thread t : notifyThreads) {
2846                 try {
2847                     t.join();
2848                 } catch (Exception e) {
2849                     logger.warn("Could not join a notifcation thread" + e);
2850                 }
2851             }
2852         }
2853     }
2854
2855     private PolicyDBDao() {
2856         // empty constructor
2857     }
2858
2859     public static PolicyDBDaoTestClass getPolicyDBDaoTestClass() {
2860         return new PolicyDBDao().new PolicyDBDaoTestClass();
2861     }
2862
2863     final class PolicyDBDaoTestClass {
2864         String getConfigFile(String filename, String scope, PolicyRestAdapter policy) {
2865             return scope + "." + PolicyDBDao.this.getConfigFile(filename, policy);
2866         }
2867
2868         String[] getPolicyNameAndVersionFromPolicyFileName(String originalPolicyName) throws PolicyDBException {
2869             return PolicyDBDao.this.getPolicyNameAndVersionFromPolicyFileName(originalPolicyName);
2870         }
2871     }
2872
2873 }