All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.landawn.abacus.remote.JavaExecutionServlet Maven / Gradle / Ivy

The newest version!
/*
 * 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.remote;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.landawn.abacus.exception.UncheckedIOException;
import com.landawn.abacus.http.AbstractHttpServlet;
import com.landawn.abacus.http.ContentFormat;
import com.landawn.abacus.http.HttpUtil;
import com.landawn.abacus.logging.Logger;
import com.landawn.abacus.logging.LoggerFactory;
import com.landawn.abacus.parser.JSONParser;
import com.landawn.abacus.parser.KryoParser;
import com.landawn.abacus.parser.ParserFactory;
import com.landawn.abacus.parser.XMLParser;
import com.landawn.abacus.util.ClassUtil;
import com.landawn.abacus.util.IOUtil;
import com.landawn.abacus.util.N;
import com.landawn.abacus.util.Strings;

// TODO: Auto-generated Javadoc
/**
 * Deploy JavaExecutionServlet under Tomcat.
 *
 * 
 *  {@code
 *     
 *         Hello javaExecution
 *         javaExecution
 *         javaExecution
 *         com.landawn.abacus.remote.JavaExecutionServlet
 *     
 *
 *     
 *         javaExecution
 *         /javaExecution/*
 *     
 * }
 * 
* * @author Haiyang Li * @since 0.8 */ @SuppressWarnings("deprecation") public class JavaExecutionServlet extends AbstractHttpServlet { private static final long serialVersionUID = 778742360481398056L; private static final Logger logger = LoggerFactory.getLogger(JavaExecutionServlet.class); static final JSONParser jsonParser = ParserFactory.createJSONParser(); static final XMLParser xmlParser = ParserFactory.isXMLAvailable() ? ParserFactory.createXMLParser() : null; static final KryoParser kryoParser = ParserFactory.isKryoAvailable() ? ParserFactory.createKryoParser() : null; 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.name()); } private static final Map activeTaskMap = new ConcurrentHashMap<>(); /** * * @throws ServletException the servlet exception */ @Override public void init() throws ServletException { super.init(); } /** * * @param request * @param response * @throws ServletException the servlet exception */ @Override protected void doPost(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, UncheckedIOException { execute(request, response); } /** * * @param request * @param response * @throws UncheckedIOException the unchecked IO exception */ @SuppressWarnings({ "static-method", "null" }) protected void execute(final HttpServletRequest request, final HttpServletResponse response) throws UncheckedIOException { final String hostName = IOUtil.getHostName(); final long startTime = System.currentTimeMillis(); final ContentFormat requestContentFormat = getRequestContentFormat(request); final Charset requestCharset = HttpUtil.getCharset(getContentType(request)); final RemoteExecutionResponse remoteResponse = new RemoteExecutionResponse(); remoteResponse.setExecutionHost(hostName); remoteResponse.setExecutionStartTime(startTime); String requestId = null; RemoteExecutionRequest remoteRequest = null; InputStream is = null; Throwable exception = null; try { is = getInputStream(request, requestContentFormat); switch (requestContentFormat) { case KRYO: remoteRequest = kryoParser.deserialize(RemoteExecutionRequest.class, is); break; case JSON: remoteRequest = jsonParser.deserialize(RemoteExecutionRequest.class, is); break; default: remoteResponse.setErrorCode(getClassName(RuntimeException.class)); remoteResponse.setErrorMessage("Unsupported content format: " + requestContentFormat + ". Only format JSON/Kryo is supported"); } if (remoteResponse.getErrorCode() == null) { requestId = remoteRequest.getRequestId(); remoteResponse.setRequestHost(remoteRequest.getRequestHost()); remoteResponse.setRequestId(requestId); remoteResponse.setRequestTime(remoteRequest.getRequestTime()); remoteResponse.setRequestRunMode(remoteRequest.getRunMode()); remoteResponse.setRequestSchedule(remoteRequest.getSchedule()); activeTaskMap.put(requestId, startTime); // remoteRequest.getRunMode() // TODO // remoteRequest.getSchedule() // TODO if (logger.isInfoEnabled()) { logger.info("==>Start task: " + requestId + " from host: " + hostName + ". Current active task count: " + activeTaskMap.size()); } 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> remoteTaskClass = (Class) dynamicClassLoader.loadClass(remoteRequest.getClassName()); final RemoteTask remoteTaskInstance = (RemoteTask) newInstance(remoteTaskClass); final Object result = remoteTaskInstance.run(remoteRequest.getParameter()); remoteResponse.setResult(result); } } catch (Throwable e) { exception = e; String msg = "Failed to execute task: " + requestId + " from host: " + hostName; logger.error(msg, e); remoteResponse.setErrorCode(getClassName(e.getClass())); remoteResponse.setErrorMessage(msg + ". " + e.getMessage()); } finally { if (Strings.isNotEmpty(requestId)) { activeTaskMap.remove(requestId); } remoteResponse.setExecutionEndTime(System.currentTimeMillis()); if (logger.isInfoEnabled()) { if (exception == null) { logger.info("<==Complete task: " + requestId + " from host: " + hostName + " in " + (System.currentTimeMillis() - startTime) + " milliseconds" + ". Current active task count: " + activeTaskMap.size()); } else { logger.info("<==Failed to complete task: " + requestId + " from host: " + hostName + " in " + (System.currentTimeMillis() - startTime) + " milliseconds due to error: " + ClassUtil.getSimpleClassName(exception.getClass()) + ": " + exception.getMessage() + ". Current active task count: " + activeTaskMap.size()); } } IOUtil.close(is); } OutputStream os = null; try { os = getOutputStream(response, requestContentFormat, requestCharset); if (requestContentFormat == ContentFormat.KRYO) { kryoParser.serialize(os, remoteResponse); } else { jsonParser.serialize(os, remoteResponse); } flush(os); } catch (IOException e) { String msg = "Failed to send task response back on server: " + hostName; throw new UncheckedIOException(msg, e); } finally { IOUtil.close(os); } } /** * * @param * @param classLoader * @param className * @param bytes * @return */ private static Class defineClass(ClassLoader classLoader, String className, byte[] bytes) { return invoke(classLoader, defineClassMethod, className, bytes, 0, bytes.length); } /** * Gets the class name. * * @param cls * @return */ private static String getClassName(final Class cls) { return cls.getName(); } /** * Gets the declared method. * * @param cls * @param methodName * @param parameterTypes * @return */ 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; } /** * * @param * @param cls * @return */ private static T newInstance(final Class cls) { // try { // if (Modifier.isStatic(cls.getModifiers()) == false && (ClassUtil.isAnonymousOrMemeberClass(cls))) { // // 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 && (ClassUtil.isAnonymousOrMemeberClass(parent))); // // 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); // } return N.newInstance(cls); } /** * * @param * @param instance * @param method * @param args * @return */ @SuppressWarnings("unchecked") private static T invoke(final Object instance, final Method method, final Object... args) { try { ClassUtil.setAccessible(method, true); return (T) method.invoke(instance, args); } catch (IllegalAccessException | InvocationTargetException e) { throw N.toRuntimeException(e); } } /** * The Class DynamicClassLoader. */ static class DynamicClassLoader extends ClassLoader { /** * Instantiates a new dynamic class loader. * * @param parent */ public DynamicClassLoader(ClassLoader parent) { super(parent); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy