JBoss6VFS.java

  1. /*
  2.  *    Copyright 2010-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.  *       https://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.migration.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 java.util.logging.Level;
  24. import java.util.logging.Logger;

  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 Logger log = Logger.getLogger(JBoss6VFS.class.getName());

  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.log(Level.SEVERE, "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, "getChildrenRecursively"));
  84.       VirtualFile.getPathNameRelativeTo = checkNotNull(
  85.           getMethod(VirtualFile.VirtualFile, "getPathNameRelativeTo", VirtualFile.VirtualFile));

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

  92.   /**
  93.    * Verifies that the provided object reference is null. If it is null, then this VFS is marked as invalid for the
  94.    * current environment.
  95.    *
  96.    * @param <T>
  97.    *          the generic type
  98.    * @param object
  99.    *          The object reference to check for null.
  100.    *
  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 this VFS is marked as
  111.    * invalid for the current environment.
  112.    *
  113.    * @param method
  114.    *          The method whose return type is to be checked.
  115.    * @param expected
  116.    *          A type to which the method's return type must be assignable.
  117.    *
  118.    * @see Class#isAssignableFrom(Class)
  119.    */
  120.   protected static void checkReturnType(Method method, Class<?> expected) {
  121.     if (method != null && !expected.isAssignableFrom(method.getReturnType())) {
  122.       log.log(Level.SEVERE, "Method " + method.getClass().getName() + "." + method.getName() + "(..) should return "
  123.           + expected.getName() + " but returns " + method.getReturnType().getName() + " instead.");
  124.       setInvalid();
  125.     }
  126.   }

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

  136.   static {
  137.     initialize();
  138.   }

  139.   @Override
  140.   public boolean isValid() {
  141.     return valid;
  142.   }

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

  150.     if (!path.endsWith("/")) {
  151.       path += "/";
  152.     }

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

  158.     return names;
  159.   }
  160. }