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.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 VirtualFile markerFile = VFS.getChild(markerUrl); 122 markerItem = new VFS3FileScannedItem(this, null, markerFile, markerFile); 123 for (ScannedItemHandler handler : handlers) { 124 boolean skip = handler.handleMarkerItem(markerItem); 125 if (skip) 126 return; 127 } 128 } 129 catch (URISyntaxException e) { 130 IOException ex = new IOException("Invalid URI " + markerUrl); 131 ex.initCause(e); 132 throw ex; 133 } 134 } 135 136 if (root.isFile()) { 137 for (ScannedItemHandler handler : handlers) 138 handler.handleScannedItem(new VFS3FileScannedItem(this, markerItem, root, root)); 139 } 140 else { 141 String rootPathName = root.getPathName(); 142 int rootPathNameLength = rootPathName.length(); 143 List<VirtualFile> children = root.getChildrenRecursively(); 144 for (VirtualFile child : children) { 145 if (child.isFile()) { 146 String name = child.getPathName(); 147 // move past '/' 148 int length = rootPathNameLength; 149 if (name.charAt(length) == '/') 150 length++; 151 for (ScannedItemHandler handler : handlers) 152 handler.handleScannedItem(new VFS3FileScannedItem(this, markerItem, root, child)); 153 } 154 } 155 } 156 } 157 158 159 protected static VirtualFile getRoot(URL url, int parentDepth) throws IOException { 160 String urlString = url.toString(); 161 // TODO - this should go away once we figure out why -exp.war is part of CL resources 162 if (urlString.startsWith("vfs") == false) 163 return null; 164 165 int p = urlString.indexOf(":"); 166 String file = urlString.substring(p + 1); 167 URL vfsurl = null; 168 String relative; 169 File fp = new File(file); 170 171 if (fp.exists()) { 172 vfsurl = fp.getParentFile().toURI().toURL(); 173 relative = fp.getName(); 174 } 175 else { 176 File curr = fp; 177 relative = fp.getName(); 178 while ((curr = curr.getParentFile()) != null) { 179 if (curr.exists()) { 180 vfsurl = curr.toURI().toURL(); 181 break; 182 } 183 184 relative = curr.getName() + "/" + relative; 185 } 186 } 187 188 try { 189 VirtualFile top = VFS.getChild(vfsurl); 190 top = top.getChild(relative); 191 while (parentDepth > 0) { 192 if (top == null) 193 throw new IllegalArgumentException("Null parent: " + vfsurl + ", relative: " + relative); 194 top = top.getParent(); 195 parentDepth--; 196 } 197 198 return top; 199 } 200 catch (URISyntaxException e) { 201 IOException ex = new IOException("Invalid URI " + url); 202 ex.initCause(e); 203 throw ex; 204 } 205 } 206}