JBoss6VFS.java

  1. /*
  2.  *    Copyright 2009-2022 the original author or authors.
  3.  *
  4.  *    Licensed under the Apache License, Version 2.0 (the "License");
  5.  *    you may not use this file except in compliance with the License.
  6.  *    You may obtain a copy of the License at
  7.  *
  8.  *       http://www.apache.org/licenses/LICENSE-2.0
  9.  *
  10.  *    Unless required by applicable law or agreed to in writing, software
  11.  *    distributed under the License is distributed on an "AS IS" BASIS,
  12.  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13.  *    See the License for the specific language governing permissions and
  14.  *    limitations under the License.
  15.  */
  16. package org.apache.ibatis.io;

  17. import java.io.IOException;
  18. import java.lang.reflect.Method;
  19. import java.net.URL;
  20. import java.util.ArrayList;
  21. import java.util.Collections;
  22. import java.util.List;

  23. import org.apache.ibatis.logging.Log;
  24. import org.apache.ibatis.logging.LogFactory;

  25. /**
  26.  * A {@link VFS} implementation that works with the VFS API provided by JBoss 6.
  27.  *
  28.  * @author Ben Gunter
  29.  */
  30. public class JBoss6VFS extends VFS {
  31.   private static final Log log = LogFactory.getLog(JBoss6VFS.class);

  32.   /** A class that mimics a tiny subset of the JBoss VirtualFile class. */
  33.   static class VirtualFile {
  34.     static Class<?> VirtualFile;
  35.     static Method getPathNameRelativeTo;
  36.     static Method getChildrenRecursively;

  37.     Object virtualFile;

  38.     VirtualFile(Object virtualFile) {
  39.       this.virtualFile = virtualFile;
  40.     }

  41.     String getPathNameRelativeTo(VirtualFile parent) {
  42.       try {
  43.         return invoke(getPathNameRelativeTo, virtualFile, parent.virtualFile);
  44.       } catch (IOException e) {
  45.         // This exception is not thrown by the called method
  46.         log.error("This should not be possible. VirtualFile.getPathNameRelativeTo() threw IOException.");
  47.         return null;
  48.       }
  49.     }

  50.     List<VirtualFile> getChildren() throws IOException {
  51.       List<?> objects = invoke(getChildrenRecursively, virtualFile);
  52.       List<VirtualFile> children = new ArrayList<>(objects.size());
  53.       for (Object object : objects) {
  54.         children.add(new VirtualFile(object));
  55.       }
  56.       return children;
  57.     }
  58.   }

  59.   /** A class that mimics a tiny subset of the JBoss VFS class. */
  60.   static class VFS {
  61.     static Class<?> VFS;
  62.     static Method getChild;

  63.     private VFS() {
  64.       // Prevent Instantiation
  65.     }

  66.     static VirtualFile getChild(URL url) throws IOException {
  67.       Object o = invoke(getChild, VFS, url);
  68.       return o == null ? null : new VirtualFile(o);
  69.     }
  70.   }

  71.   /** Flag that indicates if this VFS is valid for the current environment. */
  72.   private static Boolean valid;

  73.   /** Find all the classes and methods that are required to access the JBoss 6 VFS. */
  74.   protected static synchronized void initialize() {
  75.     if (valid == null) {
  76.       // Assume valid. It will get flipped later if something goes wrong.
  77.       valid = Boolean.TRUE;

  78.       // Look up and verify required classes
  79.       VFS.VFS = checkNotNull(getClass("org.jboss.vfs.VFS"));
  80.       VirtualFile.VirtualFile = checkNotNull(getClass("org.jboss.vfs.VirtualFile"));

  81.       // Look up and verify required methods
  82.       VFS.getChild = checkNotNull(getMethod(VFS.VFS, "getChild", URL.class));
  83.       VirtualFile.getChildrenRecursively = checkNotNull(getMethod(VirtualFile.VirtualFile,
  84.           "getChildrenRecursively"));
  85.       VirtualFile.getPathNameRelativeTo = checkNotNull(getMethod(VirtualFile.VirtualFile,
  86.           "getPathNameRelativeTo", VirtualFile.VirtualFile));

  87.       // Verify that the API has not changed
  88.       checkReturnType(VFS.getChild, VirtualFile.VirtualFile);
  89.       checkReturnType(VirtualFile.getChildrenRecursively, List.class);
  90.       checkReturnType(VirtualFile.getPathNameRelativeTo, String.class);
  91.     }
  92.   }

  93.   /**
  94.    * Verifies that the provided object reference is null. If it is null, then this VFS is marked
  95.    * as invalid for the current environment.
  96.    *
  97.    * @param <T>
  98.    *          the generic type
  99.    * @param object
  100.    *          The object reference to check for null.
  101.    * @return the t
  102.    */
  103.   protected static <T> T checkNotNull(T object) {
  104.     if (object == null) {
  105.       setInvalid();
  106.     }
  107.     return object;
  108.   }

  109.   /**
  110.    * Verifies that the return type of method is what it is expected to be. If it is not, then
  111.    * this VFS is marked as invalid for the current environment.
  112.    *
  113.    * @param method The method whose return type is to be checked.
  114.    * @param expected A type to which the method's return type must be assignable.
  115.    * @see Class#isAssignableFrom(Class)
  116.    */
  117.   protected static void checkReturnType(Method method, Class<?> expected) {
  118.     if (method != null && !expected.isAssignableFrom(method.getReturnType())) {
  119.       log.error("Method " + method.getClass().getName() + "." + method.getName()
  120.           + "(..) should return " + expected.getName() + " but returns "
  121.           + method.getReturnType().getName() + " instead.");
  122.       setInvalid();
  123.     }
  124.   }

  125.   /**
  126.    * Mark this {@link VFS} as invalid for the current environment.
  127.    */
  128.   protected static void setInvalid() {
  129.     if (JBoss6VFS.valid.booleanValue()) {
  130.       log.debug("JBoss 6 VFS API is not available in this environment.");
  131.       JBoss6VFS.valid = Boolean.FALSE;
  132.     }
  133.   }

  134.   static {
  135.     initialize();
  136.   }

  137.   @Override
  138.   public boolean isValid() {
  139.     return valid;
  140.   }

  141.   @Override
  142.   public List<String> list(URL url, String path) throws IOException {
  143.     VirtualFile directory;
  144.     directory = VFS.getChild(url);
  145.     if (directory == null) {
  146.       return Collections.emptyList();
  147.     }

  148.     if (!path.endsWith("/")) {
  149.       path += "/";
  150.     }

  151.     List<VirtualFile> children = directory.getChildren();
  152.     List<String> names = new ArrayList<>(children.size());
  153.     for (VirtualFile vf : children) {
  154.       names.add(path + vf.getPathNameRelativeTo(directory));
  155.     }

  156.     return names;
  157.   }
  158. }