/*
*LatherXCoder.java
* NOTE: This copyright does *not* cover user programs that use HQ
* program services by normal system calls through the application
* program interfaces provided as part of the Hyperic Plug-in Development
* Kit or the Hyperic Client Development Kit - this is merely considered
* normal use of the program, and does *not* fall under the heading of
* "derived work".
*
* Copyright (C) [2004, 2005, 2006], Hyperic, Inc.
* This file is part of HQ.
*
* HQ is free software; you can redistribute it and/or modify
* it under the terms version 2 of the GNU General Public License as
* published by the Free Software Foundation. This program is distributed
* in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*/
package org.hyperic.lather.xcode;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.hyperic.lather.LatherRemoteException;
import org.hyperic.lather.LatherValue;
/**
* A class which encodes/decodes LatherValue objects to/from data streams.
*
* Developer note: This class is tightly intertwined with LatherValue
* for speed purposes.
*/
public class LatherXCoder {
private final int HAS_STRINGS = 1 << 0;
private final int HAS_INTS = 1 << 1;
private final int HAS_DOUBLES = 1 << 2;
private final int HAS_BYTEAS = 1 << 3;
private final int HAS_STRINGLS = 1 << 4;
private final int HAS_INTLS = 1 << 5;
private final int HAS_DOUBLELS = 1 << 6;
private final int HAS_BYTEALS = 1 << 7;
private final int HAS_OBJECTS = 1 << 8;
private final int HAS_OBJECTLS = 1 << 9;
private final int HAS_LONGS = 1 << 10;
private final int HAS_SERIALAIZABLES = 1 << 11;
/**
* Encode the given value object into a stream.
*
* @param value
* Value to encode
* @param out
* Stream to write the encoded representation of 'value' to
*/
public void encode(LatherValue value, DataOutputStream out)
throws IOException
{
Map stringVals, intVals, doubleVals, longVals, byteaVals, objectVals,
stringLists, intLists, doubleLists, byteaLists, objectLists;
int contents = 0;
stringVals = value.getStringVals();
intVals = value.getIntVals();
longVals = value.getLongVals();
doubleVals = value.getDoubleVals();
byteaVals = value.getByteAVals();
objectVals = value.getObjectVals();
stringLists = value.getStringLists();
intLists = value.getIntLists();
doubleLists = value.getDoubleLists();
byteaLists = value.getByteALists();
objectLists = value.getObjectLists();
if (stringVals.size() > 0) {
contents |= HAS_STRINGS;
}
if (intVals.size() > 0) {
contents |= HAS_INTS;
}
if (longVals.size() > 0) {
contents |= HAS_LONGS;
}
if (doubleVals.size() > 0) {
contents |= HAS_DOUBLES;
}
if (byteaVals.size() > 0) {
contents |= HAS_BYTEAS;
}
if (stringLists.size() > 0) {
contents |= HAS_STRINGLS;
}
if (intLists.size() > 0) {
contents |= HAS_INTLS;
}
if (doubleLists.size() > 0) {
contents |= HAS_DOUBLELS;
}
if (byteaLists.size() > 0) {
contents |= HAS_BYTEALS;
}
if (objectVals.size() > 0) {
contents |= HAS_OBJECTS;
}
if (objectLists.size() > 0) {
contents |= HAS_OBJECTLS;
}
if (value.getSerializableMap().size() > 0) {
contents |= HAS_SERIALAIZABLES;
}
// The first thing we write is the type of data that will be
// sent -- this makes the minimum packet size == 4 bytes
out.writeInt(contents);
if((contents & HAS_STRINGS) != 0){
out.writeInt(stringVals.size());
for(Iterator i=stringVals.entrySet().iterator();
i.hasNext();
)
{
Map.Entry ent = (Map.Entry)i.next();
out.writeUTF((String)ent.getKey());
out.writeUTF((String)ent.getValue());
}
}
if((contents & HAS_INTS) != 0){
out.writeInt(intVals.size());
for(Iterator i=intVals.entrySet().iterator();
i.hasNext();
)
{
Map.Entry ent = (Map.Entry)i.next();
out.writeUTF((String)ent.getKey());
out.writeInt(((Integer)ent.getValue()).intValue());
}
}
if((contents & HAS_DOUBLES) != 0){
out.writeInt(doubleVals.size());
for(Iterator i=doubleVals.entrySet().iterator();
i.hasNext();
)
{
Map.Entry ent = (Map.Entry)i.next();
out.writeUTF((String)ent.getKey());
out.writeDouble(((Double)ent.getValue()).doubleValue());
}
}
if((contents & HAS_BYTEAS) != 0){
out.writeInt(byteaVals.size());
for(Iterator i=byteaVals.entrySet().iterator();
i.hasNext();
)
{
Map.Entry ent = (Map.Entry)i.next();
byte[] val;
out.writeUTF((String)ent.getKey());
val = (byte[])ent.getValue();
out.writeInt(val.length);
out.write(val, 0, val.length);
}
}
if((contents & HAS_STRINGLS) != 0){
out.writeInt(stringLists.size());
for(Iterator i=stringLists.entrySet().iterator();
i.hasNext();
)
{
Map.Entry ent = (Map.Entry)i.next();
List vals = (List)ent.getValue();
out.writeUTF((String)ent.getKey());
out.writeInt(vals.size());
for(Iterator j=vals.iterator(); j.hasNext(); ){
out.writeUTF((String)j.next());
}
}
}
if((contents & HAS_INTLS) != 0){
out.writeInt(intLists.size());
for(Iterator i=intLists.entrySet().iterator();
i.hasNext();
)
{
Map.Entry ent = (Map.Entry)i.next();
List vals = (List)ent.getValue();
out.writeUTF((String)ent.getKey());
out.writeInt(vals.size());
for(Iterator j=vals.iterator(); j.hasNext(); ){
out.writeInt(((Integer)j.next()).intValue());
}
}
}
if((contents & HAS_DOUBLELS) != 0){
out.writeInt(doubleLists.size());
for(Iterator i=doubleLists.entrySet().iterator();
i.hasNext();
)
{
Map.Entry ent = (Map.Entry)i.next();
List vals = (List)ent.getValue();
out.writeUTF((String)ent.getKey());
out.writeInt(vals.size());
for(Iterator j=vals.iterator(); j.hasNext(); ){
out.writeDouble(((Double)j.next()).doubleValue());
}
}
}
if((contents & HAS_BYTEALS) != 0){
out.writeInt(byteaLists.size());
for(Iterator i=byteaLists.entrySet().iterator();
i.hasNext();
)
{
Map.Entry ent = (Map.Entry)i.next();
List vals = (List) ent.getValue();
out.writeUTF((String)ent.getKey());
out.writeInt(vals.size());
for(Iterator j=vals.iterator(); j.hasNext(); ){
byte[] val = (byte[])j.next();
out.writeInt(val.length);
out.write(val, 0, val.length);
}
}
}
if((contents & HAS_OBJECTS) != 0){
out.writeInt(objectVals.size());
for(Iterator i=objectVals.entrySet().iterator();
i.hasNext();
)
{
ByteArrayOutputStream bOs;
DataOutputStream subDoS;
Map.Entry ent = (Map.Entry)i.next();
byte[] data;
bOs = new ByteArrayOutputStream();
subDoS = new DataOutputStream(bOs);
this.encode((LatherValue)ent.getValue(), subDoS);
out.writeUTF((String)ent.getKey());
out.writeUTF(ent.getValue().getClass().getName());
data = bOs.toByteArray();
out.writeInt(data.length);
out.write(data, 0, data.length);
}
}
if((contents & HAS_OBJECTLS) != 0){
out.writeInt(objectLists.size());
for(Iterator i=objectLists.entrySet().iterator();
i.hasNext();
)
{
Map.Entry ent = (Map.Entry)i.next();
List vals = (List)ent.getValue();
out.writeUTF((String)ent.getKey());
out.writeInt(vals.size());
for(Iterator j=vals.iterator(); j.hasNext(); ){
ByteArrayOutputStream bOs;
DataOutputStream subDoS;
LatherValue val = (LatherValue)j.next();
byte[] data;
bOs = new ByteArrayOutputStream();
subDoS = new DataOutputStream(bOs);
this.encode(val, subDoS);
out.writeUTF(val.getClass().getName());
data = bOs.toByteArray();
out.writeInt(data.length);
out.write(data, 0, data.length);
}
}
}
if((contents & HAS_LONGS) != 0){
out.writeInt(longVals.size());
for(Iterator i=longVals.entrySet().iterator();
i.hasNext();
)
{
Map.Entry ent = (Map.Entry)i.next();
out.writeUTF((String)ent.getKey());
out.writeLong(((Long)ent.getValue()).longValue());
}
}
if ((contents & HAS_SERIALAIZABLES) != 0) {
out.writeInt(value.getSerializableMap().size());
byte[] data;
ByteArrayOutputStream b;
ObjectOutputStream oos;
for (Entry<String, Serializable> entry : value.getSerializableMap().entrySet()) {
// Write Object name
out.writeUTF(entry.getKey());
// Turn the Object to byte array
b = new ByteArrayOutputStream();
oos = new ObjectOutputStream(b);
oos.writeObject(entry.getValue());
data = b.toByteArray();
// Write Object size
out.writeInt(data.length);
// Write the actual Object as byte array
out.write(data);
}
}
}
/**
* Decode a LatherValue object from a stream.
*
* @param in Stream to read from, which has an encoded LatherValue object
* @param cl Class to instantiate and store values to. The object
* must be a subclass of the LatherValue object
*
* @return an instantiation of the 'cl' argument, containing the
* decoded data.
*/
public LatherValue decode(DataInputStream in, Class cl)
throws IOException, LatherRemoteException
{
LatherValue res;
String listName;
List newList;
Map map;
int contents, nVals, nListVals;
if(LatherValue.class.isAssignableFrom(cl) == false){
throw new IllegalArgumentException("Passed class (" + cl +
") is not a subclass of " +
"LatherValue");
}
try {
res = (LatherValue)cl.newInstance();
} catch(Exception exc){
throw new IllegalArgumentException("Passed class is not " +
"accessable: " + exc);
}
contents = in.readInt();
if((contents & HAS_STRINGS) != 0){
nVals = in.readInt();
map = res.getStringVals();
for(int i=0; i<nVals; i++){
map.put(in.readUTF(), in.readUTF());
}
}
if((contents & HAS_INTS) != 0){
nVals = in.readInt();
map = res.getIntVals();
for(int i=0; i<nVals; i++){
map.put(in.readUTF(), new Integer(in.readInt()));
}
}
if((contents & HAS_DOUBLES) != 0){
nVals = in.readInt();
map = res.getDoubleVals();
for(int i=0; i<nVals; i++){
map.put(in.readUTF(), new Double(in.readDouble()));
}
}
if((contents & HAS_BYTEAS) != 0){
nVals = in.readInt();
map = res.getByteAVals();
for(int i=0; i<nVals; i++){
byte[] bytes;
listName = in.readUTF();
bytes = new byte[in.readInt()];
in.readFully(bytes);
map.put(listName, bytes);
}
}
if((contents & HAS_STRINGLS) != 0){
nVals = in.readInt();
map = res.getStringLists();
for(int i=0; i<nVals; i++){
listName = in.readUTF();
nListVals = in.readInt();
newList = new ArrayList(nListVals);
for(int j=0; j<nListVals; j++){
newList.add(in.readUTF());
}
map.put(listName, newList);
}
}
if((contents & HAS_INTLS) != 0){
nVals = in.readInt();
map = res.getIntLists();
for(int i=0; i<nVals; i++){
listName = in.readUTF();
nListVals = in.readInt();
newList = new ArrayList(nListVals);
for(int j=0; j<nListVals; j++){
newList.add(new Integer(in.readInt()));
}
map.put(listName, newList);
}
}
if((contents & HAS_DOUBLELS) != 0){
nVals = in.readInt();
map = res.getDoubleLists();
for(int i=0; i<nVals; i++){
listName = in.readUTF();
nListVals = in.readInt();
newList = new ArrayList(nListVals);
for(int j=0; j<nListVals; j++){
newList.add(new Double(in.readDouble()));
}
map.put(listName, newList);
}
}
if((contents & HAS_BYTEALS) != 0){
nVals = in.readInt();
map = res.getByteALists();
for(int i=0; i<nVals; i++){
listName = in.readUTF();
nListVals = in.readInt();
newList = new ArrayList(nListVals);
for(int j=0; j<nListVals; j++){
byte[] bytes;
bytes = new byte[in.readInt()];
in.readFully(bytes);
newList.add(bytes);
}
map.put(listName, newList);
}
}
if((contents & HAS_OBJECTS) != 0){
nVals = in.readInt();
map = res.getObjectVals();
for(int i=0; i<nVals; i++){
ByteArrayInputStream bIs;
DataInputStream subDiS;
String className;
byte[] bytes;
Class valClass;
listName = in.readUTF();
className = in.readUTF();
bytes = new byte[in.readInt()];
in.readFully(bytes);
bIs = new ByteArrayInputStream(bytes);
subDiS = new DataInputStream(bIs);
try {
valClass = Class.forName(className);
} catch(ClassNotFoundException exc){
throw new LatherRemoteException("Unable to locate '" +
className + "' to decode "+
"LatherValue");
}
map.put(listName, this.decode(subDiS, valClass));
}
}
if((contents & HAS_OBJECTLS) != 0){
nVals = in.readInt();
map = res.getObjectLists();
for(int i=0; i<nVals; i++){
ByteArrayInputStream bIs;
DataInputStream subDiS;
String className;
byte[] bytes;
Class valClass;
listName = in.readUTF();
nListVals = in.readInt();
newList = new ArrayList(nListVals);
for(int j=0; j<nListVals; j++){
className = in.readUTF();
bytes = new byte[in.readInt()];
in.readFully(bytes);
bIs = new ByteArrayInputStream(bytes);
subDiS = new DataInputStream(bIs);
try {
valClass = Class.forName(className);
} catch(ClassNotFoundException exc){
throw new LatherRemoteException("Unable to locate '" +
className + "' to decode "+
"LatherValue");
}
newList.add(this.decode(subDiS, valClass));
}
map.put(listName, newList);
}
}
if((contents & HAS_LONGS) != 0){
nVals = in.readInt();
map = res.getLongVals();
for(int i=0; i<nVals; i++){
String key = in.readUTF();
Long test = new Long(in.readLong());
map.put(key, test);
}
}
if ((contents & HAS_SERIALAIZABLES) != 0) {
ObjectInputStream ois;
ByteArrayInputStream b;
nVals = in.readInt();
byte[] bytes;
map = res.getSerializableMap();
for (int i = 0; i < nVals; i++) {
String key = in.readUTF();
Serializable obj;
try {
bytes = new byte[in.readInt()];
b = new ByteArrayInputStream(bytes);
in.readFully(bytes);
ois = new ObjectInputStream(b);
obj = (Serializable) ois.readObject();
map.put(key, obj);
} catch (ClassNotFoundException e) {
// Should not ever get here..
}
}
}
res.validate();
return res;
}
}
转载于:https://my.oschina.net/stevenliuit/blog/264116