001    /**
002     *   GRANITE DATA SERVICES
003     *   Copyright (C) 2006-2013 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    package org.granite.client.messaging.channel.amf;
021    
022    import java.io.UnsupportedEncodingException;
023    import java.net.URI;
024    import java.util.ArrayList;
025    import java.util.List;
026    
027    import org.granite.client.messaging.channel.AbstractHTTPChannel;
028    import org.granite.client.messaging.channel.Credentials;
029    import org.granite.client.messaging.channel.UsernamePasswordCredentials;
030    import org.granite.client.messaging.messages.RequestMessage;
031    import org.granite.client.messaging.messages.push.TopicMessage;
032    import org.granite.client.messaging.messages.requests.InvocationMessage;
033    import org.granite.client.messaging.messages.requests.LoginMessage;
034    import org.granite.client.messaging.messages.requests.PublishMessage;
035    import org.granite.client.messaging.messages.requests.SubscribeMessage;
036    import org.granite.client.messaging.messages.requests.UnsubscribeMessage;
037    import org.granite.client.messaging.messages.responses.AbstractResponseMessage;
038    import org.granite.client.messaging.messages.responses.FaultMessage;
039    import org.granite.client.messaging.messages.responses.FaultMessage.Code;
040    import org.granite.client.messaging.messages.responses.ResultMessage;
041    import org.granite.client.messaging.transport.Transport;
042    import org.granite.messaging.service.security.SecurityServiceException;
043    
044    import flex.messaging.messages.AcknowledgeMessage;
045    import flex.messaging.messages.AsyncMessage;
046    import flex.messaging.messages.CommandMessage;
047    import flex.messaging.messages.ErrorMessage;
048    import flex.messaging.messages.Message;
049    import flex.messaging.messages.RemotingMessage;
050    
051    /**
052     * @author Franck WOLFF
053     */
054    public abstract class AbstractAMFChannel extends AbstractHTTPChannel {
055    
056            public AbstractAMFChannel(Transport transport, String id, URI uri, int maxConcurrentRequests) {
057                    super(transport, id, uri, maxConcurrentRequests);
058            }
059    
060            protected Message[] convertToAmf(RequestMessage request) throws UnsupportedEncodingException {
061                    Message[] messages = null;
062                    
063                    switch (request.getType()) {
064                            case PING: {
065                                    CommandMessage commandMessage = new CommandMessage();
066                                    commandMessage.setOperation(CommandMessage.CLIENT_PING_OPERATION);
067                                    commandMessage.setMessageId(request.getId());
068                                    commandMessage.setTimestamp(request.getTimestamp());
069                                    commandMessage.setTimeToLive(request.getTimeToLive());
070                                    commandMessage.setHeaders(request.getHeaders());
071                                    messages = new Message[]{commandMessage};
072                                    break;
073                            }
074                            case LOGIN: {
075                                    LoginMessage login = (LoginMessage)request;
076                                    CommandMessage commandMessage = new CommandMessage();
077                                    commandMessage.setOperation(CommandMessage.LOGIN_OPERATION);
078                                    commandMessage.setMessageId(request.getId());
079                                    commandMessage.setTimestamp(request.getTimestamp());
080                                    commandMessage.setTimeToLive(request.getTimeToLive());
081                                    commandMessage.setHeaders(request.getHeaders());
082                                    Credentials credentials = login.getCredentials();
083                                    if (credentials instanceof UsernamePasswordCredentials)
084                                            commandMessage.setBody(((UsernamePasswordCredentials)credentials).encodeBase64());
085                                    else
086                                            throw new UnsupportedOperationException("Unsupported credentials type: " + credentials);
087                                    messages = new Message[]{commandMessage};
088                                    break;
089                            }
090                            case LOGOUT: {
091                                    CommandMessage commandMessage = new CommandMessage();
092                                    commandMessage.setOperation(CommandMessage.LOGOUT_OPERATION);
093                                    commandMessage.setMessageId(request.getId());
094                                    commandMessage.setTimestamp(request.getTimestamp());
095                                    commandMessage.setTimeToLive(request.getTimeToLive());
096                                    commandMessage.setHeaders(request.getHeaders());
097                                    messages = new Message[]{commandMessage};
098                                    break;
099                            }
100                            case PUBLISH: {
101                                    PublishMessage publish = (PublishMessage)request;
102                                    AsyncMessage asyncMessage = new AsyncMessage();
103                                    asyncMessage.setMessageId(publish.getId());
104                                    asyncMessage.setTimestamp(publish.getTimestamp());
105                                    asyncMessage.setTimeToLive(publish.getTimeToLive());
106                                    asyncMessage.setHeaders(publish.getHeaders());
107                                    asyncMessage.setDestination(publish.getDestination());
108                                    asyncMessage.setHeader(AsyncMessage.SUBTOPIC_HEADER, publish.getTopic());
109                                    asyncMessage.setBody(publish.getBody());
110                                    messages = new Message[]{asyncMessage};
111                                    break;
112                            }
113                            case SUBSCRIBE: {
114                                    SubscribeMessage subscribe = (SubscribeMessage)request;
115                                    CommandMessage commandMessage = new CommandMessage();
116                                    commandMessage.setOperation(CommandMessage.SUBSCRIBE_OPERATION);
117                                    commandMessage.setMessageId(subscribe.getId());
118                                    commandMessage.setTimestamp(subscribe.getTimestamp());
119                                    commandMessage.setTimeToLive(subscribe.getTimeToLive());
120                                    commandMessage.setHeaders(subscribe.getHeaders());
121                                    commandMessage.setDestination(subscribe.getDestination());
122                                    commandMessage.setHeader(AsyncMessage.SUBTOPIC_HEADER, subscribe.getTopic());
123                                    if (subscribe.getSelector() != null)
124                                            commandMessage.setHeader(CommandMessage.SELECTOR_HEADER, subscribe.getSelector());
125                                    messages = new Message[]{commandMessage};
126                                    break;
127                            }
128                            case UNSUBSCRIBE: {
129                                    UnsubscribeMessage unsubscribe = (UnsubscribeMessage)request;
130                                    CommandMessage commandMessage = new CommandMessage();
131                                    commandMessage.setOperation(CommandMessage.UNSUBSCRIBE_OPERATION);
132                                    commandMessage.setMessageId(unsubscribe.getId());
133                                    commandMessage.setTimestamp(unsubscribe.getTimestamp());
134                                    commandMessage.setTimeToLive(unsubscribe.getTimeToLive());
135                                    commandMessage.setHeaders(unsubscribe.getHeaders());
136                                    commandMessage.setDestination(unsubscribe.getDestination());
137                                    commandMessage.setHeader(AsyncMessage.SUBTOPIC_HEADER, unsubscribe.getTopic());
138                                    commandMessage.setHeader(AsyncMessage.DESTINATION_CLIENT_ID_HEADER, unsubscribe.getSubscriptionId());
139                                    messages = new Message[]{commandMessage};
140                                    break;
141                            }
142                            case INVOCATION: {
143                                    List<Message> remotingMessages = new ArrayList<Message>();
144                                    
145                                    for (InvocationMessage invocation : (InvocationMessage)request) {
146                                            RemotingMessage remotingMessage = new RemotingMessage();
147                                            remotingMessage.setDestination(invocation.getServiceId());
148                                            remotingMessage.setOperation(invocation.getMethod());
149                                            remotingMessage.setBody(invocation.getParameters() != null ? invocation.getParameters() : new Object[0]);
150                                            remotingMessage.setMessageId(invocation.getId());
151                                            remotingMessage.setTimestamp(invocation.getTimestamp());
152                                            remotingMessage.setTimeToLive(invocation.getTimeToLive());
153                                            remotingMessage.setHeaders(invocation.getHeaders());
154                                            remotingMessages.add(remotingMessage);
155                                    }
156                                    
157                                    messages = remotingMessages.toArray(new Message[remotingMessages.size()]);
158                                    break;
159                            }
160                            case DISCONNECT: {
161                                    CommandMessage commandMessage = new CommandMessage();
162                                    commandMessage.setOperation(CommandMessage.DISCONNECT_OPERATION);
163                                    commandMessage.setMessageId(request.getId());
164                                    commandMessage.setTimestamp(request.getTimestamp());
165                                    commandMessage.setTimeToLive(request.getTimeToLive());
166                                    commandMessage.setHeaders(request.getHeaders());
167                                    messages = new Message[]{commandMessage};
168                                    break;
169                            }
170                            default:
171                                    throw new IllegalArgumentException("Unsupported message type: " + request);
172                    }
173                    
174                    for (Message message : messages) {
175                            message.setClientId(getClientId());
176                            message.setHeader(Message.ENDPOINT_HEADER, getId());
177                    }
178                    
179                    return messages;
180            }
181            
182            protected TopicMessage convertFromAmf(AsyncMessage message) {
183                    return new TopicMessage(
184                            message.getMessageId(),
185                            (String)message.getClientId(),
186                            message.getTimestamp(),
187                            message.getTimeToLive(),
188                            message.getHeaders(),
189                            message.getBody()
190                    );
191            }
192            
193            protected AbstractResponseMessage convertFromAmf(AcknowledgeMessage message) {
194                    if (message instanceof ErrorMessage) {
195                            ErrorMessage errorMessage = (ErrorMessage)message;
196                            
197                            Code code = Code.UNKNOWN;
198    
199                            String flexCode = errorMessage.getFaultCode();
200                            if (ErrorMessage.CODE_SERVER_CALL_FAILED.equals(flexCode))
201                                    code = Code.SERVER_CALL_FAILED;
202                            else if (SecurityServiceException.CODE_ACCESS_DENIED.equals(flexCode))
203                                    code = Code.ACCESS_DENIED;
204                            else if (SecurityServiceException.CODE_INVALID_CREDENTIALS.equals(flexCode)) {
205                                    authenticated = false;
206                                    code = Code.INVALID_CREDENTIALS;
207                            }
208                            else if (SecurityServiceException.CODE_AUTHENTICATION_FAILED.equals(flexCode)) {
209                                    authenticated = false;
210                                    code = Code.AUTHENTICATION_FAILED;
211                            }
212                            else if (SecurityServiceException.CODE_NOT_LOGGED_IN.equals(flexCode)) {
213                                    authenticated = false;
214                                    code = Code.NOT_LOGGED_IN;
215                            }
216                            else if (SecurityServiceException.CODE_SESSION_EXPIRED.equals(flexCode)) {
217                                    authenticated = false;
218                                    code = Code.SESSION_EXPIRED;
219                            }
220                            else if ("Validation.Failed".equals(flexCode))
221                                    code = Code.VALIDATION_FAILED;
222                            else if ("Persistence.OptimisticLock".equals(flexCode))
223                                    code = Code.OPTIMISTIC_LOCK;
224                                    
225                            FaultMessage fault = new FaultMessage( 
226                                    errorMessage.getMessageId(),
227                                    (String)errorMessage.getClientId(),
228                                    errorMessage.getTimestamp(),
229                                    errorMessage.getTimeToLive(),
230                                    errorMessage.getHeaders(),
231                                    errorMessage.getCorrelationId(),
232                                    code,
233                                    errorMessage.getFaultString(),
234                                    errorMessage.getFaultDetail(),
235                                    errorMessage.getRootCause(),
236                                    errorMessage.getExtendedData()
237                            );
238                            
239                            if (code == Code.UNKNOWN)
240                                    fault.setUnknownCode(flexCode);
241                            
242                            return fault;
243                    }
244                    
245                    return new ResultMessage( 
246                            message.getMessageId(),
247                            (String)message.getClientId(),
248                            message.getTimestamp(),
249                            message.getTimeToLive(),
250                            message.getHeaders(),
251                            message.getCorrelationId(),
252                            message.getBody()
253                    );
254            }
255    }