All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.landawn.abacus.http.JavaExecutionServlet Maven / Gradle / Ivy
/*
* Copyright (C) 2015 HaiYang Li
*
* Licensed 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.landawn.abacus.http;
import static com.landawn.abacus.http.HTTP.jsonParser;
import static com.landawn.abacus.http.HTTP.kryoParser;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.landawn.abacus.exception.AbacusException;
import com.landawn.abacus.exception.UncheckedIOException;
import com.landawn.abacus.logging.Logger;
import com.landawn.abacus.logging.LoggerFactory;
import com.landawn.abacus.util.IOUtil;
import com.landawn.abacus.util.N;
import com.landawn.abacus.util.RemoteExecutionRequest;
import com.landawn.abacus.util.RemoteExecutionResponse;
import com.landawn.abacus.util.RemoteTask;
/**
* Deploy JavaExecutionServlet
under Tomcat.
*
*
* {@code
*
* Hello javaExecution
* javaExecution
* javaExecution
* com.landawn.abacus.http.JavaExecutionServlet
*
*
*
* javaExecution
* /javaExecution/*
*
* }
*
*
* @since 0.8
*
* @author Haiyang Li
*/
@SuppressWarnings("deprecation")
public class JavaExecutionServlet extends AbstractHttpServlet {
private static final long serialVersionUID = 778742360481398056L;
private static final Logger logger = LoggerFactory.getLogger(JavaExecutionServlet.class);
private static final Method defineClassMethod;
static {
defineClassMethod = getDeclaredMethod(ClassLoader.class, "defineClass", String.class, byte[].class, int.class, int.class);
defineClassMethod.setAccessible(true);
}
private static final ClassLoader rootClassLoader = JavaExecutionServlet.class.getClassLoader();
static {
logger.warn(IOUtil.JAVA_VERSION);
}
@Override
public void init() throws ServletException {
super.init();
}
@Override
protected void doPost(final HttpServletRequest request, final HttpServletResponse response) throws ServletException {
execute(request, response);
}
protected void execute(final HttpServletRequest request, final HttpServletResponse response) {
final ContentFormat contentFormat = getContentFormat(request);
final long startTime = System.currentTimeMillis();
final RemoteExecutionResponse remoteResponse = new RemoteExecutionResponse();
RemoteExecutionRequest remoteRequest = null;
InputStream is = null;
try {
is = getInputStream(request, contentFormat);
switch (contentFormat) {
case KRYO:
remoteRequest = kryoParser.deserialize(RemoteExecutionRequest.class, is);
break;
case JSON:
remoteRequest = jsonParser.deserialize(RemoteExecutionRequest.class, is);
break;
default:
remoteResponse.setErrorCode(getClassName(AbacusException.class));
remoteResponse.setErrorMessage("Unsupported content format: " + contentFormat + ". Only Kryo is supported");
}
if (remoteResponse.getErrorCode() == null) {
final String requestId = N.isNullOrEmpty(remoteRequest.getRequestId()) ? String.valueOf(System.currentTimeMillis())
: remoteRequest.getRequestId();
// remoteRequest.getRunMode() // TODO
// remoteRequest.getSchedule() // TODO
if (logger.isInfoEnabled()) {
logger.info("Start to execute task: " + requestId + " from host: " + remoteRequest.getRequestHost());
}
final DynamicClassLoader dynamicClassLoader = new DynamicClassLoader(rootClassLoader);
final Map classBytesMap = remoteRequest.getClassBytesMap();
for (Map.Entry entry : classBytesMap.entrySet()) {
defineClass(dynamicClassLoader, entry.getKey(), entry.getValue());
}
@SuppressWarnings("rawtypes")
final Class> remoteTask = (Class) dynamicClassLoader.loadClass(remoteRequest.getClassName());
final RemoteTask instance = (RemoteTask) newInstance(remoteTask);
remoteResponse.setResult(instance.run(remoteRequest.getParameter()));
if (logger.isInfoEnabled()) {
logger.info("Task: " + requestId + " is completed");
}
}
} catch (Exception e) {
String msg = "Failed to execute task on server: " + IOUtil.HOST_NAME;
logger.error(msg, e);
remoteResponse.setErrorCode(getClassName(e.getClass()));
remoteResponse.setErrorMessage(msg + ". " + e.getMessage());
} finally {
IOUtil.close(is);
}
// remoteResponse.setRequestHost(remoteRequest.getRequestHost());
// remoteResponse.setRequestTime(remoteRequest.getRequestTime());
remoteResponse.setResponseTime(System.currentTimeMillis());
remoteResponse.setExecutionTime(remoteResponse.getResponseTime() - startTime);
remoteResponse.setExecutionHost(IOUtil.HOST_NAME);
OutputStream os = null;
try {
os = getOutputStream(response, contentFormat);
switch (contentFormat) {
case KRYO:
kryoParser.serialize(os, remoteResponse);
break;
default:
jsonParser.serialize(os, remoteResponse);
}
flush(os);
} catch (IOException e) {
String msg = "Failed to execute task on server: " + IOUtil.HOST_NAME;
logger.error(msg, e);
throw new UncheckedIOException(msg, e);
} finally {
IOUtil.close(os);
}
}
private static Class defineClass(ClassLoader classLoader, String className, byte[] bytes) {
return invoke(classLoader, defineClassMethod, className, bytes, 0, bytes.length);
}
private static String getClassName(final Class cls) {
return cls.getName();
}
private static Method getDeclaredMethod(final Class cls, final String methodName, final Class... parameterTypes) {
Method method = null;
try {
method = cls.getDeclaredMethod(methodName, parameterTypes);
} catch (NoSuchMethodException e) {
// ignore.
}
if (method == null) {
Method[] methods = cls.getDeclaredMethods();
for (Method m : methods) {
if (m.getName().equalsIgnoreCase(methodName) && N.equals(parameterTypes, m.getParameterTypes())) {
method = m;
break;
}
}
}
return method;
}
private static T newInstance(final Class cls) {
try {
if (Modifier.isStatic(cls.getModifiers()) == false && (cls.isAnonymousClass() || cls.isMemberClass())) {
// http://stackoverflow.com/questions/2097982/is-it-possible-to-create-an-instance-of-nested-class-using-java-reflection
final List> toInstantiate = new ArrayList<>();
Class parent = cls.getEnclosingClass();
do {
toInstantiate.add(parent);
parent = parent.getEnclosingClass();
} while (parent != null && Modifier.isStatic(parent.getModifiers()) == false && (parent.isAnonymousClass() || parent.isMemberClass()));
if (parent != null) {
toInstantiate.add(parent);
}
N.reverse(toInstantiate);
Object instance = null;
for (Class current : toInstantiate) {
instance = instance == null ? invoke(current.getDeclaredConstructor())
: invoke(current.getDeclaredConstructor(instance.getClass()), instance);
}
return invoke(cls.getDeclaredConstructor(instance.getClass()), instance);
} else {
return invoke(cls.getDeclaredConstructor());
}
} catch (Exception e) {
throw N.toRuntimeException(e);
}
}
@SuppressWarnings("unchecked")
private static T invoke(final Object instance, final Method method, final Object... args) {
try {
if (method.isAccessible() == false) {
method.setAccessible(true);
}
return (T) method.invoke(instance, args);
} catch (IllegalAccessException | InvocationTargetException e) {
throw N.toRuntimeException(e);
}
}
@SuppressWarnings("unchecked")
private static T invoke(final Constructor c, final Object... args) {
try {
if (c.isAccessible() == false) {
c.setAccessible(true);
}
return c.newInstance(args);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw N.toRuntimeException(e);
}
}
static class DynamicClassLoader extends ClassLoader {
public DynamicClassLoader(ClassLoader parent) {
super(parent);
}
}
}