All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.jetty.util.resource.Resource Maven / Gradle / Ivy

The newest version!
//
//  ========================================================================
//  Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
//  ------------------------------------------------------------------------
//  All rights reserved. This program and the accompanying materials
//  are made available under the terms of the Eclipse Public License v1.0
//  and Apache License v2.0 which accompanies this distribution.
//
//      The Eclipse Public License is available at
//      http://www.eclipse.org/legal/epl-v10.html
//
//      The Apache License v2.0 is available at
//      http://www.opensource.org/licenses/apache2.0.php
//
//  You may elect to redistribute this code under either of these licenses.
//  ========================================================================
//

package org.eclipse.jetty.util.resource;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.nio.channels.ReadableByteChannel;
import java.text.DateFormat;
import java.util.Arrays;
import java.util.Date;

import org.eclipse.jetty.util.B64Code;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.Loader;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;


/* ------------------------------------------------------------ */
/** 
 * Abstract resource class.
 */
public abstract class Resource implements ResourceFactory
{
    private static final Logger LOG = Log.getLogger(Resource.class);
    public static boolean __defaultUseCaches = true;
    volatile Object _associate;

    /* ------------------------------------------------------------ */
    /**
     * Change the default setting for url connection caches.
     * Subsequent URLConnections will use this default.
     * @param useCaches
     */
    public static void setDefaultUseCaches (boolean useCaches)
    {
        __defaultUseCaches=useCaches;
    }

    /* ------------------------------------------------------------ */
    public static boolean getDefaultUseCaches ()
    {
        return __defaultUseCaches;
    }
    
    /* ------------------------------------------------------------ */
    /** Construct a resource from a uri.
     * @param uri A URI.
     * @return A Resource object.
     * @throws IOException Problem accessing URI
     */
    public static Resource newResource(URI uri)
        throws IOException
    {
        return newResource(uri.toURL());
    }
    
    /* ------------------------------------------------------------ */
    /** Construct a resource from a url.
     * @param url A URL.
     * @return A Resource object.
     * @throws IOException Problem accessing URL
     */
    public static Resource newResource(URL url)
        throws IOException
    {
        return newResource(url, __defaultUseCaches);
    }
    
    /* ------------------------------------------------------------ */   
    /**
     * Construct a resource from a url.
     * @param url the url for which to make the resource
     * @param useCaches true enables URLConnection caching if applicable to the type of resource
     * @return
     */
    static Resource newResource(URL url, boolean useCaches)
    {
        if (url==null)
            return null;

        String url_string=url.toExternalForm();
        if( url_string.startsWith( "file:"))
        {
            try
            {
                FileResource fileResource= new FileResource(url);
                return fileResource;
            }
            catch(Exception e)
            {
                LOG.debug(Log.EXCEPTION,e);
                return new BadResource(url,e.toString());
            }
        }
        else if( url_string.startsWith( "jar:file:"))
        {
            return new JarFileResource(url, useCaches);
        }
        else if( url_string.startsWith( "jar:"))
        {
            return new JarResource(url, useCaches);
        }

        return new URLResource(url,null,useCaches);
    }

    
    
    /* ------------------------------------------------------------ */
    /** Construct a resource from a string.
     * @param resource A URL or filename.
     * @return A Resource object.
     */
    public static Resource newResource(String resource)
        throws MalformedURLException, IOException
    {
        return newResource(resource, __defaultUseCaches);
    }
    
    /* ------------------------------------------------------------ */
    /** Construct a resource from a string.
     * @param resource A URL or filename.
     * @param useCaches controls URLConnection caching
     * @return A Resource object.
     */
    public static Resource newResource (String resource, boolean useCaches)       
    throws MalformedURLException, IOException
    {
        URL url=null;
        try
        {
            // Try to format as a URL?
            url = new URL(resource);
        }
        catch(MalformedURLException e)
        {
            if(!resource.startsWith("ftp:") &&
               !resource.startsWith("file:") &&
               !resource.startsWith("jar:"))
            {
                try
                {
                    // It's a file.
                    if (resource.startsWith("./"))
                        resource=resource.substring(2);
                    
                    File file=new File(resource).getCanonicalFile();
                    url=Resource.toURL(file);            
                    
                    URLConnection connection=url.openConnection();
                    connection.setUseCaches(useCaches);
                    return new FileResource(url,connection,file);
                }
                catch(Exception e2)
                {
                    LOG.debug(Log.EXCEPTION,e2);
                    throw e;
                }
            }
            else
            {
                LOG.warn("Bad Resource: "+resource);
                throw e;
            }
        }

        // Make sure that any special characters stripped really are ignorable.
        String nurl=url.toString();
        if (nurl.length()>0 &&  nurl.charAt(nurl.length()-1)!=resource.charAt(resource.length()-1))
        {
            if ((nurl.charAt(nurl.length()-1)!='/' ||
                 nurl.charAt(nurl.length()-2)!=resource.charAt(resource.length()-1))
                &&
                (resource.charAt(resource.length()-1)!='/' ||
                 resource.charAt(resource.length()-2)!=nurl.charAt(nurl.length()-1)
                 ))
            {
                return new BadResource(url,"Trailing special characters stripped by URL in "+resource);
            }
        }
        return newResource(url);
    }

    /* ------------------------------------------------------------ */
    public static Resource newResource (File file)
    throws MalformedURLException, IOException
    {
        file = file.getCanonicalFile();
        URL url = Resource.toURL(file);

        URLConnection connection = url.openConnection();
        FileResource fileResource = new FileResource(url, connection, file);
        return fileResource;
    }

    /* ------------------------------------------------------------ */
    /** Construct a system resource from a string.
     * The resource is tried as classloader resource before being
     * treated as a normal resource.
     * @param resource Resource as string representation 
     * @return The new Resource
     * @throws IOException Problem accessing resource.
     */
    public static Resource newSystemResource(String resource)
        throws IOException
    {
        URL url=null;
        // Try to format as a URL?
        ClassLoader
            loader=Thread.currentThread().getContextClassLoader();
        if (loader!=null)
        {
            try
            {
                url = loader.getResource(resource);
                if (url == null && resource.startsWith("/"))
                    url = loader.getResource(resource.substring(1));
            }
            catch (IllegalArgumentException e)
            {
                // Catches scenario where a bad Windows path like "C:\dev" is
                // improperly escaped, which various downstream classloaders
                // tend to have a problem with
                url = null;
            }
        }
        if (url==null)
        {
            loader=Resource.class.getClassLoader();
            if (loader!=null)
            {
                url=loader.getResource(resource);
                if (url==null && resource.startsWith("/"))
                    url=loader.getResource(resource.substring(1));
            }
        }
        
        if (url==null)
        {
            url=ClassLoader.getSystemResource(resource);
            if (url==null && resource.startsWith("/"))
                url=loader.getResource(resource.substring(1));
        }
        
        if (url==null)
            return null;
        
        return newResource(url);
    }

    /* ------------------------------------------------------------ */
    /** Find a classpath resource.
     */
    public static Resource newClassPathResource(String resource)
    {
        return newClassPathResource(resource,true,false);
    }

    /* ------------------------------------------------------------ */
    /** Find a classpath resource.
     * The {@link java.lang.Class#getResource(String)} method is used to lookup the resource. If it is not
     * found, then the {@link Loader#getResource(Class, String, boolean)} method is used.
     * If it is still not found, then {@link ClassLoader#getSystemResource(String)} is used.
     * Unlike {@link ClassLoader#getSystemResource(String)} this method does not check for normal resources.
     * @param name The relative name of the resource
     * @param useCaches True if URL caches are to be used.
     * @param checkParents True if forced searching of parent Classloaders is performed to work around 
     * loaders with inverted priorities
     * @return Resource or null
     */
    public static Resource newClassPathResource(String name,boolean useCaches,boolean checkParents)
    {
        URL url=Resource.class.getResource(name);
        
        if (url==null)
        {
            try
            {
                url=Loader.getResource(Resource.class,name,checkParents);
            }
            catch(ClassNotFoundException e)
            {
                url=ClassLoader.getSystemResource(name);
            }
        }
        if (url==null)
            return null;
        return newResource(url,useCaches);
    }
    
    /* ------------------------------------------------------------ */
    public static boolean isContainedIn (Resource r, Resource containingResource) throws MalformedURLException
    {
        return r.isContainedIn(containingResource);
    }

    /* ------------------------------------------------------------ */
    @Override
    protected void finalize()
    {
        release();
    }
    
    /* ------------------------------------------------------------ */
    public abstract boolean isContainedIn (Resource r) throws MalformedURLException;
    
    
    /* ------------------------------------------------------------ */
    /** Release any temporary resources held by the resource.
     */
    public abstract void release();
    

    /* ------------------------------------------------------------ */
    /**
     * Returns true if the respresened resource exists.
     */
    public abstract boolean exists();
    

    /* ------------------------------------------------------------ */
    /**
     * Returns true if the respresenetd resource is a container/directory.
     * If the resource is not a file, resources ending with "/" are
     * considered directories.
     */
    public abstract boolean isDirectory();

    /* ------------------------------------------------------------ */
    /**
     * Returns the last modified time
     */
    public abstract long lastModified();


    /* ------------------------------------------------------------ */
    /**
     * Return the length of the resource
     */
    public abstract long length();
    

    /* ------------------------------------------------------------ */
    /**
     * Returns an URL representing the given resource
     */
    public abstract URL getURL();

    /* ------------------------------------------------------------ */
    /**
     * Returns an URI representing the given resource
     */
    public URI getURI()
    {
        try
        {
            return getURL().toURI();
        }
        catch(Exception e)
        {
            throw new RuntimeException(e);
        }
    }
    

    /* ------------------------------------------------------------ */
    /**
     * Returns an File representing the given resource or NULL if this
     * is not possible.
     */
    public abstract File getFile()
        throws IOException;
    

    /* ------------------------------------------------------------ */
    /**
     * Returns the name of the resource
     */
    public abstract String getName();
    

    /* ------------------------------------------------------------ */
    /**
     * Returns an input stream to the resource
     */
    public abstract InputStream getInputStream()
        throws java.io.IOException;
    
    /* ------------------------------------------------------------ */
    /**
     * Returns an readable bytechannel to the resource or null if one is not available.
     */
    public abstract ReadableByteChannel getReadableByteChannel()
        throws java.io.IOException;

    /* ------------------------------------------------------------ */
    /**
     * Returns an output stream to the resource
     */
    public abstract OutputStream getOutputStream()
        throws java.io.IOException, SecurityException;
    
    /* ------------------------------------------------------------ */
    /**
     * Deletes the given resource
     */
    public abstract boolean delete()
        throws SecurityException;
    
    /* ------------------------------------------------------------ */
    /**
     * Rename the given resource
     */
    public abstract boolean renameTo( Resource dest)
        throws SecurityException;
    
    /* ------------------------------------------------------------ */
    /**
     * Returns a list of resource names contained in the given resource
     * The resource names are not URL encoded.
     */
    public abstract String[] list();

    /* ------------------------------------------------------------ */
    /**
     * Returns the resource contained inside the current resource with the
     * given name.
     * @param path The path segment to add, which should be encoded by the
     * encode method. 
     */
    public abstract Resource addPath(String path)
        throws IOException,MalformedURLException;

    /* ------------------------------------------------------------ */
    /** Get a resource from withing this resource.
     * 

* This method is essentially an alias for {@link #addPath(String)}, but without checked exceptions. * This method satisfied the {@link ResourceFactory} interface. * @see org.eclipse.jetty.util.resource.ResourceFactory#getResource(java.lang.String) */ public Resource getResource(String path) { try { return addPath(path); } catch(Exception e) { LOG.debug(e); return null; } } /* ------------------------------------------------------------ */ /** Encode according to this resource type. * The default implementation calls URI.encodePath(uri) * @param uri * @return String encoded for this resource type. */ public String encode(String uri) { return URIUtil.encodePath(uri); } /* ------------------------------------------------------------ */ public Object getAssociate() { return _associate; } /* ------------------------------------------------------------ */ public void setAssociate(Object o) { _associate=o; } /* ------------------------------------------------------------ */ /** * @return The canonical Alias of this resource or null if none. */ public URL getAlias() { return null; } /* ------------------------------------------------------------ */ /** Get the resource list as a HTML directory listing. * @param base The base URL * @param parent True if the parent directory should be included * @return String of HTML */ public String getListHTML(String base,boolean parent) throws IOException { base=URIUtil.canonicalPath(base); if (base==null || !isDirectory()) return null; String[] ls = list(); if (ls==null) return null; Arrays.sort(ls); String decodedBase = URIUtil.decodePath(base); String title = "Directory: "+deTag(decodedBase); StringBuilder buf=new StringBuilder(4096); buf.append(""); buf.append(""); buf.append(title); buf.append("\n

"); buf.append(title); buf.append("

\n\n"); if (parent) { buf.append("\n"); } String encodedBase = hrefEncodeURI(base); DateFormat dfmt=DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM); for (int i=0 ; i< ls.length ; i++) { Resource item = addPath(ls[i]); buf.append("\n"); } buf.append("
Parent Directory
"); buf.append(deTag(ls[i])); buf.append(" "); buf.append(""); buf.append(item.length()); buf.append(" bytes "); buf.append(dfmt.format(new Date(item.lastModified()))); buf.append("
\n"); buf.append("\n"); return buf.toString(); } /** * Encode any characters that could break the URI string in an HREF. * Such as ">Link * * The above example would parse incorrectly on various browsers as the "<" or '"' characters * would end the href attribute value string prematurely. * * @param raw the raw text to encode. * @return the defanged text. */ private static String hrefEncodeURI(String raw) { StringBuffer buf = null; loop: for (int i=0;i': buf=new StringBuffer(raw.length()<<1); break loop; } } if (buf==null) return raw; for (int i=0;i': buf.append("%3E"); continue; default: buf.append(c); continue; } } return buf.toString(); } private static String deTag(String raw) { return StringUtil.replace( StringUtil.replace(raw,"<","<"), ">", ">"); } /* ------------------------------------------------------------ */ /** * @param out * @param start First byte to write * @param count Bytes to write or -1 for all of them. */ public void writeTo(OutputStream out,long start,long count) throws IOException { InputStream in = getInputStream(); try { in.skip(start); if (count<0) IO.copy(in,out); else IO.copy(in,out,count); } finally { in.close(); } } /* ------------------------------------------------------------ */ public void copyTo(File destination) throws IOException { if (destination.exists()) throw new IllegalArgumentException(destination+" exists"); writeTo(new FileOutputStream(destination),0,-1); } /* ------------------------------------------------------------ */ public String getWeakETag() { try { StringBuilder b = new StringBuilder(32); b.append("W/\""); String name=getName(); int length=name.length(); long lhash=0; for (int i=0; i




© 2015 - 2024 Weber Informatics LLC | Privacy Policy