| /* |
| * 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)}. |
| * <p> |
| * 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}; |
| } |