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

src-main.org.awakefw.file.servlet.ServerCallAction Maven / Gradle / Ivy

Go to download

Awake FILE is a secure Open Source framework that allows to program very easily file uploads/downloads and RPC through http. File transfers include powerful features like file chunking and automatic recovery mechanism. Security has been taken into account from the design: server side allows to specify strong security rules in order to protect the files and to secure the RPC calls.

There is a newer version: 3.0
Show newest version
/*
 * This file is part of Awake FILE. 
 * Awake FILE: Easy file upload & download over HTTP with Java.                                    
 * Copyright (C) 2014,  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.awakefw.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 javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.awakefw.commons.api.server.AwakeCommonsConfigurator;
import org.awakefw.commons.server.util.AwakeServerLogger;
import org.awakefw.file.api.server.AwakeFileConfigurator;
import org.awakefw.file.api.util.AwakeDebug;
import org.awakefw.file.api.util.HtmlConverter;
import org.awakefw.file.json.ListOfStringTransport;
import org.awakefw.file.servlet.convert.HttpServletRequestConvertor;
import org.awakefw.file.servlet.util.CallUtil;
import org.awakefw.file.util.JavaValueBuilder;
import org.awakefw.file.util.StringUtil;
import org.awakefw.file.util.Tag;
import org.awakefw.file.util.TransferStatus;
import org.awakefw.file.util.parms.Action;
import org.awakefw.file.util.parms.Parameter;

/**
 * @author Nicolas de Pomereu
 * 
 *  Executes the client call() action.
 */
public class ServerCallAction {

    private static boolean DEBUG = AwakeDebug.isSet(ServerCallAction.class);

    /**
     * Constructor
     */
    public ServerCallAction() {
    }

    /**
     * 
     * Calls a remote method from the client side 
* Please note that all invocation are trapped and routed as code string to * the client side. * * @param request * the http request * @param awakeCommonsConfigurator * the commons configurator defined by the user * @param awakeFileConfigurator * the file configurator defined by the user * @param out * the servlet output stream * @param username * the client login (for security check) * * * @throws IOException * all Awake, network, etc. errors * @throws ClassNotFoundException * @throws IllegalAccessException * @throws InstantiationException * @throws NoSuchMethodException * @throws InvocationTargetException * @throws IllegalArgumentException */ public void call(HttpServletRequest request, AwakeCommonsConfigurator awakeCommonsConfigurator, AwakeFileConfigurator awakeFileConfigurator, OutputStream out, String username) throws SQLException, IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException { 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); boolean callAllowed = callUtil.isCallable(); if (!callAllowed) { throw new SecurityException(Tag.AWAKE_SECURITY + "Class is forbiden for remote call: " + className); } String action = request.getParameter(Parameter.ACTION); // Legacy Action.CALL_ACTION call with Base64 conversion // Corresponds to AwakeFileSession.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 listParamsTypes = ListOfStringTransport .fromJson(paramsTypes); List 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 valuesList = new Vector(); 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 = awakeCommonsConfigurator.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 = awakeCommonsConfigurator.getConnection(); } } catch (Exception e) { debug("awakeCommonsConfigurator.getConnection() exception: " + e.toString()); connection = null; } boolean isAllowed = awakeFileConfigurator.allowCallAfterAnalysis( username, connection, methodName, valuesList); if (!isAllowed) { String ipAddress = request.getRemoteAddr(); // Run the runIfCallDisallowed() configured by the user awakeFileConfigurator.runIfCallRefused(username, connection, ipAddress, methodName, valuesList); throw new SecurityException( Tag.AWAKE_SECURITY + "Method not authorized for execution by Security Checker : " + methodName + " parameters: " + valuesList.toString()); } Object theObject = c.newInstance(); String rawMethodName = StringUtils.substringAfterLast(methodName, "."); // Invoke the method Method main = c.getDeclaredMethod(rawMethodName, argTypes); Object 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 AwakeFileSession.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) { AwakeServerLogger.log(s); } } }