Thanks Emmanuel!
The pointer was helpful. Though I though about implementing somewhat
in a different way.
The decoder was implemented just to see the xml is complete and then
pass-on the buffer to an abstract function, to be
implemented by the user, picking an XML parser or Data binding
Framework of his choice, convert it to the Object as expected by their
Handler.
Before I dump the code, few words
1. The code is not very clean and production ready. It just gives an
idea of how to do it
2. The parsing doesn't handle all the XML specification conditions.
3. My limited knowledge of IoBuffer class has made code more cryptic
than it should have been :-)
Either ways, it shall server the purpose of that people can take it to
next level, and will write a post on this on my blog
I am inclined towards using regular expression for parsing and will
post the code if I am able to do that.
Thanks all!
import org.apache.mina.common.IoBuffer;
import org.apache.mina.common.IoSession;
import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class XMLDecoder extends CumulativeProtocolDecoder {
/*
* As per XML specification 1.0, http://www.w3.org/TR/REC-xml
*/
private static final char XML_START_TAG = '<';
private static final char XML_END_TAG = '>';
private static final char XML_PI_TAG = '?';
private static final char XML_COMMENT_TAG = '!';
protected static enum ParseState {ELEMENT_START, ELEMENT_END,
COMMENTS, ENDELEMENT, PI, UNDEFINED};
protected static final int ELEMENT_START = 1;
protected static final int ELEMENT_END = 2;
private static Logger logger =
LoggerFactory.getLogger(XMLDecoder.class);
@Override
protected boolean doDecode(IoSession session, IoBuffer ioBuffer,
ProtocolDecoderOutput decoderOutput) throws Exception {
int startPosition = ioBuffer.position();
if(!ioBuffer.hasRemaining()) {
logger.debug("NO bytes to read keep waiting...");
return false;
}
// Continue to read the bytes and keep parsing
char currentChar = '0', previousChar = '0';
boolean rootElementStarted = false;
boolean rootElementPresent = false;
boolean isBalanced = false;
int rootStartPosition, rootEndPosition;
ParseState parsingState = ParseState.UNDEFINED;
logger.debug("Lets start decoding the XML");
String root = null;
boolean markedForEndElement = false;
while(ioBuffer.hasRemaining()) {
previousChar = currentChar;
currentChar = (char)ioBuffer.get();
switch (parsingState) {
case ELEMENT_START:
if(currentChar == XML_PI_TAG){
logger.debug("Got PI Element");
parsingState = ParseState.PI;
} else if(currentChar ==
XML_COMMENT_TAG) {
logger.debug("Got Comment
Element");
parsingState =
ParseState.COMMENTS;
} else if((currentChar == ' ' ||
currentChar == XML_END_TAG)
&&
rootElementStarted && !rootElementPresent) {
rootEndPosition =
ioBuffer.position();
rootElementPresent = true;
// Copy the Root Element
int cPos = ioBuffer.position();
int mPos = ioBuffer.markValue();
char[] rootChar = new char[cPos
- mPos];
for(int i = mPos - 1, j =0; i <
cPos - 1; i++) {
rootChar[j++] =
(char)ioBuffer.get(i);
}
root = new String(rootChar);
logger.debug("Root Element = "+
root);
parsingState =
ParseState.ELEMENT_END;
logger.debug("Root Element
detection completed "+rootEndPosition);
} else if(currentChar == XML_END_TAG) {
parsingState =
ParseState.ELEMENT_END;
} else if(!rootElementStarted &&
!rootElementPresent) {
rootStartPosition =
ioBuffer.position();
ioBuffer.mark();
rootElementStarted = true;
logger.debug("Got the root
element at "+rootStartPosition);
} else if (currentChar == '/') {
// Change state
if(previousChar ==
XML_START_TAG) {
parsingState =
ParseState.ENDELEMENT;
}
}
break;
case ENDELEMENT:
if(currentChar == XML_END_TAG) {
parsingState =
ParseState.ELEMENT_END;
int cPos = ioBuffer.position();
int mPos = ioBuffer.markValue();
char[] el = new char[cPos -
mPos];
for(int i = mPos - 1, j =0; i <
cPos - 1; i++) {
el[j++] =
(char)ioBuffer.get(i);
}
markedForEndElement = false;
if(root.equalsIgnoreCase(new
String(el))) {
logger.debug("XML is
balanced."+root);
isBalanced = true;
}
break;
} else if (currentChar == ' ') {
continue;
} else {
// mark the position, we need
to compare the it to see that if
its the end element
if(!markedForEndElement) {
// logger.debug("Marking");
ioBuffer.mark();
markedForEndElement =
true;
}
}
break;
case ELEMENT_END:
if(currentChar == XML_START_TAG) {
parsingState =
ParseState.ELEMENT_START;
}
break;
case UNDEFINED:
if(currentChar == XML_START_TAG) {
parsingState =
ParseState.ELEMENT_START;
}
break;
case COMMENTS:
if (currentChar == '-') {
previousChar = currentChar;
} else if (previousChar == '-' &&
currentChar == '>') {
parsingState =
ParseState.ELEMENT_END;
}
break;
case PI:
if (currentChar == '?') {
previousChar = currentChar;
} else if (previousChar == '?' &&
currentChar == XML_END_TAG) {
parsingState =
ParseState.ELEMENT_END;
}
break;
default:
break;
}
}
if(isBalanced) {
decoderOutput.write(parserXML(ioBuffer));
}
if(isBalanced && !ioBuffer.hasRemaining()) {
logger.debug("No more bytes to process");
return true;
}
ioBuffer.position(startPosition);
return false;
}
/**
* Extending classes can implement their custom XML parsing to create
Objects
* from XML and use them appropriately in Handler
*
* @param xmlBuffer
* @return
*/
public abstract Object parserXML(IoBuffer xmlBuffer);
}
On Wed, Oct 22, 2008 at 10:25 PM, Emmanuel Lecharny <[EMAIL PROTECTED]> wrote:
> Smith wrote:
>>
>> Hi , i'm following your discussion and i remember that the guys from
>> JiveSoftware have created an XMPP server using mina , and the XMPP protocol
>> use XML Stream. The software is under GPL so you can take a look a the
>> source to see how they handle this problem :)
>
> There is also an Apache effort based on MINA and XMPP :
> http://svn.apache.org/repos/asf/labs/vysper/
>
> The code is available, and is ASL 2.0, of course.
>
> --
> --
> cordialement, regards,
> Emmanuel Lécharny
> www.iktek.com
> directory.apache.org
--
thanks
ashish
Blog: http://www.ashishpaliwal.com/blog
My Photo Galleries: http://www.pbase.com/ashishpaliwal