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