001 /**
002 * GRANITE DATA SERVICES
003 * Copyright (C) 2006-2013 GRANITE DATA SERVICES S.A.S.
004 *
005 * This file is part of the Granite Data Services Platform.
006 *
007 * Granite Data Services is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * Granite Data Services is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
015 * General Public License for more details.
016 *
017 * You should have received a copy of the GNU Lesser General Public
018 * License along with this library; if not, write to the Free Software
019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
020 * USA, or see <http://www.gnu.org/licenses/>.
021 */
022 package org.granite.scan;
023
024 import java.io.File;
025 import java.io.IOException;
026 import java.net.URL;
027 import java.net.URLClassLoader;
028 import java.net.URLDecoder;
029 import java.util.ArrayList;
030 import java.util.Collection;
031 import java.util.Enumeration;
032 import java.util.HashSet;
033 import java.util.List;
034 import java.util.Set;
035 import java.util.zip.ZipEntry;
036 import java.util.zip.ZipException;
037 import java.util.zip.ZipFile;
038
039 /**
040 * @author Franck WOLFF
041 */
042 public class URLScanner implements Scanner {
043
044 ///////////////////////////////////////////////////////////////////////////
045 // Fields.
046
047 private final List<ScannedItemHandler> handlers = new ArrayList<ScannedItemHandler>();
048 private final String marker;
049 private final ClassLoader loader;
050
051 ///////////////////////////////////////////////////////////////////////////
052 // Constructors.
053
054 public URLScanner(ScannedItemHandler handler) {
055 this(handler, null, Thread.currentThread().getContextClassLoader());
056 }
057
058 public URLScanner(ScannedItemHandler handler, String marker) {
059 this(handler, marker, Thread.currentThread().getContextClassLoader());
060 }
061
062 public URLScanner(ScannedItemHandler handler, ClassLoader loader) {
063 this(handler, null, loader);
064 }
065
066 public URLScanner(ScannedItemHandler handler, String marker, ClassLoader loader) {
067 this.marker = marker;
068 this.handlers.add(handler);
069 this.loader = loader;
070 }
071
072 ///////////////////////////////////////////////////////////////////////////
073 // Properties.
074
075 public String getMarker() {
076 return marker;
077 }
078
079 public void addHandler(ScannedItemHandler handler) {
080 if (!handlers.contains(handler))
081 handlers.add(handler);
082 }
083
084 public void addHandlers(Collection<ScannedItemHandler> handlers) {
085 for (ScannedItemHandler handler : handlers)
086 addHandler(handler);
087 }
088
089 public ClassLoader getLoader() {
090 return loader;
091 }
092
093 ///////////////////////////////////////////////////////////////////////////
094 // Scan methods.
095
096 public void scan() throws IOException {
097 Set<String> paths = new HashSet<String>();
098
099 if (marker == null) {
100 if (!(loader instanceof URLClassLoader))
101 throw new RuntimeException("ClassLoader used with no marker should be a URLClassLoader: " + loader);
102
103 for (URL url : ((URLClassLoader)loader).getURLs()) {
104 String urlPath = url.getFile();
105 if (urlPath.endsWith("/"))
106 urlPath = urlPath.substring(0, urlPath.length() - 1);
107 paths.add(urlPath);
108 }
109 }
110 else {
111 for (Enumeration<URL> urlEnum = loader.getResources(marker); urlEnum.hasMoreElements(); ) {
112 String urlPath = URLDecoder.decode(urlEnum.nextElement().getFile(), "UTF-8");
113
114 if (urlPath.startsWith("file:"))
115 urlPath = urlPath.substring(5);
116
117 // Jars.
118 if (urlPath.indexOf('!') > 0)
119 urlPath = urlPath.substring(0, urlPath.indexOf('!'));
120 // Regular directories.
121 else {
122 File dirOrArchive = new File(urlPath);
123
124 String[] tokens = marker.split("\\Q/\\E", -1);
125 for (int i = 0; i < tokens.length; i++)
126 dirOrArchive = dirOrArchive.getParentFile();
127
128 urlPath = dirOrArchive.getPath();
129 }
130
131 paths.add(urlPath);
132 }
133 }
134
135 for (String urlPath : paths) {
136 File file = new File(urlPath);
137 if (file.isDirectory())
138 handleDirectory(file, file);
139 else
140 handleArchive(file);
141 }
142 }
143
144
145 public void handleArchive(File file) throws ZipException, IOException {
146 ZipFile zip = new ZipFile(file);
147
148 ZipScannedItem markerItem = null;
149 if (marker != null) {
150 ZipEntry markerEntry = zip.getEntry(marker);
151 markerItem = new ZipScannedItem(this, null, zip, markerEntry);
152 for (ScannedItemHandler handler : handlers) {
153 boolean skip = handler.handleMarkerItem(markerItem);
154 if (skip)
155 return;
156 }
157 }
158
159 for (Enumeration<? extends ZipEntry> entries = zip.entries(); entries.hasMoreElements(); ) {
160 ZipEntry entry = entries.nextElement();
161 if (!entry.isDirectory() && (markerItem == null || !markerItem.getEntry().getName().equals(entry.getName()))) {
162 for (ScannedItemHandler handler : handlers)
163 handler.handleScannedItem(new ZipScannedItem(this, markerItem, zip, entry));
164 }
165 }
166 }
167
168 public void handleDirectory(File root, File path) {
169 FileScannedItem markerItem = null;
170 if (marker != null) {
171 File markerFile = new File(root, marker);
172 markerItem = new FileScannedItem(this, null, root, markerFile);
173 for (ScannedItemHandler handler : handlers) {
174 boolean skip = handler.handleMarkerItem(markerItem);
175 if (skip)
176 return;
177 }
178 }
179 handleDirectory(markerItem, root, path);
180 }
181
182 public void handleDirectory(FileScannedItem markerItem, File root, File path) {
183 for (File child : path.listFiles()) {
184 if (child.isDirectory())
185 handleDirectory(markerItem, root, child);
186 else if (markerItem == null || !markerItem.getFile().equals(child)) {
187 for (ScannedItemHandler handler : handlers)
188 handler.handleScannedItem(new FileScannedItem(this, markerItem, root, child));
189 }
190 }
191 }
192 }