Nifi execute script extrenal library not working - groovy

I have written a jar which has jedis connection pool feature, by using which I have written the groovy script in nifi for redis location search. But it is behaving stangely, sometimes it is working and sometimes not.
Redis.java
public class Redis {
private static Object staticLock = new Object();
private static JedisPool pool;
private static String host;
private static int port;
private static int connectTimeout;
private static int operationTimeout;
private static String password;
private static JedisPoolConfig config;
public static void initializeSettings(String host, int port, String password, int connectTimeout, int operationTimeout) {
Redis.host = host;
Redis.port = port;
Redis.password = password;
Redis.connectTimeout = connectTimeout;
Redis.operationTimeout = operationTimeout;
}
public static JedisPool getPoolInstance() {
if (pool == null) { // avoid synchronization lock if initialization has already happened
synchronized(staticLock) {
if (pool == null) { // don't re-initialize if another thread beat us to it.
JedisPoolConfig poolConfig = getPoolConfig();
boolean useSsl = port == 6380 ? true : false;
int db = 0;
String clientName = "MyClientName"; // null means use default
SSLSocketFactory sslSocketFactory = null; // null means use default
SSLParameters sslParameters = null; // null means use default
HostnameVerifier hostnameVerifier = new SimpleHostNameVerifier(host);
pool = new JedisPool(poolConfig, host, port);
//(poolConfig, host, port, connectTimeout,operationTimeout,password, db,
// clientName, useSsl, sslSocketFactory, sslParameters, hostnameVerifier);
}
}
}
return pool;
}
public static JedisPoolConfig getPoolConfig() {
if (config == null) {
JedisPoolConfig poolConfig = new JedisPoolConfig();
int maxConnections = 200;
poolConfig.setMaxTotal(maxConnections);
poolConfig.setMaxIdle(maxConnections);
poolConfig.setBlockWhenExhausted(true);
poolConfig.setMaxWaitMillis(operationTimeout);
poolConfig.setMinIdle(50);
Redis.config = poolConfig;
}
return config;
}
public static String getPoolCurrentUsage()
{
JedisPool jedisPool = getPoolInstance();
JedisPoolConfig poolConfig = getPoolConfig();
int active = jedisPool.getNumActive();
int idle = jedisPool.getNumIdle();
int total = active + idle;
String log = String.format(
"JedisPool: Active=%d, Idle=%d, Waiters=%d, total=%d, maxTotal=%d, minIdle=%d, maxIdle=%d",
active,
idle,
jedisPool.getNumWaiters(),
total,
poolConfig.getMaxTotal(),
poolConfig.getMinIdle(),
poolConfig.getMaxIdle()
);
return log;
}
private static class SimpleHostNameVerifier implements HostnameVerifier {
private String exactCN;
private String wildCardCN;
public SimpleHostNameVerifier(String cacheHostname)
{
exactCN = "CN=" + cacheHostname;
wildCardCN = "CN=*" + cacheHostname.substring(cacheHostname.indexOf('.'));
}
public boolean verify(String s, SSLSession sslSession) {
try {
String cn = sslSession.getPeerPrincipal().getName();
return cn.equalsIgnoreCase(wildCardCN) || cn.equalsIgnoreCase(exactCN);
} catch (SSLPeerUnverifiedException ex) {
return false;
}
}
}
}
CustomFunction:
public class Functions {
SecureRandom rand = new SecureRandom();
private static final String UTF8= "UTF-8";
public static JedisPool jedisPool=null;
public static String searchPlace(double lattitude,double longitude) {
try(Jedis jedis = jedisPool.getResource()) {
}
catch(Exception e){
log.error('execption',e);
}
}
}
Groovyscript:
import org.apache.nifi.processor.ProcessContext;
import com.customlib.functions.*;
def flowFile = session.get();
if (flowFile == null) {
return;
}
def flowFiles = [] as List<FlowFile>
def failflowFiles = [] as List<FlowFile>
def input=null;
def data=null;
static onStart(ProcessContext context){
Redis.initializeSettings("host", 6379, null,0,0);
Functions.jedisPool= Redis.getPoolInstance();
}
static onStop(ProcessContext context){
Functions.jedisPool.destroy();
}
try{
log.warn('is jedispool connected::::'+Functions.jedisPool.isClosed());
def inputStream = session.read(flowFile)
def writer = new StringWriter();
IOUtils.copy(inputStream, writer, "UTF-8");
data=writer.toString();
input = new JsonSlurper().parseText( data );
log.warn('place is::::'+Functions.getLocationByLatLong(input["data"]["lat"], input["data"]["longi"]);
.......
...........
}
catch(Exception e){
}
newFlowFile = session.write(newFlowFile, { outputStream ->
outputStream.write( data.getBytes(StandardCharsets.UTF_8) )
} as OutputStreamCallback)
failflowFiles<< newFlowFile;
}
session.transfer(flowFiles, REL_SUCCESS)
session.transfer(failflowFiles, REL_FAILURE)
session.remove(flowFile)
The nifi is in 3 node cluster. The function lib is configured in groovyscript module directory.In the above groovy script processor, the log statement is jedispool connected:::: is sometimes printing false,sometimes true but after deploying for the first time jar every time works. But later it is unpredictable, I am not getting what is wrong in the code. How the groovyscript will load the jar. How can I acheive the lib based search using groovy script.

Redis.pool never gets null after initialization. You are calling pool.destroy() but not setting it to null.
getPoolInstance() checks if pool is null only then it creates a new pool.
I don't see any reason to have 2 variables to hold reference to the same pool: in Redis and in Functions class.

Related

How to make clone of static variables of static class in c#

I am working on different approaches of cloning of an objects in c# but currently I stuck with the simple one. I have a static class with static variables & I want to make an exact copy of one of my static variable.I have sketched my code structure below:
public static class RULE_SET
{
public static bool IsdataValid;
public static GCBRequest GCBData;
public static T Clone<T>(this T source)
{
try
{
if (!typeof(T).IsSerializable)
{
throw new ArgumentException("The type must be serializable.", "source");
}
if (Object.ReferenceEquals(source, null))
{
return default(T);
}
IFormatter formatter = new BinaryFormatter();
Stream stream = new MemoryStream();
using (stream)
{
formatter.Serialize(stream, source);
stream.Seek(0, SeekOrigin.Begin);
return (T)formatter.Deserialize(stream);
}
}
catch (Exception ee) { return default(T); }
}
}
[XmlRoot(ElementName = "GCBRequest")]
public class GCBRequest
{
[XmlElement(ElementName = "PID")]
public string PID { get; set; }
[XmlElement(ElementName = "AID")]
public string AID { get; set; }
[XmlElement(ElementName = "CID")]
public string CID { get; set; }
}
//code to load the RULE_SET
string strJsonRuleset = "{\r\n \"GCdBINRequest\": {\r\n\"PID\": \"(?s).*#M#20\",\r\n\"AID\": \"(?s).*#O#10\",\r\n\"CID\": \"(?s).*#O#25\"\r\n }\r\n}";
public class RULE_SET_LOCAL
{
public static GCBRequest GCBData;
}
//from other method
RULE_SET_LOCAL objParentRuleSet = new RULE_SET_LOCAL();
objParentRuleSet = JsonConvert.DeserializeObject<RULE_SET_LOCAL>(strJsonRuleset);
RULE_SET.GCBData = objParentRuleSet.GCBData;
//Main Method from which I have to create a clone object
Object objRuleset;
objRuleset = RULE_SET.GCBData.Clone();
if(objRuleset == null)
{
** stuck here**
I don't know why Everytime I got the null object ?
}
// but I have use
objRuleset = RULE_SET.GCBData;
if(objRuleset != null)
{
** Successfully reached **
//But I can't do any operation on this object as it will effect the original one.
}
Guys, Do you have any solution/Suggestion ?
Please help me to understand this , any help will be appreciated.
Thanks.
After searching a lot I got this method :
public static T Clone<T>(this T source)
{
var serialized = JsonConvert.SerializeObject(source);
return JsonConvert.DeserializeObject<T>(serialized);
}
& now I am able to get the clone by calling
object objRuleset = RULE_SET.Clone<GCBRequest>(RULE_SET.GCBData);

Sending an object to host from a client

I cant seem to find the problem on the code but it the server is not displaying anything. It displays the catch. Client seems find and it sets the players name and score and sends it but I cant seem to find the issue on this one why server is not displaying the name and score.
Here is my Client:
public class Client
{
private static final int BUFSIZE = 64;
public static void main(String[] args) throws IOException
{
try
{
int scores;
Scanner in = new Scanner(System.in);
Socket clntSock = new Socket("127.0.0.1", 6000);
System.out.println("What is the filename?");
String input = in.nextLine();
Scanner fileInput = new Scanner(new File(input));
ObjectOutputStream out = new
ObjectOutputStream(clntSock.getOutputStream());
Player playerObject = new Player();
playerObject.setName(fileInput.nextLine());
System.out.println(""+playerObject.getName());
for (int i = 0; i < 5; i++)
{
scores = Integer.parseInt(fileInput.nextLine());
playerObject.setScore(scores);
System.out.println(""+playerObject.getScores().get(i));
}
out.writeObject(playerObject);
in.close();
fileInput.close();
out.close();
clntSock.close();
}
catch ( UnknownHostException ex )
{
System.out.println( "Unknown host" );
}
}
}
and my Host:
public class Host
{
private static final int BUFSIZE = 64;
public static void main(String[] args) throws IOException
{
// Step 1: Create a ServerSocket.
ServerSocket servSock = new ServerSocket(6000);
PrintStream fileOut = new PrintStream("Datafromclient.txt");
try
{
// Step 2: Wait for a connection..
Socket clntSock = servSock.accept();
// Step 3: Get input and output streams.
System.out.println("Step 3: Get object input stream.,");
ObjectInputStream objectIn = new
ObjectInputStream(clntSock.getInputStream());
Player playerObjct = (Player)objectIn.readObject();
System.out.println("The name of Player: "+playerObjct.getName());
for(int i=0; i <5; i++)
{
System.out.println("Scores:"+playerObjct.getScores().get(i));
}
objectIn.close();
clntSock.close();
// Step 5: Close connection
objectIn.close();
clntSock.close();
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
catch (IOException e)
{
System.err.println(e);
}
}
}
My player class:
public class Player
private String name;
private int playerId;
private int bestScore;
private static int numberOfPlayers = 0;
private ArrayList<Integer> scores = new ArrayList<Integer>();
/* -------------- CONSTRUCTOR --------------------------------------
*/
public Player()
{
numberOfPlayers++;
playerId = numberOfPlayers;
}
public Player(String name)
{
this.name = name;
}
//Create set method for setName
public void setName(String name)
{
this.name = name;
}
//Create set method for setScores
public void setScore(int score)
{
scores.add(score);
}
//Create get method for getPlayerId
public int getPlayerId()
{
return this.playerId;
}
//Create get method for getName
public String getName()
{
return this.name;
}
//Create get method for getScores
public ArrayList<Integer> getScores()
{
return scores;
}
//Create get method for getBestScore
public int getBestScore()
{
calculateBestScore();
return bestScore;
}
//Method to expose the value of numberOfPlayers
public static int getNumberOfPlayers()
{
return numberOfPlayers;
}
//Create get method for calcualteAverage
public double calculateAverage()
{
Integer sum = 0;
if(!scores.isEmpty())
{
for(Integer score : scores)
{
sum += score;
}
return sum.doubleValue() / scores.size();
}
return sum;
}
public void calculateBestScore()
{
bestScore = Collections.max(scores);
}
}
I was missing
import java.io.Serializable;
public class Player implements Serializable
now its working.

Create an custom appender in log4j which stores the log in memory

I want to create an custom appender using log4j in java programatically which stores the log in memory(Certain size will be defined for e.g. say DEFAULT_SIZE=20) & as soon as memory is full(there are 20 logs in memory) create an json array of those logs and send it to the server. Along with log message i also want information such as (class, file name,line number,method name,level etc.)
Help is appreciated.!!!
Updated ::
Below is the source code developed by me for the same . Problem which i am facing is i get line number, method name,file name as "?".I dont understand what is the reason.
package com.any.logger;
import java.util.ArrayList;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.spi.LoggingEvent;
public class Log4jAppender extends AppenderSkeleton {
private static final int DEFAULT_BUFFER_SIZE = 20;
private ArrayList<LoggingEvent> buffer;
private int bufferSize;
public Log4jAppender() {
this.bufferSize = Log4jAppender.DEFAULT_BUFFER_SIZE;
this.buffer = new ArrayList<LoggingEvent>();
}
public void close() {
}
public boolean requiresLayout() {
return false;
}
#Override
protected void append(LoggingEvent loggingEvent) {
synchronized (buffer) {
if (buffer.size() >= bufferSize) {
try {
System.out.println("Hello");
Log4jService service = new Log4jService(new ArrayList<LoggingEvent>
(buffer));
System.out.println("Buff >");
service.start();
} catch (Exception e) {
System.err.println("Failed to write logs");
e.printStackTrace();
} finally {
buffer.clear();
}
}
}
buffer.add(loggingEvent);
}
}
package com.any.logger;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Iterator;
import org.apache.log4j.Level;
import org.apache.log4j.spi.LoggingEvent;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
#SuppressWarnings("rawtypes")
public class Log4jService implements Runnable {
private ArrayList<LoggingEvent> buffer;
private Thread t;
private boolean flag;
public Log4jService(ArrayList<LoggingEvent> buffer) {
this.buffer = new ArrayList<LoggingEvent>(buffer);
this.flag = false;
}
public void start() {
if (!flag) {
this.flag = true;
this.t = new Thread(this);
this.t.start();
}
}
public void run() {
if (flag) {
String json = getLogJson(buffer);
}
}
/**
* Method to get the json log
*
* #param logEvents
* arrayList of log events
* #return an String which is json file
* #throws JSONException
*/
private String getLogJson(ArrayList<LoggingEvent> logEvents) {
System.out.println("In getLogJson");
JSONObject logger = new JSONObject();
try {
JSONArray logs = new JSONArray();
String message = "";
String time = "";
String level = "";
String tag = "";
String file = "";
String exceptionName = "";
String exceptionReason = "";
String line = "";
String clas = "";
String method = "";
int index = 0;
SimpleDateFormat formatter=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
for (Iterator i = logEvents.iterator(); i.hasNext();) {
LoggingEvent logEvent = (LoggingEvent) i.next();
boolean chk=logEvent.locationInformationExists();
System.out.println("Check :: "+chk);
clas=logEvent.getClass().toString();
JSONObject log = new JSONObject();
message = logEvent.getMessage().toString();
time = String.valueOf(formatter.format(logEvent.getTimeStamp()));
level = logEvent.getLevel().toString();
if (chk) {
System.out.println("hello");
file = logEvent.getLocationInformation().getFileName();
line = logEvent.getLocationInformation().getLineNumber();
method = logEvent.getLocationInformation().getMethodName();
}
if (logEvent.getLevel() == Level.ERROR || logEvent.getLevel() ==
Level.FATAL) {
exceptionReason = message;
}
log.put("message", message);
log.put("time", time);
log.put("level", level);
log.put("tag", tag);
log.put("file", file);
log.put("exceptionName", exceptionName);
log.put("exceptionReason", exceptionReason);
log.put("line", line);
log.put("class", clas);
log.put("method", method);
logs.put(index, log);
index++;
}
JSONObject logsObj = new JSONObject();
logsObj.put("logs", logs);
logger.put("log", logsObj);
System.out.println("Logs Array :: " + logsObj);
System.out.println("Logger Object :: " + logger);
} catch (Exception e) {
e.printStackTrace();
}
return logger.toString();
}
}
I would look at the source code for log4j2 and use an existing appender as a template for my custom appender. SocketAppender and TCPSocketManager may be good places to start.
http://logging.apache.org/log4j/2.0/log4j-core/xref/org/apache/logging/log4j/core/net/TCPSocketManager.html
Currently the buffering is based on the number of bytes, not event count. If you follow the existing appender/manager pattern then in your custom appender manager you will need to have a large enough buffer and flush every 20 events. (Perhaps also flush after some timeout? You may only get 19 events and nothing after that...)
You could also do the buffering in the appender, keep a list of event objects there and only call pass them to the manager to be written after some threshold is reached.
The default Layout for SocketAppender will use java serialization. You'll need to roll your own JasonLayout. The log event object has all the details you mentioned.

BlackBerry - cancel a thread executed in another class to refresh location

How can I cancel a thread from another class fetching/refreshing location. I am able to cancel a thread from within the same class. But I am unable to do this across classes. Declaring the GPSThread static did not help. Can anyone please guide?
Class1:
public class GPSListener {
/* Other instantiation code */
Dialog busyDialog1 = new Dialog("Refreshing Location...",
new String [] { "Cancel" },
new int [] { Dialog.CANCEL},
Dialog.CANCEL,
Bitmap.getPredefinedBitmap(Bitmap.HOURGLASS))
{
public void fieldChanged(Field field1, int context1)
{
GPSHandler.requestStop();
busyDialog1.cancel();
}
};
public String refreshCoordinates() {
String test = "nothing";
if (GPSHandler.isStopRequested())
{
GPSHandler.stopRequested = false;
return null;
}
GPSHandler.getInstance().setListener(this);
GPSHandler.getInstance().requestLocationUpdates();
if (GPSHandler.isStopRequested())
{
GPSHandler.stopRequested = false;
return null;
}
busyDialog1.setEscapeEnabled(false);
busyDialog1.show();
return test;
}
public void onLocationReceived(Coordinates location) {
lblLatitude.setText(Double.toString(location.getLatitude()));
lblLongitude.setText(Double.toString(location.getLongitude()));
busyDialog1.cancel();
}
}
Class 2:
public class GPSHandler {
private GPSThread _gpsThread;
private Coordinates _location;
private boolean _gotLocation;
private GPSListener _listener;
/** this class will be a Singleton, as the device only has one GPS system */
private static GPSHandler _instance;
/** #return the Singleton instance of the GPSHandler */
public static GPSHandler getInstance() {
if (_instance == null) {
_instance = new GPSHandler();
}
return _instance;
}
public static boolean stopRequested = false;
public synchronized static void requestStop() {
stopRequested = true;
}
public synchronized static boolean isStopRequested() {
return stopRequested;
}
/** not publicly accessible ... use getInstance() */
private GPSHandler() {
}
/** call this to trigger a new location fix */
public void requestLocationUpdates() {
if (_gpsThread == null || !_gpsThread.isAlive()) {
_gpsThread = new GPSThread();
_gpsThread.start();
}
}
public void setListener(GPSListener listener) {
// only supports one listener this way
_listener = listener;
}
private void setLocation(final Coordinates value) {
_location = value;
if (value.getLatitude() != 0.0 || value.getLongitude() != 0.0) {
_gotLocation = true;
if (_listener != null) {
// this assumes listeners are UI listeners, and want callbacks on the UI thread:
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
_listener.onLocationReceived(value);
}
});
}
}
}
private class GPSThread extends Thread {
private void getLocationFromGoogle() {
try {
int cellID = GPRSInfo.getCellInfo().getCellId();
int lac = GPRSInfo.getCellInfo().getLAC();
String urlString2 = "http://www.google.com/glm/mmap";
// Open a connection to Google Maps API
ConnectionFactory connFact = new ConnectionFactory();
ConnectionDescriptor connDesc;
connDesc = connFact.getConnection(urlString2);
HttpConnection httpConn2;
httpConn2 = (HttpConnection)connDesc.getConnection();
httpConn2.setRequestMethod("POST");
// Write some custom data to Google Maps API
OutputStream outputStream2 = httpConn2.openOutputStream();//getOutputStream();
writeDataGoogleMaps(outputStream2, cellID, lac);
// Get the response
InputStream inputStream2 = httpConn2.openInputStream();//getInputStream();
DataInputStream dataInputStream2 = new DataInputStream(inputStream2);
// Interpret the response obtained
dataInputStream2.readShort();
dataInputStream2.readByte();
final int code = dataInputStream2.readInt();
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
Dialog.alert(code + "");
}
});
if (code == 0) {
final double latitude = dataInputStream2.readInt() / 1000000D;
final double longitude = dataInputStream2.readInt() / 1000000D;
setLocation(new Coordinates(latitude, longitude, 0.0f));
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
Dialog.alert(latitude+"-----"+longitude);
}
});
dataInputStream2.readInt();
dataInputStream2.readInt();
dataInputStream2.readUTF();
} else {
System.out.println("Error obtaining Cell Id ");
}
outputStream2.close();
inputStream2.close();
} catch (Exception e) {
System.out.println("Error: " + e.getMessage());
}
}
private void tryGetLocationFromDevice() {
_gotLocation = false;
try {
Criteria myCriteria = new Criteria();
myCriteria.setCostAllowed(false);
LocationProvider myLocationProvider = LocationProvider.getInstance(myCriteria);
try {
Location myLocation = myLocationProvider.getLocation(300);
setLocation(myLocation.getQualifiedCoordinates());
} catch ( InterruptedException iex ) {
System.out.println(iex.getMessage());
} catch ( LocationException lex ) {
System.out.println(lex.getMessage());
}
} catch ( LocationException lex ) {
System.out.println(lex.getMessage());
}
if (!_gotLocation) {
getLocationFromGoogle();
}
}
public void run() {
int bbMapsHandle = CodeModuleManager.getModuleHandle("net_rim_bb_lbs"); // OS 4.5 - 6.0
int bbMapsHandle60 = CodeModuleManager.getModuleHandle("net_rim_bb_maps"); // OS 6.0
if (bbMapsHandle > 0 || bbMapsHandle60 > 0) {
tryGetLocationFromDevice();
} else {
getLocationFromGoogle();
}
}
}
private void writeDataGoogleMaps(OutputStream out, int cellID, int lac) throws IOException {
DataOutputStream dataOutputStream = new DataOutputStream(out);
dataOutputStream.writeShort(21);
dataOutputStream.writeLong(0);
dataOutputStream.writeUTF("en");
dataOutputStream.writeUTF("Android");
dataOutputStream.writeUTF("1.0");
dataOutputStream.writeUTF("Web");
dataOutputStream.writeByte(27);
dataOutputStream.writeInt(0);
dataOutputStream.writeInt(0);
dataOutputStream.writeInt(3);
dataOutputStream.writeUTF("");
dataOutputStream.writeInt(cellID);
dataOutputStream.writeInt(lac);
dataOutputStream.writeInt(0);
dataOutputStream.writeInt(0);
dataOutputStream.writeInt(0);
dataOutputStream.writeInt(0);
dataOutputStream.flush();
}
}
Your GPSThread object is currently declared as a private inner class within GPSHandler. If you want to stop execution (or indeed do anything with it) from outside the scope of GPSHandler you will need to mark it as public. You will also need to provide some public mechanism (e.g. a stop() method) to cancel the thread execution.
The most common way of doing this is to have a boolean flag inside your thread (e.g shouldStop) which is checked within your main execution loop inside run() to see if it should stop. When the stop() method is called shouldStop is set to true and your Thread will stop.
Here's a good example: How to stop threads in Java?
There's two groups of changes you should make.
Change the Stop Requested Flag
First, remember that encapsulation is a good thing in Object-Oriented languages. The isStopRequested() method, or stopRequested variable of the GPSHandler should not be used outside of that class. Your UI's GPSListener should not attempt to use either of those. I would change your GPSHandler to use this:
private static boolean stopRequested = false;
public synchronized static void requestStop() {
stopRequested = true;
}
private synchronized static boolean isStopRequested() {
return stopRequested;
}
Only requestStop() should be public. It looks like you made stopRequested public to allow the GPSListener to reset it. If it needs resetting, let the class that owns that variable do the resetting. For example, in GPSHandler:
/** call this to trigger a new location fix */
public void requestLocationUpdates() {
if (_gpsThread == null || !_gpsThread.isAlive()) {
// reset this stop flag:
stopRequested = false;
_gpsThread = new GPSThread();
_gpsThread.start();
}
}
requestLocationUpdates() is really the method that starts the thread, so it should be where stopRequested gets reset to false.
Also, another reason that you should not make stopRequested public and allow other classes to use it is that this is not generally thread-safe. One of the reasons to wrap stopRequested with the requestStop() and isStopRequested() methods is to add thread-safety. There's many ways to do that, but those two methods achieve thread-safety by being marked with the synchronized keyword.
Change How/Where You Check the Flag
After you make these fixes, you need to change where you check if a stop has been requested. You don't really want to check isStopRequested() in the refreshCoordinates() method. That method involves almost no work. Even though it starts the process of getting a location fix, that only starts a thread, but the actual work of getting the location is done on a background thread (your GPSThread). If requestStop() is called, it's very unlikely that it will be called in the middle of refreshCoordinates(), so that's not where you should check it.
Check isStopRequested() multiple times within the GPSHandler class's methods tryGetLocationFromDevice() and getLocationFromGoogle(). Those are the methods that perform slow processing. Those are the ones you might want to interrupt in the middle. So, something like this:
private void getLocationFromGoogle() {
try {
int cellID = GPRSInfo.getCellInfo().getCellId();
int lac = GPRSInfo.getCellInfo().getLAC();
String urlString2 = "http://www.google.com/glm/mmap";
if (isStopRequested()) return;
// Open a connection to Google Maps API
ConnectionFactory connFact = new ConnectionFactory();
ConnectionDescriptor connDesc;
connDesc = connFact.getConnection(urlString2);
HttpConnection httpConn2;
httpConn2 = (HttpConnection)connDesc.getConnection();
httpConn2.setRequestMethod("POST");
// Write some custom data to Google Maps API
OutputStream outputStream2 = httpConn2.openOutputStream();//getOutputStream();
writeDataGoogleMaps(outputStream2, cellID, lac);
if (isStopRequested()) return;
// Get the response
InputStream inputStream2 = httpConn2.openInputStream();//getInputStream();
DataInputStream dataInputStream2 = new DataInputStream(inputStream2);
// Interpret the response obtained
dataInputStream2.readShort();
dataInputStream2.readByte();
if (isStopRequested()) return;
final int code = dataInputStream2.readInt();
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
Dialog.alert(code + "");
}
});
And in tryGetLocationFromDevice(), you could do this (make sure to add the member variable and new method below):
private LocationProvider _locationProvider; // must be a member variable!
public void requestStop() {
if (_locationProvider != null) {
// this will interrupt the _locationProvider.getLocation(300) call
_locationProvider.reset();
}
}
private void tryGetLocationFromDevice() {
_gotLocation = false;
try {
Criteria myCriteria = new Criteria();
myCriteria.setCostAllowed(false);
_locationProvider = LocationProvider.getInstance(myCriteria);
try {
Location myLocation = _locationProvider.getLocation(300);
setLocation(myLocation.getQualifiedCoordinates());
} catch ( InterruptedException iex ) {
// this may be caught if stop requested!!!!
System.out.println(iex.getMessage());
} catch ( LocationException lex ) {
System.out.println(lex.getMessage());
}
} catch ( LocationException lex ) {
System.out.println(lex.getMessage());
}
if (!_gotLocation && !isStopRequested()) {
getLocationFromGoogle();
}
}
Then, call the GPSThread.requestStop() method from the outer GPSHandler.requestStop() method:
public synchronized static void requestStop() {
stopRequested = true;
if (_gpsThread != null) {
_gpsThread.requestStop();
}
}

Why I am getting the bad length exception when I am running this application?

I want to communicate to a server from J2me app using UDP.However, when I am running the app, I am getting a bad length exception.My codes and output are given below.
client code
import javax.microedition.midlet.MIDlet;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.TextBox;
import javax.microedition.lcdui.TextField;
import javax.microedition.io.Connector;
import javax.microedition.io.Datagram;
import javax.microedition.io.DatagramConnection;
import java.io.IOException;
public class DatagramTest extends MIDlet
implements CommandListener, Runnable
{
private static final int BUF_SIZE = 1024;
private static Command exit = new Command("Exit", Command.EXIT, 1);
private static DatagramTest instance;
private Display display;
private TextBox dgramText;
private DatagramConnection conn;
private Datagram dgram;
private String address = "datagram://myip:9876";
public DatagramTest()
{
super();
instance = this;
}
public DatagramTest(String service)
{
this();
address = service;
}
/**
Returns the single instance of this class. Calling
this method before constructing an object will return
a null pointer.
#return an instance of this class.
*/
public static DatagramTest getInstance()
{
return instance;
}
public void startApp()
{
display = Display.getDisplay(this);
dgramText = new TextBox("Datagram contents",
null,
2048,
TextField.ANY);
dgramText.setCommandListener(this);
display.setCurrent(dgramText);
System.out.println("Starting run....");
run();
System.out.println("Stopping run....");
}
public void run()
{
System.out.println("In run....");
try
{
int maxLength;
conn = (DatagramConnection)Connector.open(address);
maxLength = conn.getMaximumLength();
dgram = conn.newDatagram(1024);
dgram.reset();
conn.send(dgram);
conn.receive(dgram);
byte[] data = dgram.getData();
// Extract the response string.
String str = new String(data);
System.out.println(str);
dgram.reset();
System.out.println("Exit run....");
}
catch (IOException ioe)
{
System.out.println(ioe.getMessage());
ioe.printStackTrace();
quit();
}
return;
}
public void pauseApp()
{
}
void quit()
{
destroyApp(true);
notifyDestroyed();
}
public void destroyApp(boolean destroy)
{
try
{
conn.close();
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
}
public void display()
{
Display.getDisplay(this).setCurrent(dgramText);
}
public void commandAction(Command c, Displayable d)
{
if (c == exit)
{
quit();
}
}
}
Server code
import java.io.*;
import java.net.*;
class UDPServer
{
public static void main(String args[]) throws Exception
{
DatagramSocket serverSocket = new DatagramSocket(9876);
byte[] receiveData = new byte[1024];
byte[] sendData = new byte[1024];
while(true)
{
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
serverSocket.receive(receivePacket);
String sentence = new String( receivePacket.getData());
System.out.println("RECEIVED: " + sentence);
InetAddress IPAddress = receivePacket.getAddress();
int port = receivePacket.getPort();
String capitalizedSentence = sentence.toUpperCase();
sendData = capitalizedSentence.getBytes();
DatagramPacket sendPacket =
new DatagramPacket(sendData, sendData.length, IPAddress, port);
serverSocket.send(sendPacket);
}
}
}
Output at clientside
Starting run.... In run.... Bad
datagram length java.io.IOException:
Bad datagram length
at com.sun.midp.io.j2me.datagram.Protocol.receive(Protocol.java:367)
at hello.DatagramTest.run(DatagramTest.java:89)
at hello.DatagramTest.startApp(DatagramTest.java:69)
at javax.microedition.midlet.MIDletProxy.startApp(MIDletProxy.java:43)
at com.sun.midp.midlet.Scheduler.schedule(Scheduler.java:374)
at com.sun.midp.main.Main.runLocalClass(Main.java:466)
at com.sun.midp.main.Main.main(Main.java:120)
Stopping run....
Why I am getting this bad length exception and how do I sort it out?
One thing you need to try is to send and receive datagrams in a separate thread.
The documentation for DatagramConnection.receive() says: "This method blocks until a datagram is received"
You are calling it from inside MIDlet.startApp().
Blocking the application management system thread that calls startApp() is bad practice.

Resources