| /* |
| * 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.amf; |
| |
| import flex.messaging.MessageException; |
| import flex.messaging.io.MessageDeserializer; |
| import flex.messaging.io.MessageIOConstants; |
| import flex.messaging.io.RecoverableSerializationException; |
| import flex.messaging.io.SerializationContext; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| |
| public class AmfMessageDeserializer implements MessageDeserializer |
| { |
| public static final String CODE_VERSION_MISMATCH = "VersionMismatch"; |
| private static final int UNSUPPORTED_AMF_VERSION = 10310; |
| |
| protected ActionMessageInput amfIn; |
| |
| protected AmfTrace debugTrace; |
| protected boolean isDebug; |
| |
| public AmfMessageDeserializer() |
| { |
| } |
| |
| public void initialize(SerializationContext context, InputStream in, AmfTrace trace) |
| { |
| amfIn = new Amf0Input(context); |
| amfIn.setInputStream(in); |
| |
| debugTrace = trace; |
| isDebug = debugTrace != null; |
| amfIn.setDebugTrace(debugTrace); |
| } |
| |
| public void readMessage(ActionMessage m, ActionContext context) throws ClassNotFoundException, IOException |
| { |
| if (isDebug) |
| debugTrace.startRequest("Deserializing AMF/HTTP request"); |
| |
| int version = amfIn.readUnsignedShort(); |
| |
| // Treat FMS's AMF1 as AMF0. |
| if (version == MessageIOConstants.AMF1) |
| version = MessageIOConstants.AMF0; |
| |
| if (version != MessageIOConstants.AMF0 && version != MessageIOConstants.AMF3) |
| { |
| //Unsupported AMF version {version}. |
| MessageException ex = new MessageException(); |
| ex.setMessage(UNSUPPORTED_AMF_VERSION, new Object[] {new Integer(version)}); |
| ex.setCode(CODE_VERSION_MISMATCH); |
| throw ex; |
| } |
| |
| m.setVersion(version); |
| context.setVersion(version); |
| |
| if (isDebug) |
| debugTrace.version(version); |
| |
| // Read headers |
| int headerCount = amfIn.readUnsignedShort(); |
| for (int i = 0; i < headerCount; ++i) |
| { |
| MessageHeader header = new MessageHeader(); |
| m.addHeader(header); |
| readHeader(header, i); |
| } |
| |
| // Read bodies |
| int bodyCount = amfIn.readUnsignedShort(); |
| for (int i = 0; i < bodyCount; ++i) |
| { |
| MessageBody body = new MessageBody(); |
| m.addBody(body); |
| readBody(body, i); |
| } |
| } |
| |
| |
| /** |
| * Deserialize a message header from the input stream. |
| * A message header is structured as: |
| * NAME kString |
| * MUST UNDERSTAND kBoolean |
| * LENGTH kInt |
| * DATA kObject |
| * |
| * @param header - will hold the deserialized message header |
| * @param index header index for debugging |
| * @throws IOException thrown by the underlying stream |
| * @throws ClassNotFoundException if we don't find the class for the header data. |
| */ |
| public void readHeader(MessageHeader header, int index) throws ClassNotFoundException, IOException |
| { |
| String name = amfIn.readUTF(); |
| header.setName(name); |
| boolean mustUnderstand = amfIn.readBoolean(); |
| header.setMustUnderstand(mustUnderstand); |
| |
| amfIn.readInt(); // Length |
| |
| amfIn.reset(); |
| Object data; |
| |
| if (isDebug) |
| debugTrace.startHeader(name, mustUnderstand, index); |
| |
| try |
| { |
| data = readObject(); |
| } |
| catch (RecoverableSerializationException ex) |
| { |
| ex.setCode("Client.Header.Encoding"); |
| data = ex; |
| } |
| catch (MessageException ex) |
| { |
| ex.setCode("Client.Header.Encoding"); |
| throw ex; |
| } |
| |
| header.setData(data); |
| |
| if (isDebug) |
| debugTrace.endHeader(); |
| } |
| |
| |
| /** |
| * Deserialize a message body from the input stream. |
| * |
| * @param body - will hold the deserialized message body |
| * @param index message index for debugging |
| * @throws IOException thrown by the underlying stream |
| * @throws ClassNotFoundException if we don't find the class for the body data. |
| */ |
| public void readBody(MessageBody body, int index) throws ClassNotFoundException, IOException |
| { |
| String targetURI = amfIn.readUTF(); |
| body.setTargetURI(targetURI); |
| String responseURI = amfIn.readUTF(); |
| body.setResponseURI(responseURI); |
| |
| amfIn.readInt(); // Length |
| |
| amfIn.reset(); |
| Object data; |
| |
| if (isDebug) |
| debugTrace.startMessage(targetURI, responseURI, index); |
| |
| try |
| { |
| data = readObject(); |
| } |
| catch (RecoverableSerializationException ex) |
| { |
| ex.setCode("Client.Message.Encoding"); |
| data = ex; |
| } |
| catch (MessageException ex) |
| { |
| ex.setCode("Client.Message.Encoding"); |
| throw ex; |
| } |
| |
| body.setData(data); |
| |
| if (isDebug) |
| debugTrace.endMessage(); |
| } |
| |
| /** |
| * Read Object. |
| * @return Object the object read from AmfInput |
| * @throws ClassNotFoundException, IOException when exceptions occurs in reading the object |
| */ |
| public Object readObject() throws ClassNotFoundException, IOException |
| { |
| return amfIn.readObject(); |
| } |
| } |
| |