/* license-start * * Copyright (C) 2008 - 2013 Crispico, <http://www.crispico.com/>. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details, at <http://www.gnu.org/licenses/>. * * Contributors: * Crispico - Initial API and implementation * * license-end */ package org.flowerplatform.editor; import java.security.AccessControlContext; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Calendar; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import org.flowerplatform.editor.remote.EditableResource; import org.flowerplatform.editor.remote.EditableResourceClient; import org.flowerplatform.editor.remote.EditorStatefulService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This is a runnable scheduled at a specified time to unlock a resource. * If the {@link EditableResource#getLockExpireTime()} is greater than the current time, * then runnable is rescheduled (because this means that the client renewed the lock * while this runnable was waiting). * * @author Florin * @author Cristi * */ public class UnlockEditableResourceRunnable implements Runnable { /** * */ private static final Logger logger = LoggerFactory.getLogger(UnlockEditableResourceRunnable.class); /** * */ private Object editorInput; /** * */ private EditableResourceClient lockOwner; /** * Initial security context. * * */ private AccessControlContext context; /** * * TODO CS/STFL cred ca atunci cand vom muta runnable-ul in ac. pachet, va avea acces la ac. camp prin serviciu direct */ private ScheduledExecutorService parentScheduler; private EditorStatefulService editorStatefulService; /** * * @param editorStatefulService TODO */ public UnlockEditableResourceRunnable(EditorStatefulService editorStatefulService, Object editorInput, EditableResourceClient lockOwner, ScheduledExecutorService parentScheduler) { this.editorStatefulService = editorStatefulService; this.editorInput = editorInput; this.lockOwner = lockOwner; context = AccessController.getContext(); this.parentScheduler = parentScheduler; } /** * */ @Override public void run() { AccessController.doPrivileged(new PrivilegedAction<Void>() { @Override public Void run() { runWithInitialSecurityContext(); return null; } }, context); } /** * */ public void runWithInitialSecurityContext() { // the try block is for the lock but for catching & logging exceptions as well try { EditableResource editableResource; // TODO CS/STFL de scapat de .toString(); de asemenea de scapat si de if-ul si codul legacy de mai sus editorStatefulService.namedLockPool.lock(editorInput.toString()); editableResource = editorStatefulService.editableResources.get(editorInput.toString()); if (editableResource == null) { logger.trace("Unlock timer expired, but EditableResource is gone. For Editable Resource with editorInput = {}, client = {}", editorInput, lockOwner.getCommunicationChannel()); // the last client disconnected before the lock expired so there is no resource entry no more return; } // if the resource is still locked and the lock owner did not change if (editableResource.isLocked() && lockOwner.equals(editableResource.getLockOwner())) { // lock expire time might have changed, let's check editableResource.getLockExpireTime(); Calendar now = Calendar.getInstance(); // if lockExpireTime <= now if (editableResource.getLockExpireTime().getTime() <= now.getTimeInMillis()) { logger.trace("Unlock timer expired; unlocking...; for Editable Resource with editorInput = {}, client = {}", editorInput, lockOwner.getCommunicationChannel()); editorStatefulService.unlock(editableResource, lockOwner); editorStatefulService.dispatchEditableResourceStatus(editableResource); } else { long delay = editableResource.getLockExpireTime().getTime() - now.getTimeInMillis(); parentScheduler.schedule(this, delay, TimeUnit.MILLISECONDS); if (logger.isTraceEnabled()) { logger.trace("Unlock timer expired but was rescheduled; for Editable Resource with editorInput = {}, client = {}. Lock expires = {} and now = {} => it will run again in {} ms", new Object[] { editorInput, lockOwner.getCommunicationChannel(), editableResource.getLockExpireTime(), now.getTime(), delay}); } } } else { if (logger.isTraceEnabled()) { logger.trace("Unlock timer exprired but won't unlock, for Editable Resource with editorInput = {}, client = {}. The resource isLocked = {} by client = {}", new Object[] { editableResource.getEditorInput(), lockOwner.getCommunicationChannel(), editableResource.isLocked(), editableResource.getLockOwner().getCommunicationChannel() } ); } } } catch (Throwable t) { // log here, because it doesn't get caught by the main app logger.error("Exception caught in scheduled runnable.", t); throw new RuntimeException(t); } finally { // TODO CS/STFL de scapat de .toString(); de asemenea de scapat si de if-ul si codul legacy de mai sus editorStatefulService.namedLockPool.unlock(editorInput.toString()); } } }