package com.tesora.dve.tools.libmy;
/*
* #%L
* Tesora Inc.
* Database Virtualization Engine
* %%
* Copyright (C) 2011 - 2014 Tesora Inc.
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPromise;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.CharsetUtil;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import com.tesora.dve.db.mysql.MyFieldType;
import com.tesora.dve.db.mysql.common.JavaCharsetCatalog;
import com.tesora.dve.db.mysql.common.SimpleCredentials;
import com.tesora.dve.db.mysql.libmy.MyFieldPktResponse;
import com.tesora.dve.db.mysql.libmy.MyTextResultRow;
import com.tesora.dve.db.mysql.portal.protocol.ClientCapabilities;
import com.tesora.dve.db.mysql.portal.protocol.MSPComQueryRequestMessage;
import com.tesora.dve.db.mysql.portal.protocol.MSPComQuitRequestMessage;
import com.tesora.dve.db.mysql.portal.protocol.MyBackendDecoder;
import com.tesora.dve.db.mysql.portal.protocol.MysqlClientAuthenticationHandler;
public class AsyncExample {
public static void main(String[] args) throws Exception {
final String mysqlHost = "localhost";
final int mysqlPort = 3307;
final String username = "root";
final String password = "password";
final boolean isClearText = true;
final InetSocketAddress serverAddress = new InetSocketAddress(mysqlHost, mysqlPort);
final MyBackendDecoder.CharsetDecodeHelper charsetHelper = constructCharsetDecodeHelper();
final SimpleCredentials cred = constructCredentials(username, password, isClearText);
final JavaCharsetCatalog javaCharsetCatalog = constructJavaCharsetCatalog();
final MysqlClientAuthenticationHandler authHandler = new MysqlClientAuthenticationHandler(cred, ClientCapabilities.DEFAULT_PSITE_CAPABILITIES, javaCharsetCatalog, new AtomicReference<Charset>());
final NioEventLoopGroup connectionEventGroup = new NioEventLoopGroup(1);
final Bootstrap mysqlBootstrap = new Bootstrap();
mysqlBootstrap // .group(inboundChannel.eventLoop())
.channel(NioSocketChannel.class)
.group(connectionEventGroup)
.option(ChannelOption.ALLOCATOR, UnpooledByteBufAllocator.DEFAULT)
.handler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) throws Exception {
ch.pipeline()
.addLast(authHandler)
.addLast(MyBackendDecoder.class.getSimpleName(), new MyBackendDecoder(charsetHelper))
.addLast(new ChannelDuplexHandler() {
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
System.out.println("WRITE:" + msg);
super.write(ctx, msg, promise);
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof MyFieldPktResponse) {
final MyFieldPktResponse myFieldPktResponse = (MyFieldPktResponse) msg;
System.out.println("COLUMN: " + myFieldPktResponse.getOrig_column() + "," + myFieldPktResponse.getColumn_type());
} else if (msg instanceof MyTextResultRow) {
final StringBuilder builder = new StringBuilder();
builder.append("ROW:");
final MyTextResultRow textRow = (MyTextResultRow) msg;
for (int i = 0; i < textRow.size(); i++) {
builder.append('\t');
builder.append(textRow.getString(i));
}
System.out.println(builder.toString());
}
super.channelRead(ctx, msg);
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
super.channelInactive(ctx);
System.out.println("CLOSE. ");
}
});
}
});
final ChannelFuture connectFut = mysqlBootstrap.connect(serverAddress);
connectFut.sync();
System.out.println("Waiting to finish authenticate handshake");
authHandler.assertAuthenticated();//don't write a request until you know the login is complete.
System.out.println("Connected, and authenticated, getting channel to write requests");
final Channel chan = connectFut.channel();
System.out.println("Sending two pipelined requests without blocking for first response.");
chan.write(MSPComQueryRequestMessage.newMessage("show databases", CharsetUtil.UTF_8));
chan.write(MSPComQueryRequestMessage.newMessage("select * from information_schema.tables", CharsetUtil.UTF_8));
chan.flush();//NOTE: nothing is sent until this is called. Use writeAndFlush if you want it to go out immediately.
System.out.println("Sleeping 5 sec so all results come back"); //normally you would sync to responses here.
TimeUnit.SECONDS.sleep(5);
System.out.println("Closing socket.");
chan.writeAndFlush(MSPComQuitRequestMessage.newMessage());//send friendly hangup message. Probably correct to also wait for server close or an OK packet.
chan.close();
chan.closeFuture().sync();
System.out.println("Exiting.");
System.exit(0);
}
protected static JavaCharsetCatalog constructJavaCharsetCatalog() {
return new JavaCharsetCatalog() {
@Override
public Charset findJavaCharsetById(int clientCharsetId) {
if (clientCharsetId == 33) {
return CharsetUtil.UTF_8;
} else if (clientCharsetId == 8) {
return CharsetUtil.ISO_8859_1;
} else {
return null;
}
}
};
}
protected static SimpleCredentials constructCredentials(final String username, final String password, final boolean isClearText) {
return new SimpleCredentials() {
@Override
public String getName() {
return username;
}
@Override
public String getPassword() {
return password;
}
@Override
public boolean isCleartext() {
return isClearText;
}
};
}
protected static MyBackendDecoder.CharsetDecodeHelper constructCharsetDecodeHelper() {
return new MyBackendDecoder.CharsetDecodeHelper() {
@Override
public long lookupMaxLength(byte mysqlCharsetID) {
if (mysqlCharsetID == 33) {
return 3;
} else if (mysqlCharsetID == 8) {
return 1;
} else {
return -1;
}
}
@Override
public boolean typeSupported(MyFieldType fieldType, short flags, int maxDataLen) {
return true;
}
};
}
}