/**
* Copyright 2012 José Martínez
*
* Licensed 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 es.udc.pfc.xmpp.component;
import static com.google.common.base.Preconditions.checkNotNull;
import java.net.SocketAddress;
import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.jboss.netty.handler.execution.ExecutionHandler;
import org.jboss.netty.handler.execution.OrderedMemoryAwareThreadPoolExecutor;
import org.jboss.netty.util.CharsetUtil;
import com.google.common.util.concurrent.AbstractExecutionThreadService;
import es.udc.pfc.xmpp.handler.XEP0114Decoder;
import es.udc.pfc.xmpp.handler.XMLElementDecoder;
import es.udc.pfc.xmpp.handler.XMLFrameDecoder;
import es.udc.pfc.xmpp.handler.XMPPStreamHandler;
import es.udc.pfc.xmpp.stanza.JID;
public class ComponentService extends AbstractExecutionThreadService {
private final XMPPComponent component;
private final SocketAddress serverAddress;
private final String xmppHost;
private final String xmppSecret;
private ExecutionHandler executionHandler;
private ClientBootstrap bootstrap;
private Channel channel;
public ComponentService(XMPPComponent component, SocketAddress serverAddress, String xmppHost, String xmppSecret) {
this.component = checkNotNull(component);
this.serverAddress = checkNotNull(serverAddress);
this.xmppHost = checkNotNull(xmppHost);
this.xmppSecret = checkNotNull(xmppSecret);
}
@Override
protected void startUp() throws Exception {
executionHandler = new ExecutionHandler(new OrderedMemoryAwareThreadPoolExecutor(4, 0, 0));
bootstrap = new ClientBootstrap(new NioClientSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool()));
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
@Override
public ChannelPipeline getPipeline() throws Exception {
final ChannelPipeline pipeline = Channels.pipeline();
//pipeline.addLast("logger", new LoggingHandler(InternalLogLevel.INFO));
pipeline.addLast("xmlFramer", new XMLFrameDecoder());
pipeline.addLast("xmlDecoder", new XMLElementDecoder());
pipeline.addLast("xmppDecoder", new XEP0114Decoder(xmppHost, xmppSecret));
pipeline.addLast("executor", executionHandler);
pipeline.addLast("xmppHandler", new XMPPStreamHandler(component));
return pipeline;
}
});
final ChannelFuture future = bootstrap.connect(serverAddress).await();
if (!future.isSuccess()) {
bootstrap.releaseExternalResources();
executionHandler.releaseExternalResources();
future.rethrowIfFailed();
}
channel = future.getChannel();
component.init(channel, JID.jid("localhost"), JID.jid(xmppHost)); // FIXME
}
@Override
protected void run() throws Exception {
channel.getCloseFuture().awaitUninterruptibly().rethrowIfFailed();
}
@Override
protected void shutDown() throws Exception {
bootstrap.releaseExternalResources();
executionHandler.releaseExternalResources();
}
@Override
protected void triggerShutdown() {
if (channel != null && channel.isConnected()) {
Channels.disconnect(channel);
}
}
public final void send(final String data) {
checkNotNull(data);
if (channel != null && channel.isConnected()) {
Channels.write(channel, ChannelBuffers.copiedBuffer(data, CharsetUtil.UTF_8));
}
}
}