/** * 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.hadoop.ipc; import java.lang.reflect.Method; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Register for all FastProtocol methods. The register stores mapping from * method unique identifier to method, as well as the mapping from method to its * unique identifier. This allows to obtain the method of a protocol without * reflection, and call it on an instance of implementing class. * * Server side code must ensure that the methods are registered at startup, * before any calls are made by the clients. * * The client side should also explicitly register the methods, although if they * are not registered, the server side will handle them in a usual way. */ public final class FastProtocolRegister { /** * All protocols with registered fast methods must implement this interface. * The rpc layer determines based on this interface whether a method can be * handled in the fast way. */ public interface FastProtocol { // empty for now } public static final Log LOG = LogFactory.getLog(FastProtocolRegister.class .getName()); // length of the serial unique code for FastProtocol methods private final static int NAME_LEN = 2; // maps id -> methods, and method -> id private final static Map<String, Method> idToMethod = new ConcurrentHashMap<String, Method>(); private final static Map<Method, String> methodToId = new ConcurrentHashMap<Method, String>(); /** * Registers a FastProtocol's method for a given id (name). The names should * be unique, it is not possible to re-use a name for a different method. */ public static void register(FastProtocolId id, Method m) { synchronized (FastProtocolRegister.class) { String name = id.toString(); if (name.length() != NAME_LEN) { // we only allow two-byte serialization codes throw new RuntimeException("Code must be " + NAME_LEN + " bytes long"); } if (m == null) { throw new RuntimeException("Method cannot be null"); } Method registeredMethod = idToMethod.get(name); if (registeredMethod != null && registeredMethod != m) { throw new RuntimeException( "Trying to register different method with name: " + name); } else if (registeredMethod == m) { return; // quietly } LOG.info("FastProtocol - Registering method: " + name + " method: " + m.getName()); idToMethod.put(name, m); methodToId.put(m, name); } } /** * Tries to get a method given the id. * Returns null if no such method is registered. */ public static Method tryGetMethod(String id) { if (id.length() != NAME_LEN) { // we use it to fast discard the request without doing map lookup return null; } return idToMethod.get(id); } /** * Tries to get the id of FastProtocol's method. * Returns null if no such method is registered. */ public static String tryGetId(Method m) { return methodToId.get(m); } /** * Clear the register. */ static void clear() { synchronized (FastProtocolRegister.class) { idToMethod.clear(); methodToId.clear(); } } /** * Serial versions for all FastProtocol's methods. Each id should be referred by * a single method!!! */ public enum FastProtocolId { SERIAL_VERSION_ID_1("AA"), SERIAL_VERSION_ID_2("AB"), SERIAL_VERSION_ID_3("AC"), SERIAL_VERSION_ID_4("AD"), SERIAL_VERSION_ID_5("AE"); private String name; FastProtocolId(String name) { this.name = name; } public String toString() { return name; } } }