| /** |
| * 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.hdfs.server.federation.router; |
| |
| import java.io.IOException; |
| import java.lang.reflect.Method; |
| import java.util.Arrays; |
| |
| import org.apache.hadoop.hdfs.protocol.ClientProtocol; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| /** |
| * Determines the remote client protocol method and the parameter list for a |
| * specific location. |
| */ |
| public class RemoteMethod { |
| |
| private static final Logger LOG = LoggerFactory.getLogger(RemoteMethod.class); |
| |
| |
| /** List of parameters: static and dynamic values, matchings types. */ |
| private final Object[] params; |
| /** List of method parameters types, matches parameters. */ |
| private final Class<?>[] types; |
| /** Class of the protocol for the method. */ |
| private final Class<?> protocol; |
| /** String name of the ClientProtocol method. */ |
| private final String methodName; |
| |
| /** |
| * Create a remote method generator for the ClientProtocol with no parameters. |
| * |
| * @param method The string name of the protocol method. |
| */ |
| public RemoteMethod(String method) { |
| this(ClientProtocol.class, method); |
| } |
| |
| /** |
| * Create a method with no parameters. |
| * |
| * @param proto Protocol of the method. |
| * @param method The string name of the ClientProtocol method. |
| */ |
| public RemoteMethod(Class<?> proto, String method) { |
| this.params = null; |
| this.types = null; |
| this.methodName = method; |
| this.protocol = proto; |
| } |
| |
| /** |
| * Create a remote method generator for the ClientProtocol. |
| * |
| * @param method The string name of the ClientProtocol method. |
| * @param pTypes A list of types to use to locate the specific method. |
| * @param pParams A list of parameters for the method. The order of the |
| * parameter list must match the order and number of the types. |
| * Parameters are grouped into 2 categories: |
| * <ul> |
| * <li>Static parameters that are immutable across locations. |
| * <li>Dynamic parameters that are determined for each location by a |
| * RemoteParam object. To specify a dynamic parameter, pass an |
| * instance of RemoteParam in place of the parameter value. |
| * </ul> |
| * @throws IOException If the types and parameter lists are not valid. |
| */ |
| public RemoteMethod(String method, Class<?>[] pTypes, Object... pParams) |
| throws IOException { |
| this(ClientProtocol.class, method, pTypes, pParams); |
| } |
| |
| /** |
| * Creates a remote method generator. |
| * |
| * @param proto Protocol of the method. |
| * @param method The string name of the ClientProtocol method. |
| * @param pTypes A list of types to use to locate the specific method. |
| * @param pParams A list of parameters for the method. The order of the |
| * parameter list must match the order and number of the types. |
| * Parameters are grouped into 2 categories: |
| * <ul> |
| * <li>Static parameters that are immutable across locations. |
| * <li>Dynamic parameters that are determined for each location by a |
| * RemoteParam object. To specify a dynamic parameter, pass an |
| * instance of RemoteParam in place of the parameter value. |
| * </ul> |
| * @throws IOException If the types and parameter lists are not valid. |
| */ |
| public RemoteMethod(Class<?> proto, String method, Class<?>[] pTypes, |
| Object... pParams) throws IOException { |
| |
| if (pParams.length != pTypes.length) { |
| throw new IOException("Invalid parameters for method " + method); |
| } |
| |
| this.protocol = proto; |
| this.params = pParams; |
| this.types = Arrays.copyOf(pTypes, pTypes.length); |
| this.methodName = method; |
| } |
| |
| /** |
| * Get the interface/protocol for this method. For example, ClientProtocol or |
| * NamenodeProtocol. |
| * |
| * @return Protocol for this method. |
| */ |
| public Class<?> getProtocol() { |
| return this.protocol; |
| } |
| |
| /** |
| * Get the represented java method. |
| * |
| * @return Method |
| * @throws IOException If the method cannot be found. |
| */ |
| public Method getMethod() throws IOException { |
| try { |
| if (types != null) { |
| return protocol.getDeclaredMethod(methodName, types); |
| } else { |
| return protocol.getDeclaredMethod(methodName); |
| } |
| } catch (NoSuchMethodException e) { |
| // Re-throw as an IOException |
| LOG.error("Cannot get method {} with types {} from {}", |
| methodName, Arrays.toString(types), protocol.getSimpleName(), e); |
| throw new IOException(e); |
| } catch (SecurityException e) { |
| LOG.error("Cannot access method {} with types {} from {}", |
| methodName, Arrays.toString(types), protocol.getSimpleName(), e); |
| throw new IOException(e); |
| } |
| } |
| |
| /** |
| * Get the calling types for this method. |
| * |
| * @return An array of calling types. |
| */ |
| public Class<?>[] getTypes() { |
| return Arrays.copyOf(this.types, this.types.length); |
| } |
| |
| /** |
| * Generate a list of parameters for this specific location using no context. |
| * |
| * @return A list of parameters for the method customized for the location. |
| */ |
| public Object[] getParams() { |
| return this.getParams(null); |
| } |
| |
| /** |
| * Get the name of the method. |
| * |
| * @return Name of the method. |
| */ |
| public String getMethodName() { |
| return this.methodName; |
| } |
| |
| /** |
| * Generate a list of parameters for this specific location. Parameters are |
| * grouped into 2 categories: |
| * <ul> |
| * <li>Static parameters that are immutable across locations. |
| * <li>Dynamic parameters that are determined for each location by a |
| * RemoteParam object. |
| * </ul> |
| * |
| * @param context The context identifying the location. |
| * @return A list of parameters for the method customized for the location. |
| */ |
| public Object[] getParams(RemoteLocationContext context) { |
| if (this.params == null) { |
| return new Object[] {}; |
| } |
| Object[] objList = new Object[this.params.length]; |
| for (int i = 0; i < this.params.length; i++) { |
| Object currentObj = this.params[i]; |
| if (currentObj instanceof RemoteParam) { |
| // Map the parameter using the context |
| RemoteParam paramGetter = (RemoteParam) currentObj; |
| objList[i] = paramGetter.getParameterForContext(context); |
| } else { |
| objList[i] = currentObj; |
| } |
| } |
| return objList; |
| } |
| |
| @Override |
| public String toString() { |
| return this.protocol.getSimpleName() + "#" + this.methodName + " " + |
| Arrays.toString(this.params); |
| } |
| } |