How can I get an ObjectInputStream that supports mark/reset? - java

I'm trying to get an ObjectInputStream that will allow me to read data from it and, if it's not of the right type, put the data back onto the stream (using mark and reset) for some other code to deal with. I've tried wrapping the InputStream retrieved from the Socket (s in the following example) in a BufferedInputStream before wrapping it in an ObjectInputStream as I believed to be the solution, however when calling ois.markSupported() false is still returned. Below is that attempt:
ois = new ObjectInputStream(new BufferedInputStream(s.getInputStream()));
Any help greatly appreciated!

I would build a higher-level abstraction on top of the stream. Something like this (pseudo-code, not finalized):
public class Buffer {
private final ObjectInputStream in;
private Object current;
public Buffer(ObjectInputStream in) {
this.in = in;
}
public Object peek() {
if (current == null) {
current = in.readObject();
}
return current;
}
public void next() {
current = in.readObject();
}
}
You would use peek() repeatedly to get the current object, and if it suits you, call next() to go to the next one.
Of course, you need to deal with exceptions, the end of the stream, closing it properly, etc. But you should get the idea.
Or, if you can just read everything in memory, then do it and create a Queue with the objects from the stream, then pass that Queue around and use peek() and poll().

Related

Check if Java InputStream comes from Socket

I have a class that takes an InputStream as an argument to read data.
public Foo {
private DataInput in;
public Foo(InputStream ism) {
in = new DataInputStream(ism);
}
public byte readByte() throws IOException {
return in.readByte();
}
}
Sometimes this InputStream might come from a Socket, e.g.,
ism = new BufferedInputStream(sock.getInputStream());
foo = new Foo(ism);
My question is, is it possible to check from within Foo that the input stream comes from Socket, i.e., it's a network I/O rather than local I/O? Since the
socket.getInputStream
call returns the abstract class. I don't know which concrete input stream implementation to test for.
Edit: the motivation is that there is a piece of big Java software that has this structure. Foo is created in many places. Some place with file input stream while others with socket input stream. The software can perform poorly when the read is across the network. So I want to see if it's possible do tracing to differentiate the two scenarios for this software without changing much of its code. I'm using AspectJ to write the tracing in the hope to not create much mess to this existing software.
The problem is that an InputStream can be a FilterInputStream that is constructed around another InputStream and that socket just returns an InputStream.
One approach, very dirt & buggy: find the root InputStream, that is, recursively/loop if it is an instance of FilterInputStream, check its parent InputStream (protected field in). Then check the class of the root, the name probably contains "Socket" if it comes from a Socket.
AspectJ idea (I do not have that much experience with it): you should be able to add an aspect to the getInputStream method of Socket that stores the returned InputStream in a list (or similar) for later checking, or somehow marks that InputStream (adding a flag/method to it?).
You can create 2 superclasses of input stream before passing it into Foo class.
NetworkInputStream nis = new NetworkInputStream(sock.getInputStream());
Foo networkFoo = new Foo(nis);
FileInputStream fis = new FileInputStream(file.getInputStream());
Foo fileFoo = new Foo(fis);
public class NetworkInputStream extends BufferedInputStream {}
public class FileInputStream extends BufferedInputStream {}
Then, on Foo class:
public Foo(InputStream ism) {
if (ism instanceof NetworkInputStream) {
//Do whatever if it's from network stream
}
if (ism instanceof FileInputStream) {
//Do whateverelse
}
in = new DataInputStream(ism);
}

Effect on the original InputStream after wrapping with BufferedInputStream

Suppose I have a method that take in an InputStream.
This method need to wrap this InputStream with a BufferedInputStream to use its mark and reset functionality. However, the passed in InputStream might still be used by the caller of the method.
public static void foo(InputStream is) throws Exception {
BufferedInputStream bis = new BufferedInputStream(is);
int b = bis.read();
}
public static void main(String[] args) {
try {
InputStream is = new FileInputStream(someFile);
foo(is);
int b = is.read(); // return -1
}catch (Exception e) {
e.printStackTrace();
}
}
My questions is: what exactly happen to the original InputStream when the BufferedInputStream is read (or initialized)?
My assumption is that the original InputStream will also move forward if the BufferedInputStream is read. However, after debugging my code, I have found that the InputStream will return -1 instead when read.
If the original InputStream is not readable after such process, how should I go about achieving my purpose:
InputStream is;
foo(is); // Method only take in generic InputStream object
// Processing of the passed in InputStream object require mark and reset functionality
int b = is.read(); // Return the next byte after the last byte that is read by foo()
EDIT:
I suppose what I'm asking for is quite generic and therefore requires a lot of work. As for what I'm working on, I actually don't need the full mark & reset capability so I have found a small work around. However, I will leave the 2nd part of the question here, so feel free to attempt this problem :).
The default bufferSize of a BufferedInputStream is 8192, so when you're reading from BufferedInputStream, it tries to fill it's buffer. So, if you have to read from your InputStream less bytes, than the bufferSize, then the full content of your InputStream is read to the buffer, therefore you're getting -1 after reading from BufferedInputStream
Have a look at the BufferedInputStream source code: http://www.docjar.com/html/api/java/io/BufferedInputStream.java.html
http://docs.oracle.com/javase/7/docs/api/java/io/BufferedInputStream.html#BufferedInputStream%28java.io.InputStream%29
Looks like the BufferedInputStream uses the InputStream for the actions performed with the data stream. The Buffered class simply implements a buffer array for internal use.
Not sure what you could use instead, apart from perhaps copying the InputStream so that you have a second object to call.
BufferedInputStream will pre-load data from the underlying InputStream in batches, which will trigger respective move of the underlying InputStream position. If the buffer size is enough to consume all data from the underlying stream in one go you may well observe the behavior you describe.
Two things:
Any API that accepts a stream as input parameter is probably going to use that stream, so it is unreasonable for the caller to expect the stream to remain in any kind of usable state. Perhaps it would have been better for the java stream classes to enforce single ownership somehow to make that clearer.
As a special case, BufferedInputStream is going to use the underlying stream that it "wraps" because it achieves (a limited form of) mark and reset by buffering block reads, as others have pointed out.
private static class MybufferedInputStream extends BufferedInputStream {
public MybufferedInputStream(InputStream in) {
super(in);
}
public int getBufferSize(){
int i=0;
for (Byte byte1 : super.buf) {
if (byte1!=0) {
i++;
}
}
return i;
}
}
then you can call the getBufferSize() after read() to see the difference between a small file and a larger file.

JavaME Vector is not working properly

Well firstly i am using NetBeans IDE. There is a client that one thread of it receives messages from the server and puts them in a Vector and another thread handles them. MessageListener and MessageHandler are the ones. So the problem is that the first message that it receives it is working good, but for the next message when it calls the method byte[] getFirstMessage() it returns byte with values of 0`s.
In my oppinion the problem is either with the Vector addElement method that it adds the second message to the index 1 and not 0 although it deletes the contents of vector`s first element as soon as it passes that data to the MessageHandler or that i use local variables in some methods. P.S it should have been the message queue.
MessageListener.java
package org.rebirth;
import java.io.*;
import java.util.*;
public class MessageListener implements Runnable{
Vector v;
int size = 0;
Connections con;
byte[] buffer = new byte[100000];
boolean noErrors = true;
public MessageListener(Connections con){
v = new Vector(50,10);
this.con = con;
Thread thr = new Thread(this);
thr.start();
}
public void run(){
while(noErrors){
try{
listenForData();
Thread.sleep(1);
}catch(Exception exc){
exc.printStackTrace();
noErrors = false;
}
}
}
public void listenForData() throws IOException{
con.fill(buffer,(byte)0);
System.out.println("Trying to receive data");
// InputStream
con.in.read(buffer);
System.out.println("Data received id "+con.ReadInt3Bytes(buffer,1));
v.addElement(buffer);
size++;
if(v.isEmpty()){
System.out.println("empty");
}
}
public byte[] getFirstMessage(){
if(v.size()>0){
byte[] data = (byte[]) v.firstElement();
v.removeElementAt(0);
size--;
System.out.println("first byte element "+(int)data[0]);
return data;
}
return null;
}
}
Messagehandler.java
package org.rebirth;
import java.util.*;
import javax.microedition.lcdui.game.*;
public class MessageHandler implements Runnable{
Vector v;
MessageListener lst;
Connections con;
int vienas = 1;
public MessageHandler(Vector v,MessageListener lst){
this.v = v;
this.lst = lst;
this.con = lst.con;
Thread thr = new Thread(this);
thr.start();
}
public void run(){
while(true){
try{
if(!v.isEmpty()){
handleMessages();
}
Thread.sleep(10);
}catch(Exception exc){}
}
}
public void handleMessages(){
// vectordsfds
int id;
byte [] gotByte = lst.getFirstMessage();
id=con.ReadInt3Bytes(gotByte,1);
System.out.println("handler id: "+id);
// call a method to handle received message;
handleMessage(id,gotByte);
}
public void handleMessage(int id,byte[] gotByte){
switch(id){
case 62:
// GameServerList
con.serverNumber = (int)gotByte[4];
System.out.println("Servers "+con.serverNumber);
int nri = 6;
for(int i=0;i<con.serverNumber;i++){
nameLength = (int)gotByte[nri];
nri+=1;
con.serverName[i] = new String(gotByte, nri, nameLength);
nri+=nameLength;
int ipLength = (int)gotByte[nri];
nri+=1;
con.serverIp[i] = new String(gotByte, nri, ipLength);
nri+=ipLength;
con.online[i] = con.ReadInt3Bytes(gotByte,nri);
nri+=3;
con.maxOnline[i] = con.ReadInt3Bytes(gotByte,nri);
System.out.println("Server name " +con.serverName[i]);
System.out.println("ip "+con.serverIp[i]);
System.out.println("online "+con.online[i]);
System.out.println("max online "+con.maxOnline[i]);
nri+=4;
}
break;
case 64:
//GameVersion
int success = (int)gotByte[4];
if(success == 1){
con.version=true;
System.out.println("Version match!");
}else{
System.out.println("version does not match");
System.out.println(success);
}
break;
}
}
}
EDIT 2: I added a statement InputStream class available() method before reading the data.
I am surprised it works even sometimes. If I am reading the sources right, you are using the same buffer instance for all incoming messages. Vector.addElement does not create a copy of the buffer, it just saves the reference passed as param, so listenForData running in while(noErrors) loop will clear the (one and only) buffer with zeros as soon as it runs again. And when it runs again depedsn on how threads are scheduled, so sometimes the message listener gets the buffer with real data and sometimes with zeros.
Also I'm not sure that CLDC Vector is, unlike in J2SE, synchronized. So I think vector access should be synchronized.
And also I'm not sure what type of connections you are using, but reading bytes from stream without checking return value and without knowing how many bytes you should read seems like a bit unreliable piece of code...
EDIT: by "knowing how many bytes you should read" I did not mean using available() function, which is likely to return 0 for many types of streams. When read() returns, it may (and it often does) read less bytes than requested, so you can never be sure if you have enough data in buffer to work with, unless you known how much data you are waiting and you keep reading until you have them. I think you should define a protocol, it can be as simple as fixed-size messages if it fits you needs.
It is not so trivial to understand what happens with your code exactly. However method listenForData() indeed adds byte array filled by zeros to your vector:
con.fill(buffer,(byte)0);
......
v.addElement(buffer);
So, although you are new here and I would like to welcome you and to wish you a lot of success I would like to ask you some questions.
do you know that J2ME is obsolete? Take a look on Android OS if you want to program form mobile devices.
Do you really think that JDK classes (like Vector) contain bugs that you can discover by writing your first program?
Did you hear about debuggers? Try to debug your code to understand why it does not work.
If you want to ask question and get a good answer take a look on SSCCE.
Good luck.

Java Object Serialization issue

I have some input that I add to a serialized object.
Now when I read the serialized object, I want to check if it exists... If not loop till it has a value in it.
How do i modify the deserialization function to handle that.
There is basically a delay in populating my serializable object. So in the meantime if i were to read that object, it is going to be empty. I want to put a check to read only when it has data in it. if not it should wait till it has some data
public String _displayResults(){
String SomeData = "";
try {
FileInputStream fis = new FileInputStream("SomeDataobj");
ObjectInputStream ois = new ObjectInputStream(fis);
SomeData = (String)ois.readObject();
ois.close();
}
catch(Exception e) {
System.out.println("Exception during deserialization: ");
}
return SomeData;
}
What I tried:
added a wait condition for 2 secs for 10 times... Is there a cleaner way.
while ( ois.readObject().toString().equalsIgnoreCase("") && i <10){
Thread.sleep(2000);
i++;
}
Java provides an API called Externalizable, which allows you to customize the (de) serialization. Serialiazable is marker interface and that indicates the object can be wrote to output stream. Externalizable provides two methods readExternal() and writeExternal() where you can override the behavior.
Your question is not so clear about what you want to achieve, so I am not sure if the above information is helpful for you

Java InputStream != Readable

I am using java.util.Scanner for things such as nextInt(), and all was working fine as long as I was using a java.lang.Readable (one and only constructor argument). However, when I changed to using an InputStream instead, Scanner.nextInt() never returns. Do you know why?
My implementation of the InputStream looks like this:
private static class ConsoleInputStream extends InputStream {
...
private byte[] buffer;
private int bufferIndex;
public int read() throws IOException {
...
while (...) {
if (buffer != null && bufferIndex < buffer.length) {
return buffer[bufferIndex++]; // THE COMMENT!
}
...
}
...
}
}
When I print the data by THE COMMENT I (correctly) get stuff like '1','2','\n' for "12\n", etc. Is there some Scanner hookup, unbeknown to me, that cause this behavior?
From the javadocs for InputStream's read() method:
"Returns: the next byte of data, or -1 if the end of the stream is reached."
I would guess that you're never returning -1?
I think the problem is with your self-built InputStream. Why did you build your own, rather than simply simply using System.in ?
Update:
Wanted input from a JTextField.
OK, got it. It usually doesn't make sense to use I/O handling to read stuff that's already available, in character form, but I can see how that would make your life easier with Scanner.
Still, you could probably have saved yourself some coding and grief by using a "finished" InputStream. What comes to mind is
InputStream is = new ByteArrayInputStream(myTextField.getText().getBytes());
Java I/O is yucky. Be glad the bright people from Sun have encapsulated most of it away for you.

Categories