Unverified Commit 042a27a6 authored by Mohamed Khalil LABIDI's avatar Mohamed Khalil LABIDI Committed by GitHub
Browse files

Merge pull request #12 from mklkun/fix-threaded

Fix threaded-safe Client
parents f40747a4 25f121f8
......@@ -5,6 +5,7 @@ import org.activeeon.morphemic.application.deployment.PASchedulerGateway;
import org.activeeon.morphemic.infrastructure.deployment.PAConnectorIaasGateway;
import org.activeeon.morphemic.infrastructure.deployment.PAResourceManagerGateway;
import org.activeeon.morphemic.model.*;
import org.activeeon.morphemic.service.EntityManagerHelper;
import org.activeeon.morphemic.service.NodeCandidateUtils;
import org.activeeon.morphemic.service.UpdatingNodeCandidatesThread;
import org.apache.commons.lang3.Validate;
......@@ -24,9 +25,6 @@ import org.ow2.proactive.scheduler.common.task.TaskVariable;
import org.ow2.proactive_grid_cloud_portal.scheduler.exception.PermissionRestException;
import org.ow2.proactive_grid_cloud_portal.scheduler.exception.RestException;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.security.auth.login.LoginException;
import javax.ws.rs.NotFoundException;
import java.io.File;
......@@ -49,8 +47,6 @@ public class PAGateway {
public PAConnectorIaasGateway connectorIaasGateway;
private final EntityManager em;
private static final Logger LOGGER = Logger.getLogger(PAGateway.class);
/**
......@@ -62,9 +58,6 @@ public class PAGateway {
resourceManagerGateway = new PAResourceManagerGateway(paURL);
schedulerGateway = new PASchedulerGateway(paURL);
connectorIaasGateway = new PAConnectorIaasGateway(paURL);
EntityManagerFactory emf = Persistence.createEntityManagerFactory("model");
em = emf.createEntityManager();
}
/**
......@@ -156,7 +149,7 @@ public class PAGateway {
public void createJob(JSONObject job) {
Validate.notNull(job, "The job received is empty. Nothing to be created.");
em.getTransaction().begin();
EntityManagerHelper.begin();
Job newJob = new Job();
newJob.setJobId(job.optJSONObject("jobInformation").optString("id"));
......@@ -200,19 +193,19 @@ public class PAGateway {
}
List<Port> portsToOpen = extractListOfPortsToOpen(task.optJSONArray("ports"));
portsToOpen.forEach(em::persist);
portsToOpen.forEach(EntityManagerHelper::persist);
newTask.setPortsToOpen(portsToOpen);
newTask.setParentTasks(extractParentTasks(job, task));
em.persist(newTask);
EntityManagerHelper.persist(newTask);
tasks.add(newTask);
});
newJob.setTasks(tasks);
em.persist(newJob);
EntityManagerHelper.persist(newJob);
em.getTransaction().commit();
EntityManagerHelper.commit();
LOGGER.info("Job created: " + newJob.toString());
}
......@@ -224,7 +217,8 @@ public class PAGateway {
*/
public List<NodeCandidate> findNodeCandidates(List<Requirement> requirements) {
List<NodeCandidate> filteredNodeCandidates = new LinkedList<>();
List<NodeCandidate> allNodeCandidates = em.createQuery("SELECT nc FROM NodeCandidate nc", NodeCandidate.class).getResultList();
List<NodeCandidate> allNodeCandidates = EntityManagerHelper.createQuery("SELECT nc FROM NodeCandidate nc",
NodeCandidate.class).getResultList();
allNodeCandidates.forEach(nodeCandidate -> {
if (NodeCandidateUtils.verifyAllFilters(requirements, nodeCandidate)) {
filteredNodeCandidates.add(nodeCandidate);
......@@ -293,9 +287,9 @@ public class PAGateway {
*/
public int addEmsDeployment(List<String> nodeNames, String authorizationBearer) {
Validate.notNull(authorizationBearer,"The provided authorization bearer cannot be empty");
em.getTransaction().begin();
EntityManagerHelper.begin();
AtomicInteger failedDeployementIdentification = new AtomicInteger();
AtomicInteger failedDeploymentIdentification = new AtomicInteger();
// TODO Info to fetch from a config file and from nodeCandidate, when the feature will be available
String baguetteIp = "ems";
int baguettePort = 22;
......@@ -305,17 +299,17 @@ public class PAGateway {
// For supplied node ...
nodeNames.forEach(node -> {
Deployment deployment = em.find(Deployment.class,node);
Deployment deployment = EntityManagerHelper.find(Deployment.class,node);
PACloud cloud = deployment.getPaCloud();
EmsDeploymentRequest req = new EmsDeploymentRequest(authorizationBearer, baguetteIp, baguettePort, OperatingSystemFamily.fromValue(operatingSystem), targetType, deployment.getNodeName(), EmsDeploymentRequest.TargetProvider.valueOf(cloud.getCloudProviderName()), deployment.getLocationName(), isUsingHttps, deployment.getNodeName());
deployment.setEmsDeployment(req);
em.persist(deployment);
EntityManagerHelper.persist(deployment);
});
em.getTransaction().commit();
EntityManagerHelper.commit();
LOGGER.info("EMS deployment definition finished.");
return failedDeployementIdentification.get();
return failedDeploymentIdentification.get();
}
/**
......@@ -324,10 +318,10 @@ public class PAGateway {
* @param jobId A constructed job identifier
* @return 0 if nodes has been added properly. A greater than 0 value otherwise.
*/
public int addNodes(JSONArray nodes, String jobId) {
public synchronized int addNodes(JSONArray nodes, String jobId) {
Validate.notNull(nodes, "The received nodes structure is empty. Nothing to be created.");
em.getTransaction().begin();
EntityManagerHelper.begin();
nodes.forEach(object -> {
JSONObject node = (JSONObject) object;
......@@ -338,7 +332,7 @@ public class PAGateway {
newDeployment.setImageProviderId(nodeCandidateInfo.optString("imageProviderId"));
newDeployment.setHardwareProviderId(nodeCandidateInfo.optString("hardwareProviderId"));
PACloud cloud = em.find(PACloud.class, nodeCandidateInfo.optString("cloudID"));
PACloud cloud = EntityManagerHelper.find(PACloud.class, nodeCandidateInfo.optString("cloudID"));
cloud.addDeployment(newDeployment);
String nodeSourceName = cloud.getNodeSourceNamePrefix() + newDeployment.getLocationName();
if (!cloud.isRegionDeployed(newDeployment.getLocationName())) {
......@@ -350,20 +344,19 @@ public class PAGateway {
LOGGER.info("Node source defined.");
newDeployment.setPaCloud(cloud);
em.persist(newDeployment);
EntityManagerHelper.persist(newDeployment);
LOGGER.debug("Deployment created: " + newDeployment.toString());
em.persist(cloud);
EntityManagerHelper.persist(cloud);
LOGGER.info("Deployment added to the related cloud: " + cloud.toString());
LOGGER.info("Job found: " + em.find(Job.class, jobId));
LOGGER.info("Trying to retrieve task: " + node.optString("taskName"));
Task task = em.find(Job.class, jobId).findTask(node.optString("taskName"));
Task task = EntityManagerHelper.find(Job.class, jobId).findTask(node.optString("taskName"));
task.addDeployment(newDeployment);
em.persist(task);
EntityManagerHelper.persist(task);
});
em.getTransaction().commit();
EntityManagerHelper.commit();
LOGGER.info("Nodes added properly.");
......@@ -377,7 +370,7 @@ public class PAGateway {
*/
public void undeployClouds(List<String> cloudIDs, Boolean preempt) {
cloudIDs.forEach(cloudID -> {
PACloud cloud = em.find(PACloud.class, cloudID);
PACloud cloud = EntityManagerHelper.find(PACloud.class, cloudID);
for (Map.Entry<String, String> entry : cloud.getDeployedRegions().entrySet()) {
try {
resourceManagerGateway.undeployNodeSource(cloud.getNodeSourceNamePrefix() + entry.getKey(), preempt);
......@@ -395,7 +388,7 @@ public class PAGateway {
*/
public void removeClouds(List<String> cloudIDs, Boolean preempt) {
cloudIDs.forEach(cloudID -> {
PACloud cloud = em.find(PACloud.class, cloudID);
PACloud cloud = EntityManagerHelper.find(PACloud.class, cloudID);
for (Map.Entry<String, String> entry : cloud.getDeployedRegions().entrySet()) {
try {
resourceManagerGateway.removeNodeSource(cloud.getNodeSourceNamePrefix() + entry.getKey(), preempt);
......@@ -444,7 +437,7 @@ public class PAGateway {
public int addClouds(JSONArray clouds) {
Validate.notNull(clouds, "The received clouds structure is empty. Nothing to be created.");
em.getTransaction().begin();
EntityManagerHelper.begin();
List<String> savedCloudIds = new LinkedList<>();
clouds.forEach(object -> {
JSONObject cloud = (JSONObject) object;
......@@ -471,19 +464,19 @@ public class PAGateway {
credentials.setUserName(cloud.optJSONObject("credentials").optString("user"));
credentials.setPrivateKey(cloud.optJSONObject("credentials").optString("secret"));
credentials.setDomain(cloud.optJSONObject("credentials").optString("domain"));
em.persist(credentials);
EntityManagerHelper.persist(credentials);
newCloud.setCredentials(credentials);
String dummyInfraName = "iamadummy" + newCloud.getCloudProviderName();
connectorIaasGateway.defineInfrastructure(dummyInfraName, newCloud, "");
newCloud.setDummyInfrastructureName(dummyInfraName);
em.persist(newCloud);
EntityManagerHelper.persist(newCloud);
LOGGER.debug("Cloud created: " + newCloud.toString());
savedCloudIds.add(newCloud.getCloudID());
});
em.getTransaction().commit();
EntityManagerHelper.commit();
LOGGER.info("Clouds created properly.");
......@@ -553,7 +546,7 @@ public class PAGateway {
private ScriptTask createInfraTask(Task task, Deployment deployment, String taskNameSuffix, String nodeToken) {
LOGGER.debug("Acquiring node AWS script file: " + getClass().getResource("/acquire_node_aws_script.groovy").toString());
ScriptTask deployNodeTask = PAFactory.createGroovyScriptTaskFromFile("acquireAWSNode" + taskNameSuffix,
ScriptTask deployNodeTask = PAFactory.createGroovyScriptTaskFromFile("acquireAWSNode_" + task.getName() + taskNameSuffix,
"acquire_node_aws_script.groovy");
Map<String, TaskVariable> variablesMap = new HashMap<>();
......@@ -603,16 +596,16 @@ public class PAGateway {
public int addScaleOutTask(List<String> nodeNames, String jobId, String taskName) {
Validate.notEmpty(nodeNames,"The provided nodes list should not be empty");
Validate.notNull(jobId,"The provided jobId should not be null.");
em.getTransaction().begin();
EntityManagerHelper.begin();
// Let's find the jobId to retrieve the task
Optional<Job> optJob = Optional.ofNullable(em.find(Job.class,jobId));
Optional<Job> optJob = Optional.ofNullable(EntityManagerHelper.find(Job.class,jobId));
if (!optJob.isPresent()) {
LOGGER.error(String.format("Job [%s] not found", jobId));
return 1;
}
// Let's find the task:
Optional<Task> optTask = Optional.ofNullable(em.find(Task.class,optJob.get().findTask(taskName)));
Optional<Task> optTask = Optional.ofNullable(EntityManagerHelper.find(Task.class,optJob.get().findTask(taskName)));
if (!optTask.isPresent()) {
LOGGER.error(String.format("Task [%s] not found", taskName));
return 1;
......@@ -640,12 +633,12 @@ public class PAGateway {
return newDeployment;
}).forEach( deployment -> {
optTask.get().addDeployment(deployment);
em.persist(deployment.getEmsDeployment());
em.persist(deployment);
em.persist(optTask.get());
EntityManagerHelper.persist(deployment.getEmsDeployment());
EntityManagerHelper.persist(deployment);
EntityManagerHelper.persist(optTask.get());
});
em.getTransaction().commit();
EntityManagerHelper.commit();
return 0;
}
......@@ -659,17 +652,17 @@ public class PAGateway {
public int addScaleInTask(List<String> nodeNames, String jobId, String taskName) {
Validate.notEmpty(nodeNames,"The provided nodes list should not be empty");
Validate.notNull(jobId,"The provided jobId should not be null.");
em.getTransaction().begin();
EntityManagerHelper.begin();
// Let's find the jobId to retrieve the task
Optional<Job> optJob = Optional.ofNullable(em.find(Job.class,jobId));
Optional<Job> optJob = Optional.ofNullable(EntityManagerHelper.find(Job.class,jobId));
if (!optJob.isPresent()) {
LOGGER.error(String.format("Job [%s] not found", jobId));
return 1;
}
// Let's find the task:
Optional<Task> optTask = Optional.ofNullable(em.find(Task.class,optJob.get().findTask(taskName)));
Optional<Task> optTask = Optional.ofNullable(EntityManagerHelper.find(Task.class,optJob.get().findTask(taskName)));
if (!optTask.isPresent()) {
LOGGER.error(String.format("Task [%s] not found", taskName));
return 1;
......@@ -682,21 +675,21 @@ public class PAGateway {
}
// For supplied node, I retrieve their deployment
List<Deployment> deployments = nodeNames.stream().map(node -> em.find(Deployment.class,node)).filter(deployment -> (deployment != null)).collect(Collectors.toList());
List<Deployment> deployments = nodeNames.stream().map(node -> EntityManagerHelper.find(Deployment.class,node)).filter(deployment -> (deployment != null)).collect(Collectors.toList());
// For deployed node, I flag their removal
List<String> nodesToBeRemoved = deployments.stream().filter(deployment -> deployment.getIsDeployed()).map(Deployment::getNodeName).collect(Collectors.toList());
// For every node, I remove the deployment entree
deployments.forEach(
deployment -> {
em.remove(deployment);
em.persist(deployment);
EntityManagerHelper.remove(deployment);
EntityManagerHelper.persist(deployment);
}
);
// I commit the removal of deployed node
removeNodes(nodesToBeRemoved,false);
em.getTransaction().commit();
EntityManagerHelper.commit();
return 0;
}
......@@ -756,14 +749,15 @@ public class PAGateway {
* @return The submitted job id
*/
public long submitJob(String jobId) {
Job jobToSubmit = em.find(Job.class, jobId);
Job jobToSubmit = EntityManagerHelper.find(Job.class, jobId);
EntityManagerHelper.refresh(jobToSubmit);
LOGGER.info("Job found to submit: " + jobToSubmit.toString());
TaskFlowJob paJob = new TaskFlowJob();
paJob.setName(jobToSubmit.getName());
LOGGER.info("Job created: " + paJob.toString());
em.getTransaction().begin();
EntityManagerHelper.begin();
jobToSubmit.getTasks().forEach(task -> {
List<ScriptTask> scriptTasks = buildPATask(task);
......@@ -776,7 +770,7 @@ public class PAGateway {
LOGGER.error("Task " + task.getName() + " could not be added due to: " + e.toString());
}
});
em.persist(task);
EntityManagerHelper.persist(task);
});
setAllMandatoryDependencies(paJob, jobToSubmit);
......@@ -784,8 +778,8 @@ public class PAGateway {
long submittedJobId = schedulerGateway.submit(paJob).longValue();
jobToSubmit.setSubmittedJobId(submittedJobId);
em.persist(jobToSubmit);
em.getTransaction().commit();
EntityManagerHelper.persist(jobToSubmit);
EntityManagerHelper.commit();
LOGGER.info("Job submitted successfully. ID = " + submittedJobId);
return(submittedJobId);
......@@ -797,7 +791,7 @@ public class PAGateway {
* @return The job state
*/
public JobState getJobState(String jobId) {
Job submittedJob = em.find(Job.class, jobId);
Job submittedJob = EntityManagerHelper.find(Job.class, jobId);
JobState jobState = schedulerGateway.getJobState(String.valueOf(submittedJob.getSubmittedJobId()));
LOGGER.info("Job state of job: " + jobId + " retrieved successfully: " + jobState.toString());
return jobState;
......@@ -810,7 +804,7 @@ public class PAGateway {
* @return The job result
*/
public JobResult waitForJob(String jobId, long timeout) {
Job submittedJob = em.find(Job.class, jobId);
Job submittedJob = EntityManagerHelper.find(Job.class, jobId);
JobResult jobResult = schedulerGateway.waitForJob(String.valueOf(submittedJob.getSubmittedJobId()), timeout);
LOGGER.info("Results of job: " + jobId + " fetched successfully: " + jobResult.toString());
return jobResult;
......@@ -822,7 +816,7 @@ public class PAGateway {
* @return True if the job has been killed, False otherwise
*/
public boolean killJob(String jobId) {
Job submittedJob = em.find(Job.class, jobId);
Job submittedJob = EntityManagerHelper.find(Job.class, jobId);
boolean result = schedulerGateway.killJob(String.valueOf(submittedJob.getSubmittedJobId()));
if (result) {
LOGGER.info("The job : " + jobId + " could be killed successfully.");
......@@ -840,7 +834,7 @@ public class PAGateway {
* @return The task results
*/
public Map<String, TaskResult> waitForTask(String jobId, String taskName, long timeout) {
Job submittedJob = em.find(Job.class, jobId);
Job submittedJob = EntityManagerHelper.find(Job.class, jobId);
Task createdTask = submittedJob.findTask(taskName);
Map<String, TaskResult> taskResultsMap = new HashMap<>();
createdTask.getSubmittedTaskNames().forEach(submittedTaskName -> {
......@@ -860,7 +854,7 @@ public class PAGateway {
* @return The task results
*/
public Map<String, TaskResult> getTaskResult(String jobId, String taskName) {
Job submittedJob = em.find(Job.class, jobId);
Job submittedJob = EntityManagerHelper.find(Job.class, jobId);
Task createdTask = submittedJob.findTask(taskName);
Map<String, TaskResult> taskResultsMap = new HashMap<>();
createdTask.getSubmittedTaskNames().forEach(submittedTaskName -> {
......
......@@ -29,10 +29,10 @@ public class Deployment implements Serializable {
@Column(name = "HARDWARE_PROVIDER_ID")
private String hardwareProviderId;
@OneToOne(fetch = FetchType.EAGER)
@OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.REFRESH)
private EmsDeploymentRequest emsDeployment;
@ManyToOne(fetch = FetchType.EAGER)
@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.REFRESH)
private PACloud paCloud;
@Column(name = "IS_DEPLOYED")
......@@ -41,7 +41,7 @@ public class Deployment implements Serializable {
@Override
public String toString() {
return "Deployment{" +
", nodeName='" + nodeName + '\'' +
"nodeName='" + nodeName + '\'' +
", locationName='" + locationName + '\'' +
", imageProviderId='" + imageProviderId + '\'' +
", hardwareProviderId='" + hardwareProviderId + '\'' +
......
......@@ -41,7 +41,7 @@ public class Hardware implements Serializable {
@JsonProperty("disk")
private Double disk = null;
@ManyToOne(fetch = FetchType.EAGER)
@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.REFRESH)
@JsonProperty("location")
private Location location = null;
......
......@@ -33,7 +33,7 @@ public class Image implements Serializable {
@JsonProperty("operatingSystem")
private OperatingSystem operatingSystem = null;
@ManyToOne(fetch = FetchType.EAGER)
@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.REFRESH)
@JsonProperty("location")
private Location location = null;
......
......@@ -30,7 +30,7 @@ public class Job implements Serializable {
@Column(name = "SUBMITTED_JOB_ID")
private long submittedJobId;
@OneToMany(fetch = FetchType.EAGER, orphanRemoval = true)
@OneToMany(fetch = FetchType.EAGER, orphanRemoval = true, cascade = CascadeType.REFRESH)
private List<Task> tasks;
public Task findTask(String taskName) {
......
......@@ -80,7 +80,7 @@ public class Location implements Serializable {
@JsonProperty("geoLocation")
private GeoLocation geoLocation = null;
@ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
@JsonProperty("parent")
private Location parent = null;
......
......@@ -74,19 +74,19 @@ public class NodeCandidate implements Serializable {
@JsonProperty("price")
private Double price = null;
@ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
@JsonProperty("cloud")
private Cloud cloud = null;
@ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
@JsonProperty("location")
private Location location = null;
@ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
@JsonProperty("image")
private Image image = null;
@ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
@JsonProperty("hardware")
private Hardware hardware = null;
......
......@@ -61,7 +61,7 @@ public class PACloud implements Serializable {
@ElementCollection(targetClass=String.class)
private Map<String, String> deployedRegions;
@OneToMany(fetch = FetchType.EAGER, orphanRemoval = true)
@OneToMany(fetch = FetchType.EAGER, orphanRemoval = true, cascade = CascadeType.REFRESH)
private List<Deployment> deployments;
@OneToOne
......
......@@ -34,14 +34,14 @@ public class Task implements Serializable {
@Embedded
private DockerEnvironment environment;
@OneToMany(fetch = FetchType.EAGER, orphanRemoval = true)
@OneToMany(fetch = FetchType.EAGER, orphanRemoval = true, cascade = CascadeType.REFRESH)
private List<Deployment> deployments;
@OneToMany(fetch = FetchType.EAGER, orphanRemoval = true)
@OneToMany(fetch = FetchType.EAGER, orphanRemoval = true, cascade = CascadeType.REFRESH)
@Fetch(value = FetchMode.SUBSELECT)
private List<Port> portsToOpen;
@OneToMany(fetch = FetchType.EAGER, orphanRemoval = true)
@OneToMany(fetch = FetchType.EAGER, orphanRemoval = true, cascade = CascadeType.REFRESH)
@Fetch(value = FetchMode.SUBSELECT)
private List<Monitor> monitors;
......
package org.activeeon.morphemic.service;
import org.hibernate.CacheMode;
import org.hibernate.jpa.QueryHints;
import javax.persistence.*;
public class EntityManagerHelper {
private static final EntityManagerFactory emf;
private static final ThreadLocal<EntityManager> threadLocal;
static {
emf = Persistence.createEntityManagerFactory("model");
threadLocal = new ThreadLocal<EntityManager>();
}
public static EntityManager getEntityManager() {
EntityManager em = threadLocal.get();
if (em == null) {
em = emf.createEntityManager();
// set your flush mode here
em.setFlushMode(FlushModeType.COMMIT);
threadLocal.set(em);
}
return em;
}
public static void closeEntityManager() {
EntityManager em = threadLocal.get();
if (em != null) {
em.close();
threadLocal.set(null);
}
}
public static void closeEntityManagerFactory() {
emf.close();
}
public static void begin() {
if(!getEntityManager().getTransaction().isActive())
getEntityManager().getTransaction().begin();
}
public static void persist(Object entity) {
getEntityManager().persist(entity);
}
public static void merge(Object entity) {
getEntityManager().merge(entity);
}
public static void refresh(Object entity) {
getEntityManager().refresh(entity);
}
public static void remove(Object entity) {
getEntityManager().remove(entity);
}
public static <T> T find(Class<T> entityClass, Object primaryKey) {
return getEntityManager().find(entityClass, primaryKey);
}
public static <T> TypedQuery<T> createQuery(String qlString, Class<T> resultClass) {
return getEntityManager().createQuery(qlString, resultClass).setHint(QueryHints.HINT_CACHE_MODE, CacheMode.REFRESH);
}
public static void rollback() {
getEntityManager().getTransaction().rollback();
}
public static void commit() {
getEntityManager().getTransaction().commit();
}
}
\ No newline at end of file
......@@ -8,29 +8,21 @@ import org.codehaus.jackson.map.ObjectMapper;
import org.json.JSONArray;
import org.json.JSONObject;