Package com.odiago.flumebase.client

Source Code of com.odiago.flumebase.client.ThriftClientEnvironment

/**
* Licensed to Odiago, Inc. under one or more contributor license
* agreements.  See the NOTICE.txt file distributed with this work for
* additional information regarding copyright ownership.  Odiago, Inc.
* licenses this file to you 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.odiago.flumebase.client;

import java.io.IOException;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.apache.hadoop.conf.Configuration;

import org.apache.thrift.TException;
import org.apache.thrift.TProcessor;

import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.protocol.TProtocolFactory;

import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TSimpleServer;

import org.apache.thrift.transport.TFramedTransport;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TServerTransport;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import org.apache.thrift.transport.TTransportException;
import org.apache.thrift.transport.TTransportFactory;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.odiago.flumebase.exec.ExecEnvironment;
import com.odiago.flumebase.exec.FlowId;
import com.odiago.flumebase.exec.FlowInfo;
import com.odiago.flumebase.exec.QuerySubmitResponse;

import com.odiago.flumebase.plan.FlowSpecification;

import com.odiago.flumebase.server.SessionId;

import com.odiago.flumebase.thrift.CallbackConnectionError;
import com.odiago.flumebase.thrift.ClientConsole;
import com.odiago.flumebase.thrift.RemoteServer;
import com.odiago.flumebase.thrift.TFlowId;
import com.odiago.flumebase.thrift.TFlowInfo;

import com.odiago.flumebase.util.NetUtils;

/**
* Execution environment that proxies all client requests to a server
* via a thrift protocol.
*/
public class ThriftClientEnvironment extends ExecEnvironment {
  private static final Logger LOG = LoggerFactory.getLogger(
      ThriftClientEnvironment.class.getName());

  // Allow up to 100 clients from this same server; this is the number
  // of ports we will try to listen on locally, before giving up.
  private static final int MAX_PORTS_TO_TRY = 100;

  private Configuration mConf;

  /** Remote host to connect to. */
  private String mHost;

  /** Remote port to connect to. */
  private int mPort;

  /** The socket connection for the RPC. */
  private TTransport mTransport;

  /** The service stub endpoint we interact with. */
  private RemoteServer.Client mClient;

  /** id associated with the connection to our session. */
  private SessionId mSessionId;

  /** The TServer hosting the ClientConsole callback service. */
  private TServer mConsoleServer;

  public ThriftClientEnvironment(Configuration conf, String host, int port)  {
    mConf = conf;
    mHost = host;
    mPort = port;
  }

  @Override
  public SessionId connect() throws IOException {
    try {
      // Establish the connection to the server.
      LOG.debug("Connecting to remote server.");
      mTransport = new TFramedTransport(new TSocket(mHost, mPort));
      mTransport.open();

      TProtocol protocol = new TBinaryProtocol(mTransport);
      mClient = new RemoteServer.Client(protocol);

      String consoleHost = null;
      int consolePort = 0;
      try {
        // Start our own server hosting the ClientConsole service, so
        // the server can send us back results.
        ClientConsoleImpl consoleImpl = new ClientConsoleImpl();
        consolePort = mConf.getInt(ClientConsoleImpl.CONSOLE_SERVER_PORT_KEY,
            ClientConsoleImpl.DEFAULT_CONSOLE_SERVER_PORT);
        TServerTransport consoleTransport = null;
        int triesRemaining = MAX_PORTS_TO_TRY;
        while (triesRemaining > 0) {
          LOG.debug("Trying to start ClientConsole service on port " + consolePort);
          try {
            consoleTransport = new TServerSocket(consolePort);
            break; // On successful bind, abort the loop.
          } catch (TTransportException tte) {
            // Couldn't create a socket on this port. Try the next port.
            consolePort++;
            triesRemaining--;
          }
        }

        if (null == consoleTransport) {
          throw new IOException("Could not create ServerSocket to listen for callback");
        }

        TTransportFactory transportFactory = new TFramedTransport.Factory();
        TProtocolFactory protocolFactory = new TBinaryProtocol.Factory();
        TProcessor processor = new ClientConsole.Processor(consoleImpl);
        mConsoleServer = new TSimpleServer(processor, consoleTransport, transportFactory,
            protocolFactory);

        // TODO: Is this technically a race? The Thread.start() method returns
        // when the thread is switched to RUNNING, but there is an arbitrary
        // amount of time before serve() kicks in. TServer does not have any
        // isRunning() equivalent to join on, so we don't know if it's really
        // ready or not.
        LOG.debug("Starting server thread");
        Thread consoleThread = new Thread() {
          public void run() {
            mConsoleServer.serve();
          }
        };
        consoleThread.setDaemon(true);
        consoleThread.start();

        // Tell the server to connect back to us.
        consoleHost = NetUtils.getHostName();
        mSessionId = SessionId.fromThrift(
            mClient.createSession(consoleHost, (short) consolePort));
      } catch (CallbackConnectionError cce) {
        LOG.error("Server could not connect to our console hosted at "
            + consoleHost + ":" + consolePort);
        LOG.error("Flows may be submitted, but results cannot be viewed.");
        if (null != mConsoleServer) {
          // Stop the console server since the server can't connect to it.
          mConsoleServer.stop();
        }
      }
    } catch (TException e) {
      mTransport = null;
      mClient = null;
      throw new IOException(e);
    }

    return mSessionId;
  }

  @Override
  public boolean isConnected() {
    return mTransport.isOpen();
  }

  @Override
  public String getEnvName() {
    return "thriftClient";
  }

  @Override
  public QuerySubmitResponse submitQuery(String query, Map<String, String> options)
      throws IOException {
    try {
      return QuerySubmitResponse.fromThrift(mClient.submitQuery(query, options));
    } catch (TException te) {
      throw new IOException(te);
    }
  }

  @Override
  public FlowId addFlow(FlowSpecification spec) throws IOException {
    LOG.error("Raw addFlow() is an unsupported operation in ThriftClientEnvironment.");
    return null;
  }

  @Override
  public void cancelFlow(FlowId id) throws IOException {
    try {
      mClient.cancelFlow(id.toThrift());
    } catch (TException te) {
      throw new IOException(te);
    }
  }

  @Override
  public Map<FlowId, FlowInfo> listFlows() throws IOException {
    try {
      Map<TFlowId, TFlowInfo> flows = mClient.listFlows();
      Map<FlowId, FlowInfo> out = new TreeMap<FlowId, FlowInfo>();

      for (Map.Entry<TFlowId, TFlowInfo> entry : flows.entrySet()) {
        out.put(FlowId.fromThrift(entry.getKey()), FlowInfo.fromThrift(entry.getValue()));
      }

      return out;
    } catch (TException te) {
      throw new IOException(te);
    }
  }

  @Override
  public void joinFlow(FlowId id) throws IOException {
    try {
      mClient.joinFlow(id.toThrift(), 0);
    } catch (TException te) {
      throw new IOException(te);
    }
  }

  @Override
  public boolean joinFlow(FlowId id, long timeout) throws IOException {
    try {
      return mClient.joinFlow(id.toThrift(), timeout);
    } catch (TException te) {
      throw new IOException(te);
    }
  }

  @Override
  public void watchFlow(SessionId sessionId, FlowId flowId) throws IOException {
    try {
      mClient.watchFlow(sessionId.toThrift(), flowId.toThrift());
    } catch (TException te) {
      throw new IOException(te);
    }
  }

  @Override
  public void unwatchFlow(SessionId sessionId, FlowId flowId) throws IOException {
    try {
      mClient.unwatchFlow(sessionId.toThrift(), flowId.toThrift());
    } catch (TException te) {
      throw new IOException(te);
    }
  }

  @Override
  public List<FlowId> listWatchedFlows(SessionId sessionId) throws IOException {
    try {
      List<TFlowId> flowList = mClient.listWatchedFlows(sessionId.toThrift());
      List<FlowId> outList = new ArrayList<FlowId>();
      for (TFlowId tFlowId : flowList) {
        outList.add(FlowId.fromThrift(tFlowId));
      }
      return outList;
    } catch (TException te) {
      throw new IOException(te);
    }
  }

  @Override
  public void setFlowName(FlowId flowId, String name) throws IOException {
    try {
      mClient.setFlowName(flowId.toThrift(), name);
    } catch (TException te) {
      throw new IOException(te);
    }
  }

  @Override
  public void disconnect(SessionId sessionId) throws IOException {
    try {
      mClient.closeSession(sessionId.toThrift());
    } catch (TException te) {
      LOG.error("Exception during disconnect calling closeSession(): " + te);
      // Continue with disconnect process even in the face of an error.
    }

    mTransport.close();
    mClient = null;
  }

  @Override
  public void shutdown() throws IOException {
    try {
      mClient.shutdown();
    } catch (TException te) {
      throw new IOException(te);
    }

    mTransport.close();
    mClient = null;
  }
}
TOP

Related Classes of com.odiago.flumebase.client.ThriftClientEnvironment

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.