Java tutorial
/* * This file is part of Awake FILE. * Awake file: Easy file upload & download over HTTP with Java. * Copyright (C) 2015, KawanSoft SAS * (http://www.kawansoft.com). All rights reserved. * * Awake FILE is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * Awake FILE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * * Any modifications to this file must keep this entire header * intact. */ package org.kawanfw.file.servlet; import java.io.IOException; import java.io.OutputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.sql.Connection; import java.sql.SQLException; import java.util.List; import java.util.Vector; import java.util.logging.Level; import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang3.StringUtils; import org.kawanfw.commons.api.server.CommonsConfigurator; import org.kawanfw.commons.json.ListOfStringTransport; import org.kawanfw.commons.server.util.ServerLogger; import org.kawanfw.commons.util.FrameworkDebug; import org.kawanfw.commons.util.HtmlConverter; import org.kawanfw.commons.util.JavaValueBuilder; import org.kawanfw.commons.util.StringUtil; import org.kawanfw.commons.util.Tag; import org.kawanfw.commons.util.TransferStatus; import org.kawanfw.file.api.server.FileConfigurator; import org.kawanfw.file.servlet.convert.HttpServletRequestConvertor; import org.kawanfw.file.servlet.util.CallUtil; import org.kawanfw.file.util.parms.Action; import org.kawanfw.file.util.parms.Parameter; /** * @author Nicolas de Pomereu * * Executes the client call() action. */ public class ServerCallAction { private static boolean DEBUG = FrameworkDebug.isSet(ServerCallAction.class); /** * Constructor */ public ServerCallAction() { } /** * * Calls a remote method from the client side <br> * Please note that all invocation are trapped and routed as code string to * the client side. * * @param request * the http request * @param commonsConfigurator * the commons configurator defined by the user * @param fileConfigurator * the file configurator defined by the user * @param out * the servlet output stream * @param username * the client login (for security check) * * * @throws IOException * all framework, network, etc. errors * @throws ClassNotFoundException * @throws IllegalAccessException * @throws InstantiationException * @throws NoSuchMethodException * @throws InvocationTargetException * @throws IllegalArgumentException */ public void call(HttpServletRequest request, CommonsConfigurator commonsConfigurator, FileConfigurator fileConfigurator, OutputStream out, String username) throws SQLException, IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException, Exception { Connection connection = null; try { debug("in actionCall"); // The method name String methodName = request.getParameter(Parameter.METHOD_NAME); // The parms name String paramsTypes = request.getParameter(Parameter.PARAMS_TYPES); String paramsValues = request.getParameter(Parameter.PARAMS_VALUES); // Make sure all values are not null and trimed methodName = StringUtil.getTrimValue(methodName); paramsTypes = StringUtil.getTrimValue(paramsTypes); paramsValues = StringUtil.getTrimValue(paramsValues); if (request instanceof HttpServletRequestConvertor) { debug("request instanceof HttpServletRequestConvertor"); } else { debug("request NOT instanceof HttpServletRequestConvertor"); } debug("methodName: " + methodName); debug("username : " + username); String className = StringUtils.substringBeforeLast(methodName, "."); Class<?> c = Class.forName(className); CallUtil callUtil = new CallUtil(c, fileConfigurator); boolean callAllowed = callUtil.isCallable(); if (!callAllowed) { throw new SecurityException( Tag.PRODUCT_SECURITY + " Class is forbiden for remote call: " + className); } String action = request.getParameter(Parameter.ACTION); // Legacy Action.CALL_ACTION call with Base64 conversion // Corresponds to RemoteSession.setUseBase64EncodingForCall() // setting // on client side if (action.equals(Action.CALL_ACTION)) { paramsTypes = StringUtil.fromBase64(paramsTypes); paramsValues = StringUtil.fromBase64(paramsValues); } debug("paramsTypes : " + paramsTypes); debug("paramsValues : " + paramsValues); List<String> listParamsTypes = ListOfStringTransport.fromJson(paramsTypes); List<String> listParamsValues = ListOfStringTransport.fromJson(paramsValues); debug("actionInvokeRemoteMethod:listParamsTypes : " + listParamsTypes); debug("actionInvokeRemoteMethod:listParamsValues : " + listParamsValues); Class<?>[] argTypes = new Class[listParamsTypes.size()]; Object[] values = new Object[listParamsValues.size()]; List<Object> valuesList = new Vector<Object>(); for (int i = 0; i < listParamsTypes.size(); i++) { String value = listParamsValues.get(i); String javaType = listParamsTypes.get(i); JavaValueBuilder javaValueBuilder = new JavaValueBuilder(javaType, value); argTypes[i] = javaValueBuilder.getClassOfValue(); values[i] = javaValueBuilder.getValue(); // Special treatement if argTypes[i] is a Connection if (argTypes[i] == Connection.class) { connection = commonsConfigurator.getConnection(); values[i] = connection; } valuesList.add(values[i]); } // Try to get A connection. Will be null if user has not configured a Connection try { if (connection == null) { connection = commonsConfigurator.getConnection(); } } catch (Exception e) { debug("commonsConfigurator.getConnection() exception: " + e.toString()); if (connection != null) connection.close(); connection = null; } boolean isAllowed = fileConfigurator.allowCallAfterAnalysis(username, connection, methodName, valuesList); if (!isAllowed) { String ipAddress = request.getRemoteAddr(); // Run the runIfCallDisallowed() configured by the user fileConfigurator.runIfCallRefused(username, connection, ipAddress, methodName, valuesList); throw new SecurityException( Tag.PRODUCT_SECURITY + " Method not authorized for execution by Security Checker: " + methodName + " parameters: " + valuesList.toString()); } String rawMethodName = StringUtils.substringAfterLast(methodName, "."); // Invoke the method Object resultObj = null; debug("Before Object theObject = c.newInstance()"); Object theObject = c.newInstance(); debug("Before c.getDeclaredMethod(rawMethodName, argTypes)"); Method main = c.getDeclaredMethod(rawMethodName, argTypes); debug("Before main.invoke(theObject, values)"); resultObj = main.invoke(theObject, values); String result = null; if (resultObj != null) result = resultObj.toString(); debug("result before conversion: " + result); if (result != null) { // Legacy Action.CALL_ACTION call with Base64 conversion // Corresponds to RemoteSession.setUseBase64EncodingForCall() // setting on client side if (action.equals(Action.CALL_ACTION)) { result = StringUtil.toBase64(result); } else if (action.equals(Action.CALL_ACTION_HTML_ENCODED)) { result = HtmlConverter.toHtml(result); } else { throw new IllegalArgumentException("call action is invalid: " + action); } } debug("actionInvokeRemoteMethod:result: " + result); writeLine(out, TransferStatus.SEND_OK); writeLine(out, result); } finally { if (connection != null) { connection.close(); } } } /** * Write a line of string on the servlet output stream. Will add the * necessary CR_LF * * @param out * the servlet output stream * @param s * the string to write * @throws IOException */ private void writeLine(OutputStream out, String s) throws IOException { out.write((s + StringUtil.CR_LF).getBytes()); } private void debug(String s) { if (DEBUG) { ServerLogger.getLogger().log(Level.WARNING, s); } } }