001    /*
002     * Copyright (C) 2010 eXo Platform SAS.
003     *
004     * This is free software; you can redistribute it and/or modify it
005     * under the terms of the GNU Lesser General Public License as
006     * published by the Free Software Foundation; either version 2.1 of
007     * the License, or (at your option) any later version.
008     *
009     * This software is distributed in the hope that it will be useful,
010     * but WITHOUT ANY WARRANTY; without even the implied warranty of
011     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012     * Lesser General Public License for more details.
013     *
014     * You should have received a copy of the GNU Lesser General Public
015     * License along with this software; if not, write to the Free
016     * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
017     * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
018     */
019    
020    package org.crsh.vfs.spi.servlet;
021    
022    import org.crsh.vfs.spi.AbstractFSDriver;
023    
024    import javax.servlet.ServletContext;
025    import java.io.File;
026    import java.io.FileInputStream;
027    import java.io.IOException;
028    import java.io.InputStream;
029    import java.net.URL;
030    import java.util.Collections;
031    import java.util.Set;
032    import java.util.regex.Matcher;
033    import java.util.regex.Pattern;
034    
035    /**
036     * @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a>
037     * @version $Revision$
038     */
039    public class ServletContextDriver extends AbstractFSDriver<String> {
040    
041      /** A valid path. */
042      static final Pattern pathPattern = Pattern.compile("^(?=/).*?((?<=/)[^/]*)?(/?)$");
043    
044      /** . */
045      private final ServletContext ctx;
046    
047      public ServletContextDriver(ServletContext ctx) {
048        if (ctx == null) {
049          throw new NullPointerException();
050        }
051    
052        //
053        this.ctx = ctx;
054      }
055    
056      public String root() throws IOException {
057        return "/";
058      }
059    
060      public String name(String file) throws IOException {
061        return matcher(file).group(1);
062      }
063    
064      public boolean isDir(String file) throws IOException {
065        Matcher matcher = matcher(file);
066        String slash = matcher.group(2);
067        return "/".equals(slash);
068      }
069    
070      public Iterable<String> children(String parent) throws IOException {
071        @SuppressWarnings("unchecked")
072        Set<String> resourcePaths = (Set<String>)ctx.getResourcePaths(parent);
073        return resourcePaths != null ? resourcePaths : Collections.<String>emptyList();
074      }
075    
076      /**
077       * The implementation attempts to get an URL that will be valid for the file system first (when the
078       * war is usually exploded) and if it is not able, it will delegate to {@link ServletContext#getResource(String)}.
079       *
080       * @param file the file path
081       * @return the URL
082       * @throws IOException any io exception
083       */
084      public URL toURL(String file) throws IOException {
085        String realPath = ctx.getRealPath(file);
086        if (realPath != null) {
087          File realFile = new File(realPath);
088          if (realFile.exists() && realFile.isFile()) {
089            return realFile.toURI().toURL();
090          }
091        }
092        return ctx.getResource(file);
093      }
094    
095      public long getLastModified(String handle) throws IOException {
096        String realPath = ctx.getRealPath(handle);
097        if (realPath != null) {
098          File realFile = new File(realPath);
099          if (realFile.exists() && realFile.isFile()) {
100            return realFile.lastModified();
101          }
102        }
103        return ctx.getResource(handle).openConnection().getLastModified();
104      }
105    
106      public InputStream open(String handle) throws IOException {
107        String realPath = ctx.getRealPath(handle);
108        if (realPath != null) {
109          File realFile = new File(realPath);
110          if (realFile.exists() && realFile.isFile()) {
111            return new FileInputStream(realFile);
112          }
113        }
114        return ctx.getResource(handle).openConnection().getInputStream();
115      }
116    
117      private Matcher matcher(String path) {
118        Matcher m = pathPattern.matcher(path);
119        if (m.matches()) {
120          return m;
121        } else {
122          throw new IllegalArgumentException("Illegal path " + path);
123        }
124      }
125    }