lockDataToMatch = Collections.singletonMap(WCMUtil.LOCK_KEY_STORE_NAME, avmStoreName);
                    avmLockingService.removeLocks(wpStoreId, lockDataToMatch);
                }
            }
            
            if (logger.isTraceEnabled())
            {
               logger.trace("deleteSandbox: " + mainSandboxStore + " in "+(System.currentTimeMillis()-start)+" ms");
            }
       }
   }
   
   /**
    * Update the permissions for the list of sandbox managers applied to a user sandbox.
    * 
    * Ensures that all managers in the list have full WRITE access to the specified user stores.
    * 
    * @param storeId
    *            The store id of the sandbox to update
    * @param managers
    *            The list of authorities who have ContentManager role in the web project
    */
   public void updateSandboxManagers(final String storeId, final List managers)
   {
       String stagingStoreName = WCMUtil.buildStagingStoreName(storeId);
       updateStagingAreaManagers(stagingStoreName, managers);
   }
   
   /**
    * Update the permissions for the list of sandbox managers applied to a user sandbox.
    * 
    * Ensures that all managers in the list have full WRITE access to the specified user stores.
    * 
    * @param storeId
    *            The store id of the sandbox to update
    * @param managers
    *            The list of authorities who have ContentManager role in the web project
    */
   public void removeSandboxManagers(String storeId, List managersToRemove)
   {
       removeStagingAreaManagers(storeId, managersToRemove);
   }
   
   /**
    * Removes the ContentManager role on staging area to ex-managers.
    * 
    * @param storeId            The store id of the sandbox to update
    * @param managersToRemove   The list of authorities who have had ContentManager role in the web project
    */
   private void removeStagingAreaManagers(String storeId, List managersToRemove)
   {
       String storeName = WCMUtil.buildStagingStoreName(storeId);
       for (String remove : managersToRemove)
       {
           removeFromGroupIfRequired(storeName, remove, PermissionService.WCM_CONTENT_MANAGER);
       }
   }
   
   public void updateSandboxRoles(final String wpStoreId, List usersToUpdate, Set permissionsList)
   {
       // walk existing user sandboxes and remove manager permissions to exclude old managers
       List sbInfos = listAllSandboxes(wpStoreId); // all sandboxes
       
       for (SandboxInfo sbInfo : sbInfos)
       {
           if (sbInfo.getSandboxType().equals(SandboxConstants.PROP_SANDBOX_AUTHOR_MAIN))
           {
               String username = sbInfo.getName();
               updateUserSandboxRole(wpStoreId, username ,usersToUpdate, permissionsList);
           }
       }
       
       updateStagingAreaRole(wpStoreId, usersToUpdate, permissionsList);
   }
   
   /**
    * Updates roles on the sandbox identified by username to users from usersToUpdate list.
    * 
    * @param storeId            The store id of the sandbox to update
    * @param username           Username of the user sandbox to update
    * @param usersToUpdate      The list of users who have role changes
    * @param permissionsList    List of permissions @see org.alfresco.web.bean.wcm.InviteWebsiteUsersWizard.getPermissionsForType(). It is not mandatory.
    */
   private void updateUserSandboxRole(String storeId, String username, List usersToUpdate, Set permissionsList)
   {
       final String storeName = WCMUtil.buildStagingStoreName(storeId);
       // If permissionsList is set remove all possible user permissions and set only necessary.
       // This will fix previous wrong role changes. (paranoid)
       // For little better performance just set permissionsList to null.
       // But in this case it removes only previous permission.
       if (permissionsList != null && permissionsList.size() != 0)
       {
           for (UserRoleWrapper user : usersToUpdate)
           {
               for (String permission : permissionsList)
               {
                   removeFromGroupIfRequired(storeName, user.getUserAuth(), permission);
               }
               addToGroupIfRequired(storeName, user.getUserAuth(), user.getNewRole());
           }
       }
       else
       {
           for (UserRoleWrapper user : usersToUpdate)
           {
               removeFromGroupIfRequired(storeName, user.getUserAuth(), user.getOldRole());
               addToGroupIfRequired(storeName, user.getUserAuth(), user.getNewRole());
           }
       }
   }
   
   /**
    * Updates roles on staging sandbox to users from usersToUpdate list.
    * 
    * @param storeId            The store id of the sandbox to update
    * @param usersToUpdate      The list of users who have role changes
    * @param permissionsList    List of permissions @see org.alfresco.web.bean.wcm.InviteWebsiteUsersWizard.getPermissionsForType(). It is not mandatory.
    */
   private void updateStagingAreaRole(String storeId, List usersToUpdate, Set permissionsList)
   {
       final String storeName = WCMUtil.buildStagingStoreName(storeId);
       // If permissionsList is set remove all possible user permissions and set only necessary.
       // This will fix previous wrong role changes. (paranoid)
       // For little better performance just set permissionsList to null.
       // But in this case it removes only previous permission.
       if (permissionsList != null && permissionsList.size() != 0)
       {
           for (UserRoleWrapper user : usersToUpdate)
           {
               for (String permission : permissionsList)
               {
                   removeFromGroupIfRequired(storeName, user.getUserAuth(), permission);
               }
               addToGroupIfRequired(storeName, user.getUserAuth(), user.getNewRole());
           }
       }
       else
       {
           for (UserRoleWrapper user : usersToUpdate)
           {
               removeFromGroupIfRequired(storeName, user.getUserAuth(), user.getOldRole());
               addToGroupIfRequired(storeName, user.getUserAuth(), user.getNewRole());
           }
       }
   }
   
   /**
    * Tag a named store with a DNS path meta-data attribute.
    * The DNS meta-data attribute is set to the system path 'store:/www/avm_webapps'
    * 
    * @param store  Name of the store to tag
    */
   private static void addStoreDNSPath(String store, Map props, String... components)
   {
      String path = WCMUtil.buildSandboxRootPath(store);
      // DNS name mangle the property name - can only contain value DNS characters!
      String dnsName = DNSNameMangler.MakeDNSName(components);
      String dnsProp = SandboxConstants.PROP_DNS + dnsName;
      props.put(QName.createQName(null, dnsProp), new PropertyValue(DataTypeDefinition.TEXT, path));
   }
   
   /**
    *   Tags a store with a property that indicates one of its 
    *   backgroundStore layers, and the distance of that layer. 
    *   This function must be called separately for each background 
    *   store;  for example the "mysite--alice--preview" store had 
    *   as its immediate background "mysite--alice", which itself had
    *   as its background store "mysite", you'd make a sequence of
    *   calls like this:
    *
    *   
    *    tagStoreBackgroundLayer("mysite--alice",          "mysite",        1);
    *    tagStoreBackgroundLayer("mysite--alice--preview", "mysite--alice", 1);
    *    tagStoreBackgroundLayer("mysite--alice--preview", "mysite",        2);
    *   
    *
    *   This make it easy for other parts of the system to determine
    *   which stores depend on others directly or indirectly (which is
    *   useful for reloading virtualized webapps).
    *
    * @param store            Name of the store to tag
    * @param backgroundStore  Name of store's background store
    * @param distance         Distance from store.
    *                         The backgroundStore 'mysite' is 1 away from the store 'mysite--alice'
    *                         but 2 away from the store 'mysite--alice--preview'.
    */
   private static void addStoreBackgroundLayer(Map props,
                                               String      backgroundStore, 
                                               int         distance)
   {
      String prop_key = SandboxConstants.PROP_BACKGROUND_LAYER + backgroundStore;
      props.put(QName.createQName(null, prop_key), new PropertyValue(DataTypeDefinition.INT, distance));
   }
   
   private static void addSandboxGuid(String sandboxGuid, Map props)
   {
      final QName sandboxIdProp = QName.createQName(SandboxConstants.PROP_SANDBOXID + sandboxGuid);
      props.put(sandboxIdProp, new PropertyValue(DataTypeDefinition.TEXT, null));
   }
   
   private static void addSandboxPrefix(String storeName, Map props)
   {
      props.put(QName.createQName(null, SandboxConstants.PROP_SANDBOX_STORE_PREFIX + storeName), new PropertyValue(DataTypeDefinition.TEXT, null));
   }
   /**
    * Debug helper method to dump the properties of a store
    *  
    * @param store   Store name to dump properties for
    */
   private static void dumpStoreProperties(AVMService avmService, String store)
   {
      logger.trace("Store " + store);
      Map props = avmService.getStoreProperties(store);
      for (QName name : props.keySet())
      {
         logger.trace("   " + name + ": " + props.get(name));
      }
   }
   
   public class UserRoleWrapper
   {
       private String newRole;
       private String oldRole;
       private String userAuth;
       public UserRoleWrapper(String userAuth, String oldRole, String newRole)
       {
           this.userAuth = userAuth;
           this.oldRole = oldRole;
           this.newRole = newRole;
       }
       
       public String getNewRole()
       {
           return newRole;
       }
       public void setNewRole(String newRole)
       {
           this.newRole = newRole;
       }
       public String getOldRole()
       {
           return oldRole;
       }
       public void setOldRole(String oldRole)
       {
           this.oldRole = oldRole;
       }
       public String getUserAuth()
       {
           return userAuth;
       }
       public void setUserAuth(String userAuth)
       {
           this.userAuth = userAuth;
       }
   }
   
   public void removeGroupsForStore(final String storeRoot)
   {
       AuthenticationUtil.runAs(new RunAsWork()
       {
           public Void doWork() throws Exception
           {
               String[] permissions = new String[] { PermissionService.WCM_CONTENT_CONTRIBUTOR, PermissionService.WCM_CONTENT_MANAGER, PermissionService.WCM_CONTENT_PUBLISHER,
                       PermissionService.WCM_CONTENT_REVIEWER };
               for (String permission : permissions)
               {
                   String shortName = storeRoot + "-" + permission;
                   String group = authorityService.getName(AuthorityType.GROUP, shortName);
                   if (authorityService.authorityExists(group))
                   {
                       authorityService.deleteAuthority(group);
                   }
               }
               return null;
           }
       }, AuthenticationUtil.getSystemUserName());
   }
}