ch.tatool.app.export.ServerDataExporter.java Source code

Java tutorial

Introduction

Here is the source code for ch.tatool.app.export.ServerDataExporter.java

Source

/*******************************************************************************
 * Copyright (c) 2011 Michael Ruflin, Andr Locher, Claudia von Bastian.
 * Copyright (c) 2012 Laura Chan.
 * 
 * This file is part of Tatool.
 * 
 * Tatool 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 3 of the License, or 
 * (at your option) any later version.
 * 
 * Tatool 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 Tatool. If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/
package ch.tatool.app.export;

import java.awt.Component;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.nio.charset.Charset;
import java.util.Map;

import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ch.tatool.app.gui.MessagesImpl;
import ch.tatool.data.Module;
import ch.tatool.export.DataExporterError;

/**
 * Uploads module data to a server.
 * This class works together with the HitC (which represents the server side
 * part of the connection).
 * 
 * @author Michael Ruflin
 * @author Laura Chan (HitC modifications)
 */
public class ServerDataExporter extends DataExporterImpl {

    Logger logger = LoggerFactory.getLogger(ServerDataExporter.class);

    /** Username used to export the data (used for server authentication). */
    public static final String PROPERTY_EXPORT_USERNAME = "username";

    /** Password used to export the data (used for server authentication). */
    public static final String PROPERTY_EXPORT_PASSWORD = "password";

    public String url;

    public MessagesImpl messages;

    public DataExporterError exporterError;

    public ServerDataExporter() {
        super();
    }

    public String exportData(Component parentFrame, Module module, int fromSessionIndex,
            DataExporterError exporterError) {

        this.exporterError = exporterError;

        CSVTrialDataExport csvTrialExport = new CSVTrialDataExport(dataService);
        csvTrialExport.setCSVParameters(';');
        File tmpTrialFile = csvTrialExport.exportData(module, fromSessionIndex);

        // don't do anything if no files got exported
        if (tmpTrialFile == null) {
            this.exporterError.setErrorType(DataExporterError.GENERAL_NO_DATA);
            return "Reason: No data to export";
        }

        // get the httpentity containing the data
        HttpEntity httpEntity = getHttpEntity(module, fromSessionIndex, "trialData", tmpTrialFile);

        if (httpEntity == null) {
            this.exporterError.setErrorType(DataExporterError.SERVER_ONLINE_SETUP_MISSING);
            return "Reason: Module is not properly configured for Tatool online.";
        }

        // upload the entity
        String error = uploadFiles(parentFrame, module, httpEntity);

        // delete the temporary file
        tmpTrialFile.delete();

        return error;
    }

    private HttpEntity getHttpEntity(Module module, int fromSessionIndex, String filename, File tmpFile) {
        // we use a multipart entity to send over the files
        MultipartEntity entity = new MultipartEntity();

        // get tatool online information for module
        Map<String, String> moduleProperties = module.getModuleProperties();
        String subjectCode = moduleProperties.get(Module.PROPERTY_MODULE_CODE);
        if (subjectCode == null || subjectCode.isEmpty()) {
            subjectCode = module.getUserAccount().getName();
        }

        String moduleID = moduleProperties.get(Module.PROPERTY_MODULE_ID);

        // InputStreamBody does not provide a content length (-1), so the server complains about the request length not
        // being defined. FileBody does not allow setting the name (which is different from the temp file name
        // Easiest solution: subclass of FileBody that allows overwriting the filename with a new one
        FileBodyExt fileBody = new FileBodyExt(tmpFile);
        fileBody.setFilename(filename);
        entity.addPart("file", fileBody);

        // add some additional data
        try {
            Charset utf8CharSet = Charset.forName("UTF-8");
            entity.addPart("fromSessionIndex", new StringBody(String.valueOf(fromSessionIndex), utf8CharSet));
            entity.addPart("subjectCode", new StringBody(subjectCode, utf8CharSet));
            entity.addPart("moduleID", new StringBody(moduleID, utf8CharSet));
        } catch (UnsupportedEncodingException e) {
            // should not happen
            logger.error("Unable to set write form parts", e);
        } catch (IllegalArgumentException e) {
            // should not happen
            logger.error("Missing settings for tatool online", e);
            return null;
        }

        return entity;
    }

    private String uploadFiles(Component parentFrame, Module module, HttpEntity httpEntity) {
        // get the server upload configuration
        String serverUrl = getUrl();
        if (serverUrl == null) {
            exporterError.setErrorType(DataExporterError.SERVER_ONLINE_URL_MISSING);
            return "Reason: No upload server url defined";
        }
        String username = module.getModuleProperties().get(PROPERTY_EXPORT_USERNAME);
        if (username == null) {
            username = "anonymous";
        }
        String password = module.getModuleProperties().get(PROPERTY_EXPORT_PASSWORD);
        if (password == null) {
            password = "anonymous";
        }

        HttpParams params = new BasicHttpParams();
        HttpConnectionParams.setConnectionTimeout(params, 5000);
        HttpConnectionParams.setSoTimeout(params, 0);

        // Create a httpclient instance
        DefaultHttpClient httpclient = new DefaultHttpClient(params);

        // set the credentials we got (might or might not get used
        //httpclient.getCredentialsProvider().setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));

        // setup a POST call
        HttpPost httpPost = new HttpPost(serverUrl);
        httpPost.setEntity(httpEntity);

        // execute the post and gather the result
        try {
            HttpResponse response = httpclient.execute(httpPost);
            if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
                exporterError.setErrorType(DataExporterError.SERVER_ONLINE_HTTP);
                exporterError.setErrorReason(response.getStatusLine().getReasonPhrase() + " ("
                        + response.getStatusLine().getStatusCode() + ")");
                return "Reason: " + response.getStatusLine().getReasonPhrase() + " ("
                        + response.getStatusLine().getStatusCode() + ")";
            } else {
                // all ok
                String result = IOUtils.toString(response.getEntity().getContent());
                if (logger.isDebugEnabled()) {
                    logger.debug("Upload server response: {}", result);
                }
            }
        } catch (IOException ioe) {
            httpclient.getConnectionManager().shutdown();
            logger.error("Unable to upload data", ioe);
            exporterError.setErrorType(DataExporterError.GENERAL_UNKNOWN);
            exporterError.setErrorReason(ioe.toString() + ": " + ioe.getMessage());
            return "Reason: " + ioe.toString() + ": " + ioe.getMessage();
        } finally {
            // When HttpClient instance is no longer needed, 
            // shut down the connection manager to ensure
            // immediate deallocation of all system resources

            httpclient.getConnectionManager().shutdown();
        }
        return null;
    }

    public static String getStackTrace(Throwable aThrowable) {
        final Writer result = new StringWriter();
        final PrintWriter printWriter = new PrintWriter(result);
        aThrowable.printStackTrace(printWriter);
        return result.toString();
    }

    /**
     * FileBody class that allows setting the filename to use
     */
    class FileBodyExt extends FileBody {
        String fileNameOverwrite = null;

        public FileBodyExt(final File file) {
            super(file);
        }

        public void setFilename(String fileNameOverwrite) {
            this.fileNameOverwrite = fileNameOverwrite;
        }

        public String getFilename() {
            if (fileNameOverwrite != null) {
                return fileNameOverwrite;
            } else {
                return super.getFilename();
            }
        }
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getExporterName() {
        return "Upload";
    }
}