Spigot-Bungeecord Plugin Messaging not working - java

I am trying to make a plugin that has a 'global' configuration file. Right now, I'm trying to use Plugin Messaging to send the entire configuration file through a string, to another server. I have followed the guide at https://www.spigotmc.org/wiki/bukkit-bungee-plugin-messaging-channel/ and have put my own little twist on what is sent. I'm trying to send the plugin message within a spigot plugin so maybe that is the problem. Here is the code is a summary of the code I use to send it (I took out readFile(), clearFile() and writeFile(), let me know if you want those):
public class Main extends JavaPlugin implements PluginMessageListener {
public void onEnable() {
this.getServer().getMessenger().registerOutgoingPluginChannel(this, "BungeeCord");
this.getServer().getMessenger().registerIncomingPluginChannel(this, "BungeeCord", this);
}
public void onDisable() {}
public void updateConfig() {
String updateConfig = "";
for (String s : readFile(this.getDataFolder() + "/config.yml")) {
if (updateConfig.equals("")) {
updateConfig = s;
} else {
updateConfig = updateConfig + " |n| " + s;
}
}
Bukkit.getLogger().info("Sending config update...");
sendUpdateconfig(updateConfig);
}
public void sendUpdateconfig(String update) {
ByteArrayDataOutput out = ByteStreams.newDataOutput();
try {
out.writeUTF("Forward");
out.writeUTF("ALL");
out.writeUTF("FooServer");
ByteArrayOutputStream msgbytes = new ByteArrayOutputStream();
DataOutputStream msgout = new DataOutputStream(msgbytes);
msgout.writeUTF(update);
msgout.writeShort(295);
out.writeShort(msgbytes.toByteArray().length);
out.write(msgbytes.toByteArray());
Player player = Iterables.getLast(Bukkit.getOnlinePlayers());
player.getServer().sendPluginMessage(this, "BungeeCord", out.toByteArray());
Bukkit.getLogger().info("Sent " + update);
Bukkit.getLogger().info("Short sent: 295");
Bukkit.getLogger().info("Sent through player " + player.getName());
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void onPluginMessageReceived(String channel, Player player, byte[] message) {
Bukkit.getLogger().info("Recieved message...");
if (!channel.equals("BungeeCord")) {
return;
}
try {
Bukkit.getLogger().info("Recieved message...");
ByteArrayDataInput in = ByteStreams.newDataInput(message);
String subChannel = in.readUTF();
if (!subChannel.equals("FooServer")) {
Bukkit.getLogger().info("Loading message....");
short len = in.readShort();
byte[] msgbytes = new byte[len];
in.readFully(msgbytes);
DataInputStream msgin = new DataInputStream(new ByteArrayInputStream(msgbytes));
String somedata = msgin.readUTF();
short somenumber = msgin.readShort();
if (somenumber == 295) {
Bukkit.getLogger().info("Updating config...");
String[] toWrite = somedata.split(" |n| ");
String path = (this.getDataFolder() + "/config.yml");
clearFile(path);
for (String s : toWrite) {
writeFile(path, s);
}
Bukkit.getLogger().info("Config updated!");
}
} else {
Bukkit.getLogger().info("Message sent by this plugin.");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
The way I send the message is just by calling, updateConfig(); When that is called, onPluginMessageReceived is never run.
Is there something I'm doing wrong? Can plugin messages only be sent by a bungeecord plugin? Thanks in advance. If you have any questions about the code, let me know.

Don't work beacause it's write ( String server to send to, or ALL to send to every server (except the one sending the plugin message)) ! For use it you can use our own channel or redis

Related

Why can't my web client accept an image from my web server?

I this is my java HTTP server:
public class WebServer implements Runnable {
public static final int PORT = 80;
#Override
public void run() {
HttpServer $server;
try {
$server = HttpServer.create(new InetSocketAddress(80), 0);
} catch (IOException _e) {
throw new RuntimeException(_e);
}
$server.createContext("/", _httpExchange ->
{
String $uri = _httpExchange.getRequestURI().toString();
$uri = $uri.startsWith("/") ? $uri.replaceFirst("/", "") : $uri;
if ($uri.equals("")) {
sendFile("test.html", _httpExchange);
}
else if ($uri.matches(".*\\.[^/.]+")) {
sendFile($uri, _httpExchange);
}
else {
sendFile($uri + ".html", _httpExchange);
}
});
$server.start();
System.out.println("Server started at " + getPrivateIp() + " on port " + PORT);
}
private static String getPrivateIp() {
try (final DatagramSocket datagramSocket = new DatagramSocket()) {
datagramSocket.connect(InetAddress.getByName("8.8.8.8"), 12345);
return datagramSocket.getLocalAddress().getHostAddress();
} catch (UnknownHostException | SocketException _e) {
throw new RuntimeException(_e);
}
}
public static void sendFile(String _name, HttpExchange _exchange) throws IOException {
try {
InputStream $stream = WebServer.class.getResourceAsStream(_name);
if ($stream == null) {
_exchange.sendResponseHeaders(404, 0);
_exchange.close();
return;
}
Scanner $scanner = new Scanner($stream).useDelimiter("\\A");
String $response = $scanner.next();
_exchange.getResponseBody();
_exchange.sendResponseHeaders(200, $response.getBytes().length);
_exchange.getResponseBody().write($response.getBytes());
_exchange.close();
} catch (Exception _ex) {
throw new RuntimeException(_ex);
}
}
}
When I run it, and then open my website, everything is ok, but I cannot see any images. In the network tab, it says that the image was accepted, but it's not shown. I tried using Files.copy() in sendFile() method, but it didn't work - it didn't show the website, nor the image! (Not even when I did localhost/image.jpg).
In the network tab, it also shows that the MIME type is img/jpeg, which is correct, so it's not because of that...
Using wget, I get a normal looking .jpg file, but if I open it, it's corrupted...
Does someone know how to fix this?
Thanks.
Solved it!
You just check if the request wants .png or .jpg file (or you can just check the MIME type), and if it does, then you have to use ImageIO class
public static void sendFile(String _name, HttpExchange _exchange) {
try {
InputStream $stream = WebServer.class.getResourceAsStream(_name);
if ($stream == null) {
_exchange.sendResponseHeaders(404, 0);
_exchange.close();
return;
}
if (_name.matches(".*?\\.(png|PNG|jpg|JPG|jpeg|JPEG)")) {
BufferedImage $image = ImageIO.read($stream);
if (_name.toLowerCase().endsWith("png")) {
_exchange.sendResponseHeaders(200, getImageSize($image, "png"));
ImageIO.write($image, "png", _exchange.getResponseBody());
}
else {
_exchange.sendResponseHeaders(200, getImageSize($image,"jpeg"));
ImageIO.write($image, "jpeg", _exchange.getResponseBody());
}
$stream.close();
_exchange.close();
return;
}
Scanner $scanner = new Scanner($stream).useDelimiter("$");
String $response = $scanner.next();
_exchange.getResponseBody();
_exchange.sendResponseHeaders(200, $response.length());
_exchange.getResponseBody().write($response.getBytes());
_exchange.close();
} catch (Exception _ex) {
throw new RuntimeException(_ex);
}
}

Java Serial Communication -> Problem with EventListener

i'm trying to use Java Serial Communication to read measured values from a serial device. The task is to send the ASCII Code for 9 (57 in decimal) to the device and it will return the current value that is measured. In first place, I want to make sure that some value is correctly send back. So far, the connection works and when i changed the getListeningEvents() method to check for SerialPort.LISTENING_EVENT_DATA_WRITTEN it worked and showed me my phrase "Reading possible", but in this case this only shows that data got transferred.
So the number is send correctly, but I can't get an answer and the program gets stuck after printing "Written".
In many examples i saw the method notifyOnDataAvailable() for the SerialPort class, but i can't find it in the documentation anymore and i'm not sure if i have to use any other methods to initialize the listener. So my question is, what is wrong about my program, especially my EventListener, that it can't receive or identify the returned value?
Here is my code:
public class ConnectionNew implements SerialPortDataListener {
private SerialPort serialPort = null;
private java.io.OutputStream output = null;
private InputStream input = null;
private SerialPort [] ports = null;
public static void main(String[] args) {
ConnectionNew connect = new ConnectionNew();
connect.connectPort();
connect.initIOStream();
connect.initListener();
connect.writeData();
}
public void connectPort() {
ports = SerialPort.getCommPorts();
System.out.println("Select a port: ");
int i = 1;
for (SerialPort port : ports) {
System.out.println(i++ + ": " + port.getSystemPortName());
}
Scanner s = new Scanner(System.in);
int chosenPort = s.nextInt();
serialPort = ports[chosenPort - 1];
if (serialPort.openPort()) {
System.out.println("Port opened successfully");
} else {
System.out.println("Unable to open the port");
return;
}
}
public boolean initIOStream(){
input = serialPort.getInputStream();
output = serialPort.getOutputStream();
System.out.println("Streams Connected");
return true;
}
public void initListener() {
serialPort.addDataListener(this);
}
public void writeData(){
try {
output.write(57);
output.flush();
System.out.println("Written");
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public int getListeningEvents() {
return SerialPort.LISTENING_EVENT_DATA_RECEIVED;
}
#Override
public void serialEvent(SerialPortEvent arg0) {
System.out.println("Reading possible");
}
}
I'm very happy about any hints, thanks in advance!!
You need to get the data from the event:
public void serialEvent(SerialPortEvent e) {
byte[] data = e.getReceivedData​();
// ...
}

Why is this Class' object not serialized properly in different processes?

Context
I made a Java application, and need to run two instances of that application, synchronizing some of their attributes via socket each time there's some change. To communicate those changes, Serializable objects are sent through a socket using ObjectStreams (input and output) using read/writeUTF() for an identifier, and read/writeObject() and flush(). The app is the exact same .jar, run twice with some changes like having different ports and ip (if necessary).
Problem
I noticed that objects of some of my classes (e.g. Notification) were sent and received without any troubles, but objects from another class (RegisteredUsers) weren't sent (or received) properly. So I ran some tests to send objects between the two apps and found that the object is being sent and isn't null, it's attribute (a HashMap<String,User>) is also being sent and isn't null, but is always empty.
So I decided to scale it down to what the problem was exactly: I'm trying to write an object through a Stream, and read it in a different process of the same .jar, and with most classes it seems to work, but it doesn't with one.
There seems to be something I'm missing or don't understand about this serialization process, if the object is written and read during the execution of the same process it works, but not if this object is read on another instance of the same app. I even added a HashMap to Notification with the same creation process, but it still works, I really don't get it, what am I missing?
Code
I have taken some code from the bigger app and trimmed it down to the basic problem if anyone wants to test it. To reproduce the errors, run Main1, which will create the two files with an object persisted in each one (one with a Notification object and the other with a RegisteredUsers object) and shows their information, then Main2, which reads them from the files and shows their information, and the problem should be printed. That being that reg3's HashMap is empty and thus neither of the Users are registered.
Main1
public class Main1 {
public static void main(String[] args) {
String regFile = "registry.txt";
String notificationFile = "notification.txt";
Persistence pers = new Persistence();
RegisteredUsers reg1 = new RegisteredUsers();
RegisteredUsers reg2 = new RegisteredUsers();
reg1.register("Name1", "127.0.0.1");
reg1.register("Name2", "127.0.0.1");
try {
pers.writeReg(reg1, regFile);
} catch (IOException e) {
System.out.println("Error writing registry.");
}
try {
reg2 = pers.readReg(regFile);
} catch (IOException e) {
System.out.println("Error reading registry.");
}
System.out.println("Original registry: ");
System.out.println(reg1.isRegistered("Name1") + " " + reg1.isRegistered("Name2"));
System.out.println("Registry read from file: ");
System.out.println(reg2.isRegistered("Name1") + " " + reg2.isRegistered("Name2"));
Notification noti1 = new Notification("Name", "127.0.0.1");
Notification noti2 = new Notification(); //not necesary but it's the way it's done in the bigger app.
try {
pers.writeNotif(noti1, notificationFile);
} catch (IOException e) {
System.out.println("Error writing notification.");
}
try {
noti2 = pers.readNotif(notificationFile);
} catch (IOException e) {
System.out.println("Error reading notification.");
}
System.out.println("Original notification: ");
System.out.println(noti1.getAttributes().get(0) + " " + noti1.getAttributes().get(1));
System.out.println(noti1.getMap());
System.out.println("Notification read from file: ");
System.out.println(noti2.getAttributes().get(0) + " " + noti2.getAttributes().get(1));
System.out.println(noti2.getMap());
}
}
Main2
public class Main2 {
public static void main(String[] args) {
String regFile = "registry.txt";
String notificationFile = "notification.txt";
Persistence pers = new Persistence();
RegisteredUsers reg3 = new RegisteredUsers();
try {
reg3 = pers.readReg(regFile);
} catch (IOException e) {
System.out.println("Error reading registry.");
}
if (reg3 == null) {
System.out.println("reg3 is null");
}
if (reg3.getMap() == null)
System.out.println("reg3 has a null map");
if (reg3.getMap().isEmpty())
System.out.println("reg3 has an empty map");
System.out.println("Registry read from file on another process: ");
System.out.println(reg3.isRegistered("Name1") + " " + reg3.isRegistered("Name2"));
Notification noti3 = new Notification(); //not necesary but it's the way it's done in the bigger app.
try {
noti3 = pers.readNotif(notificationFile);
} catch (IOException e) {
System.out.println("Error reading notification.");
}
System.out.println("Notification read from file on another process: ");
System.out.println(noti3.getAttributes().get(0) + " " + noti3.getAttributes().get(1));
System.out.println(noti3.getMap());
}
}
A Class to persist the objects in the files:
public class Persistence {
public void writeReg(RegisteredUsers regus, String file) throws IOException {
try(FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);) {
oos.writeObject(regus);
oos.flush();
}
}
public RegisteredUsers readReg(String file) throws IOException {
RegisteredUsers regus = null;
try(FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);) {
regus = (RegisteredUsers) ois.readObject();
} catch (ClassNotFoundException e) {
System.out.println("Wrong class.");
}
return regus;
}
public void writeNotif(Notification regus, String file) throws IOException {
try(FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);) {
oos.writeObject(regus);
oos.flush();
}
}
public Notification readNotif(String file) throws IOException {
Notification notif = null;
try(FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);) {
notif = (Notification) ois.readObject();
} catch (ClassNotFoundException e) {
System.out.println("Wrong class.");
}
return notif;
}
}
RegisteredUsers
public class RegisteredUsers implements Serializable {
private static HashMap<String, User> users;
public RegisteredUsers() {
users = new HashMap<String, User>();
}
public HashMap<String, User> getMap() {
return users;
}
public boolean isRegistered(String name) {
User us = users.get(name);
return us != null;
}
public void register(String name, String ip) {
users.put(name, new User(name, ip, false));
}
}
Notification
public class Notification implements Serializable {
private ArrayList<String> attributes;
private HashMap<String, User> map = new HashMap<>();
public Notification() {
}
public Notification(String name, String ip) {
attributes = new ArrayList<String>();
attributes.add(0, name);
attributes.add(1, ip);
map.put(ip, new User(name, ip, false));
}
public ArrayList<String> getAttributes() {
return attributes;
}
public HashMap<String, User> getMap() {
return map;
}
}
User
public class User implements Serializable {
private String name;
private String ip;
private boolean connection_state;
public User(String name, String ip, boolean connection_state) {
this.name = name;
this.ip = ip;
this.connection_state = connection_state;
}
}
In java static fields are implicitly transient, and transient fields are not serialized.
If you modify the RegisterdUsers to
public class RegisteredUsers implements Serializable {
private HashMap<String, User> users; // static modifier is removed
...
}
The serialization will work.

Apache Camel: Download Multiple Files at once using SFTP component

on sftp i have several files with following xyz names:
40_20200313_0cd6963f-bf5b-4eb0-b310-255a23ed778e_p.dat
123_20200313_0cd6963f-bf5b-4eb0-b310-255a23ed778e_p.dat
etc.
I want camel to download all files at once as currently it is downloading file one by one.
Following is camel route and query:
private static String regex() {
return "(22|23|24|25|26|28|29|32|35|40|41|46|52|70|85|88|123)_(?:.*)_p.dat";
}
private static String sftpComponent() {
return "sftp://transit.ergogroup.no/Eyeshare/From_Eyeshare_Test"
+ "?username=Eyeshare_test"
+ "&password=epw3ePOugG" // Stored on wildfly server
+ "&download=true" //Shall be read chunk by chunk to avoid heap space issues. Earlier download=true was used: Harpreet
+ "&useList=true"
+ "&stepwise=false"
+ "&disconnect=true"
+ "&passiveMode=true"
+ "&reconnectDelay=10000"
// + "&bridgeErrorHandler=true"
+ "&delay=300000"
//+ "&fileName=" + sftpFileName
// + "&include=kiki\\.txt"
// + "&include=40_*_p\\.dat"sss
+ "&include="+regex()
+ "&preMove=$simple{file:onlyname}.$simple{date:now:yyyy-MM-dd'T'hh-mm-ss}.processing"
+ "&move=$simple{file:onlyname.noext}.$simple{date:now:yyyy-MM-dd'T'hh-mm-ss}.success"
+ "&moveFailed=$simple{file:onlyname.noext}.$simple{date:now:yyyy-MM-dd'T'hh-mm-ss}.failed";
// + "&idempotentRepository=#infinispan"
// + "&readLockRemoveOnCommit=true";
}
from(sftpComponent()).log("CHU").to(archiveReceivedFile())
Code appears fine but output is not. Anyone kindly suggest
Here some example of aggregator:
from("file:///somePath/consume/?maxMessagesPerPoll=2&delay=5000")
.aggregate(constant(true), new ZipAggregationStrategy()).completion(exchange -> exchange.getProperty("CamelBatchComplete", Boolean.class))
.to("file:///somePath/produce/")
Here maxMessagesPerPoll defining how many files will be archived. But if number of them in folder is lower then maxMessagesPerPoll value it will wait for missing files for complete archive. Here example of ZipAggregationStrategy:
private static class ZipAggregationStrategy implements AggregationStrategy {
private ZipOutputStream zipOutputStream;
private ByteArrayOutputStream out;
#Override
public Exchange aggregate(final Exchange oldExchange, final Exchange newExchange) {
try {
if (oldExchange == null) {
out = new ByteArrayOutputStream();
zipOutputStream = new ZipOutputStream(out);
}
createEntry(newExchange);
return newExchange;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private void createEntry(final Exchange exchange) throws Exception {
final ZipEntry zipEntry = new ZipEntry(exchange.getIn().getHeader(Exchange.FILE_NAME, String.class));
zipOutputStream.putNextEntry(zipEntry);
byte[] bytes = new byte[1024];
int length;
try (InputStream body = exchange.getIn().getBody(InputStream.class)) {
while ((length = body.read(bytes)) >= 0) {
zipOutputStream.write(bytes, 0, length);
}
}
}
#Override
public void onCompletion(final Exchange exchange) {
try {
zipOutputStream.close();
exchange.getIn().setBody(new ByteArrayInputStream(out.toByteArray()));
exchange.getIn().setHeader(Exchange.FILE_NAME, "someArchive.zip");
}catch (Exception e){
throw new RuntimeException(e);
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
It's in-memory example. You can improve it for example with using temporary file. And you can always create your own completion predicate based on your logic.
UPD: i think link for documentation is temporary unavailable

AVD on Windows7 Not able to connect to Linux Server

This pertains to my earlier post "http://stackoverflow.com/questions/8788825/linux-udp-server-unreachable-from-window-7", which has been solved. Now I am moving to my original job of connecting AVD to Linux server.
I am using the following code for connecting to the server
import java.net.*;
class UDPClient {
public final static int DesitnationPort = 9999;
private int mCounter;
private DatagramSocket mClientSocket;
private InetAddress mServerIPAddress;
private byte[] mDataBuffer;
private DatagramPacket mSendPacket;
private DatagramPacket mReceivePacket;
//Constructor
public UDPClient() {
//Time to make the private data good one
mCounter =1;
try {
mServerIPAddress = InetAddress.getByName("192.168.2.2");
}
catch(UnknownHostException e)
{
System.out.println("Host cannot be resolved :( ");
}
System.out.println("Host has been resolved The IP is valid one ");
try {
mClientSocket = new DatagramSocket();
}
catch(SocketException e)
{
System.out.println("Socket could not be created :( ==> " + e.getMessage());
}
System.out.println("Socket has been created ");
String temp = "This is from the Client == To my Dear Sever :) counter = " + mCounter;
mDataBuffer = temp.getBytes();
mSendPacket = new DatagramPacket(mDataBuffer, mDataBuffer.length, mServerIPAddress, DesitnationPort);
System.out.println("Datagram has been made now ");
System.out.println("Data ==>"+ mSendPacket.getData());
System.out.println("Data ==>"+ mSendPacket.getPort());
System.out.println("Data ==>"+ mSendPacket.getSocketAddress());
System.out.println("Data ==>"+ mSendPacket.getLength());
}
public void SendDataToServer(){
try {
if(!mClientSocket.isClosed()) {
String temp = "This is from the Client == To my Dear Sever :) counter = " + mCounter;
mDataBuffer = temp.getBytes();
mSendPacket = new DatagramPacket(mDataBuffer, mDataBuffer.length, mServerIPAddress, DesitnationPort);
mClientSocket.send(mSendPacket);
System.out.println("Send the packet");
mCounter++;
}
else {
System.out.println("Socket is closed");
}
}
catch(Exception e)
{
System.out.println("Could not send the data :( ==> " + e.getMessage());
}
}
public void ReceiveDataFromServer() {
byte[] tembuff = new byte[1024];
mReceivePacket = new DatagramPacket(tembuff, tembuff.length);
try {
if(!mClientSocket.isClosed()) {
mClientSocket.receive(mReceivePacket);
}
else {
System.out.println("Socket is closed");
}
}
catch(Exception e)
{
System.out.println("Could not Receive the data :( ");
return;
}
String data = new String(mReceivePacket.getData());
System.out.println(" Received the Data => " + data);
}
}
This code works well when I simply use the class in java program like this :-
class TryingWithClient {
public static void main(String a[]) {
UDPClient mClient = new UDPClient();
while(true) {
System.out.println("While Starting");
mClient.SendDataToServer();
mClient.ReceiveDataFromServer();
}
}
}
When I use the same code in AVD project I get a Null pointer exception at the following line :-
public void SendDataToServer(){
try {
if(!mClientSocket.isClosed()){ //<==# this call Null exception occurs
After browsing internet & android development sites I came to conclusion that I am missing the GMS / GPS functionality which I added to my AVD. Still I am unable to get any clue about this.
Here is my code which calls the above UDPClient.
public class StreamingProjectActivity extends Activity {
/** Called when the activity is first created. */
//All buttons
//private static final String LOG_TAG = "StreamingTest";
private StreamButton mStreamButton = null;
private UDPClient mClient= null;
class StreamButton extends Button {
boolean mStartStreaming = true;
OnClickListener clicker = new OnClickListener() {
public void onClick(View v) {
onStream(mStartStreaming);
if (mStartStreaming) {
setText("Stop Streaming");
} else {
setText("Start recording");
}
mStartStreaming = !mStartStreaming;
}
};
public StreamButton(Context ctx) {
super(ctx);
setText("Start Streaming");
setOnClickListener(clicker);
}
}//class StreamButton Ends
#Override
public void onCreate(Bundle icicle) {
try {
mClient = new UDPClient();
System.out.println("==========> Client created sucessfully :) <====== ");
super.onCreate(icicle);
LinearLayout ll = new LinearLayout(this);
mStreamButton = new StreamButton(this);
ll.addView(mStreamButton,
new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT,
0));
setContentView(ll);
System.out.println("Trying Step 2 now ");
}
catch(Exception e)
{
System.out.println("Activity could not be launched :( ");
}
}
//public StreamingTest()
public StreamingProjectActivity(){
System.out.println("Constructor ====>");
System.out.println("Constructor <====");
}//Constructor
private void onStream(boolean start) {
if (start)
{
mClient.SendDataToServer();
mClient.ReceiveDataFromServer();
try
{
Thread.sleep(4000);
}catch (InterruptedException ie)
{
System.out.println(ie.getMessage());
}
}
}//onStream
}
Kindly help.
Ok, first of all: never ever print a catched exception with System.out.println("some msg " + e.getMessage()); Please use Log.e(TAG, "my message", e); for that. So you will actually see a stack trace.
Second: I bet that this code throws an error (check if you see the print in your LogCat output):
try {
mClientSocket = new DatagramSocket();
} catch(SocketException e) {
System.out.println("Socket could not be created :( ==> " + e.getMessage());
}
That is the only reason that mClientSocket still might be null. As this call might go wrong, you should consider checking for null before you check if the socket is closed.
The problem in my earlier solution was that I was mixing the GUI & network operations in the same thread which is called "StricMode.ThreadPolicy" (although, my problem is only part of what is mentioned in the jargon).
I was getting these exceptions "android.os.NetworkOnMainThreadException & android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1099) " which I could make out only after I applied WarrenFaith's suggestion (Thanks Warren).
These are thrown only on violation of "StricMode".
Solution : Simply separate the UI work from the network. I had to write the following code for this :
enum ClientThreadStates {
eUndefined,
eStopped,
eRunning,
eIdle,
eSendToServer,
eReadFromServer
}
public class ClientThread extends Thread {
private UDPClient mClient= null;
private ClientThreadStates mStateOfTheThread = ClientThreadStates.eUndefined;
private static String mLOG_TAG;
public ClientThread(String s){
mLOG_TAG = s;
mStateOfTheThread = ClientThreadStates.eStopped;
mClient = new UDPClient(s);
start();
}//constructor
public void SetState(ClientThreadStates paramState) {
mStateOfTheThread = paramState;
}
public ClientThreadStates GetState() {
return mStateOfTheThread;
}
private void Action(ClientThreadStates s) {
synchronized(s) {
switch(mStateOfTheThread) {
case eRunning: //fall
case eIdle: break;
case eSendToServer: mClient.SendDataToServer(); break;
case eReadFromServer: mClient.ReceiveDataFromServer(); break;
}
try {
mStateOfTheThread.wait();
}
catch( InterruptedException e ){
Log.e(mLOG_TAG, "Got Exception at wait <==", e);
}
}
}
public void run() {
mStateOfTheThread = ClientThreadStates.eRunning;
System.out.println("In Thread.run .. The State is " + mStateOfTheThread);
while(ClientThreadStates.eStopped.compareTo(mStateOfTheThread) < 0){ //state >stopped
Action(mStateOfTheThread);
}//while
}//run
}//class ClientThread
Finally synchronize on the two threads on the state like this :
private void onStream(boolean start) {
ClientThreadStates State = mClientThread.GetState();
synchronized(State) {
if (start) {
mClientThread.SetState(ClientThreadStates.eSendToServer);
}
else {
mClientThread.SetState(ClientThreadStates.eReadFromServer);
}
try {
State.notify();
}
catch( IllegalMonitorStateException e ) {
Log.e(LOG_TAG, "Got Exception # notify <==", e);
}
}
}//onStream
}//StreamingProjectActivity
Now the code runs perfectly.
Thanks.
Ashutosh

Categories