Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
Copyright (C) 2014 Philip Helger (www.helger.com) philip[at]helger[dot]com Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
 
 package com.helger.appbasics.security.lock;
 
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
 
 
Default implementation of a locking manager.

Parameters:
<IDTYPE> The type of object to be locked. E.g. String or TypedObject. Must implement equals and hashCode!
Author(s):
Philip Helger
 
 public class DefaultLockManager <IDTYPE> implements ILockManager <IDTYPE>
 {
   private static final Logger s_aLogger = LoggerFactory.getLogger (DefaultLockManager.class);
 
   private final ReadWriteLock m_aRWLock = new ReentrantReadWriteLock ();
   @GuardedBy ("m_aRWLock")
 
   // Key: lockedObjectID, value: lock-info
   private final Map <IDTYPE, ILockInfom_aLockedObjs = new HashMap <IDTYPE, ILockInfo> ();
 
   public DefaultLockManager (@Nonnull final ICurrentUserIDProvider aCurrentUserIDProvider)
   {
     setCurrentUserIDProvider (aCurrentUserIDProvider);
   }
 
   public final void setCurrentUserIDProvider (@Nonnull final ICurrentUserIDProvider aCurrentUserIDProvider)
   {
     .writeLock ().lock ();
     try
     {
        = ValueEnforcer.notNull (aCurrentUserIDProvider"CurrentUserIDProvider");
     }
     finally
     {
       .writeLock ().unlock ();
     }
   }
 
   @Nullable
   private String _getCurrentUserID ()
   {
     .readLock ().lock ();
     try
     {
       return .getCurrentUserID ();
     }
     finally
     {
       .readLock ().unlock ();
     }
   }
 
  public final ILockInfo getLockInfo (@Nullable final IDTYPE aObjID)
  {
    .readLock ().lock ();
    try
    {
      return .get (aObjID);
    }
    finally
    {
      .readLock ().unlock ();
    }
  }
  public final String getLockUserID (@Nullable final IDTYPE aObjID)
  {
    final ILockInfo aLock = getLockInfo (aObjID);
    return aLock != null ? aLock.getLockUserID () : null;
  }
  public final DateTime getLockDateTime (@Nullable final IDTYPE aObjID)
  {
    final ILockInfo aLock = getLockInfo (aObjID);
    return aLock != null ? aLock.getLockDateTime () : null;
  }
  public final ELocked lockObject (@Nonnull final IDTYPE aObjID)
  {
    ValueEnforcer.notNull (aObjID"ObjectID");
    final String sCurrentUserID = _getCurrentUserID ();
    return lockObject (aObjIDsCurrentUserID);
  }
  private LockResult <IDTYPE> _lockObjectAndUnlockOthers (@Nonnull final IDTYPE aObjID,
                                                          @Nullable final String sUserID,
                                                          final boolean bUnlockOtherObjects)
  {
    if (StringHelper.hasNoText (sUserID))
      return LockResult.createFailure (aObjID);
    ELocked eLocked;
    boolean bIsNewLock = false;
    List <IDTYPE> aUnlockedObjects = null;
    .writeLock ().lock ();
    try
    {
      if (bUnlockOtherObjects)
      {
        // Unlock other objects first
        aUnlockedObjects = new ArrayList <IDTYPE> ();
        // Unlock all except the object to be locked
        _unlockAllObjects (sUserID, ContainerHelper.newSet (aObjID), aUnlockedObjects);
      }
      final ILockInfo aCurrentLock = .get (aObjID);
      if (aCurrentLock != null)
      {
        // Object is already locked.
        // Check whether the current user locked the object
        eLocked = ELocked.valueOf (aCurrentLock.getLockUserID ().equals (sUserID));
      }
      else
      {
        // Object is not locked so far - lock it now!
        .put (aObjIDnew LockInfo (sUserID));
        eLocked = .;
        bIsNewLock = true;
      }
    }
    finally
    {
      .writeLock ().unlock ();
    }
    if (.isInfoEnabled ())
    {
      if (ContainerHelper.isNotEmpty (aUnlockedObjects))
        .info ("Before locking, unlocked all objects of user '" +
                        sUserID +
                        "': " +
                        aUnlockedObjects +
                        " except '" +
                        aObjID +
                        "'");
      if (bIsNewLock)
        .info ("User '" + sUserID + "' locked object '" + aObjID + "'");
    }
    return new LockResult <IDTYPE> (aObjIDeLockedbIsNewLockaUnlockedObjects);
  }
  public final ELocked lockObject (@Nonnull final IDTYPE aObjID, @Nullable final String sUserID)
  {
    ValueEnforcer.notNull (aObjID"ObjectID");
    // Don't unlock other objects
    final LockResult <IDTYPE> aLockResult = _lockObjectAndUnlockOthers (aObjIDsUserIDfalse);
    return ELocked.valueOf (aLockResult);
  }
  public final LockResult <IDTYPE> lockObjectAndUnlockAllOthers (@Nonnull final IDTYPE aObjID)
  {
    ValueEnforcer.notNull (aObjID"ObjectID");
    final String sCurrentUserID = _getCurrentUserID ();
    return lockObjectAndUnlockAllOthers (aObjIDsCurrentUserID);
  }
  public final LockResult <IDTYPE> lockObjectAndUnlockAllOthers (@Nonnull final IDTYPE aObjID,
                                                                 @Nullable final String sUserID)
  {
    ValueEnforcer.notNull (aObjID"ObjectID");
    // Unlock other objects
    return _lockObjectAndUnlockOthers (aObjIDsUserIDtrue);
  }
  public final EChange unlockObject (@Nonnull final IDTYPE aObjID)
  {
    final String sCurrentUserID = _getCurrentUserID ();
    if (StringHelper.hasNoText (sCurrentUserID))
      return .;
    return unlockObject (sCurrentUserIDaObjID);
  }
  public final EChange unlockObject (@Nonnull final String sUserID, @Nonnull final IDTYPE aObjID)
  {
    ValueEnforcer.notNull (sUserID"UserID");
    ValueEnforcer.notNull (aObjID"ObjectID");
    // Get the locking information of the objects
    final ILockInfo aCurrentLock = getLockInfo (aObjID);
    if (aCurrentLock == null)
    {
      // Object is not locked at all
      .warn ("User '" + sUserID + "' could not unlock object '" + aObjID + "' because it is not locked");
      return .;
    }
    // Not locked by current user?
    if (!aCurrentLock.getLockUserID ().equals (sUserID))
    {
      // This may happen if the user was manually unlocked!
      .warn ("User '" +
                      sUserID +
                      "' could not unlock object '" +
                      aObjID +
                      "' because it is locked by '" +
                      aCurrentLock.getLockUserID () +
                      "'");
      return .;
    }
    .writeLock ().lock ();
    try
    {
      // this user locked the object -> unlock it
      if (.remove (aObjID) == null)
        throw new IllegalStateException ("Internal inconsistency: removing '" + aObjID + "' from lock list failed!");
    }
    finally
    {
      .writeLock ().unlock ();
    }
    if (.isInfoEnabled ())
      .info ("User '" + sUserID + "' unlocked object '" + aObjID + "'");
    return .;
  }
  public final List <IDTYPE> unlockAllObjectsOfCurrentUser ()
  {
    return unlockAllObjectsOfCurrentUserExcept ((Set <IDTYPE>) null);
  }
  public final List <IDTYPE> unlockAllObjectsOfCurrentUserExcept (@Nullable final Set <IDTYPE> aObjectsToKeepLocked)
  {
    final String sCurrentUserID = _getCurrentUserID ();
    return unlockAllObjectsOfUserExcept (sCurrentUserIDaObjectsToKeepLocked);
  }
  public final List <IDTYPE> unlockAllObjectsOfUser (@Nullable final String sUserID)
  {
    return unlockAllObjectsOfUserExcept (sUserID, (Set <IDTYPE>) null);
  }
  private void _unlockAllObjects (@Nonnull @Nonempty final String sUserID,
                                  @Nullable final Set <IDTYPE> aObjectsToKeepLocked,
                                  @Nonnull final List <IDTYPE> aUnlockedObjects)
  {
    // determine locks to be removed
    for (final Map.Entry <IDTYPE, ILockInfoaEntry : .entrySet ())
    {
      final String sLockUserID = aEntry.getValue ().getLockUserID ();
      if (sLockUserID.equals (sUserID))
      {
        // Object is locked by current user
        final IDTYPE aObjID = aEntry.getKey ();
        if (aObjectsToKeepLocked == null || !aObjectsToKeepLocked.contains (aObjID))
          aUnlockedObjects.add (aObjID);
      }
    }
    // remove locks
    for (final IDTYPE aObjID : aUnlockedObjects)
      if (.remove (aObjID) == null)
        throw new IllegalStateException ("Internal inconsistency: user '" +
                                         sUserID +
                                         "' failed to unlock '" +
                                         aObjID +
                                         "' from " +
                                         aUnlockedObjects);
  }
  public final List <IDTYPE> unlockAllObjectsOfUserExcept (@Nullable final String sUserID,
                                                           @Nullable final Set <IDTYPE> aObjectsToKeepLocked)
  {
    final List <IDTYPE> aUnlockedObjects = new ArrayList <IDTYPE> ();
    if (StringHelper.hasText (sUserID))
    {
      .writeLock ().lock ();
      try
      {
        _unlockAllObjects (sUserIDaObjectsToKeepLockedaUnlockedObjects);
      }
      finally
      {
        .writeLock ().unlock ();
      }
      if (!aUnlockedObjects.isEmpty ())
        if (.isInfoEnabled ())
          .info ("Unlocked all objects of user '" +
                          sUserID +
                          "': " +
                          aUnlockedObjects +
                          (ContainerHelper.isEmpty (aObjectsToKeepLocked) ? "" : " except " + aObjectsToKeepLocked));
    }
    return aUnlockedObjects;
  }
  public final boolean isObjectLockedByCurrentUser (@Nullable final IDTYPE aObjID)
  {
    final String sLockUserID = getLockUserID (aObjID);
    if (sLockUserID == null)
    {
      // Object is not locked at all
      return false;
    }
    final String sCurrentUserID = _getCurrentUserID ();
    return sLockUserID.equals (sCurrentUserID);
  }
  public final boolean isObjectLockedByOtherUser (@Nullable final IDTYPE aObjID)
  {
    final String sLockUser = getLockUserID (aObjID);
    if (sLockUser == null)
    {
      // Object is not locked at all
      return false;
    }
    final String sCurrentUserID = _getCurrentUserID ();
    return !sLockUser.equals (sCurrentUserID);
  }
  public final boolean isObjectLockedByAnyUser (@Nullable final IDTYPE aObjID)
  {
    return getLockUserID (aObjID) != null;
  }
  public final Set <IDTYPE> getAllLockedObjects ()
  {
    .readLock ().lock ();
    try
    {
      return ContainerHelper.newSet (.keySet ());
    }
    finally
    {
      .readLock ().unlock ();
    }
  }
  public final Map <IDTYPE, ILockInfogetAllLockInfos ()
  {
    .readLock ().lock ();
    try
    {
      return ContainerHelper.newMap ();
    }
    finally
    {
      .readLock ().unlock ();
    }
  }
  public Set <IDTYPE> getAllLockedObjectsOfCurrentUser ()
  {
    final String sCurrentUserID = _getCurrentUserID ();
    return getAllLockedObjectsOfUser (sCurrentUserID);
  }
  public Set <IDTYPE> getAllLockedObjectsOfUser (@Nullable final String sUserID)
  {
    final Set <IDTYPE> ret = new HashSet <IDTYPE> ();
    if (StringHelper.hasText (sUserID))
    {
      .readLock ().lock ();
      try
      {
        for (final Map.Entry <IDTYPE, ILockInfoaEntry : .entrySet ())
          if (aEntry.getValue ().getLockUserID ().equals (sUserID))
            ret.add (aEntry.getKey ());
      }
      finally
      {
        .readLock ().unlock ();
      }
    }
    return ret;
  }
  public String toString ()
  {
    return new ToStringGenerator (this).append ("currentUserIDProvider")
                                       .append ("lockedObjects")
                                       .toString ();
  }
New to GrepCode? Check out our FAQ X