EJB, exception during persist: "EntityManager must be access within a transaction" - java

I received this error: "EntityManager must be access within a transaction" what is strange for me because my bean is mark with annotation:
#Stateless(name = "UserControllerSession")
I have injected EntityManager like this:
#PersistenceContext(unitName = "app")
private EntityManager em;
and this is my method:
#Override
#PermitAll
public String updateBlockedAndDeactivationReasonForIds(String userPk, String iban, List<String> associatedIds) {
UserLocal user = em.find(UserLocal.class, Long.valueOf(userPk));
if (user == null) {
return ("User with id: " + userPk + " does not exist ! \n");
}
user.setBlocked(true);
user.setActive(false);
user.setDeactivationReason(DeactivationReason.DEACTIVATION_MULTIPLY_IBAN_REASON);
user.setDeactivationDate(new Date());
StringBuilder message = new StringBuilder();
message.append(" IBAN " + iban + " is linked to multiple accounts: ");
for (String id : associatedIds) {
message.append(id + " ");
}
ContactJournalEntryBean cjb = new ContactJournalEntryBean("USER", user.getLogin(), new Date(), "Internet",
message.toString());
em.persist(user);
em.persist(cjb);
return "SUCCESS operation for user with id: " + userPk;
}
As far I know default value for EJB method is Transactioanl.REQUIRED so by defualt transaction should be created. Another question is can I have 2 persists in one transaction ? Thanks for any help

I think the default REQUIRED only applies if you actually use the #TransactionAttribute annotation. Try adding it to your method (or class if you want it as default on all methods).

Related

Jetty Websocket API Session

Hello I try many hours to get the Websocket API from Jetty with Sessions running.
My Problem is that, i can't interact externally with the Session, to send Data.
I can only interact to all Sessions and not only to one.
I tried to use the "Sec-WebSocket-Key" as Session Key, but it always returns java.lang.NullPointerException as the onWebSocketError.
I already tried to save the Session in a HashMap but every time, when i like to execute a sendString the Session in the HashMap is NULL.
My Code:
Connect Method
#Override
public void onWebSocketConnect(Session sessionIO) {
sessionIO.setIdleTimeout(Integer.MAX_VALUE);
System.out.print(gsonIO.toJson(this.getSession().getUpgradeResponse().getHeaders()));
sessionsIO.add(sessionIO);
loggerIO.log(LogType.SOCKET, "New Socket Connection from Client " + sessionIO.getRemoteAddress() + " with Sesssion ID: " + sessionIO.getPolicy().getBehavior().name() + ".");
}
My Function where i try to fetch my Session out of the Array
public static Session getSession(String handshakeIO) {
//String handshakeIO = sessionIO.getUpgradeRequest().getHeader("Sec-WebSocket-Key");
Session cacheIO = null;
for (Session rowIO : sessionsIO) {
if (handshakeIO.equalsIgnoreCase(rowIO.getUpgradeRequest().getHeader("Sec-WebSocket-Key"))) {
loggerIO.info("FOUND SESSION WITH Sec-WebSocket-Key " + handshakeIO + ".");
cacheIO = rowIO;
}
}
return cacheIO;
}
Fetching Session
#SneakyThrows
#EventHandler
public static void onJoin(UserLoginEvent eventIO) {
Habbo playerIO = eventIO.habbo;
int idIO = playerIO.getHabboInfo().getId();
for (Session rowIO : sessionsIO) {
if (rowIO.isOpen()) {
rowIO.getRemote().sendString(gsonIO.toJson(new ActionPaket("broadcast", "joinedplayer")));
}
}
if (ViceCache.playerIO.containsKey(idIO)) {
Session sessionIO = ViceCache.getSession(ViceCache.playerIO.get(idIO).getSessionIO());
if (sessionIO.isOpen()) {
sessionIO.getRemote().sendString(gsonIO.toJson(new ActionPaket("session", "granted")));
}
playerIO.whisper("Voicechat was successfully connected to Room.");
loggerIO.info("Player " + playerIO.getHabboInfo().getUsername() + " in Cache joined the Server, sending Callback.");
} else {
playerIO.whisper("To use Voice Chat, please download the Offical Vice Client.");
loggerIO.warning("Can't find Player " + playerIO.getHabboInfo().getUsername() + " with ID " + idIO + " in Cache, cannot send Callback for ViceChat.");
}
}

Rest Services with jax b

I have written this service in my rest app Rest Application:
#DELETE
#Consumes(MediaType.APPLICATION_JSON)
#Path("/companies")
public void removeCompany(Company company) throws AdminFacadeException {
AdminFacade facade = (AdminFacade)req.getSession(false).getAttribute("facade");
facade.removeCompany(company);
}
and this is where the error ocure in the dao layer:
#Override
public void removeCompany(Object obj, Company company) throws CompanyDBException {
Connection con = (Connection) obj;
String sql = "Delete from company where id=" + company.getCompanyId();
try {
Statement stmt = con.createStatement();
int rowsChanged = stmt.executeUpdate(sql);
if (rowsChanged == 0) {
throw new CompanyDBException(
"CompanyDAO: Failed to remove company. ID: " + company.getCompanyId() + " can not be found.");
}
} catch (SQLException e) {
throw new CompanyDBException("CompanyDAO: Failed to remove company. ID: " + company.getCompanyId(), e);
}
}
When I created the company inside the service and set the id that I got from the client there was no problem. However, now when I changed the service to consume json, the eror(500) occurred in the DB method in the line
String sql=..........., it cant get the company.getCompanyId. more
String sql=...........,it cant get the company.getCompanyId.
I am giving some more information: The company id is automatically generated but I cant see how it is change anything, the company object getting transferred well, the id in my company bean is long, in the Company bean there is annotation #XmlRootElement.
Can someone explain what am i missing

Why is my setter called twice?

I am working on a REST web service, using JAX-RS, JPA and JAXB, for the management of games and their highscores. A game has the following properties: name, url and highscoreTableSize.
A short description of what I'm trying to do: I have the createRow() method in the controller which consumes JSON (the JSON serialization of a Game object, class Game being annotated with #XmlRootElement), which calls the static createRow() from the Game model class, and inside of it the setUrl() is called. The thing is that, for some reason, the setter is called twice.
Now what it happens is that, if the url sent in the body of the request is not valid against a pattern, after the "mysterious" first call it becomes null, and the second time the setter is called, it goes inside if (url == null), instead of going inside if (!matcher.matches()), when actually the latter is the real situation, because I've sent a mistyped URL.
Does anybody know why this is happening and how can I solve this?
Thank you in advance!
Class Game:
#Entity
#Table(name="games")
#XmlRootElement(name = "Game")
public class Game implements Serializable {
//properties
public void setUrl(String url) throws CustomWebServiceException {
String regex = "^(https?|ftp|file)://[-a-zA-Z0-9+&##/%?=~_|!:,.;]*[-a-zA-Z0-9+&##/%=~_|]";
Pattern pattern = Pattern.compile(regex);
System.out.println("URL: " + url);
if ( url == null || url.length() == 0) {
throw new CustomWebServiceException(Response.Status.BAD_REQUEST, new ErrorMessage("The url of the game is mandatory!"));
} else {
Matcher matcher = pattern.matcher(url);
if (!matcher.matches()) {
throw new CustomWebServiceException(Response.Status.BAD_REQUEST, new ErrorMessage("The url is invalid! Please check its syntax!"));
} else {
this.url = url;
}
}
}
public static Response createRow(EntityManager em, UserTransaction ut, String name, Game gameData) throws Exception {
ut.begin();
Game _game = em.find(Game.class, name);
if (_game != null) {
Util.tryRollback(ut);
ErrorMessage errorMessage = new ErrorMessage(
"The game with name " + name
+ " already exists in the database!");
throw new CustomWebServiceException(Response.Status.CONFLICT,
errorMessage);
}
String url = gameData.getUrl();
Integer highscoreTableSize = gameData.getHighscoreTableSize();
Game newGame = new Game();
newGame.setName(name);
newGame.setUrl(url);
newGame.setHighscoreTableSize(highscoreTableSize);
em.persist(newGame);
// force the persistence manager to save data to DB
ut.commit();
if (highscoreTableSize == null) {
highscoreTableSize = 7;
}
SuccessfulRequestMessage succesfulRequestMessage = new SuccessfulRequestMessage(
" Game entry created with name: " + name
+ ", url: " + url + " and highscoreTableSize: " + highscoreTableSize
+ ".");
return Response.status(Status.CREATED).entity(succesfulRequestMessage).type(MediaType.APPLICATION_JSON).build();
}
}
Controller:
#PUT
#Path("/{name}")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response createRow(
#PathParam("name") String name,
Game gameData) throws CustomWebServiceException {
try {
return Game.createRow(em, ut, name, gameData);
} catch (SystemException | NotSupportedException | IllegalStateException | SecurityException | HeuristicMixedException
| HeuristicRollbackException | RollbackException e) {
Util.tryRollback(ut);
ErrorMessage errorMessage = new ErrorMessage(
"Error when trying to create entry:" + e.toString()
+ " with message: " + e.getMessage());
throw new CustomWebServiceException(
Response.Status.INTERNAL_SERVER_ERROR, errorMessage);
} catch (CustomWebServiceException e) {
throw e;
} catch (Exception e) {
Util.tryRollback(ut);
ErrorMessage errorMessage = new ErrorMessage(
"During creation of game data, the following error(s) was(were) encountered: "
+ e.toString());
throw new CustomWebServiceException(Response.Status.BAD_REQUEST,
errorMessage);
}
}
Well, it should be called twice as per your code. Once during deserialization and once you do it yourself:
newGame.setUrl(url);
Using the same class for model and for representation is a bad idea in general.
IMHO,What you should do:
Separate your "JSON" game from the object you save in the database
Don't do validation in your setters. There is a Spring Validation for that. Use that to make sure that your JSON object is valid and then just go directly for the database.
You can use dozer to automatically convert model object to representation objects and vice versa
Edit:
Without using any libraries the easiest thing you can do is to move validation to a method in your controller:
void validateInput(Game game) throws Exception {
if (game == null) {
throw new Exception("Game object is not present in the request");
}
if (game.getUrl() == null || !game.maches({some-fancyreg-exp}) {
throw new Exception("Game URL is not valid");
}
//etc, check the rest of the fields
}
Call validateInput(game) in your controller. After that you can be sure that the input is valid. Quick and dirty. Let setters be setters.

Cleanup JSF session scope bean when application shutdown

I need to invalidate and cleanup active session objects when the JSF application shutdown or tomact shutdown. The following is the code I have written in application scoped bean
#PreDestroy
public void shutdown(){
Map appMap = FacesContext.getCurrentInstance().getExternalContext().getApplicationMap();
Map<String,HttpSession> userSessionMap=(Map<String,HttpSession>)appMap.get("USERS");
log.info("userSessionMap " + userSessionMap);
Set<Entry<String, HttpSession>> entrySet = userSessionMap.entrySet();
for(Entry<String, HttpSession> entry:entrySet){
HttpSession session = entry.getValue();
log.info("HttpSession " + session.getId() + " calling invalidate");
session.invalidate();
}
}
and the following is overwritten HttpSessionListener
#Override
public void sessionDestroyed(HttpSessionEvent se){
HttpSession session = se.getSession();
String id = session.getId();
LoginActionController controller = (LoginActionController) session.getAttribute("userInfo");
log.info("HttpSession " + id + ", LoginActionController " + controller + " is being destroyed...");
if(controller != null){
log.info("User " + controller.getUserName() + " is logged out");
String userName = controller.getUserName();
ServletContext context = session.getServletContext();
Object obj = context.getAttribute("USERS");
if(obj instanceof Map){
Map map = (Map) obj;
map.remove(userName);
RWFacade rWFacade =(RWFacade)session.getAttribute("rWFacade");
rWFacade.closeFacade();
}
}
}
when run this code
session.invalidate();
is not getting executed. I missed anything ? Thanks.
To disable session persitence across restart in tomcat you can uncomment a config in
$TOMCAT_HOME/conf/context.xml
<!-- Uncomment this to disable session persistence across Tomcat restarts
<Manager pathname="" /> -->
May be it will help you.

Seam Hibernate Serves same EntityManger instance to two separate threads

I am new to the Java / Hibernate / Seam way of development but I appear to have a strange issue with Hibernate and concurrent threads.
I have a application scoped Seam component which is executed via EJB timers at a set interval (Orchestrator.java) calling the method startProcessingWorkloads.
This method has a injected EntityManager which it uses to check the database for a collection of data, and if it finds a work collection it creates a new Asynchronous Seam component (LoadContoller.java) and executes the start() method on the Controller
LoadController has EntityManager injected and use it to perform a very large transaction (About one hour)
Once the LoadController is running as a separate thread, the Orchestrator is still being executed as a thread at a set interval, so for example
1min
Orchestrator - Looks for work collection (None found) (thread 1)
2min
Orchestrator - Looks for work collection (finds one, Starts LoadController) (thread 1)
LoadController - Starts updating database records (thread 2)
3min
Orchestrator - Looks for work collection (None found) (thread 1)
LoadController - Still updating database records (thread 2)
4min
Orchestrator - Looks for work collection (None found) (thread 1)
LoadController - Still updating database records (thread 2)
5min
Orchestrator - Looks for work collection (None found) (thread 1)
LoadController - Done updating database records (thread 2)
6min
Orchestrator - Looks for work collection (None found) (thread 1)
7min
Orchestrator - Looks for work collection (None found) (thread 1)
However, I am receiving a intermittent error (See below) when the Orchestrator runs concurrently with the LoadController.
5:10:40,852 WARN [AbstractBatcher]
exception clearing
maxRows/queryTimeout
java.sql.SQLException: Connection is
not associated with a managed
connection.org.jboss.resource.adapter.jdbc.jdk6.WrappedConnectionJDK6#1fcdb21
This error is thrown after the Orchestrator has completed its SQl query and as the LoadController attempts to execute its next SQl query.
I did some research I came to the conclusion that the EntityManager was being closed hence the LoadController was unable to use it.
Now confused as to what exactly closed the connection I did some basic object dumps of the entity manager objects used by the Orchestrator and the LoadController when each of the components are called and I found that just before I receive the above error this happens.
2010-07-30 15:06:40,804 INFO
[processManagement.LoadController]
(pool-15-thread-2)
org.jboss.seam.persistence.EntityManagerProxy#7e3da1
2010-07-30 15:10:40,758 INFO
[processManagement.Orchestrator]
(pool-15-thread-1)
org.jboss.seam.persistence.EntityManagerProxy#7e3da1
It appears that during one of the Orchestrator execution intervals it obtains a reference to the same EntityManager that the LoadController is currently using. When the Orchestrator completes its SQL execution it closes the connection and than LoadController can no longer execute its updates.
So my question is, does any one know of this happening or having I got my threading all mucked up in this code?
From my understanding when injecting a EntityManager a new instance is injected from the EntityManagerFactory which remains with that particualr object until object leaves scope (in this case they are stateless so when the start() methods ends), how could the same instance of a entity manager be injected into two separate threads?
Orchestrator.java
#Name("processOrchestrator")
#Scope(ScopeType.APPLICATION)
#AutoCreate
public class Orchestrator {
//___________________________________________________________
#Logger Log log;
#In EntityManager entityManager;
#In LoadController loadController;
#In WorkloadManager workloadManager;
//___________________________________________________________
private int fProcessInstanceCount = 0;
//___________________________________________________________
public Orchestrator() {}
//___________________________________________________________
synchronized private void incrementProcessInstanceCount() {
fProcessInstanceCount++;
}
//___________________________________________________________
synchronized private void decreaseProcessInstanceCount() {
fProcessInstanceCount--;
}
//___________________________________________________________
#Observer("controllerExceptionEvent")
synchronized public void controllerExceptionListiner(Process aProcess, Exception aException) {
decreaseProcessInstanceCount();
log.info(
"Controller " + String.valueOf(aProcess) +
" failed with the error [" + aException.getMessage() + "]"
);
Events.instance().raiseEvent(
Application.ApplicationEvent.applicationExceptionEvent.name(),
aException,
Orchestrator.class
);
}
//___________________________________________________________
#Observer("controllerCompleteEvent")
synchronized public void successfulControllerCompleteListiner(Process aProcess, long aWorkloadId) {
try {
MisWorkload completedWorklaod = entityManager.find(MisWorkload.class, aWorkloadId);
workloadManager.completeWorkload(completedWorklaod);
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
}
decreaseProcessInstanceCount();
log.info("Controller " + String.valueOf(aProcess) + " completed successfuly");
}
//___________________________________________________________
#Asynchronous
public void startProcessingWorkloads(#IntervalDuration long interval) {
log.info("Polling for workloads.");
log.info(entityManager.toString());
try {
MisWorkload pendingWorkload = workloadManager.getNextPendingWorkload();
if (pendingWorkload != null) {
log.info(
"Pending Workload found (Workload_Id = " +
String.valueOf(pendingWorkload.getWorkloadId()) +
"), starting process controller."
);
Process aProcess = pendingWorkload.retriveProcessIdAsProcess();
ControllerIntf controller = createWorkloadController(aProcess);
if (controller != null) {
controller.start(aProcess, pendingWorkload.getWorkloadId());
workloadManager.setWorkloadProcessing(pendingWorkload);
}
}
} catch (Exception ex) {
Events.instance().raiseEvent(
Application.ApplicationEvent.applicationExceptionEvent.name(),
ex,
Orchestrator.class
);
}
log.info("Polling complete.");
}
//___________________________________________________________
private ControllerIntf createWorkloadController(Process aProcess) {
ControllerIntf newController = null;
switch(aProcess) {
case LOAD:
newController = loadController;
break;
default:
log.info(
"createWorkloadController() does not know the value (" +
aProcess.name() +
") no controller will be started."
);
}
// If a new controller is created than increase the
// count of started controllers so that we know how
// many are running.
if (newController != null) {
incrementProcessInstanceCount();
}
return newController;
}
//___________________________________________________________
}
LoadController.java
#Name("loadController")
#Scope(ScopeType.STATELESS)
#AutoCreate
public class LoadController implements ControllerIntf {
//__________________________________________________
#Logger private Log log;
#In private EntityManager entityManager;
//__________________________________________________
private String fFileName = "";
private String fNMDSFileName = "";
private String fAddtFileName = "";
//__________________________________________________
public LoadController(){ }
//__________________________________________________
#Asynchronous
synchronized public void start(Process aProcess, long aWorkloadId) {
log.info(
LoadController.class.getName() +
" process thread was started for WorkloadId [" +
String.valueOf(aWorkloadId) + "]."
);
log.info(entityManager.toString());
try {
Query aQuery = entityManager.createQuery(
"from MisLoad MIS_Load where Workload_Id = " + String.valueOf(aWorkloadId)
);
MisLoad misLoadRecord = (MisLoad)aQuery.getSingleResult();
fFileName =
misLoadRecord.getInitiatedBy().toUpperCase() + "_" +
misLoadRecord.getMdSourceSystem().getMdState().getShortName() + "_" +
DateUtils.now(DateUtils.FORMAT_FILE) + ".csv"
;
fNMDSFileName = "NMDS_" + fFileName;
fAddtFileName = "Addt_" + fFileName;
createDataFile(misLoadRecord.getFileContents());
ArrayList<String>sasCode = generateSASCode(
misLoadRecord.getLoadId(),
misLoadRecord.getMdSourceSystem().getPreloadFile()
);
//TODO: As the sas password will be encrypted in the database, we will
// need to decrypt it before passing to the below function
executeLoadSASCode(
sasCode,
misLoadRecord.getInitiatedBy(),
misLoadRecord.getSasPassword()
);
createWorkloadContentRecords(aWorkloadId, misLoadRecord.getLoadId());
//TODO: Needs to remove password from DB when complete
removeTempCSVFiles();
Events.instance().raiseEvent(
Application.ApplicationEvent.controllerCompleteEvent.name(),
aProcess,
aWorkloadId
);
log.info(LoadController.class.getName() + " process thread completed.");
} catch (Exception ex) {
Events.instance().raiseEvent(
Application.ApplicationEvent.controllerExceptionEvent.name(),
aProcess,
ex
);
}
}
//__________________________________________________
private void createDataFile(byte[] aFileContent) throws Exception {
File dataFile =
new File(ECEConfig.getConfiguration().sas_tempFileDir() + "\\" + fFileName);
FileUtils.writeBytesToFile(dataFile, aFileContent, true);
}
//__________________________________________________
private ArrayList<String> generateSASCode(long aLoadId, String aSourceSystemPreloadSasFile) {
String sasTempDir = ECEConfig.getConfiguration().sas_tempFileDir();
ArrayList<String> sasCode = new ArrayList<String>();
sasCode.add("%let sOracleUserId = " + ECEConfig.getConfiguration().oracle_username() + ";");
sasCode.add("%let sOraclePassword = " + ECEConfig.getConfiguration().oracle_password() + ";");
sasCode.add("%let sOracleSID = " + ECEConfig.getConfiguration().oracle_sid() + ";");
sasCode.add("%let sSchema = " + ECEConfig.getConfiguration().oracle_username() + ";");
sasCode.add("%let sECESASSourceDir = " + ECEConfig.getConfiguration().sas_sourceDir() + ";");
sasCode.add("libname lOracle ORACLE user=&sOracleUserId pw=&sOraclePassword path=&sOracleSID schema=&sSchema;");
sasCode.add("%let sCommaDelimiter = %str(" + ECEConfig.getConfiguration().dataload_csvRawDataFileDelimiter() + ");");
sasCode.add("%let sPipeDelimiter = %nrquote(" + ECEConfig.getConfiguration().dataload_csvNMDSDataFileDelimiter() + ");");
sasCode.add("%let sDataFileLocation = " + sasTempDir + "\\" + fFileName + ";");
sasCode.add("%let sNMDSOutputDataFileLoc = " + sasTempDir + "\\" + fNMDSFileName + ";");
sasCode.add("%let sAddtOutputDataFileLoc = " + sasTempDir + "\\" + fAddtFileName + ";");
sasCode.add("%let iLoadId = " + String.valueOf(aLoadId) + ";");
sasCode.add("%include \"&sECESASSourceDir\\ECE_UtilMacros.sas\";");
sasCode.add("%include \"&sECESASSourceDir\\" + aSourceSystemPreloadSasFile + "\";");
sasCode.add("%include \"&sECESASSourceDir\\ECE_NMDSLoad.sas\";");
sasCode.add("%preload(&sDataFileLocation, &sCommaDelimiter, &sNMDSOutputDataFileLoc, &sAddtOutputDataFileLoc, &sPipeDelimiter);");
sasCode.add("%loadNMDS(lOracle, &sNMDSOutputDataFileLoc, &sAddtOutputDataFileLoc, &sPipeDelimiter, &iLoadId);");
return sasCode;
}
//__________________________________________________
private void executeLoadSASCode(
ArrayList<String> aSasCode, String aUserName, String aPassword) throws Exception
{
SASExecutor aSASExecutor = new SASExecutor(
ECEConfig.getConfiguration().sas_server(),
ECEConfig.getConfiguration().sas_port(),
aUserName,
aPassword
);
aSASExecutor.execute(aSasCode);
log.info(aSASExecutor.getCompleteSasLog());
}
//__________________________________________________
/**
* Creates the MIS_UR_Workload_Contents records for
* the ECE Unit Record data that was just loaded
*
* #param aWorkloadId
* #param aMisLoadId
* #throws Exception
*/
private void createWorkloadContentRecords(long aWorkloadId, long aMisLoadId) throws Exception {
String selectionRule =
" from EceUnitRecord ECE_Unit_Record where ECE_Unit_Record.loadId = " +
String.valueOf(aMisLoadId)
;
MisWorkload misWorkload = entityManager.find(MisWorkload.class, aWorkloadId);
SeamManualTransaction manualTx = new SeamManualTransaction(
entityManager,
ECEConfig.getConfiguration().manualSeamTxTimeLimit()
);
manualTx.begin();
RecordPager oPager = new RecordPager(
entityManager,
selectionRule,
ECEConfig.getConfiguration().recordPagerDefaultPageSize()
);
Object nextRecord = null;
while ((nextRecord = oPager.getNextRecord()) != null) {
EceUnitRecord aEceUnitRecord = (EceUnitRecord)nextRecord;
MisUrWorkloadContents aContentsRecord = new MisUrWorkloadContents();
aContentsRecord.setEceUnitRecordId(aEceUnitRecord.getEceUnitRecordId());
aContentsRecord.setMisWorkload(misWorkload);
aContentsRecord.setProcessOutcome('C');
entityManager.persist(aContentsRecord);
}
manualTx.commit();
}
/**
* Removes the CSV temp files that are created for input
* into the SAS server and that are created as output.
*/
private void removeTempCSVFiles() {
String sasTempDir = ECEConfig.getConfiguration().sas_tempFileDir();
File dataInputCSV = new File(sasTempDir + "\\" + fFileName);
File nmdsOutputCSV = new File(sasTempDir + "\\" + fNMDSFileName);
File addtOutputCSV = new File(sasTempDir + "\\" + fAddtFileName);
if (dataInputCSV.exists()) {
dataInputCSV.delete();
}
if (nmdsOutputCSV.exists()) {
nmdsOutputCSV.delete();
}
if (addtOutputCSV.exists()) {
addtOutputCSV.delete();
}
}
}
SeamManualTransaction.java
public class SeamManualTransaction {
//___________________________________________________________
private boolean fObjectUsed = false;
private boolean fJoinExistingTransaction = true;
private int fTransactionTimeout = 60; // Default: 60 seconds
private UserTransaction fUserTx;
private EntityManager fEntityManager;
//___________________________________________________________
/**
* Set the transaction timeout in milliseconds (from minutes)
*
* #param aTimeoutInMins The number of minutes to keep the transaction active
*/
private void setTransactionTimeout(int aTimeoutInSecs) {
// 60 * aTimeoutInSecs = Timeout in Seconds
fTransactionTimeout = 60 * aTimeoutInSecs;
}
//___________________________________________________________
/**
* Constructor
*
* #param aEntityManager
*/
public SeamManualTransaction(EntityManager aEntityManager) {
fEntityManager = aEntityManager;
}
//___________________________________________________________
/**
* Constructor
*
* #param aEntityManager
* #param aTimeoutInSecs
*/
public SeamManualTransaction(EntityManager aEntityManager, int aTimeoutInSecs) {
setTransactionTimeout(aTimeoutInSecs);
fEntityManager = aEntityManager;
}
//___________________________________________________________
/**
* Constructor
*
* #param aEntityManager
* #param aTimeoutInSecs
* #param aJoinExistingTransaction
*/
public SeamManualTransaction(EntityManager aEntityManager, int aTimeoutInSecs, boolean aJoinExistingTransaction) {
setTransactionTimeout(aTimeoutInSecs);
fJoinExistingTransaction = aJoinExistingTransaction;
fEntityManager = aEntityManager;
}
//___________________________________________________________
/**
* Starts the new transaction
*
* #throws Exception
*/
public void begin() throws Exception {
if (fObjectUsed) {
throw new Exception(
SeamManualTransaction.class.getCanonicalName() +
" has been used. Create new instance."
);
}
fUserTx =
(UserTransaction) org.jboss.seam.Component.getInstance("org.jboss.seam.transaction.transaction");
fUserTx.setTransactionTimeout(fTransactionTimeout);
fUserTx.begin();
/* If entity manager is created before the transaction
* is started (ie. via Injection) then it must join the
* transaction
*/
if (fJoinExistingTransaction) {
fEntityManager.joinTransaction();
}
}
//___________________________________________________________
/**
* Commit the transaction to the database
*
* #throws Exception
*/
public void commit() throws Exception {
fObjectUsed = true;
fUserTx.commit();
}
//___________________________________________________________
/**
* Rolls the transaction back
*
* #throws Exception
*/
public void rollback() throws Exception {
fObjectUsed = true;
fUserTx.rollback();
}
//___________________________________________________________
}
In general, injecting an entityManager in a Seam component of scope APPLICATION is not right. An entity manager is something you create, use and close again, in a scope typically much shorter than APPLICATION scope.
Improve by choosing smaller scopes with a standard entityManager injection, or if you need the APPLICATION scope, inject an EntityManagerFactory instead, and create, use and close the entityManager yourself.
Look in your Seam components.xml to find the name of your EntityManagerFactory compoment.
Well, my first is advice is
If you are using an EJB application, prefer To use a Bean Managed Transaction instead of your custom SeamManualTransaction. When you use a Bean Managed Transaction, you, as a developer, Take care of calling begin and commit. You get this feature by using an UserTransaction component. You can create a Facade layer which begins and commit your Transaction. Something like
/**
* default scope when using #Stateless session bean is ScopeType.STATELESS
*
* So you do not need to declare #Scope(ScopeType.STATELESS) anymore
*
* A session bean can not use both BEAN and CONTAINER Transaction management at The same Time
*/
#Stateless
#Name("businessFacade")
#TransactionManagement(TransactionManagerType.BEAN)
public class BusinessFacade implements BusinessFacadeLocal {
private #Resource TimerService timerService;
private #Resource UserTransaction userTransaction;
/**
* You can use #In of you are using Seam capabilities
*/
private #PersistenceContext entityManager;
public void doSomething() {
try {
userTransaction.begin();
userTransaction.setTransactionTimeout(int seconds);
// business logic goes here
/**
* To enable your Timer service, just call
*
* timerService.createTimer(15*60*1000, 15*60*1000, <ANY_SERIALIZABLE_INFO_GOES_HERE>);
*/
userTransaction.commit();
} catch (Exception e) {
userTransaction.rollback();
}
}
#Timeout
public void doTimer(Timer timer) {
try {
userTransaction.begin();
timer.getInfo();
// logic goes here
userTransaction.commit();
} catch (Exception e) {
userTransaction.rollback();
}
}
}
Let's see UserTransaction.begin method API
Create a new transaction and associate it with the current thread
There is more:
The lifetime of a container-managed persistence context (injected Through #PersistenceContext annotation) corresponds to the scope of a transaction (between begin and commit method call) when using transaction-scoped persistence context
Now Let's see TimerService
It is a container-provided service that allows enterprise beans to be registered for
timer callback methods to occur at a specified time, after a specified elapsed time, or after specified intervals. The bean class of an enterprise bean that uses the timer
service must provide a timeout callback method. Timers can be created for stateless session beans, message-driven beans
I hope It can be useful To you

Categories

Resources