001/** 002 * GRANITE DATA SERVICES 003 * Copyright (C) 2006-2014 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.URISyntaxException; 027import java.net.URL; 028import java.net.URLClassLoader; 029import java.util.ArrayList; 030import java.util.Collection; 031import java.util.Enumeration; 032import java.util.List; 033 034import org.jboss.vfs.VFS; 035import org.jboss.vfs.VirtualFile; 036 037/** 038 * @author Franck WOLFF 039 */ 040public class VFS3Scanner implements Scanner { 041 042 /////////////////////////////////////////////////////////////////////////// 043 // Fields. 044 045 private final List<ScannedItemHandler> handlers = new ArrayList<ScannedItemHandler>(); 046 private final String marker; 047 private final ClassLoader loader; 048 049 /////////////////////////////////////////////////////////////////////////// 050 // Constructors. 051 052 public VFS3Scanner(ScannedItemHandler handler) { 053 this(handler, null, Thread.currentThread().getContextClassLoader()); 054 } 055 056 public VFS3Scanner(ScannedItemHandler handler, String marker) { 057 this(handler, marker, Thread.currentThread().getContextClassLoader()); 058 } 059 060 public VFS3Scanner(ScannedItemHandler handler, ClassLoader loader) { 061 this(handler, null, loader); 062 } 063 064 public VFS3Scanner(ScannedItemHandler handler, String marker, ClassLoader loader) { 065 this.marker = marker; 066 this.handlers.add(handler); 067 this.loader = loader; 068 } 069 070 /////////////////////////////////////////////////////////////////////////// 071 // Properties. 072 073 public String getMarker() { 074 return marker; 075 } 076 077 public void addHandler(ScannedItemHandler handler) { 078 if (!handlers.contains(handler)) 079 handlers.add(handler); 080 } 081 082 public void addHandlers(Collection<ScannedItemHandler> handlers) { 083 for (ScannedItemHandler handler : handlers) 084 addHandler(handler); 085 } 086 087 public ClassLoader getLoader() { 088 return loader; 089 } 090 091 /////////////////////////////////////////////////////////////////////////// 092 // Scan methods. 093 094 public void scan() throws IOException { 095 if (marker == null) { 096 if (!(loader instanceof URLClassLoader)) 097 throw new RuntimeException("ClassLoader used with no marker should be a URLClassLoader: " + loader); 098 099 for (URL url : ((URLClassLoader)loader).getURLs()) { 100 VirtualFile root = getRoot(url, 1); 101 if (root != null) 102 handleRoot(null, root); 103 } 104 } 105 else { 106 for (Enumeration<URL> urlEnum = loader.getResources(marker); urlEnum.hasMoreElements(); ) { 107 URL url = urlEnum.nextElement(); 108 VirtualFile root = getRoot(url, marker.lastIndexOf('/') > 0 ? 2 : 1); 109 if (root != null) 110 handleRoot(url, root); 111 } 112 } 113 } 114 115 116 protected void handleRoot(URL markerUrl, VirtualFile root) throws IOException { 117 VFS3FileScannedItem markerItem = null; 118 119 if (markerUrl != null) { 120 try { 121 @SuppressWarnings("deprecation") 122 VirtualFile markerFile = VFS.getChild(markerUrl); 123 markerItem = new VFS3FileScannedItem(this, null, markerFile, markerFile); 124 for (ScannedItemHandler handler : handlers) { 125 boolean skip = handler.handleMarkerItem(markerItem); 126 if (skip) 127 return; 128 } 129 } 130 catch (URISyntaxException e) { 131 IOException ex = new IOException("Invalid URI " + markerUrl); 132 ex.initCause(e); 133 throw ex; 134 } 135 } 136 137 if (root.isFile()) { 138 for (ScannedItemHandler handler : handlers) 139 handler.handleScannedItem(new VFS3FileScannedItem(this, markerItem, root, root)); 140 } 141 else { 142 String rootPathName = root.getPathName(); 143 int rootPathNameLength = rootPathName.length(); 144 List<VirtualFile> children = root.getChildrenRecursively(); 145 for (VirtualFile child : children) { 146 if (child.isFile()) { 147 String name = child.getPathName(); 148 // move past '/' 149 int length = rootPathNameLength; 150 if (name.charAt(length) == '/') 151 length++; 152 for (ScannedItemHandler handler : handlers) 153 handler.handleScannedItem(new VFS3FileScannedItem(this, markerItem, root, child)); 154 } 155 } 156 } 157 } 158 159 160 protected static VirtualFile getRoot(URL url, int parentDepth) throws IOException { 161 String urlString = url.toString(); 162 // TODO - this should go away once we figure out why -exp.war is part of CL resources 163 if (urlString.startsWith("vfs") == false) 164 return null; 165 166 int p = urlString.indexOf(":"); 167 String file = urlString.substring(p + 1); 168 URL vfsurl = null; 169 String relative; 170 File fp = new File(file); 171 172 if (fp.exists()) { 173 vfsurl = fp.getParentFile().toURI().toURL(); 174 relative = fp.getName(); 175 } 176 else { 177 File curr = fp; 178 relative = fp.getName(); 179 while ((curr = curr.getParentFile()) != null) { 180 if (curr.exists()) { 181 vfsurl = curr.toURI().toURL(); 182 break; 183 } 184 185 relative = curr.getName() + "/" + relative; 186 } 187 } 188 189 try { 190 @SuppressWarnings("deprecation") 191 VirtualFile top = VFS.getChild(vfsurl); 192 top = top.getChild(relative); 193 while (parentDepth > 0) { 194 if (top == null) 195 throw new IllegalArgumentException("Null parent: " + vfsurl + ", relative: " + relative); 196 top = top.getParent(); 197 parentDepth--; 198 } 199 200 return top; 201 } 202 catch (URISyntaxException e) { 203 IOException ex = new IOException("Invalid URI " + url); 204 ex.initCause(e); 205 throw ex; 206 } 207 } 208}