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