edu.umd.cs.submit.CommandLineSubmit.java Source code

Java tutorial

Introduction

Here is the source code for edu.umd.cs.submit.CommandLineSubmit.java

Source

/**
 * Marmoset: an automated snapshot, submission and testing system
 * Copyright (C) 2005, University of Maryland
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Email: marmoset-discuss@cs.umd.edu
 *
 * Snail mail:
 * The Marmoset Project
 * Attention: Dr. Bill Pugh
 * Dept. of Computer Science
 * Univ. of Maryland
 * College Park, MD 20742
 */

/*
 * Created on Jan 24, 2005
 *
 */
package edu.umd.cs.submit;

import java.awt.Desktop;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.Console;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.util.Collection;
import java.util.Map;
import java.util.Properties;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.contrib.ssl.EasySSLProtocolSocketFactory;
import org.apache.commons.httpclient.methods.MultipartPostMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.multipart.ByteArrayPartSource;
import org.apache.commons.httpclient.methods.multipart.FilePart;
import org.apache.commons.httpclient.protocol.Protocol;

/**
 * @author pugh
 * 
 */
public class CommandLineSubmit {

    public static final String VERSION = "0.9.2";
    public static final int HTTP_TIMEOUT = Integer.getInteger("HTTP_TIMEOUT", 30).intValue() * 1000;

    public static void main(String[] args) {
        try {
            Protocol easyhttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443);
            File home = args.length > 0 ? new File(args[0]) : new File(".");

            Protocol.registerProtocol("easyhttps", easyhttps);
            File submitFile = new File(home, ".submit");
            File submitUserFile = new File(home, ".submitUser");
            File submitIgnoreFile = new File(home, ".submitIgnore");
            File cvsIgnoreFile = new File(home, ".cvsignore");

            if (!submitFile.canRead()) {
                System.out.println("Must perform submit from a directory containing a \".submit\" file");
                System.out.println("No such file found at " + submitFile.getCanonicalPath());
                System.exit(1);
            }

            Properties p = new Properties();
            p.load(new FileInputStream(submitFile));
            String submitURL = p.getProperty("submitURL");
            if (submitURL == null) {
                System.out.println(".submit file does not contain a submitURL");
                System.exit(1);
            }
            String courseName = p.getProperty("courseName");
            String courseKey = p.getProperty("courseKey");
            String semester = p.getProperty("semester");
            String projectNumber = p.getProperty("projectNumber");
            String authenticationType = p.getProperty("authentication.type");
            String baseURL = p.getProperty("baseURL");

            System.out.println("Submitting contents of " + home.getCanonicalPath());
            System.out.println(" as project " + projectNumber + " for course " + courseName);
            FilesToIgnore ignorePatterns = new FilesToIgnore();
            addIgnoredPatternsFromFile(cvsIgnoreFile, ignorePatterns);
            addIgnoredPatternsFromFile(submitIgnoreFile, ignorePatterns);

            FindAllFiles find = new FindAllFiles(home, ignorePatterns.getPattern());
            Collection<File> files = find.getAllFiles();

            boolean createdSubmitUser = false;
            Properties userProps = new Properties();
            if (submitUserFile.canRead()) {
                userProps.load(new FileInputStream(submitUserFile));
            }
            if (userProps.getProperty("cvsAccount") == null && userProps.getProperty("classAccount") == null
                    || userProps.getProperty("oneTimePassword") == null) {
                System.out.println();
                System.out.println(
                        "We need to authenticate you and create a .submitUser file so you can submit your project");

                createSubmitUser(submitUserFile, courseKey, projectNumber, authenticationType, baseURL);
                createdSubmitUser = true;
                userProps.load(new FileInputStream(submitUserFile));
            }

            MultipartPostMethod filePost = createFilePost(p, find, files, userProps);
            HttpClient client = new HttpClient();
            client.setConnectionTimeout(HTTP_TIMEOUT);
            int status = client.executeMethod(filePost);
            System.out.println(filePost.getResponseBodyAsString());
            if (status == 500 && !createdSubmitUser) {
                System.out.println("Let's try reauthenticating you");
                System.out.println();

                createSubmitUser(submitUserFile, courseKey, projectNumber, authenticationType, baseURL);
                userProps.load(new FileInputStream(submitUserFile));
                filePost = createFilePost(p, find, files, userProps);
                client = new HttpClient();
                client.setConnectionTimeout(HTTP_TIMEOUT);
                status = client.executeMethod(filePost);
                System.out.println(filePost.getResponseBodyAsString());
            }
            if (status != HttpStatus.SC_OK) {
                System.out.println("Status code: " + status);
                System.exit(1);
            }
            System.out.println("Submission accepted");
        } catch (Exception e) {
            System.out.println();
            System.out.println("An Error has occured during submission!");
            System.out.println();
            System.out.println("[DETAILS]");
            System.out.println(e.getMessage());
            e.printStackTrace(System.out);
            System.out.println();
        }
    }

    /**
     * @param p
     * @param find
     * @param files
     * @param userProps
     * @return
     * @throws IOException
     * @throws FileNotFoundException
     */
    public static MultipartPostMethod createFilePost(Properties p, FindAllFiles find, Collection<File> files,
            Properties userProps) throws IOException, FileNotFoundException {
        // ========================== assemble zip file in byte array
        // ==============================
        String loginName = userProps.getProperty("loginName");
        String classAccount = userProps.getProperty("classAccount");
        String from = classAccount;
        if (loginName != null && !loginName.equals(classAccount))
            from += "/" + loginName;
        System.out.println(" submitted by " + from);
        System.out.println();
        System.out.println("Submitting the following files");
        ByteArrayOutputStream bytes = new ByteArrayOutputStream(4096);
        byte[] buf = new byte[4096];
        ZipOutputStream zipfile = new ZipOutputStream(bytes);
        zipfile.setComment("zipfile for CommandLineTurnin, version " + VERSION);
        for (File resource : files) {
            if (resource.isDirectory())
                continue;
            String relativePath = resource.getCanonicalPath().substring(find.rootPathLength + 1);
            System.out.println(relativePath);
            ZipEntry entry = new ZipEntry(relativePath);
            entry.setTime(resource.lastModified());

            zipfile.putNextEntry(entry);
            InputStream in = new FileInputStream(resource);
            try {
                while (true) {
                    int n = in.read(buf);
                    if (n < 0)
                        break;
                    zipfile.write(buf, 0, n);
                }
            } finally {
                in.close();
            }
            zipfile.closeEntry();

        } // for each file
        zipfile.close();

        MultipartPostMethod filePost = new MultipartPostMethod(p.getProperty("submitURL"));

        p.putAll(userProps);
        // add properties
        for (Map.Entry<?, ?> e : p.entrySet()) {
            String key = (String) e.getKey();
            String value = (String) e.getValue();
            if (!key.equals("submitURL"))
                filePost.addParameter(key, value);
        }
        filePost.addParameter("submitClientTool", "CommandLineTool");
        filePost.addParameter("submitClientVersion", VERSION);
        byte[] allInput = bytes.toByteArray();
        filePost.addPart(new FilePart("submittedFiles", new ByteArrayPartSource("submit.zip", allInput)));
        return filePost;
    }

    /**
     * @param submitUserFile
     * @param courseKey
     * @param projectNumber
     * @param authenticationType
     * @param baseURL
     * @throws IOException
     * @throws UnsupportedEncodingException
     * @throws URISyntaxException
     * @throws HttpException
     */
    public static void createSubmitUser(File submitUserFile, String courseKey, String projectNumber,
            String authenticationType, String baseURL)
            throws IOException, UnsupportedEncodingException, URISyntaxException, HttpException {
        PrintWriter newUserProjectFile;
        if (authenticationType.equals("openid")) {
            String[] result = getSubmitUserForOpenId(courseKey, projectNumber, baseURL);
            String classAccount = result[0];
            String onetimePassword = result[1];
            newUserProjectFile = new PrintWriter(new FileWriter(submitUserFile));
            newUserProjectFile.println("classAccount=" + classAccount);
            newUserProjectFile.println("oneTimePassword=" + onetimePassword);
        } else {
            String loginName, password;

            Console console = System.console();

            System.out.println("Please enter your LDAP username and password");
            System.out.print("LDAP username: ");
            loginName = console.readLine();
            System.out.println("Password: ");
            password = new String(console.readPassword());
            System.out.println("Thanks!");
            System.out.println("Preparing for submission. Please wait...");

            String url = baseURL + "/eclipse/NegotiateOneTimePassword";
            PostMethod post = new PostMethod(url);

            post.addParameter("loginName", loginName);
            post.addParameter("password", password);

            post.addParameter("courseKey", courseKey);
            post.addParameter("projectNumber", projectNumber);

            HttpClient client = new HttpClient();
            client.setConnectionTimeout(HTTP_TIMEOUT);

            // System.out.println("Preparing to execute method");
            int status = client.executeMethod(post);
            // System.out.println("Post finished with status: " +status);

            if (status != HttpStatus.SC_OK) {
                throw new HttpException(
                        "Unable to negotiate one-time password with the server: " + post.getResponseBodyAsString());
            }

            InputStream inputStream = post.getResponseBodyAsStream();
            BufferedReader userStream = new BufferedReader(new InputStreamReader(inputStream));
            newUserProjectFile = new PrintWriter(new FileWriter(submitUserFile));
            while (true) {
                String line = userStream.readLine();
                if (line == null)
                    break;
                // System.out.println(line);
                newUserProjectFile.println(line);
            }
            userStream.close();
        }
        newUserProjectFile.close();
        if (!submitUserFile.canRead()) {
            System.out.println("Can't generate or access " + submitUserFile);
            System.exit(1);
        }
    }

    public static String[] getSubmitUserForOpenId(String courseKey, String projectNumber, String baseURL)
            throws UnsupportedEncodingException, URISyntaxException, IOException {
        Console console = System.console();

        boolean requested = false;
        String encodedProjectNumber = URLEncoder.encode(projectNumber, "UTF-8");
        URI u = new URI(baseURL + "/view/submitStatus.jsp?courseKey=" + courseKey + "&projectNumber="
                + encodedProjectNumber);

        if (java.awt.Desktop.isDesktopSupported()) {
            Desktop desktop = java.awt.Desktop.getDesktop();
            if (desktop.isSupported(Desktop.Action.BROWSE)) {
                System.out.println(
                        "Your browser will connect to the submit server, which may require you to authenticate yourself");
                System.out.println("Please do so, and then you will be shown a page with a textfield on it");
                System.out.println("Then copy that text and paste it into the prompt here");
                desktop.browse(u);
                requested = true;
            }
        }
        if (!requested) {
            System.out.println("Please enter the following URL into your browser");
            System.out.println("  " + u);
            System.out.println();
            System.out.println(
                    "Your browser will connect to the submit server, which may require you to authenticate yourself");
            System.out.println("Please do so, and then you will be shown a page with a textfield on it");
            System.out.println("Then copy that text and paste it into the prompt here");

        }
        while (true) {
            System.out.println();
            System.out.println("Submission verification information from browser? ");
            String info = new String(console.readLine());
            if (info.length() > 2) {
                int checksum = Integer.parseInt(info.substring(info.length() - 1), 16);
                info = info.substring(0, info.length() - 1);
                int hash = info.hashCode() & 0x0f;
                if (checksum == hash) {
                    String fields[] = info.split(";");
                    if (fields.length == 2) {
                        return fields;

                    }
                }
            }
            System.out.println("That doesn't seem right");
            System.out.println(
                    "The information should be your account name and a string of hexidecimal digits, separated by a semicolon");
            System.out.println("Please try again");
            System.out.println();
        }
    }

    /**
     * @param submitIgnoreFile
     * @param ignorePatterns
     * @throws FileNotFoundException
     * @throws IOException
     */
    private static void addIgnoredPatternsFromFile(File submitIgnoreFile, FilesToIgnore ignorePatterns)
            throws FileNotFoundException, IOException {
        if (submitIgnoreFile.canRead()) {
            BufferedReader ignoreContents = new BufferedReader(new FileReader(submitIgnoreFile));
            while (true) {
                String ignoreMe = ignoreContents.readLine();
                if (ignoreMe == null)
                    break;
                ignorePatterns.addPattern(ignoreMe);
            }
            ignoreContents.close();
        }
    }
}