diff --git a/src/main/java/org/olat/_spring/extensionContext.xml b/src/main/java/org/olat/_spring/extensionContext.xml
index 647de02fe74d1ff9866f5785131af5ad4c254668..fb44fccf81f836b7f8f9dd82bdf0e407a36a5b80 100644
--- a/src/main/java/org/olat/_spring/extensionContext.xml
+++ b/src/main/java/org/olat/_spring/extensionContext.xml
@@ -383,25 +383,6 @@
 			</list>
 		</property>
 	</bean>
-	<!--  the version ("versionisierung") menu-entry -->
-	<bean class="org.olat.core.extensions.action.GenericActionExtension" init-method="initExtensionPoints" >
-		<property name="order" value="7204" />
-		<property name="navigationKey" value="versioning" />
-		<property name="actionController">	
-			<bean class="org.olat.core.gui.control.creator.AutoCreator" scope="prototype">
-				<property name="className" value="org.olat.admin.version.VersionAdminController"/>
-			</bean>
-		</property>
-		<property name="translationPackage" value="org.olat.admin" />
-		<property name="i18nActionKey" value="menu.versions"/>
-		<property name="i18nDescriptionKey" value="menu.versions.alt"/>
-		<property name="parentTreeNodeIdentifier" value="sysconfigParent" /> 
-		<property name="extensionPoints">
-			<list>	
-				<value>org.olat.admin.SystemAdminMainController</value>		
-			</list>
-		</property>
-	</bean>
 	<!-- Security admin. panel -->
 	<bean class="org.olat.core.extensions.action.GenericActionExtension" init-method="initExtensionPoints">
 		<property name="order" value="8805" />
diff --git a/src/main/java/org/olat/admin/version/OrphanVersionsController.java b/src/main/java/org/olat/admin/version/OrphanVersionsController.java
deleted file mode 100644
index 75b3e505f478ab24309554bcec54771161d6af05..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/admin/version/OrphanVersionsController.java
+++ /dev/null
@@ -1,201 +0,0 @@
-/**
- * <a href="http://www.openolat.org">
- * OpenOLAT - Online Learning and Training</a><br>
- * <p>
- * Licensed under the Apache License, Version 2.0 (the "License"); <br>
- * you may not use this file except in compliance with the License.<br>
- * You may obtain a copy of the License at the
- * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
- * <p>
- * Unless required by applicable law or agreed to in writing,<br>
- * software distributed under the License is distributed on an "AS IS" BASIS, <br>
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
- * See the License for the specific language governing permissions and <br>
- * limitations under the License.
- * <p>
- * Initial code contributed and copyrighted by<br>
- * frentix GmbH, http://www.frentix.com
- * <p>
- */
-package org.olat.admin.version;
-
-import java.text.DecimalFormat;
-import java.text.DecimalFormatSymbols;
-import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.Collections;
-import java.util.List;
-import java.util.Locale;
-
-import org.olat.core.gui.UserRequest;
-import org.olat.core.gui.components.Component;
-import org.olat.core.gui.components.table.DefaultColumnDescriptor;
-import org.olat.core.gui.components.table.StaticColumnDescriptor;
-import org.olat.core.gui.components.table.Table;
-import org.olat.core.gui.components.table.TableController;
-import org.olat.core.gui.components.table.TableDataModel;
-import org.olat.core.gui.components.table.TableEvent;
-import org.olat.core.gui.components.table.TableGuiConfiguration;
-import org.olat.core.gui.components.table.TableMultiSelectEvent;
-import org.olat.core.gui.control.Controller;
-import org.olat.core.gui.control.Event;
-import org.olat.core.gui.control.WindowControl;
-import org.olat.core.gui.control.controller.BasicController;
-import org.olat.core.util.vfs.version.OrphanVersion;
-import org.olat.core.util.vfs.version.VFSRevision;
-import org.olat.core.util.vfs.version.VersionsManager;
-import org.springframework.beans.factory.annotation.Autowired;
-
-/**
- * 
- * Description:<br>
- * List all orphans
- * 
- * <P>
- * Initial Date:  5 mai 2011 <br>
- * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
- */
-public class OrphanVersionsController extends BasicController {
-	
-	private static final String CMD_DELETE = "delete";
-	private static final DecimalFormat sizeFormat = new DecimalFormat("#0.#", new DecimalFormatSymbols(Locale.ENGLISH));
-	
-	private TableController tableCtr;
-	private final List<OrphanVersion> orphans;
-	
-	@Autowired
-	private VersionsManager versionsManager;
-
-	public OrphanVersionsController(UserRequest ureq, WindowControl wControl, List<OrphanVersion> orphans) {
-		super(ureq, wControl);
-		
-		TableGuiConfiguration tableConfig = new TableGuiConfiguration();
-		tableConfig.setTableEmptyMessage(translate("table.empty"));
-		tableConfig.setDownloadOffered(true);
-		tableConfig.setMultiSelect(true);
-		
-		this.orphans = orphans;
-
-		tableCtr = new TableController(tableConfig, ureq, getWindowControl(), getTranslator());
-		tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("table.header.file", 0, null, getLocale()));
-		tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("table.header.versions", 1, null, getLocale()));
-		tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("table.header.size", 2, null, getLocale()));
-		tableCtr.addColumnDescriptor(new StaticColumnDescriptor(CMD_DELETE, "delete", translate("delete")));
-		tableCtr.setTableDataModel(new OrphanTableModel(orphans));
-		
-		tableCtr.addMultiSelectAction("delete", CMD_DELETE);
-		
-		listenTo(tableCtr);
-
-		putInitialPanel(tableCtr.getInitialComponent());
-	}
-	
-	@Override
-	protected void doDispose() {
-		//
-	}
-
-	@Override
-	protected void event(UserRequest ureq, Component source, Event event) {
-		//
-	}
-
-	@Override
-	protected void event(UserRequest ureq, Controller source, Event event) {
-		if(source == tableCtr) {
-			if (event.getCommand().equals(Table.COMMANDLINK_ROWACTION_CLICKED)) {
-				TableEvent te = (TableEvent) event;
-				String actionid = te.getActionId();
-				int rowid = te.getRowId();
-				OrphanVersion orphan = (OrphanVersion) tableCtr.getTableDataModel().getObject(rowid);
-				if (actionid.equals(CMD_DELETE)) {
-					versionsManager.delete(orphan);
-					orphans.remove(orphan);
-					tableCtr.modelChanged();
-				}
-			} else if (event.getCommand().equals(Table.COMMAND_MULTISELECT)) {
-				// Multiselect events
-				TableMultiSelectEvent tmse = (TableMultiSelectEvent) event;
-				BitSet selectedOrphans = tmse.getSelection();
-				String actionid = tmse.getAction();
-				if (CMD_DELETE.equals(actionid)) {
-					List<OrphanVersion> toRemove = new ArrayList<>();
-					for (int i=selectedOrphans.nextSetBit(0); i >= 0; i=selectedOrphans.nextSetBit(i+1)) {
-						int rowCount = tableCtr.getTableDataModel().getRowCount();
-						if(i >= 0 && i < rowCount) {
-							OrphanVersion orphan = (OrphanVersion)tableCtr.getTableDataModel().getObject(i);
-							versionsManager.delete(orphan);
-							toRemove.add(orphan);
-						}
-					}
-					for(OrphanVersion orphan:toRemove) {
-						orphans.remove(orphan);
-					}
-					tableCtr.setTableDataModel(new OrphanTableModel(orphans));
-					tableCtr.modelChanged();
-				}
-			}
-		}
-	}
-
-	private class OrphanTableModel implements TableDataModel<OrphanVersion> {
-		
-		private List<OrphanVersion> orphanList;
-		
-		public OrphanTableModel(List<OrphanVersion> orphans) {
-			this.orphanList = orphans;
-		}
-
-		@Override
-		public int getColumnCount() {
-			return 3;
-		}
-
-		@Override
-		public int getRowCount() {
-			return orphanList.size();
-		}
-
-		@Override
-		public Object getValueAt(int row, int col) {
-			OrphanVersion orphan = getObject(row);
-			switch(col) {
-				case 0: return orphan.getOriginalFilePath();
-				case 1: {
-					return orphan.getVersions().getRevisions().size();
-				}
-				case 2: {
-					List<VFSRevision> versions = orphan.getVersions().getRevisions();
-					long size = 0l;
-					for(VFSRevision revision:versions) {
-						size += revision.getSize();
-					}
-					
-					String unit = "KB";
-					double humanSize = size / 1024.0d;
-					if(humanSize > 1024) {
-						humanSize /= 1024;
-						unit = "MB";
-					}
-					return sizeFormat.format(humanSize) + " " + unit;
-				}
-				default: return "ERROR";
-			}
-		}
-
-		@Override
-		public OrphanVersion getObject(int row) {
-			return orphanList.get(row);
-		}
-
-		@Override
-		public void setObjects(List<OrphanVersion> objects) {
-			orphanList = objects;
-		}
-
-		@Override
-		public Object createCopyWithEmptyList() {
-			return new OrphanTableModel(Collections.<OrphanVersion>emptyList());
-		}
-	}
-}
\ No newline at end of file
diff --git a/src/main/java/org/olat/admin/version/_i18n/LocalStrings_ar.properties b/src/main/java/org/olat/admin/version/_i18n/LocalStrings_ar.properties
deleted file mode 100644
index 0353651394a26988d4e1bd12b8379c899f615cc5..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/admin/version/_i18n/LocalStrings_ar.properties
+++ /dev/null
@@ -1,14 +0,0 @@
-#Mon Feb 22 14:19:03 CET 2010
-
-
-
-
-
-form.version=\u0627\u0644\u0625\u0635\u062F\u0627\u0631\u0627\u062A
-
-version.intro=\u064A\u0631\u062C\u0649 \u0648\u0636\u0639 \u0627\u0644\u0639\u062F\u062F \u0627\u0644\u0623\u0642\u0635\u0649 \u0645\u0646 \u0627\u0644\u0625\u0635\u062F\u0627\u0631\u0627\u062A \u0641\u0649 \u0627\u0644\u0645\u062C\u0644\u062F (\u0645\u062C\u0644\u062F \u0627\u0644\u0645\u062C\u0645\u0648\u0639\u0629\u060C \u0645\u062C\u0644\u062F \u0627\u0644\u0645\u0642\u0631\u0631\u060C \u0625\u0627\u0644\u062E).
-version.notANumber=\u0644\u0645 \u064A\u062A\u0645 \u062A\u062D\u062F\u064A\u062F \u0631\u0642\u0645
-version.numOfVersions=\u0631\u0642\u0645 \u0627\u0644\u0625\u0635\u062F\u0627\u0631\u0627\u062A
-version.off=\u062A\u0639\u0637\u064A\u0644 \u0627\u0644\u0625\u0635\u062F\u0627\u0631\u0627\u062A
-version.title=\u0627\u0644\u0625\u0635\u062F\u0627\u0631\u0627\u062A
-version.unlimited=\u063A\u064A\u0631 \u0645\u062D\u062F\u0648\u062F
diff --git a/src/main/java/org/olat/admin/version/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/admin/version/_i18n/LocalStrings_de.properties
deleted file mode 100644
index 15003597c8303da357992b4a97ac0f1d6660b585..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/admin/version/_i18n/LocalStrings_de.properties
+++ /dev/null
@@ -1,30 +0,0 @@
-#Mon Mar 02 09:54:03 CET 2009
-form.version=Versionierung
-version.intro=Stellen Sie die maximale Anzahl von Versionen f\u00fcr eine Datei einer Ordnerkomponente (Gruppenordner, Kursordner etc.) ein.
-version.title=Versionierung
-version.numOfVersions=Anzahl Versionen
-version.notANumber=Keine Zahl gew\u00e4hlt
-version.unlimited=Unlimitiert
-version.off=Versionierung ausgeschaltet
-version.clean.up=Orphan Versionen l\u00f6schen
-version.orphan.size=Orphan Versionen Gr\u00f6sse
-version.orphan.size.calc=Gr\u00f6sse rechnen
-version.orphan.size.calculating=Gr\u00f6sse am rechnen...
-version.show.orphans=Orphan Versionen auflisten
-version.prune.history=Versionen aufr\u00e4umen
-version.maintenance.title=Verwaltung
-version.maintenance.intro=Verwaltung von Versionen
-table.header.file=Datei
-table.header.versions=Anzhal Versionen
-table.header.size=Gr\u00f6sse
-table.empty=Keine orphan Versionen \u00fcbrig
-
-
-
-
-
-
-
-
-confirm.delete.orphans=Wollen Sie wirklich alle Orphan Versionen l\u00f6schen?
-confirm.prune.history=Wollen Sie wirklich die \u00fcberfl\u00fcssige Versionen l\u00f6schen?
diff --git a/src/main/java/org/olat/admin/version/_i18n/LocalStrings_el.properties b/src/main/java/org/olat/admin/version/_i18n/LocalStrings_el.properties
deleted file mode 100644
index 44aa0f618e17b24a3b0d53f5b8471649c5a10ede..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/admin/version/_i18n/LocalStrings_el.properties
+++ /dev/null
@@ -1,11 +0,0 @@
-#Fri Mar 12 16:12:40 CET 2010
-
-
-form.version=\u0395\u03BA\u03B4\u03CC\u03C3\u03B5\u03B9\u03C2
-
-version.intro=\u03A0\u03B1\u03C1\u03B1\u03BA\u03B1\u03BB\u03CE \u03C1\u03C5\u03B8\u03BC\u03AF\u03C3\u03C4\u03B5 \u03C4\u03BF \u03BC\u03AD\u03B3\u03B9\u03C3\u03C4\u03BF \u03B1\u03C1\u03B9\u03B8\u03BC\u03CC \u03C4\u03C9\u03BD \u03B5\u03BA\u03B4\u03CC\u03C3\u03B5\u03C9\u03BD \u03B3\u03B9\u03B1 \u03AD\u03BD\u03B1 \u03C3\u03C4\u03BF\u03B9\u03C7\u03B5\u03AF\u03BF \u03C4\u03BF\u03C5 \u03C6\u03B1\u03BA\u03AD\u03BB\u03BF\u03C5 (\u03C6\u03AC\u03BA\u03B5\u03BB\u03BF\u03C2 \u03BF\u03BC\u03AC\u03B4\u03B1\u03C2, \u03C6\u03AC\u03BA\u03B5\u03BB\u03BF\u03C2 \u03BC\u03B1\u03B8\u03AE\u03BC\u03B1\u03C4\u03BF\u03C2 \u03BA\u03C4\u03BB.)
-version.notANumber=\u0394\u03B5\u03BD \u03B5\u03C0\u03B9\u03BB\u03AD\u03C7\u03B8\u03B7\u03BA\u03B5 \u03B1\u03C1\u03B9\u03B8\u03BC\u03CC\u03C2
-version.numOfVersions=\u0391\u03C1\u03B9\u03B8\u03BC\u03CC\u03C2 \u03B5\u03BA\u03B4\u03CC\u03C3\u03B5\u03C9\u03BD
-version.off=\u039F\u03B9 \u03B5\u03BA\u03B4\u03CC\u03C3\u03B5\u03B9\u03C2 \u03AD\u03C7\u03BF\u03C5\u03BD \u03B1\u03C0\u03B5\u03BD\u03B5\u03C1\u03B3\u03BF\u03C0\u03BF\u03B9\u03B7\u03B8\u03B5\u03AF
-version.title=\u0395\u03BA\u03B4\u03CC\u03C3\u03B5\u03B9\u03C2
-version.unlimited=\u0391\u03C0\u03B5\u03C1\u03B9\u03CC\u03C1\u03B9\u03C3\u03C4\u03BF\u03C2
diff --git a/src/main/java/org/olat/admin/version/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/admin/version/_i18n/LocalStrings_fr.properties
deleted file mode 100644
index b03f93f15367c68331f76af26ff60d3ec3bce95e..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/admin/version/_i18n/LocalStrings_fr.properties
+++ /dev/null
@@ -1,30 +0,0 @@
-#Sat Nov 02 20:59:58 CET 2013
-
-
-
-
-
-
-
-confirm.delete.orphans=Voulez-vous vraiment effacer toutes les versions orphelines?
-confirm.prune.history=Voulez-vous vraiment effacer toutes les versions qui d\u00E9passent la limite configur\u00E9e?
-form.version=V\u00E9rification des version
-
-table.empty=Aucune version orpheline ne reste
-table.header.file=Fichier
-table.header.size=Taille
-table.header.versions=Nombre de versions
-version.clean.up=Supprimer les versions orphelines
-version.intro=Etablir le nombre maximal de versions pour un fichier d'un dossier (dossier de groupe, dossier de cours etc.).
-version.maintenance.intro=Administration des versions
-version.maintenance.title=Administration
-version.notANumber=Aucun nombre choisi
-version.numOfVersions=Nombre de versions
-version.off=V\u00E9rification des versions d\u00E9sactiv\u00E9s
-version.orphan.size=Taille des versions orphelines
-version.orphan.size.calc=Calculer la taille
-version.orphan.size.calculating=Taille en cours de calcul
-version.prune.history=Nettoyer les versions
-version.show.orphans=Liste des versions orphelines
-version.title=V\u00E9rification des versions
-version.unlimited=Illimit\u00E9
diff --git a/src/main/java/org/olat/admin/version/_i18n/LocalStrings_jp.properties b/src/main/java/org/olat/admin/version/_i18n/LocalStrings_jp.properties
deleted file mode 100644
index 2ce6cbd6f87f33e061aef49a192402dc0a40c448..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/admin/version/_i18n/LocalStrings_jp.properties
+++ /dev/null
@@ -1,11 +0,0 @@
-#Thu Sep 23 20:31:41 CEST 2010
-
-
-form.version=\u30D0\u30FC\u30B8\u30E7\u30CB\u30F3\u30B0
-
-version.intro=\u30D5\u30A9\u30EB\u30C0\u69CB\u6210\u30D5\u30A1\u30A4\u30EB (\u30B0\u30EB\u30FC\u30D7\u30D5\u30A9\u30EB\u30C0\u3001\u30B3\u30FC\u30B9\u30D5\u30A9\u30EB\u30C0\u7B49) \u306E\u6700\u5927\u30D0\u30FC\u30B8\u30E7\u30F3\u6570\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002
-version.notANumber=\u6570\u304C\u9078\u629E\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002
-version.numOfVersions=\u30D0\u30FC\u30B8\u30E7\u30F3\u6570
-version.off=\u30D0\u30FC\u30B8\u30E7\u30CB\u30F3\u30B0\u7121\u52B9
-version.title=\u30D0\u30FC\u30B8\u30E7\u30CB\u30F3\u30B0
-version.unlimited=\u7121\u5236\u9650
diff --git a/src/main/java/org/olat/admin/version/_i18n/LocalStrings_nl_NL.properties b/src/main/java/org/olat/admin/version/_i18n/LocalStrings_nl_NL.properties
deleted file mode 100644
index c7d2bb586b2cd8ecb99d528de8a8227b83d54b96..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/admin/version/_i18n/LocalStrings_nl_NL.properties
+++ /dev/null
@@ -1,14 +0,0 @@
-#Thu Sep 08 16:42:42 CEST 2011
-
-
-
-
-
-form.version=Versionering
-
-version.intro=Gelieve het maximum aantal versies voor een maponderdeel in te stellen (groepmap, cursusmap, etc.).
-version.notANumber=Geen nummer geselecteerd
-version.numOfVersions=Aantal versies
-version.off=Versionering gedeactiveerd
-version.title=Versionering
-version.unlimited=Ongelimiteerd
diff --git a/src/main/java/org/olat/admin/version/_i18n/LocalStrings_pl.properties b/src/main/java/org/olat/admin/version/_i18n/LocalStrings_pl.properties
deleted file mode 100644
index fe25fb23924fcdda49e5a05c7b54cac9b8f2c87f..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/admin/version/_i18n/LocalStrings_pl.properties
+++ /dev/null
@@ -1,19 +0,0 @@
-#Sun Dec 23 19:39:03 CET 2012
-
-
-
-form.version=Wersjonowanie
-
-table.header.file=Plik
-table.header.size=Rozmiar
-table.header.versions=Liczba wersji
-version.intro=Podaj maksymaln\u0105 liczb\u0119 wersji dla folder\u00F3w (folder grupy, folder kursu, itd.).
-version.maintenance.intro=Zarz\u0105dzanie wersjami
-version.maintenance.title=Zarz\u0105dzanie
-version.notANumber=Nie wybrano liczby
-version.numOfVersions=Liczba wersji
-version.off=Wersjonowanie wy\u0142\u0105czone
-version.orphan.size.calc=Oblicz rozmiar
-version.orphan.size.calculating=Trwa obliczanie...
-version.title=Wersjonowanie
-version.unlimited=Brak limitu
diff --git a/src/main/java/org/olat/admin/version/_i18n/LocalStrings_zh_CN.properties b/src/main/java/org/olat/admin/version/_i18n/LocalStrings_zh_CN.properties
deleted file mode 100644
index ffc281ebc04a453ee1b5f4ad3750da07a2cd38e5..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/admin/version/_i18n/LocalStrings_zh_CN.properties
+++ /dev/null
@@ -1,22 +0,0 @@
-#Mon Nov 10 00:41:46 CET 2014
-
-
-
-
-
-form.version=\u7248\u672C
-
-version.clean.up=\u5220\u9664Orphan\u7248\u672C
-version.intro=\u8BF7\u4E3A\u7EC4\u6210\u6587\u4EF6\u5939\uFF08\u7FA4\u7EC4\u6587\u4EF6\u5939\uFF0C\u5B66\u7A0B\u6587\u4EF6\u5939\uFF0C\u7B49\uFF09\u7684\u6587\u4EF6\u8BBE\u7F6E\u7248\u672C\u7684\u6700\u5927\u6570\u76EE\u3002
-version.maintenance.intro=\u7248\u672C\u7BA1\u7406
-version.maintenance.title=\u7BA1\u7406
-version.notANumber=\u672A\u9009\u62E9\u4EFB\u4F55\u6570\u5B57
-version.numOfVersions=\u7248\u672C\u7684\u6570\u76EE
-version.off=\u5DF2\u5173\u95ED\u7248\u672C
-version.orphan.size=Orphan\u7248\u672C\u5927\u5C0F
-version.orphan.size.calc=\u5927\u5C0F\u8BA1\u7B97
-version.orphan.size.calculating=\u6B63\u5728\u8BA1\u7B97\u5927\u5C0F
-version.prune.history=\u7248\u672C\u6E05\u7406
-version.show.orphans=\u5217\u51FAOrphan\u7248\u672C
-version.title=\u7248\u672C
-version.unlimited=\u65E0\u9650
diff --git a/src/main/java/org/olat/admin/version/_i18n/LocalStrings_zh_TW.properties b/src/main/java/org/olat/admin/version/_i18n/LocalStrings_zh_TW.properties
deleted file mode 100644
index ce649bf4e7d5a8647e03ec6e63fae93a8b4b2c5b..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/admin/version/_i18n/LocalStrings_zh_TW.properties
+++ /dev/null
@@ -1,9 +0,0 @@
-#Sat Sep 18 15:10:48 CEST 2010
-form.version=\u7248\u672C
-
-version.intro=\u8ACB\u8A2D\u5B9A\u8CC7\u6599\u593E\u7D44\u6210\u7684\u6A94\u6848\uFF08\u5B58\u53D6\u8CC7\u6599\u593E\u3001\u8AB2\u7A0B\u8CC7\u6599\u593E\uFF0C\u7B49\uFF09\u7684\u6700\u5927\u7248\u672C\u6578\u3002
-version.notANumber=\u672A\u9078\u64C7\u4EFB\u4F55\u6578\u5B57
-version.numOfVersions=\u7248\u672C\u6578
-version.off=\u505C\u7528\u7248\u672C\u63A7\u5236
-version.title=\u7248\u672C
-version.unlimited=\u7121\u9650
diff --git a/src/main/java/org/olat/core/commons/editor/fileeditor/FileEditorController.java b/src/main/java/org/olat/core/commons/editor/fileeditor/FileEditorController.java
index 4fec7f7b421a6d3dc83fb01193707b364ca95a76..9cb508a07c5edb8be1e5fe9fb4311661e986b35e 100644
--- a/src/main/java/org/olat/core/commons/editor/fileeditor/FileEditorController.java
+++ b/src/main/java/org/olat/core/commons/editor/fileeditor/FileEditorController.java
@@ -31,7 +31,7 @@ import org.olat.core.commons.editor.htmleditor.HTMLEditorController;
 import org.olat.core.commons.editor.htmleditor.WysiwygFactory;
 import org.olat.core.commons.editor.plaintexteditor.TextEditorController;
 import org.olat.core.commons.modules.bc.components.FolderComponent;
-import org.olat.core.commons.modules.bc.version.VersionCommentController;
+import org.olat.core.commons.services.vfs.ui.version.VersionCommentController;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.velocity.VelocityContainer;
diff --git a/src/main/java/org/olat/core/commons/editor/htmleditor/HTMLEditorController.java b/src/main/java/org/olat/core/commons/editor/htmleditor/HTMLEditorController.java
index 6e29fa66ad6fd6b45c53c13fa63215df3957d78e..75d219a5ac7ce3435a218a5005081a518a1c6742 100644
--- a/src/main/java/org/olat/core/commons/editor/htmleditor/HTMLEditorController.java
+++ b/src/main/java/org/olat/core/commons/editor/htmleditor/HTMLEditorController.java
@@ -26,6 +26,7 @@ import java.util.Date;
 
 import org.olat.core.commons.controllers.linkchooser.CustomLinkTreeModel;
 import org.olat.core.commons.modules.bc.FolderConfig;
+import org.olat.core.commons.services.vfs.VFSRepositoryService;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItem;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
@@ -52,13 +53,14 @@ import org.olat.core.util.coordinate.CoordinatorManager;
 import org.olat.core.util.coordinate.LockResult;
 import org.olat.core.util.resource.OresHelper;
 import org.olat.core.util.vfs.LocalFileImpl;
+import org.olat.core.util.vfs.VFSConstants;
 import org.olat.core.util.vfs.VFSContainer;
 import org.olat.core.util.vfs.VFSItem;
 import org.olat.core.util.vfs.VFSLeaf;
-import org.olat.core.util.vfs.version.Versionable;
 import org.olat.modules.edusharing.EdusharingFilter;
 import org.olat.modules.edusharing.VFSEdusharingProvider;
 import org.olat.user.UserManager;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * Description:<br>
@@ -120,6 +122,11 @@ public class HTMLEditorController extends FormBasicController {
 	private String fileToLargeError = null;
 	private VFSEdusharingProvider edusharingProvider;
 	private Object userObject;
+	
+	@Autowired
+	private UserManager userManager;
+	@Autowired
+	private VFSRepositoryService vfsRepositoryService;
 
 	/**
 	 * Factory method to create a file based HTML editor instance that uses
@@ -199,7 +206,7 @@ public class HTMLEditorController extends FormBasicController {
 			VelocityContainer vc = (VelocityContainer) flc.getComponent();
 			if (!lock.isSuccess()) {
 				vc.contextPut("locked", Boolean.TRUE);
-				String fullname = UserManager.getInstance().getUserDisplayName(lock.getOwner());
+				String fullname = userManager.getUserDisplayName(lock.getOwner());
 				vc.contextPut("lockOwner", fullname);
 				editable = false;
 				return;
@@ -390,11 +397,15 @@ public class HTMLEditorController extends FormBasicController {
 	 */
 	private String parsePage(VFSLeaf vfsLeaf) {
 		// Load data with given encoding
-		InputStream is = vfsLeaf.getInputStream();
-		if (is == null) { throw new AssertException("Could not open input stream for file::"
-				+ getFileDebuggingPath(this.baseContainer, this.fileRelPath)); }
-		this.charSet = SimpleHtmlParser.extractHTMLCharset(vfsLeaf);
-		String leafData = FileUtils.load(is, charSet);
+		String leafData = null;
+		try(InputStream is = vfsLeaf.getInputStream()) {
+			if (is == null) { throw new AssertException("Could not open input stream for file::"
+					+ getFileDebuggingPath(this.baseContainer, this.fileRelPath)); }
+			this.charSet = SimpleHtmlParser.extractHTMLCharset(vfsLeaf);
+			leafData = FileUtils.load(is, charSet);
+		} catch(IOException e) {
+			logError("", e);
+		}
 		if (leafData == null || leafData.length() == 0) {
 			leafData = "";
 		}
@@ -471,9 +482,9 @@ public class HTMLEditorController extends FormBasicController {
 		}
 		
 		// save the file
-		if(versionsEnabled && fileLeaf instanceof Versionable && ((Versionable)fileLeaf).getVersions().isVersioned()) {
+		if(versionsEnabled && fileLeaf.canVersion() == VFSConstants.YES) {
 			try(InputStream inStream = FileUtils.getInputStream(fileContent.toString(), charSet)) {
-				((Versionable)fileLeaf).getVersions().addVersion(getIdentity(), "", inStream);
+				vfsRepositoryService.addVersion(fileLeaf, getIdentity(), "", inStream);
 			} catch(IOException e) {
 				logError("", e);
 			}
diff --git a/src/main/java/org/olat/core/commons/editor/plaintexteditor/TextEditorController.java b/src/main/java/org/olat/core/commons/editor/plaintexteditor/TextEditorController.java
index c1ee7edfcff0241ad71f3c01823bdb3c1b8fc3a5..31a8cae7deeb0874e9afb5e6212270f6f2c74252 100644
--- a/src/main/java/org/olat/core/commons/editor/plaintexteditor/TextEditorController.java
+++ b/src/main/java/org/olat/core/commons/editor/plaintexteditor/TextEditorController.java
@@ -24,6 +24,7 @@ import java.io.InputStream;
 import java.io.OutputStream;
 
 import org.olat.core.commons.modules.bc.FolderConfig;
+import org.olat.core.commons.services.vfs.VFSRepositoryService;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItem;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
@@ -37,8 +38,9 @@ import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.util.FileUtils;
+import org.olat.core.util.vfs.VFSConstants;
 import org.olat.core.util.vfs.VFSLeaf;
-import org.olat.core.util.vfs.version.Versionable;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * 
@@ -56,6 +58,9 @@ public class TextEditorController extends FormBasicController {
 	private final VFSLeaf vfsLeaf;
 	private final String encoding;
 	private final boolean readonly;
+	
+	@Autowired
+	private VFSRepositoryService vfsRepositoryService;
 
 	public TextEditorController(UserRequest ureq, WindowControl wControl, VFSLeaf vfsLeaf, String encoding, boolean readonly) {
 		super(ureq, wControl, LAYOUT_VERTICAL);
@@ -109,9 +114,9 @@ public class TextEditorController extends FormBasicController {
 
 	private void doSave() {
 		String content = contentEl.getValue();
-		if(vfsLeaf instanceof Versionable && ((Versionable)vfsLeaf).getVersions().isVersioned()) {
+		if(vfsLeaf.canVersion() == VFSConstants.YES) {
 			try (InputStream inStream = FileUtils.getInputStream(content, encoding)) {
-				((Versionable)vfsLeaf).getVersions().addVersion(getIdentity(), "", inStream);
+				vfsRepositoryService.addVersion(vfsLeaf, getIdentity(), "", inStream);
 			} catch (IOException e) {
 				logError("", e);
 			}
diff --git a/src/main/java/org/olat/core/commons/modules/bc/FileCopyController.java b/src/main/java/org/olat/core/commons/modules/bc/FileCopyController.java
index 2c263e52f0819bb68164d6945db02adeebc2dbac..968d51b2b0b008118cf7345c4a1aa60cf4a84a52 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/FileCopyController.java
+++ b/src/main/java/org/olat/core/commons/modules/bc/FileCopyController.java
@@ -22,14 +22,20 @@ package org.olat.core.commons.modules.bc;
 
 import static java.util.Arrays.asList;
 
+import java.util.List;
+
 import org.olat.core.commons.controllers.linkchooser.FileLinkChooserController;
 import org.olat.core.commons.controllers.linkchooser.LinkChooserController;
 import org.olat.core.commons.controllers.linkchooser.URLChoosenEvent;
 import org.olat.core.commons.modules.bc.commands.FolderCommand;
 import org.olat.core.commons.modules.bc.commands.FolderCommandStatus;
 import org.olat.core.commons.modules.bc.components.FolderComponent;
-import org.olat.core.commons.modules.bc.version.RevisionListController;
-import org.olat.core.commons.modules.bc.version.VersionCommentController;
+import org.olat.core.commons.services.vfs.VFSMetadata;
+import org.olat.core.commons.services.vfs.VFSRepositoryService;
+import org.olat.core.commons.services.vfs.VFSRevision;
+import org.olat.core.commons.services.vfs.VFSVersionModule;
+import org.olat.core.commons.services.vfs.ui.version.RevisionListController;
+import org.olat.core.commons.services.vfs.ui.version.VersionCommentController;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.velocity.VelocityContainer;
 import org.olat.core.gui.control.Controller;
@@ -45,14 +51,13 @@ import org.olat.core.logging.activity.CoreLoggingResourceable;
 import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
 import org.olat.core.util.FileUtils;
 import org.olat.core.util.Util;
+import org.olat.core.util.vfs.VFSConstants;
 import org.olat.core.util.vfs.VFSContainer;
 import org.olat.core.util.vfs.VFSItem;
 import org.olat.core.util.vfs.VFSLeaf;
 import org.olat.core.util.vfs.VFSLockApplicationType;
 import org.olat.core.util.vfs.VFSLockManager;
 import org.olat.core.util.vfs.VFSManager;
-import org.olat.core.util.vfs.version.Versionable;
-import org.olat.core.util.vfs.version.Versions;
 import org.springframework.beans.factory.annotation.Autowired;
 
 /**
@@ -80,6 +85,10 @@ public class FileCopyController extends LinkChooserController {
 	
 	@Autowired
 	private VFSLockManager vfsLockManager;
+	@Autowired
+	private VFSVersionModule versionsModule;
+	@Autowired
+	private VFSRepositoryService vfsRepositoryService;
 	
 	public FileCopyController(UserRequest ureq, WindowControl wControl, VFSContainer rootDir,
 			FolderComponent folderComponent) {
@@ -129,10 +138,9 @@ public class FileCopyController extends LinkChooserController {
 			if (event instanceof ButtonClickedEvent) {
 				ButtonClickedEvent buttonClickedEvent = (ButtonClickedEvent) event;
 				if (buttonClickedEvent.getPosition() == 0) { //ok
-					if (existingVFSItem instanceof Versionable && ((Versionable)existingVFSItem).getVersions().isVersioned()) {
+					if (existingVFSItem.canVersion() == VFSConstants.YES) {
 						//new version
-						String relPath = existingVFSItem.getRelPath();
-						int maxNumOfRevisions = FolderConfig.versionsAllowed(relPath);
+						int maxNumOfRevisions = versionsModule.getMaxNumberOfVersions();
 						if(maxNumOfRevisions == 0) {
 							//someone play with the configuration
 							// Overwrite...
@@ -222,8 +230,7 @@ public class FileCopyController extends LinkChooserController {
 			}
 			
 			//ok, new version of the file
-			Versionable existingVersionableItem = (Versionable)existingVFSItem;
-			boolean ok = existingVersionableItem.getVersions().addVersion(ureq.getIdentity(), comment, sourceLeaf.getInputStream());
+			boolean ok = vfsRepositoryService.addVersion(existingVFSItem, ureq.getIdentity(), comment, sourceLeaf.getInputStream());
 			if(ok) {
 				newFile = existingVFSItem;
 			}
@@ -248,14 +255,14 @@ public class FileCopyController extends LinkChooserController {
 				//don't want to delete revisions
 				fireEvent(ureq, FolderCommand.FOLDERCOMMAND_FINISHED);
 			} else {
-				if (existingVFSItem instanceof Versionable && ((Versionable)existingVFSItem).getVersions().isVersioned()) {
-	
+				if (existingVFSItem.canVersion() == VFSConstants.YES) {
+
 					revisionListDialogBox.deactivate();
 	
-					Versionable versionable = (Versionable)existingVFSItem;
-					Versions versions = versionable.getVersions();
-					int maxNumOfRevisions = FolderConfig.versionsAllowed(null);
-					if(maxNumOfRevisions < 0 || maxNumOfRevisions > versions.getRevisions().size()) {
+					int maxNumOfRevisions = versionsModule.getMaxNumberOfVersions();
+					VFSMetadata metadata = vfsRepositoryService.getMetadataFor(existingVFSItem);
+					List<VFSRevision> revisions = vfsRepositoryService.getRevisions(metadata);
+					if(maxNumOfRevisions < 0 || maxNumOfRevisions > revisions.size()) {
 						
 						removeAsListenerAndDispose(commentVersionCtr);
 						boolean locked = vfsLockManager.isLocked(existingVFSItem, VFSLockApplicationType.vfs);
@@ -271,7 +278,7 @@ public class FileCopyController extends LinkChooserController {
 					} else {
 						
 						removeAsListenerAndDispose(revisionListCtr);
-						revisionListCtr = new RevisionListController(ureq,getWindowControl(),versionable, false);
+						revisionListCtr = new RevisionListController(ureq,getWindowControl(), existingVFSItem, false);
 						listenTo(revisionListCtr);
 						
 						removeAsListenerAndDispose(revisionListDialogBox);
@@ -308,11 +315,11 @@ public class FileCopyController extends LinkChooserController {
 					asList(translate("ul.overwrite.threeoptions.rename", renamedFilename), translate("ul.overwrite.threeoptions.cancel")));
 			listenTo(lockedFileDialog);
 			lockedFileDialog.activate();
-		} else if (existingVFSItem instanceof Versionable && ((Versionable)existingVFSItem).getVersions().isVersioned()) {
-			Versionable versionable = (Versionable)existingVFSItem;
-			Versions versions = versionable.getVersions();
-			String relPath = existingVFSItem.getRelPath();
-			int maxNumOfRevisions = FolderConfig.versionsAllowed(relPath);
+		} else if (existingVFSItem.canVersion() == VFSConstants.YES) {
+
+			int maxNumOfRevisions = versionsModule.getMaxNumberOfVersions();
+			VFSMetadata metadata = vfsRepositoryService.getMetadataFor(existingVFSItem);
+			List<VFSRevision> revisions = vfsRepositoryService.getRevisions(metadata);
 			if(maxNumOfRevisions == 0) {
 				//it's possible if someone change the configuration
 				// let calling method decide what to do.
@@ -325,7 +332,7 @@ public class FileCopyController extends LinkChooserController {
 				
 				overwriteDialog.activate();
 				
-			} else if(versions.getRevisions().isEmpty() || maxNumOfRevisions < 0 || maxNumOfRevisions > versions.getRevisions().size()) {
+			} else if(revisions.isEmpty() || maxNumOfRevisions < 0 || maxNumOfRevisions > revisions.size()) {
 				// let calling method decide what to do.
 				removeAsListenerAndDispose(overwriteDialog);
 				overwriteDialog = DialogBoxUIFactory.createGenericDialog(ureq, getWindowControl(), translate("ul.overwrite.threeoptions.title"),
@@ -338,11 +345,11 @@ public class FileCopyController extends LinkChooserController {
 				
 			} else {
 			
-				String title = translate("ul.tooManyRevisions.title", new String[]{Integer.toString(maxNumOfRevisions), Integer.toString(versions.getRevisions().size())});
-				String description = translate("ul.tooManyRevisions.description", new String[]{Integer.toString(maxNumOfRevisions), Integer.toString(versions.getRevisions().size())});
+				String title = translate("ul.tooManyRevisions.title", new String[]{Integer.toString(maxNumOfRevisions), Integer.toString(revisions.size())});
+				String description = translate("ul.tooManyRevisions.description", new String[]{Integer.toString(maxNumOfRevisions), Integer.toString(revisions.size())});
 				
 				removeAsListenerAndDispose(revisionListCtr);
-				revisionListCtr = new RevisionListController(ureq, getWindowControl(), versionable, null, description, false);
+				revisionListCtr = new RevisionListController(ureq, getWindowControl(), existingVFSItem, null, description, false);
 				listenTo(revisionListCtr);
 				
 				removeAsListenerAndDispose(revisionListDialogBox);
diff --git a/src/main/java/org/olat/core/commons/modules/bc/FileUploadController.java b/src/main/java/org/olat/core/commons/modules/bc/FileUploadController.java
index 65f6cdb07fb5bc4265e40faf29a79db483ef0e55..de3ee19f34f602bd963538ab43e8eeb28235634c 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/FileUploadController.java
+++ b/src/main/java/org/olat/core/commons/modules/bc/FileUploadController.java
@@ -41,11 +41,13 @@ import java.util.regex.Pattern;
 
 import org.olat.core.commons.modules.bc.commands.FolderCommandStatus;
 import org.olat.core.commons.modules.bc.meta.MetaInfoFormController;
-import org.olat.core.commons.modules.bc.version.RevisionListController;
-import org.olat.core.commons.modules.bc.version.VersionCommentController;
 import org.olat.core.commons.services.image.ImageService;
 import org.olat.core.commons.services.vfs.VFSMetadata;
 import org.olat.core.commons.services.vfs.VFSRepositoryService;
+import org.olat.core.commons.services.vfs.VFSRevision;
+import org.olat.core.commons.services.vfs.VFSVersionModule;
+import org.olat.core.commons.services.vfs.ui.version.RevisionListController;
+import org.olat.core.commons.services.vfs.ui.version.VersionCommentController;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItem;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
@@ -82,8 +84,6 @@ import org.olat.core.util.vfs.VFSLeaf;
 import org.olat.core.util.vfs.VFSLockApplicationType;
 import org.olat.core.util.vfs.VFSLockManager;
 import org.olat.core.util.vfs.VFSManager;
-import org.olat.core.util.vfs.version.Versionable;
-import org.olat.core.util.vfs.version.Versions;
 import org.springframework.beans.factory.annotation.Autowired;
 
 /**
@@ -156,6 +156,8 @@ public class FileUploadController extends FormBasicController {
 	@Autowired
 	private VFSLockManager vfsLockManager;
 	@Autowired
+	private VFSVersionModule versionsModule;
+	@Autowired
 	private VFSRepositoryService vfsRepositoryService;
 
 	private String subfolderPath;
@@ -431,7 +433,7 @@ public class FileUploadController extends FormBasicController {
 			if(FolderCommandStatus.STATUS_CANCELED == revisionListCtr.getStatus()) {
 				//don't want to delete revisions, clean the temporary file
 				doCancel(ureq);
-			} else if (existingVFSItem instanceof Versionable && ((Versionable)existingVFSItem).getVersions().isVersioned()) {
+			} else if (existingVFSItem.canVersion() == VFSConstants.YES) {
 				doFinishRevisionList(ureq);
 			}
 		}
@@ -449,7 +451,7 @@ public class FileUploadController extends FormBasicController {
 	}
 	
 	private void doFinishOverwrite(UserRequest ureq) {
-		if (existingVFSItem instanceof Versionable && ((Versionable)existingVFSItem).getVersions().isVersioned()) {
+		if (existingVFSItem.canVersion() == VFSConstants.YES) {
 			//new version
 			int maxNumOfRevisions = getMaxNumOfRevisionsOfExistingVFSItem();
 			if(maxNumOfRevisions == 0) {
@@ -496,12 +498,11 @@ public class FileUploadController extends FormBasicController {
 		}
 		
 		//ok, new version of the file
-		Versionable existingVersionableItem = (Versionable)existingVFSItem;
-		boolean ok = existingVersionableItem.getVersions().addVersion(ureq.getIdentity(), comment, newFile.getInputStream());
-		if(ok) {
-			newFile.deleteSilently();
-			//what can i do if existingVFSItem is a container
-			if(existingVFSItem instanceof VFSLeaf) {
+		if(existingVFSItem instanceof VFSLeaf && existingVFSItem.canVersion() == VFSConstants.YES) {
+			boolean ok = vfsRepositoryService.addVersion((VFSLeaf)existingVFSItem, ureq.getIdentity(), comment, newFile.getInputStream());
+			if(ok) {
+				newFile.deleteSilently();
+				//what can i do if existingVFSItem is a container
 				newFile = (VFSLeaf)existingVFSItem;
 			}
 		}
@@ -513,28 +514,30 @@ public class FileUploadController extends FormBasicController {
 			existingVFSItem = existingVFSItem.getParentContainer().resolve(existingVFSItem.getName());
 		}
 		
-		Versionable versionable = (Versionable)existingVFSItem;
-		Versions versions = versionable.getVersions();
+		VFSMetadata metadata = vfsRepositoryService.getMetadataFor(existingVFSItem);
+		List<VFSRevision> revisions = vfsRepositoryService.getRevisions(metadata);
 		int maxNumOfRevisions = getMaxNumOfRevisionsOfExistingVFSItem();
-		if(maxNumOfRevisions < 0 || maxNumOfRevisions > versions.getRevisions().size()) {
+		if(maxNumOfRevisions < 0 || maxNumOfRevisions > revisions.size()) {
 			askForComment(ureq);
 		} else {
-			askToReduceRevisionList(ureq, versionable);
+			askToReduceRevisionList(ureq, (VFSLeaf)existingVFSItem);
 		}
 	}
 	
 	private int getMaxNumOfRevisionsOfExistingVFSItem() {
-		String relPath = existingVFSItem.getRelPath();
-		return FolderConfig.versionsAllowed(relPath);
+		return versionsModule.getMaxNumberOfVersions();
 	}
 	
-	private void askToReduceRevisionList(UserRequest ureq, Versionable versionable) {
+	private void askToReduceRevisionList(UserRequest ureq, VFSLeaf versionable) {
 		removeAsListenerAndDispose(revisionListCtr);
 		removeAsListenerAndDispose(revisionListDialogBox);
 		
-		Versions versions = versionable.getVersions();
 		int maxNumOfRevisions = getMaxNumOfRevisionsOfExistingVFSItem();
-		String[] params = new String[]{ Integer.toString(maxNumOfRevisions), Integer.toString(versions.getRevisions().size()) };
+		VFSMetadata metadata = vfsRepositoryService.getMetadataFor(versionable);
+		List<VFSRevision> revisions = vfsRepositoryService.getRevisions(metadata);
+		
+		int numOfRevisions = revisions.size();
+		String[] params = new String[]{ Integer.toString(maxNumOfRevisions), Integer.toString(numOfRevisions) };
 		String title = translate("ul.tooManyRevisions.title", params);
 		String description = translate("ul.tooManyRevisions.description", params);
 		
@@ -627,7 +630,7 @@ public class FileUploadController extends FormBasicController {
 				if (locked) {
 					//the file is locked and cannot be overwritten
 					lockedFileDialog(ureq, renamedFilename);
-				} else if (existingVFSItem instanceof Versionable && ((Versionable)existingVFSItem).getVersions().isVersioned()) {
+				} else if (existingVFSItem.canVersion() == VFSConstants.YES) {
 					uploadVersionedFile(ureq, renamedFilename);
 				} else {
 					askOverwriteOrRename(ureq, renamedFilename);
@@ -651,19 +654,19 @@ public class FileUploadController extends FormBasicController {
 	}
 	
 	private void uploadVersionedFile(UserRequest ureq, String renamedFilename) {
-		Versionable versionable = (Versionable)existingVFSItem;
-		Versions versions = versionable.getVersions();
+		VFSMetadata metadata = vfsRepositoryService.getMetadataFor(existingVFSItem);
+		List<VFSRevision> revisions = vfsRepositoryService.getRevisions(metadata);
 		int maxNumOfRevisions = getMaxNumOfRevisionsOfExistingVFSItem();
 		if(maxNumOfRevisions == 0) {
 			//it's possible if someone change the configuration
 			// let calling method decide what to do.
 			askOverwriteOrRename(ureq, renamedFilename);
-		} else if(versions.getRevisions().isEmpty() || maxNumOfRevisions < 0 || maxNumOfRevisions > versions.getRevisions().size()) {
+		} else if(revisions.isEmpty() || maxNumOfRevisions < 0 || maxNumOfRevisions > revisions.size()) {
 			// let calling method decide what to do.
 			askNewVersionOrRename(ureq, renamedFilename);
 		} else {
 			//too many revisions
-			askToReduceRevisionList(ureq, versionable);
+			askToReduceRevisionList(ureq, (VFSLeaf)existingVFSItem);
 		}
 	}
 	
diff --git a/src/main/java/org/olat/core/commons/modules/bc/FolderConfig.java b/src/main/java/org/olat/core/commons/modules/bc/FolderConfig.java
index 3f23ab173cbce1a1e67c8f1dcac82603af5334b3..1ef8d746f45618f1643e73ecb0487af4e65dfe18 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/FolderConfig.java
+++ b/src/main/java/org/olat/core/commons/modules/bc/FolderConfig.java
@@ -29,9 +29,6 @@ package org.olat.core.commons.modules.bc;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 
-import org.olat.core.util.vfs.VFSContainer;
-import org.olat.core.util.vfs.version.FolderVersioningConfigurator;
-
 /**
  * Initial Date:  18.12.2002
  *
@@ -63,7 +60,6 @@ public class FolderConfig {
 	private static final String META_DIR = "/.meta";
 	private static final String TMP_DIR = "/tmp";
 	private static final String VERSION_DIR = "/.version";
-	private static FolderVersioningConfigurator versioningConfigurator;
 	private static boolean sendDocumentToExtern;
 	private static boolean sendDocumentLinkOnly;
 	
@@ -333,33 +329,4 @@ public class FolderConfig {
 	public static boolean getSendDocumentLinkOnly() {
 		return sendDocumentLinkOnly;
 	}
-	
-	public static FolderVersioningConfigurator getVersioningConfigurator() {
-		return versioningConfigurator;
-	}
-
-	public static void setVersioningConfigurator(FolderVersioningConfigurator versioningConfigurator) {
-		FolderConfig.versioningConfigurator = versioningConfigurator;
-	}
-
-	/**
-	 * @return -1 if the number of revisions for the file is unlimited; 0 if versions are not allowed;
-	 * 	1 - n is the maximum allowed number of revisions
-	 */
-	public static int versionsAllowed(String relPath) {
-		if(versioningConfigurator == null) {
-			return 0;
-		}
-		return versioningConfigurator.versionAllowed(relPath);
-	}
-	
-	/**
-	 * @return true if versioning is enabled for the container
-	 */
-	public static boolean versionsEnabled(VFSContainer container) {
-		if(versioningConfigurator == null) {
-			return false;
-		}
-		return versioningConfigurator.versionEnabled(container);
-	}
 }
diff --git a/src/main/java/org/olat/core/commons/modules/bc/FolderModule.java b/src/main/java/org/olat/core/commons/modules/bc/FolderModule.java
index 5d69dbc670628f3f6400c85eeeb05c56c050b42d..7f63a76277842a06a00bef70f70cab91f577119c 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/FolderModule.java
+++ b/src/main/java/org/olat/core/commons/modules/bc/FolderModule.java
@@ -35,7 +35,6 @@ import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.coordinate.CoordinatorManager;
-import org.olat.core.util.vfs.version.FolderVersioningConfigurator;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
@@ -67,9 +66,6 @@ public class FolderModule extends AbstractSpringModule {
 	@Value("${folder.force.download:true}")
 	private String forceDownload;
 	
-	@Autowired
-	private FolderVersioningConfigurator versioning;
-	
 	@Autowired
 	public FolderModule(CoordinatorManager coordinatorManager) {
 		super(coordinatorManager);
@@ -114,7 +110,6 @@ public class FolderModule extends AbstractSpringModule {
 
 	@Override
 	public void init() {
-		FolderConfig.setVersioningConfigurator(versioning);
 		updateProperties();
 	}
 	
@@ -125,14 +120,6 @@ public class FolderModule extends AbstractSpringModule {
 		}
 	}
 
-	/**
-	 * [used by spring]
-	 * @param versioning
-	 */
-	public void setVersioning(FolderVersioningConfigurator versioning) {
-		this.versioning = versioning;
-	}
-
 	public boolean isForceDownload() {
 		return "true".equals(forceDownload);
 	}
diff --git a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdDeletedFiles.java b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdDeletedFiles.java
index 40427a79e913e75f6274e577f4cd402a5bb00e48..bec2c048bede67c42358436d563853f7e6508f62 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdDeletedFiles.java
+++ b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdDeletedFiles.java
@@ -20,7 +20,7 @@
 package org.olat.core.commons.modules.bc.commands;
 
 import org.olat.core.commons.modules.bc.components.FolderComponent;
-import org.olat.core.commons.modules.bc.version.DeletedFileListController;
+import org.olat.core.commons.services.vfs.ui.version.DeletedFileListController;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.control.Controller;
diff --git a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdMoveCopy.java b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdMoveCopy.java
index 0a76ea7fa15712894a42616e9a0fe0f545822d56..d4d3fa1b41695a0aadf5460a85881fa5d9943e5d 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdMoveCopy.java
+++ b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdMoveCopy.java
@@ -34,6 +34,7 @@ import org.olat.core.commons.modules.bc.FolderEvent;
 import org.olat.core.commons.modules.bc.components.FolderComponent;
 import org.olat.core.commons.services.notifications.NotificationsManager;
 import org.olat.core.commons.services.notifications.SubscriptionContext;
+import org.olat.core.commons.services.vfs.VFSRepositoryService;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.link.Link;
@@ -57,7 +58,6 @@ import org.olat.core.util.vfs.VFSManager;
 import org.olat.core.util.vfs.VFSStatus;
 import org.olat.core.util.vfs.callbacks.VFSSecurityCallback;
 import org.olat.core.util.vfs.filters.VFSItemFilter;
-import org.olat.core.util.vfs.version.Versionable;
 import org.springframework.beans.factory.annotation.Autowired;
 
 public class CmdMoveCopy extends DefaultController implements FolderCommand {
@@ -75,6 +75,8 @@ public class CmdMoveCopy extends DefaultController implements FolderCommand {
 	
 	@Autowired
 	private VFSLockManager vfsLockManager;
+	@Autowired
+	private VFSRepositoryService vfsRepositoryService;
 
 	protected CmdMoveCopy(WindowControl wControl, boolean move) {
 		super(wControl);
@@ -170,10 +172,10 @@ public class CmdMoveCopy extends DefaultController implements FolderCommand {
 		
 		for (VFSItem vfsSource:sources) {
 			VFSItem targetFile = target.resolve(vfsSource.getName());
-			if(vfsSource instanceof VFSLeaf && targetFile != null && targetFile instanceof Versionable
-					&& ((Versionable)targetFile).getVersions().isVersioned()) {
+			if(vfsSource instanceof VFSLeaf && targetFile != null && targetFile.canVersion() == VFSConstants.YES) {
 				//add a new version to the file
-				((Versionable)targetFile).getVersions().addVersion(null, "", ((VFSLeaf)vfsSource).getInputStream());
+				VFSLeaf sourceLeaf = (VFSLeaf)vfsSource;
+				vfsRepositoryService.addVersion(sourceLeaf, ureq.getIdentity(), "", sourceLeaf.getInputStream());
 			} else {
 				vfsStatus = target.copyFrom(vfsSource);
 			}
diff --git a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdUnzip.java b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdUnzip.java
index a1334855f360f927938f0b287e596663fe4de91e..7cdae01ead18df875c1f4ce05b8fa76ea0ab94b9 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdUnzip.java
+++ b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdUnzip.java
@@ -31,7 +31,6 @@ import java.util.Collections;
 import java.util.List;
 
 import org.olat.core.commons.modules.bc.FileSelection;
-import org.olat.core.commons.modules.bc.FolderConfig;
 import org.olat.core.commons.modules.bc.components.FolderComponent;
 import org.olat.core.commons.services.notifications.NotificationsManager;
 import org.olat.core.commons.services.notifications.SubscriptionContext;
@@ -154,8 +153,7 @@ public class CmdUnzip extends BasicController implements FolderCommand {
 			return Collections.emptyList();
 		}
 	
-		boolean versioning = FolderConfig.versionsEnabled(currentContainer);
-		if(!versioning) {
+		if(currentContainer.canVersion() != VFSConstants.YES) {
 			//this command don't overwrite existing folders
 			return Collections.emptyList();
 		}
@@ -182,7 +180,7 @@ public class CmdUnzip extends BasicController implements FolderCommand {
 		// we make a new folder with the same name as the zip file
 		String sZipContainer = name.substring(0, name.length() - 4);
 		
-		boolean versioning = FolderConfig.versionsEnabled(currentContainer);
+		boolean versioning = currentContainer.canVersion() == VFSConstants.YES;
 		
 		VFSContainer zipContainer = currentContainer.createChildContainer(sZipContainer);
 		if (zipContainer == null) {
diff --git a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdViewRevisions.java b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdViewRevisions.java
index bec22c4fe9f3635e622b254091419a4859954e0a..740bdb31f021f0be1e91307f08922071488a04d9 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdViewRevisions.java
+++ b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdViewRevisions.java
@@ -21,7 +21,7 @@ package org.olat.core.commons.modules.bc.commands;
 
 import org.olat.core.commons.modules.bc.components.FolderComponent;
 import org.olat.core.commons.modules.bc.components.ListRenderer;
-import org.olat.core.commons.modules.bc.version.RevisionListController;
+import org.olat.core.commons.services.vfs.ui.version.RevisionListController;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.control.Controller;
@@ -30,10 +30,10 @@ import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.controller.BasicController;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.util.StringHelper;
+import org.olat.core.util.vfs.VFSConstants;
 import org.olat.core.util.vfs.VFSItem;
 import org.olat.core.util.vfs.VFSLockApplicationType;
 import org.olat.core.util.vfs.VFSLockManager;
-import org.olat.core.util.vfs.version.Versionable;
 import org.springframework.beans.factory.annotation.Autowired;
 
 /**
@@ -84,7 +84,7 @@ public class CmdViewRevisions extends BasicController implements FolderCommand {
 		if(status == FolderCommandStatus.STATUS_FAILED) {
 			return null;
 		}
-		if (!(currentItem instanceof Versionable)) {
+		if (currentItem.canVersion() != VFSConstants.YES) {
 			status = FolderCommandStatus.STATUS_FAILED;
 			getWindowControl().setError(translator.translate("failed"));
 			return null;
@@ -93,7 +93,7 @@ public class CmdViewRevisions extends BasicController implements FolderCommand {
 		setTranslator(translator);
 		
 		boolean locked = vfsLockManager.isLockedForMe(currentItem, ureq.getIdentity(), ureq.getUserSession().getRoles(), VFSLockApplicationType.vfs);
-		revisionListCtr = new RevisionListController(ureq, wControl, (Versionable)currentItem, locked);
+		revisionListCtr = new RevisionListController(ureq, wControl, currentItem, locked);
 		listenTo(revisionListCtr);
 		putInitialPanel(revisionListCtr.getInitialComponent());
 		return this;
diff --git a/src/main/java/org/olat/core/commons/modules/bc/components/FolderComponent.java b/src/main/java/org/olat/core/commons/modules/bc/components/FolderComponent.java
index 477fa8eaeddab031b17f40e473b57e09e12a43fe..25619784fcd784900da1627f9374c727048e54f8 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/components/FolderComponent.java
+++ b/src/main/java/org/olat/core/commons/modules/bc/components/FolderComponent.java
@@ -59,7 +59,6 @@ import org.olat.core.util.vfs.VFSLeaf;
 import org.olat.core.util.vfs.filters.VFSItemExcludePrefixFilter;
 import org.olat.core.util.vfs.filters.VFSItemFilter;
 import org.olat.core.util.vfs.filters.VFSSystemItemFilter;
-import org.olat.core.util.vfs.version.Versionable;
 
 /**
  * Initial Date:  Feb 11, 2004
@@ -287,6 +286,8 @@ public class FolderComponent extends AbstractComponent {
 			comparator = new Comparator<VFSItem>() {
 				@Override
 				public int compare(VFSItem o1, VFSItem o2) {
+					return o1.getName().compareTo(o2.getName());
+					/*
 					Versionable v1 = null;
 					Versionable v2 = null;
 					if (o1 instanceof Versionable) {
@@ -309,6 +310,7 @@ public class FolderComponent extends AbstractComponent {
 						return 1;
 					}
 					return (sortAsc) ? collator.compare(r1, r2) : collator.compare(r2, r1);
+					*/
 				}
 			};
 		}  else if (col.equals(SORT_LOCK)) {																							// sort after modification date (if same, then name)
diff --git a/src/main/java/org/olat/core/commons/modules/bc/components/FolderComponentRenderer.java b/src/main/java/org/olat/core/commons/modules/bc/components/FolderComponentRenderer.java
index c701737ce8def2f52090fe78255ebef3ed153646..bd0a601f5e5baa20a7118b3ce9eaa44a2e9d5100 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/components/FolderComponentRenderer.java
+++ b/src/main/java/org/olat/core/commons/modules/bc/components/FolderComponentRenderer.java
@@ -28,7 +28,6 @@ package org.olat.core.commons.modules.bc.components;
 
 import java.util.List;
 
-import org.olat.core.commons.modules.bc.FolderConfig;
 import org.olat.core.commons.modules.bc.FolderRunController;
 import org.olat.core.commons.modules.bc.commands.FolderCommandFactory;
 import org.olat.core.gui.components.Component;
@@ -95,7 +94,7 @@ public class FolderComponentRenderer extends DefaultComponentRenderer {
 		}
 		
 		boolean canDelete = false;
-		boolean canVersion = FolderConfig.versionsEnabled(fc.getCurrentContainer());
+		boolean canVersion = fc.getCurrentContainer().canVersion() == VFSConstants.YES;
 		boolean canMail = fc.isCanMail();
 		
 		List<VFSItem> children = fc.getCurrentContainerChildren();
diff --git a/src/main/java/org/olat/core/commons/modules/bc/components/ListRenderer.java b/src/main/java/org/olat/core/commons/modules/bc/components/ListRenderer.java
index 8e67aaede13707a04e85259dd23881de2d78b929..5b9fa671b8dc0caeff90b8c1b0230d65615bba49 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/components/ListRenderer.java
+++ b/src/main/java/org/olat/core/commons/modules/bc/components/ListRenderer.java
@@ -35,7 +35,6 @@ import java.util.stream.Collectors;
 
 import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.modules.bc.FileSelection;
-import org.olat.core.commons.modules.bc.FolderConfig;
 import org.olat.core.commons.modules.bc.FolderLicenseHandler;
 import org.olat.core.commons.modules.bc.FolderManager;
 import org.olat.core.commons.services.license.License;
@@ -45,6 +44,7 @@ import org.olat.core.commons.services.license.ui.LicenseRenderer;
 import org.olat.core.commons.services.vfs.VFSLeafEditor;
 import org.olat.core.commons.services.vfs.VFSMetadata;
 import org.olat.core.commons.services.vfs.VFSRepositoryService;
+import org.olat.core.commons.services.vfs.VFSRevision;
 import org.olat.core.gui.components.form.flexible.impl.NameValuePair;
 import org.olat.core.gui.control.winmgr.AJAXFlags;
 import org.olat.core.gui.render.StringOutput;
@@ -66,8 +66,6 @@ import org.olat.core.util.vfs.VFSLockManager;
 import org.olat.core.util.vfs.VirtualContainer;
 import org.olat.core.util.vfs.filters.VFSSystemItemFilter;
 import org.olat.core.util.vfs.lock.LockInfo;
-import org.olat.core.util.vfs.version.Versionable;
-import org.olat.core.util.vfs.version.Versions;
 import org.olat.user.UserManager;
 
 /**
@@ -142,7 +140,7 @@ public class ListRenderer {
 		}
 
 		VFSContainer currentContainer = fc.getCurrentContainer();
-		boolean canVersion = FolderConfig.versionsEnabled(currentContainer);
+		boolean canVersion = currentContainer.canVersion() == VFSConstants.YES;
 		String sortOrder = fc.getCurrentSortOrder();
 		boolean sortAsc = fc.isCurrentSortAsc();
 		String sortCss = (sortAsc ? "o_orderby_asc" : "o_orderby_desc");
@@ -222,15 +220,11 @@ public class ListRenderer {
 		canWrite = canWrite && !(fc.getCurrentContainer() instanceof VirtualContainer);
 		boolean isAbstract = (child instanceof AbstractVirtualContainer);
 
-		Versions versions = null;
-		if(canContainerVersion && child instanceof Versionable) {
-			Versionable versionable = (Versionable)child;
-			Versions possibleVersions = versionable.getVersions();
-			if(possibleVersions.isVersioned()) {
-				versions = possibleVersions;
-			}
+		List<VFSRevision> revisions = null;
+		if(canContainerVersion && child.canVersion() == VFSConstants.YES) {
+			revisions = vfsRepositoryService.getRevisions(metadata);
 		}
-		boolean canVersion = versions != null && !versions.getRevisions().isEmpty();
+		boolean canVersion = revisions != null && !revisions.isEmpty();
 
 		VFSLeaf leaf = null;
 		if (child instanceof VFSLeaf) {
@@ -410,9 +404,9 @@ public class ListRenderer {
 		}
 
 		if(canContainerVersion) {
-			if (canVersion && versions != null) {
+			if (canVersion && revisions != null) {
 				sb.append("<span class='text-muted small'>")
-				  .append(versions.getRevisionNr())
+				  .append(metadata.getRevisionNr())
 				  .append("</span>");					
 			}
 			sb.append("</td><td>");
diff --git a/src/main/java/org/olat/core/commons/modules/bc/version/DeletedFileListController.java b/src/main/java/org/olat/core/commons/modules/bc/version/DeletedFileListController.java
deleted file mode 100644
index dd67832da5f51ccd4c95a634a7c310e67d335146..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/core/commons/modules/bc/version/DeletedFileListController.java
+++ /dev/null
@@ -1,339 +0,0 @@
-/**
- * <a href="http://www.openolat.org">
- * OpenOLAT - Online Learning and Training</a><br>
- * <p>
- * Licensed under the Apache License, Version 2.0 (the "License"); <br>
- * you may not use this file except in compliance with the License.<br>
- * You may obtain a copy of the License at the
- * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
- * <p>
- * Unless required by applicable law or agreed to in writing,<br>
- * software distributed under the License is distributed on an "AS IS" BASIS, <br>
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
- * See the License for the specific language governing permissions and <br>
- * limitations under the License.
- * <p>
- * Initial code contributed and copyrighted by<br>
- * frentix GmbH, http://www.frentix.com
- * <p>
- */
-package org.olat.core.commons.modules.bc.version;
-
-import java.text.DateFormat;
-import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.Calendar;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-
-import org.olat.basesecurity.BaseSecurityModule;
-import org.olat.core.commons.modules.bc.commands.FolderCommand;
-import org.olat.core.commons.modules.bc.commands.FolderCommandStatus;
-import org.olat.core.gui.UserRequest;
-import org.olat.core.gui.components.Component;
-import org.olat.core.gui.components.table.BaseTableDataModelWithoutFilter;
-import org.olat.core.gui.components.table.DefaultColumnDescriptor;
-import org.olat.core.gui.components.table.StaticColumnDescriptor;
-import org.olat.core.gui.components.table.TableController;
-import org.olat.core.gui.components.table.TableDataModel;
-import org.olat.core.gui.components.table.TableEvent;
-import org.olat.core.gui.components.table.TableGuiConfiguration;
-import org.olat.core.gui.components.table.TableMultiSelectEvent;
-import org.olat.core.gui.components.velocity.VelocityContainer;
-import org.olat.core.gui.control.Controller;
-import org.olat.core.gui.control.Event;
-import org.olat.core.gui.control.WindowControl;
-import org.olat.core.gui.control.controller.BasicController;
-import org.olat.core.gui.control.generic.modal.DialogBoxController;
-import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory;
-import org.olat.core.gui.media.MediaResource;
-import org.olat.core.util.StringHelper;
-import org.olat.core.util.vfs.VFSContainer;
-import org.olat.core.util.vfs.VFSManager;
-import org.olat.core.util.vfs.VFSRevisionMediaResource;
-import org.olat.core.util.vfs.callbacks.VFSSecurityCallback;
-import org.olat.core.util.vfs.version.VFSRevision;
-import org.olat.core.util.vfs.version.Versions;
-import org.olat.core.util.vfs.version.VersionsManager;
-import org.olat.user.UserManager;
-import org.springframework.beans.factory.annotation.Autowired;
-
-/**
- * 
- * Description:<br>
- * This controller shows the list of deleted files in a container.<br>
- * Events:
- * <ul>
- * <li>FOLDERCOMMAND_FINISHED</li>
- * </ul>
- * <P>
- * Initial Date: 15 sept. 2009 <br>
- * 
- * @author srosse
- */
-public class DeletedFileListController extends BasicController {
-
-	private static final String CMD_DOWNLOAD = "download";
-	private static final String CMD_RESTORE = "restore";
-	private static final String CMD_DELETE = "delete";
-	private static final String CMD_CANCEL = "cancel";
-
-	private int status = FolderCommandStatus.STATUS_SUCCESS;
-
-	private final VFSContainer container;
-	private final List<Versions> deletedFiles;
-
-	private VelocityContainer mainVC;
-	private TableController deletedFilesListTableCtr;
-	private DialogBoxController dialogCtr;
-
-	private boolean isAdmin;
-	
-	@Autowired
-	private UserManager userManager;
-	@Autowired
-	private VersionsManager versionsManager;
-	@Autowired
-	private BaseSecurityModule securityModule;
-	
-	public DeletedFileListController(UserRequest ureq, WindowControl wControl, VFSContainer container) {
-		super(ureq, wControl);
-		this.container = container;
-		deletedFiles = versionsManager.getDeletedFiles(container);
-		
-		isAdmin = securityModule.isUserAllowedAdminProps(ureq.getUserSession().getRoles());
-
-		TableGuiConfiguration summaryTableConfig = new TableGuiConfiguration();
-		summaryTableConfig.setDownloadOffered(false);
-		summaryTableConfig.setTableEmptyMessage(getTranslator().translate("version.noDeletedFiles"));
-
-		deletedFilesListTableCtr = new TableController(summaryTableConfig, ureq, getWindowControl(), getTranslator());
-
-		deletedFilesListTableCtr.addColumnDescriptor(new DefaultColumnDescriptor("version.name", 0, null, ureq.getLocale()));
-		deletedFilesListTableCtr.addColumnDescriptor(new DefaultColumnDescriptor("version.author", 1, null, ureq.getLocale()));
-		deletedFilesListTableCtr.addColumnDescriptor(new DefaultColumnDescriptor("version.deletedBy", 2, null, ureq.getLocale()));
-		deletedFilesListTableCtr.addColumnDescriptor(new DefaultColumnDescriptor("version.date", 3, null, ureq.getLocale()));
-		deletedFilesListTableCtr.addColumnDescriptor(new StaticColumnDescriptor(CMD_DOWNLOAD, "version.download", getTranslator().translate(
-				"version.download")));
-
-		VFSSecurityCallback secCallback = VFSManager.findInheritedSecurityCallback(container);
-		if (secCallback != null) {
-			if (secCallback.canDeleteRevisionsPermanently()) {
-				deletedFilesListTableCtr.addMultiSelectAction("delete", CMD_DELETE);
-			}
-			if (secCallback.canWrite()) {
-				deletedFilesListTableCtr.addMultiSelectAction("version.restore", CMD_RESTORE);
-			}
-		}
-
-		deletedFilesListTableCtr.addMultiSelectAction("cancel", CMD_CANCEL);
-		deletedFilesListTableCtr.setMultiSelect(true);
-		loadModel(ureq);
-		listenTo(deletedFilesListTableCtr);
-
-		mainVC = createVelocityContainer("deleted_files");
-		mainVC.put("deletedFileList", deletedFilesListTableCtr.getInitialComponent());
-		putInitialPanel(mainVC);
-	}
-	
-	private void loadModel(UserRequest ureq) {
-		Collection<String> names = new HashSet<>();
-		for(Versions deletedFile:deletedFiles) {
-			if(deletedFile.getCreator() != null && !"-".equals(deletedFile.getCreator())) {
-				names.add(deletedFile.getCreator());
-			}
-			VFSRevision lastRevision = getLastRevision(deletedFile);
-			if(lastRevision != null && lastRevision.getAuthor() != null && !"-".equals(lastRevision.getAuthor())) {
-				names.add(lastRevision.getAuthor());
-			}
-		}
-		
-		Map<String, String> mappedFullnames = userManager.getUserDisplayNamesByUserName(names);
-		DeletedFileListDataModel model = new DeletedFileListDataModel(deletedFiles, mappedFullnames, ureq.getLocale());
-		deletedFilesListTableCtr.setTableDataModel(model);
-	}
-
-	@Override
-	protected void doDispose() {
-	//
-	}
-
-	public int getStatus() {
-		return status;
-	}
-
-	@Override
-	protected void event(UserRequest ureq, Component source, Event event) {
-	// nothing to track
-	}
-
-	@Override
-	protected void event(UserRequest ureq, Controller source, Event event) {
-		if (source == deletedFilesListTableCtr) {
-			if (event instanceof TableEvent) {
-				TableEvent tEvent = (TableEvent) event;
-				int row = tEvent.getRowId();
-				if (CMD_DOWNLOAD.equals(tEvent.getActionId())) {
-					VFSRevision version = getLastRevision(deletedFiles.get(row));
-					MediaResource resource = new VFSRevisionMediaResource(version, true);
-					ureq.getDispatchResult().setResultingMediaResource(resource);
-				} else if (CMD_RESTORE.equals(tEvent.getActionId())) {
-					VFSRevision version = getLastRevision(deletedFiles.get(row));
-					if (versionsManager.restore(container, version)) {
-						status = FolderCommandStatus.STATUS_SUCCESS;
-						fireEvent(ureq, FolderCommand.FOLDERCOMMAND_FINISHED);
-					} else {
-						status = FolderCommandStatus.STATUS_FAILED;
-						// ERROR
-					}
-				}
-			} else if (event instanceof TableMultiSelectEvent) {
-				TableMultiSelectEvent tEvent = (TableMultiSelectEvent) event;
-				if (CMD_CANCEL.equals(tEvent.getAction())) {
-					status = FolderCommandStatus.STATUS_CANCELED;
-					fireEvent(ureq, FolderCommand.FOLDERCOMMAND_FINISHED);
-				} else if (CMD_RESTORE.equals(tEvent.getAction())) {
-					List<VFSRevision> selectedRevisions = getSelectedRevisions(tEvent.getSelection());
-					boolean allOk = true;
-					for (VFSRevision revision : selectedRevisions) {
-						allOk &= versionsManager.restore(container, revision);
-					}
-					if (allOk) {
-						status = FolderCommandStatus.STATUS_SUCCESS;
-						fireEvent(ureq, FolderCommand.FOLDERCOMMAND_FINISHED);
-					} else {
-						status = FolderCommandStatus.STATUS_FAILED;
-					}
-				} else if (CMD_DELETE.equals(tEvent.getAction())) {
-					List<Versions> versionsToDelete = getSelectedVersions(tEvent.getSelection());
-					if (!versionsToDelete.isEmpty()) {
-						
-						String msg = translate("version.del.confirm") + "<p>" + renderVersionsAsHtml(versionsToDelete) + "</p>";
-						// create dialog controller
-						dialogCtr = activateYesNoDialog(ureq, translate("version.del.header"), msg, dialogCtr);
-						dialogCtr.setUserObject(versionsToDelete);
-					}
-				}
-			}
-		} else if (source == dialogCtr) {
-			if (DialogBoxUIFactory.isYesEvent(event)) {	
-				@SuppressWarnings("unchecked")
-				List<Versions> versionsToDelete =  (List<Versions>)dialogCtr.getUserObject();
-				versionsManager.deleteVersions(container, versionsToDelete);
-				status = FolderCommandStatus.STATUS_SUCCESS;
-				fireEvent(ureq, FolderCommand.FOLDERCOMMAND_FINISHED);
-			}
-		}
-	}
-	
-	private String renderVersionsAsHtml(List<Versions> versions) {
-		StringBuilder sb = new StringBuilder();
-		sb.append("<ul>");
-		for (Versions version:versions) {
-			VFSRevision lastRevision = getLastRevision(version);
-			if (lastRevision != null) {
-				sb.append("<li>")
-					.append(lastRevision.getName())
-					.append("</li>");
-			}
-		}
-		sb.append("</ul>");
-		return sb.toString();
-	}
-	
-	protected List<Versions> getSelectedVersions(BitSet objectMarkers) {
-		List<Versions> results = new ArrayList<>();
-		for (int i = objectMarkers.nextSetBit(0); i >= 0; i = objectMarkers.nextSetBit(i + 1)) {
-			if (i >= 0 && i < deletedFiles.size()) {
-				results.add(deletedFiles.get(i));
-			}
-		}
-		return results;
-	}
-
-	protected List<VFSRevision> getSelectedRevisions(BitSet objectMarkers) {
-		List<VFSRevision> results = new ArrayList<>();
-		for (int i = objectMarkers.nextSetBit(0); i >= 0; i = objectMarkers.nextSetBit(i + 1)) {
-			if (i >= 0 && i < deletedFiles.size()) {
-				VFSRevision elem = getLastRevision(deletedFiles.get(i));
-				if (elem != null) {
-					results.add(elem);
-				}
-			}
-		}
-		return results;
-	}
-
-	protected VFSRevision getLastRevision(Versions versions) {
-		VFSRevision lastRevision = null;
-		if (!versions.getRevisions().isEmpty()) {
-			lastRevision = versions.getRevisions().get(versions.getRevisions().size() - 1);
-		}
-		return lastRevision;
-	}
-
-	public class DeletedFileListDataModel extends BaseTableDataModelWithoutFilter<Versions> implements TableDataModel<Versions> {
-		private final DateFormat format;
-		private final List<Versions> versionList;
-		private final Calendar cal = Calendar.getInstance();
-		private final Map<String, String> mappedFullnames;
-
-		public DeletedFileListDataModel(List<Versions> versionList, Map<String, String> mappedFullnames, Locale locale) {
-			this.versionList = versionList;
-			this.mappedFullnames = mappedFullnames;
-			format = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, locale);
-		}
-
-		public int getColumnCount() {
-			return 4;
-		}
-
-		public int getRowCount() {
-			return versionList.size();
-		}
-
-		public Object getValueAt(int row, int col) {
-			Versions versioned = versionList.get(row);
-			switch (col) {
-				case 0: {
-					VFSRevision lastRevision = getLastRevision(versioned);
-					return lastRevision == null ? null : lastRevision.getName();
-				}
-				case 1:
-					return getFullName(versioned.getCreator());
-				case 2: {
-					VFSRevision lastRevision = getLastRevision(versioned);
-					return lastRevision == null ? null : getFullName(lastRevision.getAuthor());
-				}
-				case 3: {
-					VFSRevision lastRevision = getLastRevision(versioned);
-					if (lastRevision == null) return null;
-					cal.setTimeInMillis(lastRevision.getLastModified());
-					return format.format(cal.getTime());
-				}
-				default:
-					return "";
-			}
-		}
-		
-		private String getFullName(String name) {
-			if(!StringHelper.containsNonWhitespace(name)) {
-				return null;
-			}
-			String fullName = mappedFullnames.get(name);
-			if(fullName == null) {
-				return null;
-			}
-			
-			StringBuilder sb = new StringBuilder();
-			sb.append(fullName);
-			if(isAdmin) {
-				sb.append(" (").append(name).append(")");
-			}
-			return sb.toString();
-		}
-	}
-}
diff --git a/src/main/java/org/olat/core/commons/modules/bc/version/RevisionListController.java b/src/main/java/org/olat/core/commons/modules/bc/version/RevisionListController.java
deleted file mode 100644
index aca68052e2cd7f1d8c1666d2d0220f8482b72bf6..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/core/commons/modules/bc/version/RevisionListController.java
+++ /dev/null
@@ -1,407 +0,0 @@
-/**
- * <a href="http://www.openolat.org">
- * OpenOLAT - Online Learning and Training</a><br>
- * <p>
- * Licensed under the Apache License, Version 2.0 (the "License"); <br>
- * you may not use this file except in compliance with the License.<br>
- * You may obtain a copy of the License at the
- * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
- * <p>
- * Unless required by applicable law or agreed to in writing,<br>
- * software distributed under the License is distributed on an "AS IS" BASIS, <br>
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
- * See the License for the specific language governing permissions and <br>
- * limitations under the License.
- * <p>
- * Initial code contributed and copyrighted by<br>
- * frentix GmbH, http://www.frentix.com
- * <p>
- */
-package org.olat.core.commons.modules.bc.version;
-
-import java.io.InputStream;
-import java.text.DateFormat;
-import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.Calendar;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-
-import org.olat.basesecurity.BaseSecurity;
-import org.olat.basesecurity.BaseSecurityModule;
-import org.olat.basesecurity.IdentityShort;
-import org.olat.core.commons.modules.bc.commands.FolderCommand;
-import org.olat.core.commons.modules.bc.commands.FolderCommandStatus;
-import org.olat.core.gui.UserRequest;
-import org.olat.core.gui.components.Component;
-import org.olat.core.gui.components.table.BaseTableDataModelWithoutFilter;
-import org.olat.core.gui.components.table.DefaultColumnDescriptor;
-import org.olat.core.gui.components.table.StaticColumnDescriptor;
-import org.olat.core.gui.components.table.TableController;
-import org.olat.core.gui.components.table.TableDataModel;
-import org.olat.core.gui.components.table.TableEvent;
-import org.olat.core.gui.components.table.TableGuiConfiguration;
-import org.olat.core.gui.components.table.TableMultiSelectEvent;
-import org.olat.core.gui.components.velocity.VelocityContainer;
-import org.olat.core.gui.control.Controller;
-import org.olat.core.gui.control.Event;
-import org.olat.core.gui.control.WindowControl;
-import org.olat.core.gui.control.controller.BasicController;
-import org.olat.core.gui.control.generic.modal.DialogBoxController;
-import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory;
-import org.olat.core.gui.media.MediaResource;
-import org.olat.core.util.StringHelper;
-import org.olat.core.util.vfs.VFSLeaf;
-import org.olat.core.util.vfs.VFSMediaResource;
-import org.olat.core.util.vfs.VFSRevisionMediaResource;
-import org.olat.core.util.vfs.version.VFSRevision;
-import org.olat.core.util.vfs.version.Versionable;
-import org.olat.core.util.vfs.version.Versions;
-import org.olat.user.UserManager;
-import org.springframework.beans.factory.annotation.Autowired;
-
-/**
- * 
- * Description:<br>
- * This controller shows the list of revisions from a versioned file.<br>
- * Events:
- * <ul>
- * <li>FOLDERCOMMAND_FINISHED</li>
- * </ul>
- * <P>
- * Initial Date: 15 sept. 2009 <br>
- * 
- * @author srosse
- */
-public class RevisionListController extends BasicController {
-
-	private static final String CMD_DOWNLOAD = "download";
-	private static final String CMD_RESTORE = "restore";
-	private static final String CMD_DELETE = "delete";
-	private static final String CMD_CANCEL = "cancel";
-
-	private int status = FolderCommandStatus.STATUS_SUCCESS;
-
-	private final Versionable versionedFile;
-	private TableController revisionListTableCtr;
-	private DialogBoxController confirmDeleteBoxCtr;
-	private final VelocityContainer mainVC;
-	private final boolean isAdmin;
-	
-	@Autowired
-	private UserManager userManager;
-	@Autowired
-	private BaseSecurity securityManager;
-	@Autowired
-	private BaseSecurityModule securityModule;
-
-	public RevisionListController(UserRequest ureq, WindowControl wControl, Versionable versionedFile, boolean readOnly) {
-		this(ureq, wControl, versionedFile, null, null, readOnly);
-	}
-
-	public RevisionListController(UserRequest ureq, WindowControl wControl, Versionable versionedFile,
-			String title, String description, boolean readOnly) {
-		super(ureq, wControl);
-		isAdmin = securityModule.isUserAllowedAdminProps(ureq.getUserSession().getRoles());
-		
-		//reload the file with all possible precautions
-		VFSLeaf versionedLeaf = null;
-		if(versionedFile instanceof VFSLeaf) {
-			versionedLeaf = (VFSLeaf)versionedFile;
-		}
-		if(versionedLeaf != null && versionedLeaf.getParentContainer() != null) {
-			//reload the file
-			versionedLeaf = (VFSLeaf)versionedLeaf.getParentContainer().resolve(((VFSLeaf) versionedFile).getName());
-			if(versionedLeaf instanceof Versionable) {
-				versionedFile = (Versionable)versionedLeaf;
-			}
-		}
-		this.versionedFile = versionedFile;
-
-		TableGuiConfiguration summaryTableConfig = new TableGuiConfiguration();
-		summaryTableConfig.setDownloadOffered(true);
-		summaryTableConfig.setTableEmptyMessage(getTranslator().translate("version.noRevisions"));
-
-		revisionListTableCtr = new TableController(summaryTableConfig, ureq, getWindowControl(), getTranslator());
-		revisionListTableCtr.addColumnDescriptor(new DefaultColumnDescriptor("version.nr", 0, null, ureq.getLocale()) {
-			@Override
-			public int compareTo(int rowa, int rowb) {
-				Object a = table.getTableDataModel().getValueAt(rowa, dataColumn);
-				Object b = table.getTableDataModel().getValueAt(rowb, dataColumn);
-				if (a == null || b == null) {
-					boolean bb = (b == null);
-					return (a == null) ? (bb ? 0: -1) : (bb ? 1: 0);
-				}
-				try {
-					Long la = new Long((String)a);
-					Long lb = new Long((String)b);
-					return la.compareTo(lb);
-				} catch (NumberFormatException e) {
-					return super.compareTo(rowa, rowb);
-				}
-			}
-		});
-		revisionListTableCtr.addColumnDescriptor(new DefaultColumnDescriptor("version.author", 1, null, ureq.getLocale()));
-		revisionListTableCtr.addColumnDescriptor(new DefaultColumnDescriptor("version.comment", 2, null, ureq.getLocale()));
-		revisionListTableCtr.addColumnDescriptor(new DefaultColumnDescriptor("version.date", 3, null, ureq.getLocale()));
-		revisionListTableCtr.addColumnDescriptor(new StaticColumnDescriptor(CMD_DOWNLOAD, "version.download", getTranslator().translate(
-				"version.download")));
-		//read only cannot restore / delete
-		if(!readOnly) {
-			revisionListTableCtr.addColumnDescriptor(new StaticColumnDescriptor(CMD_RESTORE, "version.restore", getTranslator().translate(
-					"version.restore")));
-			revisionListTableCtr.addMultiSelectAction("delete", CMD_DELETE);
-		}
-		
-		revisionListTableCtr.addMultiSelectAction("cancel", CMD_CANCEL);
-		revisionListTableCtr.setMultiSelect(true);
-		loadModel(versionedLeaf);
-		listenTo(revisionListTableCtr);
-
-		mainVC = createVelocityContainer("revisions");
-		mainVC.put("revisionList", revisionListTableCtr.getInitialComponent());
-
-		if (StringHelper.containsNonWhitespace(title)) {
-			mainVC.contextPut("title", title);
-		}
-		if (StringHelper.containsNonWhitespace(description)) {
-			mainVC.contextPut("description", description);
-		}
-
-		putInitialPanel(mainVC);
-	}
-	
-	private void loadModel(VFSLeaf versionedLeaf) {
-		Versions versions = versionedFile.getVersions();
-		List<VFSRevision> revisions = new ArrayList<>(versions.getRevisions());
-		revisions.add(new CurrentRevision(versionedLeaf, versions));
-		
-		Collection<String> names = new HashSet<>();
-		for(VFSRevision revision:revisions) {
-			if(revision.getAuthor() != null) {
-				names.add(revision.getAuthor());
-			}
-		}
-		
-		Map<String, IdentityShort> mappedIdentities = new HashMap<>();
-		for(IdentityShort identity :securityManager.findShortIdentitiesByName(names)) {
-			mappedIdentities.put(identity.getName(), identity);
-		}
-
-		revisionListTableCtr.setTableDataModel(new RevisionListDataModel(revisions, mappedIdentities, getLocale()));
-	}
-
-	@Override
-	protected void doDispose() {
-	// disposed by BasicController
-	}
-
-	public int getStatus() {
-		return status;
-	}
-
-	@Override
-	protected void event(UserRequest ureq, Component source, Event event) {
-	// nothing to track
-	}
-
-	@Override
-	protected void event(UserRequest ureq, Controller source, Event event) {
-		if (source == revisionListTableCtr) {
-			if (event instanceof TableEvent) {
-				TableEvent tEvent = (TableEvent) event;
-				int row = tEvent.getRowId();
-				if (CMD_DOWNLOAD.equals(tEvent.getActionId())) {
-					
-					MediaResource resource;
-					if(row < versionedFile.getVersions().getRevisions().size()) {
-						//restore current, do nothing
-						VFSRevision version = versionedFile.getVersions().getRevisions().get(row);
-						resource = new VFSRevisionMediaResource(version, true);
-					} else {
-						resource = new VFSMediaResource((VFSLeaf)versionedFile);
-						((VFSMediaResource)resource).setDownloadable(true);
-					}
-					ureq.getDispatchResult().setResultingMediaResource(resource);
-				} else if (CMD_RESTORE.equals(tEvent.getActionId())) {
-					if(row >= versionedFile.getVersions().getRevisions().size()) {
-						//restore current, do nothing
-						status = FolderCommandStatus.STATUS_SUCCESS;
-						fireEvent(ureq, FolderCommand.FOLDERCOMMAND_FINISHED);
-					} else {
-						VFSRevision version = versionedFile.getVersions().getRevisions().get(row);
-						String comment = translate("version.restore.comment", new String[]{version.getRevisionNr()});
-						if (versionedFile.getVersions().restore(ureq.getIdentity(), version, comment)) {
-							status = FolderCommandStatus.STATUS_SUCCESS;
-							fireEvent(ureq, FolderCommand.FOLDERCOMMAND_FINISHED);
-						} else {
-							status = FolderCommandStatus.STATUS_FAILED;
-							showError("version.restore.failed");
-							fireEvent(ureq, FolderCommand.FOLDERCOMMAND_FINISHED);
-						}
-					}
-				}
-			} else if (event instanceof TableMultiSelectEvent) {
-				TableMultiSelectEvent tEvent = (TableMultiSelectEvent) event;
-				if (CMD_CANCEL.equals(tEvent.getAction())) {
-					status = FolderCommandStatus.STATUS_CANCELED;
-					fireEvent(ureq, FolderCommand.FOLDERCOMMAND_FINISHED);
-				} else {
-					List<VFSRevision> selectedVersions = getSelectedRevisions(tEvent.getSelection());
-					if (!selectedVersions.isEmpty()) {
-						if (CMD_DELETE.equals(tEvent.getAction())) {
-							String numOfVersionToDelete = Integer.toString(selectedVersions.size());
-							confirmDeleteBoxCtr = activateYesNoDialog(ureq, null, translate("version.confirmDelete",
-									new String[] { numOfVersionToDelete }), confirmDeleteBoxCtr);
-							confirmDeleteBoxCtr.setUserObject(selectedVersions);
-						}
-					}
-				}
-			}
-		} else if (source == confirmDeleteBoxCtr) {
-			if (DialogBoxUIFactory.isYesEvent(event)) {
-				@SuppressWarnings("unchecked")
-				List<VFSRevision> selectedVersions = (List<VFSRevision>) confirmDeleteBoxCtr.getUserObject();
-				versionedFile.getVersions().delete(ureq.getIdentity(), selectedVersions);
-				status = FolderCommandStatus.STATUS_SUCCESS;
-			} else {
-				status = FolderCommandStatus.STATUS_CANCELED;
-			}
-			fireEvent(ureq, FolderCommand.FOLDERCOMMAND_FINISHED);
-		}
-	}
-
-	private List<VFSRevision> getSelectedRevisions(BitSet objectMarkers) {
-		List<VFSRevision> allVersions = versionedFile.getVersions().getRevisions();
-
-		List<VFSRevision> results = new ArrayList<>();
-		for (int i = objectMarkers.nextSetBit(0); i >= 0; i = objectMarkers.nextSetBit(i + 1)) {
-			if (i >= 0 && i < allVersions.size()) {
-				VFSRevision elem = allVersions.get(i);
-				results.add(elem);
-			}
-		}
-
-		return results;
-	}
-
-	public class RevisionListDataModel extends BaseTableDataModelWithoutFilter<VFSRevision> implements TableDataModel<VFSRevision> {
-		private final DateFormat format;
-		private final List<VFSRevision> versionList;
-		private final Calendar cal = Calendar.getInstance();
-		private final Map<String, IdentityShort> mappedIdentities;
-
-		public RevisionListDataModel(List<VFSRevision> versionList, Map<String, IdentityShort> mappedIdentities, Locale locale) {
-			this.versionList = versionList;
-			this.mappedIdentities = mappedIdentities;
-			format = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, locale);
-		}
-
-		@Override
-		public int getColumnCount() {
-			return 4;
-		}
-
-		@Override
-		public int getRowCount() {
-			return versionList.size();
-		}
-
-		@Override
-		public Object getValueAt(int row, int col) {
-			VFSRevision version = versionList.get(row);
-			switch (col) {
-				case 0:
-					return version.getRevisionNr();
-				case 1:
-					return getFullName(version.getAuthor());
-				case 2: {
-					String comment =  version.getComment();
-					if (StringHelper.containsNonWhitespace(comment)) {
-						return comment;
-					} else if ("1".equals(version.getRevisionNr())) {
-						return translate("version.initialRevision");
-					}
-					return "";
-				}
-				case 3:
-					cal.setTimeInMillis(version.getLastModified());
-					return format.format(cal.getTime());
-				default:
-					return "";
-			}
-		}
-		
-		private String getFullName(String name) {
-			if(!StringHelper.containsNonWhitespace(name)) {
-				return null;
-			}
-			IdentityShort id = mappedIdentities.get(name);
-			if(id == null) {
-				return null;
-			}
-			
-			StringBuilder sb = new StringBuilder();
-			sb.append(userManager.getUserDisplayName(id));
-			if(isAdmin) {
-				sb.append(" (").append(name).append(")");
-			}
-			return sb.toString();
-		}
-	}
-	
-	public class CurrentRevision implements VFSRevision {
-		private final VFSLeaf versionFile;
-		private final Versions versions;
-		
-		public CurrentRevision(VFSLeaf versionFile, Versions versions) {
-			this.versionFile = versionFile;
-			this.versions = versions;
-		}
-
-		@Override
-		public String getAuthor() {
-			return versions.getAuthor();
-		}
-
-		@Override
-		public String getComment() {
-			String comment = versions.getComment();
-			if (StringHelper.containsNonWhitespace(comment)) {
-				return comment;
-			} else if ("1".equals(versions.getRevisionNr())) {
-				return translate("version.initialRevision");
-			}
-			return "";
-		}
-
-		@Override
-		public InputStream getInputStream() {
-			return versionFile.getInputStream();
-		}
-
-		@Override
-		public long getLastModified() {
-			return versionFile.getLastModified();
-		}
-
-		@Override
-		public String getName() {
-			return versionFile.getName();
-		}
-
-		@Override
-		public String getRevisionNr() {
-			return versions.getRevisionNr();
-		}
-
-		@Override
-		public long getSize() {
-			return versionFile.getSize();
-		}
-	}
-}
\ No newline at end of file
diff --git a/src/main/java/org/olat/core/commons/modules/bc/version/_content/deleted_files.html b/src/main/java/org/olat/core/commons/modules/bc/version/_content/deleted_files.html
deleted file mode 100644
index bd3427a4b59ce5aeba63d79167e4ad1431506500..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/core/commons/modules/bc/version/_content/deleted_files.html
+++ /dev/null
@@ -1 +0,0 @@
-$r.render("deletedFileList")
\ No newline at end of file
diff --git a/src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_de.properties
deleted file mode 100644
index 47fe5f593a8e7b51d4db733e5ef1ad26a8baeb76..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_de.properties
+++ /dev/null
@@ -1,25 +0,0 @@
-version.author=Autor
-version.comment=Kommentar
-version.date=Datum
-version.deletedBy=Gel\u00F6scht von
-version.deletedFiles=Gel\u00F6schte Dateien
-version.download=Herunterladen
-version.name=Datei
-version.noDeletedFiles=Es gibt keine gel\u00F6schten Dateien unter der Dokument-Kontrolle.
-version.noRevisions=Es gibt noch keine Revision dieser Datei.
-version.nr=Revision
-version.initialRevision=Initiale Version
-version.restore=Wiederherstellen
-version.confirmDelete=Wollen Sie wirklich {0} Revision(en) l\u00F6schen?
-version.comment=Kommentar
-version.comment.title=Kommentar
-version.comment.alltitle=Kommentar / Sperre
-version.comment.description=Dieses Dokument steht unter Dokument-Kontrolle. Bitte kommentieren Sie die gemachten \u00c4nderungen.
-version.del.confirm=Wollen Sie folgende Dateien wirklich endg\u00FCltig l\u00F6schen?
-version.del.header=L\u00F6schen best\u00E4tigen
-version.restore.failed=Datei konnte nicht wiederhergestellt werden.
-version.restore.comment=Version {0} wiederhergestellt
-meta.comment.title=Sperre
-meta.locked=Dateisperre
-meta.retainlock=Die Datei f\u00FCr andere Benutzer gesperrt lassen
-meta.unlock=Die Datei f\u00FCr andere Benutzer frei geben
\ No newline at end of file
diff --git a/src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_en.properties
deleted file mode 100644
index 51521130c650860e13e81cec4b22416eff25a520..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_en.properties
+++ /dev/null
@@ -1,25 +0,0 @@
-#Mon Jan 25 15:05:06 CET 2010
-meta.comment.title=Lock
-meta.locked=File locked
-meta.retainlock=Continue locking of file for other users
-meta.unlock=Unlock file for other users
-version.author=Author
-version.comment=Comment
-version.comment.alltitle=Comment/lock
-version.comment.description=Changes are tracked in this document. Please comment your modifications.
-version.comment.title=Comment
-version.confirmDelete=Do you really want to delete {0} revision(s)?
-version.date=Date
-version.del.confirm=Do you really want to delete the following files for good?
-version.del.header=Confirm deletion
-version.deletedBy=Deleted by
-version.deletedFiles=Deleted files
-version.download=Download
-version.initialRevision=Initial version
-version.name=File
-version.noDeletedFiles=There are no deleted files with a change log.
-version.noRevisions=There are no revisions of this file yet.
-version.nr=Revision
-version.restore=Restore
-version.restore.comment=Version {0} restored
-version.restore.failed=File could not be restored.
diff --git a/src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_it.properties b/src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_it.properties
deleted file mode 100644
index 690c93d8280e977742f206566b92486f7ef7b5a4..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_it.properties
+++ /dev/null
@@ -1,25 +0,0 @@
-#Sun Mar 14 12:57:54 CET 2010
-meta.comment.title=Bloccaggio
-meta.locked=Bloccaggio file
-meta.retainlock=Mantenere bloccato il file per altri utenti
-meta.unlock=Sbloccare il file per altri utenti
-version.author=Autore
-version.comment=Commento
-version.comment.alltitle=Commento / Bloccaggio
-version.comment.description=Le modifiche a questo documento vengono registrate. Commenti le Sue modifiche, p.f.
-version.comment.title=Commento
-version.confirmDelete=Desidera veramente eliminare {0} revisione/i?
-version.date=Data
-version.del.confirm=Desidera veramente eliminare definitivamente questi file?
-version.del.header=Confermare eliminazione
-version.deletedBy=Eliminato da
-version.deletedFiles=File eliminati
-version.download=Scaricare
-version.initialRevision=Versione iniziale
-version.name=File
-version.noDeletedFiles=Non ci sono file eliminati che avevano modifiche registrate.
-version.noRevisions=Non ci sono ancora revisioni di questo file.
-version.nr=Revisione
-version.restore=Recuperare
-version.restore.comment=Versione {0} recuperata
-version.restore.failed=Il file non pu\u00F2 essere recuperato.
diff --git a/src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_pt_BR.properties
deleted file mode 100644
index c7e5bfd6c50b216a873f24e3ffcd6a91ab084a91..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_pt_BR.properties
+++ /dev/null
@@ -1,25 +0,0 @@
-#Sat Mar 20 15:19:50 CET 2010
-meta.comment.title=Bloquear
-meta.locked=Arquivo bloqueado
-meta.retainlock=Continue bloqueio de arquivo para outros usu\u00E1rios
-meta.unlock=Desbloquear arquivo para outros usu\u00E1rios
-version.author=Autor
-version.comment=Coment\u00E1rio
-version.comment.alltitle=Comentar/Bloquear
-version.comment.description=As altera\u00E7\u00F5es s\u00E3o controladas neste documento. Por favor, comente suas modifica\u00E7\u00F5es.
-version.comment.title=Comente
-version.confirmDelete=Voc\u00EA realmente quer apagar {0} revis\u00E3o(\u00F5es)?
-version.date=Data
-version.del.confirm=Voc\u00EA realmente quer excluir os seguintes arquivos?
-version.del.header=Confirme exclus\u00E3o
-version.deletedBy=Exclu\u00EDdo por
-version.deletedFiles=Arquivos exclu\u00EDdos
-version.download=Baixar
-version.initialRevision=Vers\u00E3o inicial
-version.name=Arquivo
-version.noDeletedFiles=N\u00E3o existem arquivos exclu\u00EDdos com um registo de altera\u00E7\u00F5es.
-version.noRevisions=N\u00E3o h\u00E1 revis\u00F5es deste arquivo ainda.
-version.nr=Revis\u00E3o
-version.restore=Restaurar
-version.restore.comment=Vers\u00E3o {0} restaurada
-version.restore.failed=Arquivo n\u00E3o p\u00F4de ser restaurado.
diff --git a/src/main/java/org/olat/core/commons/services/_spring/servicesCorecontext.xml b/src/main/java/org/olat/core/commons/services/_spring/servicesCorecontext.xml
index e05ab2a6958644d3dcace37049164e65b49b35cb..60ec9aecc3c931e378f6a209ba86389b719ca28b 100644
--- a/src/main/java/org/olat/core/commons/services/_spring/servicesCorecontext.xml
+++ b/src/main/java/org/olat/core/commons/services/_spring/servicesCorecontext.xml
@@ -78,6 +78,26 @@
 		</property>
 	</bean>
 	
+	<!-- The version configuration -->
+	<bean class="org.olat.core.extensions.action.GenericActionExtension" init-method="initExtensionPoints" >
+		<property name="order" value="7204" />
+		<property name="navigationKey" value="versioning" />
+		<property name="actionController">	
+			<bean class="org.olat.core.gui.control.creator.AutoCreator" scope="prototype">
+				<property name="className" value="org.olat.core.commons.services.vfs.ui.version.VersionAdminController"/>
+			</bean>
+		</property>
+		<property name="translationPackage" value="org.olat.admin" />
+		<property name="i18nActionKey" value="menu.versions"/>
+		<property name="i18nDescriptionKey" value="menu.versions.alt"/>
+		<property name="parentTreeNodeIdentifier" value="sysconfigParent" /> 
+		<property name="extensionPoints">
+			<list>	
+				<value>org.olat.admin.SystemAdminMainController</value>		
+			</list>
+		</property>
+	</bean>
+	
 	<!-- Pdf service -->
 	<bean class="org.olat.core.extensions.action.GenericActionExtension" init-method="initExtensionPoints">
 		<property name="order" value="8280" />
diff --git a/src/main/java/org/olat/core/commons/services/vfs/VFSMetadata.java b/src/main/java/org/olat/core/commons/services/vfs/VFSMetadata.java
index d778f06ba3b71b003c0ec9fe01b999bfbf064263..601cc1d6c8409a62ddc25b07d492b577cfab316d 100644
--- a/src/main/java/org/olat/core/commons/services/vfs/VFSMetadata.java
+++ b/src/main/java/org/olat/core/commons/services/vfs/VFSMetadata.java
@@ -34,12 +34,23 @@ import org.olat.core.id.ModifiedInfo;
  */
 public interface VFSMetadata extends VFSMetadataRef, ModifiedInfo, CreateInfo {
 	
+	public boolean isDeleted();
+	
 	public String getUuid();
 	
 	public void setUuid(String id);
 	
+	/**
+	 * The relative path in bcroot doesn't start with /. / is reserved
+	 * for the bcroot directory itself.
+	 * 
+	 * @return The relative path of the file without the filename
+	 */
 	public String getRelativePath();
 	
+	/**
+	 * @return The name of the file
+	 */
 	public String getFilename();
 	
 	public Date getFileLastModified();
@@ -52,6 +63,13 @@ public interface VFSMetadata extends VFSMetadataRef, ModifiedInfo, CreateInfo {
 	
 	public String getUri();
 	
+	/**
+	 * Return the protocol used to save and retrive the file.
+	 * "file" ist for the standard operations done by OpenOLAT
+	 * VFS implementation.
+	 * 
+	 * @return the procotole
+	 */
 	public String getProtocol();
 	
 	public Identity getAuthor();
@@ -67,6 +85,7 @@ public interface VFSMetadata extends VFSMetadataRef, ModifiedInfo, CreateInfo {
 	public void setComment(String text);
 	
 	public int getDownloadCount();
+
 	
 	public String getCreator();
 	
@@ -83,8 +102,7 @@ public interface VFSMetadata extends VFSMetadataRef, ModifiedInfo, CreateInfo {
 	public String[] getPublicationDate();
 	
 	public void setPublicationDate(String month, String year);
-	
-	
+
 	public String getUrl();
 
 	public void setUrl(String url);
@@ -101,9 +119,14 @@ public interface VFSMetadata extends VFSMetadataRef, ModifiedInfo, CreateInfo {
 	
 	public void setPages(String pages);
 	
-	
+	/**
+	 * @return true if the thumbnails cannot be generated for this file.
+	 */
 	public Boolean getCannotGenerateThumbnails();
 	
+	/**
+	 * @param val true if the thumbnails cannot be generated for this file.
+	 */
 	public void setCannotGenerateThumbnails(Boolean val);
 	
 	
@@ -122,12 +145,17 @@ public interface VFSMetadata extends VFSMetadataRef, ModifiedInfo, CreateInfo {
 	public String getLicensor();
 	
 	public void setLicensor(String licensor);
-	
-	
+
+	/**
+	 * @return true if the file is locked (VFS).
+	 */
 	public boolean isLocked();
 	
 	public void setLocked(boolean locked);
 	
+	/**
+	 * @return The person who locked the file or null
+	 */
 	public Identity getLockedBy();
 	
 	public void setLockedBy(Identity lockedBy);
@@ -136,6 +164,16 @@ public interface VFSMetadata extends VFSMetadataRef, ModifiedInfo, CreateInfo {
 	
 	public void setLockedDate(Date date);
 	
+	
+	public int getRevisionNr();
+	
+	public void setRevisionNr(int nr);
+	
+	public String getRevisionComment();
+	
+	public void setRevisionComment(String text);
+	
+	
 	public void copyValues(VFSMetadata metadata);
 
 }
diff --git a/src/main/java/org/olat/core/commons/services/vfs/VFSRepositoryModule.java b/src/main/java/org/olat/core/commons/services/vfs/VFSRepositoryModule.java
index 0e0a4874efd5fb35b60a0619a0eb56c279510178..49d5c501f2e1b3a98d272f0713c8f2530a855bff 100644
--- a/src/main/java/org/olat/core/commons/services/vfs/VFSRepositoryModule.java
+++ b/src/main/java/org/olat/core/commons/services/vfs/VFSRepositoryModule.java
@@ -34,6 +34,23 @@ import org.olat.core.util.vfs.VFSStatus;
  */
 public class VFSRepositoryModule {
 	
+	public static final VFSStatus canVersion(File file) {
+		VFSStatus canMeta = canMeta(file);
+		if(canMeta == VFSConstants.YES) {
+			// version only works with metadata but not in: portfolio, scorm, forum...
+			Path bFile = file.toPath();
+			Path bcRoot = FolderConfig.getCanonicalRootPath();
+			return !bFile.startsWith(bcRoot.resolve("forum"))
+					&& !bFile.startsWith(bcRoot.resolve("portfolio"))
+					&& !bFile.startsWith(bcRoot.resolve("scorm"))
+					&& !bFile.startsWith(bcRoot.resolve("certificates"))
+					&& !bFile.startsWith(bcRoot.resolve("qtiassessment"))
+					&& !bFile.startsWith(bcRoot.resolve("transcodedVideos"))
+					? VFSConstants.YES : VFSConstants.NO;
+		}
+		return canMeta;
+	}
+	
 	public static final VFSStatus canMeta(File file) {
 		Path bFile = file.toPath();
 		Path bcRoot = FolderConfig.getCanonicalRootPath();
@@ -42,8 +59,10 @@ public class VFSRepositoryModule {
 				&& !bFile.startsWith(FolderConfig.getCanonicalMetaRootPath())
 				&& !bFile.startsWith(FolderConfig.getCanonicalVersionRootPath())
 				&& !bFile.startsWith(FolderConfig.getCanonicalTmpPath())
+				&& !bFile.startsWith(bcRoot.resolve("bulkassessment"))
 				&& !file.isHidden()
 				&& !filename.startsWith("._oo_")
+				&& !filename.equals("CourseConfig.xml")
 				? VFSConstants.YES : VFSConstants.NO;
 	}
 
diff --git a/src/main/java/org/olat/core/commons/services/vfs/VFSRepositoryService.java b/src/main/java/org/olat/core/commons/services/vfs/VFSRepositoryService.java
index e8371ba910ef2a3ed10bb16aded6ec3b6c01366c..9cf80aab6b33203b83169acbacdaedf1e812f0c4 100644
--- a/src/main/java/org/olat/core/commons/services/vfs/VFSRepositoryService.java
+++ b/src/main/java/org/olat/core/commons/services/vfs/VFSRepositoryService.java
@@ -20,6 +20,7 @@
 package org.olat.core.commons.services.vfs;
 
 import java.io.File;
+import java.io.InputStream;
 import java.util.List;
 import java.util.Optional;
 
@@ -67,6 +68,9 @@ public interface VFSRepositoryService {
 	
 	public VFSMetadata updateMetadata(VFSMetadata data);
 	
+
+	public void markAsDeleted(VFSItem item, Identity author);
+	
 	public void deleteMetadata(VFSMetadata data);
 	
 	public void deleteMetadata(File file);
@@ -80,7 +84,14 @@ public interface VFSRepositoryService {
 	 */
 	public void copyTo(VFSLeaf source, VFSLeaf target, VFSContainer parentTarget);
 	
-	public VFSMetadata rename(VFSMetadata data, String newName);
+	/**
+	 * This rename the metadata and the versions but not the file itself.
+	 * 
+	 * @param item The item which is renamed.
+	 * @param newName
+	 * @return
+	 */
+	public VFSMetadata rename(VFSItem item, String newName);
 	
 	public void increaseDownloadCount(VFSItem item);
 	
@@ -129,6 +140,50 @@ public interface VFSRepositoryService {
 	 */
 	public void resetThumbnails(File file);
 	
+	/**
+	 * Get the list of revisions for a specific file.
+	 * 
+	 * @param metadata The metadata object of the file.
+	 * @return A list of revisions if the file is versioned.
+	 */
+	public List<VFSRevision> getRevisions(VFSMetadataRef metadata);
+	
+	public List<VFSRevision> getRevisions(List<VFSMetadataRef> metadatas);
+	
+	
+	public boolean addVersion(VFSLeaf currentFile, Identity identity, String comment, InputStream newFile);
+
+	/**
+	 * Restore the specified revision and replace the current file. If the
+	 * current file doesn't exist, it will recreate it.
+	 * 
+	 * @param identity The identity who make the operation
+	 * @param revision The revision to restore
+	 * @param comment A comment
+	 * @return true if successful
+	 */
+	public boolean restoreRevision(Identity identity, VFSRevision revision, String comment);
+
+	/**
+	 * Delete definitively the revisions of a file.
+	 * 
+	 * @param identity The identity who makes the operation
+	 * @param revisions The revisions to delete
+	 * @return true if ssuccessful
+	 */
+	public boolean deleteRevisions(Identity identity, List<VFSRevision> revisions);
+	
+	/**
+	 * Move the metadata and revisions from a path to the other.
+	 * 
+	 * @param currentFile The current file
+	 * @param targetFile The target file where to move the metadata
+	 * @param author The user which moved the data
+	 * @return The merged metadata
+	 */
+	public VFSMetadata move(VFSLeaf currentFile, VFSLeaf targetFile, Identity author);
+	
+	public File getRevisionFile(VFSRevision revision);
 	
 	
 	public License getLicense(VFSMetadata meta);
diff --git a/src/main/java/org/olat/core/util/vfs/version/VFSRevision.java b/src/main/java/org/olat/core/commons/services/vfs/VFSRevision.java
similarity index 81%
rename from src/main/java/org/olat/core/util/vfs/version/VFSRevision.java
rename to src/main/java/org/olat/core/commons/services/vfs/VFSRevision.java
index 3cdfe67801cd2ab84af15ff554875299d626cae9..fa9866e6ed4fe6d6c0ca2942c588013641080f87 100644
--- a/src/main/java/org/olat/core/util/vfs/version/VFSRevision.java
+++ b/src/main/java/org/olat/core/commons/services/vfs/VFSRevision.java
@@ -17,9 +17,11 @@
  * frentix GmbH, http://www.frentix.com
  * <p>
  */
-package org.olat.core.util.vfs.version;
+package org.olat.core.commons.services.vfs;
 
-import java.io.InputStream;
+import java.util.Date;
+
+import org.olat.core.id.Identity;
 
 /**
  * 
@@ -36,22 +38,25 @@ public interface VFSRevision {
 	/**
 	 * @return author of the revision
 	 */
-	public String getAuthor();
+	public Identity getAuthor();
 
 	/**
 	 * @return timestamp of the creation of this revision
 	 */
-	public long getLastModified();
+	public Date getFileLastModified();
 
 	/**
 	 * @return the revision number
 	 */
-	public String getRevisionNr();
+	public int getRevisionNr();
+	
+
+	public Date getCreationDate();
 
 	/**
 	 * @return comment
 	 */
-	public String getComment();
+	public String getRevisionComment();
 
 	/**
 	 * @return name of the file
@@ -62,9 +67,7 @@ public interface VFSRevision {
 	 * @return size of the file
 	 */
 	public long getSize();
+	
+	public VFSMetadata getMetadata();
 
-	/**
-	 * @return InputStream of the file
-	 */
-	public InputStream getInputStream();
 }
diff --git a/src/main/java/org/olat/core/commons/services/vfs/VFSVersionModule.java b/src/main/java/org/olat/core/commons/services/vfs/VFSVersionModule.java
new file mode 100644
index 0000000000000000000000000000000000000000..7e0f1c5d503f96a28ee61f040b2468b610b8729b
--- /dev/null
+++ b/src/main/java/org/olat/core/commons/services/vfs/VFSVersionModule.java
@@ -0,0 +1,84 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.commons.services.vfs;
+
+import org.olat.core.configuration.AbstractSpringModule;
+import org.olat.core.configuration.ConfigOnOff;
+import org.olat.core.util.StringHelper;
+import org.olat.core.util.coordinate.CoordinatorManager;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+/**
+ * 
+ * Description:<br>
+ * A very simple configuration bean for versioning. There is a default value for
+ * the maximum allowed number of revisions, this number can be overridden by an
+ * second value saved in the persisted properties.
+ * 
+ * <P>
+ * Initial Date: 21 sept. 2009 <br>
+ * 
+ * @author srosse, stephane.rosse@frentix.com, https://www.frentix.com
+ */
+@Service
+public class VFSVersionModule extends AbstractSpringModule implements ConfigOnOff {
+
+	private static final String MAX_NUMBER_OF_VERSIONS = "maxnumber.versions";
+
+	@Value("${maxnumber.versions:0}")
+	private int maxNumberOfVersions;
+
+	@Autowired
+	public VFSVersionModule(CoordinatorManager coordinatorManager) {
+		super(coordinatorManager, "org.olat.core.util.vfs.version.SimpleVersionConfig", false);
+	}
+
+	@Override
+	public boolean isEnabled() {
+		return maxNumberOfVersions > 0;
+	}
+
+	@Override
+	public void init() {
+		String maxNumberOfVersionsObj = getStringPropertyValue(MAX_NUMBER_OF_VERSIONS, true);
+		if(StringHelper.containsNonWhitespace(maxNumberOfVersionsObj)) {
+			maxNumberOfVersions = Integer.parseInt(maxNumberOfVersionsObj);
+		}
+	}
+
+	@Override
+	protected void initFromChangedProperties() {
+		init();
+	}
+
+	/**
+	 * @return maximum number of revisions, defined in admin. of Olat
+	 */
+	public int getMaxNumberOfVersions() {
+		return maxNumberOfVersions;
+	}
+
+	public void setMaxNumberOfVersions(int maxNumber) {
+		this.maxNumberOfVersions = maxNumber;
+		setStringProperty(MAX_NUMBER_OF_VERSIONS, Integer.toString(maxNumber), true);
+	}
+}
diff --git a/src/main/java/org/olat/core/commons/services/vfs/manager/VFSMetadataDAO.java b/src/main/java/org/olat/core/commons/services/vfs/manager/VFSMetadataDAO.java
index 9ccc9c451fe511e8271fb401cafc6b0a2a302924..77037b70581787fdd8ddacf90966da84266f543f 100644
--- a/src/main/java/org/olat/core/commons/services/vfs/manager/VFSMetadataDAO.java
+++ b/src/main/java/org/olat/core/commons/services/vfs/manager/VFSMetadataDAO.java
@@ -209,13 +209,14 @@ public class VFSMetadataDAO {
 			.executeUpdate();
 	}
 	
-	public void updateMetadata(long fileSize, String relativePath, String filename) {
-		String updateQuery = "update vfsmetadatafilesaved set fileLastModified=now(), fileSize=:fileSize where filename=:filename and relativePath=:relativePath";
+	public void updateMetadata(long fileSize, Date lastModified, String relativePath, String filename) {
+		String updateQuery = "update vfsmetadatafilesaved set fileLastModified=:lastModified, fileSize=:fileSize where filename=:filename and relativePath=:relativePath";
 		dbInstance.getCurrentEntityManager()
 			.createQuery(updateQuery)
 			.setParameter("filename", filename)
 			.setParameter("relativePath", relativePath)
 			.setParameter("fileSize", fileSize)
+			.setParameter("lastModified", lastModified)
 			.executeUpdate();
 	}
 	
diff --git a/src/main/java/org/olat/core/commons/services/vfs/manager/VFSRepositoryServiceImpl.java b/src/main/java/org/olat/core/commons/services/vfs/manager/VFSRepositoryServiceImpl.java
index d891217bf7ef0a254b9f67d73a6d9c25cff834ca..2c884c3a1ac5b2e86b6152d53da3c911c5c69c96 100644
--- a/src/main/java/org/olat/core/commons/services/vfs/manager/VFSRepositoryServiceImpl.java
+++ b/src/main/java/org/olat/core/commons/services/vfs/manager/VFSRepositoryServiceImpl.java
@@ -21,6 +21,7 @@ package org.olat.core.commons.services.vfs.manager;
 
 import java.io.File;
 import java.io.IOException;
+import java.io.InputStream;
 import java.nio.file.FileVisitResult;
 import java.nio.file.Files;
 import java.nio.file.Path;
@@ -29,14 +30,20 @@ import java.nio.file.SimpleFileVisitor;
 import java.nio.file.StandardCopyOption;
 import java.nio.file.attribute.BasicFileAttributes;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Date;
 import java.util.Deque;
+import java.util.HashMap;
+import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
 import java.util.Optional;
 import java.util.UUID;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
+import java.util.zip.Adler32;
+import java.util.zip.Checksum;
 
 import org.olat.basesecurity.BaseSecurity;
 import org.olat.core.commons.modules.bc.FolderConfig;
@@ -55,9 +62,12 @@ import org.olat.core.commons.services.vfs.VFSLeafEditor;
 import org.olat.core.commons.services.vfs.VFSMetadata;
 import org.olat.core.commons.services.vfs.VFSMetadataRef;
 import org.olat.core.commons.services.vfs.VFSRepositoryService;
+import org.olat.core.commons.services.vfs.VFSRevision;
 import org.olat.core.commons.services.vfs.VFSThumbnailMetadata;
+import org.olat.core.commons.services.vfs.VFSVersionModule;
 import org.olat.core.commons.services.vfs.manager.MetaInfoReader.Thumbnail;
 import org.olat.core.commons.services.vfs.model.VFSMetadataImpl;
+import org.olat.core.commons.services.vfs.model.VFSRevisionImpl;
 import org.olat.core.gui.control.Event;
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
@@ -67,6 +77,7 @@ import org.olat.core.util.FileUtils;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.coordinate.CoordinatorManager;
 import org.olat.core.util.event.GenericEventListener;
+import org.olat.core.util.io.ShieldInputStream;
 import org.olat.core.util.resource.OresHelper;
 import org.olat.core.util.vfs.LocalFileImpl;
 import org.olat.core.util.vfs.LocalFolderImpl;
@@ -75,6 +86,8 @@ import org.olat.core.util.vfs.VFSContainer;
 import org.olat.core.util.vfs.VFSItem;
 import org.olat.core.util.vfs.VFSLeaf;
 import org.olat.core.util.vfs.VFSManager;
+import org.olat.core.util.vfs.version.RevisionFileImpl;
+import org.olat.core.util.vfs.version.VersionsFileImpl;
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -99,12 +112,16 @@ public class VFSRepositoryServiceImpl implements VFSRepositoryService, GenericEv
 	@Autowired
 	private FolderModule folderModule;
 	@Autowired
+	private VFSRevisionDAO revisionDao;
+	@Autowired
 	private VFSMetadataDAO metadataDao;
 	@Autowired
 	private VFSThumbnailDAO thumbnailDao;
 	@Autowired
 	private LicenseService licenseService;
 	@Autowired
+	private VFSVersionModule versionModule;
+	@Autowired
 	private FolderLicenseHandler licenseHandler;
 	@Autowired
 	private ThumbnailService thumbnailService;
@@ -131,7 +148,8 @@ public class VFSRepositoryServiceImpl implements VFSRepositoryService, GenericEv
 		File file = toFile(event.getRelativePath(), event.getFilename());
 		if(file.exists()) {
 			try {
-				metadataDao.updateMetadata(file.length(), event.getRelativePath(), event.getFilename());
+				Date lastModified = new Date(file.lastModified());
+				metadataDao.updateMetadata(file.length(), lastModified, event.getRelativePath(), event.getFilename());
 				dbInstance.commit();
 			} catch (Exception e) {
 				log.error("Cannot update file size of: " + event.getRelativePath() + " " + event.getFilename(), e);
@@ -169,6 +187,7 @@ public class VFSRepositoryServiceImpl implements VFSRepositoryService, GenericEv
 			AsyncFileSizeUpdateEvent event = new AsyncFileSizeUpdateEvent(relativePath, filename);
 			coordinatorManager.getCoordinator().getEventBus().fireEventToListenersOf(event, fileSizeSubscription);
 		}
+		dbInstance.commit();
 		return metadata;
 	}
 	
@@ -211,7 +230,8 @@ public class VFSRepositoryServiceImpl implements VFSRepositoryService, GenericEv
 		
 		String filename = file.getName();
 		VFSMetadata metadata = metadataDao.getMetadata(relativePath, filename, file.isDirectory());
-		if(metadata != null && !metadata.isDirectory() && metadata.getFileSize() != file.length()) {
+		if(metadata != null && !metadata.isDirectory()
+				&& (metadata.getFileSize() != file.length() || file.lastModified() != metadata.getFileLastModified().getTime())) {
 			AsyncFileSizeUpdateEvent event = new AsyncFileSizeUpdateEvent(relativePath, filename);
 			coordinatorManager.getCoordinator().getEventBus().fireEventToListenersOf(event, fileSizeSubscription);
 		}
@@ -297,7 +317,8 @@ public class VFSRepositoryServiceImpl implements VFSRepositoryService, GenericEv
 		if(leaf == null || leaf.canMeta() != VFSConstants.YES) return; // nothing to do
 		
 		String relativePath = getContainerRelativePath(leaf);
-		metadataDao.updateMetadata(leaf.getSize(), relativePath, leaf.getName());
+		Date lastModified = new Date(leaf.getLastModified());
+		metadataDao.updateMetadata(leaf.getSize(), lastModified, relativePath, leaf.getName());
 	}
 
 	@Override
@@ -310,6 +331,24 @@ public class VFSRepositoryServiceImpl implements VFSRepositoryService, GenericEv
 			}
 			thumbnailDao.removeThumbnail(thumbnail);
 		}
+		
+		List<VFSRevision> revisions = getRevisions(data);
+		for(VFSRevision revision:revisions) {
+			File revFile = getRevisionFile(revision);
+			if(revFile != null && revFile.exists()) {
+				try {
+					Files.delete(revFile.toPath());
+				} catch (IOException e) {
+					log.error("Cannot delete thumbnail: " + revFile, e);
+				}
+			}
+			revisionDao.deleteRevision(revision);
+		}
+		
+		List<VFSMetadata> children = getChildren(data);
+		for(VFSMetadata child:children) {
+			deleteMetadata(child);
+		}
 		metadataDao.removeMetadata(data);
 	}
 
@@ -321,6 +360,18 @@ public class VFSRepositoryServiceImpl implements VFSRepositoryService, GenericEv
 		}
 	}
 
+	@Override
+	public void markAsDeleted(VFSItem item, Identity author) {
+		if(item.canMeta() != VFSConstants.YES) return;
+		
+		VFSMetadataImpl metadata = (VFSMetadataImpl)getMetadataFor(item);
+		metadata.setDeleted(true);
+		if(item instanceof VFSLeaf && item.canMeta() == VFSConstants.YES) {
+			addToRevisions((VFSLeaf)item, metadata, author, "");
+		}
+		metadataDao.updateMetadata(metadata);
+	}
+
 	@Override
 	public void copyBinaries(VFSMetadata metadata, byte[] binaries) {
 		if(binaries == null || binaries.length == 0) return;
@@ -340,23 +391,61 @@ public class VFSRepositoryServiceImpl implements VFSRepositoryService, GenericEv
 				VFSMetadata targetMetadata = loadMetadata(targetFile);
 				if(targetMetadata == null) {
 					VFSMetadata parentMetadata = getMetadataFor(parentTarget);
-					String relativePath = this.getRelativePath(targetFile.getParentFile());
+					String relativePath = getRelativePath(targetFile.getParentFile());
 					targetMetadata = metadataDao.createMetadata(UUID.randomUUID().toString(), relativePath, targetFile.getName(),
 							new Date(), targetFile.length(), false, targetFile.toURI().toString(), "file", parentMetadata);
 				}
 				targetMetadata.copyValues(sourceMetadata);
+				if(source.canVersion() == VFSConstants.YES || target.canVersion() == VFSConstants.YES) {
+					targetMetadata.setRevisionComment(sourceMetadata.getRevisionComment());
+					targetMetadata.setRevisionNr(sourceMetadata.getRevisionNr());
+					copy(sourceMetadata, targetMetadata);
+				}
 				metadataDao.updateMetadata(targetMetadata);
 			}
 		}
 	}
+	
+	private boolean copy(VFSMetadata sourceMetadata, VFSMetadata targetMetadata) {
+		List<VFSRevision> sourceRevisions = getRevisions(sourceMetadata);
+
+		boolean allOk = true;
+		for (VFSRevision sourceRevision : sourceRevisions) {
+			VFSLeaf sourceRevFile = getRevisionLeaf(sourceMetadata, (VFSRevisionImpl)sourceRevision);
+			if(sourceRevFile != null && sourceRevFile.exists()) {
+				VFSRevision targetRevision = revisionDao.createRevisionCopy(sourceRevision.getAuthor(), sourceRevision.getRevisionComment(),
+						sourceRevision, targetMetadata);
+				VFSLeaf targetRevFile = getRevisionLeaf(targetMetadata, (VFSRevisionImpl)targetRevision);
+				VFSManager.copyContent(sourceRevFile, targetRevFile, false);
+			}
+		}
+		return allOk;
+	}
 
 	@Override
-	public VFSMetadata rename(VFSMetadata data, String newName) {
-		((VFSMetadataImpl)data).setFilename(newName);
-		Path newFile = Paths.get(folderModule.getCanonicalRoot(), data.getRelativePath(), newName);
+	public VFSMetadata rename(VFSItem item, String newName) {
+		VFSMetadata metadata = getMetadataFor(item);
+
+		((VFSMetadataImpl)metadata).setFilename(newName);
+		Path newFile = Paths.get(folderModule.getCanonicalRoot(), metadata.getRelativePath(), newName);
 		String uri = newFile.toFile().toURI().toString();
-		((VFSMetadataImpl)data).setUri(uri);
-		return metadataDao.updateMetadata(data);
+		((VFSMetadataImpl)metadata).setUri(uri);
+			
+		if(item instanceof VFSContainer) {
+			//TODO rename container ???
+		}
+		
+		List<VFSRevision> revisions = getRevisions(metadata);
+		for(VFSRevision revision:revisions) {
+			VFSLeaf revFile = getRevisionLeaf(metadata, (VFSRevisionImpl)revision);
+			if(revFile != null && revFile.exists()) {
+				String newRevFilename = generateFilenameForRevision(newName, revision.getRevisionNr());
+				revFile.rename(newRevFilename);
+				((VFSRevisionImpl)revision).setFilename(newRevFilename);
+				revisionDao.updateRevision(revision);
+			}
+		}
+		return metadataDao.updateMetadata(metadata);
 	}
 
 	@Override
@@ -530,6 +619,283 @@ public class VFSRepositoryServiceImpl implements VFSRepositoryService, GenericEv
 		}
 	}
 	
+	@Override
+	public List<VFSRevision> getRevisions(VFSMetadataRef metadata) {
+		return revisionDao.getRevisions(metadata);
+	}
+
+	@Override
+	public List<VFSRevision> getRevisions(List<VFSMetadataRef> metadatas) {
+		return revisionDao.getRevisions(metadatas);
+	}
+
+	@Override
+	public boolean restoreRevision(Identity identity, VFSRevision revision, String comment) {
+		VFSMetadata metadata = ((VFSRevisionImpl)revision).getMetadata();
+
+		File currentFile = toFile(metadata);
+		if(!currentFile.exists()) {
+			// restore a deleted file
+			metadata = metadataDao.loadMetadata(metadata.getKey());
+			((VFSMetadataImpl)metadata).setDeleted(false);
+			metadata = metadataDao.updateMetadata(metadata);
+			try {
+				VFSLeaf revFile = getRevisionLeaf(metadata, ((VFSRevisionImpl)revision));
+				if (FileUtils.copyToFile(revFile.getInputStream(), currentFile, "Restore")) {
+					deleteRevisions(metadata, Collections.singletonList(revision));
+					return true;
+				}
+			} catch (IOException e) {
+				log.error("", e);
+			}
+		} else {
+		
+			String fileRelativePath = getRelativePath(currentFile);
+			VFSLeaf currentLeaf = VFSManager.olatRootLeaf(fileRelativePath);
+			// add current version to versions file
+			if (addToRevisions(currentLeaf, metadata, identity, comment)) {
+				// copy the content of the new file to the old
+				VFSLeaf revFile = getRevisionLeaf(metadata, ((VFSRevisionImpl)revision));
+				if (VFSManager.copyContent(revFile.getInputStream(), currentLeaf)) {
+					return true;
+				}
+			}
+		}
+		return false;
+	}
+	
+	@Override
+	public boolean addVersion(VFSLeaf currentFile, Identity identity, String comment, InputStream newFile) {
+		boolean allOk = false;
+		VFSMetadata metadata = getMetadataFor(currentFile);
+		if (addToRevisions(currentFile, metadata, identity, comment)) {
+			// copy the content of the new file to the old
+			if(newFile instanceof net.sf.jazzlib.ZipInputStream || newFile instanceof java.util.zip.ZipInputStream) {
+				newFile = new ShieldInputStream(newFile);
+			}
+			allOk = VFSManager.copyContent(newFile, currentFile);
+		} else {
+			log.error("Cannot create a version of this file: " + currentFile);
+		}
+		dbInstance.commit();
+		return allOk;
+	}
+	
+	public boolean addToRevisions(VFSLeaf currentLeaf, VFSMetadata metadata, Identity identity, String comment) {
+		int maxNumOfVersions = versionModule.getMaxNumberOfVersions();
+		if(maxNumOfVersions == 0) {
+			return true;//deactivated, return all ok
+		}
+
+		File currentFile = toFile(currentLeaf);
+		VFSContainer versionContainer = currentLeaf.getParentContainer();
+
+		// read from the
+		List<VFSRevision> revisions = revisionDao.getRevisions(metadata);
+		VFSRevisionImpl lastRevision = (VFSRevisionImpl)getLastRevision(revisions);
+		int versionNr = getNextRevisionNr(revisions);
+		
+		boolean sameFile = isSameFile(currentLeaf, metadata, revisions);
+		String uuid = sameFile && lastRevision != null ? lastRevision.getFilename()
+				: generateFilenameForRevision(currentFile, versionNr);
+
+		Date lastModifiedDate = metadata.getFileLastModified();
+		if(lastModifiedDate == null) {
+			lastModifiedDate = new Date(currentFile.lastModified());
+		}
+		long fileSize = metadata.getFileSize();
+		if(fileSize <= 0l) {
+			fileSize = currentFile.length();
+		}
+
+		VFSRevision newRevision = revisionDao.createRevision(metadata.getAuthor(), uuid, versionNr,
+				fileSize, lastModifiedDate, metadata.getRevisionComment(), metadata);
+		revisions.add(newRevision);
+
+		if(!sameFile) {
+			resetThumbnails(currentLeaf);
+		}
+
+		if (sameFile || VFSManager.copyContent(currentLeaf, versionContainer.createChildLeaf(uuid), false)) {
+			if(maxNumOfVersions >= 0 && revisions.size() > maxNumOfVersions) {
+				int numOfVersionsToDelete = Math.min(revisions.size(), (revisions.size() - maxNumOfVersions));
+				if(numOfVersionsToDelete > 0) {
+					List<VFSRevision> versionsToDelete = revisions.subList(0, numOfVersionsToDelete);
+					deleteRevisions(metadata, revisions, versionsToDelete);
+				}
+			}
+			metadata.setRevisionComment(comment);
+			metadata.setRevisionNr(getNextRevisionNr(revisions));
+			metadata.setAuthor(identity);//TODO dedicated author
+			updateMetadata(metadata);
+			return true;
+		} else {
+			log.error("Cannot create a version of this file: " + currentLeaf);
+		}
+		return false;
+	}
+	
+	@Override
+	public boolean deleteRevisions(Identity identity, List<VFSRevision> revisions) {
+		if(revisions == null || revisions.isEmpty()) return true;// ok, nothing to do
+		
+		VFSMetadata metadata = ((VFSRevisionImpl)revisions.get(0)).getMetadata();
+		List<VFSRevision> allRevisions = revisionDao.getRevisions(metadata);
+		return deleteRevisions(metadata, allRevisions, revisions);
+	}
+	
+	private boolean deleteRevisions(VFSMetadata metadata, List<VFSRevision> versionsToDelete) {
+		List<VFSRevision> allRevisions = revisionDao.getRevisions(metadata);
+		return deleteRevisions(metadata, allRevisions, versionsToDelete);
+	}
+	
+	private boolean deleteRevisions(VFSMetadata metadata, List<VFSRevision> allVersions, List<VFSRevision> versionsToDelete) {
+		List<VFSRevision> toDelete = new ArrayList<>(versionsToDelete);
+		Map<String,VFSRevisionImpl> filenamesToDelete = new HashMap<>(allVersions.size());
+		for (VFSRevision versionToDelete : versionsToDelete) {
+			VFSRevisionImpl versionImpl = (VFSRevisionImpl) versionToDelete;
+			for (Iterator<VFSRevision> allVersionIt = allVersions.iterator(); allVersionIt.hasNext();) {
+				VFSRevisionImpl allVersionImpl = (VFSRevisionImpl) allVersionIt.next();
+				if (allVersionImpl.getKey().equals(versionImpl.getKey())) {
+					allVersionIt.remove();
+					break;
+				}
+			}
+			String fileToDelete = versionImpl.getFilename();
+			if (fileToDelete != null) {
+				filenamesToDelete.put(fileToDelete, versionImpl);
+			}
+		}
+
+		File directory = toFile(metadata).getParentFile();
+		List<VFSRevisionImpl> missingFiles = new ArrayList<>();
+		for(VFSRevision survivingVersion:allVersions) {
+			VFSRevisionImpl survivingVersionImpl = (VFSRevisionImpl)survivingVersion;
+			String revFilename = survivingVersionImpl.getFilename();
+			if(revFilename == null || !new File(directory, revFilename).exists()) {
+				missingFiles.add(survivingVersionImpl);//file is missing
+			} else if(filenamesToDelete.containsKey(revFilename)) {
+				filenamesToDelete.remove(revFilename);
+			}
+		}
+
+		toDelete.addAll(missingFiles);
+		for(VFSRevision versionToDelete:toDelete) {
+			revisionDao.deleteRevision(versionToDelete);
+		}
+		
+		for(String fileToDelete:filenamesToDelete.keySet()) {
+			try {
+				File file = new File(directory, fileToDelete);
+				Files.deleteIfExists(file.toPath());
+			} catch (IOException e) {
+				log.error("Cannot the version of a file", e);
+			}
+		}
+		return true;
+	}
+	
+	private VFSRevision getLastRevision(List<VFSRevision> revisions) {
+		VFSRevision last = null;
+		for (VFSRevision version : revisions) {
+			if (last == null || version.getRevisionNr() > last.getRevisionNr()) {
+				last = version;
+			}
+		}
+		return last;
+	}
+	
+	private int getNextRevisionNr(List<VFSRevision> revisions) {
+		int maxNumber = 0;
+		for (VFSRevision version : revisions) {
+			int versionNr = version.getRevisionNr();
+			if (versionNr > 0 && versionNr > maxNumber) {
+				maxNumber = versionNr;
+			}
+		}
+		return maxNumber + 1;
+	}
+	
+	private boolean isSameFile(VFSLeaf currentFile, VFSMetadata metadata, List<VFSRevision> revisions) {
+		boolean same = false;
+		if(!revisions.isEmpty()) {
+			VFSRevision lastRevision = getLastRevision(revisions);
+			if(lastRevision != null) {
+				long lastSize = lastRevision.getSize();
+				long currentSize = currentFile.getSize();
+				if(currentSize == lastSize && currentSize > 0
+						&& lastRevision instanceof VFSRevisionImpl
+						&& currentFile instanceof LocalFileImpl) {
+					VFSRevisionImpl lastRev = ((VFSRevisionImpl)lastRevision);
+					LocalFileImpl current = (LocalFileImpl)currentFile;
+						//can be the same file
+					try {
+						VFSLeaf lastRevFile = getRevisionLeaf(metadata, lastRev);
+						Checksum cm1 = org.apache.commons.io.FileUtils.checksum(toFile(lastRevFile), new Adler32());
+						Checksum cm2 = org.apache.commons.io.FileUtils.checksum(toFile(current) , new Adler32());
+						same = cm1.getValue() == cm2.getValue();
+					} catch (IOException e) {
+						log.debug("Error calculating the checksum of files");
+					}	
+				}
+			}
+		}
+		return same;
+	}
+	
+	private VFSLeaf getRevisionLeaf(VFSMetadata metadata, VFSRevisionImpl rev) {
+		return VFSManager.olatRootLeaf("/" + metadata.getRelativePath(), rev.getFilename());
+	}
+	
+	private Path getRevisionPath(String relativePath, String revFilename) {
+		return Paths.get(folderModule.getCanonicalRoot(), relativePath, revFilename);
+	}
+	
+	@Override
+	public File getRevisionFile(VFSRevision revision) {
+		VFSRevisionImpl rev = (VFSRevisionImpl)revision;
+		return getRevisionPath(rev.getMetadata().getRelativePath(), rev.getFilename()).toFile();
+	}
+
+	@Override
+	public VFSMetadata move(VFSLeaf currentLeaf, VFSLeaf targetLeaf,  Identity author) {
+		VFSMetadata metadata = getMetadataFor(currentLeaf);
+
+		File currentFile = toFile(currentLeaf);
+		String currentRelativePath = getRelativePath(currentFile.getParentFile());
+
+		File targetFile = toFile(targetLeaf);
+		String targetRelativePath = getRelativePath(targetFile.getParentFile());
+		String newTargetName = targetFile.getName();
+		((VFSMetadataImpl)metadata).setFilename(newTargetName);
+		((VFSMetadataImpl)metadata).setRelativePath(targetRelativePath);
+		((VFSMetadataImpl)metadata).setUri(targetFile.toURI().toString());
+		VFSMetadata targetParent = getMetadataFor(targetFile.getParentFile());
+		((VFSMetadataImpl)metadata).setParent(targetParent);
+		((VFSMetadataImpl)metadata).setAuthor(author);
+
+		List<VFSRevision> revisions = getRevisions(metadata);
+		for(VFSRevision revision:revisions) {
+			VFSRevisionImpl revImpl = (VFSRevisionImpl)revision;
+			Path path = getRevisionPath(currentRelativePath, revImpl.getFilename());
+			File revFile = path.toFile();
+			if(revFile.exists()) {
+				String newRevFilename = generateFilenameForRevision(newTargetName, revision.getRevisionNr());
+				Path targetRevPath = getRevisionPath(targetRelativePath, newRevFilename);
+				try {
+					Files.move(path, targetRevPath, StandardCopyOption.REPLACE_EXISTING);
+				} catch (IOException e) {
+					log.error("", e);
+				}
+				((VFSRevisionImpl)revision).setFilename(newRevFilename);
+				revisionDao.updateRevision(revision);
+			}
+		}
+		
+		metadata = metadataDao.updateMetadata(metadata);
+		return metadata;
+	}
+
 	/**
 	 * Get the license of the MetaInfo
 	 *
@@ -668,9 +1034,15 @@ public class VFSRepositoryServiceImpl implements VFSRepositoryService, GenericEv
 					xmlMetadata = metaReader.getMetadata();
 					thumbnails = metaReader.getThumbnails();
 				}
+
 				metadata = metadataDao.createMetadata(xmlMetadata, relativePath, file.getName(), fileLastModified,
 						size, directory, file.toURI().toString(), "file", parent);
 				migrateThumbnails(metadata, file, thumbnails);
+				
+				File versionFile = getVersionFile(file);
+				if(versionFile != null) {
+					migrateVersions(file, versionFile, metadata);
+				}
 			}
 		} 
 		
@@ -695,6 +1067,28 @@ public class VFSRepositoryServiceImpl implements VFSRepositoryService, GenericEv
 		return sb.toString();
 	}
 	
+	/**
+	 * @param filename The original file
+	 * @param revisionNr The version number
+	 * @return A name like ._oo_vr_filename.ext
+	 */
+	private String generateFilenameForRevision(File file, int revisionNr) {
+		StringBuilder sb = new StringBuilder(128);
+		sb.append("._oo_vr_").append(revisionNr).append("_").append(file.getName());
+		return sb.toString();
+	}
+	
+	/**
+	 * @param filename The original filename
+	 * @param revisionNr The version number
+	 * @return A name like ._oo_vr_filename.ext
+	 */
+	private String generateFilenameForRevision(String filename, int revisionNr) {
+		StringBuilder sb = new StringBuilder(128);
+		sb.append("._oo_vr_").append(revisionNr).append("_").append(filename);
+		return sb.toString();
+	}
+	
 	private void migrateThumbnails(VFSMetadata metadata, File file, List<Thumbnail> thumbnails) {
 		if(thumbnails == null || thumbnails.isEmpty()) return;
 		
@@ -741,6 +1135,54 @@ public class VFSRepositoryServiceImpl implements VFSRepositoryService, GenericEv
 		}
 		return canonicalMetaPath;
 	}
+	
+	private VFSMetadata migrateVersions(File file, File versionFile, VFSMetadata metadata) {
+		VersionsFileImpl versions = (VersionsFileImpl)VFSXStream.read(versionFile);
+		List<VFSRevision> revisions = versions.getRevisions();
+		if(revisions == null || revisions.isEmpty()) {
+			return metadata;
+		}
+		
+		metadata.setRevisionComment(versions.getComment());
+		metadata.setRevisionNr(versions.getRevisionNr());
+		metadata = metadataDao.updateMetadata(metadata);
+		
+		for(VFSRevision revision:revisions) {
+			RevisionFileImpl revisionFile = (RevisionFileImpl)revision;
+			String filename = revisionFile.getFilename();
+			File oldOne = new File(versionFile.getParentFile(), filename);
+			if(oldOne.exists()) {
+				try {
+					String newRevisionFilename = generateFilenameForRevision(file, revisionFile.getRevisionNr());
+					revisionDao.createRevision(revisionFile.getAuthor(), newRevisionFilename, revisionFile.getRevisionNr(),
+							oldOne.length(), revisionFile.getFileLastModified(), revisionFile.getComment(), metadata);
+					File target = new File(file.getParentFile(), newRevisionFilename);
+					Files.move(oldOne.toPath(), target.toPath(), StandardCopyOption.REPLACE_EXISTING);
+				} catch (IOException e) {
+					log.error("", e);
+				}
+			}
+		}
+		return metadata;
+	}
+		
+	/**
+	 * @param file The regular file
+	 * @return The XML versions file
+	 */
+	private File getVersionFile(File file) {
+		if (file == null || !file.exists()) {
+			return null;
+		}
+		String relPath = getRelativePath(file);
+		if (relPath == null) {// cannot handle
+			return null;
+		}
+		
+		File versionFolder = new File(FolderConfig.getCanonicalVersionRoot(), relPath);
+		File fVersion = new File(versionFolder.getParentFile(), file.getName() + ".xml");
+		return fVersion.exists() ? fVersion : null;
+	}
 
 	@Override
 	public boolean hasEditor(String suffix) {
diff --git a/src/main/java/org/olat/core/commons/services/vfs/manager/VFSRevisionDAO.java b/src/main/java/org/olat/core/commons/services/vfs/manager/VFSRevisionDAO.java
new file mode 100644
index 0000000000000000000000000000000000000000..d702ba9ae1f5ea3da6f37ffd4f7a174941d98635
--- /dev/null
+++ b/src/main/java/org/olat/core/commons/services/vfs/manager/VFSRevisionDAO.java
@@ -0,0 +1,125 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.commons.services.vfs.manager;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.olat.core.commons.persistence.DB;
+import org.olat.core.commons.services.vfs.VFSMetadata;
+import org.olat.core.commons.services.vfs.VFSMetadataRef;
+import org.olat.core.commons.services.vfs.VFSRevision;
+import org.olat.core.commons.services.vfs.model.VFSRevisionImpl;
+import org.olat.core.id.Identity;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 
+ * Initial date: 18 mars 2019<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+@Service
+public class VFSRevisionDAO {
+	
+	@Autowired
+	private DB dbInstance;
+	
+	public VFSRevision createRevision(Identity author, String filename, int revisionNr, long size, Date fileLastModified,
+			String comment, VFSMetadata metadata) {
+		VFSRevisionImpl rev = new VFSRevisionImpl();
+		rev.setCreationDate(new Date());
+		rev.setLastModified(rev.getCreationDate());
+		rev.setRevisionNr(revisionNr);
+		rev.setFilename(filename);
+		if(fileLastModified == null) {
+			rev.setFileLastModified(rev.getCreationDate());
+		} else {
+			rev.setFileLastModified(fileLastModified);
+		}
+		rev.setSize(size);
+		rev.setRevisionComment(comment);
+		rev.copyValues(metadata);
+		rev.setAuthor(author);
+		rev.setMetadata(metadata);
+		dbInstance.getCurrentEntityManager().persist(rev);
+		return rev;
+	}
+	
+	public VFSRevision createRevisionCopy(Identity author, String revisionComment, VFSRevision revisionToCopy, VFSMetadata metadata) {
+		VFSRevisionImpl rev = new VFSRevisionImpl();
+		VFSRevisionImpl revToCopy = (VFSRevisionImpl)revisionToCopy;
+		rev.setCreationDate(new Date());
+		rev.setLastModified(rev.getCreationDate());
+		rev.setRevisionNr(revToCopy.getRevisionNr());
+		rev.setFilename(revToCopy.getFilename());
+		rev.setFileLastModified(revToCopy.getFileLastModified());
+		rev.setSize(revToCopy.getSize());
+		rev.setRevisionComment(revisionComment);
+		rev.setAuthor(author);
+		rev.copyValues(revToCopy);
+		rev.setMetadata(metadata);
+		dbInstance.getCurrentEntityManager().persist(rev);
+		return rev;
+	}
+	
+	public List<VFSRevision> getRevisions(VFSMetadataRef metadata) {
+		StringBuilder sb = new StringBuilder(256);
+		sb.append("select rev from vfsrevision rev")
+		  .append(" left join fetch rev.author as author")
+		  .append(" left join fetch author.user as authorUser")
+		  .append(" where rev.metadata.key=:metadataKey")
+		  .append(" order by rev.revisionNr");
+		return dbInstance.getCurrentEntityManager()
+			.createQuery(sb.toString(), VFSRevision.class)
+			.setParameter("metadataKey", metadata.getKey())
+			.getResultList();
+	}
+	
+	public List<VFSRevision> getRevisions(List<VFSMetadataRef> metadatas) {
+		if(metadatas == null || metadatas.isEmpty()) return new ArrayList<>();
+		
+		List<Long> metadataKeys = metadatas.stream().map(VFSMetadataRef::getKey).collect(Collectors.toList());
+		
+		StringBuilder sb = new StringBuilder(256);
+		sb.append("select rev from vfsrevision rev")
+		  .append(" left join fetch rev.author as author")
+		  .append(" left join fetch author.user as authorUser")
+		  .append(" where rev.metadata.key in (:metadataKeys)");
+		return dbInstance.getCurrentEntityManager()
+			.createQuery(sb.toString(), VFSRevision.class)
+			.setParameter("metadataKeys", metadataKeys)
+			.getResultList();
+	}
+	
+	public VFSRevision updateRevision(VFSRevision revision) {
+		return dbInstance.getCurrentEntityManager().merge(revision);
+	}
+	
+	public void deleteRevision(VFSRevision revision) {
+		VFSRevision reloadedRev = dbInstance.getCurrentEntityManager()
+				.getReference(VFSRevisionImpl.class, ((VFSRevisionImpl)revision).getKey());
+		dbInstance.getCurrentEntityManager().remove(reloadedRev);
+	}
+
+}
diff --git a/src/main/java/org/olat/core/commons/services/vfs/manager/VFSXStream.java b/src/main/java/org/olat/core/commons/services/vfs/manager/VFSXStream.java
index 870ab3505a25a881c74a17907c68fc14c82b9615..ea94e2f5b5ad325af5ec449b2d2712bade98da16 100644
--- a/src/main/java/org/olat/core/commons/services/vfs/manager/VFSXStream.java
+++ b/src/main/java/org/olat/core/commons/services/vfs/manager/VFSXStream.java
@@ -19,6 +19,7 @@
  */
 package org.olat.core.commons.services.vfs.manager;
 
+import java.io.File;
 import java.io.InputStream;
 
 import org.olat.basesecurity.BaseSecurity;
@@ -28,12 +29,12 @@ import org.olat.core.commons.services.license.LicenseService;
 import org.olat.core.commons.services.license.LicenseType;
 import org.olat.core.commons.services.license.model.LicenseTypeImpl;
 import org.olat.core.commons.services.vfs.VFSMetadata;
+import org.olat.core.commons.services.vfs.VFSRevision;
 import org.olat.core.commons.services.vfs.model.VFSMetadataImpl;
 import org.olat.core.id.Identity;
+import org.olat.core.util.StringHelper;
 import org.olat.core.util.vfs.VFSLeaf;
 import org.olat.core.util.vfs.version.RevisionFileImpl;
-import org.olat.core.util.vfs.version.VFSRevision;
-import org.olat.core.util.vfs.version.Versions;
 import org.olat.core.util.vfs.version.VersionsFileImpl;
 import org.olat.core.util.xml.XStreamHelper;
 
@@ -54,7 +55,7 @@ public class VFSXStream {
 		mystream = XStreamHelper.createXStreamInstance();
 		XStream.setupDefaultSecurity(mystream);
 		Class<?>[] types = new Class[] {
-				VersionsFileImpl.class, Versions.class, RevisionFileImpl.class, VFSRevision.class,
+				VersionsFileImpl.class, RevisionFileImpl.class, VFSRevision.class,
 				VFSMetadata.class, VFSMetadataImpl.class, Identity.class, IdentityImpl.class,
 				LicenseType.class, LicenseTypeImpl.class
 			};
@@ -77,18 +78,23 @@ public class VFSXStream {
 		mystream.omitField(VFSMetadataImpl.class, "thumbnails");
 
 		mystream.registerLocalConverter(VFSMetadataImpl.class, "licenseType", new LicenseTypeConverter());
-		mystream.registerLocalConverter(VFSMetadataImpl.class, "author", new IdentityConverter());	
+		mystream.registerLocalConverter(VFSMetadataImpl.class, "author", new IdentityConverter());
+		mystream.registerLocalConverter(RevisionFileImpl.class, "author", new IdentityConverter());	
 	}
 	
 	public static final Object read(InputStream in) {
 		return XStreamHelper.readObject(mystream, in);
 	}
 	
+	public static final Object read(File file) {
+		return XStreamHelper.readObject(mystream, file);
+	}
+	
 	public static final Object read(VFSLeaf leaf) {
 		return XStreamHelper.readObject(mystream, leaf);
 	}
 	
-	public static final void write(VFSLeaf leaf, Versions versions) {
+	public static final void write(VFSLeaf leaf, VersionsFileImpl versions) {
 		XStreamHelper.writeObject(mystream, leaf, versions);
 	}
 	
@@ -132,8 +138,15 @@ public class VFSXStream {
 
 		@Override
 		public Object fromString(String str) {
-			Long identityKey = Long.valueOf(str);
-			return CoreSpringFactory.getImpl(BaseSecurity.class).loadIdentityByKey(identityKey);
+			Identity identity = null;
+			if(StringHelper.isLong(str)) {
+				Long identityKey = Long.valueOf(str);
+				identity = CoreSpringFactory.getImpl(BaseSecurity.class).loadIdentityByKey(identityKey);
+			}
+			if(identity == null) {
+				identity = CoreSpringFactory.getImpl(BaseSecurity.class).findIdentityByName(str);
+			}
+			return identity;
 		}	
 	}
 }
diff --git a/src/main/java/org/olat/core/commons/services/vfs/model/VFSMetadataImpl.java b/src/main/java/org/olat/core/commons/services/vfs/model/VFSMetadataImpl.java
index bc0e8993f125225f3c43e88c29dc3d2d86786340..eed8e40e873e52ea454c680a55a8345b310f6edf 100644
--- a/src/main/java/org/olat/core/commons/services/vfs/model/VFSMetadataImpl.java
+++ b/src/main/java/org/olat/core/commons/services/vfs/model/VFSMetadataImpl.java
@@ -67,6 +67,8 @@ public class VFSMetadataImpl implements Persistable, VFSMetadata {
 	
 	@Column(name="f_uuid", nullable=false, insertable=true, updatable=true)
 	private String uuid;
+	@Column(name="f_deleted", nullable=false, insertable=true, updatable=true)
+	private boolean deleted;
 	@Column(name="f_filename", nullable=false, insertable=true, updatable=true)
 	private String filename;
 	@Column(name="f_relative_path", nullable=false, insertable=true, updatable=true)
@@ -129,6 +131,11 @@ public class VFSMetadataImpl implements Persistable, VFSMetadata {
 	@Column(name="f_locked", nullable=true, insertable=true, updatable=true)
 	private boolean locked;
 	
+	@Column(name="f_revision_nr", nullable=true, insertable=true, updatable=true)
+	private int revisionNr;
+	@Column(name="f_revision_comment", nullable=true, insertable=true, updatable=true)
+	private String revisionComment;
+	
 	@ManyToOne(targetEntity=IdentityImpl.class,fetch=FetchType.LAZY,optional=true)
 	@JoinColumn(name="fk_author", nullable=true, insertable=true, updatable=true)
 	private Identity author;
@@ -168,6 +175,15 @@ public class VFSMetadataImpl implements Persistable, VFSMetadata {
 		lastModified = date;
 	}
 
+	@Override
+	public boolean isDeleted() {
+		return deleted;
+	}
+
+	public void setDeleted(boolean deleted) {
+		this.deleted = deleted;
+	}
+
 	@Override
 	public String getFilename() {
 		return filename;
@@ -457,10 +473,12 @@ public class VFSMetadataImpl implements Persistable, VFSMetadata {
 		this.locked = locked;
 	}
 
+	@Override
 	public Boolean getCannotGenerateThumbnails() {
 		return cannotGenerateThumbnails;
 	}
 
+	@Override
 	public void setCannotGenerateThumbnails(Boolean cannotGenerateThumbnails) {
 		this.cannotGenerateThumbnails = cannotGenerateThumbnails;
 	}
@@ -473,6 +491,26 @@ public class VFSMetadataImpl implements Persistable, VFSMetadata {
 		this.materializedPathKeys = materializedPathKeys;
 	}
 
+	@Override
+	public int getRevisionNr() {
+		return revisionNr;
+	}
+
+	@Override
+	public void setRevisionNr(int revisionNr) {
+		this.revisionNr = revisionNr;
+	}
+
+	@Override
+	public String getRevisionComment() {
+		return revisionComment;
+	}
+
+	@Override
+	public void setRevisionComment(String revisionComment) {
+		this.revisionComment = revisionComment;
+	}
+
 	public VFSMetadata getParent() {
 		return parent;
 	}
diff --git a/src/main/java/org/olat/core/commons/services/vfs/model/VFSRevisionImpl.java b/src/main/java/org/olat/core/commons/services/vfs/model/VFSRevisionImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..d07dcff55f711419f18f2a97ec73817c4960e729
--- /dev/null
+++ b/src/main/java/org/olat/core/commons/services/vfs/model/VFSRevisionImpl.java
@@ -0,0 +1,393 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.commons.services.vfs.model;
+
+import java.util.Date;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+
+import org.olat.basesecurity.IdentityImpl;
+import org.olat.core.commons.services.license.LicenseType;
+import org.olat.core.commons.services.license.model.LicenseTypeImpl;
+import org.olat.core.commons.services.vfs.VFSMetadata;
+import org.olat.core.commons.services.vfs.VFSRevision;
+import org.olat.core.id.Identity;
+import org.olat.core.id.Persistable;
+
+/**
+ * 
+ * Initial date: 18 mars 2019<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+@Entity(name="vfsrevision")
+@Table(name="o_vfs_revision")
+public class VFSRevisionImpl implements Persistable, VFSRevision {
+
+	private static final long serialVersionUID = 2868142296811338251L;
+
+	@Id
+	@GeneratedValue(strategy = GenerationType.IDENTITY)
+	@Column(name="id", nullable=false, unique=true, insertable=true, updatable=false)
+	private Long key;
+	
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name="creationdate", nullable=false, insertable=true, updatable=false)
+	private Date creationDate;
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name="lastmodified", nullable=false, insertable=true, updatable=true)
+	private Date lastModified;
+
+	@Column(name="f_revision_nr", nullable=false, insertable=true, updatable=true)
+	private int revisionNr;
+	@Column(name="f_revision_filename", nullable=false, insertable=true, updatable=true)
+	private String filename;
+	@Column(name="f_revision_size", nullable=false, insertable=true, updatable=true)
+	private long size;
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name="f_revision_lastmodified", nullable=false, insertable=true, updatable=true)
+	private Date fileLastModified;
+	@Column(name="f_revision_comment", nullable=true, insertable=true, updatable=true)
+	private String revisionComment;
+	
+	@Column(name="f_comment", nullable=true, insertable=true, updatable=true)
+	private String comment;
+	@Column(name="f_title", nullable=true, insertable=true, updatable=true)
+	private String title;
+	@Column(name="f_publisher", nullable=true, insertable=true, updatable=true)
+	private String publisher;
+	@Column(name="f_creator", nullable=true, insertable=true, updatable=true)
+	private String creator;
+	@Column(name="f_source", nullable=true, insertable=true, updatable=true)
+	private String source;
+	@Column(name="f_city", nullable=true, insertable=true, updatable=true)
+	private String city;
+	@Column(name="f_pages", nullable=true, insertable=true, updatable=true)
+	private String pages;
+	@Column(name="f_language", nullable=true, insertable=true, updatable=true)
+	private String language;
+	@Column(name="f_url", nullable=true, insertable=true, updatable=true)
+	private String url;
+	@Column(name="f_pub_month", nullable=true, insertable=true, updatable=true)
+	private String pubMonth;
+	@Column(name="f_pub_year", nullable=true, insertable=true, updatable=true)
+	private String pubYear;
+
+	@ManyToOne(targetEntity=LicenseTypeImpl.class, optional=true)
+	@JoinColumn(name="fk_license_type", nullable=true, insertable=true, updatable=true)
+	private LicenseType licenseType;
+	@Column(name="f_license_type_name", nullable=true, insertable=true, updatable=true)
+	private String licenseTypeName;
+	@Column(name="f_license_text", nullable=true, insertable=true, updatable=true)
+	private String licenseText;
+	@Column(name="f_licensor", nullable=true, insertable=true, updatable=true)
+	private String licensor;
+	
+	
+	@ManyToOne(targetEntity=IdentityImpl.class,fetch=FetchType.LAZY,optional=true)
+	@JoinColumn(name="fk_author", nullable=true, insertable=true, updatable=true)
+	private Identity author;
+	@ManyToOne(targetEntity=VFSMetadataImpl.class,fetch=FetchType.LAZY,optional=false)
+	@JoinColumn(name="fk_metadata", nullable=false, insertable=true, updatable=false)
+	private VFSMetadata metadata;
+	
+	
+	@Override
+	public Long getKey() {
+		return key;
+	}
+	
+	public void setKey(Long key) {
+		this.key = key;
+	}
+
+	@Override
+	public Date getCreationDate() {
+		return creationDate;
+	}
+
+	public void setCreationDate(Date creationDate) {
+		this.creationDate = creationDate;
+	}
+
+	public void setLastModified(Date lastModified) {
+		this.lastModified = lastModified;
+	}
+
+	@Override
+	public Identity getAuthor() {
+		return author;
+	}
+	
+	public void setAuthor(Identity author) {
+		this.author = author;
+	}
+	
+	@Override
+	public Date getFileLastModified() {
+		return fileLastModified;
+	}
+	
+	public void setFileLastModified(Date date) {
+		this.fileLastModified = date;
+	}
+	
+	public String getFilename() {
+		return filename;
+	}
+
+	public void setFilename(String filename) {
+		this.filename = filename;
+	}
+
+	@Override
+	public int getRevisionNr() {
+		return revisionNr;
+	}
+	
+	public void setRevisionNr(int revision) {
+		this.revisionNr = revision;
+	}
+	
+	@Override
+	public String getRevisionComment() {
+		return revisionComment;
+	}
+	
+	public void setRevisionComment(String text) {
+		revisionComment = text;
+	}
+	
+	@Override
+	public String getName() {
+		return null;
+	}
+	
+	@Override
+	public long getSize() {
+		return size;
+	}
+	
+	public void setSize(long size) {
+		this.size = size;
+	}
+
+	public String getComment() {
+		return comment;
+	}
+
+	public void setComment(String comment) {
+		this.comment = comment;
+	}
+
+	public String getTitle() {
+		return title;
+	}
+
+	public void setTitle(String title) {
+		this.title = title;
+	}
+
+	public String getPublisher() {
+		return publisher;
+	}
+
+	public void setPublisher(String publisher) {
+		this.publisher = publisher;
+	}
+
+	public String getCreator() {
+		return creator;
+	}
+
+	public void setCreator(String creator) {
+		this.creator = creator;
+	}
+
+	public String getSource() {
+		return source;
+	}
+
+	public void setSource(String source) {
+		this.source = source;
+	}
+
+	public String getCity() {
+		return city;
+	}
+
+	public void setCity(String city) {
+		this.city = city;
+	}
+
+	public String getPages() {
+		return pages;
+	}
+
+	public void setPages(String pages) {
+		this.pages = pages;
+	}
+
+	public String getLanguage() {
+		return language;
+	}
+
+	public void setLanguage(String language) {
+		this.language = language;
+	}
+
+	public String getUrl() {
+		return url;
+	}
+
+	public void setUrl(String url) {
+		this.url = url;
+	}
+
+	public String getPubMonth() {
+		return pubMonth;
+	}
+
+	public void setPubMonth(String pubMonth) {
+		this.pubMonth = pubMonth;
+	}
+
+	public String getPubYear() {
+		return pubYear;
+	}
+
+	public void setPubYear(String pubYear) {
+		this.pubYear = pubYear;
+	}
+
+	public LicenseType getLicenseType() {
+		return licenseType;
+	}
+
+	public void setLicenseType(LicenseType licenseType) {
+		this.licenseType = licenseType;
+	}
+
+	public String getLicenseTypeName() {
+		return licenseTypeName;
+	}
+
+	public void setLicenseTypeName(String licenseTypeName) {
+		this.licenseTypeName = licenseTypeName;
+	}
+
+	public String getLicenseText() {
+		return licenseText;
+	}
+
+	public void setLicenseText(String licenseText) {
+		this.licenseText = licenseText;
+	}
+
+	public String getLicensor() {
+		return licensor;
+	}
+
+	public void setLicensor(String licensor) {
+		this.licensor = licensor;
+	}
+
+	public Date getLastModified() {
+		return lastModified;
+	}
+
+	@Override
+	public VFSMetadata getMetadata() {
+		return metadata;
+	}
+
+	public void setMetadata(VFSMetadata metadata) {
+		this.metadata = metadata;
+	}
+	
+	public void copyValues(VFSMetadata fromMeta) {
+		setComment(fromMeta.getComment());
+		setCity(fromMeta.getCity());
+		setCreator(fromMeta.getCreator());
+		setLanguage(fromMeta.getLanguage());
+		setPages(fromMeta.getPages());
+		String[] pubDates = fromMeta.getPublicationDate();
+		setPubYear(pubDates[0]);
+		setPubMonth(pubDates[1]);
+		setPublisher(fromMeta.getPublisher());
+		setSource(fromMeta.getSource());
+		setTitle(fromMeta.getTitle());
+		setUrl(fromMeta.getUrl());
+		setLicenseType(fromMeta.getLicenseType());
+		setLicenseTypeName(fromMeta.getLicenseTypeName());
+		setLicensor(fromMeta.getLicensor());
+		setLicenseText(fromMeta.getLicenseText());
+	}
+	
+	public void copyValues(VFSRevisionImpl fromMeta) {
+		setComment(fromMeta.getComment());
+		setCity(fromMeta.getCity());
+		setCreator(fromMeta.getCreator());
+		setLanguage(fromMeta.getLanguage());
+		setPages(fromMeta.getPages());
+		setPubYear(fromMeta.getPubYear());
+		setPubMonth(fromMeta.getPubMonth());
+		setPublisher(fromMeta.getPublisher());
+		setSource(fromMeta.getSource());
+		setTitle(fromMeta.getTitle());
+		setUrl(fromMeta.getUrl());
+		setLicenseType(fromMeta.getLicenseType());
+		setLicenseTypeName(fromMeta.getLicenseTypeName());
+		setLicensor(fromMeta.getLicensor());
+		setLicenseText(fromMeta.getLicenseText());
+	}
+
+	@Override
+	public int hashCode() {
+		return getKey() == null ? 221879 : getKey().hashCode();
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if(obj == this) {
+			return true;
+		}
+		if(obj instanceof VFSRevisionImpl) {
+			VFSRevisionImpl rev = (VFSRevisionImpl)obj;
+			return getKey() != null && getKey().equals(rev.getKey());
+		}
+		return super.equals(obj);
+	}
+
+	@Override
+	public boolean equalsByPersistableKey(Persistable persistable) {
+		return equals(persistable);
+	}
+}
diff --git a/src/main/java/org/olat/core/util/vfs/restapi/VFSStreamingOutput.java b/src/main/java/org/olat/core/commons/services/vfs/restapi/VFSStreamingOutput.java
similarity index 96%
rename from src/main/java/org/olat/core/util/vfs/restapi/VFSStreamingOutput.java
rename to src/main/java/org/olat/core/commons/services/vfs/restapi/VFSStreamingOutput.java
index ba11edb7aa0c6d288e10cc80145749ccd5173bf0..8a82e1eb2d519a266295f52f0c8bb6f381984950 100644
--- a/src/main/java/org/olat/core/util/vfs/restapi/VFSStreamingOutput.java
+++ b/src/main/java/org/olat/core/commons/services/vfs/restapi/VFSStreamingOutput.java
@@ -17,7 +17,7 @@
  * frentix GmbH, http://www.frentix.com
  * <p>
  */
-package org.olat.core.util.vfs.restapi;
+package org.olat.core.commons.services.vfs.restapi;
 
 import java.io.InputStream;
 import java.io.OutputStream;
diff --git a/src/main/java/org/olat/core/util/vfs/restapi/VFSWebServiceSecurityCallback.java b/src/main/java/org/olat/core/commons/services/vfs/restapi/VFSWebServiceSecurityCallback.java
similarity index 97%
rename from src/main/java/org/olat/core/util/vfs/restapi/VFSWebServiceSecurityCallback.java
rename to src/main/java/org/olat/core/commons/services/vfs/restapi/VFSWebServiceSecurityCallback.java
index 73e54f3de454b00141fb613fd4c1792e57943372..2e1c22917d40394a1aca27f3f351932d2839fa63 100644
--- a/src/main/java/org/olat/core/util/vfs/restapi/VFSWebServiceSecurityCallback.java
+++ b/src/main/java/org/olat/core/commons/services/vfs/restapi/VFSWebServiceSecurityCallback.java
@@ -17,7 +17,7 @@
  * frentix GmbH, http://www.frentix.com
  * <p>
  */
-package org.olat.core.util.vfs.restapi;
+package org.olat.core.commons.services.vfs.restapi;
 
 import org.olat.core.commons.services.notifications.SubscriptionContext;
 import org.olat.core.util.vfs.Quota;
diff --git a/src/main/java/org/olat/core/util/vfs/restapi/VFSWebservice.java b/src/main/java/org/olat/core/commons/services/vfs/restapi/VFSWebservice.java
similarity index 99%
rename from src/main/java/org/olat/core/util/vfs/restapi/VFSWebservice.java
rename to src/main/java/org/olat/core/commons/services/vfs/restapi/VFSWebservice.java
index 3c70f9b15f1e2180e3f1da3810544177007d4df3..a4fd665ccebe04394c286bb64d09e8848491e684 100644
--- a/src/main/java/org/olat/core/util/vfs/restapi/VFSWebservice.java
+++ b/src/main/java/org/olat/core/commons/services/vfs/restapi/VFSWebservice.java
@@ -17,7 +17,7 @@
  * frentix GmbH, http://www.frentix.com
  * <p>
  */
-package org.olat.core.util.vfs.restapi;
+package org.olat.core.commons.services.vfs.restapi;
 
 import java.io.ByteArrayInputStream;
 import java.io.File;
diff --git a/src/main/java/org/olat/core/commons/services/vfs/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/core/commons/services/vfs/ui/_i18n/LocalStrings_de.properties
new file mode 100644
index 0000000000000000000000000000000000000000..bfbc7319fefb66d29e60477dee89a76dce024b7e
--- /dev/null
+++ b/src/main/java/org/olat/core/commons/services/vfs/ui/_i18n/LocalStrings_de.properties
@@ -0,0 +1 @@
+#Mon Jan 25 15:05:06 CET 2010
\ No newline at end of file
diff --git a/src/main/java/org/olat/core/commons/services/vfs/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/core/commons/services/vfs/ui/_i18n/LocalStrings_en.properties
new file mode 100644
index 0000000000000000000000000000000000000000..1121af75e3c608b1794e69a2cd8cea07577ba61a
--- /dev/null
+++ b/src/main/java/org/olat/core/commons/services/vfs/ui/_i18n/LocalStrings_en.properties
@@ -0,0 +1 @@
+#Mon Jan 25 15:05:06 CET 2010
diff --git a/src/main/java/org/olat/core/commons/services/vfs/ui/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/core/commons/services/vfs/ui/_i18n/LocalStrings_fr.properties
new file mode 100644
index 0000000000000000000000000000000000000000..e41d2b6eaa109c20468bff62e73e4633b520ffd8
--- /dev/null
+++ b/src/main/java/org/olat/core/commons/services/vfs/ui/_i18n/LocalStrings_fr.properties
@@ -0,0 +1 @@
+#Mon Feb 08 13:20:57 CET 2010
diff --git a/src/main/java/org/olat/core/util/vfs/VFSRevisionMediaResource.java b/src/main/java/org/olat/core/commons/services/vfs/ui/media/VFSRevisionMediaResource.java
similarity index 73%
rename from src/main/java/org/olat/core/util/vfs/VFSRevisionMediaResource.java
rename to src/main/java/org/olat/core/commons/services/vfs/ui/media/VFSRevisionMediaResource.java
index 7b8db8a6a79ac2713611d22acf7bf92a293b07a4..aefbcfbd77908c3841b9bb78c45c9398a5bb9263 100644
--- a/src/main/java/org/olat/core/util/vfs/VFSRevisionMediaResource.java
+++ b/src/main/java/org/olat/core/commons/services/vfs/ui/media/VFSRevisionMediaResource.java
@@ -17,21 +17,31 @@
  * frentix GmbH, http://www.frentix.com
  * <p>
  */
-package org.olat.core.util.vfs;
+package org.olat.core.commons.services.vfs.ui.media;
 
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
 import java.io.InputStream;
+import java.util.Date;
 
 import javax.servlet.http.HttpServletResponse;
 
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.commons.services.vfs.VFSRepositoryService;
+import org.olat.core.commons.services.vfs.VFSRevision;
 import org.olat.core.gui.media.MediaResource;
 import org.olat.core.gui.media.ServletUtil;
+import org.olat.core.logging.OLog;
+import org.olat.core.logging.Tracing;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.WebappHelper;
-import org.olat.core.util.vfs.version.VFSRevision;
+import org.olat.core.util.vfs.VFSConstants;
 
 public class VFSRevisionMediaResource implements MediaResource {
 	
 	private static final String MIME_TYPE_OCTET_STREAM = "application/octet-stream";
+	private static final OLog log = Tracing.createLoggerFor(VFSRevisionMediaResource.class);
 
 	private String encoding;
 	private boolean forceDownload = false;
@@ -75,19 +85,26 @@ public class VFSRevisionMediaResource implements MediaResource {
 
 	@Override
 	public InputStream getInputStream() {
-		return revision.getInputStream();
+		File revFile = CoreSpringFactory.getImpl(VFSRepositoryService.class).getRevisionFile(revision);
+		InputStream in = null;
+		try {
+			in = new BufferedInputStream(new FileInputStream(revFile));
+		} catch(Exception e) {
+			log.error("", e);
+		}
+		return in;
 	}
 
 	@Override
 	public Long getLastModified() {
-		long lastModified = revision.getLastModified();
-		return (lastModified == VFSConstants.UNDEFINED) ? null : new Long(lastModified);
+		Date lastModified = revision.getFileLastModified();
+		return lastModified == null ? null : Long.valueOf(lastModified.getTime());
 	}
 
 	@Override
 	public Long getSize() {
 		long size = revision.getSize();
-		return (size == VFSConstants.UNDEFINED) ? null : new Long(size);
+		return (size == VFSConstants.UNDEFINED) ? null : Long.valueOf(size);
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/core/commons/services/vfs/ui/version/DeletedFileListController.java b/src/main/java/org/olat/core/commons/services/vfs/ui/version/DeletedFileListController.java
new file mode 100644
index 0000000000000000000000000000000000000000..680decec509369b3a2e260f7b5d7a8d473939190
--- /dev/null
+++ b/src/main/java/org/olat/core/commons/services/vfs/ui/version/DeletedFileListController.java
@@ -0,0 +1,286 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.commons.services.vfs.ui.version;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.olat.core.commons.modules.bc.commands.FolderCommand;
+import org.olat.core.commons.modules.bc.commands.FolderCommandStatus;
+import org.olat.core.commons.persistence.SortKey;
+import org.olat.core.commons.services.vfs.VFSMetadata;
+import org.olat.core.commons.services.vfs.VFSRepositoryService;
+import org.olat.core.commons.services.vfs.VFSRevision;
+import org.olat.core.commons.services.vfs.ui.version.DeletedFileListDataModel.DeletedCols;
+import org.olat.core.commons.services.vfs.ui.version.RevisionListDataModel.RevisionCols;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItem;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.DownloadLink;
+import org.olat.core.gui.components.form.flexible.elements.FlexiTableElement;
+import org.olat.core.gui.components.form.flexible.elements.FlexiTableSortOptions;
+import org.olat.core.gui.components.form.flexible.elements.FormLink;
+import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormEvent;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.BooleanCellRenderer;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.DateFlexiCellRenderer;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiColumnModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
+import org.olat.core.gui.components.link.Link;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.gui.control.generic.modal.DialogBoxController;
+import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory;
+import org.olat.core.util.vfs.VFSContainer;
+import org.olat.core.util.vfs.VFSManager;
+import org.olat.core.util.vfs.VFSMediaResource;
+import org.olat.core.util.vfs.callbacks.VFSSecurityCallback;
+import org.olat.user.UserManager;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * 
+ * Initial date: 21 mars 2019<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class DeletedFileListController extends FormBasicController {
+
+	private int status = FolderCommandStatus.STATUS_SUCCESS;
+
+	private FormLink deleteButton;
+	private FormLink restoreButton;
+	private FlexiTableElement tableEl;
+	private DeletedFileListDataModel tableModel;
+
+	private DialogBoxController dialogCtr;
+	
+	private int counter = 0;
+	private final VFSContainer container;
+	
+	@Autowired
+	private UserManager userManager;
+	@Autowired
+	private VFSRepositoryService vfsRepositoryService;
+	
+	public DeletedFileListController(UserRequest ureq, WindowControl wControl, VFSContainer container) {
+		super(ureq, wControl, "deleted_files");
+		this.container = container;
+		initForm(ureq);
+		loadModel();
+	}
+	
+	public int getStatus() {
+		return status;
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		VFSSecurityCallback secCallback = VFSManager.findInheritedSecurityCallback(container);
+		
+		FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, DeletedCols.id));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(DeletedCols.nr));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(DeletedCols.filename));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(DeletedCols.deletedBy, new IdentityCellRenderer(userManager)));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(DeletedCols.date, new DateFlexiCellRenderer(getLocale())));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(DeletedCols.download));
+		if (secCallback != null && secCallback.canWrite()) {
+			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(DeletedCols.restore, "restore",
+				new BooleanCellRenderer(new StaticFlexiCellRenderer(translate("version.restore"), "restore"), null)));
+		}
+		
+		tableModel = new DeletedFileListDataModel(columnsModel, getTranslator());
+		tableEl = uifactory.addTableElement(getWindowControl(), "table", tableModel, 24, false, getTranslator(), formLayout);
+		tableEl.setEmtpyTableMessageKey(translate("version.noDeletedFiles"));
+		tableEl.setMultiSelect(true);
+		FlexiTableSortOptions sortOptions = new FlexiTableSortOptions(true);
+		sortOptions.setDefaultOrderBy(new SortKey(RevisionCols.nr.name(), false));
+		tableEl.setSortSettings(sortOptions);
+		tableEl.setAndLoadPersistedPreferences(ureq, "deleted-file-list-v2");
+
+		if (secCallback != null) {
+			if (secCallback.canDeleteRevisionsPermanently()) {
+				deleteButton = uifactory.addFormLink("delete", formLayout, Link.BUTTON);
+			}
+			if (secCallback.canWrite()) {
+				restoreButton = uifactory.addFormLink("version.restore", formLayout, Link.BUTTON);
+			}
+		}
+		
+		uifactory.addFormCancelButton("cancel", formLayout, ureq, getWindowControl());
+	}
+	
+	@Override
+	protected void event(UserRequest ureq, Controller source, Event event) {
+		if (source == dialogCtr) {
+			if (DialogBoxUIFactory.isYesEvent(event)) {	
+				@SuppressWarnings("unchecked")
+				List<DeletedFileRow> rowsToDelete =  (List<DeletedFileRow>)dialogCtr.getUserObject();
+				doDelete(rowsToDelete);
+				fireEvent(ureq, FolderCommand.FOLDERCOMMAND_FINISHED);
+			}
+		}
+		super.event(ureq, source, event);
+	}
+
+	@Override
+	protected void formOK(UserRequest ureq) {
+		//
+	}
+
+	@Override
+	protected void formCancelled(UserRequest ureq) {
+		status = FolderCommandStatus.STATUS_CANCELED;
+		fireEvent(ureq, FolderCommand.FOLDERCOMMAND_FINISHED);
+	}
+
+	@Override
+	protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
+		if(restoreButton == source) {
+			doRestore(ureq);
+		} else if(deleteButton == source) {
+			doConfirmDelete(ureq);
+		} else if(tableEl == source) {
+			if(event instanceof SelectionEvent) {
+				SelectionEvent se = (SelectionEvent)event;
+				if("restore".equals(se.getCommand())) {
+					DeletedFileRow row = tableModel.getObject(se.getIndex());
+					doRestore(ureq, row);
+				}
+			}
+		}
+		super.formInnerEvent(ureq, source, event);
+	}
+
+	private void loadModel() {
+		VFSMetadata containerMetadata = vfsRepositoryService.getMetadataFor(container);
+		List<VFSMetadata> metadataList = vfsRepositoryService.getChildren(containerMetadata);
+		List<DeletedFileRow> rows = new ArrayList<>();
+		Map<VFSMetadata,DeletedFileRow> metaToRows = new HashMap<>();
+		for(VFSMetadata metadata:metadataList) {
+			if(metadata.isDeleted()) {
+				DeletedFileRow row = new DeletedFileRow(metadata);
+				rows.add(row);
+				metaToRows.put(metadata, row);
+			}
+		}
+
+		List<VFSRevision> revisionList = vfsRepositoryService.getRevisions(new ArrayList<>(rows));
+		for(VFSRevision revision:revisionList) {
+			DeletedFileRow row = metaToRows.get(revision.getMetadata());
+			if(row != null) {
+				row.addRevision(revision);
+			}
+		}
+		
+		for(DeletedFileRow row:rows) {
+			if(row.getLastRevision() != null) {
+				VFSMediaResource resource = new VFSMediaResource(null);
+				resource.setDownloadable(true);
+				DownloadLink download = uifactory.addDownloadLink("download" + (counter++), translate("download"), null, resource, tableEl);
+				row.setDownloadLink(download);
+			}
+		}
+		
+		tableModel.setObjects(rows);
+		tableEl.reset(true, true, true);
+	}
+
+	@Override
+	protected void doDispose() {
+	//
+	}
+
+	private void doConfirmDelete(UserRequest ureq) {
+		List<DeletedFileRow> versionsToDelete = getSelectedRows();
+		if (!versionsToDelete.isEmpty()) {
+			String msg = translate("version.del.confirm") + "<p>" + renderVersionsAsHtml(versionsToDelete) + "</p>";
+			// create dialog controller
+			dialogCtr = activateYesNoDialog(ureq, translate("version.del.header"), msg, dialogCtr);
+			dialogCtr.setUserObject(versionsToDelete);
+		}
+	}
+	
+	private String renderVersionsAsHtml(List<DeletedFileRow> rows) {
+		StringBuilder sb = new StringBuilder(256);
+		sb.append("<ul>");
+		for (DeletedFileRow row:rows) {
+			sb.append("<li>").append(row.getFilename()).append("</li>");
+		}
+		sb.append("</ul>");
+		return sb.toString();
+	}
+	
+	private void doDelete(List<DeletedFileRow> rowsToDelete) {
+		List<VFSRevision> revisionsToDelete = new ArrayList<>();
+		for(DeletedFileRow row:rowsToDelete) {
+			List<VFSRevision> rowRevisions = vfsRepositoryService.getRevisions(row.getMetadata());
+			revisionsToDelete.addAll(rowRevisions);
+		}
+		vfsRepositoryService.deleteRevisions(getIdentity(), revisionsToDelete);
+		status = FolderCommandStatus.STATUS_SUCCESS;
+	}
+	
+	private List<DeletedFileRow> getSelectedRows() {
+		Set<Integer> selectedIndexes = tableEl.getMultiSelectedIndex();
+		List<DeletedFileRow> selectedRows = new ArrayList<>(selectedIndexes.size());
+		for(Integer selectedIndex:selectedIndexes) {
+			DeletedFileRow row = tableModel.getObject(selectedIndex.intValue());
+			if(row != null) {
+				selectedRows.add(row);
+			}
+		}
+		return selectedRows;
+	}
+	
+	private void doRestore(UserRequest ureq, DeletedFileRow row) {
+		if (row.getLastRevision() != null && vfsRepositoryService.restoreRevision(getIdentity(), row.getLastRevision(), "")) {
+			status = FolderCommandStatus.STATUS_SUCCESS;
+			fireEvent(ureq, FolderCommand.FOLDERCOMMAND_FINISHED);
+		} else {
+			status = FolderCommandStatus.STATUS_FAILED;
+			// ERROR
+		}
+	}
+
+	private void doRestore(UserRequest ureq) {
+		List<DeletedFileRow> selectedRows = getSelectedRows();
+		boolean allOk = true;
+		for (DeletedFileRow selectedRow : selectedRows) {
+			if(selectedRow.getLastRevision() != null) {
+				allOk &= vfsRepositoryService.restoreRevision(getIdentity(), selectedRow.getLastRevision(), "");
+			}
+		}
+		if (allOk) {
+			status = FolderCommandStatus.STATUS_SUCCESS;
+			fireEvent(ureq, FolderCommand.FOLDERCOMMAND_FINISHED);
+		} else {
+			status = FolderCommandStatus.STATUS_FAILED;
+		}
+	}
+}
diff --git a/src/main/java/org/olat/core/commons/services/vfs/ui/version/DeletedFileListDataModel.java b/src/main/java/org/olat/core/commons/services/vfs/ui/version/DeletedFileListDataModel.java
new file mode 100644
index 0000000000000000000000000000000000000000..5be80561a36ea3c177929c615ffc857cd3e0f55c
--- /dev/null
+++ b/src/main/java/org/olat/core/commons/services/vfs/ui/version/DeletedFileListDataModel.java
@@ -0,0 +1,94 @@
+package org.olat.core.commons.services.vfs.ui.version;
+
+import java.util.List;
+
+import org.olat.core.commons.persistence.SortKey;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTableDataModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiSortableColumnDef;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableDataModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableModelDelegate;
+import org.olat.core.gui.translator.Translator;
+
+/**
+ * 
+ * Initial date: 21 mars 2019<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class DeletedFileListDataModel extends DefaultFlexiTableDataModel<DeletedFileRow>
+implements SortableFlexiTableDataModel<DeletedFileRow> {
+	
+	private final Translator translator;
+	
+	public DeletedFileListDataModel(FlexiTableColumnModel columnModel, Translator translator) {
+		super(columnModel);
+		this.translator = translator;
+	}
+
+	@Override
+	public void sort(SortKey orderBy) {
+		if(orderBy != null) {
+			List<DeletedFileRow> rows = new SortableFlexiTableModelDelegate<DeletedFileRow>(orderBy, this, translator.getLocale()).sort();
+			super.setObjects(rows);
+		}
+	}
+
+	@Override
+	public Object getValueAt(int row, int col) {
+		DeletedFileRow f = getObject(row);
+		return getValueAt(f, col);
+	}
+
+	@Override
+	public Object getValueAt(DeletedFileRow row, int col) {
+		switch(DeletedCols.values()[col]) {
+			case id: return row.getMetadata().getKey();
+			case nr: return row.getMetadata().getRevisionNr();
+			case filename: return row.getFilename();
+			case deletedBy: return row.getDeletedBy();
+			case date: return row.getDate();
+			case download: return row.getDownloadLink();
+			case restore: return row.getLastRevision() != null;
+			default: return "ERROR";
+		}
+	}
+
+	@Override
+	public DefaultFlexiTableDataModel<DeletedFileRow> createCopyWithEmptyList() {
+		return new DeletedFileListDataModel(getTableColumnModel(), translator);
+	}
+	
+	public enum DeletedCols implements FlexiSortableColumnDef {
+		
+		id("table.header.id"),
+		nr("table.header.nr"),
+		filename("table.header.file"),
+		deletedBy("version.deletedBy"),
+		date("table.header.date"),
+		download("download"),
+		restore("version.restore");
+
+		private final String i18nKey;
+		
+		private DeletedCols(String i18nKey) {
+			this.i18nKey = i18nKey;
+		}
+
+		@Override
+		public String i18nHeaderKey() {
+			return i18nKey;
+		}
+
+		@Override
+		public boolean sortable() {
+			return true;
+		}
+
+		@Override
+		public String sortKey() {
+			return name();
+		}
+	}
+
+}
diff --git a/src/main/java/org/olat/core/commons/services/vfs/ui/version/DeletedFileRow.java b/src/main/java/org/olat/core/commons/services/vfs/ui/version/DeletedFileRow.java
new file mode 100644
index 0000000000000000000000000000000000000000..c23ba84424524ca1c77a07d9410c442dc759da22
--- /dev/null
+++ b/src/main/java/org/olat/core/commons/services/vfs/ui/version/DeletedFileRow.java
@@ -0,0 +1,76 @@
+package org.olat.core.commons.services.vfs.ui.version;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import org.olat.core.commons.services.vfs.VFSMetadata;
+import org.olat.core.commons.services.vfs.VFSMetadataRef;
+import org.olat.core.commons.services.vfs.VFSRevision;
+import org.olat.core.gui.components.form.flexible.elements.DownloadLink;
+import org.olat.core.id.Identity;
+
+/**
+ * 
+ * Initial date: 21 mars 2019<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class DeletedFileRow implements VFSMetadataRef {
+	
+	private final VFSMetadata metadata;
+	private VFSRevision lastRevision;
+	private final List<VFSRevision> revisions = new ArrayList<>();
+	
+	private DownloadLink downloadLink;
+	
+	public DeletedFileRow(VFSMetadata metadata) {
+		this.metadata = metadata;
+	}
+	
+	@Override
+	public Long getKey() {
+		return metadata.getKey();
+	}
+	
+	public String getFilename() {
+		return metadata.getFilename();
+	}
+	
+	public Identity getDeletedBy() {
+		return lastRevision == null ? null : lastRevision.getAuthor();
+	}
+	
+	public Date getDate() {
+		return lastRevision == null ? null : lastRevision.getCreationDate();
+	}
+	
+	public VFSMetadata getMetadata() {
+		return metadata;
+	}
+	
+	public DownloadLink getDownloadLink() {
+		return downloadLink;
+	}
+	
+	public void setDownloadLink(DownloadLink link) {
+		downloadLink = link;
+	}
+	
+	public VFSRevision getLastRevision() {
+		return lastRevision;
+	}
+	
+	public List<VFSRevision> getRevisions() {
+		return revisions;
+	}
+	
+	public void addRevision(VFSRevision revision) {
+		if(revision == null) return;
+		
+		if(lastRevision == null || lastRevision.getRevisionNr() < revision.getRevisionNr()) {
+			lastRevision = revision;
+		}
+		revisions.add(revision);
+	}
+}
diff --git a/src/main/java/org/olat/core/commons/services/vfs/ui/version/IdentityCellRenderer.java b/src/main/java/org/olat/core/commons/services/vfs/ui/version/IdentityCellRenderer.java
new file mode 100644
index 0000000000000000000000000000000000000000..94404cd19164a68ffa2740cc819f9a7e224deb7c
--- /dev/null
+++ b/src/main/java/org/olat/core/commons/services/vfs/ui/version/IdentityCellRenderer.java
@@ -0,0 +1,36 @@
+package org.olat.core.commons.services.vfs.ui.version;
+
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiCellRenderer;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableComponent;
+import org.olat.core.gui.render.Renderer;
+import org.olat.core.gui.render.StringOutput;
+import org.olat.core.gui.render.URLBuilder;
+import org.olat.core.gui.translator.Translator;
+import org.olat.core.id.Identity;
+import org.olat.user.UserManager;
+
+/**
+ * 
+ * Initial date: 21 mars 2019<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class IdentityCellRenderer implements FlexiCellRenderer {
+	
+	private final UserManager userManager;
+	
+	public IdentityCellRenderer(UserManager userManager) {
+		this.userManager = userManager;
+	}
+
+	@Override
+	public void render(Renderer renderer, StringOutput target, Object cellValue, int row, FlexiTableComponent source,
+			URLBuilder ubu, Translator translator) {
+		if(cellValue instanceof Identity) {
+			String fullName = userManager.getUserDisplayName((Identity)cellValue);
+			if(fullName != null) {
+				target.append(fullName);
+			}
+		}
+	}
+}
diff --git a/src/main/java/org/olat/core/commons/services/vfs/ui/version/RevisionListController.java b/src/main/java/org/olat/core/commons/services/vfs/ui/version/RevisionListController.java
new file mode 100644
index 0000000000000000000000000000000000000000..90d44da895003f98c8328966bbef974c328da42c
--- /dev/null
+++ b/src/main/java/org/olat/core/commons/services/vfs/ui/version/RevisionListController.java
@@ -0,0 +1,264 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.commons.services.vfs.ui.version;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+import org.olat.basesecurity.BaseSecurity;
+import org.olat.basesecurity.IdentityShort;
+import org.olat.core.commons.modules.bc.commands.FolderCommand;
+import org.olat.core.commons.modules.bc.commands.FolderCommandStatus;
+import org.olat.core.commons.persistence.SortKey;
+import org.olat.core.commons.services.vfs.VFSMetadata;
+import org.olat.core.commons.services.vfs.VFSRepositoryService;
+import org.olat.core.commons.services.vfs.VFSRevision;
+import org.olat.core.commons.services.vfs.ui.media.VFSRevisionMediaResource;
+import org.olat.core.commons.services.vfs.ui.version.RevisionListDataModel.RevisionCols;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItem;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.DownloadLink;
+import org.olat.core.gui.components.form.flexible.elements.FlexiTableElement;
+import org.olat.core.gui.components.form.flexible.elements.FlexiTableSortOptions;
+import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormEvent;
+import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.BooleanCellRenderer;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.DateFlexiCellRenderer;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiColumnModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.gui.control.generic.modal.DialogBoxController;
+import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory;
+import org.olat.core.gui.media.MediaResource;
+import org.olat.core.util.StringHelper;
+import org.olat.core.util.vfs.VFSItem;
+import org.olat.core.util.vfs.VFSLeaf;
+import org.olat.core.util.vfs.VFSMediaResource;
+import org.olat.user.UserManager;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * 
+ * Initial date: 19 mars 2019<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class RevisionListController extends FormBasicController {
+
+	private int status = FolderCommandStatus.STATUS_SUCCESS;
+
+	private DialogBoxController confirmDeleteBoxCtr;
+	
+	private FlexiTableElement tableEl;
+	private RevisionListDataModel tableModel;
+	
+	private int counter = 0;
+	private final boolean readOnly;
+	private final VFSLeaf versionedFile;
+	
+	private final String title;
+	private final String description;
+	
+	@Autowired
+	private UserManager userManager;
+	@Autowired
+	private BaseSecurity securityManager;
+	@Autowired
+	private VFSRepositoryService vfsRepositoryService;
+
+	public RevisionListController(UserRequest ureq, WindowControl wControl, VFSItem versionedFile, boolean readOnly) {
+		this(ureq, wControl, versionedFile, null, null, readOnly);
+	}
+
+	public RevisionListController(UserRequest ureq, WindowControl wControl, VFSItem versionedFile,
+			String title, String description, boolean readOnly) {
+		super(ureq, wControl, "revisions");
+		
+		this.readOnly = readOnly;
+		this.title = title;
+		this.description = description;
+		this.versionedFile = (VFSLeaf)versionedFile;
+		
+		initForm(ureq);
+		loadModel(this.versionedFile);
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		if(formLayout instanceof FormLayoutContainer) {
+			FormLayoutContainer layoutCont = (FormLayoutContainer)formLayout;
+			if (StringHelper.containsNonWhitespace(title)) {
+				layoutCont.contextPut("title", title);
+			}
+			if (StringHelper.containsNonWhitespace(description)) {
+				layoutCont.contextPut("description", description);
+			}
+		}
+		
+		FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, RevisionCols.id));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(RevisionCols.nr));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(RevisionCols.author, new IdentityCellRenderer(userManager)));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(RevisionCols.comment));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(RevisionCols.date, new DateFlexiCellRenderer(getLocale())));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(RevisionCols.download));
+		if(!readOnly) {
+			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(RevisionCols.restore, "restore",
+					new BooleanCellRenderer(new StaticFlexiCellRenderer(translate("version.restore"), "restore"), null)));
+			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(RevisionCols.delete, "delete",
+					new BooleanCellRenderer(new StaticFlexiCellRenderer(translate("delete"), "delete"), null)));
+		}
+
+		tableModel = new RevisionListDataModel(columnsModel, getTranslator());
+		tableEl = uifactory.addTableElement(getWindowControl(), "table", tableModel, 24, false, getTranslator(), formLayout);
+		tableEl.setEmtpyTableMessageKey(translate("version.noRevisions"));
+		FlexiTableSortOptions sortOptions = new FlexiTableSortOptions(true);
+		sortOptions.setDefaultOrderBy(new SortKey(RevisionCols.nr.name(), false));
+		tableEl.setSortSettings(sortOptions);
+		tableEl.setAndLoadPersistedPreferences(ureq, "revisions-list");
+		
+		uifactory.addFormCancelButton("cancel", formLayout, ureq, getWindowControl());
+	}
+
+	@Override
+	protected void doDispose() {
+		//
+	}
+
+	private void loadModel(VFSLeaf versionedLeaf) {
+		VFSMetadata metadata = vfsRepositoryService.getMetadataFor(versionedLeaf);
+		List<VFSRevision> revisions = vfsRepositoryService.getRevisions(metadata);
+		List<RevisionRow> rows = new ArrayList<>(revisions.size() + 2);
+		VFSMediaResource resource = new VFSMediaResource(versionedFile);
+		resource.setDownloadable(true);
+		DownloadLink download = uifactory.addDownloadLink("download" + (counter++), translate("download"), null, resource, tableEl);
+		rows.add(new RevisionRow(metadata, download));
+		Collection<String> names = new HashSet<>();
+		for(VFSRevision revision:revisions) {
+			MediaResource revResource = new VFSRevisionMediaResource(revision, true);
+			DownloadLink revDownload = uifactory.addDownloadLink("download" + (counter++), translate("download"), null, revResource, tableEl);
+			rows.add(new RevisionRow(revision, revDownload));
+		}
+		
+		Map<String, IdentityShort> mappedIdentities = new HashMap<>();
+		for(IdentityShort identity :securityManager.findShortIdentitiesByName(names)) {
+			mappedIdentities.put(identity.getName(), identity);
+		}
+
+		tableModel.setObjects(rows);
+		tableEl.reset(true, true, true);
+	}
+
+	public int getStatus() {
+		return status;
+	}
+
+	@Override
+	protected void formOK(UserRequest ureq) {
+		//
+	}
+
+	@Override
+	protected void formCancelled(UserRequest ureq) {
+		fireEvent(ureq, Event.CANCELLED_EVENT);
+	}
+
+	@Override
+	protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
+		if(tableEl == source) {
+			if(event instanceof SelectionEvent) {
+				SelectionEvent se  = (SelectionEvent)event;
+				if("delete".equals(se.getCommand())) {
+					RevisionRow row = tableModel.getObject(se.getIndex());
+					doConfirmDelete(ureq, Collections.singletonList(row));
+				} else if("restore".equals(se.getCommand())) {
+					RevisionRow row = tableModel.getObject(se.getIndex());
+					doRestore(ureq, row);
+				}
+			}
+		}
+		super.formInnerEvent(ureq, source, event);
+	}
+
+	@Override
+	protected void event(UserRequest ureq, Controller source, Event event) {
+		if (source == confirmDeleteBoxCtr) {
+			doDeleteRevision(ureq, event);
+		}
+	}
+	
+	private void doRestore(UserRequest ureq, RevisionRow row) {
+		if(row.getRevision() == null) {
+			//restore current, do nothing
+			status = FolderCommandStatus.STATUS_SUCCESS;
+			fireEvent(ureq, FolderCommand.FOLDERCOMMAND_FINISHED);
+		} else {
+			VFSRevision version = row.getRevision();
+			String comment = translate("version.restore.comment", new String[]{ Integer.toString(version.getRevisionNr()) });
+			
+			boolean ok = vfsRepositoryService.restoreRevision(getIdentity(), version, comment);
+			if(ok) {
+				status = FolderCommandStatus.STATUS_SUCCESS;
+				fireEvent(ureq, FolderCommand.FOLDERCOMMAND_FINISHED);
+			} else {
+				status = FolderCommandStatus.STATUS_FAILED;
+				showError("version.restore.failed");
+				fireEvent(ureq, FolderCommand.FOLDERCOMMAND_FINISHED);
+			}
+		}
+	}
+	
+	private void doConfirmDelete(UserRequest ureq, List<RevisionRow> selectedRevisions) {
+		String numOfVersionToDelete = Integer.toString(selectedRevisions.size());
+		confirmDeleteBoxCtr = activateYesNoDialog(ureq, null, translate("version.confirmDelete",
+				new String[] { numOfVersionToDelete }), confirmDeleteBoxCtr);
+		confirmDeleteBoxCtr.setUserObject(selectedRevisions);
+	}
+	
+	private void doDeleteRevision(UserRequest ureq, Event event) {
+		if (DialogBoxUIFactory.isYesEvent(event)) {
+			@SuppressWarnings("unchecked")
+			List<RevisionRow> selectedVersions = (List<RevisionRow>) confirmDeleteBoxCtr.getUserObject();
+			List<VFSRevision> revisions = new ArrayList<>(selectedVersions.size());
+			for(RevisionRow selectedVersion:selectedVersions) {
+				if(selectedVersion.getRevision() != null) {
+					revisions.add(selectedVersion.getRevision());
+				}
+			}
+			vfsRepositoryService.deleteRevisions(getIdentity(), revisions);
+			status = FolderCommandStatus.STATUS_SUCCESS;
+		} else {
+			status = FolderCommandStatus.STATUS_CANCELED;
+		}
+		fireEvent(ureq, FolderCommand.FOLDERCOMMAND_FINISHED);
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/core/commons/services/vfs/ui/version/RevisionListDataModel.java b/src/main/java/org/olat/core/commons/services/vfs/ui/version/RevisionListDataModel.java
new file mode 100644
index 0000000000000000000000000000000000000000..ebe1fe77ab4fae0d36ac8dd64a76f3c9c2e27ba7
--- /dev/null
+++ b/src/main/java/org/olat/core/commons/services/vfs/ui/version/RevisionListDataModel.java
@@ -0,0 +1,121 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.commons.services.vfs.ui.version;
+
+import java.util.List;
+
+import org.olat.core.commons.persistence.SortKey;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTableDataModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiSortableColumnDef;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableDataModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableModelDelegate;
+import org.olat.core.gui.translator.Translator;
+import org.olat.core.util.StringHelper;
+
+/**
+ * 
+ * Initial date: 19 mars 2019<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class RevisionListDataModel extends DefaultFlexiTableDataModel<RevisionRow>
+implements SortableFlexiTableDataModel<RevisionRow> {
+	
+	private final Translator translator;
+	
+	public RevisionListDataModel(FlexiTableColumnModel columnModel, Translator translator) {
+		super(columnModel);
+		this.translator = translator;
+	}
+
+	@Override
+	public void sort(SortKey orderBy) {
+		if(orderBy != null) {
+			List<RevisionRow> rows = new SortableFlexiTableModelDelegate<RevisionRow>(orderBy, this, translator.getLocale()).sort();
+			super.setObjects(rows);
+		}
+	}
+
+	@Override
+	public Object getValueAt(int row, int col) {
+		RevisionRow rev = getObject(row);
+		return getValueAt(rev, col);
+	}
+
+	@Override
+	public Object getValueAt(RevisionRow row, int col) {
+		switch(RevisionCols.values()[col]) {
+			case id: return row.getKey();
+			case nr: return row.getRevisionNr();
+			case author: return row.getAuthor();
+			case comment: {
+				String comment = row.getComment();
+				if(!StringHelper.containsNonWhitespace(comment) && row.getRevisionNr() <= 1) {
+					comment = translator.translate("version.initialRevision");
+				}
+				return comment;
+			}
+			case date: return row.getRevisionDate();
+			case download: return row.getDownloadLink();
+			case restore:
+			case delete: return Boolean.valueOf(!row.isCurrent());
+			default: return "ERROR";
+		}
+	}
+
+	@Override
+	public RevisionListDataModel createCopyWithEmptyList() {
+		return new RevisionListDataModel(getTableColumnModel(), translator);
+	}
+	
+	public enum RevisionCols implements FlexiSortableColumnDef {
+		
+		id("table.header.id"),
+		nr("table.header.nr"),
+		author("table.header.author"),
+		comment("table.header.comment"),
+		date("table.header.date"),
+		download("download"),
+		restore("version.restore"),
+		delete("delete");
+
+		private final String i18nKey;
+		
+		private RevisionCols(String i18nKey) {
+			this.i18nKey = i18nKey;
+		}
+
+		@Override
+		public String i18nHeaderKey() {
+			return i18nKey;
+		}
+
+		@Override
+		public boolean sortable() {
+			return true;
+		}
+
+		@Override
+		public String sortKey() {
+			return name();
+		}
+	}
+}
diff --git a/src/main/java/org/olat/core/commons/services/vfs/ui/version/RevisionRow.java b/src/main/java/org/olat/core/commons/services/vfs/ui/version/RevisionRow.java
new file mode 100644
index 0000000000000000000000000000000000000000..77c8ee2c785a866563b94815749880894fceaa8f
--- /dev/null
+++ b/src/main/java/org/olat/core/commons/services/vfs/ui/version/RevisionRow.java
@@ -0,0 +1,102 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.commons.services.vfs.ui.version;
+
+import java.util.Date;
+
+import org.olat.core.commons.services.vfs.VFSMetadata;
+import org.olat.core.commons.services.vfs.VFSRevision;
+import org.olat.core.gui.components.form.flexible.elements.DownloadLink;
+import org.olat.core.id.Identity;
+import org.olat.core.id.Persistable;
+
+/**
+ * 
+ * Initial date: 19 mars 2019<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class RevisionRow {
+	
+	private boolean current;
+	
+	private int revisionNr;
+	private Identity author;
+	private String comment;
+	
+	private VFSRevision revision;
+	private VFSMetadata metadata;
+	private final DownloadLink downloadLink;
+	
+	public RevisionRow(VFSMetadata metadata, DownloadLink downloadLink) {
+		current = true;
+		this.metadata = metadata;
+		author = metadata.getAuthor();
+		this.downloadLink = downloadLink;
+	}
+	
+	public RevisionRow(VFSRevision revision, DownloadLink downloadLink) {
+		current = false;
+		revisionNr = revision.getRevisionNr();
+		author = revision.getAuthor();
+		comment = revision.getRevisionComment();
+		this.revision = revision;
+		this.downloadLink = downloadLink;
+	}
+
+	public boolean isCurrent() {
+		return current;
+	}
+	
+	public void setCurrent(boolean current) {
+		this.current = current;
+	}
+	
+	public Long getKey() {
+		if(isCurrent()) {
+			return metadata.getKey();
+		}
+		return revision instanceof Persistable ? ((Persistable)revision).getKey() : null;
+	}
+	
+	public int getRevisionNr() {
+		return current ? metadata.getRevisionNr() : revisionNr;
+	}
+	
+	public Identity getAuthor() {
+		return author;
+	}
+	
+	public String getComment() {
+		return comment;
+	}
+	
+	public Date getRevisionDate() {
+		return current ? metadata.getFileLastModified() : revision.getFileLastModified();
+	}
+	
+	public VFSRevision getRevision() {
+		return revision;
+	}
+
+	public DownloadLink getDownloadLink() {
+		return downloadLink;
+	}
+}
diff --git a/src/main/java/org/olat/admin/version/VersionAdminController.java b/src/main/java/org/olat/core/commons/services/vfs/ui/version/VersionAdminController.java
similarity index 97%
rename from src/main/java/org/olat/admin/version/VersionAdminController.java
rename to src/main/java/org/olat/core/commons/services/vfs/ui/version/VersionAdminController.java
index dc4ef0ee98e9ea51b7434d57fedba04203bce8e0..26d036de5cd93091ff77862021b90bed7875f413 100644
--- a/src/main/java/org/olat/admin/version/VersionAdminController.java
+++ b/src/main/java/org/olat/core/commons/services/vfs/ui/version/VersionAdminController.java
@@ -17,7 +17,7 @@
  * frentix GmbH, http://www.frentix.com
  * <p>
  */
-package org.olat.admin.version;
+package org.olat.core.commons.services.vfs.ui.version;
 
 import org.olat.admin.SystemAdminMainController;
 import org.olat.core.gui.UserRequest;
diff --git a/src/main/java/org/olat/core/commons/modules/bc/version/VersionCommentController.java b/src/main/java/org/olat/core/commons/services/vfs/ui/version/VersionCommentController.java
similarity index 98%
rename from src/main/java/org/olat/core/commons/modules/bc/version/VersionCommentController.java
rename to src/main/java/org/olat/core/commons/services/vfs/ui/version/VersionCommentController.java
index 4db3d33c1223da7bf2f8fae6692ac6e6d1393467..83f14c7533cf13cbe2070741c7a0143a794499d0 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/version/VersionCommentController.java
+++ b/src/main/java/org/olat/core/commons/services/vfs/ui/version/VersionCommentController.java
@@ -17,7 +17,7 @@
  * frentix GmbH, http://www.frentix.com
  * <p>
  */
-package org.olat.core.commons.modules.bc.version;
+package org.olat.core.commons.services.vfs.ui.version;
 
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
diff --git a/src/main/java/org/olat/admin/version/VersionMaintenanceForm.java b/src/main/java/org/olat/core/commons/services/vfs/ui/version/VersionMaintenanceForm.java
similarity index 86%
rename from src/main/java/org/olat/admin/version/VersionMaintenanceForm.java
rename to src/main/java/org/olat/core/commons/services/vfs/ui/version/VersionMaintenanceForm.java
index af67f3dac6064c0f2e07f1540da1232a6aba2fed..efc41d49e02592cd32ba47d636382fd7cca0e3e9 100644
--- a/src/main/java/org/olat/admin/version/VersionMaintenanceForm.java
+++ b/src/main/java/org/olat/core/commons/services/vfs/ui/version/VersionMaintenanceForm.java
@@ -17,16 +17,16 @@
  * frentix GmbH, http://www.frentix.com
  * <p>
  */
-package org.olat.admin.version;
+package org.olat.core.commons.services.vfs.ui.version;
 
 import java.text.DecimalFormat;
 import java.text.DecimalFormatSymbols;
-import java.util.List;
 import java.util.Locale;
 
 import org.olat.admin.SystemAdminMainController;
-import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.services.taskexecutor.TaskExecutorManager;
+import org.olat.core.commons.services.vfs.VFSRepositoryService;
+import org.olat.core.commons.services.vfs.VFSVersionModule;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItem;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
@@ -45,10 +45,7 @@ import org.olat.core.gui.control.generic.modal.DialogBoxController;
 import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory;
 import org.olat.core.util.Util;
 import org.olat.core.util.async.ProgressDelegate;
-import org.olat.core.util.vfs.version.OrphanVersion;
-import org.olat.core.util.vfs.version.SimpleVersionConfig;
-import org.olat.core.util.vfs.version.VFSRevision;
-import org.olat.core.util.vfs.version.VersionsManager;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * 
@@ -61,26 +58,26 @@ import org.olat.core.util.vfs.version.VersionsManager;
  *
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
- //fxdiff FXOLAT-127: file versions maintenance tool
 public class VersionMaintenanceForm extends FormBasicController implements ProgressDelegate {
 	
 	private FormLink cleanUpLink, pruneLink, showOrphanLink, orphanSize;
 	private StaticTextElement orphanSizeEl;
 	private CloseableModalController cmc;
-	private OrphanVersionsController orphansController;
 	private DialogBoxController confirmPrunehistoryBox;
 	private DialogBoxController confirmDeleteOrphansBox;
 	private ProgressController progressCtrl;
 	
-	private final VersionsManager versionsManager;
-	private final TaskExecutorManager taskExecutorManager;
+	@Autowired
+	private VFSVersionModule versionsModule;
+	@Autowired
+	private VFSRepositoryService versionsManager;
+	@Autowired
+	private TaskExecutorManager taskExecutorManager;
 	
 	public VersionMaintenanceForm(UserRequest ureq, WindowControl wControl) {
 		super(ureq, wControl);
 		// use combined translator from system admin main
 		setTranslator(Util.createPackageTranslator(SystemAdminMainController.class, ureq.getLocale(), getTranslator()));
-		versionsManager = CoreSpringFactory.getImpl(VersionsManager.class);
-		taskExecutorManager = CoreSpringFactory.getImpl(TaskExecutorManager.class);
 		
 		initForm(ureq);
 	}
@@ -113,10 +110,10 @@ public class VersionMaintenanceForm extends FormBasicController implements Progr
 
 	@Override
 	protected void event(UserRequest ureq, Controller source, Event event) {
-		if(source == orphansController) {
+		/* if(source == orphansController) {
 			cmc.deactivate();
 			cleanup();
-		} else if(source == confirmDeleteOrphansBox) {
+		} else */ if(source == confirmDeleteOrphansBox) {
 			if (DialogBoxUIFactory.isYesEvent(event)) {
 				doDeleteOrphans(ureq);
 			}
@@ -131,9 +128,7 @@ public class VersionMaintenanceForm extends FormBasicController implements Progr
 	}
 	
 	private void cleanup() {
-		removeAsListenerAndDispose(orphansController);
 		removeAsListenerAndDispose(cmc);
-		orphansController = null;
 		cmc = null;
 	}
 
@@ -145,11 +140,13 @@ public class VersionMaintenanceForm extends FormBasicController implements Progr
 	@Override
 	protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
 		if(source == showOrphanLink) {
-			List<OrphanVersion> orphans = versionsManager.orphans();
+			/*
+			List<OrphanVersion> orphans = new ArrayList<>();//TODO metadata versions versionsManager.orphans();
 			orphansController = new OrphanVersionsController(ureq, getWindowControl(), orphans);			
 			listenTo(orphansController);
 			cmc = new CloseableModalController(getWindowControl(), "close", orphansController.getInitialComponent());
 			cmc.activate();
+			*/
 		} else if(source == cleanUpLink) {
 			String text = translate("confirm.delete.orphans");
 			confirmDeleteOrphansBox = activateYesNoDialog(ureq, null, text, confirmDeleteOrphansBox);
@@ -179,7 +176,8 @@ public class VersionMaintenanceForm extends FormBasicController implements Progr
 		taskExecutorManager.execute(new Runnable() {
 			public void run() {
 				waitASecond();
-				versionsManager.deleteOrphans(VersionMaintenanceForm.this);
+				//TODO metadata versions 
+				//versionsManager.deleteOrphans(VersionMaintenanceForm.this);
 			}
 		});
 
@@ -197,14 +195,16 @@ public class VersionMaintenanceForm extends FormBasicController implements Progr
 		progressCtrl.setMessage(translate("version.prune.history"));
 		progressCtrl.setPercentagesEnabled(false);
 		progressCtrl.setUnitLabel("");
-		progressCtrl.setMax(versionsManager.countDirectories());
+		//TODO metadata versions 
+		//progressCtrl.setMax(versionsManager.countDirectories());
 		listenTo(progressCtrl);
 
 		taskExecutorManager.execute(new Runnable() {
 			public void run() {
 				waitASecond();
 				int numOfVersions = getNumOfVersions();
-				versionsManager.pruneHistory(numOfVersions, VersionMaintenanceForm.this);
+				//TODO metadata versions 
+				// versionsManager.pruneHistory(numOfVersions, VersionMaintenanceForm.this);
 			}
 		});
 
@@ -226,13 +226,14 @@ public class VersionMaintenanceForm extends FormBasicController implements Progr
 	}
 	
 	public int getNumOfVersions() {
-		SimpleVersionConfig config = (SimpleVersionConfig) CoreSpringFactory.getBean(SimpleVersionConfig.class);
-		return config.getMaxNumberOfVersionsProperty();
+		return versionsModule.getMaxNumberOfVersions();
 	}
 	
 	public final void calculateOrphanSize() {
 		long size = 0l;
-		List<OrphanVersion> orphans = versionsManager.orphans();
+		//TODO metadata versions 
+		/*
+		List<OrphanVersion> orphans = new ArrayList<> ();//versionsManager.orphans();
 		for(OrphanVersion orphan:orphans) {
 			List<VFSRevision> revisions = orphan.getVersions().getRevisions();
 			if(revisions != null) {
@@ -241,6 +242,7 @@ public class VersionMaintenanceForm extends FormBasicController implements Progr
 				}
 			}
 		}
+		*/
 
 		String unit = "KB";
 		double humanSize = size / 1024.0d;
diff --git a/src/main/java/org/olat/admin/version/VersionSettingsForm.java b/src/main/java/org/olat/core/commons/services/vfs/ui/version/VersionSettingsForm.java
similarity index 89%
rename from src/main/java/org/olat/admin/version/VersionSettingsForm.java
rename to src/main/java/org/olat/core/commons/services/vfs/ui/version/VersionSettingsForm.java
index 69dac4b6af731196061717160b43e71c74ce8c38..ad7770410a8179ba2dc887028ed0c61fc7f0200f 100644
--- a/src/main/java/org/olat/admin/version/VersionSettingsForm.java
+++ b/src/main/java/org/olat/core/commons/services/vfs/ui/version/VersionSettingsForm.java
@@ -17,10 +17,10 @@
  * frentix GmbH, http://www.frentix.com
  * <p>
  */
-package org.olat.admin.version;
+package org.olat.core.commons.services.vfs.ui.version;
 
 import org.olat.admin.SystemAdminMainController;
-import org.olat.core.CoreSpringFactory;
+import org.olat.core.commons.services.vfs.VFSVersionModule;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
 import org.olat.core.gui.components.form.flexible.elements.SingleSelection;
@@ -30,7 +30,7 @@ import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.util.Util;
-import org.olat.core.util.vfs.version.SimpleVersionConfig;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * 
@@ -43,7 +43,6 @@ import org.olat.core.util.vfs.version.SimpleVersionConfig;
  *
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
-//fxdiff FXOLAT-127: file versions maintenance tool
 public class VersionSettingsForm extends FormBasicController {
 	
 	private SingleSelection numOfVersions;
@@ -55,6 +54,9 @@ public class VersionSettingsForm extends FormBasicController {
 	private String[] values = new String[] {
 			"0","2","3","4","5","10","25","50","-1"
 	};
+	
+	@Autowired
+	private VFSVersionModule versionsModule;
 
 	public VersionSettingsForm(UserRequest ureq, WindowControl wControl) {
 		super(ureq, wControl);
@@ -125,12 +127,10 @@ public class VersionSettingsForm extends FormBasicController {
 	}
 
 	public int getNumOfVersions() {
-		SimpleVersionConfig config = CoreSpringFactory.getImpl(SimpleVersionConfig.class);
-		return config.getMaxNumberOfVersionsProperty();
+		return versionsModule.getMaxNumberOfVersions();
 	}
 	
 	public void setNumOfVersions(int maxNumber) {
-		SimpleVersionConfig config = (SimpleVersionConfig) CoreSpringFactory.getBean(SimpleVersionConfig.class);
-		config.setMaxNumberOfVersionsProperty(maxNumber);
+		versionsModule.setMaxNumberOfVersions(maxNumber);
 	}
 }
diff --git a/src/main/java/org/olat/admin/version/_content/admin.html b/src/main/java/org/olat/core/commons/services/vfs/ui/version/_content/admin.html
similarity index 100%
rename from src/main/java/org/olat/admin/version/_content/admin.html
rename to src/main/java/org/olat/core/commons/services/vfs/ui/version/_content/admin.html
diff --git a/src/main/java/org/olat/core/commons/services/vfs/ui/version/_content/deleted_files.html b/src/main/java/org/olat/core/commons/services/vfs/ui/version/_content/deleted_files.html
new file mode 100644
index 0000000000000000000000000000000000000000..633452cabb3cc5568bc14b6cb542d9b5441efa23
--- /dev/null
+++ b/src/main/java/org/olat/core/commons/services/vfs/ui/version/_content/deleted_files.html
@@ -0,0 +1,10 @@
+$r.render("table")
+<div class="o_button_group">
+	$r.render("cancel")
+	#if($r.available("version.restore"))
+		$r.render("version.restore")
+	#end
+	#if($r.available("delete"))
+		$r.render("delete")
+	#end
+</div>
\ No newline at end of file
diff --git a/src/main/java/org/olat/core/commons/modules/bc/version/_content/revisions.html b/src/main/java/org/olat/core/commons/services/vfs/ui/version/_content/revisions.html
similarity index 55%
rename from src/main/java/org/olat/core/commons/modules/bc/version/_content/revisions.html
rename to src/main/java/org/olat/core/commons/services/vfs/ui/version/_content/revisions.html
index cf46480a75b14198b8676913f93d6399a5d78f75..a186da0e3442b3d7fc4dae564d99b08856fcb814 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/version/_content/revisions.html
+++ b/src/main/java/org/olat/core/commons/services/vfs/ui/version/_content/revisions.html
@@ -4,4 +4,7 @@
 #if ($description)
 	<p class="o_info">$description</p>
 #end
-$r.render("revisionList")
\ No newline at end of file
+$r.render("table")
+<div class="o_button_group">
+	$r.render("cancel")
+</div>
\ No newline at end of file
diff --git a/src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_ar.properties b/src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_ar.properties
similarity index 73%
rename from src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_ar.properties
rename to src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_ar.properties
index 51ad38e5a05215c83f921baae510cbde3bb2b39a..bca4ce4026d6e0239a75ae3a32f08e533c543601 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_ar.properties
+++ b/src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_ar.properties
@@ -1,4 +1,17 @@
-#Mon Feb 15 09:33:55 CET 2010
+#Mon Feb 22 14:19:03 CET 2010
+
+
+
+
+
+form.version=\u0627\u0644\u0625\u0635\u062F\u0627\u0631\u0627\u062A
+
+version.intro=\u064A\u0631\u062C\u0649 \u0648\u0636\u0639 \u0627\u0644\u0639\u062F\u062F \u0627\u0644\u0623\u0642\u0635\u0649 \u0645\u0646 \u0627\u0644\u0625\u0635\u062F\u0627\u0631\u0627\u062A \u0641\u0649 \u0627\u0644\u0645\u062C\u0644\u062F (\u0645\u062C\u0644\u062F \u0627\u0644\u0645\u062C\u0645\u0648\u0639\u0629\u060C \u0645\u062C\u0644\u062F \u0627\u0644\u0645\u0642\u0631\u0631\u060C \u0625\u0627\u0644\u062E).
+version.notANumber=\u0644\u0645 \u064A\u062A\u0645 \u062A\u062D\u062F\u064A\u062F \u0631\u0642\u0645
+version.numOfVersions=\u0631\u0642\u0645 \u0627\u0644\u0625\u0635\u062F\u0627\u0631\u0627\u062A
+version.off=\u062A\u0639\u0637\u064A\u0644 \u0627\u0644\u0625\u0635\u062F\u0627\u0631\u0627\u062A
+version.title=\u0627\u0644\u0625\u0635\u062F\u0627\u0631\u0627\u062A
+version.unlimited=\u063A\u064A\u0631 \u0645\u062D\u062F\u0648\u062F
 meta.comment.title=\u0625\u063A\u0644\u0627\u0642
 meta.locked=\u0627\u0644\u0645\u0644\u0641 \u0645\u063A\u0644\u0642
 meta.retainlock=\u0645\u062A\u0627\u0628\u0639\u0629 \u0625\u063A\u0644\u0627\u0642 \u0627\u0644\u0645\u0644\u0641 \u0639\u0646 \u0627\u0644\u0645\u0633\u062A\u062E\u062F\u0645\u064A\u0646 \u0627\u0644\u0623\u062E\u0631\u064A\u064A\u0646
@@ -23,3 +36,4 @@ version.nr=\u0645\u0631\u0627\u062C\u0639\u0629
 version.restore=\u0627\u0633\u062A\u0631\u062C\u0627\u0639
 version.restore.comment={0} \u062A\u0645 \u0627\u0633\u062A\u0631\u062C\u0627\u0639 \u0627\u0644\u0625\u0635\u062F\u0627\u0631
 version.restore.failed=\u0644\u0627 \u064A\u0645\u0643\u0646 \u0627\u0633\u062A\u0639\u0627\u062F\u0629 \u0627\u0644\u0645\u0644\u0641.
+
diff --git a/src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_de.properties
new file mode 100644
index 0000000000000000000000000000000000000000..99ea6277d072b6984e7a2c9884624b159a591f5e
--- /dev/null
+++ b/src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_de.properties
@@ -0,0 +1,60 @@
+#Mon Mar 02 09:54:03 CET 2009
+form.version=Versionierung
+version.intro=Stellen Sie die maximale Anzahl von Versionen f\u00fcr eine Datei einer Ordnerkomponente (Gruppenordner, Kursordner etc.) ein.
+version.title=Versionierung
+version.numOfVersions=Anzahl Versionen
+version.notANumber=Keine Zahl gew\u00e4hlt
+version.unlimited=Unlimitiert
+version.off=Versionierung ausgeschaltet
+version.clean.up=Orphan Versionen l\u00f6schen
+version.orphan.size=Orphan Versionen Gr\u00f6sse
+version.orphan.size.calc=Gr\u00f6sse rechnen
+version.orphan.size.calculating=Gr\u00f6sse am rechnen...
+version.show.orphans=Orphan Versionen auflisten
+version.prune.history=Versionen aufr\u00e4umen
+version.maintenance.title=Verwaltung
+version.maintenance.intro=Verwaltung von Versionen
+table.header.file=Datei
+table.header.versions=Anzhal Versionen
+table.header.size=Gr\u00f6sse
+table.empty=Keine orphan Versionen \u00fcbrig
+table.header.author=Autor
+table.header.comment=Kommentar
+table.header.date=Datum
+download=Herunterladen
+table.header.id=Id
+version.name=Datei
+version.noDeletedFiles=Es gibt keine gel\u00F6schten Dateien unter der Dokument-Kontrolle.
+version.noRevisions=Es gibt noch keine Revision dieser Datei.
+table.header.nr=Revision
+version.initialRevision=Initiale Version
+version.restore=Wiederherstellen
+version.confirmDelete=Wollen Sie wirklich {0} Revision(en) l\u00F6schen?
+dx=dr
+confirm.delete.orphans=Wollen Sie wirklich alle Orphan Versionen l\u00f6schen?
+confirm.prune.history=Wollen Sie wirklich die \u00fcberfl\u00fcssige Versionen l\u00f6schen?
+version.author=Autor
+version.comment=Kommentar
+version.date=Datum
+version.deletedBy=Gel\u00F6scht von
+version.deletedFiles=Gel\u00F6schte Dateien
+version.download=Herunterladen
+version.name=Datei
+version.noDeletedFiles=Es gibt keine gel\u00F6schten Dateien unter der Dokument-Kontrolle.
+version.noRevisions=Es gibt noch keine Revision dieser Datei.
+version.nr=Revision
+version.initialRevision=Initiale Version
+version.restore=Wiederherstellen
+version.confirmDelete=Wollen Sie wirklich {0} Revision(en) l\u00F6schen?
+version.comment=Kommentar
+version.comment.title=Kommentar
+version.comment.alltitle=Kommentar / Sperre
+version.comment.description=Dieses Dokument steht unter Dokument-Kontrolle. Bitte kommentieren Sie die gemachten \u00c4nderungen.
+version.del.confirm=Wollen Sie folgende Dateien wirklich endg\u00FCltig l\u00F6schen?
+version.del.header=L\u00F6schen best\u00E4tigen
+version.restore.failed=Datei konnte nicht wiederhergestellt werden.
+version.restore.comment=Version {0} wiederhergestellt
+meta.comment.title=Sperre
+meta.locked=Dateisperre
+meta.retainlock=Die Datei f\u00FCr andere Benutzer gesperrt lassen
+meta.unlock=Die Datei f\u00FCr andere Benutzer frei geben
diff --git a/src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_el.properties b/src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_el.properties
similarity index 74%
rename from src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_el.properties
rename to src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_el.properties
index 9f17c8a7cd302d865de57dd18cd2395f0b22c807..f3e56e5911a0dda68cb29f31cda6a5bd2517f66d 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_el.properties
+++ b/src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_el.properties
@@ -1,4 +1,5 @@
-#Thu Mar 11 13:39:32 CET 2010
+#Fri Mar 12 16:12:40 CET 2010
+form.version=\u0395\u03BA\u03B4\u03CC\u03C3\u03B5\u03B9\u03C2
 meta.comment.title=\u039A\u03BB\u03B5\u03AF\u03B4\u03C9\u03BC\u03B1
 meta.locked=\u0391\u03C1\u03C7\u03B5\u03AF\u03BF \u03BA\u03BB\u03B5\u03B9\u03B4\u03C9\u03BC\u03AD\u03BD\u03BF
 meta.retainlock=\u03A3\u03C5\u03BD\u03AD\u03C7\u03B5\u03B9\u03B1 \u03BA\u03BB\u03B5\u03B9\u03B4\u03CE\u03BC\u03B1\u03C4\u03BF\u03C2 \u03C4\u03BF\u03C5 \u03B1\u03C1\u03C7\u03B5\u03AF\u03BF\u03C5 \u03B3\u03B9\u03B1 \u03C4\u03BF\u03C5\u03C2 \u03AC\u03BB\u03BB\u03BF\u03C5\u03C2 \u03C7\u03C1\u03AE\u03C3\u03C4\u03B5\u03C2
@@ -23,3 +24,9 @@ version.nr=\u0391\u03BD\u03B1\u03B8\u03B5\u03CE\u03C1\u03B7\u03C3\u03B7
 version.restore=\u0391\u03C0\u03BF\u03BA\u03B1\u03C4\u03AC\u03C3\u03C4\u03B1\u03C3\u03B7
 version.restore.comment=\u0388\u03BA\u03B4\u03BF\u03C3\u03B7 {0} \u03B1\u03C0\u03BF\u03BA\u03B1\u03C4\u03B1\u03C3\u03C4\u03AC\u03B8\u03B7\u03BA\u03B5
 version.restore.failed=\u03A4\u03BF \u03B1\u03C1\u03C7\u03B5\u03AF\u03BF \u03B4\u03B5\u03BD \u03B8\u03B1 \u03BC\u03C0\u03BF\u03C1\u03BF\u03CD\u03C3\u03B5 \u03BD\u03B1 \u03B1\u03C0\u03BF\u03BA\u03B1\u03C4\u03B1\u03C3\u03C4\u03B1\u03B8\u03B5\u03AF.
+version.intro=\u03A0\u03B1\u03C1\u03B1\u03BA\u03B1\u03BB\u03CE \u03C1\u03C5\u03B8\u03BC\u03AF\u03C3\u03C4\u03B5 \u03C4\u03BF \u03BC\u03AD\u03B3\u03B9\u03C3\u03C4\u03BF \u03B1\u03C1\u03B9\u03B8\u03BC\u03CC \u03C4\u03C9\u03BD \u03B5\u03BA\u03B4\u03CC\u03C3\u03B5\u03C9\u03BD \u03B3\u03B9\u03B1 \u03AD\u03BD\u03B1 \u03C3\u03C4\u03BF\u03B9\u03C7\u03B5\u03AF\u03BF \u03C4\u03BF\u03C5 \u03C6\u03B1\u03BA\u03AD\u03BB\u03BF\u03C5 (\u03C6\u03AC\u03BA\u03B5\u03BB\u03BF\u03C2 \u03BF\u03BC\u03AC\u03B4\u03B1\u03C2, \u03C6\u03AC\u03BA\u03B5\u03BB\u03BF\u03C2 \u03BC\u03B1\u03B8\u03AE\u03BC\u03B1\u03C4\u03BF\u03C2 \u03BA\u03C4\u03BB.)
+version.notANumber=\u0394\u03B5\u03BD \u03B5\u03C0\u03B9\u03BB\u03AD\u03C7\u03B8\u03B7\u03BA\u03B5 \u03B1\u03C1\u03B9\u03B8\u03BC\u03CC\u03C2
+version.numOfVersions=\u0391\u03C1\u03B9\u03B8\u03BC\u03CC\u03C2 \u03B5\u03BA\u03B4\u03CC\u03C3\u03B5\u03C9\u03BD
+version.off=\u039F\u03B9 \u03B5\u03BA\u03B4\u03CC\u03C3\u03B5\u03B9\u03C2 \u03AD\u03C7\u03BF\u03C5\u03BD \u03B1\u03C0\u03B5\u03BD\u03B5\u03C1\u03B3\u03BF\u03C0\u03BF\u03B9\u03B7\u03B8\u03B5\u03AF
+version.title=\u0395\u03BA\u03B4\u03CC\u03C3\u03B5\u03B9\u03C2
+version.unlimited=\u0391\u03C0\u03B5\u03C1\u03B9\u03CC\u03C1\u03B9\u03C3\u03C4\u03BF\u03C2
diff --git a/src/main/java/org/olat/admin/version/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_en.properties
similarity index 50%
rename from src/main/java/org/olat/admin/version/_i18n/LocalStrings_en.properties
rename to src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_en.properties
index 67a8beefbd7fbc189741283a92f8d75ab1d80c7e..3c999ef2934e55acb7345ffdf1ba6602d37e3126 100644
--- a/src/main/java/org/olat/admin/version/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_en.properties
@@ -1,15 +1,31 @@
 #Tue Dec 18 22:46:41 CET 2012
-
-
-
-
-
-
-
 confirm.delete.orphans=Do you really want to delete all orphan versions?
 confirm.prune.history=Do you really want to delete all versions that exceed the configured version limit?
 form.version=Versioning
-
+meta.comment.title=Lock
+meta.locked=File locked
+meta.retainlock=Continue locking of file for other users
+meta.unlock=Unlock file for other users
+version.author=Author
+version.comment=Comment
+version.comment.alltitle=Comment/lock
+version.comment.description=Changes are tracked in this document. Please comment your modifications.
+version.comment.title=Comment
+version.confirmDelete=Do you really want to delete {0} revision(s)?
+version.date=Date
+version.del.confirm=Do you really want to delete the following files for good?
+version.del.header=Confirm deletion
+version.deletedBy=Deleted by
+version.deletedFiles=Deleted files
+version.download=Download
+version.initialRevision=Initial version
+version.name=File
+version.noDeletedFiles=There are no deleted files with a change log.
+version.noRevisions=There are no revisions of this file yet.
+version.nr=Revision
+version.restore=Restore
+version.restore.comment=Version {0} restored
+version.restore.failed=File could not be restored.
 table.empty=No orphan version left
 table.header.file=File
 table.header.size=Size
diff --git a/src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_fr.properties
similarity index 51%
rename from src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_fr.properties
rename to src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_fr.properties
index fc353b3b3354542293313783c729d04bb4dc2064..43afa6031d06ded34ae8bc83939750d9109b6e1d 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_fr.properties
+++ b/src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_fr.properties
@@ -1,4 +1,8 @@
-#Mon Feb 08 13:20:57 CET 2010
+#Sat Nov 02 20:59:58 CET 2013
+
+confirm.delete.orphans=Voulez-vous vraiment effacer toutes les versions orphelines?
+confirm.prune.history=Voulez-vous vraiment effacer toutes les versions qui d\u00E9passent la limite configur\u00E9e?
+form.version=V\u00E9rification des version
 meta.comment.title=Blocage
 meta.locked=Blocage fichier
 meta.retainlock=Maintenir le blocage du fichier pour d'autres utilisateurs
@@ -23,3 +27,22 @@ version.nr=R\u00E9vision
 version.restore=Restaurer
 version.restore.comment=Version {0} restaur\u00E9e
 version.restore.failed=Le fichier n'a pas pu \u00EAtre restaur\u00E9.
+
+table.empty=Aucune version orpheline ne reste
+table.header.file=Fichier
+table.header.size=Taille
+table.header.versions=Nombre de versions
+version.clean.up=Supprimer les versions orphelines
+version.intro=Etablir le nombre maximal de versions pour un fichier d'un dossier (dossier de groupe, dossier de cours etc.).
+version.maintenance.intro=Administration des versions
+version.maintenance.title=Administration
+version.notANumber=Aucun nombre choisi
+version.numOfVersions=Nombre de versions
+version.off=V\u00E9rification des versions d\u00E9sactiv\u00E9s
+version.orphan.size=Taille des versions orphelines
+version.orphan.size.calc=Calculer la taille
+version.orphan.size.calculating=Taille en cours de calcul
+version.prune.history=Nettoyer les versions
+version.show.orphans=Liste des versions orphelines
+version.title=V\u00E9rification des versions
+version.unlimited=Illimit\u00E9
diff --git a/src/main/java/org/olat/admin/version/_i18n/LocalStrings_it.properties b/src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_it.properties
similarity index 50%
rename from src/main/java/org/olat/admin/version/_i18n/LocalStrings_it.properties
rename to src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_it.properties
index ae5ba0f4d95db0e99e08df301f41cbec34f9e3b5..c452e4adf1a545ad3d6766d6afeb0de7e8731456 100644
--- a/src/main/java/org/olat/admin/version/_i18n/LocalStrings_it.properties
+++ b/src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_it.properties
@@ -1,4 +1,29 @@
 #Mon Feb 13 14:15:30 CET 2017
+meta.comment.title=Bloccaggio
+meta.locked=Bloccaggio file
+meta.retainlock=Mantenere bloccato il file per altri utenti
+meta.unlock=Sbloccare il file per altri utenti
+version.author=Autore
+version.comment=Commento
+version.comment.alltitle=Commento / Bloccaggio
+version.comment.description=Le modifiche a questo documento vengono registrate. Commenti le Sue modifiche, p.f.
+version.comment.title=Commento
+version.confirmDelete=Desidera veramente eliminare {0} revisione/i?
+version.date=Data
+version.del.confirm=Desidera veramente eliminare definitivamente questi file?
+version.del.header=Confermare eliminazione
+version.deletedBy=Eliminato da
+version.deletedFiles=File eliminati
+version.download=Scaricare
+version.initialRevision=Versione iniziale
+version.name=File
+version.noDeletedFiles=Non ci sono file eliminati che avevano modifiche registrate.
+version.noRevisions=Non ci sono ancora revisioni di questo file.
+version.nr=Revisione
+version.restore=Recuperare
+version.restore.comment=Versione {0} recuperata
+version.restore.failed=Il file non pu\u00F2 essere recuperato.
+
 confirm.delete.orphans=Vuoi veramente eliminare tutte le versioni orfane?
 confirm.prune.history=Vuoi veramente eliminare tutte le versioni che eccedono il limite di versione configurato?
 form.version=Controllo delle versioni
diff --git a/src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_jp.properties b/src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_jp.properties
similarity index 75%
rename from src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_jp.properties
rename to src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_jp.properties
index 9cd24cfa9232c3db4bd9f8c317cdade6794c1ee2..1d97958702f8e247db20d3c807c521a41f007498 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_jp.properties
+++ b/src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_jp.properties
@@ -1,4 +1,5 @@
-#Fri Apr 09 21:02:51 CEST 2010
+#Thu Sep 23 20:31:41 CEST 2010
+form.version=\u30D0\u30FC\u30B8\u30E7\u30CB\u30F3\u30B0
 meta.comment.title=\u30ED\u30C3\u30AF
 meta.locked=\u30D5\u30A1\u30A4\u30EB\u304C\u30ED\u30C3\u30AF\u3055\u308C\u307E\u3057\u305F\u3002
 meta.retainlock=\u4ED6\u306E\u30E6\u30FC\u30B6\u306B\u5BFE\u3057\u3066\u3001\u30D5\u30A1\u30A4\u30EB\u30ED\u30C3\u30AF\u3092\u7D9A\u3051\u308B
@@ -23,3 +24,9 @@ version.nr=\u30EA\u30D3\u30B8\u30E7\u30F3
 version.restore=\u30EA\u30B9\u30C8\u30A2
 version.restore.comment=\u30D0\u30FC\u30B8\u30E7\u30F3 {0} \u304C\u30EA\u30B9\u30C8\u30A2\u3055\u308C\u307E\u3057\u305F\u3002
 version.restore.failed=\u30D5\u30A1\u30A4\u30EB\u3092\u30EA\u30B9\u30C8\u30A2\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002
+version.intro=\u30D5\u30A9\u30EB\u30C0\u69CB\u6210\u30D5\u30A1\u30A4\u30EB (\u30B0\u30EB\u30FC\u30D7\u30D5\u30A9\u30EB\u30C0\u3001\u30B3\u30FC\u30B9\u30D5\u30A9\u30EB\u30C0\u7B49) \u306E\u6700\u5927\u30D0\u30FC\u30B8\u30E7\u30F3\u6570\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002
+version.notANumber=\u6570\u304C\u9078\u629E\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002
+version.numOfVersions=\u30D0\u30FC\u30B8\u30E7\u30F3\u6570
+version.off=\u30D0\u30FC\u30B8\u30E7\u30CB\u30F3\u30B0\u7121\u52B9
+version.title=\u30D0\u30FC\u30B8\u30E7\u30CB\u30F3\u30B0
+version.unlimited=\u7121\u5236\u9650
diff --git a/src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_nl_NL.properties b/src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_nl_NL.properties
similarity index 76%
rename from src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_nl_NL.properties
rename to src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_nl_NL.properties
index 146f381d62aa846fa471dd91d161e759d3947699..b21ac99ae65f2d26da5100f5ffa4837498bd2a8b 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_nl_NL.properties
+++ b/src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_nl_NL.properties
@@ -1,4 +1,5 @@
-#Thu Feb 04 13:41:35 CET 2010
+#Thu Sep 08 16:42:42 CEST 2011
+form.version=Versionering
 meta.comment.title=Vergrendeld
 meta.locked=Bestand vergrendeld
 meta.retainlock=Bestand vergrendeld laten voor andere gebruikers
@@ -23,3 +24,9 @@ version.nr=Revisie
 version.restore=Terugzetten
 version.restore.comment=versie {0} teruggezet.
 version.restore.failed=Bestand kon niet worden teruggezet.
+version.intro=Gelieve het maximum aantal versies voor een maponderdeel in te stellen (groepmap, cursusmap, etc.).
+version.notANumber=Geen nummer geselecteerd
+version.numOfVersions=Aantal versies
+version.off=Versionering gedeactiveerd
+version.title=Versionering
+version.unlimited=Ongelimiteerd
diff --git a/src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_pl.properties b/src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_pl.properties
similarity index 65%
rename from src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_pl.properties
rename to src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_pl.properties
index 5c03da2ee25226df383768e8cdf5255c9dee1618..9ee4917d56a1e4fa6ee3b6932a1b423c6c27162b 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_pl.properties
+++ b/src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_pl.properties
@@ -1,4 +1,5 @@
-#Mon Feb 15 01:13:42 CET 2010
+#Sun Dec 23 19:39:03 CET 2012
+form.version=Wersjonowanie
 meta.comment.title=Blokada
 meta.locked=Plik zablokowany
 meta.retainlock=Kontynuuj blokowanie pliku dla innych u\u017Cytkownik\u00F3w
@@ -23,3 +24,16 @@ version.nr=Edycja
 version.restore=Przywr\u00F3\u0107
 version.restore.comment=Wersja {0} zosta\u0142a przywr\u00F3cona
 version.restore.failed=Plik nie mo\u017Ce zosta\u0107 przywr\u00F3cony.
+table.header.file=Plik
+table.header.size=Rozmiar
+table.header.versions=Liczba wersji
+version.intro=Podaj maksymaln\u0105 liczb\u0119 wersji dla folder\u00F3w (folder grupy, folder kursu, itd.).
+version.maintenance.intro=Zarz\u0105dzanie wersjami
+version.maintenance.title=Zarz\u0105dzanie
+version.notANumber=Nie wybrano liczby
+version.numOfVersions=Liczba wersji
+version.off=Wersjonowanie wy\u0142\u0105czone
+version.orphan.size.calc=Oblicz rozmiar
+version.orphan.size.calculating=Trwa obliczanie...
+version.title=Wersjonowanie
+version.unlimited=Brak limitu
diff --git a/src/main/java/org/olat/admin/version/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_pt_BR.properties
similarity index 50%
rename from src/main/java/org/olat/admin/version/_i18n/LocalStrings_pt_BR.properties
rename to src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_pt_BR.properties
index 6cd0d455d9b63b3bcc7937c21436066abc318e98..51d5284f3472840b31f2499d2227fe56267cf4e3 100644
--- a/src/main/java/org/olat/admin/version/_i18n/LocalStrings_pt_BR.properties
+++ b/src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_pt_BR.properties
@@ -1,15 +1,31 @@
 #Fri Sep 06 17:41:15 CEST 2013
-
-
-
-
-
-
-
 confirm.delete.orphans=Voc\u00EA realmente quer apagar todas as vers\u00F5es \u00F3rf\u00E3s?
 confirm.prune.history=Voc\u00EA realmente quer apagar todas as vers\u00F5es que excedam o limite da vers\u00E3o configurada?
 form.version=Controle de Vers\u00E3o
-
+meta.comment.title=Bloquear
+meta.locked=Arquivo bloqueado
+meta.retainlock=Continue bloqueio de arquivo para outros usu\u00E1rios
+meta.unlock=Desbloquear arquivo para outros usu\u00E1rios
+version.author=Autor
+version.comment=Coment\u00E1rio
+version.comment.alltitle=Comentar/Bloquear
+version.comment.description=As altera\u00E7\u00F5es s\u00E3o controladas neste documento. Por favor, comente suas modifica\u00E7\u00F5es.
+version.comment.title=Comente
+version.confirmDelete=Voc\u00EA realmente quer apagar {0} revis\u00E3o(\u00F5es)?
+version.date=Data
+version.del.confirm=Voc\u00EA realmente quer excluir os seguintes arquivos?
+version.del.header=Confirme exclus\u00E3o
+version.deletedBy=Exclu\u00EDdo por
+version.deletedFiles=Arquivos exclu\u00EDdos
+version.download=Baixar
+version.initialRevision=Vers\u00E3o inicial
+version.name=Arquivo
+version.noDeletedFiles=N\u00E3o existem arquivos exclu\u00EDdos com um registo de altera\u00E7\u00F5es.
+version.noRevisions=N\u00E3o h\u00E1 revis\u00F5es deste arquivo ainda.
+version.nr=Revis\u00E3o
+version.restore=Restaurar
+version.restore.comment=Vers\u00E3o {0} restaurada
+version.restore.failed=Arquivo n\u00E3o p\u00F4de ser restaurado.
 table.empty=Nenhuma vers\u00E3o \u00F3rf\u00E3
 table.header.file=Arquivo
 table.header.size=Tamanho
diff --git a/src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_ru.properties b/src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_ru.properties
similarity index 100%
rename from src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_ru.properties
rename to src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_ru.properties
diff --git a/src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_zh_CN.properties b/src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_zh_CN.properties
similarity index 61%
rename from src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_zh_CN.properties
rename to src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_zh_CN.properties
index d4ed25ce83436acbe8598d8b5d66debf40d111ec..6ba1098fba43a61a62e3c0255c6b545943494ae5 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_zh_CN.properties
+++ b/src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_zh_CN.properties
@@ -1,4 +1,5 @@
-#Sun Feb 07 10:37:58 CET 2010
+#Mon Nov 10 00:41:46 CET 2014
+form.version=\u7248\u672C
 meta.comment.title=\u9501\u5B9A
 meta.locked=\u6587\u4EF6\u9501\u5B9A
 meta.retainlock=\u7EE7\u7EED\u4E3A\u5176\u4ED6\u7528\u6237\u9501\u5B9A\u6587\u4EF6
@@ -23,3 +24,18 @@ version.nr=\u4FEE\u8BA2
 version.restore=\u91CD\u65B0\u4FDD\u5B58
 version.restore.comment=\u7248\u672C{0}\u5DF2\u88AB\u91CD\u65B0\u4FDD\u5B58
 version.restore.failed=\u6587\u4EF6\u4E0D\u80FD\u88AB\u91CD\u65B0\u4FDD\u5B58\u3002
+
+version.clean.up=\u5220\u9664Orphan\u7248\u672C
+version.intro=\u8BF7\u4E3A\u7EC4\u6210\u6587\u4EF6\u5939\uFF08\u7FA4\u7EC4\u6587\u4EF6\u5939\uFF0C\u5B66\u7A0B\u6587\u4EF6\u5939\uFF0C\u7B49\uFF09\u7684\u6587\u4EF6\u8BBE\u7F6E\u7248\u672C\u7684\u6700\u5927\u6570\u76EE\u3002
+version.maintenance.intro=\u7248\u672C\u7BA1\u7406
+version.maintenance.title=\u7BA1\u7406
+version.notANumber=\u672A\u9009\u62E9\u4EFB\u4F55\u6570\u5B57
+version.numOfVersions=\u7248\u672C\u7684\u6570\u76EE
+version.off=\u5DF2\u5173\u95ED\u7248\u672C
+version.orphan.size=Orphan\u7248\u672C\u5927\u5C0F
+version.orphan.size.calc=\u5927\u5C0F\u8BA1\u7B97
+version.orphan.size.calculating=\u6B63\u5728\u8BA1\u7B97\u5927\u5C0F
+version.prune.history=\u7248\u672C\u6E05\u7406
+version.show.orphans=\u5217\u51FAOrphan\u7248\u672C
+version.title=\u7248\u672C
+version.unlimited=\u65E0\u9650
diff --git a/src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_zh_TW.properties b/src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_zh_TW.properties
similarity index 73%
rename from src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_zh_TW.properties
rename to src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_zh_TW.properties
index 470d5f9f9f777f777a11792108d9f1fee4b73623..7cef5bd910f95ab3438dce3ba8c5d6df74013890 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/version/_i18n/LocalStrings_zh_TW.properties
+++ b/src/main/java/org/olat/core/commons/services/vfs/ui/version/_i18n/LocalStrings_zh_TW.properties
@@ -1,4 +1,5 @@
-#Sun Jan 24 11:40:40 CET 2010
+#Sat Sep 18 15:10:48 CEST 2010
+form.version=\u7248\u672C
 meta.comment.title=\u9396\u5B9A
 meta.locked=\u6A94\u6848\u88AB\u9396\u5B9A
 meta.retainlock=\u7E7C\u7E8C\u5C0D\u5176\u4ED6\u4F7F\u7528\u8005\u9396\u5B9A\u6A94\u6848
@@ -23,3 +24,9 @@ version.nr=\u4FEE\u8A02
 version.restore=\u56DE\u5B58
 version.restore.comment=\u7248\u672C {0} \u56DE\u5B58
 version.restore.failed=\u6A94\u6848\u7121\u6CD5\u88AB\u56DE\u5B58\u3002
+version.intro=\u8ACB\u8A2D\u5B9A\u8CC7\u6599\u593E\u7D44\u6210\u7684\u6A94\u6848\uFF08\u5B58\u53D6\u8CC7\u6599\u593E\u3001\u8AB2\u7A0B\u8CC7\u6599\u593E\uFF0C\u7B49\uFF09\u7684\u6700\u5927\u7248\u672C\u6578\u3002
+version.notANumber=\u672A\u9078\u64C7\u4EFB\u4F55\u6578\u5B57
+version.numOfVersions=\u7248\u672C\u6578
+version.off=\u505C\u7528\u7248\u672C\u63A7\u5236
+version.title=\u7248\u672C
+version.unlimited=\u7121\u9650
diff --git a/src/main/java/org/olat/core/commons/services/webdav/manager/VFSResourceRoot.java b/src/main/java/org/olat/core/commons/services/webdav/manager/VFSResourceRoot.java
index c63fbe62ded5c1c34bc5852a5cdde4934518720f..cda6761701896b5d31b1450361840b03ac4e0184 100644
--- a/src/main/java/org/olat/core/commons/services/webdav/manager/VFSResourceRoot.java
+++ b/src/main/java/org/olat/core/commons/services/webdav/manager/VFSResourceRoot.java
@@ -49,8 +49,6 @@ import org.olat.core.util.vfs.VFSLeaf;
 import org.olat.core.util.vfs.VFSManager;
 import org.olat.core.util.vfs.VFSStatus;
 import org.olat.core.util.vfs.callbacks.VFSSecurityCallback;
-import org.olat.core.util.vfs.version.Versionable;
-import org.olat.core.util.vfs.version.VersionsManager;
 
 
 /**
@@ -173,11 +171,11 @@ public class VFSResourceRoot implements WebResourceRoot  {
 				childLeaf = (VFSLeaf)file;
 				
 				//versioning
-				if(childLeaf instanceof Versionable && ((Versionable)childLeaf).getVersions().isVersioned()) {
-					if(childLeaf.getSize() == 0) {
-						CoreSpringFactory.getImpl(VersionsManager.class).createVersionsFor(childLeaf, true);
-					} else {
-						CoreSpringFactory.getImpl(VersionsManager.class).addToRevisions((Versionable)childLeaf, identity, "");
+				if(childLeaf.canVersion() == VFSConstants.YES) {
+					try(InputStream in=childLeaf.getInputStream()) {
+						CoreSpringFactory.getImpl(VFSRepositoryService.class).addVersion(childLeaf, identity, "", in);
+					} catch(IOException e) {
+						log.error("", e);
 					}
 				}
 			} else {
@@ -223,35 +221,28 @@ public class VFSResourceRoot implements WebResourceRoot  {
 		}
 		
 		if(identity != null && childLeaf.canMeta() == VFSConstants.YES) {
-			VFSMetadata infos = childLeaf.getMetaInfo();
-			if(infos != null && infos.getAuthor() != null) {
-				infos.setAuthor(identity);
-				addLicense(infos, identity);
-				
-				VFSRepositoryService vfsRepositoryService = CoreSpringFactory.getImpl(VFSRepositoryService.class);
-				vfsRepositoryService.updateMetadata(infos);
-				vfsRepositoryService.resetThumbnails(childLeaf);
-			}
-		}
-		
-		if(movedFrom instanceof VFSResource) {
-			VFSResource vfsResource = (VFSResource)movedFrom;
-			if(vfsResource.getItem() instanceof Versionable
-					&& ((Versionable)vfsResource.getItem()).getVersions().isVersioned()) {
-				VFSLeaf currentVersion = (VFSLeaf)vfsResource.getItem();
-				CoreSpringFactory.getImpl(VersionsManager.class).move(currentVersion, childLeaf, identity);
+			VFSRepositoryService vfsRepositoryService = CoreSpringFactory.getImpl(VFSRepositoryService.class);
+			VFSMetadata metadata;
+			if(movedFrom instanceof VFSResource && ((VFSResource)movedFrom).getItem() instanceof VFSLeaf) {
+				VFSLeaf from = (VFSLeaf)((VFSResource)movedFrom).getItem();
+				metadata = CoreSpringFactory.getImpl(VFSRepositoryService.class).move(from, childLeaf, identity);
+			} else {
+				metadata = vfsRepositoryService.getMetadataFor(childLeaf);
+				metadata.setAuthor(identity);
+				metadata = vfsRepositoryService.updateMetadata(metadata);
 			}
+			addLicense(metadata, identity);
+			vfsRepositoryService.resetThumbnails(childLeaf);
 		}
-		
 		return true;
 	}
 
-	private void addLicense(VFSMetadata meta, Identity identity) {
+	private void addLicense(VFSMetadata meta, Identity id) {
 		LicenseService licenseService = CoreSpringFactory.getImpl(LicenseService.class);
 		LicenseModule licenseModule = CoreSpringFactory.getImpl(LicenseModule.class);
 		FolderLicenseHandler licenseHandler = CoreSpringFactory.getImpl(FolderLicenseHandler.class);
 		if (licenseModule.isEnabled(licenseHandler)) {
-			License license = licenseService.createDefaultLicense(licenseHandler, identity);
+			License license = licenseService.createDefaultLicense(licenseHandler, id);
 			meta.setLicenseType(license.getLicenseType());
 			meta.setLicenseTypeName(license.getLicenseType().getName());
 			meta.setLicensor(license.getLicensor());
diff --git a/src/main/java/org/olat/core/configuration/AbstractSpringModule.java b/src/main/java/org/olat/core/configuration/AbstractSpringModule.java
index 95c2ae07896f02ce46e5d8b789905caded5c0868..a30a6ea4d11d4535bfa41ebe02a965f301369871 100644
--- a/src/main/java/org/olat/core/configuration/AbstractSpringModule.java
+++ b/src/main/java/org/olat/core/configuration/AbstractSpringModule.java
@@ -294,10 +294,7 @@ public abstract class AbstractSpringModule implements GenericEventListener, Init
 		// delegate to new property based config style
 		moduleConfigProperties.setIntPropertyDefault(key, value);		
 	}
-	
-	/**
-	 * @see org.olat.core.util.event.GenericEventListener#event(org.olat.core.gui.control.Event)
-	 */
+
 	@Override
 	public void event(Event event) {
 		if (event instanceof PersistedPropertiesChangedEvent) {
diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/FormUIFactory.java b/src/main/java/org/olat/core/gui/components/form/flexible/FormUIFactory.java
index 702cfbe3e8f20289c5d5f86db4d7188a2f183a68..a99584bbb4bdb1538016030fcce3e698e581f58c 100644
--- a/src/main/java/org/olat/core/gui/components/form/flexible/FormUIFactory.java
+++ b/src/main/java/org/olat/core/gui/components/form/flexible/FormUIFactory.java
@@ -92,6 +92,7 @@ import org.olat.core.gui.components.tree.MenuTreeItem;
 import org.olat.core.gui.components.tree.TreeModel;
 import org.olat.core.gui.control.WindowBackOffice;
 import org.olat.core.gui.control.WindowControl;
+import org.olat.core.gui.media.MediaResource;
 import org.olat.core.gui.themes.Theme;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.util.StringHelper;
@@ -1127,6 +1128,17 @@ public class FormUIFactory {
 		}
 		return fte;
 	}
+	
+	public DownloadLink addDownloadLink(String name,  String linkTitle, String i18nLabel, MediaResource resource, FlexiTableElement formLayout) {
+		DownloadLinkImpl fte = new DownloadLinkImpl(name);
+		fte.setLinkText(linkTitle);
+		fte.setDownloadMedia(resource);
+		setLabelIfNotNull(i18nLabel, fte);
+		if(formLayout != null) {
+			((FlexiTableElementImpl)formLayout).addFormItem(fte);
+		}
+		return fte;
+	}
 
 	/**
 	 * add a toggle which handles on/off state itself and can be asked for status
diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/elements/DownloadLink.java b/src/main/java/org/olat/core/gui/components/form/flexible/elements/DownloadLink.java
index 508226d47046e69003a12e826a9a459293e11d8a..2c4243dc22740dd2969cd129db5b6bdc78c32827 100644
--- a/src/main/java/org/olat/core/gui/components/form/flexible/elements/DownloadLink.java
+++ b/src/main/java/org/olat/core/gui/components/form/flexible/elements/DownloadLink.java
@@ -22,6 +22,7 @@ package org.olat.core.gui.components.form.flexible.elements;
 import java.io.File;
 
 import org.olat.core.gui.components.form.flexible.FormItem;
+import org.olat.core.gui.media.MediaResource;
 import org.olat.core.util.vfs.VFSLeaf;
 
 /**
@@ -43,5 +44,7 @@ public interface DownloadLink extends FormItem {
 	public void setDownloadItem(File downloadItem);
 	
 	public void setDownloadItem(VFSLeaf downloadItem);
+	
+	public void setDownloadMedia(MediaResource mediaResource);
 
 }
diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/DownloadLinkImpl.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/DownloadLinkImpl.java
index 1f6f08019cc8266c047eedf96109c3b5510ef117..5412bc059745b906308c65d51c6a9b38dc1a74ea 100644
--- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/DownloadLinkImpl.java
+++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/DownloadLinkImpl.java
@@ -26,6 +26,7 @@ import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.download.DownloadComponent;
 import org.olat.core.gui.components.form.flexible.elements.DownloadLink;
 import org.olat.core.gui.components.form.flexible.impl.FormItemImpl;
+import org.olat.core.gui.media.MediaResource;
 import org.olat.core.util.vfs.VFSLeaf;
 
 /**
@@ -75,6 +76,11 @@ public class DownloadLinkImpl extends FormItemImpl implements DownloadLink {
 		downloadCmp.setDownloadItem(downloadItem, true);
 	}
 
+	@Override
+	public void setDownloadMedia(MediaResource mediaResource) {
+		downloadCmp.setMediaResource(mediaResource);
+	}
+
 	@Override
 	protected Component getFormItemComponent() {
 		return downloadCmp;
diff --git a/src/main/java/org/olat/core/util/ZipUtil.java b/src/main/java/org/olat/core/util/ZipUtil.java
index eabb4c6bfc8ef37c045c121a837b7dc5f58d9ae4..ca61935ea00b3e41b515fab127c2292f20bd3762 100644
--- a/src/main/java/org/olat/core/util/ZipUtil.java
+++ b/src/main/java/org/olat/core/util/ZipUtil.java
@@ -70,7 +70,6 @@ import org.olat.core.util.vfs.VFSLockApplicationType;
 import org.olat.core.util.vfs.VFSLockManager;
 import org.olat.core.util.vfs.VFSManager;
 import org.olat.core.util.vfs.filters.VFSSystemItemFilter;
-import org.olat.core.util.vfs.version.Versionable;
 
 /**
  * Initial Date:  04.12.2002
@@ -214,11 +213,8 @@ public class ZipUtil {
 								if (!copy(oZip, newEntry)) {
 									return false;
 								}
-							} else if (newEntry instanceof Versionable) {
-								Versionable versionable = (Versionable)newEntry;
-								if(versionable.getVersions().isVersioned()) {
-									versionable.getVersions().addVersion(identity, "", oZip);
-								}
+							} else if (newEntry.canVersion() == VFSConstants.YES) {
+								vfsRepositoryService.addVersion(newEntry, identity, "", oZip);
 							}
 							if(newEntry != null && identity != null && newEntry.canMeta() == VFSConstants.YES) {
 								VFSMetadata info = newEntry.getMetaInfo();
@@ -305,6 +301,8 @@ public class ZipUtil {
 	 */
 	private static boolean unzipNonStrict(InputStream in, VFSContainer targetDir, Identity identity, boolean versioning) {
 		try(net.sf.jazzlib.ZipInputStream oZip = new net.sf.jazzlib.ZipInputStream(in)) {
+			VFSRepositoryService vfsRepositoryService = CoreSpringFactory.getImpl(VFSRepositoryService.class);
+			
 			// unzip files
 			net.sf.jazzlib.ZipEntry oEntr = oZip.getNextEntry();
 			while (oEntr != null) {
@@ -343,11 +341,8 @@ public class ZipUtil {
 								if (!copyShielded(oZip, newEntry)) {
 									return false;
 								}
-							} else if (newEntry instanceof Versionable) {
-								Versionable versionable = (Versionable)newEntry;
-								if(versionable.getVersions().isVersioned()) {
-									versionable.getVersions().addVersion(identity, "", oZip);
-								}
+							} else if (newEntry.canVersion() == VFSConstants.YES) {
+								vfsRepositoryService.addVersion(newEntry, identity, "", oZip);
 							}
 							unzipMetadata(identity, extra, newEntry);
 						} else {
diff --git a/src/main/java/org/olat/core/util/vfs/AbstractVirtualContainer.java b/src/main/java/org/olat/core/util/vfs/AbstractVirtualContainer.java
index 3fb6e3653944102612d23a1487bc23bf83d9d70d..695758bd307bf53fb5d3fdfdf661ab3de5e58139 100644
--- a/src/main/java/org/olat/core/util/vfs/AbstractVirtualContainer.java
+++ b/src/main/java/org/olat/core/util/vfs/AbstractVirtualContainer.java
@@ -119,6 +119,11 @@ public abstract class AbstractVirtualContainer implements VFSContainer {
 	public VFSStatus canMeta() {
 		return VFSConstants.NO;
 	}
+	
+	@Override
+	public VFSStatus canVersion() {
+		return VFSConstants.NO;
+	}
 
 	@Override
 	public VFSMetadata getMetaInfo() {
diff --git a/src/main/java/org/olat/core/util/vfs/LocalFileImpl.java b/src/main/java/org/olat/core/util/vfs/LocalFileImpl.java
index c2f68241d8fea393ef305dab56ff3493c047b01f..dde02732c5d5f69236e5321317a363a178999a1e 100644
--- a/src/main/java/org/olat/core/util/vfs/LocalFileImpl.java
+++ b/src/main/java/org/olat/core/util/vfs/LocalFileImpl.java
@@ -39,13 +39,13 @@ import java.nio.file.Path;
 
 import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.modules.bc.FolderConfig;
+import org.olat.core.commons.services.vfs.VFSRepositoryModule;
 import org.olat.core.commons.services.vfs.VFSRepositoryService;
+import org.olat.core.id.Identity;
 import org.olat.core.logging.AssertException;
 import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
-import org.olat.core.util.vfs.version.Versionable;
-import org.olat.core.util.vfs.version.Versions;
-import org.olat.core.util.vfs.version.VersionsManager;
+import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
 
 /**
  * Description:<br>
@@ -56,10 +56,8 @@ import org.olat.core.util.vfs.version.VersionsManager;
  *
  * @author Felix Jost
  */
-public class LocalFileImpl extends LocalImpl implements VFSLeaf, Versionable {
+public class LocalFileImpl extends LocalImpl implements VFSLeaf {
 	private static final OLog log = Tracing.createLoggerFor(LocalFileImpl.class);
-	
-	private Versions versions;
 
 	private LocalFileImpl() {
 		super(null, null);
@@ -108,6 +106,11 @@ public class LocalFileImpl extends LocalImpl implements VFSLeaf, Versionable {
 		return null;
 	}
 
+	@Override
+	public VFSStatus canVersion() {
+		return VFSRepositoryModule.canVersion(getBasefile());
+	}
+
 	@Override
 	public OutputStream getOutputStream(boolean append) {
 		OutputStream os = null;
@@ -119,14 +122,6 @@ public class LocalFileImpl extends LocalImpl implements VFSLeaf, Versionable {
 		return os;
 	}
 
-	@Override
-	public Versions getVersions() {
-		if(versions == null) {
-			versions = CoreSpringFactory.getImpl(VersionsManager.class).createVersionsFor(this);
-		}
-		return versions;
-	}
-
 	@Override
 	public VFSStatus rename(String newname) {
 		File f = getBasefile();
@@ -134,15 +129,12 @@ public class LocalFileImpl extends LocalImpl implements VFSLeaf, Versionable {
 			return VFSConstants.NO;
 		}
 		
-		File par = f.getParentFile();
-		File nf = new File(par, newname);
-		if(getVersions().isVersioned()) {
-			//rename the versions
-			CoreSpringFactory.getImpl(VersionsManager.class).rename(this, newname);
-		}
 		if(canMeta() == VFSConstants.YES) {
-			CoreSpringFactory.getImpl(VFSRepositoryService.class).rename(getMetaInfo(), newname);
+			CoreSpringFactory.getImpl(VFSRepositoryService.class).rename(this, newname);
 		}
+
+		File par = f.getParentFile();
+		File nf = new File(par, newname);
 		boolean ren = f.renameTo(nf);
 		if (ren) {
 			// f.renameTo() does NOT modify the path contained in the object f!!
@@ -158,12 +150,9 @@ public class LocalFileImpl extends LocalImpl implements VFSLeaf, Versionable {
 
 	@Override
 	public VFSStatus delete() {
-		if(getVersions().isVersioned()) {
-			CoreSpringFactory.getImpl(VersionsManager.class).delete(this, false);
-		}
-		// Versioning makes a copy of the metadata, delete metadata after it
 		if(canMeta() == VFSConstants.YES) {
-			CoreSpringFactory.getImpl(VFSRepositoryService.class).deleteMetadata(getMetaInfo());
+			Identity identity = ThreadLocalUserActivityLogger.getLoggedIdentity();
+			CoreSpringFactory.getImpl(VFSRepositoryService.class).markAsDeleted(this, identity);
 		}
 		return deleteBasefile();
 	}
@@ -173,7 +162,6 @@ public class LocalFileImpl extends LocalImpl implements VFSLeaf, Versionable {
 		if(canMeta() == VFSConstants.YES) {
 			CoreSpringFactory.getImpl(VFSRepositoryService.class).deleteMetadata(getMetaInfo());
 		}
-		CoreSpringFactory.getImpl(VersionsManager.class).delete(this, true);
 		return deleteBasefile();
 	}
 	
diff --git a/src/main/java/org/olat/core/util/vfs/LocalFolderImpl.java b/src/main/java/org/olat/core/util/vfs/LocalFolderImpl.java
index a2c60cbb42b26006762c8b60e7208c3bb1c1ffa3..b1ba217635ceb984d99435fd92e312545ba7e1c2 100644
--- a/src/main/java/org/olat/core/util/vfs/LocalFolderImpl.java
+++ b/src/main/java/org/olat/core/util/vfs/LocalFolderImpl.java
@@ -36,15 +36,16 @@ import java.util.List;
 
 import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.modules.bc.FolderConfig;
+import org.olat.core.commons.services.vfs.VFSRepositoryModule;
 import org.olat.core.commons.services.vfs.VFSRepositoryService;
+import org.olat.core.id.Identity;
 import org.olat.core.logging.AssertException;
 import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
+import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
 import org.olat.core.util.FileUtils;
-import org.olat.core.util.vfs.filters.VFSSystemItemFilter;
 import org.olat.core.util.vfs.filters.VFSItemFilter;
-import org.olat.core.util.vfs.version.Versionable;
-import org.olat.core.util.vfs.version.VersionsManager;
+import org.olat.core.util.vfs.filters.VFSSystemItemFilter;
 
 /**
  * Description:<br>
@@ -201,14 +202,10 @@ public class LocalFolderImpl extends LocalImpl implements VFSContainer {
 			} catch (Exception e) {
 				return VFSConstants.ERROR_FAILED;
 			}
-			
-			if(s instanceof Versionable && ((Versionable)s).getVersions().isVersioned()) {
-				((Versionable)s).getVersions().copy(this);
-			}
 
-			if(s.canMeta() == VFSConstants.YES) {
+			if(s.canMeta() == VFSConstants.YES || s.canVersion() == VFSConstants.YES) {
 				VFSItem target = resolve(sourcename);
-				if(target instanceof VFSLeaf && target.canMeta() == VFSConstants.YES) {
+				if(target instanceof VFSLeaf && (target.canMeta() == VFSConstants.YES || s.canVersion() == VFSConstants.YES)) {
 					CoreSpringFactory.getImpl(VFSRepositoryService.class).copyTo(s, (VFSLeaf)target, this);
 				}
 			}
@@ -225,13 +222,19 @@ public class LocalFolderImpl extends LocalImpl implements VFSContainer {
 			return VFSConstants.NO_SECURITY_DENIED;
 		return VFSConstants.YES;
 	}
+	
+	@Override
+	public VFSStatus canVersion() {
+		return VFSRepositoryModule.canVersion(getBasefile());
+	}
 
 	@Override
 	public VFSStatus rename(String newname) {
+		CoreSpringFactory.getImpl(VFSRepositoryService.class).rename(this, newname);
+		
 		File f = getBasefile();
 		File par = f.getParentFile();
 		File nf = new File(par, newname);
-		CoreSpringFactory.getImpl(VersionsManager.class).rename(this, newname);
 		boolean ren = f.renameTo(nf);
 		if (ren) {
 			// f.renameTo() does NOT modify the path contained in the object f!!
@@ -256,15 +259,11 @@ public class LocalFolderImpl extends LocalImpl implements VFSContainer {
 			child.delete();
 		}
 		
-		VersionsManager versionsManager = CoreSpringFactory.getImpl(VersionsManager.class);
-		if(versionsManager.isEnabled()) {
-			versionsManager.delete(this, false);
-		}
 		// Versioning makes a copy of the metadata, delete metadata after it
 		if(canMeta() == VFSConstants.YES) {
-			CoreSpringFactory.getImpl(VFSRepositoryService.class).deleteMetadata(getMetaInfo());
+			Identity identity = ThreadLocalUserActivityLogger.getLoggedIdentity();
+			CoreSpringFactory.getImpl(VFSRepositoryService.class).markAsDeleted(this, identity);
 		}
-
 		// now delete the directory itself
 		return deleteBasefile();
 	}
@@ -283,7 +282,6 @@ public class LocalFolderImpl extends LocalImpl implements VFSContainer {
 		if(canMeta() == VFSConstants.YES) {
 			CoreSpringFactory.getImpl(VFSRepositoryService.class).deleteMetadata(getMetaInfo());
 		}
-		CoreSpringFactory.getImpl(VersionsManager.class).delete(this, true);
 		// now delete the directory itself
 		return deleteBasefile();
 	}
diff --git a/src/main/java/org/olat/core/util/vfs/LocalImpl.java b/src/main/java/org/olat/core/util/vfs/LocalImpl.java
index d8cce3d498352b8342da0a30a39d8350e0c2a376..9d8f8db263f087d8e39c24bc8d6192a531f4cd09 100644
--- a/src/main/java/org/olat/core/util/vfs/LocalImpl.java
+++ b/src/main/java/org/olat/core/util/vfs/LocalImpl.java
@@ -143,6 +143,11 @@ public abstract class LocalImpl implements VFSItem, JavaIOItem {
 	public VFSStatus canMeta() {
 		return VFSRepositoryModule.canMeta(getBasefile());
 	}
+	
+	@Override
+	public VFSStatus canVersion() {
+		return VFSConstants.NO;
+	}
 
 	@Override
 	public VFSMetadata getMetaInfo() {
diff --git a/src/main/java/org/olat/core/util/vfs/MergeSource.java b/src/main/java/org/olat/core/util/vfs/MergeSource.java
index 2b8ae24b7992e557e6d92d07f02e36ba78c0bfa8..6bfc7b4def60c7cc66c8a85b3c007c8288419e08 100644
--- a/src/main/java/org/olat/core/util/vfs/MergeSource.java
+++ b/src/main/java/org/olat/core/util/vfs/MergeSource.java
@@ -140,34 +140,22 @@ public class MergeSource extends AbstractVirtualContainer {
 	public boolean isContainersChild(VFSContainer container) {
 		return mergedContainersChildren.contains(container);
 	}
-	
-	/**
-	 * @see org.olat.core.util.vfs.VFSItem#getParent()
-	 */
+
 	@Override
 	public VFSContainer getParentContainer() {
 		return parentContainer;
 	}
 	
-	/**
-	 * @see org.olat.core.util.vfs.VFSItem#setParentContainer(org.olat.core.util.vfs.VFSContainer)
-	 */
 	@Override
 	public void setParentContainer(VFSContainer parentContainer) {
 		this.parentContainer = parentContainer;
 	}
-	
-	/**
-	 * @see org.olat.core.util.vfs.VFSContainer#getItems()
-	 */
+
 	@Override
 	public List<VFSItem> getItems() {
 		return getItems(null);
 	}
 
-	/**
-	 * @see org.olat.core.util.vfs.VFSContainer#getItems(org.olat.core.util.vfs.filters.VFSItemFilter)
-	 */
 	@Override
 	public List<VFSItem> getItems(VFSItemFilter filter) {
 		// remember: security callback and parent was already set during add to this MergeSource
@@ -194,18 +182,12 @@ public class MergeSource extends AbstractVirtualContainer {
 		return all;
 	}
 
-	/**
-	 * @see org.olat.core.util.vfs.VFSItem#canCopyTo()
-	 */
 	@Override
 	public VFSStatus canWrite() {
 		if (rootWriteContainer == null) return VFSConstants.NO;
 		return rootWriteContainer.canWrite();
 	}
 
-	/**
-	 * @see org.olat.core.util.vfs.VFSContainer#createChildContainer(java.lang.String)
-	 */
 	@Override
 	public VFSContainer createChildContainer(String name) {
 		if (canWrite() != VFSConstants.YES) return null;
@@ -314,12 +296,17 @@ public class MergeSource extends AbstractVirtualContainer {
 	
 	@Override
 	public VFSStatus canMeta() {
-		return VFSConstants.NO;
+		return rootWriteContainer == null ? VFSConstants.NO : rootWriteContainer.canVersion();
+	}
+
+	@Override
+	public VFSStatus canVersion() {
+		return rootWriteContainer == null ? VFSConstants.NO: rootWriteContainer.canVersion();
 	}
 
 	@Override
 	public VFSMetadata getMetaInfo() {
-		return null;
+		return rootWriteContainer == null ? null : rootWriteContainer.getMetaInfo();
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/core/util/vfs/NamedContainerImpl.java b/src/main/java/org/olat/core/util/vfs/NamedContainerImpl.java
index 92afdf2678182515fb4d0357983447d220287fc3..036ed3e4b2267ba029486a1d036010e4bcd0f194 100644
--- a/src/main/java/org/olat/core/util/vfs/NamedContainerImpl.java
+++ b/src/main/java/org/olat/core/util/vfs/NamedContainerImpl.java
@@ -165,6 +165,11 @@ public class NamedContainerImpl extends AbstractVirtualContainer {
 		return getDelegate().canMeta();
 	}
 
+	@Override
+	public VFSStatus canVersion() {
+		return getDelegate().canVersion();
+	}
+
 	@Override
 	public VFSMetadata getMetaInfo() {
 		return getDelegate().getMetaInfo();
diff --git a/src/main/java/org/olat/core/util/vfs/NamedLeaf.java b/src/main/java/org/olat/core/util/vfs/NamedLeaf.java
index e17690cb10599a0b2a3b3f5da6118723fbc1b6f1..68877974acbf9a5987133d131c424af9a525c18b 100644
--- a/src/main/java/org/olat/core/util/vfs/NamedLeaf.java
+++ b/src/main/java/org/olat/core/util/vfs/NamedLeaf.java
@@ -151,6 +151,11 @@ public class NamedLeaf implements VFSLeaf {
 	public VFSItem resolve(String path) {
 		return delegate.resolve(delegate.getName());
 	}
+	
+	@Override
+	public VFSStatus canVersion() {
+		return delegate.canVersion();
+	}
 
 	@Override
 	public VFSStatus canMeta() {
diff --git a/src/main/java/org/olat/core/util/vfs/VFSItem.java b/src/main/java/org/olat/core/util/vfs/VFSItem.java
index 5524ded206783b35fd996d299074ad8780b26a0c..a0578b222e020d4b41337e58c34dabfe8ab20259 100644
--- a/src/main/java/org/olat/core/util/vfs/VFSItem.java
+++ b/src/main/java/org/olat/core/util/vfs/VFSItem.java
@@ -137,6 +137,11 @@ public interface VFSItem {
 	 */
 	public VFSStatus canMeta();
 	
+	/**
+	 * @return true if the file can be versioned
+	 */
+	public VFSStatus canVersion();
+	
 	/**
 	 * @return The metadata if the item can metadata or null if not
 	 */
diff --git a/src/main/java/org/olat/core/util/vfs/VFSLeafHandler.java b/src/main/java/org/olat/core/util/vfs/VFSLeafHandler.java
deleted file mode 100644
index 83ef1aacba208b5f2f535c3af3112478a3ae4e6e..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/core/util/vfs/VFSLeafHandler.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/**
-* OLAT - Online Learning and Training<br>
-* http://www.olat.org
-* <p>
-* Licensed under the Apache License, Version 2.0 (the "License"); <br>
-* you may not use this file except in compliance with the License.<br>
-* You may obtain a copy of the License at
-* <p>
-* http://www.apache.org/licenses/LICENSE-2.0
-* <p>
-* Unless required by applicable law or agreed to in writing,<br>
-* software distributed under the License is distributed on an "AS IS" BASIS, <br>
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
-* See the License for the specific language governing permissions and <br>
-* limitations under the License.
-* <p>
-* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br>
-* University of Zurich, Switzerland.
-* <hr>
-* <a href="http://www.openolat.org">
-* OpenOLAT - Online Learning and Training</a><br>
-* This file has been modified by the OpenOLAT community. Changes are licensed
-* under the Apache 2.0 license as the original file.  
-* <p>
-*/ 
-
-package org.olat.core.util.vfs;
-
-import java.io.UnsupportedEncodingException;
-import java.util.logging.Formatter;
-import java.util.logging.LogRecord;
-import java.util.logging.StreamHandler;
-
-import org.olat.core.logging.OLATRuntimeException;
-
-/**
- * Description:<br>
- * Log handler that logs to a virtual file system leaf. The handler opens the file
- * for each log entry and closes it after that immediately. (in order to not waste too many unix filehandles)
- * <P>
- * Initial Date:  Aug 30, 2005 <br>
- * @author gnaegi
- */
-public class VFSLeafHandler extends StreamHandler {
-	private VFSLeaf vfsLeaf;
-		
-	/**
-	 * @param vfsLeaf The logfile
-	 * @param formatter
-	 */
-	public VFSLeafHandler(VFSLeaf vfsLeaf, Formatter formatter) {
-		setFormatter(formatter);
-		try {
-			setEncoding("utf8");
-		} catch (SecurityException e) {
-			throw new OLATRuntimeException(this.getClass(), "Error when setting encoding of to 'utf8' ",e);
-		} catch (UnsupportedEncodingException e) {
-			throw new OLATRuntimeException(this.getClass(), "Error when setting encoding of to 'utf8' ",e);
-		}
-		this.vfsLeaf = vfsLeaf;
-	}
-	
-	/**
-	 * @see java.util.logging.Handler#publish(java.util.logging.LogRecord)
-	 */
-	public synchronized void publish(LogRecord arg0) {  //o_clusterOK by:fj, as long as file is written to from one vm only
-		setOutputStream(vfsLeaf.getOutputStream(true));
-		super.publish(arg0);
-		close();
-	}
-}
diff --git a/src/main/java/org/olat/core/util/vfs/VFSLockApplicationType.java b/src/main/java/org/olat/core/util/vfs/VFSLockApplicationType.java
index ef687a0490089e117a26364d789f9a761793e346..9030304b66ee65faeefbc6e3bca22b29855d0501 100644
--- a/src/main/java/org/olat/core/util/vfs/VFSLockApplicationType.java
+++ b/src/main/java/org/olat/core/util/vfs/VFSLockApplicationType.java
@@ -1,3 +1,22 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
 package org.olat.core.util.vfs;
 
 /**
diff --git a/src/main/java/org/olat/core/util/vfs/lock/VFSLockManagerImpl.java b/src/main/java/org/olat/core/util/vfs/lock/VFSLockManagerImpl.java
index 0de43417eea34c118230d063240d2c93e53b9ffd..c3ed15af32f5968fdb1ec13e30c2b7824256dff1 100644
--- a/src/main/java/org/olat/core/util/vfs/lock/VFSLockManagerImpl.java
+++ b/src/main/java/org/olat/core/util/vfs/lock/VFSLockManagerImpl.java
@@ -113,7 +113,7 @@ public class VFSLockManagerImpl implements VFSLockManager {
 	 * @return true If the lock owner is someone else or if it's a WebDAV lock
 	 */
 	@Override
-	public boolean isLockedForMe(VFSItem item, VFSMetadata loadedInfo, Identity me, Roles roles, VFSLockApplicationType type) {
+	public boolean isLockedForMe(VFSItem item, VFSMetadata loadedInfo, Identity me, Roles roles, VFSLockApplicationType type) {//TODO metadata need the name/instance of the collaboration app.
 		File file = extractFile(item);
     	if(file != null && fileLocks.containsKey(file)) {
     		LockInfo lock = fileLocks.get(file);
diff --git a/src/main/java/org/olat/core/util/vfs/version/FolderVersioningConfigurator.java b/src/main/java/org/olat/core/util/vfs/version/FolderVersioningConfigurator.java
deleted file mode 100644
index dff8415f7ef566493174d0fc5c4e53f12ec8cf93..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/core/util/vfs/version/FolderVersioningConfigurator.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/**
- * <a href="http://www.openolat.org">
- * OpenOLAT - Online Learning and Training</a><br>
- * <p>
- * Licensed under the Apache License, Version 2.0 (the "License"); <br>
- * you may not use this file except in compliance with the License.<br>
- * You may obtain a copy of the License at the
- * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
- * <p>
- * Unless required by applicable law or agreed to in writing,<br>
- * software distributed under the License is distributed on an "AS IS" BASIS, <br>
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
- * See the License for the specific language governing permissions and <br>
- * limitations under the License.
- * <p>
- * Initial code contributed and copyrighted by<br>
- * frentix GmbH, http://www.frentix.com
- * <p>
- */
-package org.olat.core.util.vfs.version;
-
-import org.olat.core.configuration.ConfigOnOff;
-import org.olat.core.util.vfs.VFSContainer;
-
-/**
- * 
- * Description:<br>
- * Interface for the configuration of versioning.
- * 
- * <P>
- * Initial Date:  21 sept. 2009 <br>
- *
- * @author srosse
- */
-public interface FolderVersioningConfigurator extends ConfigOnOff {
-	
-	/**
-	 * The absolut limit for this instance
-	 * @return -1 for versioning without limit, 0 for no versioning, 1 - n is the maximum number of revision per file
-	 */
-	public int getMaxNumOfVersionsAllowed();
-
-	/**
-	 * @param relPath
-	 * @return -1 for versioning without limit, 0 for no versioning, 1 - n is the maximum number of revision per file
-	 */
-	public int versionAllowed(String relPath);
-
-	/**
-	 * @param container
-	 * @return true if versioning is enabled for the container given as parameter
-	 */
-	public boolean versionEnabled(VFSContainer container);
-
-}
diff --git a/src/main/java/org/olat/core/util/vfs/version/NotVersioned.java b/src/main/java/org/olat/core/util/vfs/version/NotVersioned.java
deleted file mode 100644
index 9a8d94c5e332dbf8f3601ea88d32d160161a2571..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/core/util/vfs/version/NotVersioned.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/**
- * <a href="http://www.openolat.org">
- * OpenOLAT - Online Learning and Training</a><br>
- * <p>
- * Licensed under the Apache License, Version 2.0 (the "License"); <br>
- * you may not use this file except in compliance with the License.<br>
- * You may obtain a copy of the License at the
- * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
- * <p>
- * Unless required by applicable law or agreed to in writing,<br>
- * software distributed under the License is distributed on an "AS IS" BASIS, <br>
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
- * See the License for the specific language governing permissions and <br>
- * limitations under the License.
- * <p>
- * Initial code contributed and copyrighted by<br>
- * frentix GmbH, http://www.frentix.com
- * <p>
- */
-package org.olat.core.util.vfs.version;
-
-import java.io.InputStream;
-import java.util.Collections;
-import java.util.List;
-
-import org.olat.core.id.Identity;
-import org.olat.core.util.vfs.VFSContainer;
-
-/**
- * Description:<br>
- * This class implements the @see org.olat.core.util.vfs.version.Versions interface for a file
- * which is not versioned and will never be.
- * 
- * <P>
- * Initial Date: 21 sept. 2009 <br>
- * 
- * @author srosse
- */
-public class NotVersioned implements Versions {
-
-	@Override
-	public boolean isVersioned() {
-		return false;
-	}
-
-	@Override
-	public List<VFSRevision> getRevisions() {
-		return Collections.emptyList();
-	}
-
-	@Override
-	public String getAuthor() {
-		return "";
-	}
-
-	@Override
-	public String getCreator() {
-		return "";
-	}
-
-	@Override
-	public String getComment() {
-		return "";
-	}
-
-	@Override
-	public String getRevisionNr() {
-		return "";
-	}
-
-	@Override
-	public boolean addVersion(Identity identity, String comment, InputStream newVersion) {
-		return false;
-	}
-
-	@Override
-	public boolean move(VFSContainer container) {
-		return false;
-	}
-
-	@Override
-	public boolean copy(VFSContainer container) {
-		return false;
-	}
-
-	@Override
-	public boolean delete(Identity identity, List<VFSRevision> versionsToDelete) {
-		return false;
-	}
-
-	@Override
-	public boolean restore(Identity identity, VFSRevision version, String comment) {
-		return false;
-	}
-}
diff --git a/src/main/java/org/olat/core/util/vfs/version/OrphanVersion.java b/src/main/java/org/olat/core/util/vfs/version/OrphanVersion.java
deleted file mode 100644
index 4019229b03698bd7559d7268f1ae39e1cef17d6b..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/core/util/vfs/version/OrphanVersion.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/**
- * <a href="http://www.openolat.org">
- * OpenOLAT - Online Learning and Training</a><br>
- * <p>
- * Licensed under the Apache License, Version 2.0 (the "License"); <br>
- * you may not use this file except in compliance with the License.<br>
- * You may obtain a copy of the License at the
- * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
- * <p>
- * Unless required by applicable law or agreed to in writing,<br>
- * software distributed under the License is distributed on an "AS IS" BASIS, <br>
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
- * See the License for the specific language governing permissions and <br>
- * limitations under the License.
- * <p>
- * Initial code contributed and copyrighted by<br>
- * frentix GmbH, http://www.frentix.com
- * <p>
- */
-package org.olat.core.util.vfs.version;
-
-import org.olat.core.util.vfs.LocalImpl;
-import org.olat.core.util.vfs.VFSLeaf;
-
-/**
- * 
- * Description:<br>
- * TODO: srosse Class Description for OrphanVersion
- * 
- * <P>
- * Initial Date:  5 mai 2011 <br>
- * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
- */
-//fxdiff FXOLAT-127: file versions maintenance tool
-public class OrphanVersion {
-	
-	private final VFSLeaf orphan;
-	private final VFSLeaf versionsLeaf;
-	private final Versions versions;
-	
-	public OrphanVersion(VFSLeaf orphan, VFSLeaf versionsLeaf, Versions versions) {
-		this.orphan = orphan;
-		this.versionsLeaf = versionsLeaf;
-		this.versions = versions;
-	}
-	
-	public VFSLeaf getOrphan() {
-		return orphan;
-	}
-	
-	public VFSLeaf getVersionsLeaf() {
-		return versionsLeaf;
-	}
-	
-	public Versions getVersions() {
-		return versions;
-	}
-	
-	public String getOriginalFilePath() {
-		if(orphan instanceof LocalImpl) {
-			return ((LocalImpl)orphan).getBasefile().toString();
-		}
-		return orphan.toString();
-	}
-}
\ No newline at end of file
diff --git a/src/main/java/org/olat/core/util/vfs/version/RevisionFileImpl.java b/src/main/java/org/olat/core/util/vfs/version/RevisionFileImpl.java
index df713e6f7c1458c0ce2bbb43df5da6781a829d72..31cd59963bd4d97565dd4d566004e833c9777a82 100644
--- a/src/main/java/org/olat/core/util/vfs/version/RevisionFileImpl.java
+++ b/src/main/java/org/olat/core/util/vfs/version/RevisionFileImpl.java
@@ -19,9 +19,10 @@
  */
 package org.olat.core.util.vfs.version;
 
-import java.io.InputStream;
+import java.util.Date;
 
 import org.olat.core.commons.services.vfs.VFSMetadata;
+import org.olat.core.id.Identity;
 import org.olat.core.util.vfs.VFSContainer;
 import org.olat.core.util.vfs.VFSLeaf;
 
@@ -36,9 +37,9 @@ import org.olat.core.util.vfs.VFSLeaf;
  * 
  * @author srosse
  */
-public class RevisionFileImpl implements VFSRevision {
+public class RevisionFileImpl {
 
-	private String author;
+	private Identity author;
 	private String comment;
 	private String name;
 	private String uuid;
@@ -46,7 +47,7 @@ public class RevisionFileImpl implements VFSRevision {
 
 	private VFSLeaf file;
 	private VFSContainer container;
-	private String revisionNr;
+	private int revisionNr;
 	private String filename;
 	private VFSMetadata metadata;
 
@@ -83,12 +84,11 @@ public class RevisionFileImpl implements VFSRevision {
 		this.container = container;
 	}
 
-	@Override
-	public String getAuthor() {
+	public Identity getAuthor() {
 		return author;
 	}
 
-	public void setAuthor(String author) {
+	public void setAuthor(Identity author) {
 		this.author = author;
 	}
 
@@ -100,7 +100,6 @@ public class RevisionFileImpl implements VFSRevision {
 		this.filename = filename;
 	}
 
-	@Override
 	public String getComment() {
 		return comment;
 	}
@@ -109,28 +108,23 @@ public class RevisionFileImpl implements VFSRevision {
 		this.comment = comment;
 	}
 
-	@Override
 	public long getSize() {
 		VFSLeaf f = getFile();
 		return f == null ? -1l : f.getSize();
 	}
 
-	@Override
-	public InputStream getInputStream() {
-		VFSLeaf f = getFile();
-		return f == null ? null : f.getInputStream();
+	public Date getFileLastModified() {
+		return new Date(lastModified);
 	}
-
-	@Override
-	public long getLastModified() {
-		return lastModified;
+	
+	public void setFileLastModified(Date date) {
+		lastModified = date == null ? -1l : date.getTime();
 	}
 
 	public void setLastModified(long lastModified) {
 		this.lastModified = lastModified;
 	}
 
-	@Override
 	public String getName() {
 		if (name == null || name.length() == 0) { return getFilename(); }
 		return name;
@@ -148,12 +142,11 @@ public class RevisionFileImpl implements VFSRevision {
 		this.metadata = metadata;
 	}
 
-	@Override
-	public String getRevisionNr() {
+	public int getRevisionNr() {
 		return revisionNr;
 	}
 
-	public void setRevisionNr(String revisionNr) {
+	public void setRevisionNr(int revisionNr) {
 		this.revisionNr = revisionNr;
 	}
 
diff --git a/src/main/java/org/olat/core/util/vfs/version/SimpleVersionConfig.java b/src/main/java/org/olat/core/util/vfs/version/SimpleVersionConfig.java
deleted file mode 100644
index ddae1f004ef4321d7e10694ca5de418d03b5550b..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/core/util/vfs/version/SimpleVersionConfig.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/**
- * <a href="http://www.openolat.org">
- * OpenOLAT - Online Learning and Training</a><br>
- * <p>
- * Licensed under the Apache License, Version 2.0 (the "License"); <br>
- * you may not use this file except in compliance with the License.<br>
- * You may obtain a copy of the License at the
- * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
- * <p>
- * Unless required by applicable law or agreed to in writing,<br>
- * software distributed under the License is distributed on an "AS IS" BASIS, <br>
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
- * See the License for the specific language governing permissions and <br>
- * limitations under the License.
- * <p>
- * Initial code contributed and copyrighted by<br>
- * frentix GmbH, http://www.frentix.com
- * <p>
- */
-package org.olat.core.util.vfs.version;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.olat.core.commons.modules.bc.FolderConfig;
-import org.olat.core.configuration.AbstractSpringModule;
-import org.olat.core.util.StringHelper;
-import org.olat.core.util.coordinate.CoordinatorManager;
-import org.olat.core.util.event.GenericEventListener;
-import org.olat.core.util.vfs.LocalFolderImpl;
-import org.olat.core.util.vfs.MergeSource;
-import org.olat.core.util.vfs.NamedContainerImpl;
-import org.olat.core.util.vfs.VFSContainer;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Service;
-
-/**
- * 
- * Description:<br>
- * A very simple configuration bean for versioning. There is a default value for
- * the maximum allowed number of revisions, this number can be overridden by an
- * second value saved in the persisted properties.
- * 
- * <P>
- * Initial Date: 21 sept. 2009 <br>
- * 
- * @author srosse
- */
-@Service("versioningConfigurator")
-public class SimpleVersionConfig extends AbstractSpringModule implements GenericEventListener, FolderVersioningConfigurator {
-
-	private static final String MAX_NUMBER_OF_VERSIONS = "maxnumber.versions";
-	private static final String COURSE_PATH = "/course/";
-	private static final String SOLUTIONS_PATH = "/solutions/";
-	private static final String RETURNBOXES_PATH = "/returnboxes/";
-	private static final String DROPBOXES = "/dropboxes/";
-	private static final String TASKFOLDERS = "/taskfolders/";
-	
-	private static final String[] EXCLUSIONS_IN_COURSE_PATH = {SOLUTIONS_PATH, RETURNBOXES_PATH, DROPBOXES, TASKFOLDERS};
-
-	@Value("${maxnumber.versions:0}")
-	private int maxNumberOfVersions;
-
-	private String courseRoot;
-	private List<String> excludedRoots;
-
-	/**
-	 * [used by spring]
-	 */
-	@Autowired
-	public SimpleVersionConfig(CoordinatorManager coordinatorManager) {
-		super(coordinatorManager);
-	}
-
-	@Override
-	public boolean isEnabled() {
-		return maxNumberOfVersions > 0;
-	}
-
-	@Override
-	public void init() {
-		String maxNumberOfVersionsObj = getStringPropertyValue(MAX_NUMBER_OF_VERSIONS, true);
-		if(StringHelper.containsNonWhitespace(maxNumberOfVersionsObj)) {
-			maxNumberOfVersions = Integer.parseInt(maxNumberOfVersionsObj);
-		}
-	}
-
-	@Override
-	protected void initFromChangedProperties() {
-		init();
-	}
-
-	/**
-	 * @return maximum number of revisions, defined in admin. of Olat
-	 */
-	public int getMaxNumberOfVersionsProperty() {
-		return maxNumberOfVersions;
-	}
-
-	public void setMaxNumberOfVersionsProperty(int maxNumber) {
-		this.maxNumberOfVersions = maxNumber;
-		setStringProperty(MAX_NUMBER_OF_VERSIONS, Integer.toString(maxNumber), true);
-	}
-
-	@Override
-	public int getMaxNumOfVersionsAllowed() {
-		return getVersionAllowed();
-	}
-
-	@Override
-	public int versionAllowed(String relPath) {
-		if(relPath == null) {
-			return 0;
-		}
-		if(StringHelper.containsNonWhitespace(relPath)) {
-			if(relPath.startsWith("/tmp/")//no versioning in tmp
-					|| relPath.startsWith("/scorm/")//there is already a versioning in assessment tool
-					|| relPath.startsWith("/portfolio/")//portfolio is not a folder
-					|| relPath.startsWith("/forum/")) {//forum is not a folder
-				return 0;
-			}
-		}
-		return getVersionAllowed() ;
-	}
-
-	@Override
-	public boolean versionEnabled(VFSContainer container) {
-		int versionsAllowed = getVersionAllowed();
-		if(versionsAllowed == 0) {
-			return false;
-		}
-
-		if (container instanceof NamedContainerImpl) {
-			container = ((NamedContainerImpl) container).getDelegate();
-		}
-		if (container instanceof MergeSource) {
-			container = ((MergeSource)container).getRootWriteContainer();
-		}
-		
-		if (container instanceof LocalFolderImpl) {
-			try {
-				LocalFolderImpl folderImpl = (LocalFolderImpl)container;
-				String path = folderImpl.getBasefile().getCanonicalPath();
-				List<String> exRoots = getExcludedRoots();
-				for(String excludedRoot:exRoots) {
-					if(path.startsWith(excludedRoot)) {
-						return false;
-					}
-				}
-
-				String root = getCourseRoot();
-				if (path.startsWith(root)) {
-					for(String exclusion:EXCLUSIONS_IN_COURSE_PATH) {
-						if(path.indexOf(exclusion) > 0) {
-							return false;
-						}
-					}
-				}
-				return getVersionAllowed() != 0;
-			} catch (IOException e) {
-				//fail silently
-			}
-		}
-		return false;
-	}
-	
-	private int getVersionAllowed() {
-		return getMaxNumberOfVersionsProperty();
-	}
-	
-	private String getCourseRoot() {
-		if(courseRoot == null) {
-			courseRoot = FolderConfig.getCanonicalRoot();
-			courseRoot += COURSE_PATH;
-		}
-		return courseRoot;
-	}
-	
-	private List<String> getExcludedRoots() {
-		if(excludedRoots == null) {
-			excludedRoots = new ArrayList<>();
-			excludedRoots.add(FolderConfig.getCanonicalTmpDir());
-			String bcroot = FolderConfig.getCanonicalRoot();
-			excludedRoots.add(bcroot + "/forum");
-			excludedRoots.add(bcroot + "/portfolio");
-			excludedRoots.add(bcroot + "/scorm");
-		}
-		return excludedRoots;
-	}
-}
diff --git a/src/main/java/org/olat/core/util/vfs/version/Versionable.java b/src/main/java/org/olat/core/util/vfs/version/Versionable.java
deleted file mode 100644
index 913212851334d8e167c23eedef087043a465877f..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/core/util/vfs/version/Versionable.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/**
- * <a href="http://www.openolat.org">
- * OpenOLAT - Online Learning and Training</a><br>
- * <p>
- * Licensed under the Apache License, Version 2.0 (the "License"); <br>
- * you may not use this file except in compliance with the License.<br>
- * You may obtain a copy of the License at the
- * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
- * <p>
- * Unless required by applicable law or agreed to in writing,<br>
- * software distributed under the License is distributed on an "AS IS" BASIS, <br>
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
- * See the License for the specific language governing permissions and <br>
- * limitations under the License.
- * <p>
- * Initial code contributed and copyrighted by<br>
- * frentix GmbH, http://www.frentix.com
- * <p>
- */
-package org.olat.core.util.vfs.version;
-
-/**
- * 
- * Description:<br>
- * A VFSItem which want to be versioned must implements this interface.
- * 
- * <P>
- * Initial Date: 21 sept. 2009 <br>
- * 
- * @author srosse
- */
-public interface Versionable {
-
-	public Versions getVersions();
-
-}
diff --git a/src/main/java/org/olat/core/util/vfs/version/Versions.java b/src/main/java/org/olat/core/util/vfs/version/Versions.java
deleted file mode 100644
index 8de0d815927446a2f241bc0f3d1abb1658966c85..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/core/util/vfs/version/Versions.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/**
- * <a href="http://www.openolat.org">
- * OpenOLAT - Online Learning and Training</a><br>
- * <p>
- * Licensed under the Apache License, Version 2.0 (the "License"); <br>
- * you may not use this file except in compliance with the License.<br>
- * You may obtain a copy of the License at the
- * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
- * <p>
- * Unless required by applicable law or agreed to in writing,<br>
- * software distributed under the License is distributed on an "AS IS" BASIS, <br>
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
- * See the License for the specific language governing permissions and <br>
- * limitations under the License.
- * <p>
- * Initial code contributed and copyrighted by<br>
- * frentix GmbH, http://www.frentix.com
- * <p>
- */
-package org.olat.core.util.vfs.version;
-
-import java.io.InputStream;
-import java.util.List;
-
-import org.olat.core.id.Identity;
-import org.olat.core.util.vfs.VFSContainer;
-
-/**
- * 
- * Description:<br>
- * The interface which enabled the versioning
- * <P>
- * Initial Date: 21 sept. 2009 <br>
- * 
- * @author srosse
- */
-public interface Versions {
-
-	/**
-	 * @return true if the file is versioned
-	 */
-	public boolean isVersioned();
-
-	/**
-	 * @return the current version number
-	 */
-	public String getRevisionNr();
-	
-	/**
-	 * @return the current author of the file
-	 */
-	public String getAuthor();
-
-	/**
-	 * @return creator of the file
-	 */
-	public String getCreator();
-	
-	/**
-	 * @return comment on the current version
-	 */
-	public String getComment();
-
-	/**
-	 * @return the list of revisions
-	 */
-	public List<VFSRevision> getRevisions();
-
-	/**
-	 * add a new version of the file
-	 * @param identity
-	 * @param comment
-	 * @param newVersion
-	 * @return
-	 */
-	public boolean addVersion(Identity identity, String comment, InputStream newVersion);
-
-	/**
-	 * move the file
-	 * @param container
-	 * @return true if successful
-	 */
-	public boolean move(VFSContainer container);
-	
-	/**
-	 * Copy the file
-	 * @param container
-	 * @return true if successful
-	 */
-	public boolean copy(VFSContainer container);
-
-	/**
-	 * restore the file to the revision given as parameter
-	 * @param identity
-	 * @param revision
-	 * @return
-	 */
-	public boolean restore(Identity identity, VFSRevision revision, String comment);
-
-	/**
-	 * Delete the list of revisions given as parameter
-	 * @param identity
-	 * @param revisionsToDelete
-	 * @return
-	 */
-	public boolean delete(Identity identity, List<VFSRevision> revisionsToDelete);
-}
diff --git a/src/main/java/org/olat/core/util/vfs/version/VersionsFileImpl.java b/src/main/java/org/olat/core/util/vfs/version/VersionsFileImpl.java
index d725a54651ef1d4f91a9723c0a2be09e65c42c27..6b53323ef48635e136a1fea0a20c4a7eea8c5317 100644
--- a/src/main/java/org/olat/core/util/vfs/version/VersionsFileImpl.java
+++ b/src/main/java/org/olat/core/util/vfs/version/VersionsFileImpl.java
@@ -19,13 +19,10 @@
  */
 package org.olat.core.util.vfs.version;
 
-import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.olat.core.CoreSpringFactory;
-import org.olat.core.id.Identity;
-import org.olat.core.util.vfs.VFSContainer;
+import org.olat.core.commons.services.vfs.VFSRevision;
 import org.olat.core.util.vfs.VFSLeaf;
 
 /**
@@ -40,14 +37,14 @@ import org.olat.core.util.vfs.VFSLeaf;
  * 
  * @author srosse
  */
-public class VersionsFileImpl implements Versions {
+public class VersionsFileImpl {
 
 	private boolean versioned;
 	private String author;
 	private String creator;
-	private String revisionNr;
+	private int revisionNr;
 	private String comment;
-	private Versionable currentVersion;
+	private Object currentVersion;
 	private VFSLeaf versionFile;
 	private List<VFSRevision> revisions;
 
@@ -55,12 +52,11 @@ public class VersionsFileImpl implements Versions {
 	//
 	}
 
-	@Override
-	public String getRevisionNr() {
+	public int getRevisionNr() {
 		return revisionNr;
 	}
 
-	public void setRevisionNr(String revisionNr) {
+	public void setRevisionNr(int revisionNr) {
 		this.revisionNr = revisionNr;
 	}
 
@@ -72,40 +68,14 @@ public class VersionsFileImpl implements Versions {
 		this.versionFile = versionFile;
 	}
 
-	public Versionable getCurrentVersion() {
+	public Object getCurrentVersion() {
 		return currentVersion;
 	}
 
-	public void setCurrentVersion(Versionable currentVersion) {
+	public void setCurrentVersion(Object currentVersion) {
 		this.currentVersion = currentVersion;
 	}
 
-	@Override
-	public boolean addVersion(Identity identity, String comments, InputStream newVersion) {
-		return CoreSpringFactory.getImpl(VersionsManager.class).addVersion(getCurrentVersion(), identity, comments, newVersion);
-	}
-
-	@Override
-	public boolean move(VFSContainer container) {
-		return CoreSpringFactory.getImpl(VersionsManager.class).move(getCurrentVersion(), container);
-	}
-
-	@Override
-	public boolean copy(VFSContainer container) {
-		return CoreSpringFactory.getImpl(VersionsManager.class).copy(getCurrentVersion(), container);
-	}
-
-	@Override
-	public boolean restore(Identity identity, VFSRevision version, String comments) {
-		return CoreSpringFactory.getImpl(VersionsManager.class).restore(getCurrentVersion(), version, comments);
-	}
-
-	@Override
-	public boolean delete(Identity identity, List<VFSRevision> revisionsToDelete) {
-		return CoreSpringFactory.getImpl(VersionsManager.class).deleteRevisions(getCurrentVersion(), revisionsToDelete);
-	}
-
-	@Override
 	public List<VFSRevision> getRevisions() {
 		if (revisions == null) {
 			revisions = new ArrayList<>();
@@ -117,7 +87,6 @@ public class VersionsFileImpl implements Versions {
 		this.revisions = revisions;
 	}
 
-	@Override
 	public boolean isVersioned() {
 		return versioned;
 	}
@@ -126,7 +95,6 @@ public class VersionsFileImpl implements Versions {
 		this.versioned = versioned;
 	}
 
-	@Override
 	public String getAuthor() {
 		return author;
 	}
@@ -135,7 +103,6 @@ public class VersionsFileImpl implements Versions {
 		this.author = author;
 	}
 
-	@Override
 	public String getCreator() {
 		return creator;
 	}
@@ -144,7 +111,6 @@ public class VersionsFileImpl implements Versions {
 		this.creator = creator;
 	}
 
-	@Override
 	public String getComment() {
 		return comment;
 	}
@@ -152,18 +118,4 @@ public class VersionsFileImpl implements Versions {
 	public void setComment(String comment) {
 		this.comment = comment;
 	}
-
-	protected void update(Versions newVersions) {
-		if (newVersions instanceof VersionsFileImpl) {
-			VersionsFileImpl newVersionsImpl = (VersionsFileImpl) newVersions;
-			author = newVersionsImpl.getAuthor();
-			creator = newVersionsImpl.getCreator();
-			currentVersion = newVersionsImpl.getCurrentVersion();
-			revisionNr = newVersionsImpl.getRevisionNr();
-			comment = newVersionsImpl.getComment();
-		}
-
-		revisions = new ArrayList<>();
-		revisions.addAll(newVersions.getRevisions());
-	}
 }
diff --git a/src/main/java/org/olat/core/util/vfs/version/VersionsFileManager.java b/src/main/java/org/olat/core/util/vfs/version/VersionsFileManager.java
deleted file mode 100644
index 83c44b8877b91b5b473df29f3a2cf05c493dd73e..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/core/util/vfs/version/VersionsFileManager.java
+++ /dev/null
@@ -1,1062 +0,0 @@
-/**
- * <a href="http://www.openolat.org">
- * OpenOLAT - Online Learning and Training</a><br>
- * <p>
- * Licensed under the Apache License, Version 2.0 (the "License"); <br>
- * you may not use this file except in compliance with the License.<br>
- * You may obtain a copy of the License at the
- * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
- * <p>
- * Unless required by applicable law or agreed to in writing,<br>
- * software distributed under the License is distributed on an "AS IS" BASIS, <br>
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
- * See the License for the specific language governing permissions and <br>
- * limitations under the License.
- * <p>
- * Initial code contributed and copyrighted by<br>
- * frentix GmbH, http://www.frentix.com
- * <p>
- */
-package org.olat.core.util.vfs.version;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Scanner;
-import java.util.Set;
-import java.util.UUID;
-import java.util.regex.Pattern;
-import java.util.zip.Adler32;
-import java.util.zip.Checksum;
-
-import org.apache.commons.io.FileUtils;
-import org.olat.core.commons.modules.bc.FolderConfig;
-import org.olat.core.commons.services.vfs.VFSMetadata;
-import org.olat.core.commons.services.vfs.VFSRepositoryService;
-import org.olat.core.commons.services.vfs.manager.VFSXStream;
-import org.olat.core.id.Identity;
-import org.olat.core.logging.OLog;
-import org.olat.core.logging.Tracing;
-import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
-import org.olat.core.util.StringHelper;
-import org.olat.core.util.async.ProgressDelegate;
-import org.olat.core.util.io.ShieldInputStream;
-import org.olat.core.util.vfs.JavaIOItem;
-import org.olat.core.util.vfs.LocalFileImpl;
-import org.olat.core.util.vfs.LocalFolderImpl;
-import org.olat.core.util.vfs.LocalImpl;
-import org.olat.core.util.vfs.MergeSource;
-import org.olat.core.util.vfs.NamedContainerImpl;
-import org.olat.core.util.vfs.VFSConstants;
-import org.olat.core.util.vfs.VFSContainer;
-import org.olat.core.util.vfs.VFSItem;
-import org.olat.core.util.vfs.VFSLeaf;
-import org.olat.core.util.vfs.VFSManager;
-import org.olat.core.util.vfs.filters.VFSSystemItemFilter;
-import org.olat.core.util.vfs.filters.VFSItemSuffixFilter;
-import org.olat.core.util.vfs.filters.VFSLeafFilter;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-/**
- * 
- * Description:<br>
- * This implementation of the VersionsManager saved the revisions of a file in a
- * file with the same name as the original + ".xml". This xml file is saved in
- * a parallel folder .version under the root defined in FolderConfig. Every revision'file
- * have a name made of a generated unique id + the name of the original file.
- * 
- * <P>
- * Initial Date:  21 sept. 2009 <br>
- *
- * @author srosse
- */
-@Service("versionsManager")
-public class VersionsFileManager implements VersionsManager {
-	private static final OLog log = Tracing.createLoggerFor(VersionsFileManager.class);
-
-	private static final Versions NOT_VERSIONED = new NotVersioned();
-	private static final Pattern TAG_PATTERN = Pattern.compile("\\s*[<>]\\s*");
-
-	private File rootFolder;
-	private File rootVersionFolder;
-	private VFSContainer rootVersionsContainer;
-	
-	@Autowired
-	private VFSRepositoryService vfsRepositoryService;
-	@Autowired
-	private FolderVersioningConfigurator versioningConfigurator;
-
-	@Override
-	public boolean isEnabled() {
-		return versioningConfigurator.isEnabled();
-	}
-
-	@Override
-	public Versions createVersionsFor(VFSLeaf leaf) {
-		return createVersionsFor(leaf, false);
-	}
-	
-	@Override
-	public Versions createVersionsFor(VFSLeaf leaf, boolean force) {
-		if (!(leaf instanceof Versionable) || isVersionFile(leaf)) {
-			return NOT_VERSIONED;
-		}
-
-		return readVersions(leaf, false);
-	}
-
-	@Override
-	public List<Versions> getDeletedFiles(VFSContainer container) {
-		List<Versions> deletedRevisions = new ArrayList<>();
-
-		VFSContainer versionContainer = getCanonicalVersionFolder(container, false);
-		if (versionContainer != null) {
-			Set<String> currentNames = new HashSet<>();
-			for (VFSItem item : container.getItems(new VFSLeafFilter())) {
-				currentNames.add(item.getName() + ".xml");
-			}
-
-			List<VFSItem> versionItems = versionContainer.getItems(new VFSItemSuffixFilter(new String[] { "xml" }));
-			for (VFSItem versionItem : versionItems) {
-				String name = versionItem.getName();
-				if (versionItem instanceof VFSLeaf && !currentNames.contains(name) && isVersionsXmlFile((VFSLeaf)versionItem)) {
-					Versions versions = readVersions(null, (VFSLeaf) versionItem);
-					if(versions != null) {
-						List<VFSRevision> revisions = versions.getRevisions();
-						if (!revisions.isEmpty()) {
-							deletedRevisions.add(versions);
-						}
-					}
-				}
-			}
-		}
-		return deletedRevisions;
-	}
-
-	private Versions readVersions(VFSLeaf leaf, boolean create) {
-		VFSLeaf fVersions = getCanonicalVersionXmlFile(leaf, create);
-		if (!create && fVersions == null) {
-			VersionsFileImpl versions = new VersionsFileImpl();
-			versions.setCurrentVersion((Versionable) leaf);
-			versions.setVersioned(isVersioned(leaf));
-			versions.setRevisionNr(getNextRevisionNr(versions));
-			return versions;
-		}
-		return readVersions(leaf, fVersions);
-	}
-	
-	private boolean isVersionsXmlFile(VFSLeaf fVersions) {
-		if (fVersions == null || !fVersions.exists()) {
-			return false;
-		}
-		
-		boolean foundVersionsTag = false;
-		try(InputStream in = fVersions.getInputStream()) {
-			if (in == null) {
-				return false;
-			}
-	
-			Scanner scanner = new Scanner(in);
-			scanner.useDelimiter(TAG_PATTERN);
-			while (scanner.hasNext()) {
-				String tag = scanner.next();
-				if ("versions".equals(tag)) {
-					foundVersionsTag = true;
-					break;
-				}
-			}
-	
-			scanner.close();
-		} catch(IOException e) {
-			log.error("", e);
-		}
-		return foundVersionsTag;
-	}
-
-	private Versions readVersions(VFSLeaf leaf, VFSLeaf fVersions) {
-		if (fVersions == null) { return new NotVersioned(); }
-
-		try {
-			VFSContainer fVersionContainer = fVersions.getParentContainer();
-			VersionsFileImpl versions = (VersionsFileImpl) VFSXStream.read(fVersions);
-			versions.setVersionFile(fVersions);
-			versions.setCurrentVersion((Versionable) leaf);
-			if (versions.getRevisionNr() == null || versions.getRevisionNr().length() == 0) {
-				versions.setRevisionNr(getNextRevisionNr(versions));
-			}
-
-			for (VFSRevision revision : versions.getRevisions()) {
-				RevisionFileImpl revisionImpl = (RevisionFileImpl) revision;
-				revisionImpl.setContainer(fVersionContainer);
-			}
-			return versions;
-		} catch (Exception e) {
-			log.warn("This file is not a versions XML file: " + fVersions, e);
-			fVersions.delete();
-			VersionsFileImpl versions = new VersionsFileImpl();
-			versions.setCurrentVersion((Versionable) leaf);
-			versions.setVersioned(isVersioned(leaf));
-			versions.setRevisionNr(getNextRevisionNr(versions));
-			log.warn("Deleted corrupt version XML file and created new version XML file: " + versions);
-			// the old revisions can not be restored automatically. They are still on disk, you could recover them
-			// manually. This is not a perfect solution, but at least the user does not get an RS
-			return versions;
-		}
-	}
-
-	@Override
-	public boolean addVersion(Versionable currentVersion, Identity identity, String comment, InputStream newFile) {
-		VFSLeaf currentFile = (VFSLeaf) currentVersion;
-		if (addToRevisions(currentVersion, identity, comment)) {
-			// copy the content of the new file to the old
-			if(newFile instanceof net.sf.jazzlib.ZipInputStream || newFile instanceof java.util.zip.ZipInputStream) {
-				newFile = new ShieldInputStream(newFile);
-			}
-			return VFSManager.copyContent(newFile, currentFile);
-		} else {
-			log.error("Cannot create a version of this file: " + currentVersion);
-		}
-		return false;
-	}
-
-	@Override
-	public boolean move(VFSLeaf currentFile, VFSLeaf targetFile, Identity author) {
-		VFSLeaf fCurrentVersions = getCanonicalVersionXmlFile(currentFile, true);
-		Versions currentVersions = readVersions(currentFile, fCurrentVersions);
-		
-		boolean brandNewVersionFile = false;
-		VFSLeaf fTargetVersions = getCanonicalVersionXmlFile(targetFile, false);
-		if(fTargetVersions == null) {
-			brandNewVersionFile = true;
-			fTargetVersions = getCanonicalVersionXmlFile(targetFile, true);
-		}
- 
-		Versions targetVersions = readVersions(targetFile, fTargetVersions);
-		if(!(currentVersions instanceof VersionsFileImpl) || !(targetVersions instanceof  VersionsFileImpl)) {
-			return false;
-		}
-		
-		VersionsFileImpl targetVersionsImpl = (VersionsFileImpl)targetVersions;
-		if(author != null) {
-			targetVersionsImpl.setAuthor(author.getName());
-		}
-		if(brandNewVersionFile) {
-			targetVersionsImpl.setCreator(currentVersions.getCreator());
-			targetVersionsImpl.setComment(currentVersions.getComment());
-		}
-
-		boolean allOk = true;
-		for(VFSRevision revision:currentVersions.getRevisions()) {
-			allOk &= copyRevision(revision, fTargetVersions, targetVersionsImpl);
-		}
-
-		targetVersionsImpl.setRevisionNr(getNextRevisionNr(targetVersionsImpl));
-		VFSXStream.write(fTargetVersions, targetVersionsImpl);
-
-		return allOk;
-	}
-	
-	private boolean copyRevision(VFSRevision revision, VFSLeaf fNewVersions, VersionsFileImpl targetVersions) {
-		if(!(revision instanceof RevisionFileImpl)) {
-			log.warn("Copy only copy persisted revisions", null);
-		}
-		
-		RevisionFileImpl revisionImpl = (RevisionFileImpl)revision;
-		String revUuid = revisionImpl.getUuid();
-		for(VFSRevision rev:targetVersions.getRevisions()) {
-			if(rev instanceof RevisionFileImpl) {
-				RevisionFileImpl fRev = (RevisionFileImpl)rev;
-				if(StringHelper.containsNonWhitespace(fRev.getUuid()) && fRev.getUuid().equals(revUuid)) {
-					return true;
-				}
-			}
-		}
-
-		String uuid = UUID.randomUUID().toString().replace("-", "") + "_" + revision.getName();
-		
-		RevisionFileImpl newRevision = new RevisionFileImpl();
-		newRevision.setName(revision.getName());
-		newRevision.setFilename(uuid);
-		newRevision.setRevisionNr(getNextRevisionNr(targetVersions));
-		newRevision.setComment(revision.getComment());
-		newRevision.setAuthor(revision.getAuthor());
-		newRevision.setLastModified(revision.getLastModified());
-		newRevision.setUuid(revUuid);
-
-		//copy -> the files revision
-		try(InputStream revisionIn = revision.getInputStream()) {
-			VFSLeaf target = fNewVersions.getParentContainer().createChildLeaf(uuid);
-			if (VFSManager.copyContent(revisionIn, target)) {
-				targetVersions.setComment(revision.getComment());
-				targetVersions.getRevisions().add(newRevision);
-				targetVersions.setRevisionNr(getNextRevisionNr(targetVersions));
-				targetVersions.setAuthor(revision.getAuthor());
-				return true;
-			}
-		} catch(Exception e) {
-			log.error("", e);
-		}
-		return false;
-	}
-	
-	@Override
-	public boolean copy(Versionable currentVersion, VFSContainer container) {
-		VFSLeaf currentFile = (VFSLeaf) currentVersion;
-		VFSLeaf fVersions = getCanonicalVersionXmlFile(currentFile, true);
-		Versions versions = readVersions(currentFile, fVersions);
-
-		VFSContainer versionContainer = getCanonicalVersionFolder(container, true);
-		return copy(versionContainer, fVersions, versions);
-	}
-
-	@Override
-	public boolean move(Versionable currentVersion, VFSContainer container) {
-		VFSLeaf currentFile = (VFSLeaf) currentVersion;
-		VFSLeaf fVersions = getCanonicalVersionXmlFile(currentFile, true);
-		Versions versions = readVersions(currentFile, fVersions);
-
-		VFSContainer versionContainer = getCanonicalVersionFolder(container, true);
-		boolean allOk = copy(versionContainer, fVersions, versions);
-
-		allOk &= VFSConstants.YES.equals(fVersions.delete());
-		for (VFSRevision revision : versions.getRevisions()) {
-			VFSLeaf revisionFile = ((RevisionFileImpl) revision).getFile();
-			if (revisionFile != null) {
-				allOk &= VFSConstants.YES.equals(revisionFile.delete());
-			}
-		}
-		return allOk;
-	}
-	
-	private boolean copy(VFSContainer versionContainer, VFSLeaf fVersions, Versions versions) {
-		boolean allOk = VFSConstants.YES.equals(versionContainer.copyFrom(fVersions));
-		for (VFSRevision revision : versions.getRevisions()) {
-			RevisionFileImpl revisionImpl = (RevisionFileImpl) revision;
-			VFSLeaf revisionFile = revisionImpl.getFile();
-			if (revisionFile != null) {
-				allOk &= VFSConstants.YES.equals(versionContainer.copyFrom(revisionFile));
-			}
-		}
-		return allOk;
-	}
-
-	@Override
-	public boolean restore(Versionable currentVersion, VFSRevision version, String comment) {
-		VFSLeaf currentFile = (VFSLeaf) currentVersion;
-		if(!VFSManager.exists(currentFile)) {
-			return false;
-		}
-		
-		// add current version to versions file
-		if (addToRevisions(currentVersion, null, comment)) {
-			// copy the content of the new file to the old
-			if (VFSManager.copyContent(version.getInputStream(), currentFile)) { return true; }
-		} else {
-			log.error("Cannot create a version of this file: " + currentVersion);
-		}
-
-		return false;
-	}
-
-	@Override
-	public boolean restore(VFSContainer container, VFSRevision revision) {
-		String filename = revision.getName();
-		VFSItem restoredItem = container.resolve(filename);
-		boolean restoreDeletedFile = restoredItem == null;
-		if (restoredItem == null) {
-			restoredItem = container.createChildLeaf(filename);
-		}
-		
-		if (restoredItem instanceof VFSLeaf) {
-			VFSLeaf restoredLeaf = (VFSLeaf) restoredItem;
-			try(InputStream inStream = revision.getInputStream()) {
-				if (VFSManager.copyContent(inStream, restoredLeaf)) {
-					VFSLeaf versionFile = getCanonicalVersionXmlFile(restoredLeaf, true);
-					Versions versions = readVersions(restoredLeaf, versionFile);
-					if (versions instanceof VersionsFileImpl) {
-						versions.getRevisions().remove(revision);
-						((VersionsFileImpl) versions).setRevisionNr(getNextRevisionNr(versions));
-						if (revision instanceof RevisionFileImpl) {
-							VFSLeaf fileToDelete = ((RevisionFileImpl)revision).getFile();
-							if(fileToDelete != null) {
-								fileToDelete.deleteSilently();
-							}
-						}
-					}
-					if (restoreDeletedFile && revision instanceof RevisionFileImpl) {
-						VFSMetadata versionedMetadata = ((RevisionFileImpl)revision).getMetadata();
-						VFSMetadata metadata = restoredItem.getMetaInfo();
-						if(versionedMetadata != null && metadata != null) {
-							metadata.copyValues(versionedMetadata);
-							// make sure the restored file is not locked
-							metadata.setLocked(false);
-							metadata.setLockedBy(null);
-							metadata.setLockedDate(null);
-							// restore last values
-							metadata.setUuid(versionedMetadata.getUuid());
-							vfsRepositoryService.updateMetadata(metadata);
-						}
-					}
-					VFSXStream.write(versionFile, versions);
-					return true;
-				}
-			} catch(Exception e) {
-				log.error("", e);
-			}
-		}
-		return false;
-	}
-
-	@Override
-	public boolean deleteRevisions(Versionable currentVersion, List<VFSRevision> versionsToDelete) {
-		VFSLeaf currentFile = (VFSLeaf) currentVersion;
-		Versions versions = readVersions(currentFile, true);
-		List<VFSRevision> allVersions = versions.getRevisions();
-
-		Map<String,VFSLeaf> filenamesToDelete = new HashMap<>(allVersions.size());
-		for (VFSRevision versionToDelete : versionsToDelete) {
-			RevisionFileImpl versionImpl = (RevisionFileImpl) versionToDelete;
-			for (Iterator<VFSRevision> allVersionIt = allVersions.iterator(); allVersionIt.hasNext();) {
-				RevisionFileImpl allVersionImpl = (RevisionFileImpl) allVersionIt.next();
-				if (allVersionImpl.getFilename() != null && allVersionImpl.getFilename().equals(versionImpl.getFilename())) {
-					allVersionIt.remove();
-					break;
-				}
-			}
-
-			VFSLeaf fileToDelete = versionImpl.getFile();
-			if (fileToDelete != null) {
-				filenamesToDelete.put(fileToDelete.getName(), fileToDelete);
-			}
-		}
-		
-		List<RevisionFileImpl> missingFiles = new ArrayList<>();
-		for(VFSRevision survivingVersion:allVersions) {
-			RevisionFileImpl survivingVersionImpl = (RevisionFileImpl)survivingVersion;
-			VFSLeaf revFile = survivingVersionImpl.getFile();
-			if(revFile == null) {
-				missingFiles.add(survivingVersionImpl);//file is missing
-			} else if(filenamesToDelete.containsKey(revFile.getName())) {
-				filenamesToDelete.remove(revFile.getName());
-			}
-		}
-		if(!missingFiles.isEmpty()) {
-			allVersions.removeAll(missingFiles);
-		}
-		
-		for(VFSLeaf fileToDelete:filenamesToDelete.values()) {
-			fileToDelete.deleteSilently();
-		}
-
-		VFSLeaf versionFile = getCanonicalVersionXmlFile(currentFile, true);
-		VFSXStream.write(versionFile, versions);
-		if (currentVersion.getVersions() instanceof VersionsFileImpl) {
-			((VersionsFileImpl) currentVersion.getVersions()).update(versions);
-		}
-		return true;
-	}
-
-	@Override
-	public boolean deleteVersions(VFSContainer container, List<Versions> versions) {
-		for(Versions versionToDelete:versions) {
-			if(versionToDelete instanceof VersionsFileImpl) {
-				VersionsFileImpl versionsImpl = (VersionsFileImpl)versionToDelete;
-				VFSLeaf versionFile = versionsImpl.getVersionFile();
-				if(versionFile != null) {
-					//robust against manual file system manipulation
-					versionFile.deleteSilently();
-				}
-				for (VFSRevision revisionToDelete : versionsImpl.getRevisions()) {
-					RevisionFileImpl versionImpl = (RevisionFileImpl)revisionToDelete;
-					VFSLeaf fileToDelete = versionImpl.getFile();
-					if (fileToDelete != null) {
-						fileToDelete.deleteSilently();
-					}
-					
-					String originFilename = versionImpl.getName();
-					// delete
-					if(container.canMeta().equals(VFSConstants.YES) && container instanceof JavaIOItem) {
-						//if original was completely deleted, delete metadata too
-						File dir = ((JavaIOItem)container).getBasefile();
-						File file = new File(dir, originFilename);
-						if(!file.exists()) {
-							vfsRepositoryService.deleteMetadata(file);
-						}
-					}
-				}
-			}
-		}
-		return true;
-	}
-
-	@Override
-	public boolean delete(VFSItem item, boolean force) {
-		if (item instanceof VFSContainer) {
-			if (force) {
-				VFSContainer container = (VFSContainer)item;
-				VFSContainer versionContainer = getCanonicalVersionFolder(container, false);
-				if (versionContainer == null) { return true; }
-				return VFSConstants.YES.equals(versionContainer.delete());
-			}
-			return true;
-		} else if (item instanceof VFSLeaf && item instanceof Versionable) {
-			VFSLeaf leaf = (VFSLeaf)item;
-			if (force || isTemporaryFile(leaf)) {
-				cleanUp(leaf);
-			} else {
-				Identity identity = ThreadLocalUserActivityLogger.getLoggedIdentity();
-				addToRevisions((Versionable)leaf, identity, null);
-			}
-		}
-		return false;
-	}
-	
-	/**
-	 * Some temporary/lock files of specific editors need to be force deleted
-	 * with all versions. Word can reuse older names.
-	 * @param leaf
-	 * @return
-	 */
-	private boolean isTemporaryFile(VFSLeaf leaf) {
-		String name = leaf.getName();
-		//temporary files
-		if(name.endsWith(".tmp")) {
-			//Word 2010: ~WRD0002.tmp
-			if(name.startsWith("~WRD") || name.startsWith("~WRL")) {
-				return true;
-			}
-			//PowerPoint 2010: ppt5101.tmp 
-			if(name.startsWith("ppt")) {
-				return true;
-			}
-		}
-		//lock files of Word 2010, Excel 2010, PowerPoint 2010:
-		if(name.startsWith("~$") && (name.endsWith(".docx") || name.endsWith(".xlsx") || name.endsWith(".pptx"))) {
-			return true;
-		}
-		
-		//OpenOffice locks: .~lock.Versions_21.odt#
-		if(name.startsWith(".~lock.") && (name.endsWith(".odt#") /* Writer */ || name.endsWith(".ods#") /* Calc */
-				|| name.endsWith(".odp#") /* Impress */ || name.endsWith("odf#") /* Math */
-				|| name.endsWith(".odg#") /* Draw */)) {
-			return true;
-		}
-		//OpenOffice database lock
-		return name.endsWith(".odb.lck");
-	}
-	
-	/**
-	 * Clean up all revisions files, xml file
-	 * @param leaf
-	 */
-	private void cleanUp(VFSLeaf leaf) {
-		String relPath = getRelPath(leaf);
-		if (relPath == null) return; // cannot handle
-
-		File fVersion = new File(getRootVersionsFile(), relPath + ".xml");
-		File fParentVersion = fVersion.getParentFile();
-		if (!fParentVersion.exists()) return; //already deleted
-
-		VFSLeaf versionLeaf = null;
-		if (fVersion.exists()) {
-			LocalFolderImpl localVersionContainer = new LocalFolderImpl(fParentVersion);
-			versionLeaf = (VFSLeaf) localVersionContainer.resolve(fVersion.getName());
-		}
-		
-		if (versionLeaf == null) return; //already deleted
-		Versions versions = readVersions(leaf, versionLeaf);
-		for (VFSRevision versionToDelete : versions.getRevisions()) {
-			RevisionFileImpl versionImpl = (RevisionFileImpl) versionToDelete;
-			VFSLeaf fileToDelete = versionImpl.getFile();
-			if (fileToDelete != null) {
-				fileToDelete.delete();
-			}
-		}
-		versionLeaf.delete();
-	}
-
-	@Override
-	public boolean rename(VFSItem item, String newname) {
-		if (item instanceof VFSLeaf) {
-			VFSLeaf currentFile = (VFSLeaf) item;
-			VFSLeaf versionFile = getCanonicalVersionXmlFile(currentFile, true);
-			// infinite loop if rename is own versions file
-			return VFSConstants.YES.equals(versionFile.rename(newname + ".xml"));
-		} else if (item instanceof VFSContainer) {
-			VFSContainer container = (VFSContainer) item;
-			VFSContainer versionContainer = getCanonicalVersionFolder(container, false);
-			if (versionContainer == null) { return true; }
-			return VFSConstants.YES.equals(versionContainer.rename(newname));
-		}
-		return false;
-	}
-
-	@Override
-	public boolean addToRevisions(Versionable currentVersion, Identity identity, String comment) {
-		int maxNumOfVersions = versioningConfigurator.getMaxNumOfVersionsAllowed();
-		if(maxNumOfVersions == 0) {
-			return true;//deactivated, return all ok
-		}
-		
-		VFSLeaf currentFile = (VFSLeaf) currentVersion;
-		
-		VFSLeaf versionFile = getCanonicalVersionXmlFile(currentFile, true);
-		if(versionFile == null) {
-			return false;//cannot do something with the current file
-		}
-		
-		VFSContainer versionContainer = versionFile.getParentContainer();
-
-		String name = currentFile.getName();
-
-		// read from the
-		Versions v = readVersions(currentFile, versionFile);
-		if (!(v instanceof VersionsFileImpl)) {
-			log.error("Wrong implementation of Versions: " + v);
-			return false;
-		}
-		VersionsFileImpl versions = (VersionsFileImpl) v;
-		boolean sameFile = isSameFile(currentFile, versions);
-		String uuid = sameFile ? getLastRevisionFilename(versions)
-				: UUID.randomUUID().toString() + "_" + name;
-		
-		String versionNr = getNextRevisionNr(versions);
-		String currentAuthor = versions.getAuthor();
-		Date lastModifiedDate = null;
-		
-		VFSMetadata metaInfo = null;
-		if (currentFile.canMeta() == VFSConstants.YES) {
-			metaInfo = currentFile.getMetaInfo();
-			if(metaInfo != null) {
-				vfsRepositoryService.resetThumbnails(currentFile);
-				if(currentAuthor == null && metaInfo.getAuthor() != null) { 
-					currentAuthor = metaInfo.getAuthor().getName();
-				}
-				lastModifiedDate = metaInfo.getLastModified();
-			}
-		}
-		
-		if(lastModifiedDate == null) {
-			Calendar cal = Calendar.getInstance();
-			cal.setTime(new Date());
-			lastModifiedDate = cal.getTime();
-		}
-
-		RevisionFileImpl newRevision = new RevisionFileImpl();
-		newRevision.setUuid(UUID.randomUUID().toString());
-		newRevision.setName(name);
-		newRevision.setFilename(uuid);
-		newRevision.setRevisionNr(versionNr);
-		newRevision.setComment(versions.getComment());
-		newRevision.setAuthor(currentAuthor);
-		newRevision.setLastModified(lastModifiedDate.getTime());
-		//TODO metadata newRevision.setMetadata(metaInfo);
-
-		if (versions.getRevisions().isEmpty() && currentVersion instanceof VFSItem) {
-			VFSMetadata currentMeta = ((VFSItem)currentVersion).getMetaInfo();
-			if(currentMeta != null && currentMeta.getAuthor() != null) {
-				versions.setCreator(currentMeta.getAuthor().getName());
-			}
-		}
-
-		if (sameFile || VFSManager.copyContent(currentFile, versionContainer.createChildLeaf(uuid), false)) {
-			if (identity != null) {
-				versions.setAuthor(identity.getName());
-			}
-
-			if(maxNumOfVersions >= 0 && versions.getRevisions().size() >= maxNumOfVersions) {
-				List<VFSRevision> revisions = versions.getRevisions();
-				int numOfVersionsToDelete = Math.min(revisions.size(), (revisions.size() - maxNumOfVersions) + 1);
-				if(numOfVersionsToDelete > 0) {
-					List<VFSRevision> versionsToDelete = revisions.subList(0, numOfVersionsToDelete);
-					deleteRevisions(currentVersion, versionsToDelete);
-					versions = (VersionsFileImpl)currentVersion.getVersions();
-				}
-			}
-			versions.setComment(comment);
-			versions.getRevisions().add(newRevision);
-			versions.setRevisionNr(getNextRevisionNr(versions));
-			VFSXStream.write(versionFile, versions);
-			if (currentVersion.getVersions() instanceof VersionsFileImpl) {
-				((VersionsFileImpl) currentVersion.getVersions()).update(versions);
-			}
-			return true;
-		} else {
-			log.error("Cannot create a version of this file: " + currentVersion);
-		}
-		return false;
-	}
-	
-	private boolean isSameFile(VFSLeaf currentFile, VersionsFileImpl versions) {
-		boolean same = false;
-		if(versions.getRevisions() != null && !versions.getRevisions().isEmpty()) {
-			VFSRevision lastRevision = versions.getRevisions().get(versions.getRevisions().size() -1);
-			
-			long lastSize = lastRevision.getSize();
-			long currentSize = currentFile.getSize();
-			if(currentSize == lastSize && currentSize > 0
-					&& lastRevision instanceof RevisionFileImpl
-					&& currentFile instanceof LocalFileImpl) {
-				RevisionFileImpl lastRev = ((RevisionFileImpl)lastRevision);
-				LocalFileImpl current = (LocalFileImpl)currentFile;
-					//can be the same file
-				try {
-					Checksum cm1 = FileUtils.checksum(((LocalFileImpl)lastRev.getFile()).getBasefile() , new Adler32());
-					Checksum cm2 = FileUtils.checksum(current.getBasefile() , new Adler32());
-					same = cm1.getValue() == cm2.getValue();
-				} catch (IOException e) {
-					log.debug("Error calculating the checksum of files");
-				}	
-			}
-		}
-		return same;
-	}
-
-	@Override
-	public String getNextRevisionNr(Versions versions) {
-		int maxNumber = 0;
-		for (VFSRevision version : versions.getRevisions()) {
-			String versionNr = version.getRevisionNr();
-			if (versionNr != null && versionNr.length() > 0) {
-				try {
-					int number = Integer.parseInt(versionNr);
-					maxNumber = Math.max(maxNumber, number);
-				} catch (Exception ex) {
-					// if not a number, don't interest us
-				}
-			}
-		}
-		return Integer.toString(maxNumber + 1);
-	}
-	
-	private String getLastRevisionFilename(Versions versions) {
-		if(versions.getRevisions() == null || versions.getRevisions().isEmpty()) {
-			return null;
-		}
-		
-		VFSRevision revision = versions.getRevisions().get(versions.getRevisions().size() - 1);
-		if(revision instanceof RevisionFileImpl) {
-			return ((RevisionFileImpl)revision).getFilename();
-		}
-		return null;
-	}
-
-	/**
-	 * Get the canonical path to the file's meta file.
-	 * 
-	 * @param bcPath
-	 * @return String
-	 */
-	private VFSLeaf getCanonicalVersionXmlFile(VFSItem item, boolean create) {
-		File f = getOriginFile(item);
-		if (!f.exists()) { return null; }
-
-		String relPath = getRelPath(item);
-		if (relPath == null) {
-			// cannot handle
-			return null;
-		}
-
-		File fVersion = new File(getRootVersionsFile(), relPath + ".xml");
-		File fParentVersion = fVersion.getParentFile();
-		if (!fParentVersion.exists() && create) {
-			fParentVersion.mkdirs();
-		}
-
-		if (fVersion.exists()) {
-			LocalFolderImpl localVersionContainer = new LocalFolderImpl(fParentVersion);
-			return (VFSLeaf) localVersionContainer.resolve(fVersion.getName());
-		} else if (create) {
-			LocalFolderImpl localVersionContainer = new LocalFolderImpl(fParentVersion);
-			VersionsFileImpl versions = new VersionsFileImpl();
-			versions.setVersioned(isVersioned(item));
-			versions.setRevisionNr(getNextRevisionNr(versions));
-			VFSLeaf fVersions = localVersionContainer.createChildLeaf(fVersion.getName());
-			if(fVersions != null) {
-				VFSXStream.write(fVersions, versions);
-			}
-			return fVersions;
-		}
-		return null;
-	}
-
-	protected VFSContainer getCanonicalVersionFolder(VFSContainer container, boolean create) {
-		String relPath = getRelPath(container);
-		if(relPath != null) {
-			File fVersion = new File(getRootVersionsFile(), relPath);
-			if (fVersion.exists()) {
-				return new LocalFolderImpl(fVersion);
-			}
-			if (create) {
-				fVersion.mkdirs();
-				return new LocalFolderImpl(fVersion);
-			}
-		}
-		return null;
-	}
-
-	private String getRelPath(VFSItem item) {
-		if (item instanceof NamedContainerImpl) {
-			item = ((NamedContainerImpl)item).getDelegate();
-		}
-		if (item instanceof MergeSource) {
-			item = ((MergeSource)item).getRootWriteContainer();
-		}
-		return item.getRelPath();
-	}
-
-	private boolean isVersionFile(VFSItem item) {
-		File f = getOriginFile(item);
-		if (f == null) return false;
-
-		try {
-			String path = f.getCanonicalPath();
-			String vPath = getRootVersionsFile().getCanonicalPath();
-			return path.startsWith(vPath);
-		} catch (IOException e) {
-			log.error("Cannot check if this file is a version file: " + item, e);
-			return false;
-		}
-	}
-
-	private boolean isVersioned(VFSItem item) {
-		if (item == null) return false;
-		VFSContainer parent = item.getParentContainer();
-		return FolderConfig.versionsEnabled(parent);
-	}
-
-	private File getOriginFile(VFSItem item) {
-		if (item instanceof LocalImpl) {
-			LocalImpl localImpl = (LocalImpl) item;
-			return localImpl.getBasefile();
-		}
-		
-		String relPath = item.getRelPath();
-		if (relPath != null) {
-			return VFSManager.olatRootFile(relPath);
-		}
-		return null;
-	}
-	
-	public File getCanonicalRootFile() {
-		if(rootFolder == null) {
-			rootFolder = new File(FolderConfig.getCanonicalRoot());
-		}
-		return rootFolder;
-	}
-	
-	public String getCanonicalRoot() {
-		return getCanonicalRootFile().getAbsolutePath();
-	}
-	
-	public File getRootVersionsFile() {
-		if (rootVersionsContainer == null) {
-			rootVersionFolder = new File(FolderConfig.getCanonicalVersionRoot());
-			if(!rootVersionFolder.exists()) {
-				rootVersionFolder.mkdirs();
-			}
-			rootVersionsContainer = new LocalFolderImpl(rootVersionFolder);
-		}
-		return rootVersionFolder;
-	}
-
-	public VFSContainer getRootVersionsContainer() {
-		if (rootVersionsContainer == null) {
-			rootVersionFolder = new File(FolderConfig.getCanonicalVersionRoot());
-			if(!rootVersionFolder.exists()) {
-				rootVersionFolder.mkdirs();
-			}
-			rootVersionsContainer = new LocalFolderImpl(rootVersionFolder);
-		}
-		return rootVersionsContainer;
-	}
-
-	@Override
-	public int countDirectories() {
-		VFSContainer versionsContainer = getRootVersionsContainer();
-		if(versionsContainer.exists()) {
-			return countDirectories(versionsContainer);
-		}
-		return 0;
-	}
-	
-	private int countDirectories(VFSContainer container) {
-		int count = 1;//itself
-		List<VFSItem> children = container.getItems(new VFSSystemItemFilter());
-		for(VFSItem child:children) {
-			if(child instanceof VFSContainer) {
-				count += countDirectories((VFSContainer)child);
-			}
-		}
-		return count;
-	}
-
-	@Override
-	public void pruneHistory(long maxHistoryLength, ProgressDelegate progress) {
-		VFSContainer versionsContainer = getRootVersionsContainer();
-		if(!versionsContainer.exists()) {
-			return;
-		}
-		//delete folder without versioning first
-		
-		int count = 0;
-		String[] excludedRootFolders = new String[]{"tmp","scorm","forum","portfolio"};
-		for(String excludedRootFolder:excludedRootFolders) {
-			VFSItem excludedContainer = versionsContainer.resolve(excludedRootFolder);
-			if(excludedContainer instanceof LocalFolderImpl) {
-				File excludedFile = ((LocalFolderImpl)excludedContainer).getBasefile();
-				FileUtils.deleteQuietly(excludedFile);
-				if(progress != null) progress.setInfo(excludedContainer.getName());
-			}
-			if(progress != null) progress.setActual(++count);
-		}
-
-		if(maxHistoryLength < 0) {
-			//nothing to do
-		} else if(maxHistoryLength == 0 && versionsContainer instanceof LocalFolderImpl) {
-			//delete all the stuff
-			FileUtils.deleteQuietly(((LocalFolderImpl)versionsContainer).getBasefile());
-		} else {
-			pruneVersionHistory(versionsContainer, maxHistoryLength, progress, count);
-		}
-
-		if(progress != null) progress.finished();
-	}
-	
-	private void pruneVersionHistory(VFSContainer container, long maxHistoryLength, ProgressDelegate progress, int count) {
-		List<VFSItem> children = container.getItems(new VFSSystemItemFilter());
-		for(VFSItem child:children) {
-			if(child instanceof VFSContainer) {
-				if(progress != null) progress.setActual(++count);
-				pruneVersionHistory((VFSContainer)child, maxHistoryLength, progress, count);
-			}
-			if(child instanceof VFSLeaf) {
-				VFSLeaf versionsLeaf = (VFSLeaf)child;
-				pruneVersionHistory(versionsLeaf, maxHistoryLength, progress);
-			}
-		}
-	}
-	
-	private void pruneVersionHistory(VFSLeaf versionsLeaf, long maxHistoryLength, ProgressDelegate progress) {
-		if(versionsLeaf.getName().endsWith(".xml") && isVersionsXmlFile(versionsLeaf)) {	
-			File originalFile = reversedOriginFile(versionsLeaf);
-			if(originalFile.exists()) {
-				VFSLeaf original = new LocalFileImpl(originalFile);
-				if(progress != null) progress.setInfo(original.getName());
-				Versions versions = readVersions(original, versionsLeaf);
-				List<VFSRevision> revisions = versions.getRevisions();
-				if(revisions.size() > maxHistoryLength) {
-					List<VFSRevision> revisionsToDelete = revisions.subList(0, revisions.size() - (int)maxHistoryLength);
-					deleteRevisions((Versionable)original, revisionsToDelete);
-				}
-			}
-		}
-	}
-
-	@Override
-	public boolean deleteOrphans(ProgressDelegate progress) {
-		List<OrphanVersion> orphans = orphans();
-		if(progress != null) progress.setMax(orphans.size());
-		int count = 0;
-		for(OrphanVersion orphan:orphans) {
-			delete(orphan);
-			if(progress != null) {
-				progress.setActual(++count);
-				progress.setInfo(orphan.getOriginalFilePath());
-			}
-		}
-		if(progress != null) progress.finished();
-		return true;
-	}
-	
-	@Override
-	public boolean delete(OrphanVersion orphan) {
-		VFSLeaf versionLeaf = orphan.getVersionsLeaf();
-
-		if (versionLeaf == null) return true; //already deleted
-		Versions versions = orphan.getVersions();
-		for (VFSRevision versionToDelete : versions.getRevisions()) {
-			RevisionFileImpl versionImpl = (RevisionFileImpl) versionToDelete;
-			versionImpl.setContainer(orphan.getVersionsLeaf().getParentContainer());
-			VFSLeaf fileToDelete = versionImpl.getFile();
-			if (fileToDelete != null) {
-				fileToDelete.delete();
-			}
-		}
-		versionLeaf.delete();
-		return true;
-	}
-
-	@Override
-	public List<OrphanVersion> orphans() {
-		List<OrphanVersion> orphans = new ArrayList<>();
-		VFSContainer versionsContainer = getRootVersionsContainer();
-		crawlForOrphans(versionsContainer, orphans);
-		return orphans;
-	}
-	
-	private void crawlForOrphans(VFSContainer container, List<OrphanVersion> orphans) {
-		if(!container.exists()) {
-			return;
-		}
-		
-		List<VFSItem> children = container.getItems();
-		for(VFSItem child:children) {
-			if(child instanceof VFSContainer) {
-				crawlForOrphans((VFSContainer)child, orphans);
-			}
-			if(child instanceof VFSLeaf) {
-				VFSLeaf versionsLeaf = (VFSLeaf)child;
-				if(child.getName().endsWith(".xml")) {
-					Versions versions = isOrphan(versionsLeaf);
-					if(versions == null) {
-						continue;
-					} else {
-						List<VFSRevision> revisions = versions.getRevisions();
-						if(revisions != null) {
-							for(VFSRevision revision:revisions) {
-								if(revision instanceof RevisionFileImpl) {
-									((RevisionFileImpl)revision).setContainer(container);
-								}
-							}
-						}
-					}
-					File originalFile = reversedOriginFile(child);
-					if(!originalFile.exists()) {
-						VFSLeaf orphan = new LocalFileImpl(originalFile);
-						orphans.add(new OrphanVersion(orphan, versionsLeaf, versions));
-					}
-				}
-			}
-		}
-	}
-
-	private Versions isOrphan(VFSLeaf potentialOrphan) {
-		try {
-			if(potentialOrphan.exists()) {
-				return (VersionsFileImpl) VFSXStream.read(potentialOrphan);
-			}
-			return null;
-		} catch (Exception e) {
-			return null;
-		}
-	}
-
-	private File reversedOriginFile(VFSItem versionXml) {
-		String path = File.separatorChar + versionXml.getName().substring(0, versionXml.getName().length() - 4);
-		for(VFSContainer parent=versionXml.getParentContainer(); parent != null && !parent.isSame(getRootVersionsContainer()); parent = parent.getParentContainer()) {
-			path = File.separatorChar + parent.getName() + path;
-		}
-		
-		return new File(getCanonicalRoot(), path);
-	}
-}
diff --git a/src/main/java/org/olat/core/util/vfs/version/VersionsManager.java b/src/main/java/org/olat/core/util/vfs/version/VersionsManager.java
deleted file mode 100644
index 3cd8d2e8d36c15e9092d17625d1ef93951dc83e6..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/core/util/vfs/version/VersionsManager.java
+++ /dev/null
@@ -1,203 +0,0 @@
-/**
- * <a href="http://www.openolat.org">
- * OpenOLAT - Online Learning and Training</a><br>
- * <p>
- * Licensed under the Apache License, Version 2.0 (the "License"); <br>
- * you may not use this file except in compliance with the License.<br>
- * You may obtain a copy of the License at the
- * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
- * <p>
- * Unless required by applicable law or agreed to in writing,<br>
- * software distributed under the License is distributed on an "AS IS" BASIS, <br>
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
- * See the License for the specific language governing permissions and <br>
- * limitations under the License.
- * <p>
- * Initial code contributed and copyrighted by<br>
- * frentix GmbH, http://www.frentix.com
- * <p>
- */
-package org.olat.core.util.vfs.version;
-
-import java.io.InputStream;
-import java.util.List;
-
-import org.olat.core.configuration.ConfigOnOff;
-import org.olat.core.id.Identity;
-import org.olat.core.util.async.ProgressDelegate;
-import org.olat.core.util.vfs.VFSContainer;
-import org.olat.core.util.vfs.VFSItem;
-import org.olat.core.util.vfs.VFSLeaf;
-
-/**
- * 
- * Description:<br>
- * 
- * 
- * <P>
- * Initial Date: 21 sept. 2009 <br>
- * 
- * @author srosse
- */
-public interface VersionsManager extends ConfigOnOff {
-
-	/**
-	 * Get or create the versions datas of this file
-	 * 
-	 * @param a file
-	 * @return
-	 */
-	public Versions createVersionsFor(VFSLeaf leaf);
-	
-	/**
-	 * Get or create the versions datas of this file
-	 * 
-	 * @param a file
-	 * @param force the creation of the file
-	 * @return
-	 */
-	public Versions createVersionsFor(VFSLeaf leaf, boolean force);
-
-	/**
-	 * Return the list of deleted files in this container.
-	 * 
-	 * @param container
-	 * @return
-	 */
-	public List<Versions> getDeletedFiles(VFSContainer container);
-
-	/**
-	 * Only used internally
-	 * 
-	 * @param versions
-	 * @return
-	 */
-	public String getNextRevisionNr(Versions versions);
-
-	/**
-	 * Add a new version of the file. The current version will be saved and
-	 * secured, The new version replaced the old one.
-	 * 
-	 * @param currentVersion
-	 * @param author
-	 * @param comment
-	 * @param newVersion
-	 * @return
-	 */
-	public boolean addVersion(Versionable currentVersion, Identity author, String comment, InputStream newVersion);
-
-	/**
-	 * Add a new revision to the files. The method check the number of revisions against the absolute
-	 * maximum limit for the instance.
-	 * @param currentVersion
-	 * @param author
-	 * @param comment
-	 * @return
-	 */
-	public boolean addToRevisions(Versionable currentVersion, Identity author, String comment);
-	
-	/**
-	 * Move a versioned file to the target container
-	 * 
-	 * @param currentVersion
-	 * @param target container
-	 * @return
-	 */
-	public boolean move(Versionable currentVersion, VFSContainer container);
-	
-	/**
-	 * Copy a versioned file to the target container
-	 * 
-	 * @param currentVersion
-	 * @param target container
-	 * @return
-	 */
-	public boolean copy(Versionable currentVersion, VFSContainer container);
-	
-	/**
-	 * Move a versioned file to an other (WebDAV only!!!)
-	 * 
-	 * @param currentVersion
-	 * @param oldVersion
-	 * @return
-	 */
-	public boolean move(VFSLeaf currentFile, VFSLeaf targetFile, Identity author);
-
-	/**
-	 * Restore a versioned file to the selected revision. The current version is
-	 * secured before being replaced by the revision's file
-	 * 
-	 * @param currentVersion
-	 * @param version
-	 * @return
-	 */
-	public boolean restore(Versionable currentVersion, VFSRevision version, String comment);
-
-	/**
-	 * Restore a revision in the target container, usefull to restore deleted
-	 * files
-	 * 
-	 * @param target container
-	 * @param selected revision
-	 * @return
-	 */
-	public boolean restore(VFSContainer container, VFSRevision revision);
-
-	/**
-	 * Delete a list of revisions from a file
-	 * 
-	 * @param currentVersion
-	 * @param revisionsToDelete
-	 * @return
-	 */
-	public boolean deleteRevisions(Versionable currentVersion, List<VFSRevision> revisionsToDelete);
-	
-	/**
-	 * Delete and remove from versioning a list of deleted versions (files)
-	 * @param versions
-	 * @return
-	 */
-	public boolean deleteVersions(VFSContainer container, List<Versions> versions);
-
-	/**
-	 * Delete a full container
-	 * 
-	 * @param container
-	 * @param force, if true delete it definitely (the deleted files don't appear
-	 *          in the list of deleted files)
-	 * @return
-	 */
-	public boolean delete(VFSItem item, boolean force);
-
-	/**
-	 * Rename a file and propagate the change to the version.
-	 * 
-	 * @param item
-	 * @param newname
-	 * @return
-	 */
-	public boolean rename(VFSItem item, String newname);
-	
-	/**
-	 * @return The list of orphans
-	 */
-	public List<OrphanVersion> orphans();
-	
-	/**
-	 * @param orphan
-	 * @return
-	 */
-	public boolean delete(OrphanVersion orphan);
-	
-	/**
-	 * Delete the orphans
-	 * @return
-	 */
-	public boolean deleteOrphans(ProgressDelegate progress);
-	
-	
-	public void pruneHistory(long historyLength, ProgressDelegate progress);
-
-	
-	public int countDirectories();
-}
diff --git a/src/main/java/org/olat/course/PersistingCourseImpl.java b/src/main/java/org/olat/course/PersistingCourseImpl.java
index bc7c0b34d5e7a40d7956eb2123771202aba6acf3..f314db25c66fbd636fa57af8ffca60c7b9a788f0 100644
--- a/src/main/java/org/olat/course/PersistingCourseImpl.java
+++ b/src/main/java/org/olat/course/PersistingCourseImpl.java
@@ -26,11 +26,13 @@
 package org.olat.course;
 
 import java.io.File;
+import java.io.InputStream;
 import java.io.Serializable;
 
 import org.olat.admin.quota.QuotaConstants;
 import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.persistence.DBFactory;
+import org.olat.core.commons.services.vfs.VFSRepositoryService;
 import org.olat.core.id.IdentityEnvironment;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.logging.AssertException;
@@ -49,8 +51,6 @@ import org.olat.core.util.vfs.VFSLeaf;
 import org.olat.core.util.vfs.VFSManager;
 import org.olat.core.util.vfs.callbacks.FullAccessWithLazyQuotaCallback;
 import org.olat.core.util.vfs.callbacks.FullAccessWithQuotaCallback;
-import org.olat.core.util.vfs.version.Versionable;
-import org.olat.core.util.vfs.version.VersionsManager;
 import org.olat.core.util.xml.XStreamHelper;
 import org.olat.course.assessment.AssessmentHelper;
 import org.olat.course.config.CourseConfig;
@@ -446,18 +446,18 @@ public class PersistingCourseImpl implements ICourse, OLATResourceable, Serializ
 	 * @param obj
 	 */
 	private void writeObject(String fileName, Object obj) {
-		VFSItem vfsItem = getCourseBaseContainer().resolve(fileName);
+		VFSLeaf vfsItem =(VFSLeaf)getCourseBaseContainer().resolve(fileName);
 		if (vfsItem == null) {
 			vfsItem = getCourseBaseContainer().createChildLeaf(fileName);
-		} else if(vfsItem.exists() && vfsItem instanceof Versionable) {
-			try {
-				CoreSpringFactory.getImpl(VersionsManager.class).addToRevisions((Versionable)vfsItem, null, "");
+		} else if(vfsItem.exists()) {
+			try(InputStream in=vfsItem.getInputStream()) {
+				CoreSpringFactory.getImpl(VFSRepositoryService.class).addVersion(vfsItem, null, "", in);
 			} catch (Exception e) {
 				log.error("Cannot versioned " + fileName, e);
 			}
 		}
 		XStream xstream = CourseXStreamAliases.getWriteCourseXStream();
-		XStreamHelper.writeObject(xstream, (VFSLeaf)vfsItem, obj);
+		XStreamHelper.writeObject(xstream, vfsItem, obj);
 	}
 
 	/**
diff --git a/src/main/java/org/olat/course/config/manager/CourseConfigManagerImpl.java b/src/main/java/org/olat/course/config/manager/CourseConfigManagerImpl.java
index 40e7d43e8cc6282daff3e68a10a448b01df752a2..15a9185ab2a8d943c4ceed4459d22a118c8988a7 100644
--- a/src/main/java/org/olat/course/config/manager/CourseConfigManagerImpl.java
+++ b/src/main/java/org/olat/course/config/manager/CourseConfigManagerImpl.java
@@ -25,17 +25,17 @@
 
 package org.olat.course.config.manager;
 
+import java.io.InputStream;
 import java.util.HashMap;
 import java.util.Hashtable;
 
 import org.olat.core.CoreSpringFactory;
+import org.olat.core.commons.services.vfs.VFSRepositoryService;
 import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
 import org.olat.core.util.vfs.VFSConstants;
 import org.olat.core.util.vfs.VFSItem;
 import org.olat.core.util.vfs.VFSLeaf;
-import org.olat.core.util.vfs.version.Versionable;
-import org.olat.core.util.vfs.version.VersionsManager;
 import org.olat.core.util.xml.XStreamHelper;
 import org.olat.course.ICourse;
 import org.olat.course.config.CourseConfig;
@@ -106,9 +106,9 @@ public class CourseConfigManagerImpl implements CourseConfigManager {
 		if (configFile == null) {
 			// create new config file
 			configFile = course.getCourseBaseContainer().createChildLeaf(COURSECONFIG_XML);
-		} else if(configFile.exists() && configFile instanceof Versionable) {
-			try {
-				CoreSpringFactory.getImpl(VersionsManager.class).addToRevisions((Versionable)configFile, null, "");
+		} else if(configFile.exists() && configFile.canVersion() == VFSConstants.YES) {
+			try(InputStream in = configFile.getInputStream()) {
+				CoreSpringFactory.getImpl(VFSRepositoryService.class).addVersion(configFile, null, "", in);
 			} catch (Exception e) {
 				log.error("Cannot versioned CourseConfig.xml", e);
 			}
diff --git a/src/main/java/org/olat/course/nodes/bc/BCWebService.java b/src/main/java/org/olat/course/nodes/bc/BCWebService.java
index 83aecd4b8f2f95c7d9d63c0aaa2a0629cac4f82d..f93258dfa1a947e9984b2b44f2bcee579f531ce1 100644
--- a/src/main/java/org/olat/course/nodes/bc/BCWebService.java
+++ b/src/main/java/org/olat/course/nodes/bc/BCWebService.java
@@ -48,6 +48,7 @@ import javax.ws.rs.core.Response.Status;
 import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.services.notifications.NotificationsManager;
 import org.olat.core.commons.services.notifications.Subscriber;
+import org.olat.core.commons.services.vfs.restapi.VFSWebservice;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.id.IdentityEnvironment;
 import org.olat.core.util.StringHelper;
@@ -55,7 +56,6 @@ import org.olat.core.util.nodes.INode;
 import org.olat.core.util.tree.Visitor;
 import org.olat.core.util.vfs.VFSContainer;
 import org.olat.core.util.vfs.callbacks.VFSSecurityCallback;
-import org.olat.core.util.vfs.restapi.VFSWebservice;
 import org.olat.course.ICourse;
 import org.olat.course.condition.Condition;
 import org.olat.course.nodes.BCCourseNode;
diff --git a/src/main/java/org/olat/modules/fo/restapi/ForumWebService.java b/src/main/java/org/olat/modules/fo/restapi/ForumWebService.java
index 26c08eebac15e2506959b8e7a9391d5b8ddc4ec1..2ab810f59ca548f7dddfb9006d86c46af9e08d6f 100644
--- a/src/main/java/org/olat/modules/fo/restapi/ForumWebService.java
+++ b/src/main/java/org/olat/modules/fo/restapi/ForumWebService.java
@@ -60,6 +60,7 @@ import org.apache.commons.io.IOUtils;
 import org.olat.basesecurity.BaseSecurity;
 import org.olat.basesecurity.OrganisationRoles;
 import org.olat.basesecurity.model.IdentityRefImpl;
+import org.olat.core.commons.services.vfs.restapi.VFSStreamingOutput;
 import org.olat.core.gui.media.ServletUtil;
 import org.olat.core.id.Identity;
 import org.olat.core.id.Roles;
@@ -74,7 +75,6 @@ import org.olat.core.util.vfs.VFSItem;
 import org.olat.core.util.vfs.VFSLeaf;
 import org.olat.core.util.vfs.VFSManager;
 import org.olat.core.util.vfs.filters.VFSSystemItemFilter;
-import org.olat.core.util.vfs.restapi.VFSStreamingOutput;
 import org.olat.modules.fo.Forum;
 import org.olat.modules.fo.Message;
 import org.olat.modules.fo.manager.ForumManager;
diff --git a/src/main/java/org/olat/modules/wiki/Wiki.java b/src/main/java/org/olat/modules/wiki/Wiki.java
index b3312589401095078e3278e6dd4ca183ff86b87a..1fcbd81e4ad8e2616f9893efa528630732faaeb9 100644
--- a/src/main/java/org/olat/modules/wiki/Wiki.java
+++ b/src/main/java/org/olat/modules/wiki/Wiki.java
@@ -313,7 +313,7 @@ public class Wiki implements WikiContainer, Serializable {
 		List<VFSItem> mediaFilesOnly = new ArrayList<>();
 		for (Iterator<VFSItem> iter = allFiles.iterator(); iter.hasNext();) {
 			VFSItem element = iter.next();
-			if(!element.getName().endsWith(WikiMainController.METADATA_SUFFIX)) {//TODO metadata
+			if(!element.getName().endsWith(WikiMainController.METADATA_SUFFIX)) {//TODO 
 				mediaFilesOnly.add(element);
 			}
 		}
diff --git a/src/main/java/org/olat/portfolio/ui/artefacts/collect/EPCreateFileArtefactStepForm00.java b/src/main/java/org/olat/portfolio/ui/artefacts/collect/EPCreateFileArtefactStepForm00.java
index 17457c95caabdd735276d64f1fc90afb2a2a11e3..425247f485b8d837c79314cef319361e5acd6009 100644
--- a/src/main/java/org/olat/portfolio/ui/artefacts/collect/EPCreateFileArtefactStepForm00.java
+++ b/src/main/java/org/olat/portfolio/ui/artefacts/collect/EPCreateFileArtefactStepForm00.java
@@ -33,11 +33,8 @@ import org.olat.core.gui.control.generic.wizard.StepsEvent;
 import org.olat.core.gui.control.generic.wizard.StepsRunContext;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.vfs.VFSContainer;
-import org.olat.core.util.vfs.VFSLeaf;
-import org.olat.core.util.vfs.VFSManager;
 import org.olat.portfolio.manager.EPFrontendManager;
 import org.olat.portfolio.model.artefacts.AbstractArtefact;
-import org.olat.portfolio.model.artefacts.FileArtefact;
 
 /**
  * Description:<br>
@@ -127,9 +124,9 @@ public class EPCreateFileArtefactStepForm00 extends StepFormBasicController {
 	}
 	
 	private void saveUpload(){
-		VFSLeaf contFile = vfsTemp.createChildLeaf(fileupload.getUploadFileName());
-		VFSManager.copyContent(fileupload.getUploadInputStream(), contFile);
-		((FileArtefact) artefact).setFilename(fileupload.getUploadFileName());
+		//VFSLeaf contFile = vfsTemp.createChildLeaf(fileupload.getUploadFileName());
+		//VFSManager.copyContent(fileupload.getUploadInputStream(), contFile);
+		fileupload.moveUploadFileTo(vfsTemp);
 	}
 
 	/**
diff --git a/src/main/java/org/olat/restapi/group/LearningGroupWebService.java b/src/main/java/org/olat/restapi/group/LearningGroupWebService.java
index 693efc2974b393b4b682f353436c3d23c1f68417..ebd51b8c33c6cfda6daabb6cf06235478c830bae 100644
--- a/src/main/java/org/olat/restapi/group/LearningGroupWebService.java
+++ b/src/main/java/org/olat/restapi/group/LearningGroupWebService.java
@@ -52,6 +52,8 @@ import org.olat.collaboration.CollaborationTools;
 import org.olat.collaboration.CollaborationToolsFactory;
 import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.services.notifications.SubscriptionContext;
+import org.olat.core.commons.services.vfs.restapi.VFSWebServiceSecurityCallback;
+import org.olat.core.commons.services.vfs.restapi.VFSWebservice;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.id.Identity;
 import org.olat.core.logging.OLog;
@@ -62,8 +64,6 @@ import org.olat.core.util.vfs.Quota;
 import org.olat.core.util.vfs.QuotaManager;
 import org.olat.core.util.vfs.VFSManager;
 import org.olat.core.util.vfs.callbacks.VFSSecurityCallback;
-import org.olat.core.util.vfs.restapi.VFSWebServiceSecurityCallback;
-import org.olat.core.util.vfs.restapi.VFSWebservice;
 import org.olat.group.BusinessGroup;
 import org.olat.group.BusinessGroupAddResponse;
 import org.olat.group.BusinessGroupService;
diff --git a/src/main/java/org/olat/restapi/repository/SharedFolderWebService.java b/src/main/java/org/olat/restapi/repository/SharedFolderWebService.java
index 46121afd806ba90dda906a827e94bd13f88019ed..715010598c00fcaee68f33b031ada390c48c49ec 100644
--- a/src/main/java/org/olat/restapi/repository/SharedFolderWebService.java
+++ b/src/main/java/org/olat/restapi/repository/SharedFolderWebService.java
@@ -40,13 +40,13 @@ import javax.ws.rs.core.Response.Status;
 import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriInfo;
 
+import org.olat.core.commons.services.vfs.restapi.VFSWebservice;
 import org.olat.core.util.WebappHelper;
 import org.olat.core.util.vfs.VFSContainer;
 import org.olat.core.util.vfs.VFSItem;
 import org.olat.core.util.vfs.VFSLeaf;
 import org.olat.core.util.vfs.callbacks.ReadOnlyCallback;
 import org.olat.core.util.vfs.filters.VFSSystemItemFilter;
-import org.olat.core.util.vfs.restapi.VFSWebservice;
 import org.olat.modules.sharedfolder.SharedFolderManager;
 import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryManager;
diff --git a/src/main/java/org/olat/restapi/repository/course/CourseGroupWebService.java b/src/main/java/org/olat/restapi/repository/course/CourseGroupWebService.java
index 9927b2ea39d710f8624045ade28df71ddc9e7044..1fc933d17f413be087396a85338618e4adf10c4f 100644
--- a/src/main/java/org/olat/restapi/repository/course/CourseGroupWebService.java
+++ b/src/main/java/org/olat/restapi/repository/course/CourseGroupWebService.java
@@ -43,14 +43,14 @@ import org.olat.collaboration.CollaborationTools;
 import org.olat.collaboration.CollaborationToolsFactory;
 import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.services.notifications.SubscriptionContext;
+import org.olat.core.commons.services.vfs.restapi.VFSWebServiceSecurityCallback;
+import org.olat.core.commons.services.vfs.restapi.VFSWebservice;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.id.Identity;
 import org.olat.core.util.vfs.Quota;
 import org.olat.core.util.vfs.QuotaManager;
 import org.olat.core.util.vfs.VFSContainer;
 import org.olat.core.util.vfs.VFSManager;
-import org.olat.core.util.vfs.restapi.VFSWebServiceSecurityCallback;
-import org.olat.core.util.vfs.restapi.VFSWebservice;
 import org.olat.group.BusinessGroup;
 import org.olat.group.BusinessGroupService;
 import org.olat.group.model.SearchBusinessGroupParams;
diff --git a/src/main/java/org/olat/restapi/repository/course/CourseResourceFolderWebService.java b/src/main/java/org/olat/restapi/repository/course/CourseResourceFolderWebService.java
index 0710b29b240328cfb71eb8f65613d42ef6171bae..601c3482ebdfa6237b495c0e6de2a9b34d57d27f 100644
--- a/src/main/java/org/olat/restapi/repository/course/CourseResourceFolderWebService.java
+++ b/src/main/java/org/olat/restapi/repository/course/CourseResourceFolderWebService.java
@@ -64,7 +64,6 @@ import org.olat.core.util.vfs.VFSLockApplicationType;
 import org.olat.core.util.vfs.VFSLockManager;
 import org.olat.core.util.vfs.callbacks.ReadOnlyCallback;
 import org.olat.core.util.vfs.filters.VFSSystemItemFilter;
-import org.olat.core.util.vfs.version.Versionable;
 import org.olat.course.ICourse;
 import org.olat.course.config.CourseConfig;
 import org.olat.modules.sharedfolder.SharedFolderManager;
@@ -349,32 +348,29 @@ public class CourseResourceFolderWebService {
 				return Response.serverError().status(Status.UNAUTHORIZED).build();
 			}
 
-			if (existingVFSItem instanceof Versionable && ((Versionable)existingVFSItem).getVersions().isVersioned()) {
-				Versionable existingVersionableItem = (Versionable)existingVFSItem;
-				boolean ok = existingVersionableItem.getVersions().addVersion(ureq.getIdentity(), "REST upload", file);
-				if(ok) {
-					log.audit("");
-				}
-				newFile = (VFSLeaf)existingVersionableItem;
+			if (existingVFSItem instanceof VFSLeaf && existingVFSItem.canVersion() == VFSConstants.YES) {
+				VFSLeaf existingLeaf = (VFSLeaf)existingVFSItem;
+				vfsRepositoryService.addVersion(existingLeaf, ureq.getIdentity(), "REST upload", file);
+				newFile = existingLeaf;
 			} else {
 				existingVFSItem.delete();
 				newFile = container.createChildLeaf(filename);
 				OutputStream out = ((VFSLeaf)newFile).getOutputStream(false);
-				FileUtils.copy(file, out);
+				FileUtils.copy(file, out);//TODO metadata use VFSManager ?
 				FileUtils.closeSafely(out);
 				FileUtils.closeSafely(file);
 			}
 		} else if (file != null) {
 			newFile = container.createChildLeaf(filename);
 			OutputStream out = ((VFSLeaf)newFile).getOutputStream(false);
-			FileUtils.copy(file, out);
+			FileUtils.copy(file, out);//TODO metadata use VFSManager ?
 			FileUtils.closeSafely(out);
 			FileUtils.closeSafely(file);
 		} else {
 			newFile = container.createChildContainer(filename);
 		}
 
-		if(newFile.canMeta() == VFSConstants.YES ) {
+		if(newFile.canMeta() == VFSConstants.YES) {
 			VFSMetadata infos = newFile.getMetaInfo();
 			infos.setAuthor(ureq.getIdentity());
 			vfsRepositoryService.updateMetadata(infos);
diff --git a/src/main/java/org/olat/user/restapi/UserFoldersWebService.java b/src/main/java/org/olat/user/restapi/UserFoldersWebService.java
index 06b717f6ffcb2e067d70b1489e48dc651e95368d..b30a860a85badd0be7c53112528387a0522068f4 100644
--- a/src/main/java/org/olat/user/restapi/UserFoldersWebService.java
+++ b/src/main/java/org/olat/user/restapi/UserFoldersWebService.java
@@ -49,6 +49,7 @@ import org.olat.core.commons.modules.bc.BriefcaseWebDAVProvider;
 import org.olat.core.commons.modules.bc.FolderConfig;
 import org.olat.core.commons.services.notifications.NotificationsManager;
 import org.olat.core.commons.services.notifications.Subscriber;
+import org.olat.core.commons.services.vfs.restapi.VFSWebservice;
 import org.olat.core.id.Identity;
 import org.olat.core.id.IdentityEnvironment;
 import org.olat.core.id.Roles;
@@ -58,7 +59,6 @@ import org.olat.core.util.vfs.VFSContainer;
 import org.olat.core.util.vfs.VFSManager;
 import org.olat.core.util.vfs.callbacks.ReadOnlyCallback;
 import org.olat.core.util.vfs.callbacks.VFSSecurityCallback;
-import org.olat.core.util.vfs.restapi.VFSWebservice;
 import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
 import org.olat.course.nodes.BCCourseNode;
diff --git a/src/main/resources/META-INF/persistence.xml b/src/main/resources/META-INF/persistence.xml
index 063618908ae8f0a8d981e2d8c81a796947ba92df..f19d1a7eba2b3eaf4d9f9ba49c195e4242393665 100644
--- a/src/main/resources/META-INF/persistence.xml
+++ b/src/main/resources/META-INF/persistence.xml
@@ -96,6 +96,7 @@
 		<class>org.olat.core.commons.services.vfs.model.VFSMetadataFileSaved</class>
 		<class>org.olat.core.commons.services.vfs.model.VFSMetadataDownloadCount</class>
 		<class>org.olat.core.commons.services.vfs.model.VFSThumbnailMetadataImpl</class>
+		<class>org.olat.core.commons.services.vfs.model.VFSRevisionImpl</class>
 		<class>org.olat.course.assessment.model.AssessmentModeImpl</class>
 		<class>org.olat.course.assessment.model.AssessmentModeToAreaImpl</class>
 		<class>org.olat.course.assessment.model.AssessmentModeToGroupImpl</class>
diff --git a/src/main/resources/database/mysql/alter_13_2_x_to_13_3_0.sql b/src/main/resources/database/mysql/alter_13_2_x_to_13_3_0.sql
index 9e53a48280516c2c00ccf473bef12f57e94a6a13..59ac4246ad14d7fe64206c900ac25d3dfb56555a 100644
--- a/src/main/resources/database/mysql/alter_13_2_x_to_13_3_0.sql
+++ b/src/main/resources/database/mysql/alter_13_2_x_to_13_3_0.sql
@@ -4,6 +4,7 @@ create table o_vfs_metadata (
    creationdate datetime not null,
    lastmodified datetime not null,
    f_uuid varchar(64) not null,
+   f_deleted boolean default 0 not null,
    f_filename varchar(256) not null,
    f_relative_path varchar(2048) not null,
    f_directory bool default false,
@@ -29,6 +30,8 @@ create table o_vfs_metadata (
    f_licensor text(4000),
    f_locked_date timestamp,
    f_locked bool default false,
+   f_revision_nr bigint default 0 not null,
+   f_revision_comment text(32000),
    f_m_path_keys varchar(1024),
    fk_locked_identity bigint,
    fk_license_type bigint,
@@ -68,5 +71,40 @@ alter table o_vfs_thumbnail ENGINE = InnoDB;
 alter table o_vfs_thumbnail add constraint fthumb_to_meta_idx foreign key (fk_metadata) references o_vfs_metadata (id);
 
 
+create table o_vfs_revision (
+   id bigint not null auto_increment,
+   creationdate datetime not null,
+   lastmodified datetime not null,
+   f_revision_size bigint default 0 not null,
+   f_revision_nr bigint default 0 not null,
+   f_revision_filename varchar(256) not null,
+   f_revision_comment text(32000),
+   f_revision_lastmodified datetime not null,
+   f_comment text(32000),
+   f_title varchar(2000),
+   f_publisher varchar(2000),
+   f_creator varchar(2000),
+   f_source varchar(2000),
+   f_city varchar(256),
+   f_pages varchar(16),
+   f_language varchar(16),
+   f_url text(1024),
+   f_pub_month varchar(16),
+   f_pub_year varchar(16),
+   f_license_type_name varchar(256),
+   f_license_text mediumtext,
+   f_licensor text(4000),
+   fk_license_type bigint,
+   fk_author bigint,
+   fk_metadata bigint not null,
+   primary key (id)
+);
+
+alter table o_vfs_revision ENGINE = InnoDB;
+
+alter table o_vfs_revision add constraint fvers_to_author_idx foreign key (fk_author) references o_bs_identity (id);
+alter table o_vfs_revision add constraint fvers_to_meta_idx foreign key (fk_metadata) references o_vfs_metadata (id);
+alter table o_vfs_metadata add constraint fvers_to_lic_type_idx foreign key (fk_license_type) references o_lic_license_type (id);
+
 
 
diff --git a/src/main/resources/database/mysql/setupDatabase.sql b/src/main/resources/database/mysql/setupDatabase.sql
index b70d5d51b38df7b38e20b28ff7fa9490a4253a2c..74bc0f9d68976561b57221555b4f81b14c548d68 100644
--- a/src/main/resources/database/mysql/setupDatabase.sql
+++ b/src/main/resources/database/mysql/setupDatabase.sql
@@ -1686,6 +1686,7 @@ create table o_vfs_metadata (
    creationdate datetime not null,
    lastmodified datetime not null,
    f_uuid varchar(64) not null,
+   f_deleted boolean default 0 not null,
    f_filename varchar(256) not null,
    f_relative_path varchar(2048) not null,
    f_directory bool default false,
@@ -1713,6 +1714,8 @@ create table o_vfs_metadata (
    f_locked bool default false,
    f_m_path_keys varchar(1024),
    fk_locked_identity bigint,
+   f_revision_nr bigint default 0 not null,
+   f_revision_comment text(32000),
    fk_license_type bigint,
    fk_author bigint,
    fk_parent bigint,
@@ -1734,6 +1737,35 @@ create table o_vfs_thumbnail (
    primary key (id)
 );
 
+create table o_vfs_revision (
+   id bigint not null auto_increment,
+   creationdate datetime not null,
+   lastmodified datetime not null,
+   f_revision_size bigint default 0 not null,
+   f_revision_nr bigint default 0 not null,
+   f_revision_filename varchar(256) not null,
+   f_revision_comment text(32000),
+   f_revision_lastmodified datetime not null,
+   f_comment text(32000),
+   f_title varchar(2000),
+   f_publisher varchar(2000),
+   f_creator varchar(2000),
+   f_source varchar(2000),
+   f_city varchar(256),
+   f_pages varchar(16),
+   f_language varchar(16),
+   f_url text(1024),
+   f_pub_month varchar(16),
+   f_pub_year varchar(16),
+   f_license_type_name varchar(256),
+   f_license_text mediumtext,
+   f_licensor text(4000),
+   fk_license_type bigint,
+   fk_author bigint,
+   fk_metadata bigint not null,
+   primary key (id)
+);
+
 -- portfolio
 create table o_pf_binder (
    id bigint not null auto_increment,
@@ -3097,6 +3129,7 @@ alter table o_qual_generator_to_org ENGINE = InnoDB;
 alter table o_qual_analysis_presentation ENGINE = InnoDB;
 alter table o_vfs_metadata ENGINE = InnoDB;
 alter table o_vfs_thumbnail ENGINE = InnoDB;
+alter table o_vfs_revision ENGINE = InnoDB;
 alter table o_sms_message_log ENGINE = InnoDB;
 alter table o_feed ENGINE = InnoDB;
 alter table o_feed_item ENGINE = InnoDB;
@@ -3597,6 +3630,10 @@ create index f_m_filename_idx on o_vfs_metadata (f_filename(255));
 
 alter table o_vfs_thumbnail add constraint fthumb_to_meta_idx foreign key (fk_metadata) references o_vfs_metadata (id);
 
+alter table o_vfs_revision add constraint fvers_to_author_idx foreign key (fk_author) references o_bs_identity (id);
+alter table o_vfs_revision add constraint fvers_to_meta_idx foreign key (fk_metadata) references o_vfs_metadata (id);
+alter table o_vfs_metadata add constraint fvers_to_lic_type_idx foreign key (fk_license_type) references o_lic_license_type (id);
+
 -- quality management
 alter table o_qual_data_collection add constraint qual_dc_to_gen_idx foreign key (fk_generator) references o_qual_generator (id);
 create index idx_dc_status_idx on o_qual_data_collection (q_status);
diff --git a/src/main/resources/database/oracle/alter_13_2_x_to_13_3_0.sql b/src/main/resources/database/oracle/alter_13_2_x_to_13_3_0.sql
index 999ca3814b5ce1f71998d01b1265d5b38dcd3699..6faaa5f880be3b0e2430851fd5a5d258b45aff64 100644
--- a/src/main/resources/database/oracle/alter_13_2_x_to_13_3_0.sql
+++ b/src/main/resources/database/oracle/alter_13_2_x_to_13_3_0.sql
@@ -3,6 +3,7 @@ create table o_vfs_metadata (
    creationdate timestamp not null,
    lastmodified timestamp not null,
    f_uuid varchar(64) not null,
+   f_deleted number default 0 not null,
    f_filename varchar(256) not null,
    f_relative_path varchar(2048) not null,
    f_directory number default 0,
@@ -28,6 +29,8 @@ create table o_vfs_metadata (
    f_licensor varchar(4000),
    f_locked_date timestamp,
    f_locked number default 0,
+   f_revision_nr number(20) default 0 not null,
+   f_revision_comment varchar(32000),
    f_m_path_keys varchar(1024),
    fk_locked_identity number(20),
    fk_license_type number(20),
@@ -67,3 +70,41 @@ create table o_vfs_thumbnail (
 alter table o_vfs_thumbnail add constraint fthumb_to_meta_idx foreign key (fk_metadata) references o_vfs_metadata (id);
 create index idx_fthumb_to_meta_idx on o_vfs_thumbnail (fk_metadata);
 
+
+create table o_vfs_revision (
+   id number(20) generated always as identity,
+   creationdate timestamp not null,
+   lastmodified timestamp not null,
+   f_revision_size number(20) default 0 not null,
+   f_revision_nr number(20) default 0 not null,
+   f_revision_filename varchar(256) not null,
+   f_revision_comment varchar(32000),
+   f_revision_lastmodified timestamp not null,
+   f_comment varchar(32000),
+   f_title varchar(2000),
+   f_publisher varchar(2000),
+   f_creator varchar(2000),
+   f_source varchar(2000),
+   f_city varchar(256),
+   f_pages varchar(2000),
+   f_language varchar(16),
+   f_url varchar(1024),
+   f_pub_month varchar(16),
+   f_pub_year varchar(16),
+   f_license_type_name varchar(256),
+   f_license_text CLOB,
+   f_licensor varchar(4000),
+   fk_license_type number(20),
+   fk_author number(20),
+   fk_metadata number(20) not null,
+   primary key (id)
+);
+
+alter table o_vfs_revision add constraint fvers_to_author_idx foreign key (fk_author) references o_bs_identity (id);
+create index idx_fvers_to_author_idx on o_vfs_revision (fk_author);
+alter table o_vfs_revision add constraint fvers_to_meta_idx foreign key (fk_metadata) references o_vfs_metadata (id);
+create index idx_fvers_to_meta_idx on o_vfs_revision (fk_metadata);
+alter table o_vfs_revision add constraint fvers_to_lic_type_idx foreign key (fk_license_type) references o_lic_license_type (id);
+create index idx_fvers_to_lic_type_idx on o_vfs_revision (fk_license_type);
+
+
diff --git a/src/main/resources/database/oracle/setupDatabase.sql b/src/main/resources/database/oracle/setupDatabase.sql
index 4824214ded791b0410144bd45d6a294a5a694a6f..356a54d716e6acac5699d8e7508e2a559ef2a332 100644
--- a/src/main/resources/database/oracle/setupDatabase.sql
+++ b/src/main/resources/database/oracle/setupDatabase.sql
@@ -1664,6 +1664,35 @@ create table o_vfs_thumbnail (
    primary key (id)
 );
 
+create table o_vfs_revision (
+   id number(20) generated always as identity,
+   creationdate timestamp not null,
+   lastmodified timestamp not null,
+   f_revision_size number(20) default 0 not null,
+   f_revision_nr number(20) default 0 not null,
+   f_revision_filename varchar(256) not null,
+   f_revision_comment varchar(32000),
+   f_revision_lastmodified timestamp not null,
+   f_comment varchar(32000),
+   f_title varchar(2000),
+   f_publisher varchar(2000),
+   f_creator varchar(2000),
+   f_source varchar(2000),
+   f_city varchar(256),
+   f_pages varchar(2000),
+   f_language varchar(16),
+   f_url varchar(1024),
+   f_pub_month varchar(16),
+   f_pub_year varchar(16),
+   f_license_type_name varchar(256),
+   f_license_text CLOB,
+   f_licensor varchar(4000),
+   fk_license_type number(20),
+   fk_author number(20),
+   fk_metadata number(20) not null,
+   primary key (id)
+);
+
 -- portfolio
 create table o_pf_binder (
    id number(20) GENERATED ALWAYS AS IDENTITY,
@@ -3628,6 +3657,13 @@ create index f_m_filename_idx on o_vfs_metadata (f_filename);
 alter table o_vfs_thumbnail add constraint fthumb_to_meta_idx foreign key (fk_metadata) references o_vfs_metadata (id);
 create index idx_fthumb_to_meta_idx on o_vfs_thumbnail (fk_metadata);
 
+alter table o_vfs_revision add constraint fvers_to_author_idx foreign key (fk_author) references o_bs_identity (id);
+create index idx_fvers_to_author_idx on o_vfs_revision (fk_author);
+alter table o_vfs_revision add constraint fvers_to_meta_idx foreign key (fk_metadata) references o_vfs_metadata (id);
+create index idx_fvers_to_meta_idx on o_vfs_revision (fk_metadata);
+alter table o_vfs_revision add constraint fvers_to_lic_type_idx foreign key (fk_license_type) references o_lic_license_type (id);
+create index idx_fvers_to_lic_type_idx on o_vfs_revision (fk_license_type);
+
 -- portfolio
 alter table o_pf_binder add constraint pf_binder_resource_idx foreign key (fk_olatresource_id) references o_olatresource (resource_id);
 create index idx_pf_binder_resource_idx on o_pf_binder (fk_olatresource_id);
diff --git a/src/main/resources/database/postgresql/alter_13_2_x_to_13_3_0.sql b/src/main/resources/database/postgresql/alter_13_2_x_to_13_3_0.sql
index 08ccac477dd9feabf2455492558181e5d5f374a4..646f00ab4e5545dc47d82c3c13c6ae6b8ab3f3ff 100644
--- a/src/main/resources/database/postgresql/alter_13_2_x_to_13_3_0.sql
+++ b/src/main/resources/database/postgresql/alter_13_2_x_to_13_3_0.sql
@@ -4,6 +4,7 @@ create table o_vfs_metadata (
    creationdate timestamp not null,
    lastmodified timestamp not null,
    f_uuid varchar(64) not null,
+   f_deleted bool default false not null,
    f_filename varchar(256) not null,
    f_relative_path varchar(2048) not null,
    f_directory bool default false,
@@ -29,6 +30,8 @@ create table o_vfs_metadata (
    f_licensor varchar(4000),
    f_locked_date timestamp,
    f_locked bool default false,
+   f_revision_nr bigint default 0 not null,
+   f_revision_comment varchar(32000),
    f_m_path_keys varchar(1024),
    fk_locked_identity bigint,
    fk_license_type bigint,
@@ -68,3 +71,43 @@ create table o_vfs_thumbnail (
 alter table o_vfs_thumbnail add constraint fthumb_to_meta_idx foreign key (fk_metadata) references o_vfs_metadata (id);
 create index idx_fthumb_to_meta_idx on o_vfs_thumbnail (fk_metadata);
 
+
+create table o_vfs_revision (
+   id bigserial,
+   creationdate timestamp not null,
+   lastmodified timestamp not null,
+   f_revision_size bigint default 0 not null,
+   f_revision_nr bigint default 0 not null,
+   f_revision_filename varchar(256) not null,
+   f_revision_comment varchar(32000),
+   f_revision_lastmodified timestamp not null,
+   f_comment varchar(32000),
+   f_title varchar(2000),
+   f_publisher varchar(2000),
+   f_creator varchar(2000),
+   f_source varchar(2000),
+   f_city varchar(256),
+   f_pages varchar(2000),
+   f_language varchar(16),
+   f_url varchar(1024),
+   f_pub_month varchar(16),
+   f_pub_year varchar(16),
+   f_license_type_name varchar(256),
+   f_license_text text,
+   f_licensor varchar(4000),
+   fk_license_type bigint,
+   fk_author bigint,
+   fk_metadata bigint not null,
+   primary key (id)
+);
+
+alter table o_vfs_revision add constraint fvers_to_author_idx foreign key (fk_author) references o_bs_identity (id);
+create index idx_fvers_to_author_idx on o_vfs_revision (fk_author);
+alter table o_vfs_revision add constraint fvers_to_meta_idx foreign key (fk_metadata) references o_vfs_metadata (id);
+create index idx_fvers_to_meta_idx on o_vfs_revision (fk_metadata);
+alter table o_vfs_revision add constraint fvers_to_lic_type_idx foreign key (fk_license_type) references o_lic_license_type (id);
+create index idx_fvers_to_lic_type_idx on o_vfs_revision (fk_license_type);
+
+
+
+
diff --git a/src/main/resources/database/postgresql/setupDatabase.sql b/src/main/resources/database/postgresql/setupDatabase.sql
index f04b654639ab0c8a047c0fc88f2b659c9bb2e28e..fd61561d79a331751d3eee49b62677449fdc4701 100644
--- a/src/main/resources/database/postgresql/setupDatabase.sql
+++ b/src/main/resources/database/postgresql/setupDatabase.sql
@@ -1579,6 +1579,7 @@ create table o_vfs_metadata (
    creationdate timestamp not null,
    lastmodified timestamp not null,
    f_uuid varchar(64) not null,
+   f_deleted bool default false not null,
    f_filename varchar(256) not null,
    f_relative_path varchar(2048) not null,
    f_directory bool default false,
@@ -1604,6 +1605,8 @@ create table o_vfs_metadata (
    f_licensor varchar(4000),
    f_locked_date timestamp,
    f_locked bool default false,
+   f_revision_nr bigint default 0 not null,
+   f_revision_comment varchar(32000),
    f_m_path_keys varchar(1024),
    fk_locked_identity bigint,
    fk_license_type bigint,
@@ -1627,6 +1630,35 @@ create table o_vfs_thumbnail (
    primary key (id)
 );
 
+create table o_vfs_revision (
+   id bigserial,
+   creationdate timestamp not null,
+   lastmodified timestamp not null,
+   f_revision_size bigint default 0 not null,
+   f_revision_nr bigint default 0 not null,
+   f_revision_filename varchar(256) not null,
+   f_revision_comment varchar(32000),
+   f_revision_lastmodified timestamp not null,
+   f_comment varchar(32000),
+   f_title varchar(2000),
+   f_publisher varchar(2000),
+   f_creator varchar(2000),
+   f_source varchar(2000),
+   f_city varchar(256),
+   f_pages varchar(2000),
+   f_language varchar(16),
+   f_url varchar(1024),
+   f_pub_month varchar(16),
+   f_pub_year varchar(16),
+   f_license_type_name varchar(256),
+   f_license_text text,
+   f_licensor varchar(4000),
+   fk_license_type bigint,
+   fk_author bigint,
+   fk_metadata bigint not null,
+   primary key (id)
+);
+
 -- portfolio
 create table o_pf_binder (
    id bigserial,
@@ -3589,6 +3621,13 @@ create index f_m_filename_idx on o_vfs_metadata (f_filename);
 alter table o_vfs_thumbnail add constraint fthumb_to_meta_idx foreign key (fk_metadata) references o_vfs_metadata (id);
 create index idx_fthumb_to_meta_idx on o_vfs_thumbnail (fk_metadata);
 
+alter table o_vfs_revision add constraint fvers_to_author_idx foreign key (fk_author) references o_bs_identity (id);
+create index idx_fvers_to_author_idx on o_vfs_revision (fk_author);
+alter table o_vfs_revision add constraint fvers_to_meta_idx foreign key (fk_metadata) references o_vfs_metadata (id);
+create index idx_fvers_to_meta_idx on o_vfs_revision (fk_metadata);
+alter table o_vfs_revision add constraint fvers_to_lic_type_idx foreign key (fk_license_type) references o_lic_license_type (id);
+create index idx_fvers_to_lic_type_idx on o_vfs_revision (fk_license_type);
+
 -- evaluation form
 alter table o_eva_form_survey add constraint eva_surv_to_surv_idx foreign key (fk_series_previous) references o_eva_form_survey (id);
 create unique index idx_eva_surv_ores_idx on o_eva_form_survey (e_resid, e_resname, e_sub_ident);
diff --git a/src/test/java/org/olat/core/commons/services/vfs/manager/VFSMetadataDAOTest.java b/src/test/java/org/olat/core/commons/services/vfs/manager/VFSMetadataDAOTest.java
index cff00b3cf6cad7012bb79afa84e37f145965ed03..c6fa47af0799a019f3dcc22b5e64ffb392a1aa2c 100644
--- a/src/test/java/org/olat/core/commons/services/vfs/manager/VFSMetadataDAOTest.java
+++ b/src/test/java/org/olat/core/commons/services/vfs/manager/VFSMetadataDAOTest.java
@@ -141,7 +141,7 @@ public class VFSMetadataDAOTest extends OlatTestCase {
 		dbInstance.commitAndCloseSession();
 		Assert.assertNotNull(metadata);
 		
-		vfsMetadataDao.updateMetadata(12345l, relativePath, filename);
+		vfsMetadataDao.updateMetadata(12345l, new Date(),relativePath, filename);
 		dbInstance.commitAndCloseSession();
 		
 		VFSMetadata loadedMetadata = vfsMetadataDao.loadMetadata(metadata.getKey());
diff --git a/src/test/java/org/olat/core/commons/services/vfs/manager/VFSRevisionDAOTest.java b/src/test/java/org/olat/core/commons/services/vfs/manager/VFSRevisionDAOTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..e99f109090a5657182d1d9f7f856c47bbfb247f1
--- /dev/null
+++ b/src/test/java/org/olat/core/commons/services/vfs/manager/VFSRevisionDAOTest.java
@@ -0,0 +1,76 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.commons.services.vfs.manager;
+
+import java.util.Date;
+import java.util.List;
+import java.util.UUID;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.olat.core.commons.persistence.DB;
+import org.olat.core.commons.services.vfs.VFSMetadata;
+import org.olat.core.commons.services.vfs.VFSRevision;
+import org.olat.core.id.Identity;
+import org.olat.test.JunitTestHelper;
+import org.olat.test.OlatTestCase;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * 
+ * Initial date: 18 mars 2019<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class VFSRevisionDAOTest extends OlatTestCase {
+	
+	@Autowired
+	private DB dbInstance;
+	@Autowired 
+	private VFSRevisionDAO revisionDao;
+	@Autowired
+	private VFSMetadataDAO vfsMetadataDao;
+	
+	@Test
+	public void createRevision() {
+		Identity author = JunitTestHelper.createAndPersistIdentityAsRndUser("rev-1");
+		VFSMetadata metadata = vfsMetadataDao.createMetadata(UUID.randomUUID().toString(), "test/revs", "text.txt",
+				new Date(), 10l, false, "file:///text.tx", "file", null);
+		VFSRevision revision = revisionDao.createRevision(author, "._oo_vr_1_text.txt", 1, 25l, new Date(), "A comment", metadata);
+		dbInstance.commitAndCloseSession();
+		
+		Assert.assertNotNull(revision);
+	}
+	
+	@Test
+	public void getRevisions() {
+		Identity author = JunitTestHelper.createAndPersistIdentityAsRndUser("rev-1");
+		VFSMetadata metadata = vfsMetadataDao.createMetadata(UUID.randomUUID().toString(), "test/revs", "text.txt",
+				new Date(), 10l, false, "file:///text.tx", "file", null);
+		VFSRevision revision = revisionDao.createRevision(author, "._oo_vr_1_text.txt", 1, 25l, new Date(), "A comment", metadata);
+		dbInstance.commitAndCloseSession();
+		
+		List<VFSRevision> revisions = revisionDao.getRevisions(metadata);
+		Assert.assertNotNull(revisions);
+		Assert.assertEquals(1, revisions.size());
+		Assert.assertEquals(revision, revisions.get(0));
+	}
+
+}
diff --git a/src/test/java/org/olat/core/commons/services/vfs/manager/VFSVersioningTest.java b/src/test/java/org/olat/core/commons/services/vfs/manager/VFSVersioningTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..22d2a108994927861f7f657d4a8108e994e89e09
--- /dev/null
+++ b/src/test/java/org/olat/core/commons/services/vfs/manager/VFSVersioningTest.java
@@ -0,0 +1,637 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.commons.services.vfs.manager;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.Callable;
+
+import org.apache.commons.io.IOUtils;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.olat.core.commons.persistence.DB;
+import org.olat.core.commons.services.vfs.VFSMetadata;
+import org.olat.core.commons.services.vfs.VFSRepositoryService;
+import org.olat.core.commons.services.vfs.VFSRevision;
+import org.olat.core.commons.services.vfs.VFSVersionModule;
+import org.olat.core.commons.services.vfs.model.VFSRevisionImpl;
+import org.olat.core.id.Identity;
+import org.olat.core.util.vfs.VFSConstants;
+import org.olat.core.util.vfs.VFSContainer;
+import org.olat.core.util.vfs.VFSItem;
+import org.olat.core.util.vfs.VFSLeaf;
+import org.olat.core.util.vfs.VFSManager;
+import org.olat.core.util.vfs.filters.VFSItemFilter;
+import org.olat.test.JunitTestHelper;
+import org.olat.test.OlatTestCase;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * 
+ * Initial date: 20 mars 2019<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class VFSVersioningTest extends OlatTestCase {
+	
+	@Autowired
+	private DB dbInstance;
+	@Autowired
+	private VFSVersionModule versionsModule;
+	@Autowired
+	private VFSRepositoryService vfsRepositoryService;
+	
+	@Before
+	public void setUp() throws Exception {
+		waitForCondition(new SetMaxNumberOfVersions(versionsModule, 10l), 2000);
+	}
+	
+	@After
+	public void resetMaxVersions() {
+		int maxNumberOfVersions = versionsModule.getMaxNumberOfVersions();
+		if(maxNumberOfVersions != 10) {
+			versionsModule.setMaxNumberOfVersions(10);
+			waitForCondition(new SetMaxNumberOfVersions(versionsModule, 10l), 2000);
+		}
+	}
+	
+	@Test
+	public void addVersions() throws IOException {
+		Identity id = JunitTestHelper.createAndPersistIdentityAsRndUser("vers-1");
+		
+		//create a file
+		VFSContainer rootTest = VFSManager.olatRootContainer("/test", null);
+		String filename = UUID.randomUUID().toString() + ".txt";
+		VFSLeaf file = rootTest.createChildLeaf(filename);
+		int byteCopied = copyTestTxt(file);
+		Assert.assertFalse(byteCopied == 0);
+		VFSMetadata data = vfsRepositoryService.getMetadataFor(file);
+		data.setAuthor(id);
+		vfsRepositoryService.updateMetadata(data);
+		dbInstance.commitAndCloseSession();
+		
+		//save a first version
+		InputStream in1 = new ByteArrayInputStream("Hello version 1".getBytes());
+		vfsRepositoryService.addVersion(file, id, "Version 1", in1);
+		in1.close();
+		
+		//save a second version
+		InputStream in2 = new ByteArrayInputStream("Hello version 2".getBytes());
+		vfsRepositoryService.addVersion(file, id, "Version 2", in2);
+		in2.close();
+		
+		//save a third version
+		InputStream in3 = new ByteArrayInputStream("Hello version 3".getBytes());
+		vfsRepositoryService.addVersion(file, id, "Version 3", in3);
+		in3.close();
+
+		//make the checks
+		VFSItem retrievedFile = rootTest.resolve(filename);
+		VFSMetadata metadata = vfsRepositoryService.getMetadataFor(retrievedFile);
+		List<VFSRevision> revisions = vfsRepositoryService.getRevisions(metadata);	
+		Assert.assertNotNull(revisions);
+		Assert.assertEquals(3, revisions.size());
+		
+		VFSRevision revision0 = revisions.get(0);
+		//we don't set an author for the original file
+		Assert.assertEquals(id, revision0.getAuthor());//TODO remove the first author
+		VFSRevision revision1 = revisions.get(1);
+		Assert.assertEquals(id, revision1.getAuthor());
+		VFSRevision revision2 = revisions.get(2);
+		Assert.assertEquals(id, revision2.getAuthor());
+
+		//check the comments
+		Assert.assertNull(revision0.getRevisionComment());	
+		Assert.assertEquals("Version 1", revision1.getRevisionComment());
+		Assert.assertEquals("Version 2", revision2.getRevisionComment());
+		Assert.assertEquals("Version 3", metadata.getRevisionComment());
+	}
+	
+	@Test
+	public void addVersions_overflow_lowLevel() throws IOException {
+		versionsModule.setMaxNumberOfVersions(3);
+		waitForCondition(new SetMaxNumberOfVersions(versionsModule, 3l), 2000);
+		
+		Identity id2 = JunitTestHelper.createAndPersistIdentityAsRndUser("vers-2");
+		
+		//create a file
+		VFSContainer rootTest = VFSManager.olatRootContainer("/test_" + UUID.randomUUID(), null);
+		String filename = UUID.randomUUID().toString() + ".txt";
+		VFSLeaf file = rootTest.createChildLeaf(filename);
+		int byteCopied = copyTestTxt(file);
+		Assert.assertFalse(byteCopied == 0);
+		
+		//save a first version
+		for(int i=0; i<5; i++) {
+			InputStream inv = new ByteArrayInputStream(("Hello version " + i).getBytes());
+			vfsRepositoryService.addVersion(file, id2, "Version " + (1 +i), inv);
+			inv.close();
+		}
+
+		VFSItem retrievedFile = rootTest.resolve(filename);
+		VFSMetadata metadata = vfsRepositoryService.getMetadataFor(retrievedFile);
+		List<VFSRevision> revisions = vfsRepositoryService.getRevisions(metadata);
+		Assert.assertNotNull(revisions);
+		Assert.assertEquals(3, revisions.size());
+		Assert.assertEquals(3, revisions.get(0).getRevisionNr());
+		Assert.assertEquals(4, revisions.get(1).getRevisionNr());
+		Assert.assertEquals(5, revisions.get(2).getRevisionNr());
+
+		Assert.assertEquals("Version 5", metadata.getRevisionComment());
+		Assert.assertEquals(id2, revisions.get(2).getAuthor());
+	}
+	
+	@Test
+	public void addVersions_overflow_lowLevel_deactivated() throws IOException {
+		versionsModule.setMaxNumberOfVersions(0);
+		waitForCondition(new SetMaxNumberOfVersions(versionsModule,  0l), 2000);
+		
+		Identity id = JunitTestHelper.createAndPersistIdentityAsRndUser("vers-");
+		
+		//create a file
+		VFSContainer rootTest = VFSManager.olatRootContainer("/test_" + UUID.randomUUID(), null);
+		String filename = UUID.randomUUID().toString() + ".txt";
+		VFSLeaf file = rootTest.createChildLeaf(filename);
+		int byteCopied = copyTestTxt(file);
+		Assert.assertFalse(byteCopied == 0);
+		
+		//save a first version
+		for(int i=0; i<5; i++) {
+			InputStream inv = new ByteArrayInputStream(("Hello version " + i).getBytes());
+			vfsRepositoryService.addVersion(file, id, "Version " + (1 +i), inv);
+			inv.close();
+		}
+
+		VFSItem retrievedFile = rootTest.resolve(filename);
+		VFSMetadata metadata = vfsRepositoryService.getMetadataFor(retrievedFile);	
+		List<VFSRevision> revisions = vfsRepositoryService.getRevisions(metadata);
+		Assert.assertNotNull(revisions);
+		Assert.assertTrue(revisions.isEmpty());
+	}
+	
+	@Test
+	public void versionChecksum() throws IOException {
+		VFSContainer rootTest = VFSManager.olatRootContainer("/ver-" + UUID.randomUUID(), null);
+		String filename = UUID.randomUUID().toString() + ".txt";
+		VFSLeaf file = rootTest.createChildLeaf(filename);
+		int byteCopied = copyTestTxt(file);
+		Assert.assertFalse(byteCopied == 0);
+		
+		Identity id = JunitTestHelper.createAndPersistIdentityAsRndUser("vers-4");
+
+		//save a first version
+		InputStream in1 = VFSVersioningTest.class.getResourceAsStream("test.txt");
+		vfsRepositoryService.addVersion(file, id, "Version 1", in1);
+		in1.close();
+		
+		//save a second version
+		InputStream in2 = VFSVersioningTest.class.getResourceAsStream("test.txt");
+		vfsRepositoryService.addVersion(file, id, "Version 2", in2);
+		in2.close();
+		
+		//save a third version
+		InputStream in3 = VFSVersioningTest.class.getResourceAsStream("test.txt");
+		vfsRepositoryService.addVersion(file, id, "Version 3", in2);
+		in3.close();
+		
+		//check if there is only one backup file
+		VFSContainer versionContainer = file.getParentContainer();
+		List<VFSItem> items = versionContainer.getItems(new VersionsFilter(filename));
+		Assert.assertEquals(1, items.size());// TODO metadata was 2 but 1 seems correcter
+		
+		//check number of versions
+		VFSItem reloadFile = rootTest.resolve(filename);
+		VFSMetadata metadata = vfsRepositoryService.getMetadataFor(reloadFile);
+		List<VFSRevision> revisions = vfsRepositoryService.getRevisions(metadata);
+		Assert.assertNotNull(revisions);
+		Assert.assertEquals(3, revisions.size());
+	}
+	
+	@Test
+	public void container_copyFrom() throws IOException {
+		Identity id = JunitTestHelper.createAndPersistIdentityAsRndUser("vers-11");
+		
+		//create a file
+		VFSContainer rootTest = VFSManager.olatRootContainer("/test_" + UUID.randomUUID(), null);
+		VFSContainer targetRootTest = rootTest.createChildContainer("Copy");
+		String filename = UUID.randomUUID().toString() + ".txt";
+		VFSLeaf file = rootTest.createChildLeaf(filename);
+		int byteCopied = copyTestTxt(file);
+		Assert.assertFalse(byteCopied == 0);
+		
+		//save a first version
+		for(int i=0; i<2; i++) {
+			InputStream inv = new ByteArrayInputStream(("Hello version " + i).getBytes());
+			vfsRepositoryService.addVersion(file, id, "Version " + (1 +i), inv);
+			inv.close();
+		}
+
+		targetRootTest.copyFrom(file);
+		dbInstance.commitAndCloseSession();
+		
+		VFSItem targetFile = targetRootTest.resolve(filename);
+		VFSMetadata targetMetadata = vfsRepositoryService.getMetadataFor(targetFile);
+		List<VFSRevision> revisions = vfsRepositoryService.getRevisions(targetMetadata);
+		Assert.assertNotNull(revisions);
+		Assert.assertEquals(2, revisions.size());
+		for(VFSRevision revision:revisions) {
+			VFSItem revFile = targetRootTest.resolve(((VFSRevisionImpl)revision).getFilename());
+			Assert.assertNotNull(revFile);
+			Assert.assertTrue(revFile.exists());
+			Assert.assertTrue(revFile instanceof VFSLeaf);
+			Assert.assertTrue(((VFSLeaf)revFile).getSize() > 4);
+		}
+	}
+	
+	/**
+	 * The test create an original file and 3 revisions with exactly
+	 * the same content. We delete the original and the first version.
+	 * We check that version 2 and 3 survives and that the file exists.
+	 * 
+	 * @throws IOException
+	 */
+	@Test
+	public void deleteVersions_withSameFile() throws IOException {
+		VFSContainer rootTest = VFSManager.olatRootContainer("/ver-" + UUID.randomUUID(), null);
+		String filename = UUID.randomUUID().toString() + ".txt";
+		VFSLeaf file = rootTest.createChildLeaf(filename);
+		int byteCopied = copyTestTxt(file);
+		Assert.assertFalse(byteCopied == 0);
+		
+		Identity id = JunitTestHelper.createAndPersistIdentityAsRndUser("vers-5");
+		
+		//save a first version
+		InputStream in1 = VFSVersioningTest.class.getResourceAsStream("test.txt");
+		vfsRepositoryService.addVersion(file, id, "Version 1", in1);
+		in1.close();
+		
+		//save a second version
+		InputStream in2 = VFSVersioningTest.class.getResourceAsStream("test.txt");
+		vfsRepositoryService.addVersion(file, id, "Version 2", in2);
+		in2.close();
+		
+		//save a third version
+		InputStream in3 = VFSVersioningTest.class.getResourceAsStream("test.txt");
+		vfsRepositoryService.addVersion(file, id, "Version 3", in2);
+		in3.close();
+		
+		//delete revisions
+		VFSItem reloadFile = rootTest.resolve(filename);
+		VFSMetadata metadata = vfsRepositoryService.getMetadataFor(reloadFile);
+		List<VFSRevision> revisions = vfsRepositoryService.getRevisions(metadata);
+		vfsRepositoryService.deleteRevisions(id, revisions.subList(0, 2));
+		dbInstance.commitAndCloseSession();
+		
+		//check number of versions
+		List<VFSRevision> trimmedRevisions = vfsRepositoryService.getRevisions(metadata);
+
+		Assert.assertNotNull(trimmedRevisions);
+		Assert.assertEquals(1, trimmedRevisions.size());
+		//check surviving versions
+		Assert.assertEquals("Version 2", trimmedRevisions.get(0).getRevisionComment());
+		Assert.assertEquals("Version 3", metadata.getRevisionComment());
+		//check that the last backup file exists
+		VFSRevisionImpl revision2 = (VFSRevisionImpl)trimmedRevisions.get(0);
+		VFSItem revision2File =  reloadFile.getParentContainer().resolve(revision2.getFilename());
+		Assert.assertNotNull(revision2File);
+		Assert.assertTrue(revision2File.exists());
+		Assert.assertTrue(revision2File instanceof VFSLeaf);
+		
+		//check if there is only one backup file
+		VFSContainer versionContainer = reloadFile.getParentContainer();
+		List<VFSItem> items = versionContainer.getItems(new VersionsFilter(filename));
+		Assert.assertEquals(1, items.size());
+	}
+	
+	/**
+	 * The test create an original file and 5 versions. It manually
+	 * delete the physical back up file. We delete the versions
+	 * of the orginal, 1 and 2. At the end, there is only version 4
+	 * and 5.
+	 * 
+	 * 
+	 * @throws IOException
+	 */
+	@Test
+	public void deleteVersions_withMissingRevisionFile() throws IOException {
+		VFSContainer rootTest = VFSManager.olatRootContainer("/ver-" + UUID.randomUUID(), null);
+		String filename = UUID.randomUUID().toString() + ".txt";
+		VFSLeaf file = rootTest.createChildLeaf(filename);
+		int byteCopied = copyTestTxt(file);
+		Assert.assertFalse(byteCopied == 0);
+		
+		Identity id2 = JunitTestHelper.createAndPersistIdentityAsRndUser("vers-6");
+		
+		//save a first version
+		InputStream in1 = new ByteArrayInputStream("Hello version 1".getBytes());
+		vfsRepositoryService.addVersion(file, id2, "Version 1", in1);
+		in1.close();
+		
+		//save a second version
+		InputStream in2 = new ByteArrayInputStream("Hello version 2".getBytes());
+		vfsRepositoryService.addVersion(file, id2, "Version 2", in2);
+		in2.close();
+		
+		//save a third version
+		InputStream in3 = new ByteArrayInputStream("Hello version 3".getBytes());
+		vfsRepositoryService.addVersion(file, id2, "Version 3", in3);
+		in3.close();
+		
+		//save a fourth version
+		InputStream in4 = new ByteArrayInputStream("Hello version 4".getBytes());
+		vfsRepositoryService.addVersion(file, id2, "Version 4", in4);
+		in4.close();
+		
+		//save a fourth version
+		InputStream in5 = new ByteArrayInputStream("Hello version 5".getBytes());
+		vfsRepositoryService.addVersion(file, id2, "Version 5", in5);
+		in5.close();
+		
+		dbInstance.commitAndCloseSession();
+		
+		//delete a specific
+		VFSMetadata metadata = vfsRepositoryService.getMetadataFor(file);
+		List<VFSRevision> revisions = vfsRepositoryService.getRevisions(metadata);
+		VFSRevision rev4 = revisions.get(3);
+		VFSRevisionImpl toDeleteVersionImpl = (VFSRevisionImpl)rev4;
+		VFSItem itemToDelete = file.getParentContainer().resolve(toDeleteVersionImpl.getFilename());
+		itemToDelete.deleteSilently();
+		
+		//delete revisions
+		List<VFSRevision> toDelete = new ArrayList<>(revisions.subList(0, 3));
+		vfsRepositoryService.deleteRevisions(id2, toDelete);
+		
+		dbInstance.commitAndCloseSession();
+		
+		//check number of versions
+		VFSItem reloadFile = rootTest.resolve(filename);
+		VFSMetadata reloadedMetadata = vfsRepositoryService.getMetadataFor(reloadFile);
+		List<VFSRevision> reloadedRevisions = vfsRepositoryService.getRevisions(reloadedMetadata);
+
+		Assert.assertNotNull(reloadedRevisions);
+		Assert.assertEquals(1, reloadedRevisions.size());
+		VFSRevision revision = reloadedRevisions.get(0);
+		Assert.assertEquals("Version 4", revision.getRevisionComment());
+		Assert.assertEquals("Version 5", reloadedMetadata.getRevisionComment());
+		
+		//check if there is only one backup file
+		VFSContainer versionContainer = file.getParentContainer();
+		List<VFSItem> items = versionContainer.getItems(new VersionsFilter(filename));
+		Assert.assertEquals(1, items.size());
+	}
+	
+	@Test
+	public void verionsWithAuthorsAndCreators() throws IOException {
+		//create a file
+		VFSContainer rootTest = VFSManager.olatRootContainer("/ver" + UUID.randomUUID(), null);
+		String filename = UUID.randomUUID().toString() + ".txt";
+		VFSLeaf file = rootTest.createChildLeaf(filename);
+		int byteCopied = copyTestTxt(file);
+		Assert.assertFalse(byteCopied == 0);
+		Assert.assertEquals(VFSConstants.YES, file.canMeta());
+		
+		Identity id1 = JunitTestHelper.createAndPersistIdentityAsRndUser("vers-7");
+		Identity id2 = JunitTestHelper.createAndPersistIdentityAsRndUser("vers-8");
+		
+		//set the author
+		VFSMetadata metadata = vfsRepositoryService.getMetadataFor(file);
+		metadata.setAuthor(id1);
+		metadata.setCreator(id1.getName());
+		metadata = vfsRepositoryService.updateMetadata(metadata);
+		dbInstance.commitAndCloseSession();
+		
+		//save a first version -> id2
+		InputStream in1 = new ByteArrayInputStream("Hello version 1".getBytes());
+		vfsRepositoryService.addVersion(file, id2, "Version 1", in1);
+		in1.close();
+		
+		//save a second version -> id1
+		InputStream in2 = new ByteArrayInputStream("Hello version 2".getBytes());
+		vfsRepositoryService.addVersion(file, id1, "Version 2", in2);
+		in2.close();
+		
+		//save a third version -> id2
+		InputStream in3 = new ByteArrayInputStream("Hello version 3".getBytes());
+		vfsRepositoryService.addVersion(file, id2, "Version 3", in3);
+		in3.close();
+
+		//make the checks
+		VFSItem retrievedFile = rootTest.resolve(filename);
+		metadata = vfsRepositoryService.getMetadataFor(file);	
+		List<VFSRevision> revisions = vfsRepositoryService.getRevisions(metadata);
+		Assert.assertNotNull(revisions);
+		Assert.assertEquals(3, revisions.size());
+		Assert.assertEquals(VFSConstants.YES, retrievedFile.canMeta());
+		
+		VFSRevision revision0 = revisions.get(0);
+		//we don't set an author for the original file
+		Assert.assertEquals(id1, revision0.getAuthor());
+		VFSRevision revision1 = revisions.get(1);
+		Assert.assertEquals(id2, revision1.getAuthor());
+		VFSRevision revision2 = revisions.get(2);
+		Assert.assertEquals(id1, revision2.getAuthor());
+		//current
+		Assert.assertEquals(id2, metadata.getAuthor());
+	}
+	
+	@Test
+	public void deleteLeaf() throws IOException {
+		//create a file
+		VFSContainer rootTest = VFSManager.olatRootContainer("/ver" + UUID.randomUUID(), null);
+		String filename = UUID.randomUUID().toString() + ".txt";
+		VFSLeaf file = rootTest.createChildLeaf(filename);
+		int byteCopied = copyTestTxt(file);
+		Assert.assertFalse(byteCopied == 0);
+		Assert.assertEquals(VFSConstants.YES, file.canMeta());
+		
+		Identity id = JunitTestHelper.createAndPersistIdentityAsRndUser("vers-12");
+		
+		//save a first version -> id
+		InputStream in1 = new ByteArrayInputStream("Hello version 1".getBytes());
+		vfsRepositoryService.addVersion(file, id, "Version 1", in1);
+		in1.close();
+		
+		dbInstance.commitAndCloseSession();
+		VFSMetadata metadata = vfsRepositoryService.getMetadataFor(file);
+		
+		
+		// make sure the version is there
+		List<VFSItem> revFiles = file.getParentContainer().getItems(new VersionsFilter(filename));
+		Assert.assertEquals(1, revFiles.size());
+		
+		// delete all metadata and versions
+		file.deleteSilently();
+		dbInstance.commitAndCloseSession();
+		
+		List<VFSRevision> revisions = vfsRepositoryService.getRevisions(metadata);
+		Assert.assertTrue(revisions.isEmpty());
+		List<VFSItem> deletedRevFiles = file.getParentContainer().getItems(new VersionsFilter(filename));
+		Assert.assertTrue(deletedRevFiles.isEmpty());
+	}
+	
+	@Test
+	public void rename_leaf() throws IOException {
+		//create a file
+		VFSContainer rootTest = VFSManager.olatRootContainer("/ver" + UUID.randomUUID(), null);
+		String filename = UUID.randomUUID().toString() + ".txt";
+		VFSLeaf file = rootTest.createChildLeaf(filename);
+		int byteCopied = copyTestTxt(file);
+		Assert.assertFalse(byteCopied == 0);
+		Assert.assertEquals(VFSConstants.YES, file.canMeta());
+		
+		Identity id = JunitTestHelper.createAndPersistIdentityAsRndUser("vers-12");
+		
+		//save a first version -> id
+		InputStream in1 = new ByteArrayInputStream("Hello, move me".getBytes());
+		vfsRepositoryService.addVersion(file, id, "Version 1", in1);
+		in1.close();
+		dbInstance.commitAndCloseSession();
+		
+		VFSMetadata metadata = vfsRepositoryService.getMetadataFor(file);
+
+		// make sure the version is there
+		List<VFSItem> revFiles = file.getParentContainer().getItems(new VersionsFilter(filename));
+		Assert.assertEquals(1, revFiles.size());
+		
+		// delete all metadata and versions
+		String newName = "IMoved.txt";
+		file.rename(newName);
+		dbInstance.commitAndCloseSession();
+		
+		List<VFSRevision> revisions = vfsRepositoryService.getRevisions(metadata);
+		Assert.assertEquals(1, revisions.size());
+		List<VFSItem> movedRevFiles = file.getParentContainer().getItems(new VersionsFilter(newName));
+		Assert.assertEquals(1, movedRevFiles.size());
+		Assert.assertEquals(((VFSRevisionImpl)revisions.get(0)).getFilename(), movedRevFiles.get(0).getName());
+	}
+	
+	@Test
+	public void testMove() throws IOException {
+		//create a file
+		VFSContainer rootTest = VFSManager.olatRootContainer("/ver" + UUID.randomUUID(), null);
+		String filename = UUID.randomUUID().toString() + ".txt";
+		VFSLeaf file = rootTest.createChildLeaf(filename);
+		int byteCopied = copyTestTxt(file);
+		Assert.assertFalse(byteCopied == 0);
+		Assert.assertEquals(VFSConstants.YES, file.canMeta());
+		
+		Identity id1 = JunitTestHelper.createAndPersistIdentityAsRndUser("vers-9");
+		Identity id2 = JunitTestHelper.createAndPersistIdentityAsRndUser("vers-10");
+		
+		
+		//set the author
+		VFSMetadata metadata = vfsRepositoryService.getMetadataFor(file);
+		metadata.setAuthor(id1);
+		metadata.setCreator(id1.getName());
+		metadata = vfsRepositoryService.updateMetadata(metadata);
+		
+		//save a first version -> id2
+		InputStream in1 = new ByteArrayInputStream("Hello version 1".getBytes());
+		vfsRepositoryService.addVersion(file, id2, "Version 1", in1);
+		in1.close();
+		
+		//save a second version -> id1
+		InputStream in2 = new ByteArrayInputStream("Hello version 2".getBytes());
+		vfsRepositoryService.addVersion(file, id1, "Version 2", in2);
+		in2.close();
+		
+		//move the file
+		VFSLeaf retrievedLeaf = (VFSLeaf)rootTest.resolve(filename);
+		String copyFilename = UUID.randomUUID().toString() + ".txt";
+		VFSLeaf copyFile = rootTest.createChildLeaf(copyFilename);
+		OutputStream copyOutput = copyFile.getOutputStream(false);
+		InputStream copyInput = retrievedLeaf.getInputStream();
+		IOUtils.copy(copyInput, copyOutput);
+		copyOutput.close();
+		copyInput.close();
+		//move the revisions
+		vfsRepositoryService.move(retrievedLeaf, copyFile, id2);
+		
+		//check if the revisions are moved
+		VFSLeaf retirevedCopyFile = (VFSLeaf)rootTest.resolve(copyFilename);
+		VFSMetadata metadataCopy = vfsRepositoryService.getMetadataFor(retirevedCopyFile);	
+		List<VFSRevision> revisions = vfsRepositoryService.getRevisions(metadataCopy);
+		Assert.assertNotNull(revisions);
+		Assert.assertEquals(2, revisions.size());
+		
+		VFSRevision revision0 = revisions.get(0);
+		//we don't set an author for the original file
+		assertEquals(id1, revision0.getAuthor());
+		VFSRevision revision1 = revisions.get(1);
+		assertEquals(id2, revision1.getAuthor());
+		//current
+		assertEquals(id1.getName(), metadataCopy.getCreator());
+		assertEquals(id2, metadataCopy.getAuthor());
+	}
+	
+	private int copyTestTxt(VFSLeaf file) {
+		try(OutputStream out = file.getOutputStream(false);
+				InputStream in = VFSVersioningTest.class.getResourceAsStream("test.txt")) {
+			return IOUtils.copy(in, out);
+		} catch(IOException e) {
+			return -1;
+		}
+	}
+	
+
+	private static class SetMaxNumberOfVersions implements Callable<Boolean> {
+		
+		private final Long maxNumOfVersions;
+		private final VFSVersionModule versionConfig;
+		
+		public SetMaxNumberOfVersions(VFSVersionModule versionConfig, Long maxNumOfVersions) {
+			this.versionConfig = versionConfig;
+			this.maxNumOfVersions = maxNumOfVersions;
+		}
+
+		@Override
+		public Boolean call() throws Exception {
+			int currentValue = versionConfig.getMaxNumberOfVersions();
+			return currentValue == maxNumOfVersions.longValue();
+		}
+	}
+	
+	private static class VersionsFilter implements VFSItemFilter {
+		
+		private final String filename;
+		
+		public VersionsFilter(String filename) {
+			this.filename = filename;
+		}
+
+		@Override
+		public boolean accept(VFSItem item) {
+			if(item instanceof VFSLeaf && item.isHidden() && item.getName().endsWith(filename)) {
+				return true;
+			}
+			return false;
+		}
+		
+	}
+}
diff --git a/src/test/java/org/olat/core/util/vfs/version/VersionManagerTest.java b/src/test/java/org/olat/core/util/vfs/version/VersionManagerTest.java
deleted file mode 100644
index 7023235fa1a7627f2691a3bd69f152ebfdb65419..0000000000000000000000000000000000000000
--- a/src/test/java/org/olat/core/util/vfs/version/VersionManagerTest.java
+++ /dev/null
@@ -1,609 +0,0 @@
-/**
- * <a href="http://www.openolat.org">
- * OpenOLAT - Online Learning and Training</a><br>
- * <p>
- * Licensed under the Apache License, Version 2.0 (the "License"); <br>
- * you may not use this file except in compliance with the License.<br>
- * You may obtain a copy of the License at the
- * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
- * <p>
- * Unless required by applicable law or agreed to in writing,<br>
- * software distributed under the License is distributed on an "AS IS" BASIS, <br>
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
- * See the License for the specific language governing permissions and <br>
- * limitations under the License.
- * <p>
- * Initial code contributed and copyrighted by<br>
- * frentix GmbH, http://www.frentix.com
- * <p>
- */
-package org.olat.core.util.vfs.version;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.UUID;
-import java.util.concurrent.Callable;
-
-import org.apache.commons.io.IOUtils;
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.olat.core.CoreSpringFactory;
-import org.olat.core.commons.services.vfs.VFSMetadata;
-import org.olat.core.commons.services.vfs.VFSRepositoryService;
-import org.olat.core.id.Identity;
-import org.olat.core.util.vfs.VFSConstants;
-import org.olat.core.util.vfs.VFSContainer;
-import org.olat.core.util.vfs.VFSItem;
-import org.olat.core.util.vfs.VFSLeaf;
-import org.olat.core.util.vfs.VFSManager;
-import org.olat.core.util.vfs.filters.VFSSystemItemFilter;
-import org.olat.test.JunitTestHelper;
-import org.olat.test.OlatTestCase;
-import org.springframework.beans.factory.annotation.Autowired;
-
-/**
- * 
- * Description:<br>
- * 
- * <P>
- * Initial Date:  23 déc. 2011 <br>
- *
- * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
- */
-public class VersionManagerTest extends OlatTestCase {
-	
-	private static boolean setuped = false;
-	
-	private static Identity id1, id2;
-	
-	@Autowired
-	private VersionsFileManager versionsManager;
-	@Autowired
-	private SimpleVersionConfig versioningConfigurator;
-	@Autowired
-	private VFSRepositoryService vfsRepositoryService;
-	
-	@Before
-	public void setUp() throws Exception {
-		if(setuped) return;
-		
-		//create identities
-		id1 = JunitTestHelper.createAndPersistIdentityAsUser("vm-one" + getRandomName());
-		id2 = JunitTestHelper.createAndPersistIdentityAsUser("vm-two" + getRandomName());
-		
-		SimpleVersionConfig versionConfig = (SimpleVersionConfig)CoreSpringFactory.getBean("versioningConfigurator");
-		versionConfig.setMaxNumberOfVersionsProperty(10);
-		waitForCondition(new SetMaxNumberOfVersions(versionConfig,  10l), 2000);
-		setuped = true;
-	}
-	
-	@After
-	public void resetMaxVersions() {
-		int maxNumberOfVersions = versioningConfigurator.getMaxNumberOfVersionsProperty();
-		if(maxNumberOfVersions != 10) {
-			versioningConfigurator.setMaxNumberOfVersionsProperty(10);
-			waitForCondition(new SetMaxNumberOfVersions(versioningConfigurator,  10l), 2000);
-		}
-	}
-	
-	private static class SetMaxNumberOfVersions implements Callable<Boolean> {
-		
-		private final Long maxNumOfVersions;
-		private final SimpleVersionConfig versioningConfig;
-		
-		public SetMaxNumberOfVersions(SimpleVersionConfig versioningConfig, Long maxNumOfVersions) {
-			this.versioningConfig = versioningConfig;
-			this.maxNumOfVersions = maxNumOfVersions;
-		}
-
-		@Override
-		public Boolean call() throws Exception {
-			int currentValue = versioningConfig.getMaxNumberOfVersionsProperty();
-			return currentValue == maxNumOfVersions.longValue();
-		}
-	}
-	
-	@Test
-	public void testVersionManager() throws IOException {
-		//create a file
-		VFSContainer rootTest = VFSManager.olatRootContainer("/test", null);
-		String filename = getRandomName();
-		VFSLeaf file = rootTest.createChildLeaf(filename);
-		int byteCopied = copyTestTxt(file);
-		assertFalse(byteCopied == 0);
-		assertTrue(file instanceof Versionable);
-		
-		//save a first version
-		Versionable versionedFile1 = (Versionable)file;
-		InputStream in1 = new ByteArrayInputStream("Hello version 1".getBytes());
-		versionedFile1.getVersions().addVersion(id2, "Version 1", in1);
-		in1.close();
-		
-		//save a second version
-		Versionable versionedFile2 = (Versionable)file;
-		InputStream in2 = new ByteArrayInputStream("Hello version 2".getBytes());
-		versionedFile2.getVersions().addVersion(id2, "Version 2", in2);
-		in2.close();
-		
-		//save a third version
-		Versionable versionedFile3 = (Versionable)file;
-		InputStream in3 = new ByteArrayInputStream("Hello version 3".getBytes());
-		versionedFile3.getVersions().addVersion(id2, "Version 3", in3);
-		in3.close();
-
-		//make the checks
-		VFSItem retrievedFile = rootTest.resolve(filename);
-		assertTrue(retrievedFile instanceof Versionable);
-		Versions versions = versionsManager.createVersionsFor((VFSLeaf)retrievedFile);	
-		List<VFSRevision> revisions = versions.getRevisions();
-		assertNotNull(revisions);
-		assertEquals(3, revisions.size());
-		
-		VFSRevision revision0 = revisions.get(0);
-		//we don't set an author for the original file
-		assertNull(null, revision0.getAuthor());
-		VFSRevision revision1 = revisions.get(1);
-		assertEquals(id2.getName(), revision1.getAuthor());
-		VFSRevision revision2 = revisions.get(2);
-		assertEquals(id2.getName(), revision2.getAuthor());
-
-		//check the comments
-		assertNull(revision0.getComment());	
-		assertEquals("Version 1", revision1.getComment());
-		assertEquals("Version 2", revision2.getComment());
-		assertEquals("Version 3", versions.getComment());
-	}
-	
-	@Test
-	public void testOverflow_lowLevel() throws IOException {
-		versioningConfigurator.setMaxNumberOfVersionsProperty(3);
-		waitForCondition(new SetMaxNumberOfVersions(versioningConfigurator, 3l), 2000);
-		
-		//create a file
-		VFSContainer rootTest = VFSManager.olatRootContainer("/test_" + UUID.randomUUID(), null);
-		String filename = getRandomName();
-		VFSLeaf file = rootTest.createChildLeaf(filename);
-		int byteCopied = copyTestTxt(file);
-		assertFalse(byteCopied == 0);
-		assertTrue(file instanceof Versionable);
-		
-		//save a first version
-		for(int i=0; i<5; i++) {
-			Versionable versionedFile = (Versionable)file;
-			InputStream inv = new ByteArrayInputStream(("Hello version " + i).getBytes());
-			versionedFile.getVersions().addVersion(id2, "Version " + (1 +i), inv);
-			inv.close();
-		}
-
-		VFSItem retrievedFile = rootTest.resolve(filename);
-		Versions versions = versionsManager.createVersionsFor((VFSLeaf)retrievedFile);	
-		List<VFSRevision> revisions = versions.getRevisions();
-		assertNotNull(revisions);
-		assertEquals(3, revisions.size());
-		assertEquals("3", revisions.get(0).getRevisionNr());
-		assertEquals("4", revisions.get(1).getRevisionNr());
-		assertEquals("5", revisions.get(2).getRevisionNr());
-
-		assertEquals("Version 5", versions.getComment());
-		assertEquals(id2.getName(), revisions.get(2).getAuthor());
-	}
-	
-	@Test
-	public void testOverflow_lowLevel_deactivated() throws IOException {
-		versioningConfigurator.setMaxNumberOfVersionsProperty(0);
-		waitForCondition(new SetMaxNumberOfVersions(versioningConfigurator,  0l), 2000);
-		
-		//create a file
-		VFSContainer rootTest = VFSManager.olatRootContainer("/test_" + UUID.randomUUID(), null);
-		String filename = getRandomName();
-		VFSLeaf file = rootTest.createChildLeaf(filename);
-		int byteCopied = copyTestTxt(file);
-		assertFalse(byteCopied == 0);
-		assertTrue(file instanceof Versionable);
-		
-		//save a first version
-		for(int i=0; i<5; i++) {
-			Versionable versionedFile = (Versionable)file;
-			InputStream inv = new ByteArrayInputStream(("Hello version " + i).getBytes());
-			versionedFile.getVersions().addVersion(id2, "Version " + (1 +i), inv);
-			inv.close();
-		}
-
-		VFSItem retrievedFile = rootTest.resolve(filename);
-		Versions versions = versionsManager.createVersionsFor((VFSLeaf)retrievedFile);	
-		List<VFSRevision> revisions = versions.getRevisions();
-		assertNotNull(revisions);
-		assertTrue(revisions.isEmpty());
-	}
-	
-	@Test
-	public void testVersionChecksum() throws IOException {
-		VFSContainer rootTest = VFSManager.olatRootContainer("/ver-" + UUID.randomUUID(), null);
-		String filename = getRandomName();
-		VFSLeaf file = rootTest.createChildLeaf(filename);
-		int byteCopied = copyTestTxt(file);
-		assertFalse(byteCopied == 0);
-		assertTrue(file instanceof Versionable);
-		
-		
-		//save a first version
-		Versionable versionedFile = (Versionable)file;
-		InputStream in1 = VersionManagerTest.class.getResourceAsStream("test.txt");
-		versionedFile.getVersions().addVersion(id2, "Version 1", in1);
-		in1.close();
-		
-		//save a second version
-		InputStream in2 = VersionManagerTest.class.getResourceAsStream("test.txt");
-		versionedFile.getVersions().addVersion(id2, "Version 2", in2);
-		in2.close();
-		
-		//save a third version
-		InputStream in3 = VersionManagerTest.class.getResourceAsStream("test.txt");
-		versionedFile.getVersions().addVersion(id2, "Version 3", in2);
-		in3.close();
-		
-		//check if there is only one backup file
-		VFSContainer versionContainer = versionsManager.getCanonicalVersionFolder(file.getParentContainer(), false);
-		Assert.assertNotNull(versionContainer);
-		List<VFSItem> items = versionContainer.getItems(new VFSSystemItemFilter());
-		Assert.assertNotNull(items);
-		Assert.assertEquals(2, items.size());
-		
-		//check number of versions
-		VFSItem reloadFile = rootTest.resolve(filename);
-		assertTrue(reloadFile instanceof Versionable);
-		Versionable reloadedVersionedFile = (Versionable)reloadFile;
-		List<VFSRevision> revisions = reloadedVersionedFile.getVersions().getRevisions();
-		Assert.assertNotNull(revisions);
-		Assert.assertEquals(3, revisions.size());
-	}
-	
-	/**
-	 * The test create an original file and 3 revisions with exactly
-	 * the same content. We delete the original and the first version.
-	 * We check that version 2 and 3 survives and that the file exists.
-	 * 
-	 * @throws IOException
-	 */
-	@Test
-	public void testDeleteRevisions_withSameFile() throws IOException {
-		VFSContainer rootTest = VFSManager.olatRootContainer("/ver-" + UUID.randomUUID(), null);
-		String filename = getRandomName();
-		VFSLeaf file = rootTest.createChildLeaf(filename);
-		int byteCopied = copyTestTxt(file);
-		assertFalse(byteCopied == 0);
-		assertTrue(file instanceof Versionable);
-		
-		//save a first version
-		Versionable versionedFile = (Versionable)file;
-		InputStream in1 = VersionManagerTest.class.getResourceAsStream("test.txt");
-		versionedFile.getVersions().addVersion(id2, "Version 1", in1);
-		in1.close();
-		
-		//save a second version
-		InputStream in2 = VersionManagerTest.class.getResourceAsStream("test.txt");
-		versionedFile.getVersions().addVersion(id2, "Version 2", in2);
-		in2.close();
-		
-		//save a third version
-		InputStream in3 = VersionManagerTest.class.getResourceAsStream("test.txt");
-		versionedFile.getVersions().addVersion(id2, "Version 3", in2);
-		in3.close();
-		
-		//delete revisions
-		versionsManager.deleteRevisions(versionedFile, versionedFile.getVersions().getRevisions().subList(0, 2));
-		
-		//check number of versions
-		VFSItem reloadFile = rootTest.resolve(filename);
-		assertTrue(reloadFile instanceof Versionable);
-		Versionable reloadedVersionedFile = (Versionable)reloadFile;
-		List<VFSRevision> revisions = reloadedVersionedFile.getVersions().getRevisions();
-		Assert.assertNotNull(revisions);
-		Assert.assertEquals(1, revisions.size());
-		//check surviving versions
-		Assert.assertEquals("Version 2", revisions.get(0).getComment());
-		Assert.assertEquals("Version 3", reloadedVersionedFile.getVersions().getComment());
-		//check that the last backup file exists
-		RevisionFileImpl revision2 = (RevisionFileImpl)revisions.get(0);
-		VFSLeaf revision2File = revision2.getFile();
-		Assert.assertNotNull(revision2File);
-		Assert.assertTrue(revision2File.exists());
-		
-		//check if there is only one backup file
-		VFSContainer versionContainer = versionsManager.getCanonicalVersionFolder(file.getParentContainer(), false);
-		Assert.assertNotNull(versionContainer);
-		List<VFSItem> items = versionContainer.getItems(new VFSSystemItemFilter());
-		Assert.assertNotNull(items);
-		Assert.assertEquals(2, items.size());
-	}
-	
-	/**
-	 * The test create an original file and 5 versions. It manually
-	 * delete the physical back up file. We delete the versions
-	 * of the orginal, 1 and 2. At the end, there is only version 4
-	 * and 5.
-	 * 
-	 * 
-	 * @throws IOException
-	 */
-	@Test
-	public void testDeleteRevisions_withMissingRevisionFile() throws IOException {
-		VFSContainer rootTest = VFSManager.olatRootContainer("/ver-" + UUID.randomUUID(), null);
-		String filename = getRandomName();
-		VFSLeaf file = rootTest.createChildLeaf(filename);
-		int byteCopied = copyTestTxt(file);
-		assertFalse(byteCopied == 0);
-		assertTrue(file instanceof Versionable);
-		
-		//save a first version
-		Versionable versionedFile = (Versionable)file;
-		InputStream in1 = new ByteArrayInputStream("Hello version 1".getBytes());
-		versionedFile.getVersions().addVersion(id2, "Version 1", in1);
-		in1.close();
-		
-		//save a second version
-		InputStream in2 = new ByteArrayInputStream("Hello version 2".getBytes());
-		versionedFile.getVersions().addVersion(id2, "Version 2", in2);
-		in2.close();
-		
-		//save a third version
-		InputStream in3 = new ByteArrayInputStream("Hello version 3".getBytes());
-		versionedFile.getVersions().addVersion(id2, "Version 3", in3);
-		in3.close();
-		
-		//save a fourth version
-		InputStream in4 = new ByteArrayInputStream("Hello version 4".getBytes());
-		versionedFile.getVersions().addVersion(id2, "Version 4", in4);
-		in4.close();
-		
-		//save a fourth version
-		InputStream in5 = new ByteArrayInputStream("Hello version 5".getBytes());
-		versionedFile.getVersions().addVersion(id2, "Version 5", in5);
-		in5.close();
-		
-		//delete a specific
-		VFSRevision rev3 = versionedFile.getVersions().getRevisions().get(3);
-		RevisionFileImpl toDeleteVersionImpl = (RevisionFileImpl)rev3;
-		VFSContainer versionContainerAlt = versionsManager.getCanonicalVersionFolder(rootTest, false);
-		VFSItem itemToDelete = versionContainerAlt.resolve(toDeleteVersionImpl.getFilename());
-		itemToDelete.deleteSilently();
-		
-		//delete revisions
-		List<VFSRevision> toDelete = new ArrayList<>(versionedFile.getVersions().getRevisions().subList(0, 3));
-		versionsManager.deleteRevisions(versionedFile, toDelete);
-		
-		//check number of versions
-		VFSItem reloadFile = rootTest.resolve(filename);
-		assertTrue(reloadFile instanceof Versionable);
-		Versionable reloadedVersionedFile = (Versionable)reloadFile;
-		List<VFSRevision> revisions = reloadedVersionedFile.getVersions().getRevisions();
-		Assert.assertNotNull(revisions);
-		Assert.assertEquals(1, revisions.size());
-		VFSRevision revision = revisions.get(0);
-		Assert.assertEquals("Version 4", revision.getComment());
-		Assert.assertEquals("Version 5", reloadedVersionedFile.getVersions().getComment());
-		
-		//check if there is only one backup file
-		VFSContainer versionContainer = versionsManager.getCanonicalVersionFolder(file.getParentContainer(), false);
-		Assert.assertNotNull(versionContainer);
-		List<VFSItem> items = versionContainer.getItems(new VFSSystemItemFilter());
-		Assert.assertNotNull(items);
-		Assert.assertEquals(2, items.size());
-	}
-	
-	@Test
-	public void testAuthorsAndCreators() throws IOException {
-		//create a file
-		VFSContainer rootTest = VFSManager.olatRootContainer("/test2", null);
-		String filename = getRandomName();
-		VFSLeaf file = rootTest.createChildLeaf(filename);
-		int byteCopied = copyTestTxt(file);
-		assertFalse(byteCopied == 0);
-		assertTrue(file instanceof Versionable);
-		assertEquals(VFSConstants.YES, file.canMeta());
-		
-		//set the author
-		VFSMetadata metaInfo = file.getMetaInfo();
-		metaInfo.setAuthor(id1);
-		metaInfo.setCreator(id1.getName());
-		metaInfo = vfsRepositoryService.updateMetadata(metaInfo);
-		
-		//save a first version -> id2
-		Versionable versionedFile1 = (Versionable)file;
-		InputStream in1 = new ByteArrayInputStream("Hello version 1".getBytes());
-		versionedFile1.getVersions().addVersion(id2, "Version 1", in1);
-		in1.close();
-		
-		//save a second version -> id1
-		Versionable versionedFile2 = (Versionable)file;
-		InputStream in2 = new ByteArrayInputStream("Hello version 2".getBytes());
-		versionedFile2.getVersions().addVersion(id1, "Version 2", in2);
-		in2.close();
-		
-		//save a third version -> id2
-		Versionable versionedFile3 = (Versionable)file;
-		InputStream in3 = new ByteArrayInputStream("Hello version 3".getBytes());
-		versionedFile3.getVersions().addVersion(id2, "Version 3", in3);
-		in3.close();
-
-		//make the checks
-		VFSItem retrievedFile = rootTest.resolve(filename);
-		assertTrue(retrievedFile instanceof Versionable);
-		assertTrue(retrievedFile instanceof VFSLeaf);
-		Versions versions = versionsManager.createVersionsFor((VFSLeaf)retrievedFile);	
-		List<VFSRevision> revisions = versions.getRevisions();
-		assertNotNull(revisions);
-		assertEquals(3, revisions.size());
-		assertEquals(VFSConstants.YES, retrievedFile.canMeta());
-		
-		VFSRevision revision0 = revisions.get(0);
-		//we don't set an author for the original file
-		assertEquals(id1.getName(), revision0.getAuthor());
-		VFSRevision revision1 = revisions.get(1);
-		assertEquals(id2.getName(), revision1.getAuthor());
-		VFSRevision revision2 = revisions.get(2);
-		assertEquals(id1.getName(), revision2.getAuthor());
-		//current
-		assertEquals(id2.getName(), versions.getAuthor());
-	}
-	
-	@Test
-	public void testMove() throws IOException {
-		//create a file
-		VFSContainer rootTest = VFSManager.olatRootContainer("/test2", null);
-		String filename = getRandomName();
-		VFSLeaf file = rootTest.createChildLeaf(filename);
-		int byteCopied = copyTestTxt(file);
-		assertFalse(byteCopied == 0);
-		assertTrue(file instanceof Versionable);
-		assertEquals(VFSConstants.YES, file.canMeta());
-		
-		//set the author
-		VFSMetadata metaInfo = file.getMetaInfo();
-		metaInfo.setAuthor(id1);
-		metaInfo.setCreator(id1.getName());
-		metaInfo = vfsRepositoryService.updateMetadata(metaInfo);
-		
-		//save a first version -> id2
-		Versionable versionedFile1 = (Versionable)file;
-		InputStream in1 = new ByteArrayInputStream("Hello version 1".getBytes());
-		versionedFile1.getVersions().addVersion(id2, "Version 1", in1);
-		in1.close();
-		
-		//save a second version -> id1
-		Versionable versionedFile2 = (Versionable)file;
-		InputStream in2 = new ByteArrayInputStream("Hello version 2".getBytes());
-		versionedFile2.getVersions().addVersion(id1, "Version 2", in2);
-		in2.close();
-		
-		//move the file
-		VFSLeaf retrievedLeaf = (VFSLeaf)rootTest.resolve(filename);
-		String copyFilename = getRandomName();
-		VFSLeaf copyFile = rootTest.createChildLeaf(copyFilename);
-		OutputStream copyOutput = copyFile.getOutputStream(false);
-		InputStream copyInput = retrievedLeaf.getInputStream();
-		IOUtils.copy(copyInput, copyOutput);
-		copyOutput.close();
-		copyInput.close();
-		//move the revisions
-		versionsManager.move(retrievedLeaf, copyFile, id2);
-		
-		//check if the revisions are moved
-		VFSLeaf retirevedCopyFile = (VFSLeaf)rootTest.resolve(copyFilename);
-		assertTrue(retirevedCopyFile instanceof Versionable);
-		Versions versions = versionsManager.createVersionsFor(retirevedCopyFile);	
-		List<VFSRevision> revisions = versions.getRevisions();
-		assertNotNull(revisions);
-		assertEquals(2, revisions.size());
-		
-		VFSRevision revision0 = revisions.get(0);
-		//we don't set an author for the original file
-		assertEquals(id1.getName(), revision0.getAuthor());
-		VFSRevision revision1 = revisions.get(1);
-		assertEquals(id2.getName(), revision1.getAuthor());
-		//current
-		assertEquals(id1.getName(), versions.getCreator());
-		assertEquals(id2.getName(), versions.getAuthor());
-	}
-	
-	/**
-	 * Create a file with 2 revision, move it to another name, move it to the primitive name:
-	 * File A, change file A, change file A, move to file B, move to file A
-	 * @throws IOException
-	 */
-	@Test
-	public void testCircleMove() throws IOException {
-		//create a file A
-		VFSContainer rootTest = VFSManager.olatRootContainer("/test2", null);
-		String filename = getRandomName();
-		VFSLeaf file = rootTest.createChildLeaf(filename);
-		int byteCopied = copyTestTxt(file);
-		assertFalse(byteCopied == 0);
-		assertTrue(file instanceof Versionable);
-		assertEquals(VFSConstants.YES, file.canMeta());
-		
-		//set the author
-		VFSMetadata metaInfo = file.getMetaInfo();
-		metaInfo.setAuthor(id1);
-		metaInfo.setCreator(id1.getName());
-		metaInfo = vfsRepositoryService.updateMetadata(metaInfo);
-		
-		//save a first version of file A -> id2
-		Versionable versionedFile1 = (Versionable)file;
-		InputStream in1 = new ByteArrayInputStream("Hello version 1".getBytes());
-		versionedFile1.getVersions().addVersion(id2, "Version 1", in1);
-		in1.close();
-		
-		//save a second version of file A -> id1
-		Versionable versionedFile2 = (Versionable)file;
-		InputStream in2 = new ByteArrayInputStream("Hello version 2".getBytes());
-		versionedFile2.getVersions().addVersion(id1, "Version 2", in2);
-		in2.close();
-		
-		//move the file A -> file B
-		VFSLeaf retrievedLeaf = (VFSLeaf)rootTest.resolve(filename);
-		String copyFilename = getRandomName();
-		VFSLeaf copyFile = rootTest.createChildLeaf(copyFilename);
-		OutputStream copyOutput = copyFile.getOutputStream(false);
-		InputStream copyInput = retrievedLeaf.getInputStream();
-		IOUtils.copy(copyInput, copyOutput);
-		copyOutput.close();
-		copyInput.close();
-		//move the revisions
-		versionsManager.move(retrievedLeaf, copyFile, id2);
-		
-		//move the file B -> file A
-		VFSLeaf retrievedCopyLeaf = (VFSLeaf)rootTest.resolve(copyFilename);
-		VFSLeaf originalFile = (VFSLeaf)rootTest.resolve(filename);
-		OutputStream originalOutput = originalFile.getOutputStream(false);
-		InputStream retrievedCopyInput = retrievedCopyLeaf.getInputStream();
-		IOUtils.copy(retrievedCopyInput, originalOutput);
-		originalOutput.close();
-		retrievedCopyInput.close();
-		//move the revisions
-		versionsManager.move(retrievedCopyLeaf, originalFile, id2);
-		
-		
-		//check if the revisions are moved
-		VFSLeaf retirevedOriginalFile = (VFSLeaf)rootTest.resolve(filename);
-		assertTrue(retirevedOriginalFile instanceof Versionable);
-		Versions versions = versionsManager.createVersionsFor(retirevedOriginalFile);	
-		List<VFSRevision> revisions = versions.getRevisions();
-		assertNotNull(revisions);
-		assertEquals(2, revisions.size());
-		
-		VFSRevision revision0 = revisions.get(0);
-		//we don't set an author for the original file
-		assertEquals(id1.getName(), revision0.getAuthor());
-		VFSRevision revision1 = revisions.get(1);
-		assertEquals(id2.getName(), revision1.getAuthor());
-		//current
-		assertEquals(id1.getName(), versions.getCreator());
-		assertEquals(id2.getName(), versions.getAuthor());
-	}
-	
-	private int copyTestTxt(VFSLeaf file) {
-		try(OutputStream out = file.getOutputStream(false);
-				InputStream in = VersionManagerTest.class.getResourceAsStream("test.txt")) {
-			return IOUtils.copy(in, out);
-		} catch(IOException e) {
-			return -1;
-		}
-	}
-	
-	private String getRandomName() {
-		return UUID.randomUUID().toString().replace("-", "");
-	}
-}
\ No newline at end of file
diff --git a/src/test/java/org/olat/modules/webFeed/manager/FeedFileStorgeTest.java b/src/test/java/org/olat/modules/webFeed/manager/FeedFileStorgeTest.java
index 4b37ba4ea4852aeed2065fb1683a8131f56bd904..5773263cf4012c976c9391ebd3384f2374b538b4 100644
--- a/src/test/java/org/olat/modules/webFeed/manager/FeedFileStorgeTest.java
+++ b/src/test/java/org/olat/modules/webFeed/manager/FeedFileStorgeTest.java
@@ -28,6 +28,7 @@ import java.util.List;
 import org.junit.Before;
 import org.junit.Test;
 import org.olat.core.util.vfs.VFSContainer;
+import org.olat.core.util.vfs.filters.VFSSystemItemFilter;
 import org.olat.fileresource.FileResourceManager;
 import org.olat.fileresource.types.BlogFileResource;
 import org.olat.fileresource.types.FeedFileResource;
@@ -499,7 +500,7 @@ public class FeedFileStorgeTest extends OlatTestCase {
 		sut.deleteFeedXML(feed);
 
 		// check if there is no file in the feed container
-		assertThat(sut.getOrCreateFeedContainer(feed).getItems().size()).isEqualTo(0);
+		assertThat(sut.getOrCreateFeedContainer(feed).getItems(new VFSSystemItemFilter()).size()).isEqualTo(0);
 
 		fileResourceManager.deleteFileResource(resource);
 	}
@@ -714,7 +715,7 @@ public class FeedFileStorgeTest extends OlatTestCase {
 		sut.deleteItemXML(item);
 
 		// check if there is no file in the item container
-		assertThat(sut.getOrCreateItemContainer(item).getItems().size()).isEqualTo(0);
+		assertThat(sut.getOrCreateItemContainer(item).getItems(new VFSSystemItemFilter()).size()).isEqualTo(0);
 
 		fileResourceManager.deleteFileResource(resource);
 	}
diff --git a/src/test/java/org/olat/restapi/FolderTest.java b/src/test/java/org/olat/restapi/FolderTest.java
index 63e08bdab9fb78c2d5438b92335b8449a514b318..8e39a27cdef2bb0d3750f7f49b48acf3b99a9494 100644
--- a/src/test/java/org/olat/restapi/FolderTest.java
+++ b/src/test/java/org/olat/restapi/FolderTest.java
@@ -28,7 +28,7 @@ import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 import org.junit.runners.Parameterized.Parameters;
-import org.olat.core.util.vfs.restapi.VFSWebservice;
+import org.olat.core.commons.services.vfs.restapi.VFSWebservice;
 /**
  * 
  * <h3>Description:</h3>
diff --git a/src/test/java/org/olat/test/AllTestsJunit4.java b/src/test/java/org/olat/test/AllTestsJunit4.java
index 55285c10e93983e6b4f0e74d095eb6a0a21c1571..ddb8225e42480f46b5a82adfbbfa84ce20c12e4f 100644
--- a/src/test/java/org/olat/test/AllTestsJunit4.java
+++ b/src/test/java/org/olat/test/AllTestsJunit4.java
@@ -98,10 +98,11 @@ import org.junit.runners.Suite;
 	org.olat.commons.coordinate.cluster.lock.LockTest.class,
 	org.olat.commons.coordinate.CoordinatorTest.class,
 	org.olat.core.commons.services.csp.manager.CSPManagerTest.class,
+	org.olat.core.commons.services.vfs.manager.VFSXStreamTest.class,
 	org.olat.core.commons.services.vfs.manager.VFSMetadataDAOTest.class,
-	org.olat.core.commons.services.vfs.manager.VFSRepositoryServiceTest.class,
+	org.olat.core.commons.services.vfs.manager.VFSRevisionDAOTest.class,
 	org.olat.core.commons.services.vfs.manager.VFSThumbnailDAOTest.class,
-	org.olat.core.commons.services.vfs.manager.VFSXStreamTest.class,
+	org.olat.core.commons.services.vfs.manager.VFSRepositoryServiceTest.class,
 	org.olat.core.commons.services.help.ConfluenceHelperTest.class,
 	org.olat.core.commons.services.help.spi.ConfluenceLinkSPITest.class,
 	org.olat.core.commons.services.license.manager.LicenseTypeActivationDAOTest.class,
@@ -420,7 +421,6 @@ import org.junit.runners.Suite;
 	org.olat.resource.accesscontrol.ACTransactionManagerTest.class,
 	org.olat.resource.accesscontrol.ACReservationDAOTest.class,
 	org.olat.resource.accesscontrol.provider.auto.manager.AdvanceOrderDAOTest.class,
-	org.olat.core.util.vfs.version.VersionManagerTest.class,
 	/**
 	 * Pure JUnit test without need of framework
 	 */
diff --git a/src/test/java/org/olat/test/VFSJavaIOFile.java b/src/test/java/org/olat/test/VFSJavaIOFile.java
index 703845216d1e313ab024a0cf323cf2aa2875c5d9..7f9482c8e449c69c72f8bf11e9f80ce5c97f5cef 100644
--- a/src/test/java/org/olat/test/VFSJavaIOFile.java
+++ b/src/test/java/org/olat/test/VFSJavaIOFile.java
@@ -158,6 +158,11 @@ public class VFSJavaIOFile implements VFSLeaf, JavaIOItem {
 		return VFSConstants.NO;
 	}
 
+	@Override
+	public VFSStatus canVersion() {
+		return VFSConstants.NO;
+	}
+
 	@Override
 	public VFSMetadata getMetaInfo() {
 		return null;