org.apache.zeppelin.resource.Resource Maven / Gradle / Ivy
The newest version!
/*
* 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.zeppelin.resource;
import com.google.gson.Gson;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import com.google.gson.internal.Primitives;
import org.apache.zeppelin.common.JsonSerializable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
/**
* Information and reference to the resource
*/
public class Resource implements JsonSerializable, Serializable {
private static final Logger LOGGER = LoggerFactory.getLogger(Resource.class);
private static final Gson gson = new Gson();
private final transient Object r;
private final transient LocalResourcePool pool;
private final boolean serializable;
private final ResourceId resourceId;
private final String className;
/**
* Create local resource
*
* @param resourceId
* @param r must not be null
*/
Resource(LocalResourcePool pool, ResourceId resourceId, Object r) {
this.r = r;
this.pool = pool;
this.resourceId = resourceId;
this.serializable = r instanceof Serializable;
this.className = r.getClass().getName();
}
/**
* Create remote object
*
* @param resourceId
*/
Resource(LocalResourcePool pool, ResourceId resourceId, boolean serializable, String className) {
this.r = null;
this.pool = pool;
this.resourceId = resourceId;
this.serializable = serializable;
this.className = className;
}
public ResourceId getResourceId() {
return resourceId;
}
public String getClassName() {
return className;
}
/**
* @return null when this is remote resource and not serializable.
*/
public Object get() {
if (isLocal() || isSerializable()) {
return r;
} else {
return null;
}
}
public T get(Class clazz) {
return Primitives.wrap(clazz).cast(r);
}
public boolean isSerializable() {
return serializable;
}
/**
* if it is remote object
*
* @return
*/
public boolean isRemote() {
return !isLocal();
}
/**
* Whether it is locally accessible or not
*
* @return
*/
public boolean isLocal() {
return true;
}
/**
* Invoke a method without param
* @param methodName
* @return
*/
public Object invokeMethod(String methodName) {
return invokeMethod(methodName, (Class []) null, (Object []) null);
}
/**
* Invoke a method and store result in ResourcePool
* @param methodName
* @param returnResourceName
* @return
*/
public Resource invokeMethod(String methodName, String returnResourceName) {
return invokeMethod(methodName, (Class []) null, (Object []) null, returnResourceName);
}
/**
* Invoke a method with automatic parameter type inference
* @param methodName
* @param params
* @return
* @throws ClassNotFoundException
*/
public Object invokeMethod(String methodName, Object [] params)
throws ClassNotFoundException {
return invokeMethod(methodName, (Type[]) null, params);
}
/**
* Invoke a method with automatic parameter type inference
* @param methodName
* @param params python interpreter convert python array '[]' to ArrayList through py4j
* @return
* @throws ClassNotFoundException
*/
public Object invokeMethod(
String methodName, ArrayList params)
throws ClassNotFoundException {
Object[] paramsArray = params.toArray(new Object[]{});
return invokeMethod(methodName, paramsArray);
}
/**
* Invoke a method with automatic parameter type inference and store result in ResourcePool
* @param methodName
* @param params
* @param returnResourceName
* @return
* @throws ClassNotFoundException
*/
public Resource invokeMethod(String methodName, Object [] params, String returnResourceName)
throws ClassNotFoundException {
return (Resource) invokeMethod(methodName, (Type[]) null, params, returnResourceName);
}
/**
* Invoke a method with automatic parameter type inference and store result in ResourcePool
* @param methodName
* @param params python interpreter convert python array '[]' to ArrayList through py4j
* @param returnResourceName
* @return
* @throws ClassNotFoundException
*/
public Resource invokeMethod(
String methodName, ArrayList params, String returnResourceName)
throws ClassNotFoundException {
Object[] paramsArray = params.toArray(new Object[]{});
return invokeMethod(methodName, paramsArray, returnResourceName);
}
/**
* Invoke a method with given parameter class names
* @param methodName
* @param paramTypes list of fully qualified class name
* @param params
* @return
* @throws ClassNotFoundException
*/
public Object invokeMethod(
String methodName, String[] paramTypes, Object[] params)
throws ClassNotFoundException {
Type [] types = typeFromName(paramTypes);
return invokeMethod(methodName, types, params);
}
/**
* Invoke a method with given parameter class names
* @param methodName
* @param paramTypes list of fully qualified class name. python interpreter convert python array '[]' to ArrayList through py4j
* @param params python interpreter convert python array '[]' to ArrayList through py4j
* @return
* @throws ClassNotFoundException
*/
public Object invokeMethod(
String methodName, ArrayList paramTypes, ArrayList params)
throws ClassNotFoundException {
String[] paramTypesArray = paramTypes.toArray(new String[]{});
Object[] paramsArray = params.toArray(new Object[]{});
return invokeMethod(methodName, paramTypesArray, paramsArray);
}
/**
* Invoke a method with given parameter class names and store result in ResourcePool
* @param methodName
* @param paramTypes
* @param params
* @param returnResourceName
* @return
* @throws ClassNotFoundException
*/
public Resource invokeMethod(
String methodName, String[] paramTypes, Object[] params, String returnResourceName)
throws ClassNotFoundException {
Type [] types = typeFromName(paramTypes);
return (Resource) invokeMethod(methodName, types, params, returnResourceName);
}
public Resource invokeMethod(
String methodName, ArrayList paramTypes, ArrayList params, String returnResourceName)
throws ClassNotFoundException {
String[] paramTypesArray = paramTypes.toArray(new String[]{});
Object[] paramsArray = params.toArray(new Object[]{});
return invokeMethod(methodName, paramTypesArray, paramsArray, returnResourceName);
}
/**
* Invoke a method with give parameter types
* @param methodName
* @param types
* @param params
* @return
* @throws ClassNotFoundException
*/
public Object invokeMethod(
String methodName, Type[] types, Object[] params)
throws ClassNotFoundException {
return invokeMethod(methodName, types, params, null);
}
/**
* Invoke a method with given parameter type and store result in ResourcePool
* @param methodName
* @param types
* @param params
* @param returnResourceName
* @return
* @throws ClassNotFoundException
*/
public Object invokeMethod(
String methodName, Type[] types, Object[] params, String returnResourceName) throws ClassNotFoundException {
Object[] convertedParams = null;
Class[] classes = null;
if (types != null) {
convertedParams = convertParams(types, params);
classes = classFromType(types);
} else {
// inference method param types
boolean found = false;
Method[] methods = r.getClass().getDeclaredMethods();
for (Method m : methods) {
// try to find method by name
if (!m.getName().equals(methodName)) {
continue;
}
Type[] paramTypes = m.getGenericParameterTypes();
if (paramTypes.length != params.length) {
// parameter count doesn't match
continue;
} else {
try {
// try to convert parameters
convertedParams = convertParams(paramTypes, params);
} catch (Exception e) {
LOGGER.info(
String.format("The parameter types of method \'%s\' don't match with the arguments", m.getName()));
continue;
}
}
classes = classFromType(paramTypes);
found = true;
break;
}
if (!found) {
throw new ClassNotFoundException("No method found for given parameters");
}
}
if (returnResourceName == null) {
return invokeMethod(methodName, classes, convertedParams);
} else {
return invokeMethod(methodName, classes, convertedParams, returnResourceName);
}
}
/**
* Call a method of the object that this resource holds
*
* @param methodName name of method to call
* @param paramTypes method parameter types
* @param params method parameter values
* @return return value of the method
*/
public Object invokeMethod(
String methodName, Class[] paramTypes, Object[] params) {
if (r != null) {
try {
Method method = r.getClass().getMethod(
methodName,
paramTypes);
method.setAccessible(true);
Object ret = method.invoke(r, params);
return ret;
} catch (Exception e) {
logException(e);
return null;
}
} else {
return null;
}
}
/**
* Call a method of the object that this resource holds and save return value as a resource
*
* @param methodName name of method to call
* @param paramTypes method parameter types
* @param params method parameter values
* @param returnResourceName name of resource that return value will be saved
* @return Resource that holds return value
*/
public Resource invokeMethod(
String methodName, Class[] paramTypes, Object[] params, String returnResourceName) {
if (r != null) {
try {
Method method = r.getClass().getMethod(
methodName,
paramTypes);
Object ret = method.invoke(r, params);
pool.put(
resourceId.getNoteId(),
resourceId.getParagraphId(),
returnResourceName,
ret
);
return pool.get(
resourceId.getNoteId(),
resourceId.getParagraphId(),
returnResourceName);
} catch (Exception e) {
logException(e);
return null;
}
} else {
return null;
}
}
public static ByteBuffer serializeObject(Object o) throws IOException {
if (o == null || !(o instanceof Serializable)) {
return null;
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
ObjectOutputStream oos;
oos = new ObjectOutputStream(out);
oos.writeObject(o);
oos.close();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
return ByteBuffer.wrap(out.toByteArray());
}
public static Object deserializeObject(ByteBuffer buf)
throws IOException, ClassNotFoundException {
if (buf == null) {
return null;
}
InputStream ins = ByteBufferInputStream.get(buf);
ObjectInputStream oin;
Object object = null;
oin = new ObjectInputStream(ins);
object = oin.readObject();
oin.close();
ins.close();
return object;
}
private void logException(Exception e) {
Logger logger = LoggerFactory.getLogger(Resource.class);
logger.error(e.getMessage(), e);
}
public String toJson() {
return gson.toJson(this);
}
public static Resource fromJson(String json) {
return gson.fromJson(json, Resource.class);
}
private ParameterizedType [] typeFromName(String [] classNames) throws ClassNotFoundException {
if (classNames == null) {
return null;
}
ParameterizedType[] types = new ParameterizedType[classNames.length];
for (int i = 0; i < classNames.length; i++) {
types[i] = typeFromName(classNames[i]);
}
return types;
}
private ParameterizedType typeFromName(String commaSeparatedClasses) throws ClassNotFoundException {
String[] classNames = commaSeparatedClasses.split(",");
Class [] arguments;
if (classNames.length > 1) {
arguments = new Class[classNames.length - 1];
for (int i = 1; i < classNames.length; i++) {
arguments[i - 1] = loadClass(classNames[i]);
}
} else {
arguments = new Class[0];
}
Class rawType = loadClass(classNames[0]);
return new ParameterizedType() {
@Override
public Type[] getActualTypeArguments() {
return arguments;
}
@Override
public Type getRawType() {
return rawType;
}
@Override
public Type getOwnerType() {
return null;
}
};
}
private Class [] classFromType(Type[] types) throws ClassNotFoundException {
Class[] cls = new Class[types.length];
for (int i = 0; i < types.length; i++) {
if (types[i] instanceof ParameterizedType) {
String typeName = ((ParameterizedType) types[i]).getRawType().getTypeName();
cls[i] = loadClass(typeName);
} else {
cls[i] = loadClass(types[i].getTypeName());
}
}
return cls;
}
private Object [] convertParams(Type[] types, Object [] params) {
Object [] converted = new Object[types.length];
for (int i = 0; i < types.length; i++) {
Type type = types[i];
String typeName;
if (type instanceof ParameterizedType) {
typeName = ((ParameterizedType) type).getRawType().getTypeName();
} else {
typeName = type.getTypeName();
}
Object param = params[i];
if (param == null) {
converted[i] = null;
} else if (param.getClass().getName().equals(typeName)) {
converted[i] = param;
} else {
// try to convert param
converted[i] = gson.fromJson(gson.toJson(param), type);
}
}
return converted;
}
private Class loadClass(String className) throws ClassNotFoundException {
switch(className) {
case "byte":
return byte.class;
case "short":
return short.class;
case "int":
return int.class;
case "long":
return long.class;
case "float":
return float.class;
case "double":
return double.class;
case "boolean":
return boolean.class;
case "char":
return char.class;
default:
return getClass().getClassLoader().loadClass(className);
}
}
}