jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ste...@apache.org
Subject svn commit: r156521 - in incubator/jackrabbit/trunk/contrib/vfs: ./ src/ src/java/ src/java/org/ src/java/org/apache/ src/java/org/apache/jackrabbit/ src/java/org/apache/jackrabbit/core/ src/java/org/apache/jackrabbit/core/fs/ src/java/org/apache/jackrabbit/core/fs/vfs/ src/test/ src/test/org/ src/test/org/apache/ src/test/org/apache/jackrabbit/ src/test/org/apache/jackrabbit/core/ src/test/org/apache/jackrabbit/core/fs/ src/test/org/apache/jackrabbit/core/fs/vfs/
Date Tue, 08 Mar 2005 12:36:08 GMT
Author: stefan
Date: Tue Mar  8 04:36:05 2005
New Revision: 156521

URL: http://svn.apache.org/viewcvs?view=rev&rev=156521
Log:
adding Commons VFS-backed FileSystem implementation contributed by edgar poce to contrib directory
(http://issues.apache.org/jira/browse/JCR-55)

Added:
    incubator/jackrabbit/trunk/contrib/vfs/
    incubator/jackrabbit/trunk/contrib/vfs/05-03-03-repository.xml   (with props)
    incubator/jackrabbit/trunk/contrib/vfs/README.txt   (with props)
    incubator/jackrabbit/trunk/contrib/vfs/src/
    incubator/jackrabbit/trunk/contrib/vfs/src/java/
    incubator/jackrabbit/trunk/contrib/vfs/src/java/org/
    incubator/jackrabbit/trunk/contrib/vfs/src/java/org/apache/
    incubator/jackrabbit/trunk/contrib/vfs/src/java/org/apache/jackrabbit/
    incubator/jackrabbit/trunk/contrib/vfs/src/java/org/apache/jackrabbit/core/
    incubator/jackrabbit/trunk/contrib/vfs/src/java/org/apache/jackrabbit/core/fs/
    incubator/jackrabbit/trunk/contrib/vfs/src/java/org/apache/jackrabbit/core/fs/vfs/
    incubator/jackrabbit/trunk/contrib/vfs/src/java/org/apache/jackrabbit/core/fs/vfs/VFSFileSystem.java
  (with props)
    incubator/jackrabbit/trunk/contrib/vfs/src/java/org/apache/jackrabbit/core/fs/vfs/VFSRAFOutputStream.java
  (with props)
    incubator/jackrabbit/trunk/contrib/vfs/src/java/providers.xml   (with props)
    incubator/jackrabbit/trunk/contrib/vfs/src/test/
    incubator/jackrabbit/trunk/contrib/vfs/src/test/org/
    incubator/jackrabbit/trunk/contrib/vfs/src/test/org/apache/
    incubator/jackrabbit/trunk/contrib/vfs/src/test/org/apache/jackrabbit/
    incubator/jackrabbit/trunk/contrib/vfs/src/test/org/apache/jackrabbit/core/
    incubator/jackrabbit/trunk/contrib/vfs/src/test/org/apache/jackrabbit/core/fs/
    incubator/jackrabbit/trunk/contrib/vfs/src/test/org/apache/jackrabbit/core/fs/vfs/
    incubator/jackrabbit/trunk/contrib/vfs/src/test/org/apache/jackrabbit/core/fs/vfs/VFSFileSystemTest.java
  (with props)

Added: incubator/jackrabbit/trunk/contrib/vfs/05-03-03-repository.xml
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/vfs/05-03-03-repository.xml?view=auto&rev=156521
==============================================================================
--- incubator/jackrabbit/trunk/contrib/vfs/05-03-03-repository.xml (added)
+++ incubator/jackrabbit/trunk/contrib/vfs/05-03-03-repository.xml Tue Mar  8 04:36:05 2005
@@ -0,0 +1,228 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!-- <!DOCTYPE Repository PUBLIC "-//The Apache Software Foundation//DTD Repository//EN"
"file://config.dtd"> -->
+<!DOCTYPE Repository [
+    <!--
+        the Repository element configures a repository instance;
+        individual workspaces of the repository are configured through
+        separate configuration files called workspace.xml which are
+        located in a subfolder of the workspaces root directory
+        (see Workspaces element).
+
+        it consists of
+
+            a FileSystem element (the virtual file system
+            used by the repository to persist global state such as
+            registered namespaces, custom node types, etc..
+
+            a Security element that specifies the name of the app-entry
+            in the JAAS config and the access manager
+
+            a Workspaces element that specifies to the location of
+            workspaces root directory and the name of default workspace
+
+            a Workspace element that is used as a workspace configuration
+            template; it is used to create the initial workspace if there's
+            no workspace yet and for creating additional workspaces through
+            the api
+
+            a SearchIndex element that is used for configuring per workspace
+            Indexing-related settings
+
+            a Versioning element that is used for configuring
+            versioning-related settings
+    -->
+    <!ELEMENT Repository (FileSystem,Security,Workspaces,Workspace,Versioning)>
+
+    <!--
+        a virtual file system
+    -->
+    <!ELEMENT FileSystem (param*)>
+    <!ATTLIST FileSystem
+      class CDATA #REQUIRED>
+
+    <!--
+        the Security element specifies the name (appName attribute)
+        of the JAAS configuration app-entry for this repository. 
+
+        it also specifies the access manager to be used (AccessManager element).
+    -->
+    <!ELEMENT Security (AccessManager)>
+    <!ATTLIST Security
+      appName CDATA #REQUIRED>
+
+    <!--
+        the AccessManager element configures the access manager to be used by
+        this repository instance; the class attribute specifies the FQN of the
+        class implementing the AccessManager interface
+    -->
+    <!ELEMENT AccessManager (param*)>
+    <!ATTLIST AccessManager
+      class CDATA #REQUIRED>
+
+    <!--
+        generic parameter (name/value pair)
+    -->
+    <!ELEMENT param EMPTY>
+    <!ATTLIST param
+      name CDATA #REQUIRED
+      value CDATA #REQUIRED>
+
+    <!--
+        the Workspaces element specifies the workspaces root directory
+        (rootPath attribute) and the name of the default workspace
+        (defaultWorkspace attribute).
+
+        individual workspaces are configured through individual workspace.xml
+        files located in a subfolder each of the workspaces root directory.
+    -->
+    <!ELEMENT Workspaces EMPTY>
+    <!ATTLIST Workspaces
+      rootPath CDATA #REQUIRED
+      defaultWorkspace CDATA #REQUIRED>
+
+    <!--
+        the Workspace element serves as a workspace configuration template;
+        it is used to create the initial workspace if there's no workspace yet
+        and for creating additional workspaces through the api
+    -->
+    <!ELEMENT Workspace (FileSystem,PersistenceManager,SearchIndex?)>
+    <!ATTLIST Workspace
+      name CDATA #REQUIRED>
+
+    <!--
+        the PersistenceManager element configures the persistence manager
+        to be used for the workspace; the class attribute specifies the
+        FQN of the class implementing the PersistenceManager interface
+    -->
+    <!ELEMENT PersistenceManager (param*)>
+    <!ATTLIST PersistenceManager
+      class CDATA #REQUIRED>
+
+    <!--
+        the SearchIndex element specifies the locaction of the search index
+        (used by the QueryHandler); the class attribute specifies the
+        FQN of the class implementing the QueryHandler interface.
+    -->
+    <!ELEMENT SearchIndex (param*,FileSystem)>
+    <!ATTLIST SearchIndex
+      class CDATA #REQUIRED>
+
+    <!--
+        the Versioning element configures the persistence manager
+        to be used for persisting version state
+    -->
+    <!ELEMENT Versioning (FileSystem, PersistenceManager)>
+    <!ATTLIST Versioning
+      rootPath CDATA #REQUIRED
+    >
+]>
+<!-- Example Repository Configuration File -->
+<Repository>
+    <!--
+        virtual file system where the repository stores global state
+        (e.g. registered namespaces, custom node types, etc.)
+    -->
+    <FileSystem class="org.apache.jackrabbit.core.fs.vfs.VFSFileSystem">
+        <param name="path" value="${rep.home}/repository"/>
+        <param name="prefix" value="tmp"/>
+        <param name="config" value="providers.xml" /> 
+    </FileSystem>
+
+    <!--
+        security configuration
+    -->
+    <Security appName="Jackrabbit">
+        <!--
+            access manager:
+            class: FQN of class implementing the AccessManager interface
+        -->
+        <AccessManager class="org.apache.jackrabbit.core.security.SimpleAccessManager">
+            <!-- <param name="config" value="${rep.home}/access.xml"/> -->
+        </AccessManager>
+    </Security>
+
+    <!--
+        location of workspaces root directory and name of default workspace
+    -->
+    <Workspaces rootPath="${rep.home}/workspaces" defaultWorkspace="default"/>
+    <!--
+        workspace configuration template:
+        used to create the initial workspace if there's no workspace yet
+    -->
+    <Workspace name="${wsp.name}">
+        <!--
+            virtual file system of the workspace:
+            class: FQN of class implementing the FileSystem interface
+        -->
+        <FileSystem class="org.apache.jackrabbit.core.fs.vfs.VFSFileSystem">
+	        <param name="path" value="${wsp.home}/wspStore.dat"/>
+	        <param name="prefix" value="tmp"/>
+	        <param name="config" value="providers.xml"/>
+        </FileSystem>
+        <!--
+        <FileSystem class="org.apache.jackrabbit.core.fs.vfs.VFSFileSystem">
+	        <param name="path" value="${wsp.home}"/>
+	        <param name="prefix" value="tmp"/>
+	        <param name="config" value="providers.xml"/>
+        </FileSystem>
+        -->
+        <!--
+            persistence manager of the workspace:
+            class: FQN of class implementing the PersistenceManager interface
+        -->
+        <!--
+        <PersistenceManager class="org.apache.jackrabbit.core.state.xml.XMLPersistenceManager"/>
+        -->
+        <!--
+        <PersistenceManager class="org.apache.jackrabbit.core.state.mem.InMemPersistenceManager">
+            <param name="initialCapacity" value="100000"/>
+            <param name="loadFactor" value="0.3"/>
+            <param name="persistent" value="true"/>
+        </PersistenceManager>
+        -->
+        <PersistenceManager class="org.apache.jackrabbit.core.state.obj.ObjectPersistenceManager"/>
+        <!--
+            Search index and the file system it uses.
+        -->
+        <SearchIndex class="org.apache.jackrabbit.core.search.lucene.SearchIndex">
+            <param name="useCompoundFile" value="true"/>
+            <param name="minMergeDocs" value="1000"/>
+            <param name="maxMergeDocs" value="10000"/>
+            <param name="mergeFactor" value="10"/>
+
+            <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
+                <param name="path" value="${wsp.home}/index"/>
+            </FileSystem>
+        </SearchIndex>
+    </Workspace>
+
+    <!--
+        Configures the versioning
+    -->
+    <Versioning rootPath="${rep.home}/version">
+        <!--
+            Configures the filesystem to use for versioning for the respective
+            persistence manager
+        -->
+        <FileSystem class="org.apache.jackrabbit.core.fs.vfs.VFSFileSystem">
+	        <param name="path" value="${rep.home}/version/version.dat"/>
+	        <param name="prefix" value="tmp"/>
+	        <param name="config" value="providers.xml" /> 
+        </FileSystem>
+    
+        <!--
+            <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
+                <param name="path" value="${rep.home}/version"/>
+            </FileSystem>
+        -->
+        
+        <!--
+            Configures the perisistence manager to be used for persisting version state.
+            Please note that the current versioning implementation is based on
+            a 'normal' persistence manager, but this could change in future
+            implementations.
+        -->
+        <PersistenceManager class="org.apache.jackrabbit.core.state.obj.ObjectPersistenceManager"/>
+
+    </Versioning>
+</Repository>

Propchange: incubator/jackrabbit/trunk/contrib/vfs/05-03-03-repository.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/jackrabbit/trunk/contrib/vfs/README.txt
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/vfs/README.txt?view=auto&rev=156521
==============================================================================
--- incubator/jackrabbit/trunk/contrib/vfs/README.txt (added)
+++ incubator/jackrabbit/trunk/contrib/vfs/README.txt Tue Mar  8 04:36:05 2005
@@ -0,0 +1,14 @@
+For testing you can use tmp provider. This provider will delete 
+all the files and folders on repository shutdown.
+
+The providers configuration file (providers.xml) must be in the classpath.
+
+repository.xml Example:
+<FileSystem class="org.apache.jackrabbit.core.fs.vfs.VFSFileSystem">
+	<!-- full path to the base folder. -->
+    <param name="path" value="/repository"/>
+    <!-- provider prefix -->
+    <param name="prefix" value="tmp"/>
+	<!-- providers configuration file name -->
+    <param name="config" value="providers.xml"/>
+</FileSystem>

Propchange: incubator/jackrabbit/trunk/contrib/vfs/README.txt
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/jackrabbit/trunk/contrib/vfs/src/java/org/apache/jackrabbit/core/fs/vfs/VFSFileSystem.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/vfs/src/java/org/apache/jackrabbit/core/fs/vfs/VFSFileSystem.java?view=auto&rev=156521
==============================================================================
--- incubator/jackrabbit/trunk/contrib/vfs/src/java/org/apache/jackrabbit/core/fs/vfs/VFSFileSystem.java
(added)
+++ incubator/jackrabbit/trunk/contrib/vfs/src/java/org/apache/jackrabbit/core/fs/vfs/VFSFileSystem.java
Tue Mar  8 04:36:05 2005
@@ -0,0 +1,631 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation or its licensors,
+ *                     as applicable.
+ *
+ * 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 org.apache.jackrabbit.core.fs.vfs;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collection;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.vfs.AllFileSelector;
+import org.apache.commons.vfs.FileObject;
+import org.apache.commons.vfs.FileSelector;
+import org.apache.commons.vfs.FileSystemException;
+import org.apache.commons.vfs.FileType;
+import org.apache.commons.vfs.FileUtil;
+import org.apache.commons.vfs.RandomAccessContent;
+import org.apache.commons.vfs.cache.SoftRefFilesCache;
+import org.apache.commons.vfs.impl.StandardFileSystemManager;
+import org.apache.commons.vfs.util.RandomAccessMode;
+import org.apache.jackrabbit.core.fs.FileSystem;
+import org.apache.jackrabbit.core.fs.RandomAccessOutputStream;
+
+/**
+ * FileSystem backed by Commons VFS
+ * 
+ * @author <a href="mailto:edgarpoce@gmail.com">Edgar Poce </a>
+ */
+public class VFSFileSystem implements FileSystem
+{
+    /**
+     * Logger
+     */
+    private Log log = LogFactory.getLog(VFSFileSystem.class);
+
+    /**
+     * File selector
+     */
+    public final static FileSelector ALL = new AllFileSelector() ;
+    
+    /**
+     * VFS manager
+     */
+    StandardFileSystemManager fsManager;
+
+    /**
+     * Scheme
+     */
+    private String prefix;
+
+    /**
+     * Path
+     */
+    private String path;
+
+    /**
+     * The config file
+     */
+    private String config;
+
+    /**
+     * 
+     */
+    public VFSFileSystem()
+    {
+        super();
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.jackrabbit.core.fs.FileSystem#init()
+     */
+    public void init() throws org.apache.jackrabbit.core.fs.FileSystemException
+    {
+
+        if (this.path == null)
+        {
+            String msg = "Path is not set";
+            log.error(msg);
+            throw new org.apache.jackrabbit.core.fs.FileSystemException(msg);
+        }
+
+        if (this.config == null)
+        {
+            String msg = "Configuration file name is not set (\"config\" parameter ).";
+            log.error(msg);
+            throw new org.apache.jackrabbit.core.fs.FileSystemException(msg);
+        }
+
+        try
+        {
+            // Init file system
+            fsManager = new StandardFileSystemManager();
+            
+            // Set class loader for resource retrieval
+            fsManager.setClassLoader(this.getClass().getClassLoader());
+            
+            // Configuration file name
+            fsManager.setConfiguration(this.getClass().getClassLoader()
+                    .getResource(this.config).toExternalForm());
+            
+            // Set the logger
+            fsManager.setLogger(log);
+            
+            // Cache strategy
+            // FIXME: set through configuration
+            fsManager.setFilesCache(new SoftRefFilesCache());
+            fsManager.init();
+
+            // Set the base folder
+            FileObject fo = fsManager
+                    .resolveFile(this.prefix + ":" + this.path);
+            fsManager.setBaseFile(fo);
+            
+        } catch (FileSystemException e)
+        {
+            String msg = "Unable to init VFS FileSystem";
+            log.error(msg, e);
+            throw new org.apache.jackrabbit.core.fs.FileSystemException(msg, e);
+        }
+
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.jackrabbit.core.fs.FileSystem#close()
+     */
+    public void close()
+            throws org.apache.jackrabbit.core.fs.FileSystemException
+    {
+        this.fsManager.close() ;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.jackrabbit.core.fs.FileSystem#getInputStream(java.lang.String)
+     */
+    public InputStream getInputStream(String filePath)
+            throws org.apache.jackrabbit.core.fs.FileSystemException
+    {
+        try
+        {
+            FileObject file = this.getFile(filePath);
+            this.validateFile(file);
+            return file.getContent().getInputStream();
+        } catch (FileSystemException e)
+        {
+            throw new org.apache.jackrabbit.core.fs.FileSystemException(e);
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.jackrabbit.core.fs.FileSystem#getOutputStream(java.lang.String)
+     */
+    public OutputStream getOutputStream(String filePath)
+            throws org.apache.jackrabbit.core.fs.FileSystemException
+    {
+        try
+        {
+            FileObject file = this.getFile(filePath);
+            if (!file.exists())
+            {
+                file.createFile();
+            }
+            this.validateFile(file);
+            return file.getContent().getOutputStream();
+        } catch (FileSystemException e)
+        {
+            throw new org.apache.jackrabbit.core.fs.FileSystemException(e);
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.jackrabbit.core.fs.FileSystem#getRandomAccessOutputStream(java.lang.String)
+     */
+    public RandomAccessOutputStream getRandomAccessOutputStream(String filePath)
+            throws org.apache.jackrabbit.core.fs.FileSystemException
+    {
+        try
+        {
+            FileObject file = this.getFile(filePath);
+            this.validateFile(file);
+            RandomAccessContent raf = file.getContent().getRandomAccessContent(
+                    RandomAccessMode.READWRITE);
+            return new VFSRAFOutputStream(raf);
+        } catch (FileSystemException e)
+        {
+            throw new org.apache.jackrabbit.core.fs.FileSystemException(e);
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.jackrabbit.core.fs.FileSystem#createFolder(java.lang.String)
+     */
+    public void createFolder(String folderPath)
+            throws org.apache.jackrabbit.core.fs.FileSystemException
+    {
+        try
+        {
+            FileObject folder = this.getFile(folderPath);
+            folder.createFolder();
+        } catch (FileSystemException e)
+        {
+            throw new org.apache.jackrabbit.core.fs.FileSystemException(e);
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.jackrabbit.core.fs.FileSystem#exists(java.lang.String)
+     */
+    public boolean exists(String path)
+            throws org.apache.jackrabbit.core.fs.FileSystemException
+    {
+        try
+        {
+            return this.getFile(path).exists();
+        } catch (FileSystemException e)
+        {
+            throw new org.apache.jackrabbit.core.fs.FileSystemException(e);
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.jackrabbit.core.fs.FileSystem#isFile(java.lang.String)
+     */
+    public boolean isFile(String path)
+            throws org.apache.jackrabbit.core.fs.FileSystemException
+    {
+        try
+        {
+            return this.getFile(path).getType().equals(FileType.FILE);
+        } catch (FileSystemException e)
+        {
+            throw new org.apache.jackrabbit.core.fs.FileSystemException(e);
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.jackrabbit.core.fs.FileSystem#isFolder(java.lang.String)
+     */
+    public boolean isFolder(String path)
+            throws org.apache.jackrabbit.core.fs.FileSystemException
+    {
+        try
+        {
+            return this.getFile(path).getType().equals(FileType.FOLDER);
+        } catch (FileSystemException e)
+        {
+            throw new org.apache.jackrabbit.core.fs.FileSystemException(e);
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.jackrabbit.core.fs.FileSystem#hasChildren(java.lang.String)
+     */
+    public boolean hasChildren(String path)
+            throws org.apache.jackrabbit.core.fs.FileSystemException
+    {
+        try
+        {
+            return this.getFile(path).getChildren().length > 0;
+        } catch (FileSystemException e)
+        {
+            throw new org.apache.jackrabbit.core.fs.FileSystemException(e);
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.jackrabbit.core.fs.FileSystem#length(java.lang.String)
+     */
+    public long length(String filePath)
+            throws org.apache.jackrabbit.core.fs.FileSystemException
+    {
+        try
+        {
+            FileObject file = this.getFile(filePath);
+            this.validateFile(file);
+            return file.getContent().getSize();
+        } catch (FileSystemException e)
+        {
+            throw new org.apache.jackrabbit.core.fs.FileSystemException(e);
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.jackrabbit.core.fs.FileSystem#lastModified(java.lang.String)
+     */
+    public long lastModified(String path)
+            throws org.apache.jackrabbit.core.fs.FileSystemException
+    {
+        try
+        {
+            return this.getFile(path).getContent().getLastModifiedTime();
+        } catch (FileSystemException e)
+        {
+            throw new org.apache.jackrabbit.core.fs.FileSystemException(e);
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.jackrabbit.core.fs.FileSystem#touch(java.lang.String)
+     */
+    public void touch(String filePath)
+            throws org.apache.jackrabbit.core.fs.FileSystemException
+    {
+        try
+        {
+            FileObject file = this.getFile(filePath);
+            this.validateFile(file);
+            file.getContent().setLastModifiedTime(
+                    Calendar.getInstance().getTimeInMillis());
+        } catch (FileSystemException e)
+        {
+            throw new org.apache.jackrabbit.core.fs.FileSystemException(e);
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.jackrabbit.core.fs.FileSystem#list(java.lang.String)
+     */
+    public String[] list(String folderPath)
+            throws org.apache.jackrabbit.core.fs.FileSystemException
+    {
+        return this.list(this.getFile(folderPath), null);
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.jackrabbit.core.fs.FileSystem#listFiles(java.lang.String)
+     */
+    public String[] listFiles(String folderPath)
+            throws org.apache.jackrabbit.core.fs.FileSystemException
+    {
+        return this.list(this.getFile(folderPath), FileType.FILE);
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.jackrabbit.core.fs.FileSystem#listFolders(java.lang.String)
+     */
+    public String[] listFolders(String folderPath)
+            throws org.apache.jackrabbit.core.fs.FileSystemException
+    {
+        return this.list(this.getFile(folderPath), FileType.FOLDER);
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.jackrabbit.core.fs.FileSystem#deleteFile(java.lang.String)
+     */
+    public void deleteFile(String filePath)
+            throws org.apache.jackrabbit.core.fs.FileSystemException
+    {
+        try
+        {
+            FileObject file = this.getFile(filePath);
+            this.validateFile(file);
+            this.delete(file);
+        } catch (FileSystemException e)
+        {
+            throw new org.apache.jackrabbit.core.fs.FileSystemException(e);
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.jackrabbit.core.fs.FileSystem#deleteFolder(java.lang.String)
+     */
+    public void deleteFolder(String folderPath)
+            throws org.apache.jackrabbit.core.fs.FileSystemException
+    {
+        try
+        {
+            FileObject folder = this.getFile(folderPath);
+            this.validateFolder(folder);
+            this.delete(folder);
+        } catch (FileSystemException e)
+        {
+            throw new org.apache.jackrabbit.core.fs.FileSystemException(e);
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.jackrabbit.core.fs.FileSystem#move(java.lang.String,
+     *      java.lang.String)
+     */
+    public void move(String srcPath, String destPath)
+            throws org.apache.jackrabbit.core.fs.FileSystemException
+    {
+        try
+        {
+            FileObject src = this.getFile(srcPath);
+            FileObject dest = this.getFile(destPath);
+            src.moveTo(dest);
+        } catch (FileSystemException e)
+        {
+            throw new org.apache.jackrabbit.core.fs.FileSystemException(e);
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.jackrabbit.core.fs.FileSystem#copy(java.lang.String,
+     *      java.lang.String)
+     */
+    public void copy(String srcPath, String destPath)
+            throws org.apache.jackrabbit.core.fs.FileSystemException
+    {
+        try
+        {
+            FileObject src = this.getFile(srcPath);
+            FileObject dest = this.getFile(destPath);
+            FileUtil.copyContent(src, dest);
+        } catch (FileSystemException e)
+        {
+            throw new org.apache.jackrabbit.core.fs.FileSystemException(e);
+        } catch (IOException e)
+        {
+            throw new org.apache.jackrabbit.core.fs.FileSystemException(e);
+        }
+    }
+
+    /**
+     * Gets the FileObject for the given path
+     * 
+     * @param path
+     * @return FileSystem
+     * @throws FileSystemException
+     */
+    private FileObject getFile(String path)
+            throws org.apache.jackrabbit.core.fs.FileSystemException
+    {
+        try
+        {
+            if (path.startsWith("/")) {
+                path = path.substring(1, path.length()) ;
+            }
+            return fsManager.resolveFile(path);
+        } catch (FileSystemException e)
+        {
+            String msg = "Unable to get file " + path;
+            log.error(msg, e);
+            throw new org.apache.jackrabbit.core.fs.FileSystemException(msg, e);
+        }
+    }
+
+    /**
+     * Validates Folder Type
+     * 
+     * @param folder
+     * @throws FileSystemException
+     */
+    private void validateFolder(FileObject folder) throws FileSystemException
+    {
+        if (!folder.getType().equals(FileType.FOLDER))
+        {
+            String msg = folder.getName().getPath()
+                    + " does not denote a folder";
+            log.error(msg);
+            throw new FileSystemException(msg);
+        }
+    }
+
+    /**
+     * Validates File Type
+     * 
+     * @param folder
+     * @throws FileSystemException
+     */
+    private void validateFile(FileObject file) throws FileSystemException
+    {
+        if (!file.getType().equals(FileType.FILE))
+        {
+            String msg = file.getName().getPath() + " does not denote a file";
+            log.error(msg);
+            throw new FileSystemException(msg);
+        }
+    }
+
+    /**
+     * List the children for the given Type.
+     * 
+     * @param path
+     * @param type
+     * @return
+     * @throws org.apache.jackrabbit.core.fs.FileSystemException
+     */
+    private String[] list(FileObject folder, FileType type)
+            throws org.apache.jackrabbit.core.fs.FileSystemException
+    {
+        try
+        {
+            this.validateFolder(folder);
+            FileObject[] fo = folder.getChildren();
+            Collection c = new ArrayList();
+            for (int i = 0; i < fo.length; i++)
+            {
+                if (type == null)
+                {
+                    c.add(fo[i].getName().getBaseName());
+                } else
+                {
+                    if (fo[i].getType().equals(type))
+                    {
+                        c.add(fo[i].getName().getBaseName());
+                    }
+                }
+            }
+            return (String[]) c.toArray(new String[c.size()]);
+        } catch (FileSystemException e)
+        {
+            throw new org.apache.jackrabbit.core.fs.FileSystemException(e);
+        }
+    }
+
+    /**
+     * Deletes the given File
+     */
+    private void delete(FileObject file)
+            throws org.apache.jackrabbit.core.fs.FileSystemException
+    {
+        try
+        {
+            file.delete(ALL);
+        } catch (FileSystemException e)
+        {
+            throw new org.apache.jackrabbit.core.fs.FileSystemException(e);
+        }
+    }
+
+    public String getPath()
+    {
+        return path;
+    }
+
+    public void setPath(String path)
+    {
+        this.path = path;
+    }
+
+    /**
+     * Makes a file canonical
+     */
+    public static File getCanonicalFile(final File file)
+    {
+        try
+        {
+            return file.getCanonicalFile();
+        } catch (IOException e)
+        {
+            return file.getAbsoluteFile();
+        }
+    }
+
+    public String getConfig()
+    {
+        return config;
+    }
+
+    public void setConfig(String config)
+    {
+        this.config = config;
+    }
+
+    /**
+     * @return Returns the scheme.
+     */
+    public String getPrefix()
+    {
+        return prefix;
+    }
+
+    /**
+     * @param scheme
+     *            The scheme to set.
+     */
+    public void setPrefix(String prefix)
+    {
+        this.prefix = prefix;
+    }
+}
\ No newline at end of file

Propchange: incubator/jackrabbit/trunk/contrib/vfs/src/java/org/apache/jackrabbit/core/fs/vfs/VFSFileSystem.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/jackrabbit/trunk/contrib/vfs/src/java/org/apache/jackrabbit/core/fs/vfs/VFSRAFOutputStream.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/vfs/src/java/org/apache/jackrabbit/core/fs/vfs/VFSRAFOutputStream.java?view=auto&rev=156521
==============================================================================
--- incubator/jackrabbit/trunk/contrib/vfs/src/java/org/apache/jackrabbit/core/fs/vfs/VFSRAFOutputStream.java
(added)
+++ incubator/jackrabbit/trunk/contrib/vfs/src/java/org/apache/jackrabbit/core/fs/vfs/VFSRAFOutputStream.java
Tue Mar  8 04:36:05 2005
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation or its licensors,
+ *                     as applicable.
+ *
+ * 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 org.apache.jackrabbit.core.fs.vfs;
+
+import java.io.IOException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.vfs.RandomAccessContent;
+import org.apache.jackrabbit.core.fs.RandomAccessOutputStream;
+
+/**
+ * Wrapper of VFS output stream on a random access file.
+ * 
+ * @author <a href="mailto:edgarpoce@gmail.com">Edgar Poce </a>
+ */
+class VFSRAFOutputStream extends RandomAccessOutputStream
+{
+
+    private Log log = LogFactory.getLog(VFSRAFOutputStream.class);
+
+    /**
+     * The default size of the write buffer in bytes.
+     */
+    static final int DEFAULT_BUFFER_SIZE = 1024;
+
+    /**
+     * The write buffer.
+     */
+    private final byte[] buffer;
+
+    /**
+     * The underlying <code>RandomAccessContent</code>.
+     */
+    protected RandomAccessContent rac;
+
+    /**
+     * The starting position of the buffer in the code.
+     */
+    private long bufferStart;
+
+    /**
+     * The end of valid data in the buffer.
+     */
+    private int bufferEnd;
+
+    /**
+     * Dummy buffer for {@link #write(int)}.
+     */
+    private byte[] one = new byte[1];
+
+    /**
+     * Constructor
+     */
+    public VFSRAFOutputStream(RandomAccessContent rac, int size)
+    {
+        super();
+        this.rac = rac;
+        this.buffer = new byte[size];
+        try
+        {
+            bufferStart = rac.getFilePointer();
+        } catch (IOException e)
+        {
+            log.error("Unable to get file pointer");
+        }
+    }
+
+    /**
+     * Constructor
+     */
+    public VFSRAFOutputStream(RandomAccessContent rac)
+    {
+        this(rac, DEFAULT_BUFFER_SIZE);
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.jackrabbit.core.fs.RandomAccessOutputStream#seek(long)
+     */
+    public void seek(long position) throws IOException
+    {
+        flush();
+        rac.seek(position);
+        bufferStart = position;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see java.io.OutputStream#write(int)
+     */
+    public void write(int b) throws IOException
+    {
+        one[0] = (byte) b;
+        write(one, 0, 1);
+    }
+
+    public void close() throws IOException
+    {
+        flush();
+        rac.close();
+        rac = null;
+    }
+
+    public void flush() throws IOException
+    {
+        rac.write(buffer, 0, bufferEnd);
+        bufferEnd = 0;
+        bufferStart = rac.getFilePointer();
+    }
+
+    public void write(byte b[], int off, int len) throws IOException
+    {
+        if (len > buffer.length - bufferEnd)
+        {
+            flush();
+            rac.write(b, off, len);
+        } else
+        {
+            System.arraycopy(b, off, buffer, bufferEnd, len);
+            bufferEnd += len;
+        }
+    }
+
+    public void write(byte[] b) throws IOException
+    {
+        write(b, 0, b.length);
+    }
+}
\ No newline at end of file

Propchange: incubator/jackrabbit/trunk/contrib/vfs/src/java/org/apache/jackrabbit/core/fs/vfs/VFSRAFOutputStream.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/jackrabbit/trunk/contrib/vfs/src/java/providers.xml
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/vfs/src/java/providers.xml?view=auto&rev=156521
==============================================================================
--- incubator/jackrabbit/trunk/contrib/vfs/src/java/providers.xml (added)
+++ incubator/jackrabbit/trunk/contrib/vfs/src/java/providers.xml Tue Mar  8 04:36:05 2005
@@ -0,0 +1,107 @@
+<providers>
+    <default-provider class-name="org.apache.commons.vfs.provider.url.UrlFileProvider">
+    </default-provider>
+    
+    <provider class-name="org.apache.commons.vfs.provider.local.DefaultLocalFileProvider">
+        <scheme name="file"/>
+    </provider>
+    <provider class-name="org.apache.commons.vfs.provider.zip.ZipFileProvider">
+        <scheme name="zip"/>
+    </provider>
+    <provider class-name="org.apache.commons.vfs.provider.tar.TarFileProvider">
+        <scheme name="tar"/>
+        <if-available class-name="org.apache.commons.compress.tar.TarInputStream"/>
+    </provider>
+
+    <provider class-name="org.apache.commons.vfs.provider.bzip2.Bzip2FileProvider">
+        <scheme name="bz2"/>
+        <if-available class-name="org.apache.commons.compress.bzip2.CBZip2InputStream"/>
+    </provider>
+    <provider class-name="org.apache.commons.vfs.provider.gzip.GzipFileProvider">
+        <scheme name="gz"/>
+    </provider>
+
+    <provider class-name="org.apache.commons.vfs.provider.jar.JarFileProvider">
+        <scheme name="jar"/>
+    </provider>
+    <provider class-name="org.apache.commons.vfs.provider.temp.TemporaryFileProvider">
+        <scheme name="tmp"/>
+    </provider>
+    <provider class-name="org.apache.commons.vfs.provider.ftp.FtpFileProvider">
+        <scheme name="ftp"/>
+        <if-available class-name="org.apache.commons.net.ftp.FTPFile"/>
+    </provider>
+    <provider class-name="org.apache.commons.vfs.provider.smb.SmbFileProvider">
+        <scheme name="smb"/>
+        <if-available class-name="jcifs.smb.SmbFile"/>
+    </provider>
+    <provider class-name="org.apache.commons.vfs.provider.http.HttpFileProvider">
+        <scheme name="http"/>
+        <if-available class-name="org.apache.commons.httpclient.HttpClient"/>
+    </provider>
+    <provider class-name="org.apache.commons.vfs.provider.webdav.WebdavFileProvider">
+        <scheme name="webdav"/>
+        <if-available class-name="org.apache.webdav.lib.WebdavResource"/>
+        <if-available class-name="org.apache.commons.httpclient.HttpClient"/>
+    </provider>
+    <provider class-name="org.apache.commons.vfs.provider.sftp.SftpFileProvider">
+        <scheme name="sftp"/>
+        <if-available class-name="javax.crypto.Cipher"/>
+        <if-available class-name="com.jcraft.jsch.JSch"/>
+    </provider>
+    <provider class-name="org.apache.commons.vfs.provider.res.ResourceFileProvider">
+        <scheme name="res"/>
+    </provider>
+    <!--
+        <provider class-name="org.apache.commons.vfs.provider.tar.TgzFileProvider">
+            <scheme name="tgz"/>
+            <if-available scheme="gz"/>
+            <if-available scheme="tar"/>
+        </provider>
+        <provider class-name="org.apache.commons.vfs.provider.tar.Tbz2FileProvider">
+            <scheme name="tbz2"/>
+            <if-available scheme="bz2"/>
+            <if-available scheme="tar"/>
+        </provider>
+    -->
+    <provider class-name="org.apache.commons.vfs.provider.tar.TarFileProvider">
+        <scheme name="tgz"/>
+        <if-available scheme="gz"/>
+        <if-available scheme="tar"/>
+    </provider>
+    <provider class-name="org.apache.commons.vfs.provider.tar.TarFileProvider">
+        <scheme name="tbz2"/>
+        <if-available scheme="bz2"/>
+        <if-available scheme="tar"/>
+    </provider>
+
+    <extension-map extension="zip" scheme="zip"/>
+    <extension-map extension="tar" scheme="tar"/>
+    <mime-type-map mime-type="application/zip" scheme="zip"/>
+    <mime-type-map mime-type="application/x-tar" scheme="tar"/>
+    <!--
+    <mime-type-map mime-type="application/x-tgz" scheme="tgz"/>
+    -->
+    <extension-map extension="jar" scheme="jar"/>
+    <extension-map extension="bz2" scheme="bz2"/>
+    <extension-map extension="gz" scheme="gz"/>
+    <!--
+    <extension-map extension="tgz" scheme="tgz"/>
+    <extension-map extension="tbz2" scheme="tbz2"/>
+    -->
+    <extension-map extension="tgz" scheme="tar"/>
+    <extension-map extension="tbz2" scheme="tar"/>
+
+    <!--
+    <filter-map class-name="org.apache.commons.vfs.content.bzip2.Bzip2Compress">
+        <extension name="bz2"/>
+        <extension name="tbz2"/>
+        <if-available class-name="org.apache.commons.compress.bzip2.CBZip2InputStream"/>
+    </filter-map>
+    <filter-map class-name="org.apache.commons.vfs.content.gzip.GzipCompress">
+        <extension name="gz"/>
+        <extension name="tgz"/>
+        <mime-type name="application/x-tgz" />
+    </filter-map>
+    -->
+</providers>
\ No newline at end of file

Propchange: incubator/jackrabbit/trunk/contrib/vfs/src/java/providers.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/jackrabbit/trunk/contrib/vfs/src/test/org/apache/jackrabbit/core/fs/vfs/VFSFileSystemTest.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/vfs/src/test/org/apache/jackrabbit/core/fs/vfs/VFSFileSystemTest.java?view=auto&rev=156521
==============================================================================
--- incubator/jackrabbit/trunk/contrib/vfs/src/test/org/apache/jackrabbit/core/fs/vfs/VFSFileSystemTest.java
(added)
+++ incubator/jackrabbit/trunk/contrib/vfs/src/test/org/apache/jackrabbit/core/fs/vfs/VFSFileSystemTest.java
Tue Mar  8 04:36:05 2005
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation or its licensors,
+ *                     as applicable.
+ *
+ * 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 org.apache.jackrabbit.core.fs.vfs;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+
+import org.apache.jackrabbit.core.fs.RandomAccessOutputStream;
+import org.apache.jackrabbit.test.JUnitTest;
+
+/**
+ * <p>
+ * FileSystem backed by Commons VFS Tests
+ * </p>
+ * 
+ * <p>
+ * In order to run the following VM arguments must be set:
+ * <ul>
+ * <li>fs.prefix = [provider prefix]</li>
+ * <li>fs.path = [root path]</li>
+ * <li>fs.config = [providers config file]</li>
+ * </ul>
+ * 
+ * @author <a href="mailto:edgarpoce@gmail.com">Edgar Poce </a>
+ */
+public class VFSFileSystemTest extends JUnitTest
+{
+    private static final String PREFIX = "fs.prefix";
+
+    private static final String PATH = "fs.path";
+
+    private static final String CONFIG = "fs.config";
+
+    private static final String TEST_FOLDER = "testFolder1";
+
+    private static final String TEST_FILE = "testFile1.txt";
+
+    private static final String TEST_FOLDER2 = TEST_FOLDER + "/testFolder2";
+
+    private static final String TEST_FILE2 = TEST_FOLDER2 + "/testFile2.txt";
+
+    private static final String TEST_FILE3 = TEST_FOLDER2 + "/testFile3.txt";
+
+    /**
+     * VFS fs
+     */
+    private VFSFileSystem fs;
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see junit.framework.TestCase#setUp()
+     */
+    protected void setUp() throws Exception
+    {
+        super.setUp();
+        fs = new VFSFileSystem();
+        fs.setPrefix(System.getProperty(PREFIX));
+        fs.setPath(System.getProperty(PATH));
+        fs.setConfig(System.getProperty(CONFIG));
+        fs.init();
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see junit.framework.TestCase#tearDown()
+     */
+    protected void tearDown() throws Exception
+    {
+        super.tearDown();
+        fs.close();
+        fs = null;
+    }
+
+    public void testFileSystem() throws Exception
+    {
+        /*
+         * Create folder
+         */
+        // depth = 0
+        fs.createFolder(TEST_FOLDER);
+        assertTrue(fs.exists(TEST_FOLDER));
+        assertTrue(fs.isFolder(TEST_FOLDER));
+        // depth = 1
+        fs.createFolder(TEST_FOLDER2);
+        assertTrue(fs.exists(TEST_FOLDER2));
+        assertTrue(fs.isFolder(TEST_FOLDER2));
+        // Children
+        assertTrue(fs.hasChildren(TEST_FOLDER));
+        assertTrue(fs.list(TEST_FOLDER)[0].equals(getName(TEST_FOLDER2)));
+        assertTrue(fs.listFiles(TEST_FOLDER).length == 0);
+        assertTrue(fs.listFolders(TEST_FOLDER)[0].equals(getName(TEST_FOLDER2)));
+
+        /*
+         * Create file
+         */
+        // depth = 1
+        byte[] write = "hello world".getBytes();
+        byte[] read = new byte[write.length];
+
+        OutputStream out = fs.getOutputStream(TEST_FILE);
+        out.write(write);
+        out.flush();
+        out.close();
+        assertTrue(fs.exists(TEST_FILE));
+        fs.getInputStream(TEST_FILE).read(read);
+        assertTrue(Arrays.equals(write, read));
+        // depth = 2
+        out = fs.getOutputStream(TEST_FILE2);
+        out.write(write);
+        out.flush();
+        out.close();
+        assertTrue(fs.exists(TEST_FILE2));
+        InputStream in = fs.getInputStream(TEST_FILE2);
+        in.read(read);
+        in.close();
+        assertTrue(Arrays.equals(write, read));
+
+        /*
+         * Delete file
+         */
+        fs.deleteFile(TEST_FILE2);
+        assertFalse(fs.exists(TEST_FILE2));
+
+        /*
+         * Delete folder
+         */
+        fs.deleteFolder(TEST_FOLDER2);
+        assertFalse(fs.exists(TEST_FOLDER2));
+
+        /*
+         * Copy file
+         */
+        fs.copy(TEST_FILE, TEST_FILE2);
+        assertTrue(fs.exists(TEST_FILE2));
+        assertTrue(fs.isFile(TEST_FILE2));
+
+        /*
+         * Move file
+         */
+        fs.move(TEST_FILE2, TEST_FILE3);
+        assertFalse(fs.exists(TEST_FILE2));
+        assertTrue(fs.exists(TEST_FILE3));
+        assertTrue(fs.isFile(TEST_FILE3));
+
+        /* Radom access content */
+        RandomAccessOutputStream rout = fs
+                .getRandomAccessOutputStream(TEST_FILE);
+        rout.seek(100);
+        rout.write(10);
+        rout.flush();
+        rout.close();
+
+        in = fs.getInputStream(TEST_FILE);
+        in.skip(100);
+        assertTrue(in.read() == 10);
+        in.close();
+
+    }
+
+    /**
+     * Get the name
+     * 
+     * @param path
+     * @return
+     */
+    private String getName(String path)
+    {
+        return path.substring(path.lastIndexOf("/") + 1, path.length());
+    }
+
+}
\ No newline at end of file

Propchange: incubator/jackrabbit/trunk/contrib/vfs/src/test/org/apache/jackrabbit/core/fs/vfs/VFSFileSystemTest.java
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message