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