org.paxml.selenium.rc.FileServer.java Source code

Java tutorial

Introduction

Here is the source code for org.paxml.selenium.rc.FileServer.java

Source

/**
 * This file is part of PaxmlSelenium.
 *
 * PaxmlSelenium 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.
 *
 * PaxmlSelenium 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 PaxmlSelenium.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.paxml.selenium.rc;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.URLEncoder;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mortbay.jetty.Handler;
import org.mortbay.jetty.Request;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.handler.AbstractHandler;
import org.mortbay.jetty.handler.DefaultHandler;
import org.mortbay.jetty.handler.HandlerList;
import org.mortbay.jetty.handler.ResourceHandler;
import org.mortbay.jetty.nio.SelectChannelConnector;
import org.paxml.core.PaxmlRuntimeException;
import org.springframework.core.io.ClassPathResource;

public class FileServer {
    private static final Log log = LogFactory.getLog(FileServer.class);
    public static final String PREFERRED_HOST_ADDRESS = "paxml.attachFile.preferredHostAddress";
    private static final ConcurrentMap<String, String> memFiles = new ConcurrentHashMap<String, String>();
    public static final String IN_MEM_IDENT = "mem:";
    public static final String TMP_FILE_IDENT = "tmpf:";
    public static final String CLASSPATH_IDENT = "classpath:";
    private static final String TMP_DIR = "target";
    private final Server server = new Server();
    private volatile int port;

    public String hostIt(String data, boolean content) {
        start();
        if (content) {
            return getHostedUrl(hostFileContent(data));
        } else if (data.contains("://")) {
            return data;
        } else {
            return getHostedUrl(CLASSPATH_IDENT + data);
        }
    }

    /**
     * Host a string as file content, preferrably in a system temp file. If
     * system temp file does not work, host in memory. In either case, a file is
     * readable for only once.
     * 
     * @param content
     *            the file content
     * @return the hosted path
     */
    public static String hostFileContent(String content) {
        String path;
        File file;
        try {
            File dir = new File(TMP_DIR);
            dir.mkdirs();
            file = File.createTempFile(FileServer.class.getSimpleName() + "_", ".tmp", dir);
            file.deleteOnExit();

            FileOutputStream fout = new FileOutputStream(file, false);
            try {
                fout.write(content.getBytes("UTF-8"));
                fout.flush();
            } finally {
                IOUtils.closeQuietly(fout);
            }
            path = TMP_FILE_IDENT + file.getName();

        } catch (IOException e) {
            path = IN_MEM_IDENT + UUID.randomUUID().toString() + ".txt";
            if (null != memFiles.putIfAbsent(path, content)) {
                throw new RuntimeException("Duplicated in memory fike key: " + path);
            }

        }
        if (log.isDebugEnabled()) {
            log.debug("File content held in: " + path);
        }
        return path;

    }

    public String getHostedUrl(String path) {

        if (path.contains("://")) {
            return path;
        }
        path = URLEncoder.encode(path);
        return "http://" + getCalculatedHostAddress() + ":" + getHostPort()
                + (path.startsWith("/") ? path : ("/" + path));
    }

    public static AbstractHandler newFileHandler() {
        return new AbstractHandler() {
            @Override
            public void handle(String path, HttpServletRequest request, HttpServletResponse res, int arg3)
                    throws IOException, ServletException {
                if (path.startsWith("/")) {
                    path = path.substring(1);
                }
                String tmpFile = null;
                InputStream in = null;
                try {
                    if (path.startsWith(IN_MEM_IDENT)) {
                        // let a file be read for only once, otherwise memory
                        // could explode
                        String content = memFiles.remove(path);
                        in = new ByteArrayInputStream(content.getBytes("UTF-8"));
                    } else if (path.startsWith(TMP_FILE_IDENT)) {
                        tmpFile = path.substring(TMP_FILE_IDENT.length());
                        in = new FileInputStream(new File(TMP_DIR, tmpFile));
                    } else if (path.startsWith(CLASSPATH_IDENT)) {
                        in = new ClassPathResource(path.substring(CLASSPATH_IDENT.length())).getInputStream();
                    } else {
                        throw new IOException("Path with unknown identifier: " + path);
                    }

                    res.setStatus(HttpServletResponse.SC_OK);
                    res.setContentType("binary/x-paxml");
                    res.setHeader("Content-Disposition", "attachment; filename=\"" + path + "\"");
                    res.setHeader("Pragma", "");
                    res.setHeader("Cache-control", "");

                    IOUtils.copy(in, res.getOutputStream());

                    ((Request) request).setHandled(true);

                } catch (Exception e) {
                    if (log.isErrorEnabled()) {
                        log.error("Cannot resolve path: " + path, e);
                    }
                    res.setStatus(HttpServletResponse.SC_NOT_FOUND);

                    return;
                } finally {
                    IOUtils.closeQuietly(in);
                    if (tmpFile != null) {
                        new File(tmpFile).delete();
                    }
                }

            }

        };
    }

    public synchronized void start() {
        if (isRunning()) {
            return;
        }
        start(0, newFileHandler());
    }

    public synchronized void start(int port, AbstractHandler... handlers) {
        if (isRunning()) {
            return;
        }
        // install shutdown hook to stop file server
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {

            @Override
            public void run() {
                stop();
            }

        }));
        if (log.isInfoEnabled()) {
            log.info("Starting file server");
        }
        SelectChannelConnector connector = new SelectChannelConnector();
        connector.setPort(port);
        server.addConnector(connector);

        HandlerList _handlers = new HandlerList();
        List<AbstractHandler> list = new ArrayList<AbstractHandler>(Arrays.asList(handlers));
        list.add(new DefaultHandler());

        _handlers.setHandlers(list.toArray(new Handler[list.size()]));
        server.setHandler(_handlers);

        try {
            server.start();
        } catch (Exception e) {
            throw new PaxmlRuntimeException("Cannot start file server", e);
        }

        this.port = connector.getLocalPort();

        if (log.isInfoEnabled()) {
            log.info("File server started at port: " + this.port);
        }

    }

    public synchronized void stop() {
        if (!isRunning()) {
            return;
        }
        try {
            if (log.isInfoEnabled()) {
                log.info("Stopping file server");
            }
            server.stop();
        } catch (Exception e) {
            throw new PaxmlRuntimeException("Cannot stop file server", e);
        }
    }

    public static ResourceHandler newFileHandler(String baseDir) {
        if (StringUtils.isBlank(baseDir)) {
            baseDir = ".";
        }
        ResourceHandler fileHandler = new ResourceHandler();

        fileHandler.setResourceBase(baseDir);
        return fileHandler;
    }

    public static String getHostIp() {
        try {
            InetAddress addr = InetAddress.getLocalHost();
            return addr.getHostAddress();
        } catch (UnknownHostException e) {
            throw new PaxmlRuntimeException("Cannot get this machine's ip", e);
        }
    }

    public static String getHostName() {
        try {
            InetAddress addr = InetAddress.getLocalHost();
            return addr.getHostName();
        } catch (UnknownHostException e) {
            throw new PaxmlRuntimeException("Cannot get this machine's name", e);
        }
    }

    public static String getPreferredHostAddress() {
        return System.getProperty(PREFERRED_HOST_ADDRESS);
    }

    public static String getCalculatedHostAddress() {
        String addr = getPreferredHostAddress();
        if (StringUtils.isBlank(addr)) {
            addr = getHostIp();
        }
        return addr;
    }

    public int getHostPort() {
        return port;
    }

    public synchronized boolean isRunning() {

        return server.isRunning();
    }
}