Package org.apache.avro.ipc

Source Code of org.apache.avro.ipc.Responder

/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF 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 org.apache.avro.ipc;

import java.io.IOException;
import java.nio.ByteBuffer;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;

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

import org.apache.avro.AvroRuntimeException;
import org.apache.avro.Protocol;
import org.apache.avro.Schema;
import org.apache.avro.Protocol.Message;
import org.apache.avro.util.Utf8;
import org.apache.avro.generic.GenericDatumReader;
import org.apache.avro.generic.GenericDatumWriter;
import org.apache.avro.io.BinaryDecoder;
import org.apache.avro.io.BinaryEncoder;
import org.apache.avro.io.Decoder;
import org.apache.avro.io.Encoder;
import org.apache.avro.specific.SpecificDatumReader;
import org.apache.avro.specific.SpecificDatumWriter;

/** Base class for the server side of a protocol interaction. */
public abstract class Responder {
  private static final Logger LOG = LoggerFactory.getLogger(Responder.class);

  private static final Schema META =
    Schema.createMap(Schema.create(Schema.Type.BYTES));
  private static final GenericDatumReader<Map<Utf8,ByteBuffer>> META_READER =
    new GenericDatumReader<Map<Utf8,ByteBuffer>>(META);
  private static final GenericDatumWriter<Map<Utf8,ByteBuffer>> META_WRITER =
    new GenericDatumWriter<Map<Utf8,ByteBuffer>>(META);

  private Map<Transceiver,Protocol> remotes
    = Collections.synchronizedMap(new WeakHashMap<Transceiver,Protocol>());
  private Map<MD5,Protocol> protocols
    = Collections.synchronizedMap(new HashMap<MD5,Protocol>());

  private Protocol local;
  private MD5 localHash;
  protected List<RPCPlugin> rpcMetaPlugins;

  protected Responder(Protocol local) {
    this.local = local;
    this.localHash = new MD5();
    localHash.bytes(local.getMD5());
    protocols.put(localHash, local);
    this.rpcMetaPlugins =
      Collections.synchronizedList(new ArrayList<RPCPlugin>());
  }

  public Protocol getLocal() { return local; }
 
  /**
   * Adds a new plugin to manipulate per-call metadata.  Plugins
   * are executed in the order that they are added.
   * @param plugin a plugin that will manipulate RPC metadata
   */
  public void addRPCPlugin(RPCPlugin plugin) {
    rpcMetaPlugins.add(plugin);
  }

  /** Called by a server to deserialize a request, compute and serialize
   * a response or error. */
  public List<ByteBuffer> respond(Transceiver transceiver) throws IOException {
    ByteBufferInputStream bbi =
      new ByteBufferInputStream(transceiver.readBuffers());
   
    Decoder in = new BinaryDecoder(bbi);
    ByteBufferOutputStream bbo =
      new ByteBufferOutputStream();
    Encoder out = new BinaryEncoder(bbo);
    AvroRemoteException error = null;
    RPCContext context = new RPCContext();
    try {
      Protocol remote = handshake(transceiver, in, out);
      if (remote == null)                        // handshake failed
        return bbo.getBufferList();

      // read request using remote protocol specification
      context.setRequestCallMeta(META_READER.read(null, in));
      String messageName = in.readString(null).toString();
      Message m = remote.getMessages().get(messageName);
      if (m == null)
        throw new AvroRuntimeException("No such remote message: "+messageName);
     
      Object request = readRequest(m.getRequest(), in);
     
      for (RPCPlugin plugin : rpcMetaPlugins) {
        plugin.serverReceiveRequest(context);
      }

      // create response using local protocol specification
      m = getLocal().getMessages().get(messageName);
      if (m == null)
        throw new AvroRuntimeException("No such local message: "+messageName);
      Object response = null;
      try {
        response = respond(m, request);
        context.setResponse(response);
      } catch (AvroRemoteException e) {
        error = e;
        context.setError(error);
      } catch (Exception e) {
        LOG.warn("application error", e);
        error = new AvroRemoteException(new Utf8(e.toString()));
        context.setError(error);
      }
     
      for (RPCPlugin plugin : rpcMetaPlugins) {
        plugin.serverSendResponse(context);
      }
     
      META_WRITER.write(context.responseCallMeta(), out);
      out.writeBoolean(error != null);
      if (error == null)
        writeResponse(m.getResponse(), response, out);
      else
        writeError(m.getErrors(), error, out);

    } catch (AvroRuntimeException e) {            // system error
      LOG.warn("system error", e);
      error = new AvroRemoteException(e);
      context.setError(error);
      bbo = new ByteBufferOutputStream();
      out = new BinaryEncoder(bbo);
      META_WRITER.write(context.responseCallMeta(), out);
      out.writeBoolean(true);
      writeError(Protocol.SYSTEM_ERRORS, error, out);
    }
     
    return bbo.getBufferList();
  }

  private SpecificDatumWriter handshakeWriter =
    new SpecificDatumWriter(HandshakeResponse._SCHEMA);
  private SpecificDatumReader handshakeReader =
    new SpecificDatumReader(HandshakeRequest._SCHEMA);

  @SuppressWarnings("unchecked")
  private Protocol handshake(Transceiver transceiver,
                             Decoder in, Encoder out)
    throws IOException {
    Protocol remote = remotes.get(transceiver);
    if (remote != null) return remote;            // already established
     
    HandshakeRequest request = (HandshakeRequest)handshakeReader.read(null, in);
    remote = protocols.get(request.clientHash);
    if (remote == null && request.clientProtocol != null) {
      remote = Protocol.parse(request.clientProtocol.toString());
      protocols.put(request.clientHash, remote);
    }
    if (remote != null)
      remotes.put(transceiver, remote);
    HandshakeResponse response = new HandshakeResponse();
    if (localHash.equals(request.serverHash)) {
      response.match =
        remote == null ? HandshakeMatch.NONE : HandshakeMatch.BOTH;
    } else {
      response.match =
        remote == null ? HandshakeMatch.NONE : HandshakeMatch.CLIENT;
    }
    if (response.match != HandshakeMatch.BOTH) {
      response.serverProtocol = new Utf8(local.toString());
      response.serverHash = localHash;
    }
   
    RPCContext context = new RPCContext();
    context.setRequestSessionMeta((Map<Utf8, ByteBuffer>) request.meta);
   
    for (RPCPlugin plugin : rpcMetaPlugins) {
      plugin.serverConnecting(context);
    }
    response.meta = context.responseSessionMeta();
   
    handshakeWriter.write(response, out);
    return remote;
  }

  /** Computes the response for a message. */
  public abstract Object respond(Message message, Object request)
    throws AvroRemoteException;

  /** Reads a request message. */
  public abstract Object readRequest(Schema schema, Decoder in)
    throws IOException;

  /** Writes a response message. */
  public abstract void writeResponse(Schema schema, Object response,
                                     Encoder out) throws IOException;

  /** Writes an error message. */
  public abstract void writeError(Schema schema, AvroRemoteException error,
                                  Encoder out) throws IOException;

}
TOP

Related Classes of org.apache.avro.ipc.Responder

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.