/* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved. * This code is licensed under the GPL 2.0 license, availible at the root * application directory. */ package org.geoserver.rest.util; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URL; import java.nio.channels.FileChannel; import java.nio.channels.ReadableByteChannel; import java.util.HashSet; import java.util.Set; import java.util.zip.ZipFile; import javax.servlet.http.HttpServletRequest; import org.apache.commons.io.FileUtils; import org.restlet.data.MediaType; import org.restlet.data.Reference; import org.restlet.data.Request; import org.vfny.geoserver.global.ConfigurationException; import org.vfny.geoserver.global.GeoserverDataDirectory; import com.noelios.restlet.ext.servlet.ServletCall; import com.noelios.restlet.http.HttpRequest; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; /** * Utility class for Restlets. * * @author David Winslow, OpenGeo * @author Simone Giannecchini, GeoSolutions * @author Justin Deoliveira, OpenGeo * */ public class RESTUtils { /** * Returns the underlying HttpServletRequest from a Restlet Request object. * <p> * Note that this only returns a value in the case where the Restlet * request/call is originating from a servlet. * </p> * @return The HttpServletRequest, or null. */ public static HttpServletRequest getServletRequest( Request request ) { if ( request instanceof HttpRequest ) { HttpRequest httpRequest = (HttpRequest) request; if ( httpRequest.getHttpCall() instanceof ServletCall ) { ServletCall call = (ServletCall) httpRequest.getHttpCall(); return call.getRequest(); } } return null; } /** * Returns the base url of a request. */ public static String getBaseURL( Request request ) { Reference ref = request.getResourceRef(); HttpServletRequest servletRequest = getServletRequest(request); if ( servletRequest != null ) { String baseURL = ref.getIdentifier(); return baseURL.substring(0, baseURL.length()-servletRequest.getPathInfo().length()); } else { return ref.getParentRef().getIdentifier(); } } /** * This function gets the stream of the request to copy it into a file. * @deprecated use {@link #handleBinUpload(String, File, Request)}. */ public static File handleBinUpload(String datasetName, String extension, Request request) throws IOException, ConfigurationException { final File dir = GeoserverDataDirectory.findCreateConfigDir("data"); return handleBinUpload( datasetName + "." + extension, dir, request ); } /** * Reads content from the body of a request and writes it to a file. * * @param fileName The name of the file to write out. * @param directory The directory to write the file to. * @param request The request. * * @return The file object representing the newly written file. * * @throws IOException Any I/O errors that occur. * * TODO: move this to IOUtils. */ public static File handleBinUpload(String fileName, File directory, Request request ) throws IOException { final File newFile = new File(directory, fileName); if (newFile.exists()) { FileUtils.cleanDirectory(directory); } final ReadableByteChannel source =request.getEntity().getChannel(); final FileChannel outputChannel = IOUtils.getOuputChannel(newFile); IOUtils.copyChannel(1024*1024, source,outputChannel ); IOUtils.closeQuietly(source); IOUtils.closeQuietly(outputChannel); return newFile; } /** * Handles the upload of a dataset using the URL method. * * @param datasetName the name of the uploaded dataset. * @param extension the extension of the uploaded dataset. * @param request the incoming request. * @return a {@link File} that points to the final uploaded dataset. * * @throws IOException * @throws ConfigurationException * * @deprecated use {@link #handleURLUpload(String, File, Request)}. */ public static File handleURLUpload(String datasetName, String extension, Request request) throws IOException, ConfigurationException { //// // // Get the dir where to write and create a file there // //// File dir = GeoserverDataDirectory.findCreateConfigDir("data"); return handleURLUpload(datasetName + "." + extension, dir, request); } /** * Reads a url from the body of a request, reads the contents of the url and writes it to a file. * * @param fileName The name of the file to write. * @param directory The directory to write the new file to. * @param request The request. * * @return The file object representing the newly written file. * * @throws IOException Any I/O errors that occur. * * TODO: move this to IOUtils */ public static File handleURLUpload(String fileName, File directory, Request request ) throws IOException { //this may exists already, but we don't fail here since //it might be old and unused, if needed we fail later while copying File newFile = new File(directory,fileName); //get the URL for this file to upload final InputStream inStream=request.getEntity().getStream(); final String stringURL=IOUtils.getStringFromStream(inStream); final URL fileURL=new URL(stringURL); //// // // Now do the real upload // //// //check if it is a file final File inputFile= IOUtils.URLToFile(fileURL); if(inputFile!=null && inputFile.exists() && inputFile.canRead()) { IOUtils.copyFile(inputFile, newFile); } else { final InputStream inputStream = fileURL.openStream(); final OutputStream outStream = new FileOutputStream(newFile); IOUtils.copyStream(inputStream, outStream, true, true); } return newFile; } /** * Handles an upload using the EXTERNAL method. * * @param request * @throws IOException */ public static File handleEXTERNALUpload(Request request) throws IOException { //get the URL for this file to upload final InputStream inStream=request.getEntity().getStream(); final String stringURL=IOUtils.getStringFromStream(inStream); final URL fileURL=new URL(stringURL); final File inputFile= IOUtils.URLToFile(fileURL); if(inputFile!=null && inputFile.exists() && inputFile.canRead()) { return inputFile; } return null; } static Set<String> ZIP_MIME_TYPES = new HashSet(); static { ZIP_MIME_TYPES.add( "application/zip" ); ZIP_MIME_TYPES.add( "multipart/x-zip" ); ZIP_MIME_TYPES.add( "application/x-zip-compressed" ); } /** * Determines if the specified media type represents a zip stream. */ public static boolean isZipMediaType( MediaType mediaType ) { return ZIP_MIME_TYPES.contains( mediaType.toString() ); } /** * Unzips a zip a file to a specified directory, deleting the zip file after unpacking. * * @param zipFile The zip file. * @param outputDirectory The directory to unpack the contents to. * * @throws IOException Any I/O errors that occur. * * TODO: move this to IOUtils */ public static void unzipFile( File zipFile, File outputDirectory ) throws IOException { if ( outputDirectory == null ) { outputDirectory = zipFile.getParentFile(); } if ( outputDirectory != null && !outputDirectory.exists() ) { outputDirectory.mkdir(); } ZipFile archive = new ZipFile(zipFile); IOUtils.inflate(archive, outputDirectory, null); IOUtils.deleteFile(zipFile); } /** * Unzip a zipped dataset. * * @param storeName the name of the store to handle. * @param zipFile the zipped archive * @return null if the zip file does not point to a valid zip file, the output directory otherwise. * * @deprecated use {@link #unzipFile(File, File)} * */ public static File unpackZippedDataset(String storeName, File zipFile) throws IOException, ConfigurationException { File outputDirectory = new File(GeoserverDataDirectory.findCreateConfigDir("data"), storeName); unzipFile(zipFile, outputDirectory); return outputDirectory; } /** * Fetch a request attribute as a String, accounting for URL-encoding. * * @param request the Restlet Request object that might contain the attribute * @param name the name of the attribute to retrieve * * @return the attribute, URL-decoded, if it exists and is a valid URL-encoded string, or null * otherwise */ public static String getAttribute(Request request, String name) { Object o = request.getAttributes().get(name); return decode(o); } public static String getQueryStringValue(Request request, String key) { String value = request.getResourceRef().getQueryAsForm().getFirstValue(key); return decode(value); } static String decode(Object value) { if (value == null) { return null; } try { return URLDecoder.decode(value.toString(), "UTF-8"); } catch (UnsupportedEncodingException e) { return null; } } }