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

org.kawanfw.file.api.client.RemoteSession 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.

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

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.MalformedURLException;
import java.net.PasswordAuthentication;
import java.net.Proxy;
import java.net.SocketException;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Vector;
import java.util.logging.Level;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.kawanfw.commons.api.client.InvalidLoginException;
import org.kawanfw.commons.api.client.RemoteException;
import org.kawanfw.commons.api.client.SessionParameters;
import org.kawanfw.commons.client.http.HttpTransfer;
import org.kawanfw.commons.client.http.HttpTransferUtil;
import org.kawanfw.commons.client.http.SimpleNameValuePair;
import org.kawanfw.commons.json.ListOfStringTransport;
import org.kawanfw.commons.util.ClientLogger;
import org.kawanfw.commons.util.FrameworkDebug;
import org.kawanfw.commons.util.HtmlConverter;
import org.kawanfw.commons.util.StringUtil;
import org.kawanfw.commons.util.Tag;
import org.kawanfw.file.util.parms.Action;
import org.kawanfw.file.util.parms.Parameter;
import org.kawanfw.file.util.parms.ReturnCode;
import org.kawanfw.file.version.FileVersion;

/**
 * Main class for establishing an http session with a remote host.
 * 

* Also allows the execution of some basic operations: *

    *
  • Get the Java version of the servlet container on the remote server.
  • *
  • Call remote Java methods.
  • *
  • Upload files by wrapping bytes copy from a {@code FileInputStream} to a * {@link RemoteOutputStream}.
  • *
  • Download files by wrapping bytes copy from a {@link RemoteInputStream} to * a {@code FileOutputStream}.
  • *
  • Returns with one call the length of a list of files located on the remote * host.
  • *
*
* Note that main operations on remote files are done using {@link RemoteFile} * class whose method names, signatures and roles are equivalent to those of * {@code File} class. *

* Example:

* *
 * // Define URL of the path to the {@code ServerFileManager} servlet
 * String url = "https://www.acme.org/ServerFileManager";
 * 
 * // The login info for strong authentication on server side:
 * String username = "myUsername";
 * char[] password = { 'm', 'y', 'P', 'a', 's', 's', 'w', 'o', 'r', 'd' };
 * 
 * // Establish a session with the remote server
 * RemoteSession remoteSession = new RemoteSession(url, username, password);
 * 
 * // OK: upload a file
 * remoteSession.upload(new File("c:\\myFile.txt"), "/home/mylogin/myFile.txt");
 * 
* *
*

* Communication via a proxy server is done using * {@code java.net.Proxy} and {@code java.net.PasswordAuthentication} for * authentication. * *

* *
	String url = "http://www.acme.org/ServerFileManager";
	String username = "myUsername";
	char[] password = "myPassword".toCharArray();

	Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(
		    "proxyHostname", 8080));
	    
	PasswordAuthentication passwordAuthentication = null;
	
	// If proxy requires authentication:
	passwordAuthentication = new PasswordAuthentication("proxyUsername", "proxyPassword".toCharArray());
	
	RemoteSession remoteSession = new RemoteSession(url, username,
		password, proxy, passwordAuthentication);
	// Etc.
 * 
* *
* *

* NTLM authentication is done using {@code PasswordAuthentication}: * *

* *
	String url = "http://www.acme.org/ServerFileManager";
	String username = "myUsername";
	char[] password = "myPassword".toCharArray();

	Proxy proxy = Proxy.NO_PROXY;
	
	// DOMAIN is passed along username:
	PasswordAuthentication passwordAuthentication = new PasswordAuthentication("DOMAIN\\username", "password".toCharArray());
	
	RemoteSession remoteSession = new RemoteSession(url, username,
		password, proxy, passwordAuthentication);
	// Etc.
 * 
* *
* * @see org.kawanfw.file.api.client.RemoteFile * @see org.kawanfw.file.api.client.RemoteInputStream * @see org.kawanfw.file.api.client.RemoteOutputStream * * @author Nicolas de Pomereu * @since 1.0 */ public class RemoteSession implements Cloneable { static final String REMOTE_SESSION_IS_CLOSED = "RemoteSession is closed."; /** For debug info */ private static boolean DEBUG = FrameworkDebug.isSet(RemoteSession.class); /** Defines 1 kilobyte */ public static final int KB = 1024; /** Defines 1 megabyte */ public static final int MB = 1024 * KB; /** Defines if we must use base64 or html encode when using call() */ private static boolean USE_HTML_ENCODING = true; /** The url to use to connectet to the Awake FILE Server */ private String url = null; /** * The username is stored in static memory to be passed to upload file * servlet */ private String username = null; /** * Token is stored in static to be available during all session and contains * SHA-1(userId + ServerClientLogin.SECRET_FOR_LOGIN) computed by server. * Token is re-send and checked at each send or recv command to be sure user * is authenticated. */ private String authenticationToken = null; /** Proxy to use with HttpUrlConnection */ private Proxy proxy = null; /** For authenticated proxy */ private PasswordAuthentication passwordAuthentication = null; /** The Http Parameters instance */ private SessionParameters sessionParameters = null; /** The http transfer instance */ private HttpTransfer httpTransfer = null; /** The remote Java version */ private String remoteJavaVersion = null; /** * Says if we want to use base64 encoding for parameters passed to call() - * This is a method for legacy applications prior to v1.0. */ public static void setUseBase64EncodingForCall() { USE_HTML_ENCODING = false; } /** * Private constructor for clone(). * * @param url * the URL of the path to the {@code ServerFileManager} Servlet * @param username * the username for authentication on the Awake Server (may be * null for call() or downloadUrl()) * @param authenticationToken * the actual token of the Awake FILE session to clone * @param proxy * the proxy to use, may be null for direct access * @param passwordAuthentication * the proxy credentials, null if no proxy or if the proxy does * not require authentication * @param sessionParameters * the http parameters to use * @param remoteJavaVersion * the Java version on remote server */ private RemoteSession(String url, String username, String authenticationToken, Proxy proxy, PasswordAuthentication passwordAuthentication, SessionParameters sessionParameters, String remoteJavaVersion) { this.url = url; this.username = username; this.authenticationToken = authenticationToken; this.proxy = proxy; this.passwordAuthentication = passwordAuthentication; this.sessionParameters = sessionParameters; this.remoteJavaVersion = remoteJavaVersion; httpTransfer = HttpTransferUtil.HttpTransferFactory(url, proxy, passwordAuthentication, sessionParameters); } /** * Creates an Awake FILE session with a proxy and protocol parameters. * * @param url * the URL of the path to the {@code ServerFileManager} Servlet * @param username * the username for authentication on the Awake Server (may be * null for call() * @param password * the user password for authentication on the Awake Server (may * be null) * @param proxy * the proxy to use, may be null for direct access * @param passwordAuthentication * the proxy credentials, null if no proxy or if the proxy does * not require authentication * @param sessionParameters * the session parameters to use (may be null) * * @throws MalformedURLException * if the url is malformed * @throws UnknownHostException * if host URL (http://www.acme.org) does not exists or no * Internet Connection. * @throws ConnectException * if the Host is correct but the {@code ServerFileManager} * Servlet is not reachable * (http://www.acme.org/ServerFileManager) and access failed * with a status != OK (200). (If the host is incorrect, or is * impossible to connect to - Tomcat down - the * {@code ConnectException} will be the sub exception * {@code HttpHostConnectException}.) * @throws SocketException * if network failure during transmission * @throws InvalidLoginException * the username or password is invalid * @throws SecurityException * Scheme is required to be https (SSL/TLS) * @throws RemoteException * an exception has been thrown on the server side. This traps * an Awake product failure and should not happen. * @throws IOException * for all other IO / Network / System Error */ public RemoteSession(String url, String username, char[] password, Proxy proxy, PasswordAuthentication passwordAuthentication, SessionParameters sessionParameters) throws MalformedURLException, UnknownHostException, ConnectException, SocketException, InvalidLoginException, RemoteException, SecurityException, IOException { if (url == null) { throw new MalformedURLException("url is null!"); } @SuppressWarnings("unused") URL asUrl = new URL(url); // Try to raise a MalformedURLException; this.username = username; this.url = url; this.proxy = proxy; this.passwordAuthentication = passwordAuthentication; this.sessionParameters = sessionParameters; // username & password may be null: for call() if (username == null) { return; } // Launch the Servlet httpTransfer = HttpTransferUtil.HttpTransferFactory(url, proxy, passwordAuthentication, sessionParameters); // TestReload if SSL required by host if (this.url.toLowerCase().startsWith("http://") && isForceHttps()) { throw new SecurityException( Tag.PRODUCT_SECURITY + " Remote Host requires a SSL url that starts with \"https\" scheme"); } String passwordStr = new String(password); // Prepare the request parameters List requestParams = new Vector(); requestParams.add(new SimpleNameValuePair(Parameter.TEST_CRYPTO, Parameter.TEST_CRYPTO)); requestParams.add(new SimpleNameValuePair(Parameter.ACTION, Action.LOGIN_ACTION)); requestParams .add(new SimpleNameValuePair(Parameter.USERNAME, username)); requestParams.add(new SimpleNameValuePair(Parameter.PASSWORD, passwordStr)); httpTransfer.send(requestParams); // If everything is OK, we have in our protocol a response that // 1) starts with "OK". 2) Is followed by the Authentication Token // else: response starts with "INVALID_LOGIN_OR_PASSWORD". String receive = httpTransfer.recv(); debug("receive: " + receive); if (receive.startsWith(ReturnCode.INVALID_LOGIN_OR_PASSWORD)) { throw new InvalidLoginException("Invalid username or password."); } else if (receive.startsWith(ReturnCode.OK)) { // OK! We are logged in & and correctly authenticated // Keep in static memory the Authentication Token for next api // commands (First 20 chars) String theToken = receive.substring(ReturnCode.OK.length() + 1); authenticationToken = StringUtils.left(theToken, Parameter.TOKEN_LEFT_SIZE); } else { this.username = null; // Should never happen throw new InvalidLoginException(Tag.PRODUCT_PRODUCT_FAIL + " Please contact support."); } } /** * Creates an Awake FILE session with a proxy. * * @param url * the URL of the path to the {@code ServerFileManager} Servlet * @param username * the username for authentication on the Awake Server (may be * null for call() * @param password * the user password for authentication on the Awake Server (may * be null) * @param proxy * the proxy to use, may be null for direct access * @param passwordAuthentication * the proxy credentials, null if no proxy or if the proxy does * not require authentication * * @throws MalformedURLException * if the url is malformed * @throws UnknownHostException * if host URL (http://www.acme.org) does not exists or no * Internet Connection. * @throws ConnectException * if the Host is correct but the {@code ServerFileManager} * Servlet is not reachable * (http://www.acme.org/ServerFileManager) and access failed * with a status != OK (200). (If the host is incorrect, or is * impossible to connect to - Tomcat down - the * {@code ConnectException} will be the sub exception * {@code HttpHostConnectException}.) * @throws SocketException * if network failure during transmission * @throws InvalidLoginException * the username or password is invalid * @throws SecurityException * scheme is required to be https (SSL/TLS) * @throws RemoteException * an exception has been thrown on the server side * @throws IOException * for all other IO / Network / System Error */ public RemoteSession(String url, String username, char[] password, Proxy proxy, PasswordAuthentication passwordAuthentication) throws MalformedURLException, UnknownHostException, ConnectException, SocketException, InvalidLoginException, RemoteException, SecurityException, IOException { this(url, username, password, proxy, passwordAuthentication, null); } /** * Creates an Awake FILE session. * * @param url * the URL of the path to the {@code ServerFileManager} Servlet * @param username * the username for authentication on the Awake Server (may be * null for call() * @param password * the user password for authentication on the Awake Server (may * be null) * * @throws MalformedURLException * if the url is malformed * @throws UnknownHostException * if host URL (http://www.acme.org) does not exists or no * Internet Connection. * @throws ConnectException * if the Host is correct but the {@code ServerFileManager} * Servlet is not reachable * (http://www.acme.org/ServerFileManager) and access failed * with a status != OK (200). (If the host is incorrect, or is * impossible to connect to - Tomcat down - the * {@code ConnectException} will be the sub exception * {@code HttpHostConnectException}.) * @throws SocketException * if network failure during transmission * @throws InvalidLoginException * the username or password is invalid * @throws SecurityException * scheme is required to be https (SSL/TLS) * @throws RemoteException * an exception has been thrown on the server side * @throws IOException * for all other IO / Network / System Error */ public RemoteSession(String url, String username, char[] password) throws MalformedURLException, UnknownHostException, ConnectException, SocketException, InvalidLoginException, RemoteException, IOException, SecurityException { this(url, username, password, null, null); } /** * Returns the username of this Awake FILE session * * @return the username of this Awake FILE session */ public String getUsername() { return this.username; } /** * Returns the {@code SessionParameters} instance in use for the Awake FILE * session. * * @return the {@code SessionParameters} instance in use for the Awake FILE * session */ public SessionParameters getSessionParameters() { return this.sessionParameters; } /** * Returns the URL of the path to the ServerFileManager Servlet * (or ServerSqlManager Servlet if session has been initiated * by a RemoteConnection). * * @return the URL of the path to the ServerFileManager Servlet */ public String getUrl() { return url; } /** * Returns the {@code Proxy} instance in use for this File Session. * * @return the {@code Proxy} instance in use for this File Session */ public Proxy getProxy() { return this.proxy; } /** * Returns the proxy credentials * * @return the proxy credentials */ public PasswordAuthentication getPasswordAuthentication() { return passwordAuthentication; } /** * Returns the http status code of the last executed verb * * @return the http status code of the last executed verb */ public int getHttpStatusCode() { if (httpTransfer != null) { return httpTransfer.getHttpStatusCode(); } else { return 0; } } /** * Returns the Authentication Token. This method is used by the Kawansoft * frameworks. * * @return the Authentication Token */ public String getAuthenticationToken() { return this.authenticationToken; } /** * Calls a remote Java method and (eventually) pass some parameters to it. * * @param methodName * the full method name to call in the format * org.acme.config.package.MyClass.myMethod * @param params * the array of parameters passed to the method * * @return the result of the Java call as {@code String} * * @throws IllegalArgumentException * if methodName is null * @throws InvalidLoginException * the session has been closed by a {@code logoff()} * * @throws UnknownHostException * if host URL (http://www.acme.org) does not exists or no * Internet Connection. * @throws ConnectException * if the Host is correct but the {@code ServerFileManager} * Servlet is not reachable * (http://www.acme.org/ServerFileManager) and access failed * with a status != OK (200). (If the host is incorrect, or is * impossible to connect to - Tomcat down - the * {@code ConnectException} will be the sub exception * {@code HttpHostConnectException}.) * @throws SocketException * if network failure during transmission * @throws RemoteException * an exception has been thrown on the server side * @throws IOException * for all other IO / Network / System Error * */ public String call(String methodName, Object... params) throws IllegalArgumentException, InvalidLoginException, UnknownHostException, ConnectException, SocketException, RemoteException, IOException { // For legacy methods if (!USE_HTML_ENCODING) { return callBase64Encoded(methodName, params); } // Class and method name can not be null if (methodName == null) { throw new IllegalArgumentException("methodName can not be null!"); } // username & Authentication Token may be null // because some methods can be called freely if (username == null) { username = "null"; } if (authenticationToken == null) { authenticationToken = "null"; } // Build the params types List paramsTypes = new Vector(); // Build the params values List paramsValues = new Vector(); debug(""); for (int i = 0; i < params.length; i++) { if (params[i] == null) { throw new IllegalArgumentException( Tag.PRODUCT + " null values are not supported. Please provide a value for all parameters."); } else { String classType = params[i].getClass().getName(); // NO! can alter class name if value is obsfucated // classType = StringUtils.substringAfterLast(classType, "."); paramsTypes.add(classType); String value = params[i].toString(); debug(""); debug("classType: " + classType); debug("value : " + value); paramsValues.add(value); } } // ListHolder listHolderTypes = new ListHolder(); // listHolderTypes.setList(paramsTypes); String jsonParamTypes = ListOfStringTransport.toJson(paramsTypes); // ListHolder listHolderValues = new ListHolder(); // listHolderValues.setList(paramsValues); String jsonParamValues = ListOfStringTransport.toJson(paramsValues); debug("methodName : " + methodName); debug("jsonParamTypes : " + jsonParamTypes); debug("jsonParamValues: " + jsonParamValues); // Prepare the request parameters List requestParams = new Vector(); requestParams.add(new SimpleNameValuePair(Parameter.ACTION, Action.CALL_ACTION_HTML_ENCODED)); requestParams .add(new SimpleNameValuePair(Parameter.USERNAME, username)); requestParams.add(new SimpleNameValuePair(Parameter.TOKEN, authenticationToken)); requestParams.add(new SimpleNameValuePair(Parameter.METHOD_NAME, methodName)); requestParams.add(new SimpleNameValuePair(Parameter.PARAMS_TYPES, jsonParamTypes)); requestParams.add(new SimpleNameValuePair(Parameter.PARAMS_VALUES, jsonParamValues)); httpTransfer.send(requestParams); // Return the answer String response = httpTransfer.recv(); debug("response: " + response); // Content is OK if (response.startsWith(ReturnCode.INVALID_LOGIN_OR_PASSWORD)) { throw new InvalidLoginException(REMOTE_SESSION_IS_CLOSED); } // The response is in Html encode: if (!response.isEmpty()) { response = HtmlConverter.fromHtml(response); } return response; } /** * Returns with one call the length of a list of files located on the remote * host. *

* This convenient methods is provided for fast compute of the total length * of a list of files to download, without contacting the server for each * file result. (Case using a progress monitor). *

* The real paths of the remote files depend on the Awake FILE configuration * on the server. See User Documentation. * * @param pathnames * the list of pathnames on host with "/" as file separator. Must * be absolute. * * @return the total length in bytes of the files located on the remote * host. * * @throws IllegalArgumentException * if pathnames is null * @throws InvalidLoginException * the session has been closed by a {@code logoff()} * * @throws UnknownHostException * if the host URL (http://www.acme.org) does not exists or no * Internet Connection. * @throws ConnectException * if the Host is correct but the {@code ServerFileManager} * Servlet is not reachable * (http://www.acme.org/ServerFileManager) and access failed * with a status != OK (200). (If the host is incorrect, or is * impossible to connect to - Tomcat down - the * {@code ConnectException} will be the sub exception * {@code HttpHostConnectException}.) * @throws SocketException * if network failure during transmission * @throws RemoteException * an exception has been thrown on the server side * @throws IOException * for all other IO / Network / System Error */ public long length(List pathnames) throws IllegalArgumentException, InvalidLoginException, UnknownHostException, ConnectException, SocketException, RemoteException, IOException { if (pathnames == null) { throw new IllegalArgumentException("pathnames can not be null!"); } if (username == null || authenticationToken == null) { throw new InvalidLoginException(REMOTE_SESSION_IS_CLOSED); } pathnames = HtmlConverter.toHtml(pathnames); String jsonString = ListOfStringTransport.toJson(pathnames); // Prepare the request parameters List requestParams = new Vector(); requestParams.add(new SimpleNameValuePair(Parameter.ACTION, Action.GET_FILE_LENGTH_ACTION)); requestParams .add(new SimpleNameValuePair(Parameter.USERNAME, username)); requestParams.add(new SimpleNameValuePair(Parameter.TOKEN, authenticationToken)); requestParams.add(new SimpleNameValuePair(Parameter.FILENAME, jsonString)); httpTransfer.send(requestParams); // If everything is OK, we have in our protocol a response that // 1) starts with "OK". 2) Is followed by the Authentication Token // else: response starts with "INVALID_LOGIN_OR_PASSWORD". String response = httpTransfer.recv(); if (response.startsWith(ReturnCode.INVALID_LOGIN_OR_PASSWORD)) { throw new InvalidLoginException(REMOTE_SESSION_IS_CLOSED); } else { try { long fileLength = Long.parseLong(response); return fileLength; } catch (NumberFormatException nfe) { // Build an Awake Exception with the content of the recv stream throw new IOException(Tag.PRODUCT_PRODUCT_FAIL + " " + nfe.getMessage(), nfe); } } } /** * Downloads a file from the remote server.
* This method simply wraps bytes copy from a {@link RemoteInputStream} to a * {@code FileOutputStream}. *

* The real path of the remote file depends on the Awake FILE configuration * on the server. See User Documentation. *

* Large files are split in chunks that are downloaded in sequence. The * default chunk length is 10Mb. You can change the default value with * {@link SessionParameters#setDownloadChunkLength(long)} before passing * {@code SessionParameters} to this class constructor. *

* Note that file chunking requires that all chunks be downloaded from to * the same web server. Thus, file chunking does not support true stateless * architecture with multiple identical web servers. If you want to set a * full stateless architecture with multiple identical web servers, you must * disable file chunking. This is done by setting a 0 download chunk length * value using {@link SessionParameters#setDownloadChunkLength(long)}.
*
* A recovery mechanism allows - in case of failure - to start again in the * same JVM run the file download from the last non-downloaded chunk. See * User Guide for more information.
*
* Note that this method can not be used with a progress indicator/monitor * and so does not implement any increment mechanism. The reason is dual: *

    *
  • Implementing an increment mechanism would require to add cumbersome * API.
  • *
  • Wrapped classes {@link RemoteInputStream} and * {@code FileOutputStream} allow easy implementation of progress * indicators. See Tutorial and included examples.
  • *
* * @param pathname * the pathname on host with "/" as file separator. Must be * absolute. * @param file * the file to create on the client side * @throws IllegalArgumentException * if file or pathname is null * @throws InvalidLoginException * the session has been closed by a {@code logoff()} * @throws FileNotFoundException * if the remote file is not found on server * @throws UnknownHostException * if host URL (http://www.acme.org) does not exists or no * Internet Connection. * @throws ConnectException * if the Host is correct but the {@code ServerFileManager} * Servlet is not reachable * (http://www.acme.org/ServerFileManager) and access failed * with a status != OK (200). (If the host is incorrect, or is * impossible to connect to - Tomcat down - the * {@code ConnectException} will be the sub exception * {@code HttpHostConnectException}.) * @throws SocketException * if network failure during transmission * @throws RemoteException * an exception has been thrown on the server side * @throws IOException * for all other IO / Network / System Error */ public void download(String pathname, File file) throws IllegalArgumentException, InvalidLoginException, FileNotFoundException, UnknownHostException, ConnectException, SocketException, RemoteException, IOException { if (pathname == null) { throw new IllegalArgumentException("pathname can not be null!"); } if (file == null) { throw new IllegalArgumentException("file can not be null!"); } if (getUsername() == null || getAuthenticationToken() == null) { throw new InvalidLoginException( RemoteSession.REMOTE_SESSION_IS_CLOSED); } InputStream in = null; OutputStream out = null; // (IOUtils is a general IO stream manipulation utilities // provided by Apache Commons IO) try { in = new RemoteInputStream(this, pathname); out = new BufferedOutputStream(new FileOutputStream(file)); IOUtils.copy(in, out); // Cleaner to close in here so that no Exception is thrown in // finally clause in.close(); } finally { IOUtils.closeQuietly(in); IOUtils.closeQuietly(out); } } /** * Uploads a file on the server.
* This method simply wraps bytes copy from a {@code FileInputStream} to a * {@link RemoteOutputStream}. *

* The real path of the remote file depends on the Awake FILE configuration * on the server. See User Documentation. *

* Large files are split in chunks that are uploaded in sequence. The * default chunk length is 10Mb. You can change the default value with * {@link SessionParameters#setUploadChunkLength(long)} before passing * {@code SessionParameters} to this class constructor. *

* Note that file chunking requires all chunks to be sent to the same web * server that will aggregate the chunks after the last send. Thus, file * chunking does not support true stateless architecture with multiple * identical web servers. If you want to set a full stateless architecture * with multiple identical web servers, you must disable file chunking. This * is done by setting a 0 upload chunk length value using * {@link SessionParameters#setUploadChunkLength(long)}.
*
* A recovery mechanism allows - in case of failure - to start again in the * same JVM run the file upload from the last non-uploaded chunk. See User * Guide for more information.
*
* Note that this method can not be used with a progress indicator/monitor * and so does not implement any increment mechanism. The reason is dual: *

    *
  • Implementing an increment mechanism would require to add cumbersome * API.
  • *
  • Wrapped classes {@code FileInputStream} and * {@link RemoteOutputStream} allow easy implementation of progress * indicators. See Tutorial and included examples.
  • *
* * @param file * the file to upload * @param pathname * the pathname on host with "/" as file separator. Must be * absolute. * @throws IllegalArgumentException * if file or pathname is null * @throws InvalidLoginException * the session has been closed by a {@code logoff()} * @throws FileNotFoundException * if the file to upload is not found * @throws UnknownHostException * if host URL (http://www.acme.org) does not exists or no * Internet Connection. * @throws ConnectException * if the Host is correct but the {@code ServerFileManager} * Servlet is not reachable * (http://www.acme.org/ServerFileManager) and access failed * with a status != OK (200). (If the host is incorrect, or is * impossible to connect to - Tomcat down - the * {@code ConnectException} will be the sub exception * {@code HttpHostConnectException}.) * @throws SocketException * if network failure during transmission * @throws RemoteException * an exception has been thrown on the server side * @throws IOException * for all other IO / Network / System Error * */ public void upload(File file, String pathname) throws IllegalArgumentException, InvalidLoginException, FileNotFoundException, UnknownHostException, ConnectException, SocketException, RemoteException, IOException { if (pathname == null) { throw new IllegalArgumentException("pathname can not be null!"); } if (file == null) { throw new IllegalArgumentException("file can not be null!"); } if (!file.exists()) { throw new FileNotFoundException("File does not exists: " + file); } if (getUsername() == null || getAuthenticationToken() == null) { throw new InvalidLoginException( RemoteSession.REMOTE_SESSION_IS_CLOSED); } InputStream in = null; OutputStream out = null; // (IOUtils is a general IO stream manipulation utilities // provided by Apache Commons IO) try { in = new BufferedInputStream(new FileInputStream(file)); out = new RemoteOutputStream(this, pathname, file.length()); IOUtils.copy(in, out); // Cleaner to close out here so that no Exception is thrown in // finally clause out.close(); } finally { IOUtils.closeQuietly(in); IOUtils.closeQuietly(out); } } /** * Returns the Java version of the the servlet container on the remote * server
* (The value of {@code System.getProperty("java.version")}. * * @return the Java version of the the servlet container on the remote * server * * @throws InvalidLoginException * the session has been closed by a {@code logoff()} * * @throws UnknownHostException * if the host URL (http://www.acme.org) does not exists or no * Internet Connection. * @throws ConnectException * if the Host is correct but the {@code ServerFileManager} * Servlet is not reachable * (http://www.acme.org/ServerFileManager) and access failed * with a status != OK (200). (If the host is incorrect, or is * impossible to connect to - Tomcat down - the * {@code ConnectException} will be the sub exception * {@code HttpHostConnectException}.) * @throws SocketException * if network failure during transmission * @throws RemoteException * an exception has been thrown on the server side * @throws IOException * for all other IO / Network / System Error */ public String getRemoteJavaVersion() throws InvalidLoginException, UnknownHostException, ConnectException, SocketException, RemoteException, IOException { if (username == null || authenticationToken == null) { throw new InvalidLoginException(REMOTE_SESSION_IS_CLOSED); } // Remote Java verdion is cached if (remoteJavaVersion != null) { return remoteJavaVersion; } // Prepare the request parameters List requestParams = new Vector(); requestParams.add(new SimpleNameValuePair(Parameter.ACTION, Action.GET_JAVA_VERSION)); requestParams .add(new SimpleNameValuePair(Parameter.USERNAME, username)); requestParams.add(new SimpleNameValuePair(Parameter.TOKEN, authenticationToken)); httpTransfer.send(requestParams); // If everything is OK, we have in our protocol a response that // 1) starts with "OK". 2) Is followed by the Authentication Token // else: response starts with "INVALID_LOGIN_OR_PASSWORD". String response = httpTransfer.recv(); if (response.startsWith(ReturnCode.INVALID_LOGIN_OR_PASSWORD)) { throw new InvalidLoginException(REMOTE_SESSION_IS_CLOSED); } else { remoteJavaVersion = response; return remoteJavaVersion; } } /** * Allows to get a copy of the current RemoteSession: use it to * do some simultaneous operations in a different thread (in order to avoid * conflicts). */ @Override public RemoteSession clone() { RemoteSession remoteSession = new RemoteSession(this.url, this.username, this.authenticationToken, this.proxy, this.passwordAuthentication, this.sessionParameters, this.remoteJavaVersion); return remoteSession; } /** * Returns the Awake FILE Version. * * @return the Awake FILE Version */ public String getVersion() { return FileVersion.getVersion(); } /** * Logs off from the remote host.  This will purge the authentication * values necessary for method calls. *

* Method should be called at the closure of the Client application. */ public void logoff() { username = null; authenticationToken = null; proxy = null; passwordAuthentication = null; sessionParameters = null; remoteJavaVersion = null; if (httpTransfer != null) { httpTransfer.close(); httpTransfer = null; } } /** * Returns the HttpTransfer instance in use * * @return the httpTransfer instance */ HttpTransfer getHttpTransfer() { return httpTransfer; } /** * * Tests if remote host requires our URL to be SSL * * @return true if the host requires SSL * * @throws UnknownHostException * @throws ConnectException * @throws RemoteException * @throws SecurityException * @throws IOException */ private boolean isForceHttps() throws UnknownHostException, ConnectException, RemoteException, SecurityException, IOException { // Prepare the request parameters List requestParams = new Vector(); requestParams.add(new SimpleNameValuePair(Parameter.ACTION, Action.BEFORE_LOGIN_ACTION)); httpTransfer.send(requestParams); // If everything is OK, we have in our protocol a response that // 1) starts with "OK". 2) Is followed by the Authentication Token // else: response starts with "INVALID_LOGIN_OR_PASSWORD". String receive = httpTransfer.recv(); Boolean isForceHttps = new Boolean(receive); return isForceHttps.booleanValue(); } /** * Calls a remote Java {@code class.method} and (eventually) pass some * parameters to it. This method transforms the values in Base64. It's a * legacy method not to be used anymore: use {@code call} instead. * * @param methodName * the full method name to call in the format * org.acme.config.package.MyClass.myMethod * @param params * the array of parameters passed to the method * @return the result of the Java call as string * * @throws IllegalArgumentException * if methodName is null * @throws InvalidLoginException * the session has been closed by a {@code logoff()} * * @throws UnknownHostException * if host URL (http://www.acme.org) does not exists or no * Internet Connection. * @throws ConnectException * if the Host is correct but the {@code ServerFileManager} * Servlet is not reachable * (http://www.acme.org/ServerFileManager) and access failed * with a status != OK (200). (If the host is incorrect, or is * impossible to connect to - Tomcat down - the * {@code ConnectException} will be the sub exception * {@code HttpHostConnectException}.) * @throws SocketException * if network failure during transmission * @throws RemoteException * an exception has been thrown on the server side * @throws IOException * for all other IO / Network / System Error * */ private String callBase64Encoded(String methodName, Object... params) throws IllegalArgumentException, InvalidLoginException, UnknownHostException, ConnectException, SocketException, RemoteException, IOException { // Class and method name can not be null if (methodName == null) { throw new IllegalArgumentException("methodName can not be null!"); } // username & Authentication Token may be null // because some methods can be called freely if (username == null) { username = "null"; } if (authenticationToken == null) { authenticationToken = "null"; } // Build the params types List paramsTypes = new Vector(); // Build the params values List paramsValues = new Vector(); debug(""); for (int i = 0; i < params.length; i++) { if (params[i] == null) { throw new IllegalArgumentException( Tag.PRODUCT + " null values are not supported. Please provide a value for all parameters."); } else { String classType = params[i].getClass().getName(); // NO! can alter class name if value is obsfucated // classType = StringUtils.substringAfterLast(classType, "."); paramsTypes.add(classType); String value = params[i].toString(); debug(""); debug("classType: " + classType); debug("value : " + value); paramsValues.add(value); } } // ListHolder listHolderTypes = new ListHolder(); // listHolderTypes.setList(paramsTypes); String jsonParamTypes = ListOfStringTransport.toJson(paramsTypes); // ListHolder listHolderValues = new ListHolder(); // listHolderValues.setList(paramsValues); String jsonParamValues = ListOfStringTransport.toJson(paramsValues); debug("methodName : " + methodName); debug("jsonParamTypes : " + jsonParamTypes); debug("jsonParamValues: " + jsonParamValues); // Prepare the request parameters List requestParams = new Vector(); requestParams.add(new SimpleNameValuePair(Parameter.ACTION, Action.CALL_ACTION)); // requestParams.add(new SimpleNameValuePair(Parameter.LOGIN, // StringUtil.toBase64(username))); requestParams .add(new SimpleNameValuePair(Parameter.USERNAME, username)); requestParams.add(new SimpleNameValuePair(Parameter.TOKEN, authenticationToken)); requestParams.add(new SimpleNameValuePair(Parameter.METHOD_NAME, methodName)); requestParams.add(new SimpleNameValuePair(Parameter.PARAMS_TYPES, StringUtil.toBase64(jsonParamTypes))); requestParams.add(new SimpleNameValuePair(Parameter.PARAMS_VALUES, StringUtil.toBase64(jsonParamValues))); httpTransfer.send(requestParams); // Return the answer String response = httpTransfer.recv(); debug("response: " + response); // Content is OK if (response.startsWith(ReturnCode.INVALID_LOGIN_OR_PASSWORD)) { throw new InvalidLoginException(REMOTE_SESSION_IS_CLOSED); } // The response is in Base 64 try { if (!response.isEmpty()) { response = StringUtil.fromBase64(response); } } catch (Exception e) { debug(response); // May happen till new Awake FILE is not deployed on Server throw new IOException(Tag.PRODUCT_PRODUCT_FAIL + " Response must be and is not base64!", e); } return response; } /* * (non-Javadoc) * * @see java.lang.Object#hashCode() */ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((authenticationToken == null) ? 0 : authenticationToken .hashCode()); result = prime * result + ((url == null) ? 0 : url.hashCode()); result = prime * result + ((username == null) ? 0 : username.hashCode()); return result; } /* * (non-Javadoc) * * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; RemoteSession other = (RemoteSession) obj; if (authenticationToken == null) { if (other.authenticationToken != null) return false; } else if (!authenticationToken.equals(other.authenticationToken)) return false; if (url == null) { if (other.url != null) return false; } else if (!url.equals(other.url)) return false; if (username == null) { if (other.username != null) return false; } else if (!username.equals(other.username)) return false; return true; } /* * (non-Javadoc) * * @see java.lang.Object#toString() */ @Override public String toString() { return "RemoteSession [url=" + url + ", username=" + username + ", proxy=" + proxy + ", passwordAuthentication=" + passwordAuthentication + ", SessionParameters=" + sessionParameters + "]"; } /** * debug tool */ private void debug(String s) { if (DEBUG) { ClientLogger.getLogger().log(Level.WARNING, s); } } } // End





© 2015 - 2025 Weber Informatics LLC | Privacy Policy