org.kawanfw.file.servlet.ServerCallAction.java Source code

Java tutorial

Introduction

Here is the source code for org.kawanfw.file.servlet.ServerCallAction.java

Source

/*
 * 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);
        }
    }

}