How to pass an InputStream via RMI - java

Consider these two functions:
Function A takes inputStream as parameter.
public void processStream(InputStream stream)
{
//Do process routine
}
Function B loads a file content to pass it to Function A as InputStream.
pulic void loadFile()
{
File file =new File("c:\\file.txt");
//Pass file as InputStream
}
How can I pass file from Function B to Function A as InputStream without reading it on first hand?
I did something like this:
File file = new File("c:\\file.txt");
DataInputStream stream= new DataInputStream(new FileInputStream(file));
This generated the exception below:
java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: java.io.DataInputStream
EDIT:
loadFile() is passing the InputStream as RMI response.

The following should work just fine
processStream(new FileInputStream(file));
You should only not attempt to serialize an InputStream instance by ObjectOutputStream like as
objectOutputStream.writeObject(inputStream);
which you're apparently doing in processStream() method. That's namely exactly what the exception is trying to tell you. How to solve it properly depends on the sole functional requirement which you omitted from the question.
Update as per the comment
I am passing the InputStream as an RMI response.
There's the problem. You cannot pass non-serializable objects around as RMI response, let alone unread streams. You need to read the InputStream into a ByteArrayOutputStream the usual IO way and then use its toByteArray() to get a byte[] out of it and pass that instead. Something like:
InputStream input = new FileInputStream(file);
ByteArrayOutputStream output = new ByteArrayOutputStream();
byte[] buffer = new byte[8192];
for (int length = 0; (length = input.read(buffer)) > 0;) {
output.write(buffer, 0, length);
}
byte[] bytes = output.toByteArray(); // Pass that instead to RMI response.
Be careful with large files though. Every byte of a byte[] eats one byte of JVM's memory.

That exception seems to indicate that you are calling the processStream method on a remote object using something like RMI? if that is the case, you will need to re-visit what you are doing. sending streams of data over RMI is not an easy thing to do. if you are guaranteed to be using small files, you could copy the file data to a byte[] and pass that to the remote method call. if you need to process larger files, however, that will most likely cause memory issues on the client and/or server. in that case, you should use something like rmiio, which provides utilities for streaming data over RMI.

You could just pass the FileInputStream ?
processStream(new FileInputStream(yourFile));
The reason you are getting the exception is because DataInputStream is intended to read primitive Java types

Related

Download .class file and load it into JVM

How can I download .class file and and load it into jvm using class loader , I have write a simple code simulates downloading a .class file the I tried to load it into JVM
public class face {
public static void main(String[] args) throws IOException,
ClassNotFoundException {
File f = new File("Task.class");
int count;
byte[] buffer = new byte[1024];
DataInputStream dis = new DataInputStream(new FileInputStream(f));
StringBuilder all = new StringBuilder();
while ((count = dis.read(buffer)) > 0) {
// System.out.write(buffer, 0, count);
all.append(buffer);
// System.out.flush();
}
File b = new File("Task.class");
FileOutputStream fos = new FileOutputStream(b);
DataOutputStream dos = new DataOutputStream(fos);
dos.write(all.toString().getBytes());
ClassLoader lod = face.class.getClassLoader();
lod.loadClass(b.getAbsolutePath());
}
}
Use Class.forName(<package_qualified_class_name>)
First, I would like to applogies for the long list of suggestion here, but you have managed to cram an impressive number of mistakes into a small piece of code.
I suggest don't do any of these things
don't use DataInputStream or DataOutputStream when it doesn't add anything. You don't use any method which requires it.
don't write binary data to a StringBuilder. A StringBuilder is for text.
don't copy an entire buffer if you only read part of it. i.e. you need to record the length actual read and copy only the amount used.
don't append a byte[] to a StringBuilder. It won't do what you expect.
don't use a String to store binary data.
don't convert a String to byte[] using the default encoding unless you know you have ASCII data (which you don't)
don't write to a file you just read. As this doesn't make sense. You should have tested this works without the file copy and you would have found this didn't work, before you attempted something more complicated.
you can't write to a file which you still have open in windows. I suggest you close() a file when you are finished with it.
don't attempt to load a class using the file name. You load it by package.class name.
I suggest you try a one liner to load a class first and show this works. The class should appear in your class path, and when you write to the file, you should write it to a directory appropriate for the package.
Instead of doing all this, you could add a http://yourserver/basepath to your class path and it will load the classes from a web service. i.e. you might be able to do this without writing any code at all.

change byte[] to inputstream?

I'm using two libraries in an android app I'm trying to make. New to android. The app is for connecting to serial devices and controlling their console via a terminal.
One library is for setting up a serial connection, setting baud rate etc. and can also write read/data over serial.. The other is for creating a terminal session. My problem lies in incorporating both of these together to have a terminal that is connected to a serial device.
In the terminal library I need to supply an InputStream and OutputStream to provide input and output to the terminal. So I have to call setTermIn(java.io.InputStream) and setTermOut(java.io.OutputStream) to connect the input and output streams to the emulator.
In the serial library however there are two methods for sending and receiving and these deal with arrays of bytes.
sendData(byte[] data) for sending data and a dataListener for receiving data. I have to implement this and code the method onDataReceived(int id, byte[] data) with id being the name of the device.
I don't have source code for the function that sends an array of bytes over serial, so how do I make the array of bytes into a stream to send to my terminal?
EDIT:
I think this should override it and that is what I want?
Private USB2SerialAdapter mSelectedAdapter;
...
public void sendData(byte[] data)
{
//this should echo what I send to the terminal in the correct format
ByteArrayOutputStream bos = new ByteArrayOutputStream(data.length);
bos.write(data, 0, data.length);
setTermOut(bos);
//send data over serial using original sendData() method
mSelectedAdapter.sendData(data);
}
These two snippets should give you enough information to find a solution to your problem.
reading:
byte[] source = ...;
ByteArrayInputStream bis = new ByteArrayInputStream(source);
// read bytes from bis ...
writing
ByteArrayOutputStream bos = new ByteArrayOutputStream();
// write bytes to bos ...
byte[] sink = bos.toByteArray();
This should do it: ByteArrayInputStream, ByteArrayOutputStream
Just look at the docs in those cases.

Sending object through TCP socket - ClassNotFoundException

I have two simple applications: client and server. Client encrypts (simple AES) custom object and sends it through TCP socket, as bytes, to the server. Server decrypts those bytes and calls the method that recreates this object, like this:
private static Object getObjectFromBytes(byte[] credentials) throws IOException, ClassNotFoundException{
ByteArrayInputStream bis = new ByteArrayInputStream(credentials);
ObjectInput in = null;
Object credentialsObj = null;
try {
in = new ObjectInputStream(bis);
credentialsObj = in.readObject();
} finally {
bis.close();
in.close();
}
return credentialsObj;
}
On the client side, when I'am encrypting this object, it is of type mds.hm5.client.ITU_Credentials. On the server side, when I'm decrypting it and converting back to object, it should be mds.hm5.tokenservice.ITU_Credentials. Instead I'am getting the following exception:
java.lang.ClassNotFoundException: mds.hm5.client.ITU_Credentials
He is looking for this object by the old classpath. Why is it happening and how should I fix it?
Additional information:
Here is how I convert this object to byte array on the client side:
private static byte[] getBytesFromObject(Object credentials) throws IOException{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutput out = null;
byte[] newBytes = null;
try {
out = new ObjectOutputStream(bos);
out.writeObject(credentials);
newBytes = bos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
} finally {
out.close();
bos.close();
}
return newBytes;
}
The reason why I use generic type Object is because I am going use those methods to convert/encrypt/decrypt multiple types. Is it the proper way?
On the client side, when I'am encrypting this object, it is of type mds.hm5.client.ITU_Credentials.
So that's what it is in the serialized stream.
On the server side, when I'm decrypting it and converting back to object, it should be mds.hm5.tokenservice.ITU_Credentials.
No it shouldn't. It should be the same as when you serialized it [unless you have taken certain magic steps, which clearly you haven't. Without those magic steps there is no magic, and nothing to connect mds.hm5.client.ITU_Credentials with mds.hm5.tokenservice.ITU_Credentials whatsoever]. You have two different classes with the same name and different packages, one in each location. They aren't the same.
He is looking for this object by the old classpath.
You are confused between CLASSPATH and package name. They aren't the same thing. It is looking for this object by its actual package name. What else can it possibly do?
The object output stream doesn't serialize the class itself but only its state (the field values). The receiver needs the class file on it's classpath.
It is possible to transfer the class too. You'll have to find (or write) a classloader that can load the class from your connection. If you have an URL for your classfile then you could use the URLClassloader. Then you don't have to add the class to your classpath.
Your client neeeds to have in its classpath the .class files that define the object. What you are doing is serializing/deserializing the instance, not the class.
Late, but it may be useful for someone in the future:
I wanted to send an object Message whose package was entities in the client side, but in the server side this Message class was not nested within a entities package, so this Exception was thrown. It may be dumb but I spent many hours figuring out this.

Getting an InputStream of Writer using standard Java library

I have an method which writes data to an OutputStream but needs to return the contents of the OutputStream as an InputStream
public InputStream getInputStreamOfData(type param) {
// ..... data
OutputStreamWriter writer = new OutputStreamWriter();
writer.write(data);
// convert writer object to an InputStream
}
I came across some libraries to do this such as IOUtils and other thread based methods. Is there a simple way to achieve this using standard Java library ? I want to return the contents in the writer as an InputStream to be consumed by the calling method.
Thanks!
Write to a ByteArrayOutputStream, then get the byte array, and return a ByteArrayInputStream from this byte array.
I think the correct way to do it is using PipedInputStream. It's just like unix pipes (in highlevel). PipedInputStream constructor takes PipedOutputStream, so if you write to PipedOutputStream, you will get exactly what you want!
Good luck!

Client-Server File Transfer in Java

I'm looking for an efficient way to transfer files between client and server processes using TCP in Java. My server code looks something like this:
socket = serverSocket.accept();
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
FileInputStream fis = new FileInputStream(new File(filename));
I'm just unsure of how to proceed. I know I want to read bytes from fis and then write them to os, but I'm unsure about the best way to read and write bytes using byte streams in Java. I'm only familiar with writing/reading text using Writers and Readers. Can anyone tell me the appropriate way to do this? What should I wrap os and fis in (if anything) and how do I keep reading bytes until the end of file without a hasNext() method (or equivalent)
You could do something like:
byte[] contents = new byte[BUFFER_SIZE];
int numBytes =0;
while((numBytes = is.read(contents))>0){
os.write(contents,0,numBytes);
}
You could use Apache's IOUtils.copy(in, out) or
import org.apache.commons.fileupload.util.Streams;
...
Streams.copy(in, out, false);
Inspecting the source might prove interesting. ( http://koders.com ?)
There is the java.nio.Channel with a transferTo method, with mixed opinions in the community wether better for smaller/larger files.
A simple block wise copy between Input/OutputStream would be okay. You could wrap it in buffered streams.

Categories