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