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 */
019package org.crsh.lang.java;
020
021import org.crsh.util.ZipIterator;
022
023import javax.tools.JavaFileObject;
024import java.io.File;
025import java.io.IOException;
026import java.net.URI;
027import java.net.URISyntaxException;
028import java.net.URL;
029import java.util.ArrayList;
030import java.util.Arrays;
031import java.util.Enumeration;
032import java.util.zip.ZipEntry;
033
034/** @author Julien Viet */
035class ClasspathResolver {
036
037  /** . */
038  final ClassLoader loader;
039
040  public ClasspathResolver(ClassLoader loader) {
041    this.loader = loader;
042  }
043
044  public Iterable<JavaFileObject> resolve(String pkg, boolean recurse) throws IOException, URISyntaxException {
045    String pkgName = pkg.replace('.', '/');
046    ArrayList<JavaFileObject> ret = new ArrayList<JavaFileObject>();
047    final Enumeration<URL> en = loader.getResources(pkgName);
048    while (en.hasMoreElements()) {
049      URL url = en.nextElement();
050      String protocol = url.getProtocol();
051      if (protocol.equals("file")) {
052        File root = new File(url.toURI());
053        resolve(pkgName, ret, root, recurse);
054      } else if ("jar".equals(protocol)) {
055        String path = url.getPath();
056        int index = path.lastIndexOf('!');
057        String containerURLs = path.substring(0, index);
058        URL containerURL = new URL(containerURLs);
059        ZipIterator i = ZipIterator.create(containerURL);
060        while (i.hasNext()) {
061          ZipEntry entry = i.next();
062          String name = entry.getName();
063          if (!entry.isDirectory() && name.startsWith(pkgName) && (name.indexOf('/', pkgName.length() + 1) == -1 || recurse)) {
064            String binaryName = name.substring(0, name.length() - ".class".length()).replace('/', '.');
065            URI entryURI = new URI("jar:" + containerURLs + "!/" + name);
066            ret.add(new URIJavaFileObject(binaryName, entryURI, entry.getTime()));
067          }
068        }
069      } else {
070        throw new UnsupportedOperationException("Protocol for url " + url + " not supported");
071      }
072    }
073    return ret;
074  }
075
076  private void resolve(String pkgName, ArrayList<JavaFileObject> ret, File file, boolean recurse) {
077    final File[] children = file.listFiles();
078    if (children != null) {
079      Arrays.sort(children);
080      for (File child : children) {
081        if (child.isDirectory()) {
082          if (recurse) {
083            resolve(pkgName, ret, child, recurse);
084          }
085        } else {
086          String childName = child.getName();
087          if (childName.endsWith(".class")) {
088            String binaryName = pkgName + "." + childName.substring(0, childName.length() - ".class".length());
089            ret.add(new URIJavaFileObject(binaryName, child.toURI(), child.lastModified()));
090          }
091        }
092      }
093    }
094  }
095}