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 }