| Reply | « Previous Thread | Next Thread » |
|
Hi Folks,
i need to update data through RMS (Record Management System) system. I could use recordStoreObj.setRecord(int recordId, byte[] newData, int offset, int numBytes). However, this is a compound data, which has three primitive ''ints'', one String object, and one byte array (byte[]). To store such a thing, i have used ByteArrayOutputStream and DataOutputStream. To retrieve them, ByteArrayInputStream and DataInputStream are used. How can i update the data!?!?!!? Thanks! |
| thiagobrunoms |
| View Public Profile |
| Find all posts by thiagobrunoms |
|
Hi Folks,
i'm trying to update a compound date through RMS. Below follow my code. However, after executing it, and when i try to read (again) the data, the following exception is thrown: Code:
java.lang.ArrayIndexOutOfBoundsException at com.sun.midp.io.j2me.storage.RandomAccessStream.readBytes(+13) at com.sun.midp.rms.RecordStoreFile.read(+10) at javax.microedition.rms.RecordStore$RecordHeader.read(+36) at javax.microedition.rms.RecordStore.getRecord(+27) at br.cg.pactus.PersistenceManager.readStream(+75) at br.cg.pactus.Pactus.showReports(+88) at br.cg.pactus.Pactus.itemStateChanged(+192) at javax.microedition.lcdui.Form.callItemStateChanged(+27) at javax.microedition.lcdui.Display.callItemStateChanged(+14) at javax.microedition.lcdui.Display.access$900(+5) at javax.microedition.lcdui.Display$DisplayAccessor.callItemStateChanged(+8) at javax.microedition.lcdui.Display$DisplayManagerImpl.callItemStateChanged(+10) at com.sun.midp.lcdui.DefaultEventHandler.itemStateChangedEvent(+17) at com.sun.midp.lcdui.DefaultEventHandler$QueuedEventHandler.run(+835) Code:
try {
newsId = 10;
SearchFielter search = new SearchFielter(newsId);
RecordEnumeration e = this.record.enumerateRecords(s, null, false);
if (e.numRecords() > 0) {
int recordId = e.nextRecordId();
ByteArrayOutputStream arrayOut = new ByteArrayOutputStream();
DataOutputStream streamDataType = new DataOutputStream(arrayOut);
streamDataType.writeInt(newsId); streamDataType.writeInt(newsStatus); streamDataType.writeInt(newsContentType);
streamDataType.writeUTF(newsDescription);
streamDataType.write((byte[]) newsBytes);
byte[] newsUpdated = arrayOut.toByteArray();
this.record.setRecord(recordId, newsUpdated, 0, newsUpdated.length);
arrayOut.close();
streamDataType.close();
} else {
System.out.println("nenhum encontrado!");
}
search.closeSearchFilter();
e.destroy();
Thanks for helping me!!!!! |
| thiagobrunoms |
| View Public Profile |
| Find all posts by thiagobrunoms |
|
Hi,
The exception does not match the code. You create a search filter, that you don't seem to use afterwards, so I understand you modified the code previously to post it here and removed the conflictive lines, as you are using variables that look to be the ones you read but are delcared or used anywhere. The error raises in getRecord, and you are not calling getRecord here, but you might be doing in your filter ir order to filter out rows or in that piece of missing code. Despite that, it is advisable to declare the streams outside a try-catch-finally bloc, making sure to close them in the finally block. And also advisable is to reuse objects as much as possible. In this case, you can use the output stream once and again just by calling arrayOut.reset() before each record. I would create methods for reading and writting independently, so it's easier to deal with possible read and/or write errors. You seem to be using a byte array to get the record data with getRecord (in the missing code), and I presume that the issue is that the array size is not the right one, you might be using an array smaller than the recordsize. If you post the full code we might be able to help you further. I've already posted how to retrieve/iterate the records of a record store, and there're many other examples out there. ----------------------- Narciso Cerezo CTO Elondra OpenBaseMovil http://www.openbasemovil.org The Framework for enterprise class J2ME applications with a pure J2ME relational database engine and much more. |
|
hI ncerezo2, thanks for helping. There r some codes bellow. The first method is responsible for writing streams:
Code:
ByteArrayOutputStream output = new ByteArrayOutputStream(); DataOutputStream streamDataType = new DataOutputStream(output); byte[] record = null; streamDataType.writeInt(newsId); streamDataType.writeInt(newsStatus); streamDataType.writeInt(newsContentType); streamDataType.writeUTF(newsDescription); //newsStreams[] is an Object array. streamDataType.write((byte[]) newsStreams[0]); streamDataType.flush(); record = output.toByteArray(); this.recordIndex = this.record.addRecord(record, 0, record.length); output.reset(); output.close(); streamDataType.close(); Code:
public void matches(byte[] candidate) {
this.inputByte = new ByteArrayInputStream(candidate);
this.dataInput = new DataInputStream(this.inputByte);
int idP = -1;
try {
idP = this.dataInput.readInt();
} catch (IOException e) {
e.printStackTrace();
}
this.closeByteArrayInputAndDataInputStream();
if(this.id == idP) {
return true;
} else {
return false;
}
}
}
Code:
SearchFielter s = new SearchFielter(newsId);
RecordEnumeration e = this.record.enumerateRecords(s, null, false);
if (e.numRecords() > 0) {
int recordId = e.nextRecordId();
e.destroy();
ByteArrayOutputStream arrayOut = new ByteArrayOutputStream();
DataOutputStream streamDataType = new DataOutputStream(arrayOut);
streamDataType.writeInt(newsId);
streamDataType.writeInt(newsStatus);
streamDataType.writeInt(newsContentType);
streamDataType.writeUTF(newsDescription);
streamDataType.write((byte[]) newsStreams[0]);
arrayOut.close();
streamDataType.close();
byte[] newsUpdated = arrayOut.toByteArray();
this.record.setRecord(recordId, newsUpdated, 0, newsUpdated.length);
}
Code:
byte[] recData = new byte[100000];
ByteArrayInputStream streamBytes = new ByteArrayInputStream(recData);
DataInputStream streamDataType = new DataInputStream(streamBytes);
Hashtable hash = new Hashtable();
Object[] news = null;
byte[] media = null;
RecordEnumeration enumeration = this.record.enumerateRecords(null,null,false);
while (enumeration.hasNextElement()) {
this.record.getRecord(enumeration.nextRecordId(), recData, 0);
media = new byte[streamBytes.available()];
int newsId = streamDataType.readInt();
int newsStatus = streamDataType.readInt();
int newsContentType = streamDataType.readInt();
String description = streamDataType.readUTF();
streamDataType.read(media);
streamBytes.reset();
}
enumeration.destroy();
streamBytes.close();
streamDataType.close();
Thanks one more time ncerezo2.
Last edited by thiagobrunoms : 2008-01-28 at 12:18.
|
| thiagobrunoms |
| View Public Profile |
| Find all posts by thiagobrunoms |
|
There're a couple of wrong things here that might be raising the error:
1. First piece of code, it has just a small non-harmful issue: a. You're calling output.reset(); before closing. That won't hurt, but is unnecessary. The purpose of reset is to reuse the byte buffer that the ByteArrayOutputStream has created for new output, it is just as if you were opening a new stream but with much less overhead and object churning. Since you declare the streams locally (apparently) it is no sense. It might be advisable to declare the streams as class members to reuse them, or if you are in a loop to declare them outside the loop, but it depends on how you use them. 2. Second one, some non-harmful issues: a. You're declaring the streams as class members, and this is no sense here since you're assigning new values each time (no other way to do it as you receive the byte array). b. The use of the exceptions is a bit misleading, the method could be easily rewritten as: Code:
public void matches(byte[] candidate)
{
ByteArrayInputStream bais = null;
DataInputStream in = null;
try
{
bais = new ByteArrayInputStream( candidate );
in = new DataInputStream( bais );
int idP = in.readInt();
return idP == id;
}
catch( IOException e )
{
e.printStackTrace();
return false;
}
finally
{
if( in != null ) try{ in.close() }catch( Exception e ){}
if( bais != null ) try{ bais.close() }catch( Exception e ){}
}
}
3. Third one: one potentially harming issue, some minor. a. You're closing the ByteArrayOutputStream first, then the DataOutputStream which depends on it. The close method for DataInputStream calls flush and then close on the underlying stream, so you could simply call close on the DataOutputStream. The way you do it, you could end up with some data in a buffer of the DataOutputStream unable to be written to a closed ByteOutputStream and you would have corrupted the record data. It is safe to call it as you did in the first piece: DataOutputStream.flush, DataOutputStream.close, ByteArrayOutputStream.close, although only DataOutputStream.close is needed if we rely in the documentation. b. The minor ones are the same as above, you should declare the streams outside a try-catch-finally to ensure that exceptions are handled properly and streams closed. This is not an issue as big as it would be with real files or with RecordStores, as they're in-memory arrays, but it's advisable. 4. Fourth pice: the worst one :-) a. You're wasting a lot of memory here, look at this thread for some good ways of iterating RecordStores. b. The first thing is that you call available to determine the media size and: b.1. It won't work since the DataInputStream has no way to determine where in the 100000 bytes of the byte array stream is the end of the current data, it will probably decide that 100000 is the available size, so you are again creating another byte array of 100000 bytes. b.2. You're assuming that the "media" size is the same as the available data, but the available data will include also the 3 ints and the string you're writting/reading first. c. I've found that some implementations are buggy (WTK 2.2 for example) with the read( byte[] ) methods, so it is safer to do it the hard way (with a for reading 1 byte at a time). So to be sure you do things right, take the example of the other thread with the growing size byte array, and then make two changes to your write and read code: First, you should write an int to the stream with the byte[] size for "media", and then the media itself. Second, change your read code to read the int with the size, and create an array for the media with that size, then read it from the stream. You can also save time an take a look at OpenBaseMovil, the core library has some useful things for dealing with this kind of things, such as the SerializerInputStream and SerializerOutputStream which are high level streams over DataInputStream and DataOutputStream. They provide methods for writing complex objects, including collections, custom Serializable objects, byte arrays, and other types. ----------------------- Narciso Cerezo CTO Elondra OpenBaseMovil http://www.openbasemovil.org The Framework for enterprise class J2ME applications with a pure J2ME relational database engine and much more. |
|
Hi ncerezo2, thanks one more time for helping. The problem was really the size of the media byte[]. :)
Thanks for the advices. :D Regards. Thiago |
| thiagobrunoms |
| View Public Profile |
| Find all posts by thiagobrunoms |
| Reply | « Previous Thread | Next Thread » |
| Thread Tools | Search this Thread |
|---|---|
| Thread | Thread Starter | Forum | Replies | Last Post |
|---|---|---|---|---|
| RMS record sizes. | earamsey | Mobile Java General | 1 | 2007-10-18 14:51 |
| Is it possible to update a record from a MIDlet's RMS? | fightersoft | Python | 4 | 2006-12-27 17:39 |
| update rms via ota | kevin1964 | Mobile Java General | 2 | 2006-02-21 08:32 |
| How to update calendar entrys date? | kosjanne | General Symbian C++ | 3 | 2005-03-08 18:08 |
| 7210 & 7250 RMS resetting problem | keithmcneill | Mobile Java General | 1 | 2003-11-13 22:04 |