/**
* GRANITE DATA SERVICES
* Copyright (C) 2006-2015 GRANITE DATA SERVICES S.A.S.
*
* This file is part of the Granite Data Services Platform.
*
* Granite Data Services is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* Granite Data Services is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA, or see <http://www.gnu.org/licenses/>.
*/
package org.granite.client.messaging.channel;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import flex.messaging.messages.Message;
import org.granite.client.messaging.ClientAliasRegistry;
import org.granite.client.messaging.ServerApp;
import org.granite.client.messaging.codec.MessagingCodec;
import org.granite.client.messaging.transport.Transport;
import org.granite.client.messaging.transport.TransportException;
import org.granite.client.platform.Platform;
import org.granite.messaging.AliasRegistry;
import org.granite.messaging.amf.AMF0Message;
import org.granite.util.ContentType;
import org.granite.util.ServiceLoader;
/**
* @author Franck WOLFF
*/
public abstract class AbstractChannelFactory implements ChannelFactory {
protected final ContentType contentType;
private String defaultChannelType = ChannelType.LONG_POLLING;
protected Transport remotingTransport = null;
protected Transport messagingTransport = null;
protected Map<String, Transport> messagingTransports = new HashMap<String, Transport>();
protected Object context = null;
protected ChannelBuilder defaultChannelBuilder = new DefaultChannelBuilder();
protected Set<String> scanPackageNames = null;
protected AliasRegistry aliasRegistry = null;
protected Long defaultTimeToLive = null;
protected Long defaultMaxReconnectAttempts = null;
protected AbstractChannelFactory(ContentType contentType) {
this(contentType, null, null, null);
}
protected AbstractChannelFactory(ContentType contentType, Object context) {
this(contentType, context, null, null);
}
protected AbstractChannelFactory(ContentType contentType, Object context, Transport remotingTransport, Transport messagingTransport) {
this.contentType = contentType;
this.context = context;
this.remotingTransport = remotingTransport;
this.messagingTransport = messagingTransport;
}
public Object getContext() {
return context;
}
public void setContext(Object context) {
this.context = context;
}
public void setDefaultChannelBuilder(ChannelBuilder channelBuilder) {
this.defaultChannelBuilder = channelBuilder;
}
public ContentType getContentType() {
return contentType;
}
public long getDefaultTimeToLive() {
return (defaultTimeToLive != null ? defaultTimeToLive.longValue() : -1L);
}
public void setDefaultTimeToLive(long defaultTimeToLive) {
this.defaultTimeToLive = Long.valueOf(defaultTimeToLive);
}
public void setDefaultMaxReconnectAttempts(long maxReconnectAttempts) {
this.defaultMaxReconnectAttempts = Long.valueOf(maxReconnectAttempts);
}
public void setAliasRegistry(AliasRegistry aliasRegistry) {
this.aliasRegistry = aliasRegistry;
}
public void setDefaultChannelType(String channelType) {
this.defaultChannelType = channelType;
}
public String getDefaultChannelType() {
return defaultChannelType;
}
public Transport getRemotingTransport() {
return remotingTransport;
}
public void setRemotingTransport(Transport remotingTransport) {
this.remotingTransport = remotingTransport;
}
public void setMessagingTransport(Transport messagingTransport) {
this.messagingTransport = messagingTransport;
}
public void setMessagingTransport(String channelType, Transport messagingTransport) {
this.messagingTransports.put(channelType, messagingTransport);
}
public Transport getMessagingTransport() {
return messagingTransport;
}
public Map<String, Transport> getMessagingTransports() {
return messagingTransports;
}
public Transport getMessagingTransport(String channelType) {
if (channelType != null && messagingTransports.containsKey(channelType))
return messagingTransports.get(channelType);
return messagingTransport;
}
public void setScanPackageNames(String... packageNames) {
if (packageNames != null)
this.scanPackageNames = new HashSet<String>(Arrays.asList(packageNames));
else
this.scanPackageNames = null;
}
public void setScanPackageNames(Set<String> packageNames) {
this.scanPackageNames = packageNames;
}
public void start() {
Platform platform = Platform.getInstance();
platform.setContext(context);
if (remotingTransport == null)
remotingTransport = Platform.getInstance().newRemotingTransport();
defaultChannelType = Platform.getInstance().defaultChannelType();
if (messagingTransport == null) {
messagingTransport = Platform.getInstance().newMessagingTransport();
if (messagingTransport == null)
messagingTransport = remotingTransport;
}
if (!messagingTransports.containsKey(defaultChannelType))
messagingTransports.put(defaultChannelType, messagingTransport);
for (Map.Entry<String, Transport> me : Platform.getInstance().getMessagingTransports().entrySet()) {
if (!messagingTransports.containsKey(me.getKey()))
messagingTransports.put(me.getKey(), me.getValue());
}
if (aliasRegistry == null)
aliasRegistry = new ClientAliasRegistry();
if (scanPackageNames != null)
aliasRegistry.scan(scanPackageNames);
}
public void stop() {
aliasRegistry = null;
stop(true);
}
public void stop(boolean stopTransports) {
if (stopTransports) {
if (remotingTransport != null && remotingTransport.isStarted()) {
remotingTransport.stop();
remotingTransport = null;
}
if (messagingTransport != null && messagingTransport.isStarted()) {
messagingTransport.stop();
messagingTransport = null;
}
for (Transport transport : messagingTransports.values()) {
if (transport.isStarted())
transport.stop();
}
messagingTransports.clear();
}
}
@Override
public RemotingChannel newRemotingChannel(String id, String uri) {
return newRemotingChannel(id, uri, RemotingChannel.DEFAULT_MAX_CONCURRENT_REQUESTS);
}
@Override
public RemotingChannel newRemotingChannel(String id, URI uri) {
return newRemotingChannel(id, uri, RemotingChannel.DEFAULT_MAX_CONCURRENT_REQUESTS);
}
@Override
public RemotingChannel newRemotingChannel(String id, ServerApp serverApp) {
return newRemotingChannel(id, serverApp, RemotingChannel.DEFAULT_MAX_CONCURRENT_REQUESTS);
}
@Override
public RemotingChannel newRemotingChannel(String id, String uri, int maxConcurrentRequests) {
try {
return newRemotingChannel(id, new URI(uri), maxConcurrentRequests);
}
catch (URISyntaxException e) {
throw new IllegalArgumentException("Bad uri: " + uri, e);
}
}
@Override
public RemotingChannel newRemotingChannel(String id, URI uri, int maxConcurrentRequests) {
if (getRemotingTransport() == null)
throw new RuntimeException("Remoting transport not defined, start the ChannelFactory first");
if (!getRemotingTransport().isStarted() && !getRemotingTransport().start())
throw new TransportException("Could not start remoting transport: " + getRemotingTransport());
RemotingChannel channel = defaultChannelBuilder.buildRemotingChannel(getRemotingChannelClass(), id, uri, maxConcurrentRequests, getRemotingTransport(), newMessagingCodec(AMF0Message.class));
if (defaultTimeToLive != null)
channel.setDefaultTimeToLive(defaultTimeToLive);
return channel;
}
@Override
public RemotingChannel newRemotingChannel(String id, ServerApp serverApp, int maxConcurrentRequests) {
if (getRemotingTransport() == null)
throw new RuntimeException("Remoting transport not defined, start the ChannelFactory first");
if (!getRemotingTransport().isStarted() && !getRemotingTransport().start())
throw new TransportException("Could not start remoting transport: " + getRemotingTransport());
RemotingChannel channel = defaultChannelBuilder.buildRemotingChannel(getRemotingChannelClass(), id, serverApp, maxConcurrentRequests, getRemotingTransport(), newMessagingCodec(AMF0Message.class));
if (defaultTimeToLive != null)
channel.setDefaultTimeToLive(defaultTimeToLive);
return channel;
}
protected abstract Class<? extends RemotingChannel> getRemotingChannelClass();
@Override
public MessagingChannel newMessagingChannel(String id, String uri) {
return newMessagingChannel(defaultChannelType, id, uri);
}
@Override
public MessagingChannel newMessagingChannel(String id, URI uri) {
return newMessagingChannel(defaultChannelType, id, uri);
}
@Override
public MessagingChannel newMessagingChannel(String id, ServerApp serverApp) {
return newMessagingChannel(defaultChannelType, id, serverApp);
}
@Override
public MessagingChannel newMessagingChannel(String channelType, String id, String uri) {
try {
return newMessagingChannel(channelType, id, new URI(uri));
}
catch (URISyntaxException e) {
throw new IllegalArgumentException("Bad uri: " + uri, e);
}
}
@Override
public MessagingChannel newMessagingChannel(String channelType, String id, URI uri) {
Transport transport = getMessagingTransport(channelType);
if (transport == null)
throw new RuntimeException("No transport defined for channel type " + channelType + ", start the ChannelFactory first");
if (!transport.isStarted() && !transport.start())
throw new TransportException("Could not start messaging transport: " + transport);
MessagingCodec<Message[]> codec = newMessagingCodec(Message[].class);
for (ChannelBuilder builder : ServiceLoader.load(ChannelBuilder.class)) {
MessagingChannel channel = builder.buildMessagingChannel(channelType, id, uri, transport, codec);
if (channel != null) {
if (defaultTimeToLive != null)
channel.setDefaultTimeToLive(defaultTimeToLive);
if (defaultMaxReconnectAttempts != null)
channel.setDefaultMaxReconnectAttempts(defaultMaxReconnectAttempts);
return channel;
}
}
MessagingChannel channel = defaultChannelBuilder.buildMessagingChannel(channelType, id, uri, transport, codec);
if (channel == null)
throw new RuntimeException("Could not build channel for type " + channelType + " and uri " + uri);
if (defaultTimeToLive != null)
channel.setDefaultTimeToLive(defaultTimeToLive);
if (defaultMaxReconnectAttempts != null)
channel.setDefaultMaxReconnectAttempts(defaultMaxReconnectAttempts);
return channel;
}
@Override
public MessagingChannel newMessagingChannel(String channelType, String id, ServerApp serverApp) {
Transport transport = getMessagingTransport(channelType);
if (transport == null)
throw new RuntimeException("No transport defined for channel type " + channelType + ", start the ChannelFactory first");
if (!transport.isStarted() && !transport.start())
throw new TransportException("Could not start messaging transport: " + transport);
MessagingCodec<Message[]> codec = newMessagingCodec(Message[].class);
for (ChannelBuilder builder : ServiceLoader.load(ChannelBuilder.class)) {
MessagingChannel channel = builder.buildMessagingChannel(channelType, id, serverApp, transport, codec);
if (channel != null) {
if (defaultTimeToLive != null)
channel.setDefaultTimeToLive(defaultTimeToLive);
if (defaultMaxReconnectAttempts != null)
channel.setDefaultMaxReconnectAttempts(defaultMaxReconnectAttempts);
return channel;
}
}
MessagingChannel channel = defaultChannelBuilder.buildMessagingChannel(channelType, id, serverApp, transport, codec);
if (channel == null)
throw new RuntimeException("Could not build channel for type " + channelType + " and server " + serverApp.getServerName());
if (defaultTimeToLive != null)
channel.setDefaultTimeToLive(defaultTimeToLive);
if (defaultMaxReconnectAttempts != null)
channel.setDefaultMaxReconnectAttempts(defaultMaxReconnectAttempts);
return channel;
}
protected abstract <M> MessagingCodec<M> newMessagingCodec(Class<M> messageClass);
}