blob: b5a3c09fc5420bf6baa99a52089a49ef9d3fc8cb [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package flex.messaging.io.amfx;
import flex.messaging.io.MessageDeserializer;
import flex.messaging.io.amf.ActionContext;
import flex.messaging.io.amf.ActionMessage;
import flex.messaging.io.amf.AmfTrace;
import flex.messaging.io.SerializationContext;
import flex.messaging.MessageException;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* SAX based AMFX Parser.
*/
public class AmfxMessageDeserializer extends DefaultHandler implements MessageDeserializer
{
protected InputStream in;
protected Locator locator;
protected AmfxInput amfxIn;
/*
* DEBUG LOGGING
*/
protected AmfTrace debugTrace;
protected boolean isDebug;
/**
* Constructor.
* Create a new AmfxMessageDeserializer object
*
*/
public AmfxMessageDeserializer()
{
}
/**
* Establishes the context for reading in data from the given InputStream.
* A null value can be passed for the trace parameter if a record of the
* AMFX data should not be made.
*
* @param context SerializationContext object
* @param in InputStream to process
* @param trace AmfTrace object
*/
public void initialize(SerializationContext context, InputStream in, AmfTrace trace)
{
amfxIn = new AmfxInput(context);
this.in = in;
debugTrace = trace;
isDebug = debugTrace != null;
if (debugTrace != null)
amfxIn.setDebugTrace(debugTrace);
}
/**
* Set the SerializationContext.
*
* @param context the SerializationContext object
*/
public void setSerializationContext(SerializationContext context)
{
amfxIn = new AmfxInput(context);
}
/**
* Read message from the ActionMessage and ActionContext.
*
* @param m current ActionMessage
* @param context current ActionContext
* @throws IOException when the read message process failed
*/
public void readMessage(ActionMessage m, ActionContext context) throws IOException
{
if (isDebug)
debugTrace.startRequest("Deserializing AMFX/HTTP request");
amfxIn.reset();
amfxIn.setDebugTrace(debugTrace);
amfxIn.setActionMessage(m);
parse(m);
context.setVersion(m.getVersion());
}
/**
* Read Object.
* @return Object the object read from AmfxInput
* @throws ClassNotFoundException, IOException when exceptions occurs in reading the object
*/
public Object readObject() throws ClassNotFoundException, IOException
{
return amfxIn.readObject();
}
protected void parse(ActionMessage m)
{
try
{
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setValidating(false);
factory.setNamespaceAware(true);
SAXParser parser = factory.newSAXParser();
parser.parse(in, this);
}
catch (MessageException ex)
{
clientMessageEncodingException(m, ex);
}
catch (SAXParseException e)
{
if (e.getException() != null)
{
clientMessageEncodingException(m, e.getException());
}
else
{
clientMessageEncodingException(m, e);
}
}
catch (Exception ex)
{
clientMessageEncodingException(m, ex);
}
}
/**
* Implement {@link org.xml.sax.EntityResolver#resolveEntity(String, String)}.
*
* AMFX does not need or use external entities, so disallow external entities
* to prevent external entity injection attacks.
*
* @param publicId the public Id
* @param systemId the system Id
* @return InputSource the InputSource after entity resolution
* @throws SAXException, IOException if the process failed
*/
public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException
{
throw new MessageException("External entities are not allowed");
}
protected void clientMessageEncodingException(ActionMessage m, Throwable t)
{
MessageException me;
if (t instanceof MessageException)
{
me = (MessageException)t;
}
else
{
me = new MessageException("Error occurred parsing AMFX: " + t.getMessage());
}
me.setCode("Client.Message.Encoding");
throw me;
}
/**
* Start process of an Element.
*
* @param uri the URI of the element
* @param localName the local name of the element
* @param qName the qualify name of the element
* @param attributes the Attributes in the element
* @throws SAXException if the process failed
*/
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
{
try
{
String methodName = "start_" + localName;
Method method = amfxIn.getClass().getMethod(methodName, attribArr);
method.invoke(amfxIn, new Object[]{attributes});
}
catch (NoSuchMethodException e)
{
fatalError(new SAXParseException("Unknown type: " + qName, locator));
}
catch (IllegalAccessException e)
{
fatalError(new SAXParseException(e.getMessage(), locator, e));
}
catch (InvocationTargetException e)
{
Throwable t = e.getTargetException();
if (t instanceof SAXException)
{
throw (SAXException)t;
}
else if (t instanceof Exception)
{
fatalError(new SAXParseException(t.getMessage(), locator, (Exception)t));
}
else
{
fatalError(new SAXParseException(e.getMessage(), locator, e));
}
}
}
/**
* End process of an Element.
*
* @param uri the URI of the element
* @param localName the local name of the element
* @param qName the qualify name of the element
* @throws SAXException if the process failed
*/
public void endElement(String uri, String localName, String qName) throws SAXException
{
try
{
String methodName = "end_" + localName;
Method method = amfxIn.getClass().getMethod(methodName, new Class[]{});
method.invoke(amfxIn, new Object[]{});
}
catch (NoSuchMethodException e)
{
fatalError(new SAXParseException("Unfinished type: " + qName, locator));
}
catch (IllegalAccessException e)
{
fatalError(new SAXParseException(e.getMessage(), locator, e));
}
catch (InvocationTargetException e)
{
Throwable t = e.getTargetException();
if (t instanceof SAXException)
{
throw (SAXException)t;
}
else if (t instanceof Error)
{
throw (Error)t;
}
else
{
fatalError(new SAXParseException(t.getMessage(), locator));
}
}
}
/**
* Process a char array.
*
* @param ch the char array
* @param start the start position in the char array
* @param length the length of chars to process
* @throws SAXException if the process failed
*/
public void characters(char ch[], int start, int length) throws SAXException
{
String chars = new String(ch, start, length);
if (chars.length() > 0)
{
amfxIn.text(chars);
}
}
/**
* Set the DocumentLocator object.
*
* @param l the DocumentLocator object
*/
public void setDocumentLocator(Locator l)
{
locator = l;
}
/**
* Process Error of a SAXParseException.
*
* @param exception SAXParseException
* @throws SAXException rethrow the SAXException
*/
public void error(SAXParseException exception) throws SAXException
{
throw new MessageException(exception.getMessage());
}
/**
* Process FatalError of a SAXParseException.
*
* @param exception SAXParseException
* @throws SAXException rethrow the SAXException
*/
public void fatalError(SAXParseException exception) throws SAXException
{
if ((exception.getException() != null) && (exception.getException() instanceof MessageException))
throw (MessageException)exception.getException();
throw new MessageException(exception.getMessage());
}
/**
* Process warning of a SAXParseException.
*
* @param exception SAXParseException
* @throws SAXException rethrow the SAXException
*/
public void warning(SAXParseException exception) throws SAXException
{
throw new MessageException(exception.getMessage());
}
private static Class[] attribArr = new Class[]{Attributes.class};
}