001    /*
002     * Copyright (C) 2012 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.util.Utils;
023    import org.crsh.vfs.spi.AbstractFSDriver;
024    
025    import javax.servlet.ServletContext;
026    import java.io.File;
027    import java.io.FileInputStream;
028    import java.io.IOException;
029    import java.io.InputStream;
030    import java.net.URL;
031    import java.util.Collections;
032    import java.util.Iterator;
033    import java.util.Set;
034    import java.util.regex.Matcher;
035    import java.util.regex.Pattern;
036    
037    public class ServletContextDriver extends AbstractFSDriver<String> {
038    
039      /** A valid path. */
040      static final Pattern pathPattern = Pattern.compile("^(?=/).*?((?<=/)[^/]*)?(/?)$");
041    
042      /** . */
043      private final ServletContext ctx;
044    
045      /** . */
046      private final String root;
047    
048      public ServletContextDriver(ServletContext ctx, String root) {
049        if (ctx == null) {
050          throw new NullPointerException();
051        }
052        if (root == null) {
053          throw new NullPointerException();
054        }
055        assertMatch(root);
056    
057        //
058        this.ctx = ctx;
059        this.root = root;
060      }
061    
062      public String root() throws IOException {
063        return root;
064      }
065    
066      public String name(String file) throws IOException {
067        return assertMatch(file).group(1);
068      }
069    
070      public boolean isDir(String file) throws IOException {
071        Matcher matcher = assertMatch(file);
072        String slash = matcher.group(2);
073        return "/".equals(slash);
074      }
075    
076      public Iterable<String> children(String parent) throws IOException {
077        @SuppressWarnings("unchecked")
078        Set<String> resourcePaths = (Set<String>)ctx.getResourcePaths(parent);
079        return resourcePaths != null ? resourcePaths : Collections.<String>emptyList();
080      }
081    
082      /**
083       * The implementation attempts to get an URL that will be valid for the file system first (when the
084       * war is usually exploded) and if it is not able, it will delegate to {@link ServletContext#getResource(String)}.
085       *
086       * @param file the file path
087       * @return the URL
088       * @throws IOException any io exception
089       */
090      public URL toURL(String file) throws IOException {
091        String realPath = ctx.getRealPath(file);
092        if (realPath != null) {
093          File realFile = new File(realPath);
094          if (realFile.exists() && realFile.isFile()) {
095            return realFile.toURI().toURL();
096          }
097        }
098        return ctx.getResource(file);
099      }
100    
101      public long getLastModified(String handle) throws IOException {
102        String realPath = ctx.getRealPath(handle);
103        if (realPath != null) {
104          File realFile = new File(realPath);
105          if (realFile.exists() && realFile.isFile()) {
106            return realFile.lastModified();
107          }
108        }
109        return ctx.getResource(handle).openConnection().getLastModified();
110      }
111    
112      public Iterator<InputStream> open(String handle) throws IOException {
113        String realPath = ctx.getRealPath(handle);
114        if (realPath != null) {
115          File realFile = new File(realPath);
116          if (realFile.exists() && realFile.isFile()) {
117            return Utils.<InputStream>iterator(new FileInputStream(realFile));
118          }
119        }
120        return Utils.iterator(ctx.getResource(handle).openConnection().getInputStream());
121      }
122    
123      private Matcher assertMatch(String path) {
124        Matcher m = pathPattern.matcher(path);
125        if (m.matches()) {
126          return m;
127        } else {
128          throw new IllegalArgumentException("Illegal path " + path);
129        }
130      }
131    }