001    /*
002      GRANITE DATA SERVICES
003      Copyright (C) 2011 GRANITE DATA SERVICES S.A.S.
004    
005      This file is part of Granite Data Services.
006    
007      Granite Data Services is free software; you can redistribute it and/or modify
008      it under the terms of the GNU Library General Public License as published by
009      the Free Software Foundation; either version 2 of the License, or (at your
010      option) any later version.
011    
012      Granite Data Services is distributed in the hope that it will be useful, but
013      WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014      FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
015      for more details.
016    
017      You should have received a copy of the GNU Library General Public License
018      along with this library; if not, see <http://www.gnu.org/licenses/>.
019    */
020    
021    package org.granite.messaging.amf.process;
022    
023    import java.util.Iterator;
024    import java.util.List;
025    
026    import org.granite.context.AMFContextImpl;
027    import org.granite.context.GraniteContext;
028    import org.granite.logging.Logger;
029    import org.granite.messaging.amf.AMF0Body;
030    import org.granite.messaging.amf.AMF0Message;
031    import org.granite.messaging.amf.AMF3Object;
032    import org.granite.util.UUIDUtil;
033    
034    import flex.messaging.messages.ErrorMessage;
035    import flex.messaging.messages.Message;
036    
037    /**
038     * @author Franck WOLFF
039     */
040    public abstract class AMF0MessageProcessor {
041    
042        private static final Logger log = Logger.getLogger(AMF0MessageProcessor.class);
043    
044        public static AMF0Message process(AMF0Message amf0RequestMessage) {
045    
046            log.debug(">> Processing AMF0 request:%s", amf0RequestMessage);
047    
048            GraniteContext context = GraniteContext.getCurrentInstance();
049            AMFContextImpl amf = (AMFContextImpl)context.getAMFContext();
050    
051            AMF0Message amf0ResponseMessage = new AMF0Message();
052            amf0ResponseMessage.setVersion(amf0RequestMessage.getVersion());
053    
054            ErrorMessage loginError = null;
055            String dsId = null;
056            for (Iterator<AMF0Body> bodies = amf0RequestMessage.getBodies(); bodies.hasNext(); ) {
057                AMF0Body requestBody = bodies.next();
058    
059                Object value = requestBody.getValue();
060                           
061                Message amf3RequestMessage = null;
062                
063                if (value instanceof List<?>)
064                    amf3RequestMessage = (Message)((List<?>)value).get(0);
065                else
066                    amf3RequestMessage = (Message)((Object[])value)[0];                             
067                
068                log.debug(">> Processing AMF3 request:\n%s", amf3RequestMessage);
069    
070                // If we get a login error (setCredentials on flex side), we don't execute subsequent requests and
071                // just copy the initial login error (GDS specific, otherwise the FaultEvent dispatched by the
072                // RemoteObject is not the login error but an authorization error after actual service call).
073                Message amf3ResponseMessage = null;
074                if (loginError == null) {
075                    amf.setCurrentAmf3Message(amf3RequestMessage);
076    
077                    amf.getCustomResponseHeaders().clear();
078                    amf3ResponseMessage = AMF3MessageProcessor.process(amf3RequestMessage);
079    
080                    if ((amf3ResponseMessage instanceof ErrorMessage) && ((ErrorMessage)amf3ResponseMessage).loginError())
081                        loginError = (ErrorMessage)amf3ResponseMessage;
082    
083                    // For SDK 2.0.1_Hotfix2+ (LCDS 2.5+).
084                    if ("nil".equals(amf3ResponseMessage.getHeader(Message.DS_ID_HEADER))) {
085                        amf3ResponseMessage.getHeaders().put(
086                            Message.DS_ID_HEADER,
087                            (dsId == null ? (dsId = UUIDUtil.randomUUID()) : dsId)
088                        );
089                    }
090                    amf3ResponseMessage.getHeaders().putAll(amf.getCustomResponseHeaders());
091                }
092                else
093                    amf3ResponseMessage = loginError.copy(amf3RequestMessage);
094    
095                log.debug("<< Got AMF3 response:\n%s", amf3ResponseMessage);
096    
097                AMF3Object data = new AMF3Object(amf3ResponseMessage);
098                AMF0Body responseBody = new AMF0Body(
099                    getResponseTarget(requestBody, amf3ResponseMessage), "", data, AMF0Body.DATA_TYPE_AMF3_OBJECT
100                );
101                amf0ResponseMessage.addBody(responseBody);
102            }
103    
104            log.debug("<< Returning AMF0 response:%s", amf0ResponseMessage);
105    
106            return amf0ResponseMessage;
107        }
108    
109        private static String getResponseTarget(AMF0Body requestBody, Message responseMessage) {
110            if (responseMessage instanceof ErrorMessage)
111                return requestBody.getResponse() + "/onStatus";
112            return requestBody.getResponse() + "/onResult";
113        }
114    }