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.url; 021 022 import org.crsh.util.Safe; 023 024 import java.io.FileInputStream; 025 import java.io.IOException; 026 import java.io.InputStream; 027 import java.net.URISyntaxException; 028 import java.net.URL; 029 import java.util.ArrayList; 030 import java.util.Collections; 031 import java.util.Enumeration; 032 import java.util.HashMap; 033 import java.util.zip.ZipEntry; 034 035 /** @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a> */ 036 public abstract class Node { 037 038 /** . */ 039 final String name; 040 041 protected Node(String name) { 042 this.name = name; 043 } 044 045 static class Dir extends Node { 046 047 /** . */ 048 HashMap<String, Node> children = new HashMap<String, Node>(); 049 050 Dir() { 051 this(""); 052 } 053 054 private Dir(String name) { 055 super(name); 056 } 057 058 void merge(ClassLoader loader) throws IOException, URISyntaxException { 059 060 // Get the root class path files 061 for (Enumeration<URL> i = loader.getResources("");i.hasMoreElements();) { 062 URL url = i.nextElement(); 063 merge(url); 064 } 065 ArrayList<URL> items = Collections.list(loader.getResources("META-INF/MANIFEST.MF")); 066 for (URL item : items) { 067 if ("jar".equals(item.getProtocol())) { 068 String path = item.getPath(); 069 int pos = path.indexOf("!/"); 070 URL url = new URL(path.substring(0, pos)); 071 merge(url); 072 } else { 073 // 074 } 075 } 076 } 077 078 void merge(URL url) throws IOException, URISyntaxException { 079 if (url.getProtocol().equals("file")) { 080 try { 081 java.io.File f = new java.io.File(url.toURI()); 082 if (f.isDirectory()) { 083 merge(f); 084 } 085 else if (f.getName().endsWith(".jar")) { 086 merge(new URL("jar:" + url + "!/")); 087 } else { 088 // WTF ? 089 } 090 } 091 catch (URISyntaxException e) { 092 throw new IOException(e); 093 } 094 } if (url.getProtocol().equals("jar")) { 095 int pos = url.getPath().lastIndexOf("!/"); 096 URL jarURL = new URL(url.getPath().substring(0, pos)); 097 String path = url.getPath().substring(pos + 2); 098 ZipIterator i = ZipIterator.create(jarURL); 099 try { 100 while (i.hasNext()) { 101 ZipEntry entry = i.next(); 102 if (entry.getName().startsWith(path)) { 103 add(url, entry.getName().substring(path.length()), i.open()); 104 } 105 } 106 } 107 finally { 108 Safe.close(i); 109 } 110 } else { 111 if (url.getPath().endsWith(".jar")) { 112 merge(new URL("jar:" + url + "!/")); 113 } else { 114 // WTF ? 115 } 116 } 117 } 118 119 private void merge(java.io.File f) throws IOException { 120 for (final java.io.File file : f.listFiles()) { 121 String name = file.getName(); 122 Node child = children.get(name); 123 if (file.isDirectory()) { 124 if (child == null) { 125 Dir dir = new Dir(name); 126 dir.merge(file); 127 children.put(name, dir); 128 } else if (child instanceof Dir) { 129 ((Dir)child).merge(file); 130 } 131 } 132 else { 133 if (child == null) { 134 children.put(name, new File(name, new InputStreamResolver() { 135 public InputStream open() throws IOException { 136 return new FileInputStream(file); 137 } 138 }, file.lastModified())); 139 } 140 } 141 } 142 } 143 144 private void add(URL baseURL, String entryName, InputStreamResolver resolver) throws IOException { 145 if (entryName.length() > 0 && entryName.charAt(entryName.length() - 1) != '/') { 146 add(baseURL, 0, entryName, 1, resolver); 147 } 148 } 149 150 private void add(URL baseURL, int index, String entryName, long lastModified, InputStreamResolver resolver) throws IOException { 151 int next = entryName.indexOf('/', index); 152 if (next == -1) { 153 String name = entryName.substring(index); 154 Node child = children.get(name); 155 if (child == null) { 156 children.put(name, new File(name, resolver, lastModified)); 157 } 158 } else { 159 String name = entryName.substring(index, next); 160 Node child = children.get(name); 161 if (child == null) { 162 Dir dir = new Dir(name); 163 children.put(name, dir); 164 dir.add(baseURL, next + 1, entryName, lastModified, resolver); 165 } else if (child instanceof Dir) { 166 ((Dir)child).add(baseURL, next + 1, entryName, lastModified, resolver); 167 } else { 168 // 169 } 170 } 171 } 172 } 173 174 static class File extends Node { 175 176 /** . */ 177 final InputStreamResolver resolver; 178 179 /** . */ 180 final long lastModified; 181 182 File(String name, InputStreamResolver url, long lastModified) { 183 super(name); 184 185 // 186 this.resolver = url; 187 this.lastModified = lastModified; 188 } 189 } 190 }