mirror of
https://bitbucket.org/wisemapping/wisemapping-open-source.git
synced 2024-11-22 14:17:57 +01:00
Edition lock is working. Working on user interation.
This commit is contained in:
parent
04d43e62c7
commit
6303ba93c7
@ -18,14 +18,19 @@
|
||||
|
||||
mindplot.RESTPersistenceManager = new Class({
|
||||
Extends:mindplot.PersistenceManager,
|
||||
initialize:function (saveUrl, revertUrl, lockUrl) {
|
||||
initialize:function (options) {
|
||||
this.parent();
|
||||
$assert(saveUrl, "saveUrl can not be null");
|
||||
$assert(revertUrl, "revertUrl can not be null");
|
||||
this.saveUrl = saveUrl;
|
||||
this.revertUrl = revertUrl;
|
||||
this.lockUrl = lockUrl;
|
||||
this.timestamp = null;
|
||||
$assert(options.saveUrl, "saveUrl can not be null");
|
||||
$assert(options.revertUrl, "revertUrl can not be null");
|
||||
$assert(options.lockUrl, "lockUrl can not be null");
|
||||
$assert(options.session, "session can not be null");
|
||||
$assert(options.timestamp, "timestamp can not be null");
|
||||
|
||||
this.saveUrl = options.saveUrl;
|
||||
this.revertUrl = options.revertUrl;
|
||||
this.lockUrl = options.lockUrl;
|
||||
this.timestamp = options.timestamp;
|
||||
this.session = options.session;
|
||||
},
|
||||
|
||||
saveMapXml:function (mapId, mapXml, pref, saveHistory, events, sync) {
|
||||
@ -39,6 +44,7 @@ mindplot.RESTPersistenceManager = new Class({
|
||||
var persistence = this;
|
||||
var query = "minor=" + !saveHistory;
|
||||
query = query + (this.timestamp ? "×tamp=" + this.timestamp : "");
|
||||
query = query + (this.session ? "&session=" + this.session : "");
|
||||
|
||||
var request = new Request({
|
||||
url:this.saveUrl.replace("{id}", mapId) + "?" + query,
|
||||
|
83
mindplot/src/main/javascript/widget/ErrorNotifier.js
Normal file
83
mindplot/src/main/javascript/widget/ErrorNotifier.js
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright [2011] [wisemapping]
|
||||
*
|
||||
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
|
||||
* It is basically the Apache License, Version 2.0 (the "License") plus the
|
||||
* "powered by wisemapping" text requirement on every single page;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the license at
|
||||
*
|
||||
* http://www.wisemapping.org/license
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
mindplot.widget.ToolbarNotifier = new Class({
|
||||
|
||||
initialize:function () {
|
||||
var container = $('headerNotifier');
|
||||
// In case of print,embedded no message is displayed ....
|
||||
if (container) {
|
||||
this._effect = new Fx.Elements(container, {
|
||||
onComplete:function () {
|
||||
container.setStyle('display', 'none');
|
||||
}.bind(this),
|
||||
link:'cancel',
|
||||
duration:8000,
|
||||
transition:Fx.Transitions.Expo.easeInOut
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
logError:function (userMsg) {
|
||||
this.logMessage(userMsg, mindplot.widget.ToolbarNotifier.MsgKind.ERROR);
|
||||
},
|
||||
|
||||
hide:function () {
|
||||
|
||||
},
|
||||
|
||||
logMessage:function (msg, fade) {
|
||||
$assert(msg, 'msg can not be null');
|
||||
|
||||
var container = $('headerNotifier');
|
||||
|
||||
// In case of print,embedded no message is displayed ....
|
||||
if (container) {
|
||||
container.set('text', msg);
|
||||
container.setStyle('display', 'block');
|
||||
container.position({
|
||||
relativeTo:$('header'),
|
||||
position:'upperCenter',
|
||||
edge:'centerTop'
|
||||
});
|
||||
|
||||
if (!$defined(fade) || fade) {
|
||||
this._effect.start({
|
||||
0:{
|
||||
opacity:[1, 0]
|
||||
}
|
||||
});
|
||||
|
||||
} else {
|
||||
container.setStyle('opacity', '1');
|
||||
this._effect.pause();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
mindplot.widget.ToolbarNotifier.MsgKind = {
|
||||
INFO:1,
|
||||
WARNING:2,
|
||||
ERROR:3,
|
||||
FATAL:4
|
||||
};
|
||||
|
||||
var toolbarNotifier = new mindplot.widget.ToolbarNotifier();
|
||||
$notify = toolbarNotifier.logMessage.bind(toolbarNotifier);
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright [2011] [wisemapping]
|
||||
*
|
||||
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
|
||||
* It is basically the Apache License, Version 2.0 (the "License") plus the
|
||||
* "powered by wisemapping" text requirement on every single page;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the license at
|
||||
*
|
||||
* http://www.wisemapping.org/license
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.wisemapping.exceptions;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class EditionSessionExpiredException
|
||||
extends ClientException
|
||||
{
|
||||
public static final String MSG_KEY = "MINDMAP_TIMESTAMP_OUTDATED";
|
||||
|
||||
public EditionSessionExpiredException(@NotNull String msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected String getMsgBundleKey() {
|
||||
return MSG_KEY;
|
||||
}
|
||||
}
|
@ -20,12 +20,12 @@ package com.wisemapping.exceptions;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class MindmapOutdatedException
|
||||
public class MultipleSessionsOpenException
|
||||
extends ClientException
|
||||
{
|
||||
public static final String MSG_KEY = "MINDMAP_TIMESTAMP_OUTDATED";
|
||||
|
||||
public MindmapOutdatedException(@NotNull String msg)
|
||||
public MultipleSessionsOpenException(@NotNull String msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright [2011] [wisemapping]
|
||||
*
|
||||
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
|
||||
* It is basically the Apache License, Version 2.0 (the "License") plus the
|
||||
* "powered by wisemapping" text requirement on every single page;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the license at
|
||||
*
|
||||
* http://www.wisemapping.org/license
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.wisemapping.exceptions;
|
||||
|
||||
import com.wisemapping.model.Collaborator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class SessionExpiredException
|
||||
extends ClientException
|
||||
{
|
||||
public static final String MSG_KEY = "MINDMAP_TIMESTAMP_OUTDATED";
|
||||
|
||||
public SessionExpiredException(@NotNull String msg,@NotNull Collaborator newEditor)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected String getMsgBundleKey() {
|
||||
return MSG_KEY;
|
||||
}
|
||||
}
|
@ -27,6 +27,7 @@ import com.wisemapping.model.Mindmap;
|
||||
import com.wisemapping.model.MindMapHistory;
|
||||
import com.wisemapping.model.User;
|
||||
import com.wisemapping.security.Utils;
|
||||
import com.wisemapping.service.LockInfo;
|
||||
import com.wisemapping.service.LockManager;
|
||||
import com.wisemapping.service.MindmapService;
|
||||
import com.wisemapping.view.MindMapBean;
|
||||
@ -147,7 +148,7 @@ public class MindmapController {
|
||||
return showEditorPage(id, model, true);
|
||||
}
|
||||
|
||||
private String showEditorPage(int id, @NotNull final Model model, boolean requiresLock) throws AccessDeniedSecurityException, LockException {
|
||||
private String showEditorPage(int id, @NotNull final Model model, boolean requiresLock) throws WiseMappingException {
|
||||
final MindMapBean mindmapBean = findMindmapBean(id);
|
||||
final Mindmap mindmap = mindmapBean.getDelegated();
|
||||
final User collaborator = Utils.getUser();
|
||||
@ -159,10 +160,13 @@ public class MindmapController {
|
||||
final LockManager lockManager = this.mindmapService.getLockManager();
|
||||
if (lockManager.isLocked(mindmap) && !lockManager.isLockedBy(mindmap, collaborator)) {
|
||||
readOnlyMode = true;
|
||||
model.addAttribute("lockedBy", lockManager.getLockInfo(mindmap));
|
||||
} else {
|
||||
lockManager.lock(mindmap, collaborator);
|
||||
final long session = lockManager.generateSession();
|
||||
final LockInfo lock = lockManager.lock(mindmap, collaborator, session);
|
||||
model.addAttribute("lockTimestamp", lock.getTimestamp());
|
||||
model.addAttribute("lockSession", session);
|
||||
}
|
||||
model.addAttribute("lockInfo", lockManager.getLockInfo(mindmap));
|
||||
}
|
||||
|
||||
// Set render attributes ...
|
||||
@ -176,12 +180,12 @@ public class MindmapController {
|
||||
}
|
||||
|
||||
@RequestMapping(value = "maps/{id}/view", method = RequestMethod.GET)
|
||||
public String showMindmapViewerPage(@PathVariable int id, @NotNull Model model) throws LockException, AccessDeniedSecurityException {
|
||||
public String showMindmapViewerPage(@PathVariable int id, @NotNull Model model) throws WiseMappingException {
|
||||
return showEditorPage(id, model, false);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "maps/{id}/try", method = RequestMethod.GET)
|
||||
public String showMindmapTryPage(@PathVariable int id, @NotNull Model model) throws LockException, AccessDeniedSecurityException {
|
||||
public String showMindmapTryPage(@PathVariable int id, @NotNull Model model) throws WiseMappingException {
|
||||
final String result = showEditorPage(id, model, false);
|
||||
model.addAttribute("memoryPersistence", true);
|
||||
return result;
|
||||
|
@ -19,9 +19,7 @@
|
||||
package com.wisemapping.rest;
|
||||
|
||||
|
||||
import com.wisemapping.exceptions.ImportUnexpectedException;
|
||||
import com.wisemapping.exceptions.MindmapOutdatedException;
|
||||
import com.wisemapping.exceptions.WiseMappingException;
|
||||
import com.wisemapping.exceptions.*;
|
||||
import com.wisemapping.importer.ImportFormat;
|
||||
import com.wisemapping.importer.Importer;
|
||||
import com.wisemapping.importer.ImporterException;
|
||||
@ -30,10 +28,10 @@ import com.wisemapping.model.*;
|
||||
import com.wisemapping.rest.model.*;
|
||||
import com.wisemapping.security.Utils;
|
||||
import com.wisemapping.service.CollaborationException;
|
||||
import com.wisemapping.service.LockInfo;
|
||||
import com.wisemapping.service.LockManager;
|
||||
import com.wisemapping.service.MindmapService;
|
||||
import com.wisemapping.validator.MapInfoValidator;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
@ -141,7 +139,7 @@ public class MindmapController extends BaseController {
|
||||
|
||||
@RequestMapping(method = RequestMethod.PUT, value = "/maps/{id}/document", consumes = {"application/xml", "application/json"}, produces = {"application/json", "text/html", "application/xml"})
|
||||
@ResponseBody
|
||||
public long updateDocument(@RequestBody RestMindmap restMindmap, @PathVariable int id, @RequestParam(required = false) boolean minor, @RequestParam(required = false) Long timestamp) throws WiseMappingException, IOException {
|
||||
public long updateDocument(@RequestBody RestMindmap restMindmap, @PathVariable int id, @RequestParam(required = false) boolean minor, @RequestParam(required = false) Long timestamp, @RequestParam(required = false) Long session) throws WiseMappingException, IOException {
|
||||
|
||||
final Mindmap mindmap = mindmapService.findMindmapById(id);
|
||||
final User user = Utils.getUser();
|
||||
@ -152,10 +150,8 @@ public class MindmapController extends BaseController {
|
||||
throw new IllegalArgumentException("Map properties can not be null");
|
||||
}
|
||||
|
||||
// Check that there we are not overwriting an already existing map ...
|
||||
if (timestamp != null && mindmap.getLastModificationTime().getTimeInMillis() > timestamp) {
|
||||
throw new MindmapOutdatedException("Mindmap timestamp out of sync. Client timestamp: " + timestamp + ", DB Timestamp:" + timestamp);
|
||||
}
|
||||
// Could the map be updated ?
|
||||
checkUpdate(mindmap, user, session, timestamp);
|
||||
|
||||
// Update collaboration properties ...
|
||||
final CollaborationProperties collaborationProperties = mindmap.findCollaborationProperties(user);
|
||||
@ -172,8 +168,36 @@ public class MindmapController extends BaseController {
|
||||
logger.debug("Mindmap save completed:" + restMindmap.getXml());
|
||||
saveMindmap(minor, mindmap, user);
|
||||
|
||||
// Return last update timestamp ...
|
||||
return mindmap.getLastModificationTime().getTimeInMillis();
|
||||
// Update edition timeout ...
|
||||
final LockManager lockManager = mindmapService.getLockManager();
|
||||
final LockInfo lockInfo = lockManager.updateExpirationTimeout(mindmap, user, session);
|
||||
return lockInfo.getTimestamp();
|
||||
}
|
||||
|
||||
private void checkUpdate(@NotNull Mindmap mindmap, @NotNull User user, long session, long timestamp) throws WiseMappingException {
|
||||
// The lock was lost, reclaim as the ownership of it.
|
||||
final LockManager lockManager = mindmapService.getLockManager();
|
||||
final boolean lockLost = lockManager.isLocked(mindmap);
|
||||
if (!lockLost) {
|
||||
lockManager.lock(mindmap, user, session);
|
||||
}
|
||||
|
||||
final LockInfo lockInfo = lockManager.getLockInfo(mindmap);
|
||||
if (lockInfo.getCollaborator().equals(user)) {
|
||||
final boolean outdated = mindmap.getLastModificationTime().getTimeInMillis() > timestamp;
|
||||
if (lockInfo.getSession() == session) {
|
||||
// Timestamp might not be returned to the client. This try to cover this case, ignoring the client timestamp check.
|
||||
final User lastEditor = mindmap.getLastEditor();
|
||||
if (outdated && (lockInfo.getPreviousTimestamp() != timestamp || lastEditor == null || !lastEditor.equals(user))) {
|
||||
throw new MultipleSessionsOpenException("The map has been updated and not by you. Session lost.");
|
||||
}
|
||||
} else if (outdated) {
|
||||
throw new MultipleSessionsOpenException("The map has been updated and not by you. Session lost.");
|
||||
}
|
||||
} else {
|
||||
throw new SessionExpiredException("You have lost the edition session", lockInfo.getCollaborator());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -361,7 +385,13 @@ public class MindmapController extends BaseController {
|
||||
final User user = Utils.getUser();
|
||||
final LockManager lockManager = mindmapService.getLockManager();
|
||||
final Mindmap mindmap = mindmapService.findMindmapById(id);
|
||||
lockManager.updateLock(Boolean.parseBoolean(value), mindmap, user);
|
||||
|
||||
final boolean lock = Boolean.parseBoolean(value);
|
||||
if (!lock) {
|
||||
lockManager.unlock(mindmap, user);
|
||||
} else {
|
||||
throw new UnsupportedOperationException("REST lock must be implemented.");
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.DELETE, value = "/maps/batch")
|
||||
|
@ -24,14 +24,23 @@ import java.util.Set;
|
||||
getterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY,
|
||||
isGetterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class RestMindmapLock {
|
||||
public class RestLockInfo {
|
||||
|
||||
@NotNull
|
||||
private Collaborator user;
|
||||
@Nullable
|
||||
private LockInfo lockInfo;
|
||||
final private Collaborator user;
|
||||
|
||||
public RestMindmapLock(@Nullable LockInfo lockInfo, @NotNull Collaborator collaborator) {
|
||||
@Nullable
|
||||
final private LockInfo lockInfo;
|
||||
|
||||
// This is required only for compliance with the JAXB serializer.
|
||||
public RestLockInfo(){
|
||||
|
||||
this.lockInfo = null;
|
||||
//noinspection ConstantConditions
|
||||
this.user = null;
|
||||
}
|
||||
|
||||
public RestLockInfo(@Nullable LockInfo lockInfo, @NotNull Collaborator collaborator) {
|
||||
|
||||
this.lockInfo = lockInfo;
|
||||
this.user = collaborator;
|
||||
@ -52,4 +61,13 @@ public class RestMindmapLock {
|
||||
public void setLockedByMe(boolean lockedForMe) {
|
||||
// Ignore ...
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return lockInfo != null ? lockInfo.getTimestamp() : -1;
|
||||
}
|
||||
|
||||
public void setTimestamp(long value) {
|
||||
//
|
||||
}
|
||||
|
||||
}
|
@ -19,6 +19,7 @@
|
||||
package com.wisemapping.service;
|
||||
|
||||
import com.wisemapping.model.Collaborator;
|
||||
import com.wisemapping.model.Mindmap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Calendar;
|
||||
@ -26,11 +27,15 @@ import java.util.Calendar;
|
||||
public class LockInfo {
|
||||
final private Collaborator collaborator;
|
||||
private Calendar timeout;
|
||||
private static int EXPIRATION_MIN = 25;
|
||||
private long session;
|
||||
private static int EXPIRATION_MIN = 30;
|
||||
private long timestamp = -1;
|
||||
private long previousTimestamp;
|
||||
|
||||
public LockInfo(@NotNull Collaborator collaborator) {
|
||||
public LockInfo(@NotNull Collaborator collaborator, @NotNull Mindmap mindmap, long session) {
|
||||
this.collaborator = collaborator;
|
||||
this.updateTimeout();
|
||||
this.updateTimestamp(mindmap);
|
||||
}
|
||||
|
||||
public Collaborator getCollaborator() {
|
||||
@ -47,4 +52,25 @@ public class LockInfo {
|
||||
this.timeout = calendar;
|
||||
|
||||
}
|
||||
|
||||
public long getSession() {
|
||||
return session;
|
||||
}
|
||||
|
||||
public void setSession(long session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public long getPreviousTimestamp() {
|
||||
return previousTimestamp;
|
||||
}
|
||||
|
||||
public void updateTimestamp(@NotNull Mindmap mindmap) {
|
||||
this.previousTimestamp = this.timestamp;
|
||||
this.timestamp = mindmap.getLastModificationTime().getTimeInMillis();
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
package com.wisemapping.service;
|
||||
|
||||
import com.wisemapping.exceptions.AccessDeniedSecurityException;
|
||||
import com.wisemapping.exceptions.ClientException;
|
||||
import com.wisemapping.exceptions.LockException;
|
||||
import com.wisemapping.exceptions.WiseMappingException;
|
||||
import com.wisemapping.model.Collaborator;
|
||||
@ -31,13 +32,13 @@ public interface LockManager {
|
||||
|
||||
LockInfo getLockInfo(@NotNull Mindmap mindmap);
|
||||
|
||||
void updateExpirationTimeout(@NotNull Mindmap mindmap, @NotNull Collaborator user);
|
||||
LockInfo updateExpirationTimeout(@NotNull Mindmap mindmap, @NotNull Collaborator user,long session);
|
||||
|
||||
void unlock(@NotNull Mindmap mindmap, @NotNull Collaborator user) throws LockException, AccessDeniedSecurityException;
|
||||
|
||||
boolean isLockedBy(@NotNull Mindmap mindmap, @NotNull Collaborator collaborator);
|
||||
|
||||
void lock(@NotNull Mindmap mindmap, @NotNull Collaborator user) throws AccessDeniedSecurityException, LockException;
|
||||
LockInfo lock(@NotNull Mindmap mindmap, @NotNull Collaborator user, long session) throws WiseMappingException;
|
||||
|
||||
void updateLock(boolean value, Mindmap mindmap, User user) throws WiseMappingException;
|
||||
long generateSession();
|
||||
}
|
||||
|
@ -24,7 +24,6 @@ import com.wisemapping.exceptions.WiseMappingException;
|
||||
import com.wisemapping.model.CollaborationRole;
|
||||
import com.wisemapping.model.Collaborator;
|
||||
import com.wisemapping.model.Mindmap;
|
||||
import com.wisemapping.model.User;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@ -36,6 +35,15 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
* En caso que no sea posible grabar por que se perdio el lock, usar mensaje de error para explicar el por que...
|
||||
* Mensaje modal explicando que el mapa esta siendo editado, por eso no es posible edilarlo....
|
||||
* Internacionalizacion de los mensaje ...
|
||||
* Logout limpiar las sessiones ...
|
||||
*
|
||||
* Casos:
|
||||
* - Usuario pierde el lock:
|
||||
* - Y grabo con la misma sessions y el timestap ok.
|
||||
* - Y grabo con la misma session y el timestap esta mal
|
||||
* - Y grabo con distinta sessions
|
||||
* -
|
||||
* - Usuario pierde el lock, pero intenta grabar camio
|
||||
*/
|
||||
|
||||
class LockManagerImpl implements LockManager {
|
||||
@ -44,30 +52,6 @@ class LockManagerImpl implements LockManager {
|
||||
final static Timer expirationTimer = new Timer();
|
||||
final private static Logger logger = Logger.getLogger("com.wisemapping.service.LockManager");
|
||||
|
||||
public LockManagerImpl() {
|
||||
lockInfoByMapId = new ConcurrentHashMap<Integer, LockInfo>();
|
||||
expirationTimer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
logger.debug("Lock expiration scheduler started. Current locks:" + lockInfoByMapId.keySet());
|
||||
|
||||
final List<Integer> toRemove = new ArrayList<Integer>();
|
||||
final Set<Integer> mapIds = lockInfoByMapId.keySet();
|
||||
for (Integer mapId : mapIds) {
|
||||
final LockInfo lockInfo = lockInfoByMapId.get(mapId);
|
||||
if (lockInfo.isExpired()) {
|
||||
toRemove.add(mapId);
|
||||
}
|
||||
}
|
||||
|
||||
for (Integer mapId : toRemove) {
|
||||
unlock(mapId);
|
||||
}
|
||||
}
|
||||
}, ONE_MINUTE_MILLISECONDS, ONE_MINUTE_MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLocked(@NotNull Mindmap mindmap) {
|
||||
return this.getLockInfo(mindmap) != null;
|
||||
@ -79,18 +63,21 @@ class LockManagerImpl implements LockManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateExpirationTimeout(@NotNull Mindmap mindmap, @NotNull Collaborator user) {
|
||||
if (this.isLocked(mindmap)) {
|
||||
final LockInfo lockInfo = this.getLockInfo(mindmap);
|
||||
if (!lockInfo.getCollaborator().equals(user)) {
|
||||
throw new IllegalStateException("Could not update map lock timeout if you are not the locking user. User:" + lockInfo.getCollaborator() + ", " + user);
|
||||
}
|
||||
lockInfo.updateTimeout();
|
||||
logger.debug("Timeout updated for:" + mindmap.getId());
|
||||
|
||||
}else {
|
||||
public LockInfo updateExpirationTimeout(@NotNull Mindmap mindmap, @NotNull Collaborator user, long session) {
|
||||
if (!this.isLocked(mindmap)) {
|
||||
throw new IllegalStateException("Lock lost for map. No update possible.");
|
||||
}
|
||||
|
||||
final LockInfo result = this.getLockInfo(mindmap);
|
||||
if (!result.getCollaborator().equals(user)) {
|
||||
throw new IllegalStateException("Could not update map lock timeout if you are not the locking user. User:" + result.getCollaborator() + ", " + user);
|
||||
}
|
||||
|
||||
result.updateTimeout();
|
||||
result.setSession(session);
|
||||
result.updateTimestamp(mindmap);
|
||||
logger.debug("Timeout updated for:" + mindmap.getId());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -122,7 +109,8 @@ class LockManagerImpl implements LockManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lock(@NotNull Mindmap mindmap, @NotNull Collaborator user) throws AccessDeniedSecurityException, LockException {
|
||||
@NotNull
|
||||
public LockInfo lock(@NotNull Mindmap mindmap, @NotNull Collaborator user, long session) throws WiseMappingException {
|
||||
if (isLocked(mindmap) && !isLockedBy(mindmap, user)) {
|
||||
throw new LockException("Invalid lock, this should not happen");
|
||||
}
|
||||
@ -131,24 +119,46 @@ class LockManagerImpl implements LockManager {
|
||||
throw new AccessDeniedSecurityException("Invalid lock, this should not happen");
|
||||
}
|
||||
|
||||
final LockInfo lockInfo = lockInfoByMapId.get(mindmap.getId());
|
||||
if (lockInfo != null) {
|
||||
LockInfo result = lockInfoByMapId.get(mindmap.getId());
|
||||
if (result != null) {
|
||||
// Update timeout only...
|
||||
logger.debug("Update timestamp:" + mindmap.getId());
|
||||
updateExpirationTimeout(mindmap, user);
|
||||
updateExpirationTimeout(mindmap, user, session);
|
||||
} else {
|
||||
logger.debug("Lock map id:" + mindmap.getId());
|
||||
lockInfoByMapId.put(mindmap.getId(), new LockInfo(user));
|
||||
result = new LockInfo(user, mindmap, session);
|
||||
lockInfoByMapId.put(mindmap.getId(), result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLock(boolean lock, @NotNull Mindmap mindmap, @NotNull User user) throws WiseMappingException {
|
||||
if (lock) {
|
||||
this.lock(mindmap, user);
|
||||
} else {
|
||||
this.unlock(mindmap, user);
|
||||
public long generateSession() {
|
||||
return System.nanoTime();
|
||||
}
|
||||
|
||||
public LockManagerImpl() {
|
||||
lockInfoByMapId = new ConcurrentHashMap<Integer, LockInfo>();
|
||||
expirationTimer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
logger.debug("Lock expiration scheduler started. Current locks:" + lockInfoByMapId.keySet());
|
||||
|
||||
final List<Integer> toRemove = new ArrayList<Integer>();
|
||||
final Set<Integer> mapIds = lockInfoByMapId.keySet();
|
||||
for (Integer mapId : mapIds) {
|
||||
final LockInfo lockInfo = lockInfoByMapId.get(mapId);
|
||||
if (lockInfo.isExpired()) {
|
||||
toRemove.add(mapId);
|
||||
}
|
||||
}
|
||||
|
||||
for (Integer mapId : toRemove) {
|
||||
unlock(mapId);
|
||||
}
|
||||
}
|
||||
}, ONE_MINUTE_MILLISECONDS, ONE_MINUTE_MILLISECONDS);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -100,10 +100,6 @@ public class MindmapServiceImpl
|
||||
throw new WiseMappingException("The tile can not be empty");
|
||||
}
|
||||
|
||||
// Update edition timeout ...
|
||||
final LockManager lockManager = this.getLockManager();
|
||||
lockManager.updateExpirationTimeout(mindMap, Utils.getUser());
|
||||
|
||||
mindmapManager.updateMindmap(mindMap, saveHistory);
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,7 @@
|
||||
<value>com.wisemapping.rest.model.RestCollaboration</value>
|
||||
<value>com.wisemapping.rest.model.RestCollaborationList</value>
|
||||
<value>com.wisemapping.rest.model.RestLogItem</value>
|
||||
<value>com.wisemapping.rest.model.RestLockInfo</value>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
@ -34,8 +34,16 @@
|
||||
|
||||
// Configure designer options ...
|
||||
var options = loadDesignerOptions();
|
||||
<c:if test="${!memoryPersistence}">
|
||||
options.persistenceManager = new mindplot.RESTPersistenceManager("service/maps/{id}/document", "service/maps/{id}/history/latest","service/maps/{id}/lock");
|
||||
<c:if test="${!memoryPersistence && !readOnlyMode}">
|
||||
options.persistenceManager = new mindplot.RESTPersistenceManager(
|
||||
{
|
||||
saveUrl:"service/maps/{id}/document",
|
||||
revertUrl:"service/maps/{id}/history/latest",
|
||||
lockUrl:"service/maps/{id}/lock",
|
||||
timestamp: ${lockTimestamp},
|
||||
session: ${lockSession}
|
||||
}
|
||||
);
|
||||
</c:if>
|
||||
var userOptions = ${mindmap.properties};
|
||||
options.zoom = userOptions.zoom;
|
||||
|
Loading…
Reference in New Issue
Block a user