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 */ 022package org.granite.scan; 023 024import java.io.File; 025import java.io.IOException; 026import java.net.URL; 027import java.net.URLClassLoader; 028import java.net.URLDecoder; 029import java.util.ArrayList; 030import java.util.Collection; 031import java.util.Enumeration; 032import java.util.HashSet; 033import java.util.List; 034import java.util.Set; 035import java.util.zip.ZipEntry; 036import java.util.zip.ZipException; 037import java.util.zip.ZipFile; 038 039/** 040 * @author Franck WOLFF 041 */ 042public 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}