| /* | |
| * 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. | |
| */ | |
| import java.io.*; | |
| import java.lang.reflect.Field; | |
| import java.lang.reflect.Method; | |
| import java.lang.reflect.Modifier; | |
| import java.nio.charset.StandardCharsets; | |
| import java.util.Collections; | |
| import java.util.HashMap; | |
| import java.util.Map; | |
| import com.google.gson.*; | |
| import java.security.Permission; | |
| import java.lang.reflect.InvocationTargetException; | |
| class Launcher { | |
| private static String mainClassName = "Main"; | |
| private static String mainMethodName = "main"; | |
| private static Class mainClass = null; | |
| private static Method mainMethod = null; | |
| @SuppressWarnings({ "unchecked", "rawtypes" }) | |
| private static void augmentEnv(Map<String, String> newEnv) { | |
| try { | |
| for (Class cl : Collections.class.getDeclaredClasses()) { | |
| if ("java.util.Collections$UnmodifiableMap".equals(cl.getName())) { | |
| Field field = cl.getDeclaredField("m"); | |
| field.setAccessible(true); | |
| Object obj = field.get(System.getenv()); | |
| Map<String, String> map = (Map<String, String>) obj; | |
| map.putAll(newEnv); | |
| } | |
| } | |
| } catch (Exception e) {} | |
| } | |
| private static void initMain(String[] args) throws Exception { | |
| if(args.length > 0) | |
| mainClassName = args[0]; | |
| int pos = mainClassName.indexOf("#"); | |
| if(pos != -1) { | |
| if(pos + 1 != mainClassName.length()) | |
| mainMethodName = args[0].substring(pos+1); | |
| mainClassName = args[0].substring(0,pos); | |
| } | |
| mainClass = Class.forName(mainClassName); | |
| Method[] methods = mainClass.getDeclaredMethods(); | |
| Boolean existMain = false; | |
| for(Method method: methods) { | |
| if (method.getName().equals(mainMethodName)) { | |
| existMain = true; | |
| break; | |
| } | |
| } | |
| if (!existMain) { | |
| throw new NoSuchMethodException(mainMethodName); | |
| } | |
| } | |
| private static Object invokeMain(JsonElement arg, Map<String, String> env) throws Exception { | |
| augmentEnv(env); | |
| return mainMethod.invoke(null, arg); | |
| } | |
| /* | |
| Use of SecurityManager has been Deprrecated from JDK17. Alternatives to prevent System.exit() are not yet available. | |
| private static SecurityManager defaultSecurityManager = null; | |
| private static void installSecurityManager() { | |
| defaultSecurityManager = System.getSecurityManager(); | |
| System.setSecurityManager(new SecurityManager() { | |
| @Override | |
| public void checkPermission(Permission p) { | |
| // Not throwing means accepting anything. | |
| } | |
| @Override | |
| public void checkPermission(Permission p, Object ctx) { | |
| // Not throwing means accepting anything. | |
| } | |
| @Override | |
| public void checkExit(int status) { | |
| super.checkExit(status); | |
| throw new SecurityException("System.exit(" + status + ") called from within an action."); | |
| } | |
| }); | |
| } | |
| private static void uninstallSecurityManager() { | |
| if(defaultSecurityManager != null) { | |
| System.setSecurityManager(defaultSecurityManager); | |
| } | |
| } | |
| */ | |
| public static void main(String[] args) throws Exception { | |
| initMain(args); | |
| // exit after main class loading if "exit" specified | |
| // used to check healthy launch after init | |
| if(args.length >1 && args[1] == "-exit") | |
| System.exit(0); | |
| // install a security manager to prevent exit | |
| //installSecurityManager(); | |
| BufferedReader in = new BufferedReader( | |
| new InputStreamReader(System.in, StandardCharsets.UTF_8)); | |
| PrintWriter out = new PrintWriter( | |
| new OutputStreamWriter( | |
| new FileOutputStream("/dev/fd/3"), StandardCharsets.UTF_8)); | |
| JsonParser json = new JsonParser(); | |
| JsonObject emptyForJsonObject = json.parse("{}").getAsJsonObject(); | |
| JsonArray emptyForJsonArray = json.parse("[]").getAsJsonArray(); | |
| Boolean isJsonObjectParam = true; | |
| String input = ""; | |
| while (true) { | |
| try { | |
| input = in.readLine(); | |
| if (input == null) | |
| break; | |
| JsonElement element = json.parse(input); | |
| JsonObject payloadForJsonObject = emptyForJsonObject.deepCopy(); | |
| JsonArray payloadForJsonArray = emptyForJsonArray.deepCopy(); | |
| Map<String, String> env = new HashMap<>(); | |
| if (element.isJsonObject()) { | |
| // collect payload and environment | |
| for (Map.Entry<String, JsonElement> entry : element.getAsJsonObject().entrySet()) { | |
| if (entry.getKey().equals("value")) { | |
| if (entry.getValue().isJsonObject()) | |
| payloadForJsonObject = entry.getValue().getAsJsonObject(); | |
| else { | |
| payloadForJsonArray = entry.getValue().getAsJsonArray(); | |
| isJsonObjectParam = false; | |
| } | |
| } else { | |
| env.put(String.format("__OW_%s", entry.getKey().toUpperCase()), | |
| entry.getValue().getAsString()); | |
| } | |
| } | |
| augmentEnv(env); | |
| } | |
| Method m = null; | |
| if (isJsonObjectParam) { | |
| m = mainClass.getMethod(mainMethodName, new Class[] { JsonObject.class }); | |
| } else { | |
| m = mainClass.getMethod(mainMethodName, new Class[] { JsonArray.class }); | |
| } | |
| m.setAccessible(true); | |
| int modifiers = m.getModifiers(); | |
| if ((m.getReturnType() != JsonObject.class && m.getReturnType() != JsonArray.class) || !Modifier.isStatic(modifiers) || !Modifier.isPublic(modifiers)) { | |
| throw new NoSuchMethodException(mainMethodName); | |
| } | |
| mainMethod = m; | |
| Object response; | |
| if (isJsonObjectParam) { | |
| response = invokeMain(payloadForJsonObject, env); | |
| } else { | |
| response = invokeMain(payloadForJsonArray, env); | |
| } | |
| out.println(response.toString()); | |
| } catch(NullPointerException npe) { | |
| System.out.println("the action returned null"); | |
| npe.printStackTrace(System.err); | |
| JsonObject error = new JsonObject(); | |
| error.addProperty("error", "the action returned null"); | |
| out.println(error.toString()); | |
| out.flush(); | |
| } catch(InvocationTargetException ite) { | |
| Throwable ex = ite; | |
| if(ite.getCause() != null) | |
| ex = ite.getCause(); | |
| ex.printStackTrace(System.err); | |
| JsonObject error = new JsonObject(); | |
| error.addProperty("error", ex.getMessage()); | |
| out.println(error.toString()); | |
| out.flush(); | |
| } catch (Exception ex) { | |
| ex.printStackTrace(System.err); | |
| JsonObject error = new JsonObject(); | |
| error.addProperty("error", ex.getMessage()); | |
| out.println(error.toString()); | |
| out.flush(); | |
| } | |
| out.flush(); | |
| System.out.flush(); | |
| System.err.flush(); | |
| } | |
| //uninstallSecurityManager(); | |
| } | |
| } |