/***************************************************************** JADE - Java Agent DEvelopment Framework is a framework to develop multi-agent systems in compliance with the FIPA specifications. Copyright (C) 2000 CSELT S.p.A. The updating of this file to JADE 2.0 has been partially supported by the IST-1999-10211 LEAP Project This file refers to parts of the FIPA 99/00 Agent Message Transport Implementation Copyright (C) 2000, Laboratoire d'Intelligence Artificielle, Ecole Polytechnique Federale de Lausanne GNU Lesser General Public License This library is free software; you can redistribute it sand/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, version 2.1 of the License. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *****************************************************************/ /** * XMLCodec.java * * * @author Jose Antonio Exposito * @author MARISM-A Development group ( marisma-info@ccd.uab.es ) * @version 0.1 * @author Nicolas Lhuillier * @author Joan Ametller * @version 1.0 */ package jade.mtp.http; import java.io.*; //import java.net.*; import jade.util.leap.Iterator; import jade.mtp.MTPException; import jade.domain.FIPAAgentManagement.Envelope; import jade.domain.FIPAAgentManagement.ReceivedObject; import jade.domain.FIPAAgentManagement.Property; import jade.core.AID; import jade.util.Logger; //#DOTNET_EXCLUDE_BEGIN import org.xml.sax.*; import org.xml.sax.helpers.DefaultHandler; //#DOTNET_EXCLUDE_END import org.apache.commons.codec.binary.Base64; /*#DOTNET_INCLUDE_BEGIN import System.Xml.*; import System.Collections.ArrayList; #DOTNET_INCLUDE_END*/ public class XMLCodec extends DefaultHandler { // Constants public final static String PREAMBUL = "<?xml version=\"1.0\"?>\n"; public final static String ENVELOPE_TAG = "envelope"; public final static String PARAMS_TAG = "params"; public final static String INDEX = "index"; public final static String INDEX_ATTR = " index=\""; public final static String TO_TAG = "to"; public final static String AID_TAG = "agent-identifier"; public final static String AID_NAME = "name"; public final static String AID_ADDRESSES = "addresses"; public final static String AID_ADDRESS = "url"; public final static String FROM_TAG = "from"; public final static String COMMENTS_TAG = "comments"; public final static String REPRESENTATION_TAG = "acl-representation"; public final static String LENGTH_TAG = "payload-length"; public final static String ENCODING_TAG = "payload-encoding"; public final static String DATE_TAG = "date"; //public final static String ENCRYPTED_TAG = "encrypted"; public final static String INTENDED_TAG = "intended-receiver"; public final static String RECEIVED_TAG = "received"; public final static String RECEIVED_DATE = "received-date"; public final static String RECEIVED_BY = "received-by"; public final static String RECEIVED_FROM = "received-from"; public final static String RECEIVED_ID = "received-id"; public final static String RECEIVED_VIA = "received-via"; public final static String RECEIVED_ATTR = "value"; public final static String PROP_TAG = "user-defined"; public final static String PROP_ATTR = "href"; public final static String PROP_ATTR_TYPE = "type"; public final static String PROP_STRING_TYPE ="string"; public final static String PROP_BYTE_TYPE="byte-array"; public final static String PROP_SER_TYPE="serialized"; public final static String OT = "<"; public final static String ET = "</"; public final static String CT = ">"; public final static String NULL = ""; /*#DOTNET_INCLUDE_BEGIN public final static char[] badChars = { '\r', '\n', ' ' }; public final static String CHARS_CODEC = "ISO-8859-1"; #DOTNET_INCLUDE_END*/ //#DOTNET_EXCLUDE_BEGIN private XMLReader parser = null; //#DOTNET_EXCLUDE_END /*#DOTNET_INCLUDE_BEGIN private XmlTextReader parser = null; #DOTNET_INCLUDE_END*/ private Envelope env = null; private ReceivedObject ro = null; private AID aid = null; private Property prop = null; // Accumulate parsed text private StringBuffer accumulator; private String propType; //logging private static Logger logger = Logger.getMyLogger(XMLCodec.class.getName()); //var for detected tag to then origin=0, or tag from then origin=1 //private int origin; /*#DOTNET_INCLUDE_BEGIN //To XML reading private boolean found = false; private String aidStr = ""; private String addressStr = ""; private String mts = ""; private ReceivedObject recObj = null; private int diffInPayLoad = 0; #DOTNET_INCLUDE_END*/ //#DOTNET_EXCLUDE_BEGIN /** * Constructor: * @param parserClass the SAX parser class to use */ public XMLCodec(String parserClass) throws MTPException { try{ parser = (XMLReader)Class.forName(parserClass).newInstance(); parser.setContentHandler(this); parser.setErrorHandler(this); } catch(Exception e) { throw new MTPException(e.toString()); } } //#DOTNET_EXCLUDE_END /*#DOTNET_INCLUDE_BEGIN //Constructor: //For dotnet is used the System.Xml.XmlTextReader parser. //Nothing to do in the constructor public XMLCodec() throws MTPException {} #DOTNET_INCLUDE_END*/ // *************************************************** // * Encoding methods * // *************************************************** /** Encode the information of Agent, Tags To and From **/ private static void encodeAid(StringBuffer sb, AID aid) { sb.append(OT).append(AID_TAG).append(CT); encodeTag(sb,AID_NAME,aid.getName()); sb.append(OT).append(AID_ADDRESSES).append(CT); String[] addresses = aid.getAddressesArray(); for (int i=0; i<addresses.length ; i++) { encodeTag(sb,AID_ADDRESS,addresses[i]); } sb.append(ET).append(AID_ADDRESSES).append(CT); sb.append(ET).append(AID_TAG).append(CT); } /** * This does the following: * < tag > * content * </ tag > */ private static void encodeTag(StringBuffer sb, String tag, String content) { sb.append(OT).append(tag).append(CT); sb.append(content); sb.append(ET).append(tag).append(CT); } /** * A user-defined property (String name, Object value) is encoded the following way: * <user-defined href="name" type="type">value</user-defined> * */ private static void encodeProp(StringBuffer sb, Property p) { String v = null; Object o = p.getValue(); String type = PROP_STRING_TYPE; if (o instanceof String) { v = (String)o; } else if (o instanceof byte[]) { type = PROP_BYTE_TYPE; try { v = new String(Base64.encodeBase64((byte[])o), "US-ASCII"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } else if (o instanceof Serializable) { type = PROP_SER_TYPE; try{ ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(o); oos.close(); byte[] bytes = bos.toByteArray(); if(bytes != null) v = new String(Base64.encodeBase64(bytes), "US-ASCII"); }catch(IOException ioe){ return; } } else { return; } sb.append(OT).append(PROP_TAG).append(" "); sb.append(PROP_ATTR).append("=\"").append(p.getName()).append("\" "); sb.append(PROP_ATTR_TYPE).append("=\"").append(type).append("\""); sb.append(CT); sb.append(v); sb.append(ET).append(PROP_TAG).append(CT); } private void decodeProp(StringBuffer acc, Property p) { if(propType.equals(PROP_SER_TYPE)){ try{ byte[] serdata = acc.toString().getBytes("US-ASCII"); ObjectInputStream ois = new ObjectInputStream( new ByteArrayInputStream(Base64.decodeBase64(serdata))); p.setValue((Serializable)ois.readObject()); }catch(Exception e){ // nothing, we leave value of this property as null; } }else if(propType.equals(PROP_BYTE_TYPE)){ byte[] bytes=null; try { bytes = acc.toString().getBytes("US-ASCII"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } p.setValue(Base64.decodeBase64(bytes)); }else{ p.setValue(acc.toString()); } propType = null; } private static void encodeOneLineTag(StringBuffer sb, String tag1, String tag2, String value) { sb.append(OT).append(tag1).append(" "); sb.append(tag2).append("=\"").append(value).append("\"/>"); } /** General Encoding of the envelope */ public static synchronized String encodeXML(Envelope env) { //Create the message XML StringBuffer sb = new StringBuffer(PREAMBUL); sb.append(OT).append(ENVELOPE_TAG).append(CT); sb.append(OT).append(PARAMS_TAG).append(INDEX_ATTR).append(1).append("\"").append(CT); //Create tag TO Iterator i; for (i=env.getAllTo(); i.hasNext(); ) { sb.append(OT).append(TO_TAG).append(CT); encodeAid(sb,(AID)i.next()); sb.append(ET).append(TO_TAG).append(CT); } //Create tag from if (env.getFrom() != null) { sb.append(OT).append(FROM_TAG).append(CT); encodeAid(sb,env.getFrom()); sb.append(ET).append(FROM_TAG).append(CT); } //Create tag comments if ((env.getComments() != null) && (env.getComments().length() > 0)) { encodeTag(sb,COMMENTS_TAG,env.getComments()); } //Create tag acl-representation if (env.getAclRepresentation() != null) { encodeTag(sb,REPRESENTATION_TAG,env.getAclRepresentation()); } //Create tag payload-length if (env.getPayloadLength() != null) { //System.out.println("Length: "+env.getPayloadLength()); encodeTag(sb,LENGTH_TAG,String.valueOf(env.getPayloadLength())); } //Create tag payload-encoding if ((env.getPayloadEncoding() != null) && (env.getPayloadEncoding().length() > 0)) { encodeTag(sb,ENCODING_TAG,env.getPayloadEncoding()); } //Create tag date //Create object BAsicFipaDateTime BasicFipaDateTime date = new BasicFipaDateTime(env.getDate()); if( date != null ) { encodeTag(sb,DATE_TAG,date.toString()); } //Create tag encrypted (NL: not sure it is still in FIPA) /* for (i=env.getAllEncrypted();i.hasNext();) { encodeTag(sb,ENCRYPTED_TAG,i.next().toString()); } */ //Create tag intended-receiver for (i = env.getAllIntendedReceiver();i.hasNext();) { sb.append(OT).append(INTENDED_TAG).append(CT); encodeAid(sb,(AID)i.next()); sb.append(ET).append(INTENDED_TAG).append(CT); } //Create tags for user properties for (i=env.getAllProperties();i.hasNext();) { encodeProp(sb,(Property)i.next()); } //Create tag received ReceivedObject ro = env.getReceived(); if (ro != null) { //Create tag received sb.append(OT).append(RECEIVED_TAG).append(CT); //Date String value = new BasicFipaDateTime(ro.getDate()).toString(); if (value != null) { encodeOneLineTag(sb, RECEIVED_DATE,RECEIVED_ATTR,value); } //By if (((value=ro.getBy()) != null)&&(!value.equals(NULL))) { encodeOneLineTag(sb, RECEIVED_BY,RECEIVED_ATTR,value); } //From if (((value=ro.getFrom()) != null)&&(!value.equals(NULL))) { encodeOneLineTag(sb, RECEIVED_FROM,RECEIVED_ATTR,value); } //Id if (((value=ro.getId()) != null)&&(!value.equals(NULL))) { encodeOneLineTag(sb, RECEIVED_ID,RECEIVED_ATTR,value); } //Via if (((value=ro.getVia()) != null)&&(!value.equals(NULL))) { encodeOneLineTag(sb, RECEIVED_VIA,RECEIVED_ATTR,value); } sb.append(ET).append(RECEIVED_TAG).append(CT); } sb.append(ET).append(PARAMS_TAG).append(CT); sb.append(ET).append(ENVELOPE_TAG).append(CT); return sb.toString(); } // *************************************************** // * Decoding methods * // *************************************************** /** This method is called when start the document XML*/ public void startDocument() { env = new Envelope(); } /** This method is called at the end of parsing */ public void endDocument() { //Put the ro object in to envelope //env.setReceived(ro); } /** This method is called when jmp event of begin element.*/ public void startElement(String uri, String localName, String rawName, Attributes attributes) { //Detection of the begin of to or from tags //Update the acumulator accumulator = new StringBuffer(); if (TO_TAG.equalsIgnoreCase(localName)) { aid = new AID(); env.addTo(aid); } else if (FROM_TAG.equalsIgnoreCase(localName)) { aid = new AID(); env.setFrom(aid); } else if (INTENDED_TAG.equalsIgnoreCase(localName)) { aid = new AID(); env.addIntendedReceiver(aid); } else if (RECEIVED_TAG.equalsIgnoreCase(localName)) { ro = new ReceivedObject(); env.addStamp(ro); } else if (RECEIVED_BY.equalsIgnoreCase(localName)) { ro.setBy(attributes.getValue(RECEIVED_ATTR)); } else if (RECEIVED_FROM.equalsIgnoreCase(localName)) { ro.setFrom(attributes.getValue(RECEIVED_ATTR)); } else if (RECEIVED_DATE.equalsIgnoreCase(localName)) { ro.setDate(new BasicFipaDateTime(attributes.getValue(RECEIVED_ATTR)).getTime()); } else if (RECEIVED_ID.equalsIgnoreCase(localName)) { ro.setId(attributes.getValue(RECEIVED_ATTR)); } else if (RECEIVED_VIA.equalsIgnoreCase(localName)) { ro.setVia(attributes.getValue(RECEIVED_ATTR)); } else if (PROP_TAG.equalsIgnoreCase(localName)) { prop = new Property(); env.addProperties(prop); prop.setName(attributes.getValue(PROP_ATTR)); propType = attributes.getValue(PROP_ATTR_TYPE); } } /** This method is called the end of element */ public void endElement(String namespaceURL, String localName, String qname) { //Capture the value the attributes of class if (AID_NAME.equalsIgnoreCase(localName)) { aid.setName(accumulator.toString()); } else if (AID_ADDRESS.equalsIgnoreCase(localName)) { aid.addAddresses(accumulator.toString()); } else if (COMMENTS_TAG.equalsIgnoreCase(localName)) { env.setComments(accumulator.toString()); } else if (REPRESENTATION_TAG.equalsIgnoreCase(localName)) { env.setAclRepresentation(accumulator.toString()); } else if (LENGTH_TAG.equalsIgnoreCase(localName)) { env.setPayloadLength(new Long(accumulator.toString())); if(logger.isLoggable(Logger.WARNING)) logger.log(Logger.FINE,"Length: "+env.getPayloadLength()); } else if (ENCODING_TAG.equalsIgnoreCase(localName)) { env.setPayloadEncoding(accumulator.toString()); } else if (DATE_TAG.equalsIgnoreCase(localName)) { env.setDate(new BasicFipaDateTime(accumulator.toString()).getTime()); } else if (PROP_TAG.equalsIgnoreCase(localName)) { decodeProp(accumulator, prop); //prop.setValue(accumulator.toString()); } /* // Not sure it is still in FIPA else if (ENCRYPTED_TAG.equalsIgnoreCase(localName)) { env.addEncrypted(accumulator.toString()); } */ } /** This method is called when exist characters in the elements*/ public void characters(char[] buffer, int start, int length) { accumulator.append(buffer, start, length); } /** This method is called when warning occur*/ //#DOTNET_EXCLUDE_BEGIN public void warning(SAXParseException exception) { //#DOTNET_EXCLUDE_END /*#DOTNET_INCLUDE_BEGIN public void warning(ParseException exception) { #DOTNET_INCLUDE_END*/ if(logger.isLoggable(Logger.WARNING)) //#DOTNET_EXCLUDE_BEGIN logger.log(Logger.WARNING," line " + exception.getLineNumber() + ": "+ exception.getMessage()); //#DOTNET_EXCLUDE_END /*#DOTNET_INCLUDE_BEGIN logger.log(Logger.WARNING," line " + exception.getError() + ": " + exception.get_Message()); #DOTNET_INCLUDE_END*/ } /** This method is called when errors occur*/ //#DOTNET_EXCLUDE_BEGIN public void error(SAXParseException exception) { //#DOTNET_EXCLUDE_END /*#DOTNET_INCLUDE_BEGIN public void error(ParseException exception) { #DOTNET_INCLUDE_END*/ if(logger.isLoggable(Logger.WARNING)) //#DOTNET_EXCLUDE_BEGIN logger.log(Logger.WARNING,"ERROR: line " + exception.getLineNumber() + ": " + exception.getMessage()); //#DOTNET_EXCLUDE_END /*#DOTNET_INCLUDE_BEGIN logger.log(Logger.WARNING,"ERROR: line " + exception.getError() + ": " + exception.get_Message()); #DOTNET_INCLUDE_END*/ } /** This method is called when non-recoverable errors occur.*/ //#DOTNET_EXCLUDE_BEGIN public void fatalError(SAXParseException exception) throws SAXException{ //#DOTNET_EXCLUDE_END /*#DOTNET_INCLUDE_BEGIN public void fatalError(ParseException exception) { #DOTNET_INCLUDE_END*/ if(logger.isLoggable(Logger.WARNING)) //#DOTNET_EXCLUDE_BEGIN logger.log(Logger.SEVERE,"FATAL: line " + exception.getLineNumber() + ": " + exception.getMessage()); throw exception; //#DOTNET_EXCLUDE_END /*#DOTNET_INCLUDE_BEGIN logger.log(Logger.SEVERE,"FATAL: line " + exception.getError() + ": " + exception.get_Message()); #DOTNET_INCLUDE_END*/ } //#DOTNET_EXCLUDE_BEGIN // Main method public Envelope parse(Reader in) throws MTPException { try { parser.parse(new InputSource(in)); return env; } catch (Exception ex) { throw new MTPException(ex.getMessage()); } } //#DOTNET_EXCLUDE_END /*#DOTNET_INCLUDE_BEGIN // Main method public Envelope parse(System.IO.TextReader in) throws MTPException { try { //Inizialization of variables used ArrayList elemList = new ArrayList(); String textStr = ""; env = new Envelope(); recObj = new ReceivedObject(); parser = new XmlTextReader(in); while ( parser.Read() ) { XmlNodeType myNType = parser.get_NodeType(); if (myNType.Equals( XmlNodeType.Element )) { elemList.Add( parser.get_Name() ); if ( parser.get_HasAttributes() ) { while( parser.MoveToNextAttribute() ) { compare (parser.get_Name(), parser.get_Value()); }//End WHILE block }//End IF block parser.MoveToElement(); } else if (myNType.Equals( XmlNodeType.Text )) { textStr = parser.ReadString(); int counter = elemList.get_Count()-1; found = false; while (counter >= 0 && !found) { compare(elemList.get_Item(counter).ToString(), textStr); counter--; } if (counter < 0) //Console.WriteLine("ERRORE"); System.out.println("ERRORE"); else { found = false; elemList.RemoveAt(elemList.get_Count()-1); } } else if ( myNType.Equals( XmlNodeType.EndElement ) ) { int idx = elemList.LastIndexOf(parser.get_Name()); elemList.RemoveAt(idx); if (elemList.get_Count() > 0) compare(elemList.get_Item(elemList.get_Count()-1).ToString(), ""); } }//End WHILE block parser.Close(); } catch (XmlException e) { env = new Envelope(); throw new MTPException("Exception during parsing XML file.\nNested exception is: "+e.get_Message()); } finally { return env; } } public void compare(String s, String r) throws MTPException { try { this.found = true; if (s.equalsIgnoreCase(this.AID_NAME)) { aidStr = r.Trim(badChars); } else if (s.equalsIgnoreCase(this.TO_TAG)) { //aidStr = convertHostname(aidStr); AID newAID = new AID(aidStr, AID.ISGUID); newAID.addAddresses( addressStr ); env.addTo( newAID ); //reset values aidStr = ""; addressStr = ""; } else if (s.equalsIgnoreCase(this.FROM_TAG)) { AID newAID = new AID(aidStr, AID.ISGUID); newAID.addAddresses( addressStr ); env.setFrom( newAID ); //reset values aidStr = ""; addressStr = ""; } else if (s.equalsIgnoreCase(this.AID_ADDRESS)) { if (r != "") addressStr = r.Trim(badChars); } else if (s.equalsIgnoreCase(this.AID_ADDRESSES)) { if (r != "") addressStr = r.Trim(badChars); } else if (s.equalsIgnoreCase(this.REPRESENTATION_TAG)) { String aclStr = r.Trim(badChars); env.setAclRepresentation( aclStr ); } else if (s.equalsIgnoreCase(this.DATE_TAG)) { String dateStr = r.Trim(badChars); BasicFipaDateTime bfdt = new BasicFipaDateTime(dateStr); env.setDate( bfdt.getTime() ); } else if (s.equalsIgnoreCase(this.INTENDED_TAG)) { //aidStr = convertHostname(aidStr); AID newAID = new AID(aidStr, AID.ISGUID); newAID.addAddresses( addressStr ); env.addIntendedReceiver( newAID ); //reset values aidStr = ""; addressStr = ""; } else if (s.equalsIgnoreCase(this.ENCODING_TAG)) { String payStr = r.Trim(badChars); env.setPayloadEncoding( payStr ); } else if (s.equalsIgnoreCase(this.LENGTH_TAG)) { String payStr = r.Trim(badChars); env.setPayloadLength( new java.lang.Long(payStr) ); } else if (s.equalsIgnoreCase(this.COMMENTS_TAG)) { String cmtStr = r.Trim(badChars); env.setComments( cmtStr ); } else if (s.equalsIgnoreCase(this.RECEIVED_TAG)) { env.setReceived( recObj ); } else if (s.equalsIgnoreCase(this.RECEIVED_VIA)) { String via = r.Trim(badChars); recObj.setVia( via ); } else if (s.equalsIgnoreCase(this.RECEIVED_BY)) { String mts = r.Trim(badChars); recObj.setBy( mts ); } else if (s.equalsIgnoreCase(this.RECEIVED_DATE)) { String aDate = r.Trim(badChars); BasicFipaDateTime bfdt = new BasicFipaDateTime(aDate); recObj.setDate( bfdt.getTime() ); } else if (s.equalsIgnoreCase(this.RECEIVED_FROM)) { String from = r.Trim(badChars); recObj.setFrom( from ); } else if (s.equalsIgnoreCase(this.RECEIVED_ID)) { String id = r.Trim(badChars); recObj.setId( id ); } else if (s.equalsIgnoreCase(this.INDEX)) { String index = r.Trim(badChars); Property prop = new Property(); prop.setName(s); prop.setValue(index); env.addProperties( prop ); } else found = false; } catch (Exception e) { throw new MTPException("Error during tags comparison"); } } #DOTNET_INCLUDE_END*/ }//End of XMLCodec class