Serlvet mixing session responses - java

I'm developing an Android printing application. A part of my application is a local server that receive files from the users.
I implemented the server in Tomcat Java servlet.
My problem is that when two devices sending 2 files instantaneously to the server, there is two possible results:
1. One client receives a good response, and the second client receives an empty response.
2. One client receives a response of the second client and vise versa.
Here is my servlet code:
protected void doPost(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException {
new Runnable() {
#Override
public void run() {
try {
request.setCharacterEncoding("UTF-8");
} catch (UnsupportedEncodingException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
response.setCharacterEncoding("UTF-8");
try {
writer = response.getWriter();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
// get access to file that is uploaded from client
Part p1 = request.getPart("File");
InputStream is = p1.getInputStream();
// read filename which is sent as a part
Part p2 = request.getPart("MetaData");
Scanner s = new Scanner(p2.getInputStream());
String stringJson = s.nextLine(); // read filename from stream
s.close();
json = new JSONObject(stringJson);
fileName = new String(json.getString("FileName").getBytes("UTF-8"));
fileDirectory = BASE + request.getSession().getId();
File dir = new File(fileDirectory);
dir.mkdir();
// get filename to use on the server
String outputfile = BASE + dir.getName() + "/" + fileName; // get path on the server
FileOutputStream os = new FileOutputStream (outputfile);
// write bytes taken from uploaded file to target file
byte[] buffer = new byte[1024];
int ch = is.read(buffer);
while (ch != -1) {
os.write(buffer);
ch = is.read(buffer);
}
os.close();
is.close();
}
catch(Exception ex) {
writer.println("Exception -->" + ex.getMessage());
}
finally {
try {
myRequest = request;
try {
printFile(request.getSession().getId());
} catch (IOException e) {
// TODO Auto-generated catch block
writer.println("Exception -->" + e.getMessage());
}
writer.close();
} catch (InterruptedException e) {
writer.println("Exception -->" + e.getMessage());
}
}
}
}.run();
}
The tomcat server is running over Ubuntu 13.04 as a virtual machine.
Any idea?

I don't think the use of Runnable makes a difference but it's kind of pointless. I can't see where you declared your writer. If that's an instance variable of the servlet (i.e. not in the post method) then that one is prone to session swapping when used by two sessions at the same time. Try declaring it within the post method.

You need not to implement Runnable. By default Servlets are thread safe, which means a new thread is created for each of the request. If you are using some static variables then make sure you use them in a thread safe way. I think your thread creation may be troubling the tomcat/container to send the response in an incorrect way. In short I believe you are doing more than is required, container is there for your rescue.

Any web container manages multi-threading of servlets. You need not implement your own thread. Remove the multi-threading from your code and it will work perfectly.

Related

Apache commons FPTSClient explicit transfer file is incomplete

Iam currently struggling a little bit with the FTPSClient from Apache Commons. See code down below. I try to write a file to FTP Server (vsftpd) when using FTPClient things are working perfectly fine. When using my code snippet I will always get a 451 Error, when debugging and waiting after Util.copyStream() returned everything works fine or settings a Thread.sleep(100). This also does not happen when I do not set the ftpsClient.execProt("P). Does anyone know by what this could be caused.
final FTPSClient client;
client = new FTPSClient("TLS", false);
client.setUseClientMode(true);
client.setDefaultPort(21);
// connect
try {
client.connect("serverAddress", 21);
} catch (SSLException e) {
throw e;
}
// setup any after connected
client.setSoTimeout(300);
client.setListHiddenFiles(true);
client.enterLocalPassiveMode();
FTPClientConfig ftpConfig;
try {
ftpConfig = new FTPClientConfig(client.getSystemType());
} catch (FTPConnectionClosedException e) {
throw e;
} catch (IOException e) {
ftpConfig = new FTPClientConfig();
}
client.configure(ftpConfig);
final FTPSClient ftpsClient = client;
// remove data buffer limit
ftpsClient.execPBSZ(0);
// set data channel encrypted
ftpsClient.execPROT("P");
client.login("user", "password");
if (!FTPReply.isPositiveCompletion(client.getReplyCode())) {
throw new IOException("Authentication failed: " + client.getReplyString().trim());
}
// postconfigure connection
if (!client.setFileTransferMode(FTP.STREAM_TRANSFER_MODE) || !client.setFileType(FTP.BINARY_FILE_TYPE)) {
throw new IOException("Failed to correctly configure client: " + client.getReplyString().trim());
}
InputStream input;
OutputStream output;
input = new FileInputStream(pathToLocalFile);
output = client.storeFileStream("foobar.txt");
final var number = Util.copyStream(input, output);
System.out.println(number);
input.close();
// Thread.sleep(100);
output.close();
// Must call completePendingCommand() to finish command.
if (!client.completePendingCommand()) {
client.logout();
client.disconnect();
System.err.println("File transfer failed.");
}
This library has been around for a long time, and things change a bit under the hood. Try:
input = new FileInputStream(pathToLocalFile);
boolean result = client.storeFile("foobar.txt", input);
if (result) {
System.out.println("\tFile Transfer Completed Successfully");
}
I have noticed that every once in a while when transferring files to a mainframe, it won't complete. I think it has something to do with the file length, but I've never been able to track it down. I also don't use the stream_transfer_mode.

How to convert FTP from Spring MVC to Spring Boot/Thymeleaf?

So I've been working on taking the logic from an older webapp and making a new Spring Boot application out of it. I've come to a stuck spot regarding an ftp connection and call. Since I don't have a bunch of experience with this, I'm curious if there is a better/more modern way to handle most of this ftp stuff using Spring Boot/Thymeleaf and ways to go ahead and set that up. Any advice/guidance would be fantastic.
This is the older code that I'd like to modernize a bit.
String serverName = getFtpServer();
// Connect to the server
try {
ftp.connect(serverName);
ftp.enterLocalPassiveMode();
String replyText = ftp.getReplyString();
System.out.println(replyText);
} catch (Exception e) {
e.printStackTrace();
return false;
}
// Login to the server
try {
ftp.login(userName, password);
String replyText = ftp.getReplyString();
System.out.println(replyText);
} catch (Exception e) {
e.printStackTrace();
return false;
}
// Tell server that the file will have JCL records
try {
ftp.site("filetype=jes");
String replyText = ftp.getReplyString();
System.out.println(replyText);
} catch (Exception e) {
e.printStackTrace();
return false;
}
// Submit and run the JCL
try {
System.out.println("TRYING TO START MAINFRAME JCL");
submitJcl(filename, serverName);
String replyText = ftp.getReplyString();
System.out.println(replyText);
} catch (Exception e) {
String replyText = ftp.getReplyString();
System.out.println(replyText);
e.printStackTrace();
return false;
}
// Quit the server
try {
ftp.quit();
} catch (Exception e) {
e.printStackTrace();
}
Storing the file
private String submitJcl(String remoteFile, String serverName) throws IOException {
String filePath = getFilePath();
String result = "";
String fileName = filePath + remoteFile;
System.out.println("filePath = " + fileName);
FileInputStream inputStream = new FileInputStream(fileName);
ftp.storeFile(serverName, inputStream);
return result;
}
For this I figured out that there may be better ways to change it into the newer ftp format for Spring Boot, but this still completely works.
Changes I made to it regardless:
Consolidated the try/catch blocks into one.
Pushed the ftp stuff into its own function and then just called it inside the try/catch block
Changed all of the sys.out's to info.debugs.
Changed the way it gets the filePath to more of a relative path with the file stored within the system instead of user files.

Can't send objects using Sockets

Hello Im writing an app in which client sends name of room to server, server creates it and then sends back whole list of rooms. I have problem with receiving this object from server also whats interesting when I close clients' app and open again I have list of rooms just like it should be. I refresh room list in client app but its always empty only reopening helps that's pretty weird and I don't know an issue of this.
On client side:
getIs() method is returning is object
getOs() method returning os object
this.os = new ObjectOutputStream(clientSocket.getOutputStream());
this.is = new ObjectInputStream(clientSocket.getInputStream());
private void createRoom(ActionEvent event) {
String roomName = "CreateRoom ";
roomName += setRoomName();
String response = null;
try {
client.getOs().writeObject(roomName);
response = (String) client.getIs().readObject();
System.out.println(response);
} catch (IOException | ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void refreshRooms() {
String response = null;
try {
client.getOs().writeObject("RefreshRooms");
response = (String) client.getIs().readObject();
System.out.println(response);
rooms = (Rooms) client.getIs().readObject();
System.out.println("Print in client: ");
rooms.printAllRooms();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Server:
this.os = new ObjectOutputStream(connection.getOutputStream());
this.is = new ObjectInputStream(connection.getInputStream());
public void run() {
String inputRequest = null;
try {
while((inputRequest = (String) ois.readObject()) != null) {
System.out.println(inputRequest);
handleRequest(inputRequest);
}
} catch (IOException | ClassNotFoundException e) {
System.out.println("Client has disconnected.");
e.printStackTrace();
}
}
private void handleRequest(String request) {
String response = null;
String[] msg = request.split(" ");
if(msg[0].equals("CreateRoom")) {
try {
oos.writeObject("You want create a room.");
Room newRoom = new Room(msg[1]);
rooms.addRoom(newRoom);
System.out.println("Created room: " + newRoom.getName());
System.out.println("\n Print after creation: ");
rooms.printAllRooms();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else if (msg[0].equals("RefreshRooms")) {
try {
oos.writeObject("You want list of rooms.");
System.out.println("Print before send.");
rooms.printAllRooms();
oos.writeObject(rooms);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
///EDIT:
So I removed PrintWriter and BufferedReader objects and now Im using only Object Streams. What doesn't work now is:
I create some rooms one after another and then refresh rooms list on clients app - in that case I get all rooms
But when I create one room refresh then create another and refresh I get only 1 room after 2nd refresh, so basically when I refresh server sends me always the same object from 1st send and I don't know how to change it.
Also Im printing these rooms on server side and always get all rooms so room creation is OK.
You could try to flush the buffered streams:
os.flush()
This will force the stream to actually send the bytes of the serialized object. Without that, the BufferedOutputStream might just wait around and buffer data, as the name says. This is done so that the size of the sent packets does not become too small, which would result in a lot of overhead if you want to send multiple objects.
If you are done, you should close the stream anyway.

Java client sending multiple requests instead of one

I'm setting up a basic client server program. Right now the client is simply sending an object with a command string in it to the server and the server is acknowledging it. This is done using a JFrame with buttons on it. It seems to work ok, except the client seems to be sending multiple requests instead of just one.
Inner class within my Client code:
private class CommandHandler implements ActionListener{
FTPCommand c;
ObjectOutputStream oos;
#Override
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
if (cmd == "DIR"){
c = new FTPCommand("DIR");
}
if (cmd == "CHDIR"){
String newDirectory = JOptionPane.showInputDialog("Please enter directory to change to:");
c = new FTPCommand("CHDIR", newDirectory);
}
try {
oos = new ObjectOutputStream(sock.getOutputStream());
oos.writeObject(c);
oos.flush();
//System.out.println("Command: " + c.getCommand() + ", sent successfully");
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
Server:
public void run(){
ObjectInputStream in;
try {
in = new ObjectInputStream(sock.getInputStream());
FTPCommand cmd = (FTPCommand) in.readObject();
System.out.println("Received command: " + cmd.getCommand() + " at " + System.currentTimeMillis());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
So if I click on the DIR button just once, this is the output I get, although sometimes it might just be one or two lines:
Received command: DIR at 1390572358017
Received command: DIR at 1390572365578
Received command: DIR at 1390572377229
Why is it sending multiple requests?
Check inside the constructor of FTPCommand; that how many time... it has been called... If thrice .... trace the calling methods.
It turns out that this was the result of the client holding onto previous connections, and sending requests through all open sockets.

Making a small program part as a bigger one in java. Multithreading?. Noobs

I am working on a small project where I have to communicate to an Android app on my phone and with Arduino.
Now, I have the connection between Android and laptop (used as server, I have a small amount of data stored here), and I can change the contents of text files when I send certain instructions from Android app.
This is how I do it:
I have a ServerSide class that listens on port 3000 and I read the text I stream from phone, then I make certain changes in text files for different messages.
The code:
public class ServerSide {
public static void main(String[] args) throws IOException {
while (true) {
ServerSocket serverSocket = null;
// check if client is trying to connect
try {
serverSocket = new ServerSocket(3000);
} catch (IOException e) {
System.err.println("Cannot communicate on this port");
System.exit(1);
}
Socket clientSocket = null;
// move to another socket
try {
clientSocket = serverSocket.accept();
} catch (IOException e) {
System.err.println("Accept failed");
System.exit(1);
}
// stream that will be sent to client. "true" is for creating from
// existing
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(),
true);
// stream that comes from the client
BufferedReader in = new BufferedReader(new InputStreamReader(
clientSocket.getInputStream()));
String recivedData, sendData;
ServerProtocol communicationProtocol = new ServerProtocol();
while ((recivedData = in.readLine()) != null) {
sendData = communicationProtocol.process(recivedData);
out.println(sendData);
System.out.println("The text should now be written in file");
System.out.println(sendData);
}
in.close();
out.close();
clientSocket.close();
serverSocket.close();
}
}
}
ServerProtocol.process() is the method that updates the files
By the way, this is a good version of a program that implies connection via sockets (if anyone should need information about this, at a future time).
Everything works great, I can see my updates immediatly after I send them, the server is up and running, waiting for messages.
I forgot to mention, I am new to java and a novice in programming, in general.
Now, I want this code I managed to write to be part of a bigger "server". By "server", I understand a program that "serves", performs a service. When it runs on my laptop, it takes information that comes from the Internet on the port I specify, change things in files according to my messages, keeps theese files updated and in the same time it uses theese files to "interpert" data I send from phone, and then sends according messages to Arduino Shield. (THIS IS WHAT I WANT TO ACHIVE)
I guess that what I miss, is the following:
How do i make this code I have written untill now, part of a bigger project, that does all that?
I managed to split the project in 3 parts:
Communication laptop - Android
Constant data updates
Communication laptop - Arduino
I've done some research, and I came across threads. So I thought about having the communication with Android on a separate thread of a MainServer. I clearly got it wrong, because it doesn't do what I expect it to do, so here is the code:
I create the ServerSide class that extends Thread, and has a run() method that should be called when I start the thread. It behaves just like the one above, but the executing code lays inside a run() method:
public class ServerSide extends Thread {
#Override
public void run() {
while (true) {
ServerSocket serverSocket = null;
// check if client is trying to connect
try {
serverSocket = new ServerSocket(3000);
} catch (IOException e) {
System.err.println("Cannot communicate on this port");
System.exit(1);
}
Socket clientSocket = null;
// move to another socket
try {
clientSocket = serverSocket.accept();
} catch (IOException e) {
System.err.println("Accept failed");
System.exit(1);
}
// stream that will be sent to client. "true" is for creating from
// existing
PrintWriter out = null;
try {
out = new PrintWriter(clientSocket.getOutputStream(), true);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// stream that comes from the client
BufferedReader in = null;
try {
in = new BufferedReader(new InputStreamReader(
clientSocket.getInputStream()));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String recivedData, sendData;
recivedData = null;
sendData = null;
ServerProtocol communicationProtocol = new ServerProtocol();
try {
while ((recivedData = in.readLine()) != null) {
try {
sendData = communicationProtocol.process(recivedData);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
out.println(sendData);
System.out
.println("The text should now be written in file");
System.out.println(sendData);
}
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
out.close();
try {
clientSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
serverSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Then, I have the MainServer:
public class MainServer {
public static void main(String[] args) throws IOException {
System.out.println("Started");
Thread myThread = new Thread(new ServerSide());
myThread.start();
System.out.println("Started2");
while (true);
}
}
It should do nothing, just start the new thread. I expect this new thread do act just like the old ServerSide above (the one with main() method).
Someone, please tell me where I got it wrong !?!
Well, two things seem a little unusual about the MainServer class. First, creating a thread with new Thread(new ServerSide()) will cause a compilation error. There are two ways to fix this: either you make ServerSide implement the Runnable interface instead of extending Thread, or you create the thread with new ServerSide(). Second, the infinite loop at the end of main is useless and can be removed. The main method runs in its own thread, and if it finishes, all other threads keep running, and there is no need to keep main alive. The program will indeed keep running when main finishes, which may seem strange, but that's what will happen.
Everything was OK here, my problem was actually my phone connection to wi-fi, I was a bit too far in the back yard :)

Categories