001/* 002 GRANITE DATA SERVICES 003 Copyright (C) 2011 GRANITE DATA SERVICES S.A.S. 004 005 This file is part of Granite Data Services. 006 007 Granite Data Services is free software; you can redistribute it and/or modify 008 it under the terms of the GNU Lesser General Public License as published by 009 the Free Software Foundation; either version 3 of the License, or (at your 010 option) any later version. 011 012 Granite Data Services is distributed in the hope that it will be useful, but 013 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 014 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 015 for more details. 016 017 You should have received a copy of the GNU Lesser General Public License 018 along with this library; if not, see <http://www.gnu.org/licenses/>. 019*/ 020 021package org.granite.scan; 022 023import java.io.File; 024import java.io.IOException; 025import java.net.URISyntaxException; 026import java.net.URL; 027import java.net.URLClassLoader; 028import java.util.ArrayList; 029import java.util.Collection; 030import java.util.Enumeration; 031import java.util.List; 032 033import org.jboss.vfs.VFS; 034import org.jboss.vfs.VirtualFile; 035 036/** 037 * @author Franck WOLFF 038 */ 039public class VFS3Scanner implements Scanner { 040 041 /////////////////////////////////////////////////////////////////////////// 042 // Fields. 043 044 private final List<ScannedItemHandler> handlers = new ArrayList<ScannedItemHandler>(); 045 private final String marker; 046 private final ClassLoader loader; 047 048 /////////////////////////////////////////////////////////////////////////// 049 // Constructors. 050 051 public VFS3Scanner(ScannedItemHandler handler) { 052 this(handler, null, Thread.currentThread().getContextClassLoader()); 053 } 054 055 public VFS3Scanner(ScannedItemHandler handler, String marker) { 056 this(handler, marker, Thread.currentThread().getContextClassLoader()); 057 } 058 059 public VFS3Scanner(ScannedItemHandler handler, ClassLoader loader) { 060 this(handler, null, loader); 061 } 062 063 public VFS3Scanner(ScannedItemHandler handler, String marker, ClassLoader loader) { 064 this.marker = marker; 065 this.handlers.add(handler); 066 this.loader = loader; 067 } 068 069 /////////////////////////////////////////////////////////////////////////// 070 // Properties. 071 072 public String getMarker() { 073 return marker; 074 } 075 076 public void addHandler(ScannedItemHandler handler) { 077 if (!handlers.contains(handler)) 078 handlers.add(handler); 079 } 080 081 public void addHandlers(Collection<ScannedItemHandler> handlers) { 082 for (ScannedItemHandler handler : handlers) 083 addHandler(handler); 084 } 085 086 public ClassLoader getLoader() { 087 return loader; 088 } 089 090 /////////////////////////////////////////////////////////////////////////// 091 // Scan methods. 092 093 public void scan() throws IOException { 094 if (marker == null) { 095 if (!(loader instanceof URLClassLoader)) 096 throw new RuntimeException("ClassLoader used with no marker should be a URLClassLoader: " + loader); 097 098 for (URL url : ((URLClassLoader)loader).getURLs()) { 099 VirtualFile root = getRoot(url, 1); 100 if (root != null) 101 handleRoot(null, root); 102 } 103 } 104 else { 105 for (Enumeration<URL> urlEnum = loader.getResources(marker); urlEnum.hasMoreElements(); ) { 106 URL url = urlEnum.nextElement(); 107 VirtualFile root = getRoot(url, marker.lastIndexOf('/') > 0 ? 2 : 1); 108 if (root != null) 109 handleRoot(url, root); 110 } 111 } 112 } 113 114 115 protected void handleRoot(URL markerUrl, VirtualFile root) throws IOException { 116 VFS3FileScannedItem markerItem = null; 117 118 if (markerUrl != null) { 119 try { 120 VirtualFile markerFile = VFS.getChild(markerUrl); 121 markerItem = new VFS3FileScannedItem(this, null, markerFile, markerFile); 122 for (ScannedItemHandler handler : handlers) { 123 boolean skip = handler.handleMarkerItem(markerItem); 124 if (skip) 125 return; 126 } 127 } 128 catch (URISyntaxException e) { 129 IOException ex = new IOException("Invalid URI " + markerUrl); 130 ex.initCause(e); 131 throw ex; 132 } 133 } 134 135 if (root.isFile()) { 136 for (ScannedItemHandler handler : handlers) 137 handler.handleScannedItem(new VFS3FileScannedItem(this, markerItem, root, root)); 138 } 139 else { 140 String rootPathName = root.getPathName(); 141 int rootPathNameLength = rootPathName.length(); 142 List<VirtualFile> children = root.getChildrenRecursively(); 143 for (VirtualFile child : children) { 144 if (child.isFile()) { 145 String name = child.getPathName(); 146 // move past '/' 147 int length = rootPathNameLength; 148 if (name.charAt(length) == '/') 149 length++; 150 for (ScannedItemHandler handler : handlers) 151 handler.handleScannedItem(new VFS3FileScannedItem(this, markerItem, root, child)); 152 } 153 } 154 } 155 } 156 157 158 protected static VirtualFile getRoot(URL url, int parentDepth) throws IOException { 159 String urlString = url.toString(); 160 // TODO - this should go away once we figure out why -exp.war is part of CL resources 161 if (urlString.startsWith("vfs") == false) 162 return null; 163 164 int p = urlString.indexOf(":"); 165 String file = urlString.substring(p + 1); 166 URL vfsurl = null; 167 String relative; 168 File fp = new File(file); 169 170 if (fp.exists()) { 171 vfsurl = fp.getParentFile().toURI().toURL(); 172 relative = fp.getName(); 173 } 174 else { 175 File curr = fp; 176 relative = fp.getName(); 177 while ((curr = curr.getParentFile()) != null) { 178 if (curr.exists()) { 179 vfsurl = curr.toURI().toURL(); 180 break; 181 } 182 183 relative = curr.getName() + "/" + relative; 184 } 185 } 186 187 try { 188 VirtualFile top = VFS.getChild(vfsurl); 189 top = top.getChild(relative); 190 while (parentDepth > 0) { 191 if (top == null) 192 throw new IllegalArgumentException("Null parent: " + vfsurl + ", relative: " + relative); 193 top = top.getParent(); 194 parentDepth--; 195 } 196 197 return top; 198 } 199 catch (URISyntaxException e) { 200 IOException ex = new IOException("Invalid URI " + url); 201 ex.initCause(e); 202 throw ex; 203 } 204 } 205}