I'm currently having an issue with stopping a background thread in a webachive. I currently tie it in the war's deployment, and destroy it when the archive is un-deployed.
The threads starts up without issue, but when I close the archive, It seems to lose the handle on the thread. In the below case: st is null when the contextDestroyed method is called.
This is an issue as Tomcat notes the thread as orphaned in its warning about memory leaks.
public class LimitOrderContextListener implements ServletContextListener {
static Logger logger = Logger.getLogger(LimitOrderRuntime.class.getName());
private SwiftThread st = null;
/**
* Initializes this listener when this war's context is initialized
*/
public void contextInitialized(ServletContextEvent sce)
{
try {
if ( (st == null) || (!st.isAlive()) ) {
LimitOrderRuntime lor = new LimitOrderRuntime();
SwiftThread st = new SwiftThread(lor);
st.start();
} else {
st.gracefulStop();
st.join(2000);
}
} catch(Exception e) {
logger.warn("Unable to properly load thread! " +
e.getMessage() + " --cause " + e.getCause());
e.printStackTrace();
}
}
/**
* When this war is destroyed/stopped, stop the thread.
*/
public void contextDestroyed(ServletContextEvent sce)
{
try {
boolean success = st.gracefulStop();
if (!success) {
st.interrupt();
}
} catch (Exception e) {
logger.warn("Unable to properly release thread! " +
e.getMessage() + " --cause " + e.getCause());
e.printStackTrace();
}
}
}
In your contextInitialized method, you're redeclaring st as a local variable, rather than initializing the instance variable with the thread.
Replace
SwiftThread st = new SwiftThread(lor);
with
this.st = new SwiftThread(lor);
Related
I am creating a Javafx chat app which also allows for file transfer. My issue is I open a FileOutputStream for the received file within the below method. I can see my listener.statusTransferring() updating the UI only if I enable Platform.runLater. I think I now need to enable the same on the fos.write(b, 0, tmpTransferred) within the while loop but don't know how to do this. I have tried unsuccessfully wrapping the whole method within Platform runlater. Note: If I don't use platform runlater I don't get any errors however the UI does not update until the file transfer is complete eg listener.statusCompleted() is called;. The error I get now as a result of the fos being in Platform runlater. is below.. Line 185 is fos.write(b, 0, tmpTransferred); The other listener calls appear to work fine. Just not listener.statusTransferring(); or listener.transferUpdate(); which utilise the fos. Any help will be greatly appreciated. Also for your own sanity I am a self taught google programmer. Yep the worst kind I am sure. Thanks in advance.
Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
at net.thebowdens.net.FileReceiver.transfer(FileReceiver.java:185)
at net.thebowdens.net.DefaultMessageResponder.fileSend(DefaultMessageResponder.java:543)
public boolean transfer() {
listener.statusConnecting();
received = false;
cancel = false;
try {
if (sSock != null) {
sock = sSock.accept();
listener.statusTransferring();
Platform.runLater(() ->{
try {
fos = new FileOutputStream(file);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
});
is = sock.getInputStream();
final byte[] b = new byte[1024];
transferred = 0;
percent = 0;
int tmpTransferred = 0;
int tmpPercent = 0;
int transCounter = 0;
bCounter.prepare();
while (!cancel && (tmpTransferred = is.read(b)) != -1) {
fos.write(b, 0, tmpTransferred);
transferred += tmpTransferred;
percent = (int) ((transferred * 100) / size);
bCounter.addBytes(tmpTransferred);
transCounter++;
if (percent > tmpPercent || transCounter >= 250) {
transCounter = 0;
tmpPercent = percent;
listener.transferUpdate();
}
}
if (!cancel && transferred == size) {
received = true;
listener.statusCompleted();
}
else {
listener.statusFailed();
}
}
}
catch (final IOException e) {
LOG.log(Level.SEVERE, e.toString());
listener.statusFailed();
}
finally {
stopReceiver();
cleanupConnections();
}
return received;
}
Keep in mind that you should use Platform.runLater only for updating the UI, everything else should be outside it otherwhise the UI will become unresponsive.
I suggest you to to refactor your code according to this.
Well after much discussion over the correct language and other issues I solved my problem of the UI updating. I had two issues. My choice selector and Filechooser methods were not on the Javafx application thread (hope this is the right terminology) so I had to do the following:
private ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(new Runnable() {
#Override
public void run() {
Platform.runLater(() -> {
try {
receiveRequest(tmpUser, fileRes, user, fileName, size, fileHash);
} catch (IOException | ServerException | CommandException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
});
}
});
I then had to do the same within the Filechooser and file accept method for the transfer class UI to update
executorService.execute(new Runnable() {
#Override public void run() {
if (fileRes.transfer()) {
ui.showSystemMessage("Successfully received " + fileName +
" from " + user + ", and saved as " + fileRes.getFile().getName());
}
else {
ui.showSystemMessage("Failed to receive " + fileName + " from " + user);
fileRes.cancel();
}
}
});
}
I need to send notifications from time to time, I perform this task asynchronously. I'm using HystrixCommand as below to perform an asynchronous RestTemplate call which is not working:
#HystrixCommand
public Future<String> notify(final Query query) {
return new AsyncResult<String>() {
#Override
public String invoke() {
String result = null;
try {
ResponseEntity<HashMap> restExchange = restTemplate.exchange(url,
HttpMethod.POST,
new HttpEntity<String>(mapper.writeValueAsString(queryMap), httpHeaders),
HashMap.class);
LOGGER.info("Response code from " + url + " = " + restExchange.getStatusCodeValue());
result = ""+ restExchange.getStatusCodeValue();
} catch(Exception e) {
LOGGER.error("Exception while sending notification! Message = " + e.getMessage(), e);
}
return result;
}
};
}
This is what I was trying to do earlier(which didn't work either):
#HystrixCommand
public String notify(final Query query) {
new Thread(new Runnable() {
#Override
public void run() {
try {
ResponseEntity<HashMap> restExchange = restTemplate.exchange(url, HttpMethod.POST,
new HttpEntity<String>(mapper.writeValueAsString(queryMap), httpHeaders), HashMap.class);
LOGGER.info("Response code from " + url + " = " + restExchange.getStatusCodeValue());
} catch (Exception e) {
LOGGER.error("Exception while sending notification! Message = " + e.getMessage(), e);
}
}
}).start();
}
P.S: Reason for adding sleuth to the tags is, performing this in a new Thread does not propagate the headers(baggage-*) so trying this hoping the Hystrix command will do the trick
Is the method notify being called from a method in the same class? If that is the case, try calling the method notify directly from a different class where the notify method's enclosing class is injected as a dependency.
Basically, try doing this:
Instead of this:
When using Runnable you have to wrap them in a trace representation. i.e. TraceRunnable. It's there in the docs - http://cloud.spring.io/spring-cloud-sleuth/spring-cloud-sleuth.html#_runnable_and_callable .
As for why the Hystrix stuff doesn't work - most likely it's related to https://github.com/spring-cloud/spring-cloud-sleuth/issues/612 .
I am receiving strings from my server that I want to append into a Textarea on the client side (Think chat window). Problem is, when I receive the string, the client freezes.
insertUserNameButton.setOnAction((event) -> {
userName=userNameField.getText();
try {
connect();
} catch (IOException e) {
e.printStackTrace();
}
});
public Client() {
userInput.setOnAction((event) -> {
out.println(userInput.getText());
userInput.setText("");
});
}
private void connect() throws IOException {
String serverAddress = hostName;
Socket socket = new Socket(serverAddress, portNumber);
in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
while (true) {
String line = in.readLine();
if (line.startsWith("SUBMITNAME")) {
out.println(userName);
} else if (line.startsWith("MESSAGE")) {
Platform.runLater(()->serverOutput.appendText(line.substring(8) + "\n"));
} else if (line.startsWith("QUESTION")) {
Platform.runLater(()->serverOutput.appendText(line.substring(8) + "\n"));
} else if (line.startsWith("CORRECTANSWER")) {
Platform.runLater(()->serverOutput.appendText(line.substring(14) + "\n"));
}
}
}
public static void main(String[] args) {
launch(args);
}
I have done some research and it seems that using Platform.runLater on each append should fix the problem. It doesn't for me.
Anyone has an idea of what it can be caused by? Thank you!
You are calling connect() on the FX Application Thread. Since it blocks indefinitely via the
while(true) {
String line = in.readLine();
// ...
}
construct, you block the FX Application Thread and prevent it from doing any of its usual work (rendering the UI, responding to user events, etc).
You need to run this on a background thread. It's best to use a Executor to manage the threads:
private final Executor exec = Executors.newCachedThreadPool(runnable -> {
Thread t = new Thread(runnable);
t.setDaemon(true);
return t ;
});
and then do
insertUserNameButton.setOnAction((event) -> {
userName=userNameField.getText();
exec.execute(() -> {
try {
connect();
} catch (IOException e) {
e.printStackTrace();
}
});
});
I have java SE sample client which run on desktop (code below). But I have access to WebSphere were called EJB is deployed. How to rewrite below code to work on WebSphere? (When I leave this code just like it is program works but I think this can be done more simple and clear)
Main method:
WSConn connection = new WSConn();
final Plan plan = connection.getPlanBean();
com.ibm.websphere.security.auth.WSSubject.doAs(connection.getSubject(), new java.security.PrivilegedAction<Object>() {
public Object run() {
try {
// App logic
} catch (Throwable t) {
System.err.println("PrivilegedAction - Error calling EJB: " + t);
t.printStackTrace();
}
return null;
}
}); // end doAs
WSConn class:
public class WSConn {
private static final String INITIAL_CONTEXT_FACTORY = "com.ibm.websphere.naming.WsnInitialContextFactory";
private static final String JAAS_MODULE = "WSLogin";
private static final String MODEL_EJB_NAME_LONG = "ejb/com/ibm/ModelHome";
private static final String PLAN_EJB_NAME_LONG = "ejb/com/ibm/PlanHome";
private Subject subject;
private InitialContext initialContext;
private String serverName;
private String serverPort;
private String uid;
private String pwd;
private String remoteServerName;
private Model modelBean;
private Plan planBean;
public WSConn() {
Properties props = new Properties();
try {
props.load(WSConn.class.getClassLoader().getResourceAsStream("WSConn.properties"));
} catch (IOException e) {
e.printStackTrace();
}
serverName = props.getProperty("WSConn.serverName");
serverPort = props.getProperty("WSConn.serverPort");
uid = props.getProperty("WSConn.userID");
pwd = props.getProperty("WSConn.password");
remoteServerName = props.getProperty("WSConn.remoteServerName");
}
private void init() {
if (subject == null || initialContext == null) {
subject = login();
}
}
private Subject login() {
Subject subject = null;
try {
LoginContext lc = null;
// CRATE LOGIN CONTEXT
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, INITIAL_CONTEXT_FACTORY);
env.put(Context.PROVIDER_URL, "corbaloc:iiop:" + serverName + ":" + serverPort);
initialContext = new InitialContext(env);
// Just to test the connection
initialContext.lookup("");
lc = new LoginContext(JAAS_MODULE, new WSCallbackHandlerImpl(uid, pwd));
lc.login();
subject = lc.getSubject();
} catch (javax.naming.NoPermissionException exc) {
System.err.println("[WSConn] - Login Error: " + exc);
} catch (Exception exc) {
System.err.println("[WSConn] - Error: " + exc);
}
return subject;
}
public wModel getModelBean() {
if (modelBean == null) {
init();
modelBean = (wModel) com.ibm.websphere.security.auth.WSSubject.doAs(subject,
new java.security.PrivilegedAction<wModel>() {
public wModel run() {
wModel session = null;
try {
Object o = initialContext.lookup(MODEL_EJB_NAME_LONG);
wModelHome home = (wModelHome) PortableRemoteObject.narrow(o, wModelHome.class);
if (home != null) {
session = home.create(remoteServerName);
}
} catch (Exception exc) {
System.err.println("Error getting model bean: " + exc);
}
return session;
}
}); // end doAs
}
return modelBean;
}
public wPlan getPlanBean() {
if (planBean == null) {
init();
planBean = (wPlan) com.ibm.websphere.security.auth.WSSubject.doAs(subject,
new java.security.PrivilegedAction<wPlan>() {
public wPlan run() {
wPlan session = null;
try {
Object o = initialContext.lookup(PLAN_EJB_NAME_LONG);
wPlanHome home = (wPlanHome) PortableRemoteObject.narrow(o, wPlanHome.class);
if (home != null) {
session = home.create(remoteServerName);
}
} catch (Exception exc) {
System.err.println("Error getting plan bean: " + exc);
}
return session;
}
}); // end doAs
}
return planBean;
}
public Subject getSubject() {
if (subject == null) {
init();
}
return subject;
}
}
As indicated in another answer, the classic mechanism is to lookup and narrow the home interface.
Get the initial context
final InitialContext initialContext = new InitialContext();
Lookup for the home by jndi name, specifying either the full jndi name
Object obj = initialContext.lookup("ejb/com/ibm/tws/conn/plan/ConnPlanHome");
or you can create e reference in your WAR and use java:comp/env/yourname
Then narrow the home to the home interface class
ConnPlanHome planHome = (ConnPlanHome)PortableRemoteObject.narrow(obj, ConnPlanHome.class);
and then create the EJB remote interface
ConnPlan plan = planHome.create();
The about calls should work for IBM Workload Scheduler distributed.
For IBM Workload Scheduler z/OS the JNDI name and the class names are different:
final InitialContext initialContext = new InitialContext();
String engineName = "XXXX";
Object obj = initialContext.lookup("ejb/com/ibm/tws/zconn/plan/ZConnPlanHome");
ZConnPlanHome planHome = (ZConnPlanHome)PortableRemoteObject.narrow(obj, ZConnPlanHome.class);
ZConnPlan plan = planHome.create(engineName);
User credentials are propagated from the client to the engine, the client need to be authenticated otherwise the engine will reject the request.
If you're trying to access an EJB from a POJO class, then there is nothing more simple than lookup+narrow. However, if the POJO is included in an application (EAR or WAR), then you could declare and lookup an EJB reference (java:comp/ejb/myEJB), and then the container would perform the narrow rather than your code. If you change your code to be a managed class like a servlet, another EJB, or a CDI bean, then you could use #EJB injection, and then you would not even need a lookup.
Can anybody help telling me what is wrong with my code? I am trying to connect to SQLite database, and executing some queries. when trying to create and open the database, create and insert the table, no exception returned. but when I try to execute delete statement,
DatabaseIOException: File system error (12)
always returned. I don't know the cause of the exception exactly. would you tell me what usually cause this kind of exception? I don't even know when I need to close the database and when I don't need to. this solution also makes me confused.
here is my code:
public class DatabaseManager {
Logger log = new Logger();
Database db;
public DatabaseManager() {
createDatabase();
}
private void createDatabase() {
// Determine if an SDCard is present
boolean sdCardPresent = false;
String root = null;
Enumeration enum = FileSystemRegistry.listRoots();
while (enum.hasMoreElements()) {
root = (String) enum.nextElement();
if(root.equalsIgnoreCase("sdcard/")) {
sdCardPresent = true;
}
}
if(!sdCardPresent) {
alert("This application requires an SD card to be present. Exiting application...");
}
else {
try {
URI uri = URI.create("/SDCard/databases/MyAdvanceUI/myadvanceui.db");
db = DatabaseFactory.openOrCreate(uri);
db.close();
//alert("Database OK!");
} catch (Exception e) {
// TODO Auto-generated catch block
//alert("Exception in createDatabase(): " + e);
}
}
}
private void alert(final String message) {
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
Dialog.inform(message);
System.exit(0);
}
});
}
private void createTableTask() {
try {
URI uri = URI.create("/SDCard/databases/MyAdvanceUI/myadvanceui.db");
db = DatabaseFactory.open(uri);
Statement st = db.createStatement("CREATE TABLE IF NOT EXISTS t_task (id INTEGER PRIMARY KEY AUTOINCREMENT, "
+ "client TEXT, task TEXT)");
st.prepare();
st.execute();
st.close();
db.close();
//alert("Table Task created!");
} catch (Exception e) {
// TODO: handle exception
//alert("Exception in createTableTask(): " + e);
}
}
private void insertTableTask() {
String[] clients = { "Budi Setiawan", "Dian Kusuma", "Joko Ahmad", "Titi Haryanto", "Wahyu" };
String[] tasks = {
"Penawaran terhadap instalasi server",
"Follow up untuk keperluan produk terbaru",
"Pendekatan untuk membina relasi",
"Penawaran jasa maintenance",
"Penawaran terhadap instalasi database"
};
try {
URI uri = URI.create("/SDCard/databases/MyAdvanceUI/myadvanceui.db");
db = DatabaseFactory.open(uri);
for(int i = 0; i < clients.length; i++) {
Statement st = db.createStatement("INSERT INTO t_task (client, task) VALUES (?, ?)");
st.prepare();
st.bind(1, clients[i]);
st.bind(2, tasks[i]);
st.execute();
st.close();
}
db.close();
} catch (Exception e) {
// TODO: handle exception
//alert("Exception in insertTableTask(): " + e);
}
}
public void loadInitialData() {
createTableTask();
insertTableTask();
}
public Cursor getTasks() {
// TODO Auto-generated method stub
Cursor results = null;
try {
URI uri = URI.create("/SDCard/databases/MyAdvanceUI/myadvanceui.db");
db = DatabaseFactory.open(uri);
Statement st = db.createStatement("SELECT client, task FROM t_task");
st.prepare();
results = st.getCursor();
return results;
} catch (Exception e) {
// TODO: handle exception
//alert("Exception: " + e);
}
return results;
}
public void delete(String string) {
// TODO Auto-generated method stub
try {
URI uri = URI.create("/SDCard/databases/MyAdvanceUI/myadvanceui.db");
db = DatabaseFactory.open(uri);
Statement st = db.createStatement("DELETE FROM t_task WHERE client=?");
st.prepare();
st.bind(1, string);
st.execute();
} catch (Exception e) {
// TODO: handle exception
alert("Exception: " + e);
}
}
}
thank you for your help.
I don't see that you close the statement and close the database after select and delete actions. Most probably you can't open database because it wasn't closed correctly.
Big warning SD card isn't available when user mounted devices to PC as external drive. Some devices are going without SD card preinstalled. DB operations are really slow on 5 OS devices. Your alert method code wan't close db what could be issue to open it after on the next application start.
Warning As #pankar mentioned in comment you should add finally {} where you will close resources for sure. In your current implementation if you get exception in execution you will never close database.
Big improvements You don't need to create and prepare statement every loop. Just do it before for. Do bind and execute every loop. And close statement after for.
Improvements You could keep one opened db during application run cycle. It will save you some line of code and time for opening closing.
Notation It's bad practice to have parameter named like 'string'. I would rename it to something more meaningful.