diff --git a/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/OnlyOfficeEditor.java b/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/OnlyOfficeEditor.java
index 664410d3dbc467060a3f99a468b3ddae3da4f112..3d1544722f783c1caacac992abe0ef004085a107 100644
--- a/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/OnlyOfficeEditor.java
+++ b/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/OnlyOfficeEditor.java
@@ -72,7 +72,9 @@ public class OnlyOfficeEditor implements DocEditor {
 
 	@Override
 	public boolean isLockedForMe(VFSLeaf vfsLeaf, Identity identity, Mode mode) {
-		// TODO uh Auto-generated method stub
+		if (onlyOfficeService.isLockNeeded(mode)) {
+			return onlyOfficeService.isLockedForMe(vfsLeaf, identity);
+		}
 		return false;
 	}
 
diff --git a/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/OnlyOfficeService.java b/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/OnlyOfficeService.java
index beb9ee803d9ec6d5e1dde98742b8df144395b92c..c09561ab0694de7e9c43cd350c11bf9248cc0c2c 100644
--- a/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/OnlyOfficeService.java
+++ b/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/OnlyOfficeService.java
@@ -24,6 +24,8 @@ import java.io.File;
 import org.olat.core.commons.services.doceditor.DocEditor.Mode;
 import org.olat.core.commons.services.vfs.VFSMetadata;
 import org.olat.core.id.Identity;
+import org.olat.core.util.vfs.VFSLeaf;
+import org.olat.core.util.vfs.lock.LockResult;
 
 /**
  * 
@@ -37,9 +39,19 @@ public interface OnlyOfficeService {
 
 	File getFile(String fileId);
 
-	boolean canUpdateContent(String fileId, Identity identity);
+	VFSLeaf getVfsLeaf(String fileId);
 
-	boolean updateContent(String fileId, Identity identity, String url);
+	boolean canUpdateContent(VFSLeaf vfsLeaf, Identity identity, String documentKey);
+
+	boolean updateContent(VFSLeaf vfsLeaf, Identity identity, String url);
+	
+	boolean isLockNeeded(Mode mode);
+
+	boolean isLockedForMe(VFSLeaf vfsLeaf, Identity identity);
+
+	LockResult lock(VFSLeaf vfsLeaf, Identity identity);
+
+	void unlock(VFSLeaf vfsLeaf);
 	
 	boolean isSupportedFormat(String suffix, Mode mode);
 
diff --git a/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/manager/OnlyOfficeServiceImpl.java b/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/manager/OnlyOfficeServiceImpl.java
index bc3e6d0a1dd796930c2fe47fde2244d727bced69..b3bd9cd27fb229c5ee082b68dc7ac4980989a9ff 100644
--- a/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/manager/OnlyOfficeServiceImpl.java
+++ b/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/manager/OnlyOfficeServiceImpl.java
@@ -22,21 +22,26 @@ package org.olat.core.commons.services.doceditor.onlyoffice.manager;
 import java.io.File;
 import java.io.InputStream;
 import java.net.URL;
+import java.nio.file.Paths;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
 
 import org.olat.basesecurity.BaseSecurityManager;
 import org.olat.core.commons.services.doceditor.DocEditor.Mode;
 import org.olat.core.commons.services.doceditor.onlyoffice.OnlyOfficeService;
-import org.olat.core.commons.services.doceditor.wopi.WopiService;
 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.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.VFSLockApplicationType;
+import org.olat.core.util.vfs.VFSLockManager;
 import org.olat.core.util.vfs.VFSManager;
+import org.olat.core.util.vfs.lock.LockInfo;
+import org.olat.core.util.vfs.lock.LockResult;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -51,36 +56,53 @@ public class OnlyOfficeServiceImpl implements OnlyOfficeService {
 
 	private static final OLog log = Tracing.createLoggerFor(OnlyOfficeServiceImpl.class);
 	
+	private static final String LOCK_APP_NAME = "onlyoffice";
+
 	private static DateFormat LAST_MODIFIED = new SimpleDateFormat("yyyyMMddHHmmSS");
 
-	@Autowired
-	private WopiService wopiService;
 	@Autowired
 	private VFSRepositoryService vfsRepositoryService;
 	@Autowired
+	private VFSLockManager lockManager;
+	@Autowired
 	private BaseSecurityManager securityManager;
 
 	@Override
 	public boolean fileExists(String fileId) {
-		return wopiService.fileExists(fileId);
+		return vfsRepositoryService.getItemFor(fileId) != null? true: false;
 	}
 
 	@Override
 	public File getFile(String fileId) {
-		return wopiService.getFile(fileId);
+		VFSLeaf vfsLeaf = getVfsLeaf(fileId);
+		if (vfsLeaf != null) {
+			String uri = vfsLeaf.getMetaInfo().getUri();
+			try {
+				return Paths.get(new URL(uri).toURI()).toFile();
+			} catch (Exception e) {
+				log.error("", e);
+			}
+		}
+		return null;
+	}
+
+	@Override
+	public VFSLeaf getVfsLeaf(String fileId) {
+		VFSItem item = vfsRepositoryService.getItemFor(fileId);
+		if (item instanceof VFSLeaf) {
+			return (VFSLeaf) item;
+		}
+		return null;
 	}
 
 	@Override
-	public boolean canUpdateContent(String fileId, Identity identity) {
-		return true;
-		//TODO uh check lock
-//		VFSLeaf vfsLeaf = wopiService.getVfsLeaf(fileId);
-//		return !isLockedForMe(vfsLeaf, access.getIdentity());
+	public boolean canUpdateContent(VFSLeaf vfsLeaf, Identity identity, String documentKey) {
+		String currentDocumentKey = getDocumentKey(vfsLeaf.getMetaInfo());
+		return currentDocumentKey.equals(documentKey) && !isLockedForMe(vfsLeaf, identity);
 	}
 
 	@Override
-	public boolean updateContent(String fileId, Identity identity, String url) {
-		VFSLeaf vfsLeaf = wopiService.getVfsLeaf(fileId);
+	public boolean updateContent(VFSLeaf vfsLeaf, Identity identity, String url) {
 		boolean updated = false;
 		try (InputStream in = new URL(url).openStream()) {
 			//TODO uh versionCntrolled
@@ -94,12 +116,46 @@ public class OnlyOfficeServiceImpl implements OnlyOfficeService {
 			log.error("", e);
 		}
 		if (updated) {
-			log.debug("File updated. File ID: " + fileId);
-			//TODO uh lock
-//			refreshLock(vfsLeaf);
+			log.debug("File updated. File name: " + vfsLeaf.getName());
+			refreshLock(vfsLeaf);
 		}
 		return updated;
 	}
+	
+	private void refreshLock(VFSLeaf vfsLeaf) {
+		LockInfo lock = lockManager.getLock(vfsLeaf);
+		if (lock != null) {
+			long inADay = System.currentTimeMillis() + (24 * 60 * 60 * 1000);
+			lock.setExpiresAt(inADay);
+		}
+	}
+	
+	@Override
+	public boolean isLockNeeded(Mode mode) {
+		return Mode.EDIT.equals(mode);
+	}
+
+	@Override
+	public boolean isLockedForMe(VFSLeaf vfsLeaf, Identity identity) {
+		return lockManager.isLockedForMe(vfsLeaf, identity, VFSLockApplicationType.collaboration, LOCK_APP_NAME);
+	}
+
+	@Override
+	public LockResult lock(VFSLeaf vfsLeaf, Identity identity) {
+		LockResult lock = lockManager.lock(vfsLeaf, identity, VFSLockApplicationType.collaboration, LOCK_APP_NAME);
+		log.debug("Locked file. File name: " + vfsLeaf.getName() + ", Identity: " + identity);
+		return lock;
+	}
+
+	@Override
+	public void unlock(VFSLeaf vfsLeaf) {
+		LockInfo lock = lockManager.getLock(vfsLeaf);
+		if (lock != null && LOCK_APP_NAME.equals(lock.getAppName())) {
+			lock.getTokens().clear();
+			lockManager.unlock(vfsLeaf, VFSLockApplicationType.collaboration);
+			log.debug("Unlocked file. File name: " + vfsLeaf.getName());
+		}
+	}
 
 	@Override
 	public boolean isSupportedFormat(String suffix, Mode mode) {
diff --git a/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/restapi/CallbackStatus.java b/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/restapi/CallbackStatus.java
new file mode 100644
index 0000000000000000000000000000000000000000..f153f01377a67dfbb3d0386d120b59ec6c2f9da8
--- /dev/null
+++ b/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/restapi/CallbackStatus.java
@@ -0,0 +1,53 @@
+/**
+ * <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.doceditor.onlyoffice.restapi;
+
+/**
+ * 
+ * Initial date: 16 Apr 2019<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+enum CallbackStatus {
+	
+	ErrorDocumentNotFound(0),
+	Editing(1),
+	MustSave(2),
+	ErrorCorrupted(3),
+	ClosedWithoutChanges(4),
+	MustForceSave(6),
+	ErrorCorruptedForce(7);
+	
+	private final int value;
+	
+	private CallbackStatus(int value) {
+		this.value = value;
+	}
+	
+	static CallbackStatus valueOf(int value) {
+		for (CallbackStatus callbackStatus : CallbackStatus.values()) {
+			if (callbackStatus.value == value) {
+				return callbackStatus;
+			}
+		}
+		return null;
+	}
+
+}
diff --git a/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/restapi/CallbackVO.java b/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/restapi/CallbackVO.java
index 7cb85686fef6c65148603be9759057a99f661d07..40b6660e36193833a5292e7a352a5d4471778a0f 100644
--- a/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/restapi/CallbackVO.java
+++ b/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/restapi/CallbackVO.java
@@ -35,8 +35,6 @@ public class CallbackVO {
 	
 	// see https://api.onlyoffice.com/editors/callback
 	
-	static final int STATUS_READY_FOR_SAVING = 2;
-	
 	private List<Action> actions;
 	private Integer forcesavetype;
 	private String key;
diff --git a/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/restapi/OnlyOfficeWebService.java b/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/restapi/OnlyOfficeWebService.java
index 33be973f60664200047cb8326717d99927d5dd6d..013da213468196de86ef0b102475cd5bbdf0605a 100644
--- a/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/restapi/OnlyOfficeWebService.java
+++ b/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/restapi/OnlyOfficeWebService.java
@@ -21,7 +21,6 @@ package org.olat.core.commons.services.doceditor.onlyoffice.restapi;
 
 import static org.olat.core.commons.services.doceditor.onlyoffice.restapi.CallbackResponseVO.error;
 import static org.olat.core.commons.services.doceditor.onlyoffice.restapi.CallbackResponseVO.success;
-import static org.olat.core.commons.services.doceditor.onlyoffice.restapi.CallbackVO.STATUS_READY_FOR_SAVING;
 
 import java.io.File;
 import java.util.List;
@@ -45,6 +44,8 @@ import org.olat.core.commons.services.doceditor.onlyoffice.OnlyOfficeService;
 import org.olat.core.id.Identity;
 import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
+import org.olat.core.util.vfs.VFSLeaf;
+import org.olat.core.util.vfs.lock.LockResult;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -87,10 +88,37 @@ public class OnlyOfficeWebService {
 		}
 		
 		CallbackResponseVO responseVO;
-		switch(callbackVO.getStatus()) {
-		case STATUS_READY_FOR_SAVING:
+		CallbackStatus status = CallbackStatus.valueOf(callbackVO.getStatus());
+		switch(status) {
+		case Editing:
+			responseVO = lock(fileId, callbackVO);
+			break;
+		case ClosedWithoutChanges:
+			// This callback is called
+			//     A) if a user closes a document without changes.
+			//     B) if a user does not edit a document for about one minute.
+			// Case B) results in a opened, unlocked file. If the user starts to edit the file again callback "Editing" is called and the file is locked again.
+			// However, is is possible to edit the file in the meantime in another editor and all changes made in ONLYOFFICE are lost!
+			// (This is the same implementation like in Alfresco, ownCloud, Nextcloud etc.)
+			responseVO = unlock(fileId, callbackVO);
+			break;
+		case MustSave:
+		case MustForceSave:
 			responseVO = updateContent(fileId, callbackVO);
 			break;
+		case ErrorCorrupted:
+			log.warn("ONLYOFFICE has reported that saving the document has failed. File ID: " + fileId);
+			responseVO = success();
+			break;
+		case ErrorCorruptedForce:
+			log.warn("ONLYOFFICE has reported that saving the document has failed. File ID: " + fileId);
+			responseVO = success();
+			break;
+		case ErrorDocumentNotFound:
+			// I never get that status, so I do not know, how to reproduce it.
+			log.warn("ONLYOFFICE has reported that no doc with the specified key can be found. File ID: " + fileId);
+			responseVO = success();
+			break;
 		default:
 			// nothing to do
 			responseVO = success();
@@ -99,19 +127,53 @@ public class OnlyOfficeWebService {
 		return Response.ok(responseVO).build();
 	}
 
-	private CallbackResponseVO updateContent(String fileId, CallbackVO callbackVO) {
+	private CallbackResponseVO lock(String fileId, CallbackVO callbackVO) {
 		String IdentityId = callbackVO.getUsers()[0];
 		Identity identity = onlyOfficeService.getIdentity(IdentityId);
-		if (identity == null) {
+		if (identity == null) return error();
+		
+		VFSLeaf vfsLeaf = onlyOfficeService.getVfsLeaf(fileId);
+		if (vfsLeaf == null) return error();
+		
+		boolean isLockedForMe = onlyOfficeService.isLockedForMe(vfsLeaf, identity);
+		if (isLockedForMe) return error();
+		
+		boolean canUpdate = onlyOfficeService.canUpdateContent(vfsLeaf, identity, callbackVO.getKey());
+		if (!canUpdate) {
+			log.debug("ONLYOFFICE has no right to update file. File ID: " + fileId + ", identity: " + IdentityId);
 			return error();
 		}
 		
-		boolean canUpdate = onlyOfficeService.canUpdateContent(fileId, identity);
+		LockResult lock = onlyOfficeService.lock(vfsLeaf, identity);
+		return lock != null? success(): error();
+	}
+
+	private CallbackResponseVO unlock(String fileId, CallbackVO callbackVO) {
+		VFSLeaf vfsLeaf = onlyOfficeService.getVfsLeaf(fileId);
+		if (vfsLeaf == null) return error();
+		
+		boolean lastUser = callbackVO.getUsers() == null || callbackVO.getUsers().length == 0;
+		if (lastUser) {
+			onlyOfficeService.unlock(vfsLeaf);
+		}
+		return success();
+	}
+
+	private CallbackResponseVO updateContent(String fileId, CallbackVO callbackVO) {
+		String IdentityId = callbackVO.getUsers()[0];
+		Identity identity = onlyOfficeService.getIdentity(IdentityId);
+		if (identity == null) return error();
+		
+		VFSLeaf vfsLeaf = onlyOfficeService.getVfsLeaf(fileId);
+		if (vfsLeaf == null) return error();
+		
+		boolean canUpdate = onlyOfficeService.canUpdateContent(vfsLeaf, identity, callbackVO.getKey());
 		if (!canUpdate) {
-			log.debug("Access has not right to update file. File ID: " + fileId + ", identity: " + IdentityId);
+			log.debug("ONLYOFFICE has no right to update file. File ID: " + fileId + ", identity: " + IdentityId);
 			return error();
 		}
-		boolean updated = onlyOfficeService.updateContent(fileId, identity, callbackVO.getUrl());
+		boolean updated = onlyOfficeService.updateContent(vfsLeaf, identity, callbackVO.getUrl());
+		onlyOfficeService.unlock(vfsLeaf);
 		return updated? success(): error();
 	}
 	
diff --git a/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/ui/ApiConfigBuilder.java b/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/ui/ApiConfigBuilder.java
index a6d9eff81eb6137f2d7bfbc8799ece4047aed6b2..946500f5e84e3286101fd490071303cd7a7be4e1 100644
--- a/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/ui/ApiConfigBuilder.java
+++ b/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/ui/ApiConfigBuilder.java
@@ -402,11 +402,10 @@ public class ApiConfigBuilder {
 		private String mode;
 		private User user;
 		// not implemented yet
+		// private Customization customization;
 		// private Object recent;
-//		private String createUrl;
-		// private Customization costumisazion;
+		// private String createUrl;
 		// private Embedded embedded;
-		// private Customization costumisazion;
 		
 		public String getCallbackUrl() {
 			return callbackUrl;
diff --git a/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/ui/OnlyOfficeEditorController.java b/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/ui/OnlyOfficeEditorController.java
index 45ca2514bc5ca0f03ec34ef2eb00ba5c0b763c29..e203d61930266d3e8fb193fa92f69a36b5e150e7 100644
--- a/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/ui/OnlyOfficeEditorController.java
+++ b/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/ui/OnlyOfficeEditorController.java
@@ -21,7 +21,9 @@ package org.olat.core.commons.services.doceditor.onlyoffice.ui;
 
 import org.olat.core.commons.services.doceditor.DocEditor.Mode;
 import org.olat.core.commons.services.doceditor.DocEditorSecurityCallback;
+import org.olat.core.commons.services.doceditor.DocEditorSecurityCallbackBuilder;
 import org.olat.core.commons.services.doceditor.onlyoffice.OnlyOfficeModule;
+import org.olat.core.commons.services.doceditor.onlyoffice.OnlyOfficeService;
 import org.olat.core.commons.services.vfs.VFSMetadata;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
@@ -47,11 +49,25 @@ public class OnlyOfficeEditorController extends BasicController {
 	
 	@Autowired
 	private OnlyOfficeModule onlyOfficeModule;
+	@Autowired
+	private OnlyOfficeService onlyOfficeService;
 
 	public OnlyOfficeEditorController(UserRequest ureq, WindowControl wControl, VFSLeaf vfsLeaf,
 			final DocEditorSecurityCallback securityCallback) {
 		super(ureq, wControl);
+
+		DocEditorSecurityCallback secCallback = securityCallback;
 		
+		if (onlyOfficeService.isLockNeeded(secCallback.getMode())) {
+			if (onlyOfficeService.isLockedForMe(vfsLeaf, getIdentity())) {
+				secCallback = DocEditorSecurityCallbackBuilder.clone(secCallback)
+						.withMode(Mode.VIEW)
+						.build();
+				showWarning("editor.warning.locked");
+			} else {
+				onlyOfficeService.lock(vfsLeaf, getIdentity());
+			}
+		}
 		VelocityContainer mainVC = createVelocityContainer("editor");
 		
 		VFSMetadata vfsMetadata = vfsLeaf.getMetaInfo();
@@ -59,7 +75,7 @@ public class OnlyOfficeEditorController extends BasicController {
 			mainVC.contextPut("warning", translate("editor.warning.no.metadata"));
 		} else {
 			String apiConfig = ApiConfigBuilder.builder(vfsMetadata, getIdentity())
-					.withEdit(Mode.EDIT.equals(securityCallback.getMode()))
+					.withEdit(Mode.EDIT.equals(secCallback.getMode()))
 					.buildJson();
 			log.debug("OnlyOffice ApiConfig: " + apiConfig);