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.util.ArrayList; 029import java.util.Collection; 030import java.util.Enumeration; 031import java.util.List; 032 033import org.jboss.virtual.VFS; 034import org.jboss.virtual.VirtualFile; 035 036/** 037 * @author Franck WOLFF 038 */ 039public class VFSScanner 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 VFSScanner(ScannedItemHandler handler) { 052 this(handler, null, Thread.currentThread().getContextClassLoader()); 053 } 054 055 public VFSScanner(ScannedItemHandler handler, String marker) { 056 this(handler, marker, Thread.currentThread().getContextClassLoader()); 057 } 058 059 public VFSScanner(ScannedItemHandler handler, ClassLoader loader) { 060 this(handler, null, loader); 061 } 062 063 public VFSScanner(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 VFSFileScannedItem markerItem = null; 117 118 if (markerUrl != null) { 119 VirtualFile markerFile = VFS.getRoot(markerUrl); 120 markerItem = new VFSFileScannedItem(this, null, markerFile, markerFile); 121 for (ScannedItemHandler handler : handlers) { 122 boolean skip = handler.handleMarkerItem(markerItem); 123 if (skip) 124 return; 125 } 126 } 127 128 if (root.isLeaf()) { 129 for (ScannedItemHandler handler : handlers) 130 handler.handleScannedItem(new VFSFileScannedItem(this, markerItem, root, root)); 131 } 132 else { 133 String rootPathName = root.getPathName(); 134 int rootPathNameLength = rootPathName.length(); 135 List<VirtualFile> children = root.getChildrenRecursively(); 136 for (VirtualFile child : children) { 137 if (child.isLeaf()) { 138 String name = child.getPathName(); 139 // move past '/' 140 int length = rootPathNameLength; 141 if (name.charAt(length) == '/') 142 length++; 143 for (ScannedItemHandler handler : handlers) 144 handler.handleScannedItem(new VFSFileScannedItem(this, markerItem, root, child)); 145 } 146 } 147 } 148 } 149 150 151 protected static VirtualFile getRoot(URL url, int parentDepth) throws IOException { 152 String urlString = url.toString(); 153 // TODO - this should go away once we figure out why -exp.war is part of CL resources 154 if (urlString.startsWith("vfs") == false) 155 return null; 156 157 int p = urlString.indexOf(":"); 158 String file = urlString.substring(p + 1); 159 URL vfsurl = null; 160 String relative; 161 File fp = new File(file); 162 163 if (fp.exists()) { 164 vfsurl = fp.getParentFile().toURI().toURL(); 165 relative = fp.getName(); 166 } 167 else { 168 File curr = fp; 169 relative = fp.getName(); 170 while ((curr = curr.getParentFile()) != null) { 171 if (curr.exists()) { 172 vfsurl = curr.toURI().toURL(); 173 break; 174 } 175 176 relative = curr.getName() + "/" + relative; 177 } 178 } 179 180 VirtualFile top = VFS.getRoot(vfsurl); 181 top = top.getChild(relative); 182 while (parentDepth > 0) { 183 if (top == null) 184 throw new IllegalArgumentException("Null parent: " + vfsurl + ", relative: " + relative); 185 top = top.getParent(); 186 parentDepth--; 187 } 188 189 return top; 190 } 191}