com.baidu.rigel.biplatform.tesseract.node.service.IndexAndSearchClient.java Source code

Java tutorial

Introduction

Here is the source code for com.baidu.rigel.biplatform.tesseract.node.service.IndexAndSearchClient.java

Source

/**
 * Copyright (c) 2014 Baidu, Inc. All Rights Reserved.
 *
 * 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 com.baidu.rigel.biplatform.tesseract.node.service;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.concurrent.ConcurrentHashMap;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import com.baidu.rigel.biplatform.tesseract.isservice.exception.IndexAndSearchException;
import com.baidu.rigel.biplatform.tesseract.isservice.exception.IndexAndSearchExceptionType;
import com.baidu.rigel.biplatform.tesseract.isservice.meta.IndexShard;
import com.baidu.rigel.biplatform.tesseract.isservice.netty.service.FileClientHandler;
import com.baidu.rigel.biplatform.tesseract.isservice.netty.service.IndexClientHandler;
import com.baidu.rigel.biplatform.tesseract.isservice.netty.service.SearchClientHandler;
import com.baidu.rigel.biplatform.tesseract.netty.AbstractChannelInboundHandler;
import com.baidu.rigel.biplatform.tesseract.netty.exception.HandlerRegistException;
import com.baidu.rigel.biplatform.tesseract.netty.message.AbstractMessage;
import com.baidu.rigel.biplatform.tesseract.netty.message.MessageHeader;
import com.baidu.rigel.biplatform.tesseract.netty.message.NettyAction;
import com.baidu.rigel.biplatform.tesseract.netty.message.isservice.IndexMessage;
import com.baidu.rigel.biplatform.tesseract.netty.message.isservice.SearchRequestMessage;
import com.baidu.rigel.biplatform.tesseract.netty.message.isservice.SearchResultMessage;
import com.baidu.rigel.biplatform.tesseract.netty.message.isservice.SendFileMessage;
import com.baidu.rigel.biplatform.tesseract.netty.message.isservice.ServerExceptionMessage;
import com.baidu.rigel.biplatform.tesseract.netty.message.isservice.ServerFeedbackMessage;
import com.baidu.rigel.biplatform.tesseract.node.meta.Node;
import com.baidu.rigel.biplatform.tesseract.qsservice.query.vo.QueryRequest;
import com.baidu.rigel.biplatform.tesseract.resultset.TesseractResultSet;
import com.baidu.rigel.biplatform.tesseract.util.FileUtils;
import com.baidu.rigel.biplatform.tesseract.util.IndexFileSystemConstants;
import com.baidu.rigel.biplatform.tesseract.util.TesseractConstant;
import com.baidu.rigel.biplatform.tesseract.util.TesseractExceptionUtils;
import com.baidu.rigel.biplatform.tesseract.util.isservice.LogInfoConstants;

/**
 * IndexAndSearchClient spring??
 * 
 * @author lijin
 *
 */

public class IndexAndSearchClient {
    /**
     * logger
     */
    private Logger logger = LoggerFactory.getLogger(IndexAndSearchClient.class);

    /**
     * isNodeService
     */
    @Resource(name = "isNodeService")
    private IsNodeService isNodeService;

    /**
     * LOCAL_HOST_ADDRESS
     */
    private static final String LOCAL_HOST_ADDRESS = "127.0.0.1";

    // private ConcurrentHashMap<NodeAddress, Channel> channelMaps;
    private ConcurrentHashMap<String, ChannelHandler> actionHandlerMaps;
    private Bootstrap b;
    private EventLoopGroup group;

    private static IndexAndSearchClient INSTANCE;

    public IndexAndSearchClient() {
        // channelMaps = new ConcurrentHashMap<NodeAddress, Channel>();
        actionHandlerMaps = new ConcurrentHashMap<String, ChannelHandler>();
        b = new Bootstrap();
        group = new NioEventLoopGroup();
        b.group(group);
        b.channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true);
        b.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000);
        b.handler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel ch) throws Exception {
                ChannelPipeline pipeline = ch.pipeline();
                pipeline.addLast("encode", new ObjectEncoder());
                pipeline.addLast("decode", new ObjectDecoder(ClassResolvers.weakCachingConcurrentResolver(null)));
                //                pipeline.addLast("frameencoder",new LengthFieldPrepender(4,false));
                //                pipeline.addLast("framedecoder",new LengthFieldBasedFrameDecoder(1024*1024*1024, 0, 4,0,4));
            }
        });

        logger.info("IndexAndSearchClient init finished");
    }

    public static synchronized IndexAndSearchClient getNodeClient() {
        if (INSTANCE == null) {
            INSTANCE = new IndexAndSearchClient();
        }
        return INSTANCE;
    }

    public class NodeAddress {
        private String ip;
        private int port;

        /**
         * @param ip
         * @param port
         */
        public NodeAddress(String ip, int port) {
            super();
            this.ip = ip;
            this.port = port;
        }

        /**
         * getter method for property ip
         * 
         * @return the ip
         */
        public String getIp() {
            return ip;
        }

        /**
         * setter method for property ip
         * 
         * @param ip
         *            the ip to set
         */
        public void setIp(String ip) {
            this.ip = ip;
        }

        /**
         * getter method for property port
         * 
         * @return the port
         */
        public int getPort() {
            return port;
        }

        /**
         * setter method for property port
         * 
         * @param port
         *            the port to set
         */
        public void setPort(int port) {
            this.port = port;
        }

        /*
         * (non-Javadoc)
         * 
         * @see java.lang.Object#hashCode()
         */
        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + getOuterType().hashCode();
            result = prime * result + ((ip == null) ? 0 : ip.hashCode());
            result = prime * result + port;
            return result;
        }

        /*
         * (non-Javadoc)
         * 
         * @see java.lang.Object#equals(java.lang.Object)
         */
        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (obj == null) {
                return false;
            }
            if (!(obj instanceof NodeAddress)) {
                return false;
            }
            NodeAddress other = (NodeAddress) obj;
            if (!getOuterType().equals(other.getOuterType())) {
                return false;
            }
            if (ip == null) {
                if (other.ip != null) {
                    return false;
                }
            } else if (!ip.equals(other.ip)) {
                return false;
            }
            if (port != other.port) {
                return false;
            }
            return true;
        }

        private IndexAndSearchClient getOuterType() {
            return IndexAndSearchClient.this;
        }

        /*
         * (non-Javadoc)
         * 
         * @see java.lang.Object#toString()
         */
        @Override
        public String toString() {
            return "NodeAddress [ip=" + ip + ", port=" + port + "]";
        }

    }

    public ChannelHandler getActionHandler(String actionMove) {
        logger.info("getActionHandler:[actionMove=" + actionMove + "]");
        if (!StringUtils.isEmpty(actionMove) && this.actionHandlerMaps.containsKey(actionMove)) {
            return this.actionHandlerMaps.get(actionMove);
        }
        logger.info("getActionHandler:[actionMove=" + actionMove + "] has no handler");
        return null;
    }

    private boolean registerActionHandler(NettyAction nettyAction, AbstractChannelInboundHandler handler)
            throws InstantiationException, IllegalAccessException {
        logger.info("registerActionHandler:[NettyAction=" + nettyAction + "][handler=" + handler + "] start");
        if (nettyAction == null || handler == null) {
            return false;
        }
        this.actionHandlerMaps.put(nettyAction.getActionName(), handler);
        logger.info("registerActionHandler:[NettyAction=" + nettyAction + "][handler=" + handler + "] success");
        return true;
    }

    public Channel getChannelByAddressAndPort(String ipAddress, int port) throws IndexAndSearchException {
        logger.info("getChannelByAddressAndPort:[address=" + ipAddress + "][port=" + port + "] start");
        if (StringUtils.isEmpty(ipAddress) || port <= 0) {
            throw new IndexAndSearchException(
                    TesseractExceptionUtils.getExceptionMessage(IndexAndSearchException.INDEXEXCEPTION_MESSAGE,
                            IndexAndSearchExceptionType.ILLEGALARGUMENT_EXCEPTION),
                    IndexAndSearchExceptionType.ILLEGALARGUMENT_EXCEPTION);
        }
        Channel channel = null;
        // NodeAddress nodeAddr = new NodeAddress(address, port);
        String address = ipAddress;
        try {
            InetAddress currAddress = InetAddress.getLocalHost();

            if (ipAddress.equals(currAddress.getHostAddress())) {
                address = LOCAL_HOST_ADDRESS;
            }
            if (b != null) {
                channel = b.connect(address, port).sync().channel();
                // this.channelMaps.put(nodeAddr, channel);
                logger.info("getChannelByAddressAndPort:connect server success [address=" + address + "][port="
                        + port + "]");
            }

        } catch (Exception e) {
            logger.error("getChannelByAddressAndPort:connect server [address=" + address + "][port=" + port
                    + "] exception.", e);
            throw new IndexAndSearchException(
                    TesseractExceptionUtils.getExceptionMessage(IndexAndSearchException.INDEXEXCEPTION_MESSAGE,
                            IndexAndSearchExceptionType.INDEX_EXCEPTION),
                    e, IndexAndSearchExceptionType.INDEX_EXCEPTION);
        }

        logger.info("getChannelByAddressAndPort:[address=" + address + "][port=" + port + "] connect sucess");
        return channel;

    }

    public IndexMessage index(TesseractResultSet data, boolean isInit, boolean isUpdate, IndexShard idxShard,
            String idName, boolean lastPiece) throws IndexAndSearchException {
        logger.info("index:[data=" + data + "][isUpdate=" + isUpdate + "][idxShard=" + idxShard + "][idName:"
                + idName + "] start");
        if (data == null || idxShard == null || StringUtils.isEmpty(idxShard.getFilePath())
                || StringUtils.isEmpty(idxShard.getIdxFilePath())) {
            throw new IndexAndSearchException(
                    TesseractExceptionUtils.getExceptionMessage(IndexAndSearchException.INDEXEXCEPTION_MESSAGE,
                            IndexAndSearchExceptionType.ILLEGALARGUMENT_EXCEPTION),
                    IndexAndSearchExceptionType.ILLEGALARGUMENT_EXCEPTION);
        }

        NettyAction action = null;
        if (isUpdate) {
            action = NettyAction.NETTY_ACTION_UPDATE;
        } else if (isInit) {
            action = NettyAction.NETTY_ACTION_INITINDEX;
        } else {
            action = NettyAction.NETTY_ACTION_INDEX;
        }
        MessageHeader messageHeader = new MessageHeader(action, data.toString());
        IndexMessage message = new IndexMessage(messageHeader, data);
        message.setIdxPath(idxShard.getAbsoluteFilePath());
        message.setIdxServicePath(idxShard.getAbsoluteIdxFilePath());
        message.setBlockSize(IndexFileSystemConstants.DEFAULT_INDEX_SHARD_SIZE);
        message.setIdName(idName);
        message.setLastPiece(lastPiece);
        //        List<String> measureInfoList = new ArrayList<String>();
        //        measureInfoList.addAll(idxShard.getIndexMeta().getMeasureInfoMap().keySet());
        //        message.setMeasureInfo(measureInfoList);
        logger.info("ready to send index message:" + message.toString());
        AbstractMessage ret = null;
        IndexMessage result = null;
        IndexClientHandler handler = new IndexClientHandler();
        try {
            ret = this.executeAction(action, message, handler, idxShard.getNode());
            if (ret instanceof IndexMessage) {
                result = (IndexMessage) ret;
            } else {
                throw new IndexAndSearchException(
                        TesseractExceptionUtils.getExceptionMessage(IndexAndSearchException.INDEXEXCEPTION_MESSAGE,
                                IndexAndSearchExceptionType.INDEX_EXCEPTION),
                        ((ServerExceptionMessage) ret).getCause(), IndexAndSearchExceptionType.INDEX_EXCEPTION);
            }
        } catch (Exception e) {
            throw new IndexAndSearchException(
                    TesseractExceptionUtils.getExceptionMessage(IndexAndSearchException.INDEXEXCEPTION_MESSAGE,
                            IndexAndSearchExceptionType.INDEX_EXCEPTION),
                    e.getCause(), IndexAndSearchExceptionType.INDEX_EXCEPTION);
        }
        logger.info(
                "index:[data=" + data + "][isUpdate=" + isUpdate + "][idxShard=" + idxShard + "] finished index ");
        return result;
    }

    public ServerFeedbackMessage copyIndexDataToRemoteNode(String filePath, String targetFilePath, boolean replace,
            Node node) throws IndexAndSearchException {
        logger.info(String.format(LogInfoConstants.INFO_PATTERN_FUNCTION_BEGIN, "copyIndexDataToRemoteNode",
                "[filePath:" + filePath + "][replace:" + replace + "][Node:" + node + "]"));

        if (StringUtils.isEmpty(filePath) || node == null) {
            logger.info(String.format(LogInfoConstants.INFO_PATTERN_FUNCTION_EXCEPTION, "copyIndexDataToRemoteNode",
                    "[filePath:" + filePath + "][replace:" + replace + "][nodeList:" + node + "]"));
            throw new IllegalArgumentException();
        }
        // 
        String compressedFilePath = filePath + ".tar.gz";
        File compressedFile = new File(compressedFilePath);
        compressedFile.deleteOnExit();

        try {
            compressedFilePath = FileUtils.doCompressFile(filePath);
        } catch (IOException e2) {
            throw new IndexAndSearchException(
                    TesseractExceptionUtils.getExceptionMessage(IndexAndSearchException.INDEXEXCEPTION_MESSAGE,
                            IndexAndSearchExceptionType.INDEX_EXCEPTION),
                    e2, IndexAndSearchExceptionType.INDEX_EXCEPTION);
        }

        // 
        File fin = new File(compressedFilePath);
        FileChannel fcin = null;
        try {
            fcin = new RandomAccessFile(fin, "r").getChannel();
        } catch (FileNotFoundException e1) {
            throw new IndexAndSearchException(
                    TesseractExceptionUtils.getExceptionMessage(IndexAndSearchException.INDEXEXCEPTION_MESSAGE,
                            IndexAndSearchExceptionType.INDEX_EXCEPTION),
                    e1, IndexAndSearchExceptionType.INDEX_EXCEPTION);
        }
        ByteBuffer rBuffer = ByteBuffer.allocate(TesseractConstant.FILE_BLOCK_SIZE);
        ServerFeedbackMessage backMessage = null;
        boolean isFirst = true;
        try {
            while (true) {
                rBuffer.clear();
                int r = fcin.read(rBuffer);

                if (r == -1) {
                    break;
                }
                boolean isLast = false;
                if (rBuffer.position() < rBuffer.capacity()) {
                    isLast = true;
                }
                rBuffer.flip();

                NettyAction action = NettyAction.NETTY_ACTION_COPYFILE;
                MessageHeader mh = new MessageHeader(action);
                SendFileMessage sfm = new SendFileMessage(mh, rBuffer.array(),
                        targetFilePath + File.separator + fin.getName());
                if (isFirst) {
                    sfm.setFirst(isFirst);
                } else {
                    sfm.setFirst(false);
                }

                sfm.setLast(isLast);

                FileClientHandler handler = new FileClientHandler();
                AbstractMessage bMessage = this.executeAction(action, sfm, handler, node);

                if (bMessage instanceof ServerFeedbackMessage) {
                    backMessage = (ServerFeedbackMessage) bMessage;
                } else {
                    throw new IndexAndSearchException(
                            TesseractExceptionUtils.getExceptionMessage(
                                    IndexAndSearchException.INDEXEXCEPTION_MESSAGE,
                                    IndexAndSearchExceptionType.INDEX_EXCEPTION),
                            ((ServerExceptionMessage) bMessage).getCause(),
                            IndexAndSearchExceptionType.INDEX_EXCEPTION);
                }

                if (backMessage == null
                        || backMessage.getResult().equals(TesseractConstant.FEED_BACK_MSG_RESULT_FAIL)) {
                    throw new IndexAndSearchException(
                            TesseractExceptionUtils.getExceptionMessage(
                                    IndexAndSearchException.INDEXEXCEPTION_MESSAGE,
                                    IndexAndSearchExceptionType.INDEX_EXCEPTION),
                            IndexAndSearchExceptionType.INDEX_EXCEPTION);
                }

            }
        } catch (Exception e) {
            throw new IndexAndSearchException(
                    TesseractExceptionUtils.getExceptionMessage(IndexAndSearchException.INDEXEXCEPTION_MESSAGE,
                            IndexAndSearchExceptionType.INDEX_EXCEPTION),
                    e.getCause(), IndexAndSearchExceptionType.INDEX_EXCEPTION);
        } finally {
            try {
                fcin.close();
            } catch (IOException e) {
                throw new IndexAndSearchException(
                        TesseractExceptionUtils.getExceptionMessage(IndexAndSearchException.INDEXEXCEPTION_MESSAGE,
                                IndexAndSearchExceptionType.INDEX_EXCEPTION),
                        e.getCause(), IndexAndSearchExceptionType.INDEX_EXCEPTION);
            }
        }
        return backMessage;
    }

    public SearchResultMessage search(QueryRequest query, IndexShard idxShard, Node searchNode)
            throws IndexAndSearchException {
        NettyAction action = NettyAction.NETTY_ACTION_SEARCH;

        MessageHeader messageHeader = new MessageHeader(action);

        SearchRequestMessage message = new SearchRequestMessage(messageHeader, query);
        message.setIdxPath(idxShard.getAbsoluteIdxFilePath(searchNode));

        AbstractMessage ret = null;

        SearchClientHandler handler = new SearchClientHandler();
        SearchResultMessage result = null;

        try {
            ret = this.executeAction(action, message, handler, searchNode);
            if (ret instanceof SearchResultMessage) {
                result = (SearchResultMessage) ret;
            } else {
                throw new IndexAndSearchException(
                        TesseractExceptionUtils.getExceptionMessage(IndexAndSearchException.QUERYEXCEPTION_MESSAGE,
                                IndexAndSearchExceptionType.SEARCH_EXCEPTION),
                        ((ServerExceptionMessage) ret).getCause(), IndexAndSearchExceptionType.SEARCH_EXCEPTION);
            }
        } catch (Exception e) {
            throw new IndexAndSearchException(
                    TesseractExceptionUtils.getExceptionMessage(IndexAndSearchException.QUERYEXCEPTION_MESSAGE,
                            IndexAndSearchExceptionType.SEARCH_EXCEPTION),
                    e.getCause(), IndexAndSearchExceptionType.SEARCH_EXCEPTION);
        }

        return result;
    }

    public <T extends AbstractMessage, R extends AbstractMessage, S extends AbstractChannelInboundHandler> T executeAction(
            NettyAction action, R message, S handler, Node node) throws Exception {
        logger.info("executeAction:[NettyAction=" + action + "][Message=" + message + "][Handler=" + handler + "]");
        T returnMessage = null;
        if (action == null || handler == null) {
            logger.info("executeAction:[NettyAction=" + action + "][Message=" + message + "][Handler=" + handler
                    + "]-Exception:IllegalArgumentException");
            throw new IllegalArgumentException();
        }
        if (!registerActionHandler(action, handler)) {
            logger.info("executeAction-Exception:HandlerRegistException");
            throw new HandlerRegistException();
        }
        Channel channel = null;
        channel = this.getChannelByAddressAndPort(node.getAddress(), node.getPort());
        channel.pipeline().addLast(handler);

        channel.writeAndFlush(message);
        channel.closeFuture().sync();
        returnMessage = handler.getMessage();
        logger.info("executeAction:[NettyAction=" + action + "][Message=" + message + "][Handler=" + handler
                + "] success");

        return returnMessage;

    }

    public void shutDown() {

        if (this.actionHandlerMaps != null && !this.actionHandlerMaps.isEmpty()) {
            this.actionHandlerMaps.clear();
        }
        this.b.group().shutdownGracefully();
    }

    public ConcurrentHashMap<String, ChannelHandler> getActionHandlerMaps() {
        if (this.actionHandlerMaps == null) {
            this.actionHandlerMaps = new ConcurrentHashMap<String, ChannelHandler>();
        }
        return actionHandlerMaps;
    }

}