content: /*
   *  Licensed to the Apache Software Foundation (ASF) under one or more
   *  contributor license agreements.  See the NOTICE file distributed with
   *  this work for additional information regarding copyright ownership.
   *  The ASF licenses this file to You 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
   *
   *      https://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 org.apache.ivy.plugins.repository.vfs;
  
  import java.io.IOException;
  import java.io.InputStream;
  import java.util.ArrayList;
  import java.util.List;
  
  import org.apache.commons.vfs2.FileContent;
  import org.apache.commons.vfs2.FileObject;
  import org.apache.commons.vfs2.FileSystemException;
  import org.apache.commons.vfs2.FileSystemManager;
  import org.apache.commons.vfs2.FileType;
  import org.apache.ivy.plugins.repository.Resource;
  import org.apache.ivy.plugins.resolver.VfsResolver;
  import org.apache.ivy.util.Message;
  
  /**
   * VFS implementation of the Resource interface
   */
  public class VfsResource implements Resource {
      private String vfsURI;
  
      private FileSystemManager fsManager;
  
      private transient boolean init = false;
  
      private transient boolean exists;
  
      private transient long lastModified;
  
      private transient long contentLength;
  
      private transient FileContent content = null;
  
      private transient FileObject resourceImpl;
  
      // Constructor
      public VfsResource(String vfsURI, FileSystemManager fsManager) {
          this.vfsURI = vfsURI;
          this.fsManager = fsManager;
          this.init = false;
      }
  
      private void init() {
          if (!init) {
              try {
                  resourceImpl = fsManager.resolveFile(vfsURI);
                  content = resourceImpl.getContent();
                  exists = resourceImpl.exists();
                  lastModified = content.getLastModifiedTime();
                  contentLength = content.getSize();
              } catch (FileSystemException e) {
                  Message.debug(e);
                  Message.verbose(e.getLocalizedMessage());
                  exists = false;
                  lastModified = 0;
                  contentLength = 0;
              }
              init = true;
          }
      }
  
      /**
       * Get a list of direct descendants of the given resource. Note that attempts to get a list of
       * children does <em>not</em> result in an error. Instead an error message is
       * logged and an empty ArrayList returned.
       *
       * @return A <code>ArrayList</code> of VFSResources
       */
      public List<String> getChildren() {
          init();
          List<String> list = new ArrayList<>();
          try {
              if (resourceImpl != null && resourceImpl.exists()
                      && resourceImpl.getType() == FileType.FOLDER) {
                  for (FileObject child : resourceImpl.getChildren()) {
                      list.add(normalize(child.getName().getURI()));
                  }
              }
          } catch (IOException e) {
              Message.debug(e);
              Message.verbose(e.getLocalizedMessage());
          }
          return list;
      }
  
      public FileContent getContent() {
          init();
          return content;
      }
  
      /**
       * Get the name of the resource.
       *
       * @return a <code>String</code> representing the Resource URL.
       */
      public String getName() {
          return normalize(vfsURI);
      }
  
      public Resource clone(String cloneName) {
          return new VfsResource(cloneName, fsManager);
      }
  
      /**
       * The VFS FileName getURI method seems to have a bug in it where file: URIs will have 4 forward
       * slashes instead of 3.
       *
       * @param vfsURI ditto
       * @return a normalized String representing the VFS URI
       */
      public static String normalize(String vfsURI) {
          if (vfsURI == null) {
              return "";
          }
  
          if (vfsURI.startsWith("file:////")) {
              vfsURI = vfsURI.replaceFirst("////", "///");
          }
          return vfsURI;
      }
  
      /**
       * Get the last modification time of the resource.
       *
       * @return a <code>long</code> indicating last modified time.
       */
      public long getLastModified() {
          init();
          return lastModified;
      }
  
      /**
       * Get the size of the resource
       *
       * @return a <code>long</code> representing the size of the resource (in bytes).
       */
      public long getContentLength() {
          init();
          return contentLength;
      }
  
      /**
       * Flag indicating whether a resource is available for querying
       *
       * @return <code>true</code> if the resource is available for querying, <code>false</code>
       *         otherwise.
       */
      public boolean exists() {
          init();
          return exists;
      }
  
      /**
       * Return a flag indicating whether a provided VFS resource physically exists
       *
       * @return <code>true</code> if the resource physically exists, <code>false</code> otherwise.
       */
      public boolean physicallyExists() {
          // TODO: there is no need for this method anymore, replace it by calling exists();
          init();
  
          try {
              return resourceImpl.exists();
              // originally I only checked for a FileSystemException. I expanded it to
              // include all exceptions when I found it would throw a NPE exception when the query was
              // run on ill-formed VFS URI.
          } catch (Exception e) {
              Message.verbose("Fail to check the existence of the resource " + getName(), e);
              return false;
          }
      }
  
      public String toString() {
          return VfsResolver.prepareForDisplay(getName());
      }
  
      public boolean isLocal() {
          return getName().startsWith("file:");
      }
  
      public InputStream openStream() throws IOException {
          return getContent().getInputStream();
      }
  }
  