We know the servlet instance is created once and based on multiple user requests to the servlet , container creates threads to address each of the user request.
What if I have stored procedure in the servlet which is multithreaded. The stored procedure takes the parameters from the user request and generates output for that user alone.
What if ,i have multiple users request coming at same time. Does procedure results generated by user1 will be overwritten by another user request as each thread have its own execution flow. please help to understand.
I have given simple example end to end which I'm trying. here i didn't use synchronization
public class Demo {
public static void main(String[] args) {
DBThread db = new DBThread();
//Only one instance and multiple threads
Thread request1= new Thread(db, "request1");
Thread request2= new Thread(db, "request2");
request1.start();
request2.start();
}
}
DBThread.java
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class DBThread implements Runnable {
public void getData(){
Connection con=null;
Statement statement = null;
CallableStatement callProcedure = null;
ResultSet rs = null;
try {
con = getDBConnection();
if(con==null)
System.out.println("Unable to get connection for " + Thread.currentThread().getName());
else
{
callProcedure = con.prepareCall("{call PROCEDURE1(?)}");
callProcedure.setString(1,Thread.currentThread().getName());
callProcedure.execute();
statement = con.createStatement();
rs = statement.executeQuery("select id,inputname from temp1");
while(rs.next()){
System.out.println("Thread "+Thread.currentThread().getName() +":"+ rs.getString(1) +":" + rs.getString(2));
}
}
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
finally{
try{
if(callProcedure!=null){
callProcedure.close();
}
if(rs!=null)
rs.close();
if(con!=null){
con.close();
System.out.println("Connection close for " + Thread.currentThread().getName());
}
}catch(Exception e){
System.out.println("print therea" + Thread.currentThread().getName());
}
}
}
public void run() {
this.getData();
}
public Connection getDBConnection() throws SQLException, Exception{
String user = null;
String pwd = null;
String dbURL = null;
String driverClassName = null;
Connection con = null;
if(con == null || con.isClosed() == true){
user = "readonly";
pwd = "XXXX"
dbURL = "jdbc:oracle:thin:#host:port:SID;
driverClassName = "oracle.jdbc.driver.OracleDriver";
Class.forName(driverClassName);
con = DriverManager.getConnection(dbURL, user, pwd);
}
System.out.println("Connection got for " + Thread.currentThread().getName()+ "Connection "+ con);
return con;
}
}
Oracle procedure :
create or replace
PROCEDURE PROCEDURE1(id varchar2) AS
BEGIN
DELETE from temp1;
FOR i IN 1..5 LOOP
INSERT INTO temp1 VALUES (i,id);
END LOOP;
COMMIT;
END PROCEDURE1;
Since you're using the same connection which is closed at the end of the function (finally block) then in case of parallel execution you will very likely get some SQLException inside the second thread after the first one completed.
Related
I do have a multi node spark cluster and submitting my spark program on node where master resides.
When the job submitted to worker nodes, the HOSTNAME paramter is giving null value. Here is the line where properties are being read as null.
System.getenv(HOSTNAME) is not being read from worker node.
System.out.println("line 76 System.getenv(HOSTNAME)=" + System.getenv("HOSTNAME"));
AUDIT_USER, AUDIT_PASSWORD also null when being read(they both were on properties file).
If i submit job with one node i have no issues with these parameters. But, if u submit job on standalone mode with 6 nodes i am getting this issue.
I have created the same folder for properties file on all nodes.
Here is my code. could you please let me know why System.env is not giving null and my properties are null?
package com.fb.cpd.myapp;
import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.UUID;
import java.util.concurrent.Future;
import org.apache.commons.configuration.ConfigurationConverter;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.Producer;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.clients.producer.RecordMetadata;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.spark.TaskContext;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.Function;
import org.apache.spark.streaming.Duration;
import org.apache.spark.streaming.api.java.JavaInputDStream;
import org.apache.spark.streaming.api.java.JavaStreamingContext;
import org.apache.spark.streaming.kafka.KafkaUtils;
import kafka.common.TopicAndPartition;
import kafka.message.MessageAndMetadata;
import kafka.serializer.DefaultDecoder;
import kafka.serializer.StringDecoder;
public class GenericLogic implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private static final Logger logger = LogManager.getLogger(GenericLogic.class);
private PropertiesConfiguration props;
private Producer<String, String> producer = null;
private Future<RecordMetadata> receipt = null;
private RecordMetadata receiptInfo = null;
private ConnectToRDBMS auditor = null;
private ConnectToRDBMS df = null;
private static String myId = null;
private Map<TopicAndPartition, Long> getOffsets(String topic) throws SQLException {
String appName = "myapp";
String TopicName = topic;
Map<TopicAndPartition, Long> topicMap = new HashMap<>(); //
System.out.println("line 64 before making connection");
try {
props = new PropertiesConfiguration("/app/lock/conf/empty.properties");
} catch (ConfigurationException e) { // TODO Auto-generated catch block
System.out.println("Line 70");
e.printStackTrace();
}
try {
System.out.println("line 76 System.getenv(HOSTNAME)=" + System.getenv("HOSTNAME"));
auditor = new ConnectToRDBMS(System.getenv("HOSTNAME"), "lockSparkCollector", null, null, null, null, null,
0, props.getString("AUDIT_USER"), props.getString("AUDIT_PASSWORD"),
props.getString("AUDIT_DB_URL"));
} catch (SQLException e) {
logger.error("ASSERT: run() ERROR CONNECTING TO AUDIT DB " + e.getMessage());
}
System.out.println("line 64 after making connection");
Statement stmt = null;
String query = "select va_application, topic_name, partition_id, from_offset,until_offset from lock_spark_offsets where va_application = "
+ "'" + appName + "'" + " and topic_name= " + "'" + TopicName + "'";
System.out.println("query" + query);
System.out.println("before query exection");
try {
stmt = auditor.dbConnection.createStatement();
System.out.println("line 81");
ResultSet rs = stmt.executeQuery(query);
System.out.println("line 83");
while (rs.next()) {
System.out.println("pass 1 of Resultset");
System.out.println("getOffsets=" + topic.trim() + " " + rs.getInt("partition_id") + " "
+ rs.getString("until_offset") + " " + rs.getString("until_offset"));
Integer partition = rs.getInt("partition_id");
TopicAndPartition tp = new TopicAndPartition(topic.trim(), partition);
System.out.println("102");
Long.parseLong(rs.getString("until_offset"));
topicMap.put(tp, Long.parseLong(rs.getString("until_offset")));
System.out.println("105");
}
System.out.println("after populating topic map");
} catch (
SQLException e) {
System.out.println("printing exception");
e.printStackTrace();
} finally {
if (stmt != null) {
System.out.println("closing statement");
stmt.close();
}
}
return topicMap;
}
public void setDefaultProperties() {
FileChangedReloadingStrategy strategy = new FileChangedReloadingStrategy();
strategy.setRefreshDelay(10000);
System.out.println("Line 45");
// supply the properties file.
try {
props = new PropertiesConfiguration("/app/lock/conf/empty.properties");
} catch (ConfigurationException e) {
// TODO Auto-generated catch block
System.out.println("Line 51");
e.printStackTrace();
}
props.setReloadingStrategy(strategy);
System.out.println("Line 56");
// Producer configs
if (!props.containsKey("acks")) {
props.setProperty("acks", "1");
}
if (!props.containsKey("retries")) {
props.setProperty("retries", "1000");
}
if (!props.containsKey("compression.type")) {
props.setProperty("compression.type", "gzip");
}
if (!props.containsKey("request.timeout.ms")) {
props.setProperty("request.timeout.ms", "600000");
}
if (!props.containsKey("batch.size")) {
props.setProperty("batch.size", "32768");
}
if (!props.containsKey("buffer.memory")) {
props.setProperty("buffer.memory", "134217728");
}
if (!props.containsKey("block.on.buffer.full")) {
props.setProperty("block.on.buffer.full", "true");
}
if (!props.containsKey("SHUTDOWN")) {
props.setProperty("SHUTDOWN", "false");
}
if (!props.containsKey("producer.topic")) {
props.setProperty("producer.topic", "mytopic1");
}
Properties producer_props = ConfigurationConverter.getProperties(props);
producer_props.setProperty("bootstrap.servers", props.getString("target.bootstrap.servers"));
producer_props.setProperty("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
producer_props.setProperty("value.serializer", "org.apache.kafka.common.serialization.StringSerializer"); // ????
this.producer = new KafkaProducer<String, String>(producer_props);
System.out.println("Line 107");
}
public void PublishMessages(String st) {
try {
System.out.println("Line 111");
String key = UUID.randomUUID().toString().replace("-", "");
System.out.println("Started Producing...");
receipt = producer.send(new ProducerRecord<String, String>(props.getString("producer.topic"), key, // Key
st));
System.out.println("After Completion of Producing Producing");
} catch (Exception e) {
e.printStackTrace();
System.out.println("Exception in PublishMessages ");
}
}
public void DBConnect() {
try {
auditor = new ConnectToRDBMS(System.getenv("HOSTNAME"), "myapp", props.getString("consumer.topic"), null,
null, null, null, 0, props.getString("AUDIT_USER"), props.getString("AUDIT_PASSWORD"),
props.getString("AUDIT_DB_URL"));
} catch (SQLException e) {
logger.error("ASSERT: run() ERROR CONNECTING TO AUDIT DB " + e.getMessage());
return;
}
}
private void writeToDB(Long startTime, Integer partnId, String fromOffset, String untilOffset, Integer count) {
this.auditor.audit(startTime, partnId, fromOffset, untilOffset, count);
}
/**
*
* #param jsc
* #param topicSet
* #throws Exception
*/
public static void main(String[] args) {
String topicNames = "MySourceTopic";
GenericLogic ec = new GenericLogic();
Map<TopicAndPartition, Long> topicMap = null;
try {
topicMap = ec.getOffsets("MySourceTopic");
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
boolean clusterMode = false;
Integer batchDuration = Integer.parseInt("30000");
JavaSparkContext sparkConf = new JavaSparkContext("abcd.net:7077", "Kafka-Spark-Integration");
sparkConf.getConf().set("spark.local.ip", "lock-dt-a4d.xyz.com");
sparkConf.getConf().set("spark.eventLog.enabled", "false");
sparkConf.getConf().set("spark.shuffle.blockTransferService", "nio");
JavaStreamingContext jsc = new JavaStreamingContext(sparkConf, new Duration(10000));
Map<String, String> kafkaParams = new HashMap<String, String>();
String pollInterval = "10000";
String zookeeper = "lock-dt-a5d.xyz.com:2181,lock-dt-a6d.xyz.com:2181";
kafkaParams.put("metadata.broker.list", "lock-dt-a5d.xyz.com:9092,lock-dt-a6d.xyz.com:9092");
kafkaParams.put("group.id", "Consumer");
kafkaParams.put("client.id", "Consumer");
kafkaParams.put("zookeeper.connect", zookeeper);
JavaInputDStream<byte[]> directKafkaStream = KafkaUtils.createDirectStream(jsc, String.class, byte[].class,
StringDecoder.class, DefaultDecoder.class, byte[].class, kafkaParams, topicMap,
(Function<MessageAndMetadata<String, byte[]>, byte[]>) MessageAndMetadata::message);
directKafkaStream.foreachRDD(rdd -> {
if (rdd.isEmpty()) {
System.out.println("No events polled in last " + pollInterval + " milli seconds");
return;
}
rdd.foreachPartition(itr -> {
Integer partnId = TaskContext.get().partitionId();
Long systime = System.nanoTime();
Map<String, String> hmap = new HashMap<String, String>();
GenericLogic ec2 = new GenericLogic();
ec2.setDefaultProperties();
ec2.DBConnect();
try {
while (itr.hasNext()) {
System.out.println("232");
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
});
});
jsc.start();
jsc.awaitTermination();
}
}
I started the salves with start-slaves.sh.
That's the issue. I have to start workers by supplying master addres.
Can you please let us know OS of all the nodes and if you have ensured that noting on Master node is exporting the HOSTNAME. Answering your question will be better if you let us know about your OS detail.
May not be correctly related to your context but just for information System.getenv("HOSTNAME") may not provide hostname in all the platforms (for example Ubuntu or Mac).
Better is why not export the HOSTNAME.
Note: I am assuming you have already checked that props is not null or empty?
If not debug and check whether properties files is loaded or not and if loaded it is not the empty properties file and hence it has loaded the properties from the file.
Looking at your problem (not only environment variable but properties are also not returning, there may be something wrong with properties file or its relative location on different computers.
If it is not exact copy which is placed at different computers, please also check if it is a file good for Linux (not written and edited in windows and put in linux).
I've tried two different ways to call a simple REST method from Android; said REST method - which works from other clients - simply returns an int val such as 17.
Both of the following attempts were based on code I found online. One is like so:
public void onFetchBtnClicked(View v){
if(v.getId() == R.id.FetchBtn){
Toast.makeText(getApplicationContext(), "You mashed the button, dude.", Toast.LENGTH_SHORT).show();
new NetworkTask().execute();
}
}
public static class NetworkTask extends AsyncTask {
#Override
protected String doInBackground(Void... params) {
final String TAG;
TAG = "callWebService";
String deviceId = "Android Device";
HttpClient httpclient = new DefaultHttpClient();
HttpGet request = new HttpGet("http://localhost:28642/api/Departments/GetCount");
request.addHeader("deviceId", deviceId);
ResponseHandler<String> handler = new BasicResponseHandler();
String result = "";
try
{
result = httpclient.execute(request, handler);
}
catch (ClientProtocolException e)
{
e.printStackTrace();
Log.e(TAG, "ClientProtocolException in callWebService(). " + e.getMessage());
}
catch (IOException e)
{
e.printStackTrace();
Log.e(TAG, "IOException in callWebService(). " + e.getMessage());
}
httpclient.getConnectionManager().shutdown();
Log.i(TAG, "**callWebService() successful. Result: **");
Log.i(TAG, result);
Log.i(TAG, "*****************************************");
return result;
}
#Override
protected void onPostExecute(String result) {
final String TAG;
TAG = "onPostExecute";
if (null != result)
Log.i(TAG, result);
}
With the code above, after the following line of code fails:
result = httpclient.execute(request, handler) ;
...I get, "*E/callWebService﹕ IOException in callWebService(). Connection to http://localhost:28642 refused*"
This problem may be a threading issue, as I read this in O'Reilly's "Programming Android" book by Mednieks, Dornin, Meike, and Nakamura: "AsyncTask is a convenenient tool for running small, asynchronous tasks. Just remember that the doInBackground method runs on a different thread! It must not write any state visible from another thread or read any state writable from another thread. This includes its parameters."
With my other attempt:
public void onFetchBtnClicked(View v){
if(v.getId() == R.id.FetchBtn){
Toast.makeText(getApplicationContext(), "You mashed the button, dude.", Toast.LENGTH_SHORT).show();
callWebService("http://localhost:28642/api/Departments/GetCount");
}
}
public String callWebService(String requestUrl)
{
final String TAG;
TAG = "callWebService";
String deviceId = "Android Device";
HttpClient httpclient = new DefaultHttpClient();
HttpGet request = new HttpGet(requestUrl);
request.addHeader("deviceId", deviceId);
ResponseHandler<String> handler = new BasicResponseHandler();
String result = "";
try
{
result = httpclient.execute(request, handler);
}
catch (ClientProtocolException e)
{
e.printStackTrace();
Log.e(TAG, "ClientProtocolException in callWebService(). " + e.getMessage());
}
catch (IOException e)
{
e.printStackTrace();
Log.e(TAG, "IOException in callWebService(). " + e.getMessage());
}
httpclient.getConnectionManager().shutdown();
Log.i(TAG, "**callWebService() successful. Result: **");
Log.i(TAG, result);
Log.i(TAG, "*****************************************");
return result;
}
...the debugger dumps me into View.class after hitting that same problem line (result = httpclient.execute(request, handler)). Why it does that, I don't know*, but I think the crux of the problem, as indicated by err msgs in logcat, is: "Caused by: android.os.NetworkOnMainThreadException"
*Maybe because something untoward is being attempted within the UI (View) thread.
Also (not a big deal, but "interesting," perhaps): the Toast doesn't pop up when a method call is made after it (it works otherwise).
The (Web API) server has a breakpoint set in its corresponding Controller method, but it is never reached. As mentioned, the server is running, and responds just fine to other (Windows app) clients.
There must be a somewhat straightforward way of calling a RESTful method from Android. But what/how?
UPDATE
I tried this, now, too, calling it like so:
RestClient client = new RestClient("http://localhost:28642/api/Departments/GetCount");
try {
client.Execute(RestClient.RequestMethod.GET);
} catch (Exception e) {
e.printStackTrace();
}
String response = client.getResponse();
Log.i("CZECH_THIS", response);
...but it also is (or seems, anyway) happy to throw the "NetworkOnMainThread" exception.
UPDATE 2
This is the closest I've gotten so far, I think. Maybe the server is the culprit in this case, because with this code:
public void onFetchBtnClicked(View v){
if(v.getId() == R.id.FetchBtn){
Toast.makeText(getApplicationContext(), "You mashed the button, dude.", Toast.LENGTH_SHORT).show();
new CallAPI().execute("http://localhost:28642/api/Departments/GetCount");
}
}
public static class CallAPI extends AsyncTask<String, String, String> {
#Override
protected String doInBackground(String... params) {
String urlString=params[0]; // URL to call
String resultToDisplay = "";
InputStream in = null;
// HTTP Get
try {
URL url = new URL(urlString);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
in = new BufferedInputStream(urlConnection.getInputStream());
} catch (Exception e ) {
System.out.println(e.getMessage());
return e.getMessage();
}
return resultToDisplay;
}
protected void onPostExecute(String result) {
Log.i("FromOnPostExecute", result);
}
} // end CallAPI
....the exception that is thrown is:
libcore.io.ErrnoException: connect failed: ECONNREFUSED (Connection refused)
failed to connect to localhost/127.0.0.1 (port 28642): connect failed: ECONNREFUSED (Connection refused)
...and the Android app continues to run (it falls over in the other examples).
Why is my server refusing the connection?
UPDATE 3
I thought for a minute I had it: I forgot to pass the serial Num with the URL. But even after doing so, it fails.
I have a breakpoint in the server app, in the Controller method; also, in the Repository method, but they are never reached.
What could be wrong?
Is "localhost" the wrong thing to use (in the URL)? Should I use the name of the computer instead?
Does the URL (passed literally as "http://localhost:28642/api/Departments/GetCount?serialNum=4242") need to be verbatimized?
UPDATE 4
Changing the "locohost" to the machine name, I get "No address associated with hostname" so that's not the problem...
Oddly, though, this line runs fine:
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
...whereas this is the last line before the exception is thrown/caught:
in = new BufferedInputStream(urlConnection.getInputStream());
Looking at this, though, perhaps I need to escape my whacks; but when you already have double-whacks, as in after "http:", do you have to do triple-whacks? Or quadruple whacks? Surely not ceiling wax...?
I've got it working now. There's an article about it here.
This is the code from there without any explanation:
public class MainActivity extends ActionBarActivity {
private GetDepartmentsCount _getDeptsCount;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button getDeptsCountBtn = (Button)findViewById(R.id.DeptsCountBtn);
getDeptsCountBtn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
_getDeptsCount = new GetDepartmentsCount();
_getDeptsCount.execute("http://10.0.2.2:28642/api/Departments/GetCount?serialNum=4242");
}
});
}
#Override
public void onStop() {
super.onStop();
_getDeptsCount.cancel(true);
}
private class GetDepartmentsCount extends AsyncTask<String, String, String> {
#Override
protected String doInBackground(String... params) {
String urlString = params[0]; // URL to call
String result = "";
// HTTP Get
try {
URL url = new URL(urlString);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
InputStream inputStream = urlConnection.getInputStream();
if (null != inputStream)
result = IOUtils.toString(inputStream);
} catch (Exception e) {
System.out.println(e.getMessage());
return e.getMessage();
}
return result;
}
#Override
protected void onPostExecute(String result) {
EditText dynCount = (EditText)findViewById(R.id.dynamicCountEdit);
dynCount.setText(result + " records were found");
Log.i("FromOnPostExecute", result);
}
}
}
I am making a http-post request from my J2ME app for Nokia Asha 501(s40). I'm using the Nokia Asha SDK 1.0 for development.
Once the app tries to make http connection it goes directly into the finally clause of try-catch statement without throwing any exceptions.
In the emulator, the following message is displayed - "Something went wrong with running this app" - Screenshot-link
I then tried the sample http-post source code given in the Nokia developer forum and got the same result.
The code is given below.
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.io.*;
import java.io.*;
public class HttpPOST extends MIDlet implements CommandListener {
private static String defaultURL = "http://localhost/api/signin";
private Display myDisplay = null;
private Form mainScreen;
private TextField requestField;
private Form resultScreen;
private StringItem resultField;
Command sendCommand = new Command("SEND", Command.OK, 1);
Command backCommand = new Command("BACK", Command.OK, 1);
public HttpPOST()
{
myDisplay = Display.getDisplay(this);
mainScreen = new Form("Type in a URL:");
requestField = new TextField(null, defaultURL, 100, TextField.URL);
mainScreen.append(requestField);
mainScreen.addCommand(sendCommand);
mainScreen.setCommandListener(this);
}
public void startApp() {myDisplay.setCurrent(mainScreen);}
public void pauseApp() {}
public void destroyApp(boolean unconditional) {}
public void commandAction(Command c, Displayable s)
{
if (c == sendCommand)
{
String urlstring = requestField.getString();
String resultstring = sendPostRequest(urlstring);
resultScreen = new Form("POST Result:");
resultField = new StringItem(null, resultstring);
resultScreen.append(resultField);
resultScreen.addCommand(backCommand);
resultScreen.setCommandListener(this);
myDisplay.setCurrent(resultScreen);
}
else if (c == backCommand)
{
requestField.setString(defaultURL);
myDisplay.setCurrent(mainScreen);
}
}
public String sendPostRequest(String urlstring)
{
HttpConnection hc = null;
DataInputStream dis = null;
DataOutputStream dos = null;
String message = "";
String requeststring = "email=test#gmail.com&password=1234";
try
{
hc = (HttpConnection) Connector.open(urlstring, Connector.READ_WRITE);
hc.setRequestMethod(HttpConnection.POST);
dos = hc.openDataOutputStream();
byte[] request_body = requeststring.getBytes();
for (int i = 0; i < request_body.length; i++)
{
dos.writeByte(request_body[i]);
}
// flush outdos.flush();
dis = new DataInputStream(hc.openInputStream());
int ch;
while ((ch = dis.read()) != -1)
{
message = message + (char) ch;
}
}
catch (IOException ioe)
{
message = "ERROR";
}
finally
{
try
{
if (hc != null)
hc.close();
}
catch (IOException ignored)
{
}
try
{
if (dis != null)
dis.close();
}
catch (IOException ignored)
{
}
try
{
if (dos != null)
dos.close();
}
catch (IOException ignored)
{
}
}
return message;
}
}
Somebody please help me out in solving this issue.
Thanks in advance.
Please find below an example. It will helpful to somebody. It is tested in Nokia Asha 501, It is perfectly working.
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.io.*;
import java.io.*;
public class GetNpost extends MIDlet implements CommandListener
{
private Display display; // Reference to Display object
private Form fmMain; // The main form
private Alert alError; // Alert to error message
private Command cmGET; // Request method GET
private Command cmPOST; // Request method Post
private Command cmExit; // Command to exit the MIDlet
private TextField tfAcct; // Get account number
private TextField tfPwd; // Get password
private StringItem siBalance;// Show account balance
private String errorMsg = null;
GetNetworkConnection getObject = null;
PostNetworkConnection postObject = null;
GetNpost mainObject = null;
public GetNpost()
{
display = Display.getDisplay(this);
mainObject = this;
// Create commands
cmGET = new Command("GET", Command.SCREEN, 2);
cmPOST = new Command("POST", Command.SCREEN, 3);
cmExit = new Command("Exit", Command.EXIT, 1);
// Textfields
tfAcct = new TextField("Account:", "", 5, TextField.NUMERIC);
tfPwd = new TextField("Password:", "", 10, TextField.ANY | TextField.PASSWORD);
// Balance string item
siBalance = new StringItem("Balance: $", "");
// Create Form, add commands & componenets, listen for events
fmMain = new Form("Account Information");
fmMain.addCommand(cmExit);
fmMain.addCommand(cmGET);
fmMain.addCommand(cmPOST);
fmMain.append(tfAcct);
fmMain.append(tfPwd);
fmMain.append(siBalance);
fmMain.setCommandListener(this);
}
public void startApp()
{
display.setCurrent(fmMain);
}
public void pauseApp()
{ }
public void destroyApp(boolean unconditional)
{ }
public void commandAction(Command c, Displayable s)
{
if (c == cmGET || c == cmPOST)
{
try
{
if (c == cmGET){
getObject = new GetNetworkConnection();
getObject.start();
}
else{
postObject = new PostNetworkConnection();
postObject.start();
}
}
catch (Exception e)
{
System.err.println("Msg: " + e.toString());
}
}
else if (c == cmExit)
{
destroyApp(false);
notifyDestroyed();
}
}
/*--------------------------------------------------
* Access servlet using GET
*-------------------------------------------------*/
private void lookupBalance_withGET() throws IOException
{
HttpConnection http = null;
InputStream iStrm = null;
boolean ret = false;
// Data is passed at the end of url for GET
// don't use localhost as a ip
String url = "http://(ip address):(port)/ServerSide/hello" + "?" +
"account=" + tfAcct.getString() + "&" +
"password=" + tfPwd.getString();
try
{
http = (HttpConnection) Connector.open(url);
//----------------
// Client Request
//----------------
// 1) Send request method
http.setRequestMethod(HttpConnection.GET);
// 2) Send header information - none
// 3) Send body/data - data is at the end of URL
//----------------
// Server Response
//----------------
iStrm = http.openInputStream();
// Three steps are processed in this method call
ret = processServerResponse(http, iStrm);
}
finally
{
// Clean up
if (iStrm != null)
iStrm.close();
if (http != null)
http.close();
}
// Process request failed, show alert
if (ret == false)
showAlert(errorMsg);
}
/*--------------------------------------------------
* Access servlet using POST
*-------------------------------------------------*/
private void lookupBalance_withPOST() throws IOException
{
HttpConnection http = null;
OutputStream oStrm = null;
InputStream iStrm = null;
boolean ret = false;
// Data is passed as a separate stream for POST (below)
// don't use localhost as a ip
String url = "http://(ip address):(port)/ServerSide/hello";
try
{
http = (HttpConnection) Connector.open(url);
//----------------
// Client Request
//----------------
// 1) Send request type
http.setRequestMethod(HttpConnection.POST);
// 2) Send header information. Required for POST to work!
http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
oStrm = http.openOutputStream();
// If you experience connection/IO problems, try
// removing the comment from the following line
// http.setRequestProperty("Connection", "close");
// 3) Send data/body
// Write account number
byte data[] = ("account=" + tfAcct.getString()).getBytes();
oStrm.write(data);
// Write password
data = ("&password=" + tfPwd.getString()).getBytes();
oStrm.write(data);
// For 1.0.3 remove flush command
// See the note at the bottom of this file
// oStrm.flush();
//----------------
// Server Response
//----------------
iStrm = http.openInputStream();
// Three steps are processed in this method call
ret = processServerResponse(http, iStrm);
}
catch(Exception e){
System.out.println("Error in Post: "+e.getMessage());
}
finally
{
// Clean up
if (iStrm != null)
iStrm.close();
if (oStrm != null)
oStrm.close();
if (http != null)
http.close();
}
// Process request failed, show alert
if (ret == false)
showAlert(errorMsg);
}
/*--------------------------------------------------
* Process a response from a server
*-------------------------------------------------*/
private boolean processServerResponse(HttpConnection http, InputStream iStrm) throws IOException
{
//Reset error message
errorMsg = null;
// 1) Get status Line
if (http.getResponseCode() == HttpConnection.HTTP_OK)
{
// 2) Get header information - none
// 3) Get body (data)
int length = (int) http.getLength();
String str;
if (length != -1)
{
byte servletData[] = new byte[length];
iStrm.read(servletData);
str = new String(servletData);
}
else // Length not available...
{
ByteArrayOutputStream bStrm = new ByteArrayOutputStream();
int ch;
while ((ch = iStrm.read()) != -1)
bStrm.write(ch);
str = new String(bStrm.toByteArray());
bStrm.close();
}
// Update the string item on the display
siBalance.setText(str);
return true;
}
else
// Use message from the servlet
errorMsg = new String( http.getResponseMessage());
return false;
}
/*--------------------------------------------------
* Show an Alert
*-------------------------------------------------*/
private void showAlert(String msg)
{
// Create Alert, use message returned from servlet
alError = new Alert("Error", msg, null, AlertType.ERROR);
// Set Alert to type Modal
alError.setTimeout(Alert.FOREVER);
// Display the Alert. Once dismissed, display the form
display.setCurrent(alError, fmMain);
}
public class GetNetworkConnection extends Thread{
public void run(){
try {
mainObject.lookupBalance_withGET();
}
catch(Exception e){
System.out.println("Error in Get Connection: "+e.getMessage());
}
}
}
public class PostNetworkConnection extends Thread{
public void run(){
try {
mainObject.lookupBalance_withPOST();
}
catch(Exception e){
System.out.println("Error in Post Connection: "+e.getMessage());
}
}
}
}
The server side code is, (It is a servlet. Name is hello.java)
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
*
* #author thirumalvalavan
*/
#WebServlet(name = "hello", urlPatterns = {"/hello"})
public class hello extends HttpServlet {
/**
* Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
* #param request servlet request
* #param response servlet response
* #throws ServletException if a servlet-specific error occurs
* #throws IOException if an I/O error occurs
*/
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
// /*TODO output your page here
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet hello</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Servlet hello at " + request.getContextPath() + "</h1>");
out.println("</body>");
out.println("</html>");
// */
} finally {
out.close();
}
}
// <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
/**
* Handles the HTTP <code>GET</code> method.
* #param request servlet request
* #param response servlet response
* #throws ServletException if a servlet-specific error occurs
* #throws IOException if an I/O error occurs
*/
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// processRequest(request, response);
String acct = request.getParameter("account"),
pwd = request.getParameter("password");
System.out.println("Hello Get Method::: " + acct + " " + pwd);
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet hello</title>");
out.println("</head>");
out.println("<body>");
out.print("<h1>Hi Get Method: </h1> <br> <h2> Your Account is: " + acct + "<br> Your pwd is: " + pwd + "</h2>");
out.println("</body>");
out.println("</html>");
out.close();
}
/**
* Handles the HTTP <code>POST</code> method.
* #param request servlet request
* #param response servlet response
* #throws ServletException if a servlet-specific error occurs
* #throws IOException if an I/O error occurs
*/
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// processRequest(request, response);
String acct = request.getParameter("account"),
pwd = request.getParameter("password");
System.out.println("Hello Post Method::: " + acct + " " + pwd);
response.setContentType("text/plain");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet hello</title>");
out.println("</head>");
out.println("<body>");
out.print("<h1>Hi Post Method: </h1> <br> <h2> Your Account is: " + acct + "<br> Your pwd is: " + pwd + "</h2>");
out.println("</body>");
out.println("</html>");
out.close();
}
/**
* Returns a short description of the servlet.
* #return a String containing servlet description
*/
#Override
public String getServletInfo() {
return "Short description";
}// </editor-fold>
}
I'm wondering if anybody can help me with a rather annoying problem regarding creating a background thread in JavaFX! I currently have several SQL queries that add data to the UI which currently run on the JavaFX Application Thread (see example below). However when each of these queries execute it freezes the UI because it isn't running on a background thread. I've looked at various examples that use Task and sort of understand them but I cannot get them to work when doing database queries, some of which take a few seconds to run.
Here is one of the methods that executes a query:
public void getTopOrders() {
customerOrders.clear();
try {
Connection con = DriverManager.getConnection(connectionUrl);
//Get all records from table
String SQL = "EXEC dbo.Get_Top_5_Customers_week";
ResultSet rs;
try (Statement stmt = con.createStatement();) {
rs = stmt.executeQuery(SQL);
while (rs.next()) {
double orderValue = Double.parseDouble(rs.getString(3));
customerOrders.add(new CustomerOrders(rs.getString(1),
rs.getString(2), "£" + formatter.format(orderValue),
rs.getString(4).substring(6, 8) + "/" +
rs.getString(4).substring(4, 6) + "/" +
rs.getString(4).substring(0, 4)));
}
}
} catch (SQLException | NumberFormatException e) {
}
}
Each processed record is added to an ObservableList which is linked to a TableView, or graph or simply sets the text on a label (depends on the query). How can I execute the query on a background thread and still leave the interface free to use and be updated from the queries
Thanks in advance
I created a sample solution for using a Task (as suggested in Alexander Kirov's comment) to access a database on a concurrently executing thread to the JavaFX application thread.
The relevant parts of the sample solution are reproduced below:
// fetches a collection of names from a database.
class FetchNamesTask extends DBTask<ObservableList<String>> {
#Override protected ObservableList<String> call() throws Exception {
// artificially pause for a while to simulate a long
// running database connection.
Thread.sleep(1000);
try (Connection con = getConnection()) {
return fetchNames(con);
}
}
private ObservableList<String> fetchNames(Connection con) throws SQLException {
logger.info("Fetching names from database");
ObservableList<String> names = FXCollections.observableArrayList();
Statement st = con.createStatement();
ResultSet rs = st.executeQuery("select name from employee");
while (rs.next()) {
names.add(rs.getString("name"));
}
logger.info("Found " + names.size() + " names");
return names;
}
}
// loads a collection of names fetched from a database into a listview.
// displays a progress indicator and disables the trigge button for
// the operation while the data is being fetched.
private void fetchNamesFromDatabaseToListView(
final Button triggerButton,
final ProgressIndicator databaseActivityIndicator,
final ListView listView) {
final FetchNamesTask fetchNamesTask = new FetchNamesTask();
triggerButton.setDisable(true);
databaseActivityIndicator.setVisible(true);
databaseActivityIndicator.progressProperty().bind(fetchNamesTask.progressProperty());
fetchNamesTask.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
#Override public void handle(WorkerStateEvent t) {
listView.setItems(fetchNamesTask.getValue());
}
});
fetchNamesTask.runningProperty().addListener(new ChangeListener<Boolean>() {
#Override public void changed(ObservableValue<? extends Boolean> observable, Boolean wasRunning, Boolean isRunning) {
if (!isRunning) {
triggerButton.setDisable(false);
databaseActivityIndicator.setVisible(false);
}
};
});
databaseExecutor.submit(fetchNamesTask);
}
private Connection getConnection() throws ClassNotFoundException, SQLException {
logger.info("Getting a database connection");
Class.forName("org.h2.Driver");
return DriverManager.getConnection("jdbc:h2:~/test", "sa", "");
}
abstract class DBTask<T> extends Task<T> {
DBTask() {
setOnFailed(new EventHandler<WorkerStateEvent>() {
#Override public void handle(WorkerStateEvent t) {
logger.log(Level.SEVERE, null, getException());
}
});
}
}
// executes database operations concurrent to JavaFX operations.
private ExecutorService databaseExecutor = Executors.newFixedThreadPool(
1,
new DatabaseThreadFactory()
);
static class DatabaseThreadFactory implements ThreadFactory {
static final AtomicInteger poolNumber = new AtomicInteger(1);
#Override public Thread newThread(Runnable runnable) {
Thread thread = new Thread(runnable, "Database-Connection-" + poolNumber.getAndIncrement() + "-thread");
thread.setDaemon(true);
return thread;
}
}
Note that once you start doing things concurrently, your coding and your UI gets more complicated than the default mode without Tasks when everything is single threaded. For example, in my sample I disabled the button which initiates the Task so you cannot have multiple Tasks running in the background doing the same thing (this kind of processing is similar to the web world where you might disable a form post button to prevent a form being double posted). I also added an animated progress indicator to the scene while the long running database task was executing so that the user has an indication that something is going on.
Sample program output demonstrating the UI experience when a long running database operation is in progress (note the progress indicator is animating during the fetch which means the UI is responsive though the screenshot does not show this):
To compare the additional complexity and functionality of an implementation with concurrent tasks versus an implementation which executes everything on the JavaFX application thread, you can see another version of the same sample which does not use tasks. Note that in my case with a toy, local database the additional complexity of the task based application is unnecessary because the local database operations execute so quickly, but if you were connecting to a large remote database using long running complex queries, than the Task based approach is worthwhile as it provides users with a smoother UI experience.
Managed to resolve using the solution provided by jewelsea. It is worth noting that if implementing this method when not using lists, tables and/or observable lists where you need to update an item on the UI such as a text field or label then simply add the update code within Platform.runLater. Below are some code snippets that show my working solution.
Code:
public void getSalesData() {
try {
Connection con = DriverManager.getConnection(connectionUrl);
//Get all records from table
String SQL = "EXEC dbo.Order_Information";
try (Statement stmt = con.createStatement(); ResultSet rs =
stmt.executeQuery(SQL)) {
while (rs.next()) {
todayTot = Double.parseDouble(rs.getString(7));
weekTot = Double.parseDouble(rs.getString(8));
monthTot = Double.parseDouble(rs.getString(9));
yearTot = Double.parseDouble(rs.getString(10));
yearTar = Double.parseDouble(rs.getString(11));
monthTar = Double.parseDouble(rs.getString(12));
weekTar = Double.parseDouble(rs.getString(13));
todayTar = Double.parseDouble(rs.getString(14));
deltaValue = Double.parseDouble(rs.getString(17));
yearPer = yearTot / yearTar * 100;
monthPer = monthTot / monthTar * 100;
weekPer = weekTot / weekTar * 100;
todayPer = todayTot / todayTar * 100;
//Doesn't update UI unless you add the update code to Platform.runLater...
Platform.runLater(new Runnable() {
public void run() {
todayTotal.setText("£" + formatter.format(todayTot));
weekTotal.setText("£" + formatter.format(weekTot));
monthTotal.setText("£" + formatter.format(monthTot));
yearTotal.setText("£" + formatter.format(yearTot));
yearTarget.setText("£" + formatter.format(yearTar));
monthTarget.setText("£" + formatter.format(monthTar));
weekTarget.setText("£" + formatter.format(weekTar));
todayTarget.setText("£" + formatter.format(todayTar));
yearPercent.setText(percentFormatter.format(yearPer) + "%");
currentDelta.setText("Current Delta (Week Ends): £"
+ formatter.format(deltaValue));
}
});
}
}
} catch (SQLException | NumberFormatException e) {
}
}
public void databaseThreadTester() {
fetchDataFromDB();
}
private void fetchDataFromDB() {
final testController.FetchNamesTask fetchNamesTask = new testController.FetchNamesTask();
databaseActivityIndicator.setVisible(true);
databaseActivityIndicator.progressProperty().bind(fetchNamesTask.progressProperty());
fetchNamesTask.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
#Override
public void handle(WorkerStateEvent t) {
}
});
fetchNamesTask.runningProperty().addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean wasRunning, Boolean isRunning) {
if (!isRunning) {
databaseActivityIndicator.setVisible(false);
}
}
;
});
databaseExecutor.submit(fetchNamesTask);
}
abstract class DBTask<T> extends Task {
DBTask() {
setOnFailed(new EventHandler<WorkerStateEvent>() {
#Override
public void handle(WorkerStateEvent t) {
}
});
}
}
class FetchNamesTask extends testController.DBTask {
#Override
protected String call() throws Exception {
fetchNames();
return null;
}
private void fetchNames() throws SQLException, InterruptedException {
Thread.sleep(5000);
getTopOrders();
getSalesData();
}
}
The only thing that doesn't appear to work with this implementation is the following, not sure why it doesn't work but it doesn't draw the graph.
public void addCricketGraphData() {
yearChart.getData().clear();
series.getData().clear();
series2.getData().clear();
try {
Connection con = DriverManager.getConnection(connectionUrl);
//Get all records from table
String SQL = "...omitted...";
try (Statement stmt = con.createStatement(); ResultSet rs =
stmt.executeQuery(SQL)) {
while (rs.next()) {
Platform.runLater(new Runnable() {
#Override
public void run() {
try {
series.getData().add(new XYChart.Data<String, Number>(rs.getString(1),
Double.parseDouble(rs.getString(7))));
series2.getData().add(new XYChart.Data<String, Number>(rs.getString(1),
Double.parseDouble(rs.getString(8))));
} catch (SQLException ex) {
Logger.getLogger(testController.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
}
} catch (SQLException | NumberFormatException e) {
}
yearChart = createChart();
}
protected LineChart<String, Number> createChart() {
final CategoryAxis xAxis = new CategoryAxis();
final NumberAxis yAxis = new NumberAxis();
// setup chart
series.setName("Target");
series2.setName("Actual");
xAxis.setLabel("Period");
yAxis.setLabel("£");
//Add custom node for each point of data on the line chart.
for (int i = 0; i < series2.getData().size(); i++) {
nodeCounter = i;
final int value = series.getData().get(nodeCounter).getYValue().intValue();
final int value2 = series2.getData().get(nodeCounter).getYValue().intValue();
int result = value2 - value;
Node node = new HoveredThresholdNode(0, result);
node.toBack();
series2.getData().get(nodeCounter).setNode(node);
}
yearChart.getData().add(series);
yearChart.getData().add(series2);
return yearChart;
}
I have a webservice on axis2, and in this class a function starts a thread, another function checks if the thread is still running, but when i do a request for the function that checks of the thread is still runnning, i get this error:
org.apache.axis2.AxisFault: Exception occurred while trying to invoke service method isTaskRunning
at org.apache.axis2.util.Utils.getInboundFaultFromMessageContext(Utils.java:531)
at org.apache.axis2.description.OutInAxisOperationClient.handleResponse(OutInAxisOperation.java:375)
at org.apache.axis2.description.OutInAxisOperationClient.send(OutInAxisOperation.java:421)
at org.apache.axis2.description.OutInAxisOperationClient.executeImpl(OutInAxisOperation.java:229)
at org.apache.axis2.client.OperationClient.execute(OperationClient.java:165)
at be.kdg.cosys.thesis.ExecutorStub.isTaskRunning(ExecutorStub.java:487)
at be.kdg.cosys.thesis.AllToPublicScheduler.executeTask(AllToPublicScheduler.java:158)
at be.kdg.cosys.thesis.AllToPublicScheduler.incomingApplication(AllToPublicScheduler.java:106)
at be.kdg.cosys.thesis.ParserToScheduler.run(ParserToScheduler.java:111)
at java.lang.Thread.run(Unknown Source)
Here's is the webservice class:
public class Executor {
private Task task = null;
private long startTime = 0;
private long runTime = 0;
private Thread taskThread=null;
public void execute(byte[] object){
ObjectInputStream in = null;
try {
in = new ObjectInputStream(new ByteArrayInputStream(object));
task = (Task) in.readObject();
in.close();
} catch (IOException | ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
runTime = task.getRunTime();
startTime = System.currentTimeMillis();
taskThread=new Thread(task);
taskThread.start();
}
public long timeToFinish()
{
return runTime-(System.currentTimeMillis()-startTime);
}
public boolean isTaskRunning()
{
return taskThread.isAlive();
}
public byte[] getTask()
{
byte[] ser=null;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutput out = null;
try {
out = new ObjectOutputStream(bos);
out.writeObject(task);
ser = bos.toByteArray();
out.close();
bos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return ser;
}
}
On the server of the webservice i get a nullpointerexeception (log of catalina)
Can anyone help me?
Yorick
Yes you will get a Null pointer exception - Because the Web-service method would not be called on the Same class instance which started the Thread. Since the variable taskThread will be null , and in the method isTaskRunning() calls a method on a null object, it causes a NullpointerException
Ideally , if you need to poll a Thread using web-service , you should use an intimidatory media which states the Status of Thread. intimidatory can be a Database Table which stores the Thread Status