Sending object, int and String via socket, serialisation - java

so I have a PrintWriter and a ObjectOutputStream trying to send an int, String and a Color[] from the client when the user clicks the list, where 'out' is the PrintWriter and outObject is the ObjectOutputStream.
private class MyMouseListener implements MouseListener{
public void mouseExited(MouseEvent e){}
public void mouseEntered(MouseEvent e){}
public void mouseClicked(MouseEvent e){
if(e.getSource() == list){
int index = list.locationToIndex(e.getPoint()); ///get the game that the player has selected
try{
out.println(index);
out.println("hel");
Color[] colors = new Color[5];
outObject.writeObject(colors)
}
}
Server, where 'in' is a scanner, 'objectIn' is an objectInputStream :
while(true)
if(in.nextLine().equals("hel")){
System.out.println("fee");
}
else if(in.hasNextInt()){
System.out.println("dee");
}
Object o = objectIn.readObject();
if(o instanceof Color[]){
System.out.println("ree");
}
If i try to send all three, on the first click the server only registers the String, and then all clicks after the server only registers the int, never registering the Color[], if i send the int first, then the Color[] and then the int like :`
out.println(index);
Color[] colors = new Color[5];
outObject.writeObject(colors);
out.println("hel");
Only the int and Object are registered first, on the second click only the String and then subsequent clicks only the int.
`
Object o = objectIn.readObject();
if(in.nextLine().equals("hel")){
System.out.println("fee");
}
//Object o = objectIn.readObject();
else if(in.hasNextInt()){
System.out.println("dee");
}
else if(o instanceof Color[]){
System.out.println("ree");
o = null;
}
If I use the above series of if statements nothing is registered
Using the first series of if statements, if i try to send the Color[] on it's own it's not registered, but if I send it with an int both are registered.
If i try to send the String and the Color[], sending the String first like so :
out.println("hel");
Color[] a = new Color[5];
outObject.writeObject(a);
both are registered once and then never again, also in the opposite way than was expected i.e the Color[] was registered first and then the String; if i send both but the Color[] first and then the String neither are registered.

I assume your out object (which is a PrintWriter) wraps the outObject object, which is the ObjectOutputStream. You should not use both a PrintWriter and a ObjectOutputStream for the same underlying connection. See this question for more details.

Related

How to handle async calls and transferring information

So I'm completely lost on this one, it might be obvious solution or I'm just trying somethin that's not possible but here it is.
I have two classes one is being used as e listener class and second one is the one that handles queue(i will only include relevant code).
Handler class:
public void check() {
for (Queueable queueable : queue) {
if (!doesReceiverHavePlayers(queueable)) continue;
}
}
private boolean doesReceiverHavePlayers(Queueable queueable) {
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF("PlayerCount");
out.writeUTF(queueable.getReceiver());
Player player = Iterables.getFirst(Bukkit.getOnlinePlayers(), null);
player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray());
return /*response*/ > 0;
}
Listener class:
#Override
public void onPluginMessageReceived(String channel, #NotNull Player player, byte[] message) {
if (!channel.equals("BungeeCord")) return;
ByteArrayDataInput in = ByteStreams.newDataInput(message);
String subChannel = in.readUTF();
switch (subChannel) {
case "PlayerCount":
int response = in.readInt();
break;
}
}
The check method is called every 5 seconds and doesReceiverHavePlayers requests player count from a certain server to see if there are any players on it, but the 'response' arrives in the listener class onPluginMessageReceived method. But as you can see I'm trying to use response in the doesReceiverHavePlayers method and return boolean value. Is there any way I can achieve this and how should I do it?
In onPluginMessageReceived store the result in a ConcurrentHashMap and then lookup the value in doesReceiverHavePlayers instead of making a blocking call.
Something like this:
ConcurrentHashMap<String, Integer> playerCounts = new ConcurrentHashMap<>();
void onPluginMessageReceived() {
playerCounts.put(subChannel, response);
}
boolean doesReceiverHavePlayers() {
return playerCounts.get(queueable.getReceiver()) > 0;
}

Is there a way to catch a players chat input without an AsyncPlayerChatEvent?

I'm once again writing another Banksystem plugin, but this time with an ATM. I'm trying to figure out how to get a players chat-input after clicking on the option, to prevent clicking 100 times to deposit 50,000 Dollars on the bank-account.
I'm writing this Plugin with Paper-Spigot 1.14.4 and I've tried following steps:
A AsyncPlayerChatEvent as a separate Class, which activates only when I register the Event with the Pluginmanager:
Bukkit.getPluginManager().registerEvents(new ChatListener(), Main.getPlugin());
Creating a private AsyncPlayerChatEvent variable e with get- and set-method, and calling it in the method when I need it.
String input = getChat().getMessage();
My current chatListener() Method:
public void chatListener(Inventory inv, Player pl) {
pl.closeInventory();
pl.sendMessage("§6Please enter your amount:");
String input = getChat().getMessage();
if(input.matches("[0-9]+")) {
pl.openInventory(inv);
inv.setItem(0, new ItemStack(Material.AIR));
inv.setItem(0, CustomHeads.customHead(CustomHeads.BITCOIN,
input));
} else {
pl.sendMessage("§cPlease enter only numeric characters!");
}
}
AsyncPlayerChatEvent get-method:
public AsyncPlayerChatEvent getChat() {
return chat;
}
I expect the message of the player to be saved inside the input variable, after the message "Please enter your amount:" appears.
When I create a System.out.println(input), the console shows nothing, including neither errors nor any warnings.
Create an AsyncPlayerChatEvent and a public static ArrayList.
ExampleChatEvent.class
public static ArrayList<Player> waitingForAmountPlayers = new ArrayList<>();
public void onChat(AsyncPlayerChatEvent e) {
Player p = e.getPlayer();
if (waitingForAmountPlayers.indexOf(p) != -1) {
//
// YOUR CODE
//
waitingForAmountPlayers.remove(p);
}
}
Don't forget to add the player to waitingForAmountPlayers when you want to type the player the amount in the chat (ExampleChatEvent.waitingForAmountPlayers.add(p);).

How can I save the color/size of a JLabel in a file?

I am trying to save the color, text and size (gridheight/gridwidth) of a JLabel in a file. So whenever the program runs I can view past JLabels.
I know how to read/write Strings onto a file but is it possible to save the state of a JLabel?
JLabel is a serialized object, you can save the whole JLabel object in a file using ObjectOutputStream and read it from ObjectInputStream. Like this.
UPDATED THE PREVIOUS CODE ACCORDING TO DataObject CLASS:
public static void main(String[] args) {
// Creating a JLabel
JLabel label = new JLabel("REHAN JAVED");
label.setForeground(Color.RED);
label.setSize(new Dimension(500, 500));
// adding it into the file.
addItIntoFile(new DataObject(label, 200, 50, 0, 1));
// reading file..
DataObject dataObj = readDataObject();
JLabel newLabel = dataObj.getLabel();
int x = dataObj.getXPosition();
// and take all the data from getters.
System.out.println(newLabel.getText()+"\n"+newLabel.getForeground()+"\n"+label.getSize());
}
public static void addItIntoFile(DataObject dataObj) {
File file = new File("data.txt");
try {
file.createNewFile();
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
oos.writeObject(dataObj);
oos.close();
// You can handle the different exceptions according to you.
} catch (Exception e) {
e.printStackTrace();
}
}
public static DataObject readDataObject() {
DataObject dataObj = null;
try {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("data.txt")));
dataObj = (DataObject) ois.readObject();
ois.close();
// You can handle the different exceptions according to you.
} catch (Exception e) {
e.printStackTrace();
}
// Handling null data..
if(dataObj == null) {
dataObj = new DataObject(new JLabel(), 0, 0, 0, 0);
}
return dataObj;
}
It will works fine with it. :)
UPDATED VERSION:
To include the grid constraints like width, height, x, and y positions, create a new class and implements the Serializable interface with it and store it directly into the file.
public class DataObject implements Serializable {
private JLabel label;
private int gridWidth;
private int gridHeight;
private int gridXPosition;
private int gridYPosition;
// Your Constructor..
public DataObject(JLabel label, int gridWidth, int gridHeight,
int gridXPosition, int gridYPosition) {
this.label = label;
this.gridWidth = gridWidth;
this.gridHeight = gridHeight;
this.gridXPosition = gridXPosition;
this.gridYPosition = gridYPosition;
}
// your getter and setters...
}
You have to define what you need to save, and how.
What to save
You need to define what is important for you, as an example the color can be the with or without transparency informations.
The text can be a simple string or an object holding informations like character type, size, decorations (bold, underline... ).
How to save
You need to define a format for each information (for example the color can be saved with its name "red" or its hex value "#FF0000" or can be a reference to a custom variable "mainColorTemplate1").
You need also to define a format of the file (xml, json, custom binary, property file, yaml...).
I suggest to try the simplest solution for your knowledge. It is very simple to hold all the data in an object and save it as JSon using libraries like GSon or Faster Jackson.
Here is a possible format in json:
{
"labels": [
{
"text":"My first label",
"x":2,
"y":1,
"color":"#FF0000"
},
{
"text":"My Second label",
"x":4,
"y":3,
"color":"#FFFF00"
}
]
}
One way do it is, by utilizing object Serialization. All Swing components implement Serializable interface. You can save the component and the next time you run the application, the component will be as you left it. Two interesting questions to read about this are: Why is Java Swing serializable? and Swing components and serialization.

JFrame progressbar doesn't update when downloading [duplicate]

OK so I have the uploader uploading files using the Java FTP, I would like to update the label and the progress bar. Label with the percent text, bar with the percent int value. Right now with the current code only get the 100 and full bar at the end of the upload. During the upload none of them change.
here it is:
OutputStream output = new BufferedOutputStream(ftpOut);
CopyStreamListener listener = new CopyStreamListener() {
public void bytesTransferred(long totalBytesTransferred, int bytesTransferred, long streamSize) {
System.out.printf("\r%-30S: %d / %d", "Sent", totalBytesTransferred, streamSize);
ftpup.this.upd(totalBytesTransferred,streamSize);
}
public void bytesTransferred(CopyStreamEvent arg0) { }
};
Util.copyStream(input, output, ftp.getBufferSize(), f.length(), listener);
}
public void upd(long num, long size){
int k = (int) ((num*100)/size);
System.out.println(String.valueOf(k));
this.d.setText(String.valueOf(k));
//d.setText(String.valueOf(k));
progressBar.setValue(k);
}
From the sounds of it (and lacking any evidence to the contree) it sounds like your processing a time consuming action in the Event Dispatching Thread
You might like to read Concurrency in Swing for some further insight
I'd suggest using a SwingWorker to perform the actual transfer & take advantage of its built in progress support
UPDATE after seeing source code
Don't mix heavy weight components with light weight components. Change Applet to JApplet, change TextField to JTextField, don't use Canvas use a JPanel or JComponent
If you expect other people to read your code, please use proper names for your variables, I have no idea what p is.
Your Thread is useless. Rather then starting the thread and using it's run method you simply make your download call within it's constructor. This will do nothing for you...
Remove your implementation of MyThread and replace it with
public class MyWorker extends SwingWorker<Object, Object> {
private URL host;
private File outputFile;
public MyWorker(URL host, File f) {
this.host = host;
outputFile = f;
}
#Override
protected Object doInBackground() throws Exception {
// You're ignoring the host you past in to the constructor
String hostName = "localhost";
String username = "un";
String password = "pass";
String location = f.toString();
//FTPClient ftp = null;
ftp.connect(hostName, 2121);
ftp.login(username, password);
ftp.setFileType(FTP.BINARY_FILE_TYPE);
ftp.setKeepAlive(true);
ftp.setControlKeepAliveTimeout(3000);
ftp.setDataTimeout(3000); // 100 minutes
ftp.setConnectTimeout(3000); // 100 minutes
ftp.changeWorkingDirectory("/SSL");
int reply = ftp.getReplyCode();
System.out.println("Received Reply from FTP Connection:" + reply);
if (FTPReply.isPositiveCompletion(reply)) {
System.out.println("Connected Success");
}
System.out.println(f.getName().toString());
File f1 = new File(location);
in = new FileInputStream(f1);
FileInputStream input = new FileInputStream(f1);
// ftp.storeFile(f.getName().toString(),in);
//ProgressMonitorInputStream is= new ProgressMonitorInputStream(getParent(), "st", in);
OutputStream ftpOut = ftp.storeFileStream(f.getName().toString());
System.out.println(ftpOut.toString());
//newname hereSystem.out.println(ftp.remoteRetrieve(f.toString()));
OutputStream output = new BufferedOutputStream(ftpOut);
CopyStreamListener listener = new CopyStreamListener() {
public void bytesTransferred(final long totalBytesTransferred, final int bytesTransferred, final long streamSize) {
setProgress((int) Math.round(((double) totalBytesTransferred / (double) streamSize) * 100d));
}
#Override
public void bytesTransferred(CopyStreamEvent arg0) {
// TODO Auto-generated method stub
}
};
Util.copyStream(input, output, ftp.getBufferSize(), f.length(), listener);
return null;
}
}
In your ActionListener of o (??) replace the thread execution code with
try {
MyWorker worker = new MyWorker(new URL("http://localhost"), file);
worker.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("progress")) {
Integer progress = (Integer) evt.getNewValue();
progressBar.setValue(progress);
}
}
});
worker.execute();
} catch (MalformedURLException ex) {
ex.printStackTrace();
}
Note. You are ignoring the URL you pass to the constructor. http:// is not ftp:// so I doubt this will work...
During the upload you don't see changes to the GUI, because you run the upload and the GUI changes in the same thread.
You should start one threayd that does the upload and another one in EDT (Event-Dispatch-Thread) that does the GUI updates.
For more info see:
The Event Dispatch Thread
You should implement the transfer logic in a SwingWorker, that way the UI will have the chance to present the progress.

JList in UI not reflecting changes from all peer processes

I am writing a simple chat application in Java. As soon as a new user joins, the server component of my application should inform all other clients about this event.
The relevant code on the server side is as follows:
private void notifyUser() throws IOException {
String[] user = new String[onlineUsers.size()];
int i = 0;
for(Socket sock : sockets){
out.get(i).writeInt(1);
out.get(i).writeObject(onlineUsers.toArray(user));
out.get(i).flush();
}
}
The client thread is listening on the socket using the following code:
ObjectInputStream in = new ObjectInputStream(sockfd.getInputStream());
while(true) {
command = in.readInt();
switch(command) {
case 1:
String[] user = (String[])in.readObject();
System.out.println(user);
client.addOnlineUsers(user);
}
}
The addOnlineUsers(..) method consists of the following code:
public void addOnlineUsers(String[] user) {
for(String s : user){
listmodel.addElement(s);
}
}
I have instantiated the JList like so:
JList list = new JList(listmodel);
, where listmodel is a public instance.
The problem is, however, that as soon as a new user joins the server, the JList of the 1st (i.e. the oldest) client is updated while the rest of the users don't receive any updates to the JList in their UI.
In the notifyUser method, you are only writing to the output stream of the first user in the array, i.e.
i = 0;
It should be incremented after
out.get(i).flush();

Categories

Resources