/* Copyright 2010 Ben Gunter * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.sourceforge.stripes.vfs; import java.io.IOException; import java.lang.reflect.Method; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.List; import net.sourceforge.stripes.util.Log; /** * A {@link VFS} implementation that works with the VFS API provided by JBoss 6. * * @author Ben Gunter */ public class JBoss6VFS extends net.sourceforge.stripes.vfs.VFS { private static final Log log = Log.getInstance(JBoss6VFS.class); /** A class that mimics a tiny subset of the JBoss VirtualFile class. */ static class VirtualFile { static Class<?> VirtualFile; static Method getPathNameRelativeTo, getChildrenRecursively; Object virtualFile; VirtualFile(Object virtualFile) { this.virtualFile = virtualFile; } String getPathNameRelativeTo(VirtualFile parent) { try { return invoke(getPathNameRelativeTo, virtualFile, parent.virtualFile); } catch (IOException e) { // This exception is not thrown by the called method log.error("This should not be possible. VirtualFile.getPathNameRelativeTo() threw IOException."); return null; } } List<VirtualFile> getChildren() throws IOException { List<?> objects = invoke(getChildrenRecursively, virtualFile); List<VirtualFile> children = new ArrayList<VirtualFile>(objects.size()); for (Object object : objects) { children.add(new VirtualFile(object)); } return children; } } /** A class that mimics a tiny subset of the JBoss VFS class. */ static class VFS { static Class<?> VFS; static Method getChild; static VirtualFile getChild(URL url) throws IOException { Object o = invoke(getChild, VFS, url); return o == null ? null : new VirtualFile(o); } } /** Flag that indicates if this VFS is valid for the current environment. */ private static Boolean valid; /** Find all the classes and methods that are required to access the JBoss 6 VFS. */ protected static synchronized void initialize() { if (valid == null) { // Assume valid. It will get flipped later if something goes wrong. valid = true; // Look up and verify required classes VFS.VFS = checkNotNull(getClass("org.jboss.vfs.VFS")); VirtualFile.VirtualFile = checkNotNull(getClass("org.jboss.vfs.VirtualFile")); // Look up and verify required methods VFS.getChild = checkNotNull(getMethod(VFS.VFS, "getChild", URL.class)); VirtualFile.getChildrenRecursively = checkNotNull(getMethod(VirtualFile.VirtualFile, "getChildrenRecursively")); VirtualFile.getPathNameRelativeTo = checkNotNull(getMethod(VirtualFile.VirtualFile, "getPathNameRelativeTo", VirtualFile.VirtualFile)); // Verify that the API has not changed checkReturnType(VFS.getChild, VirtualFile.VirtualFile); checkReturnType(VirtualFile.getChildrenRecursively, List.class); checkReturnType(VirtualFile.getPathNameRelativeTo, String.class); } } /** * Verifies that the provided object reference is null. If it is null, then this VFS is marked * as invalid for the current environment. * * @param object The object reference to check for null. */ protected static <T> T checkNotNull(T object) { if (object == null) setInvalid(); return object; } /** * Verifies that the return type of a method is what it is expected to be. If it is not, then * this VFS is marked as invalid for the current environment. * * @param method The method whose return type is to be checked. * @param expected A type to which the method's return type must be assignable. * @see Class#isAssignableFrom(Class) */ protected static void checkReturnType(Method method, Class<?> expected) { if (method != null && !expected.isAssignableFrom(method.getReturnType())) { log.warn("Method ", method.getClass().getName(), ".", method.getName(), "(..) should return ", expected.getName(), " but returns ", // method.getReturnType().getName(), " instead."); setInvalid(); } } /** Mark this {@link VFS} as invalid for the current environment. */ protected static void setInvalid() { if (JBoss6VFS.valid != null && JBoss6VFS.valid) { log.debug("JBoss 6 VFS API is not available in this environment."); JBoss6VFS.valid = false; } } static { initialize(); } @Override public boolean isValid() { return valid; } @Override public List<String> list(URL url, String path) throws IOException { VirtualFile directory; directory = VFS.getChild(url); if (directory == null) return Collections.emptyList(); if (!path.endsWith("/")) path += "/"; List<VirtualFile> children = directory.getChildren(); List<String> names = new ArrayList<String>(children.size()); for (VirtualFile vf : children) { String relative = vf.getPathNameRelativeTo(directory); names.add(path + relative); } return names; } }