From 1cf0ebbd7f120c0b8d421cc459f2d5a1386d82dc Mon Sep 17 00:00:00 2001 From: snowleo Date: Mon, 10 Sep 2012 20:49:07 +0200 Subject: Thread safety for GM --- .../nbproject/project.properties | 14 ++++++++++- .../org/anjocaido/groupmanager/GlobalGroups.java | 23 +++++++++++------ .../org/anjocaido/groupmanager/data/DataUnit.java | 18 +++++++++----- .../src/org/anjocaido/groupmanager/data/Group.java | 21 ++++++++++------ .../groupmanager/data/GroupVariables.java | 5 +++- .../src/org/anjocaido/groupmanager/data/User.java | 11 +++++--- .../anjocaido/groupmanager/data/UserVariables.java | 5 +++- .../org/anjocaido/groupmanager/data/Variables.java | 10 +++++--- .../groupmanager/dataholder/GroupsDataHolder.java | 11 +++++--- .../dataholder/OverloadedWorldHolder.java | 11 +++++++- .../groupmanager/dataholder/UsersDataHolder.java | 12 +++++---- .../groupmanager/dataholder/WorldDataHolder.java | 29 ++++++++++++++++------ 12 files changed, 122 insertions(+), 48 deletions(-) diff --git a/EssentialsGroupManager/nbproject/project.properties b/EssentialsGroupManager/nbproject/project.properties index 5b58a2c8c..26d72fd8a 100644 --- a/EssentialsGroupManager/nbproject/project.properties +++ b/EssentialsGroupManager/nbproject/project.properties @@ -1,5 +1,6 @@ annotation.processing.enabled=true annotation.processing.enabled.in.editor=false +annotation.processing.processors.list= annotation.processing.run.all.processors=true annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output application.title=EssentialsGroupManager @@ -11,7 +12,7 @@ auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.tab-size=2 auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width=120 auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.text-line-wrap=none auxiliary.org-netbeans-modules-editor-indent.CodeStyle.usedProfile=project -auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.expand-tabs=true +auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.expand-tabs=false auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.indent-shift-width=4 auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaces-per-tab=4 auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.tab-size=4 @@ -41,7 +42,9 @@ endorsed.classpath= excludes= file.reference.craftbukkit.jar=../lib/craftbukkit.jar includes=** +jar.archive.disabled=${jnlp.enabled} jar.compress=true +jar.index=${jnlp.enabled} javac.classpath=\ ${file.reference.craftbukkit.jar} # Space-separated list of extra javac options @@ -67,6 +70,15 @@ javadoc.splitindex=true javadoc.use=true javadoc.version=false javadoc.windowtitle= +jnlp.codebase.type=no.codebase +jnlp.descriptor=application +jnlp.enabled=false +jnlp.mixed.code=default +jnlp.offline-allowed=false +jnlp.signed=false +jnlp.signing= +jnlp.signing.alias= +jnlp.signing.keystore= main.class= manifest.file=manifest.mf meta.inf.dir=${src.dir}/META-INF diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/GlobalGroups.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/GlobalGroups.java index d0f5fed8b..d4871b286 100644 --- a/EssentialsGroupManager/src/org/anjocaido/groupmanager/GlobalGroups.java +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/GlobalGroups.java @@ -8,6 +8,7 @@ import java.io.IOException; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -35,7 +36,7 @@ public class GlobalGroups { private GroupManager plugin; //private Yaml GGroups; - private Map groups; + private final Map groups = Collections.synchronizedMap(new HashMap()); protected long timeStampGroups = 0; protected boolean haveGroupsChanged = false; @@ -55,11 +56,13 @@ public class GlobalGroups { if (this.haveGroupsChanged) { return true; } + synchronized(groups) { for (Group g : groups.values()) { if (g.isChanged()) { return true; } } + } return false; } @@ -227,6 +230,7 @@ public class GlobalGroups { Map groupsMap = new HashMap(); root.put("groups", groupsMap); + synchronized(groups) { for (String groupKey : groups.keySet()) { Group group = groups.get(groupKey); @@ -245,6 +249,7 @@ public class GlobalGroups { // Permission nodes aGroupMap.put("permissions", group.getPermissionList()); } + } if (!root.isEmpty()) { DumperOptions opt = new DumperOptions(); @@ -418,26 +423,26 @@ public class GlobalGroups { * * @return Set containing all group names. */ - public Set getGlobalGroups() { + /*public Set getGlobalGroups() { return groups.keySet(); - } + }*/ /** * Resets GlobalGroups. */ public void resetGlobalGroups() { - - this.groups = new HashMap(); + this.groups.clear(); } /** * * @return a collection of the groups */ - public Collection getGroupList() { - - return groups.values(); + public Group[] getGroupList() { + synchronized(groups) { + return groups.values().toArray(new Group[0]); + } } /** @@ -469,9 +474,11 @@ public class GlobalGroups { public void removeGroupsChangedFlag() { setGroupsChanged(false); + synchronized(groups) { for (Group g : groups.values()) { g.flagAsSaved(); } + } } } \ No newline at end of file diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/DataUnit.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/DataUnit.java index bb04fa3d7..5cd07048f 100644 --- a/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/DataUnit.java +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/DataUnit.java @@ -21,7 +21,7 @@ public abstract class DataUnit { private WorldDataHolder dataSource; private String name; private boolean changed, sorted = false; - private ArrayList permissions = new ArrayList(); + private List permissions = Collections.unmodifiableList(Collections.emptyList()); public DataUnit(WorldDataHolder dataSource, String name) { @@ -144,7 +144,9 @@ public abstract class DataUnit { public void addPermission(String permission) { if (!hasSamePermissionNode(permission)) { - permissions.add(permission); + List clone = new ArrayList(permissions); + clone.add(permission); + permissions = Collections.unmodifiableList(clone); } flagAsChanged(); } @@ -152,7 +154,10 @@ public abstract class DataUnit { public boolean removePermission(String permission) { flagAsChanged(); - return permissions.remove(permission); + List clone = new ArrayList(permissions); + boolean ret = clone.remove(permission); + permissions = Collections.unmodifiableList(clone); + return ret; } /** @@ -162,8 +167,7 @@ public abstract class DataUnit { * @return a copy of the permission list */ public List getPermissionList() { - - return Collections.unmodifiableList(permissions); + return permissions; } public boolean isSorted() { @@ -174,7 +178,9 @@ public abstract class DataUnit { public void sortPermissions() { if (!isSorted()) { - Collections.sort(permissions, StringPermissionComparator.getInstance()); + List clone = new ArrayList(permissions); + Collections.sort(clone, StringPermissionComparator.getInstance()); + permissions = Collections.unmodifiableList(clone); sorted = true; } } diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/Group.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/Group.java index 751dc8fd6..8da6ba85a 100644 --- a/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/Group.java +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/Group.java @@ -23,7 +23,7 @@ public class Group extends DataUnit implements Cloneable { /** * The group it inherits DIRECTLY! */ - private ArrayList inherits = new ArrayList(); + private List inherits = Collections.unmodifiableList(Collections.emptyList()); /** * This one holds the fields in INFO node. * like prefix = 'c' @@ -75,7 +75,9 @@ public class Group extends DataUnit implements Cloneable { clone = new Group(this.getName()); } else { clone = new Group(getDataSource(), this.getName()); - clone.inherits = new ArrayList(this.getInherits()); + clone.inherits = this.getInherits().isEmpty() ? + Collections.unmodifiableList(Collections.emptyList()) + : Collections.unmodifiableList(new ArrayList(this.getInherits())); } for (String perm : this.getPermissionList()) { @@ -102,7 +104,9 @@ public class Group extends DataUnit implements Cloneable { // Don't add inheritance for GlobalGroups if (!isGlobal()) { - clone.inherits = new ArrayList(this.getInherits()); + clone.inherits = this.getInherits().isEmpty() ? + Collections.unmodifiableList(Collections.emptyList()) + : Collections.unmodifiableList(new ArrayList(this.getInherits())); } for (String perm : this.getPermissionList()) { clone.addPermission(perm); @@ -120,8 +124,7 @@ public class Group extends DataUnit implements Cloneable { * @return the inherits */ public List getInherits() { - - return Collections.unmodifiableList(inherits); + return inherits; } /** @@ -134,7 +137,9 @@ public class Group extends DataUnit implements Cloneable { getDataSource().addGroup(inherit); } if (!inherits.contains(inherit.getName().toLowerCase())) { - inherits.add(inherit.getName().toLowerCase()); + List clone = new ArrayList(inherits); + clone.add(inherit.getName().toLowerCase()); + inherits = Collections.unmodifiableList(clone); } flagAsChanged(); if (GroupManager.isLoaded()) { @@ -148,7 +153,9 @@ public class Group extends DataUnit implements Cloneable { if (!isGlobal()) { if (this.inherits.contains(inherit.toLowerCase())) { - this.inherits.remove(inherit.toLowerCase()); + List clone = new ArrayList(inherits); + clone.remove(inherit.toLowerCase()); + inherits = Collections.unmodifiableList(clone); flagAsChanged(); GroupManagerEventHandler.callEvent(this, Action.GROUP_INHERITANCE_CHANGED); return true; diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/GroupVariables.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/GroupVariables.java index e08d1db7d..588d50116 100644 --- a/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/GroupVariables.java +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/GroupVariables.java @@ -26,7 +26,8 @@ public class GroupVariables extends Variables implements Cloneable { public GroupVariables(Group owner, Map varList) { super(owner); - variables = varList; + variables.clear(); + variables.putAll(varList); if (variables.get("prefix") == null) { variables.put("prefix", ""); owner.flagAsChanged(); @@ -54,9 +55,11 @@ public class GroupVariables extends Variables implements Cloneable { protected GroupVariables clone(Group newOwner) { GroupVariables clone = new GroupVariables(newOwner); + synchronized(variables) { for (String key : variables.keySet()) { clone.variables.put(key, variables.get(key)); } + } newOwner.flagAsChanged(); return clone; } diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/User.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/User.java index 6c74c2e50..b1b2c6985 100644 --- a/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/User.java +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/User.java @@ -6,6 +6,8 @@ package org.anjocaido.groupmanager.data; //import com.sun.org.apache.bcel.internal.generic.AALOAD; import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import org.anjocaido.groupmanager.GroupManager; import org.anjocaido.groupmanager.dataholder.WorldDataHolder; @@ -26,7 +28,7 @@ public class User extends DataUnit implements Cloneable { * */ private String group = null; - private ArrayList subGroups = new ArrayList(); + private List subGroups = Collections.synchronizedList(Collections.emptyList()); /** * This one holds the fields in INFO node. like prefix = 'c' or build = * false @@ -213,6 +215,7 @@ public class User extends DataUnit implements Cloneable { public ArrayList subGroupListCopy() { ArrayList val = new ArrayList(); + synchronized(subGroups) { for (String gstr : subGroups) { Group g = getDataSource().getGroup(gstr); if (g == null) { @@ -221,12 +224,14 @@ public class User extends DataUnit implements Cloneable { } val.add(g); } + } return val; } public ArrayList subGroupListStringCopy() { - - return new ArrayList(subGroups); + synchronized(subGroups) { + return new ArrayList(subGroups); + } } /** diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/UserVariables.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/UserVariables.java index f994595c1..05c3aecee 100644 --- a/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/UserVariables.java +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/UserVariables.java @@ -23,7 +23,8 @@ public class UserVariables extends Variables { public UserVariables(User owner, Map varList) { super(owner); - this.variables = varList; + this.variables.clear(); + this.variables.putAll(varList); this.owner = owner; } @@ -35,9 +36,11 @@ public class UserVariables extends Variables { protected UserVariables clone(User newOwner) { UserVariables clone = new UserVariables(newOwner); + synchronized(variables) { for (String key : variables.keySet()) { clone.variables.put(key, variables.get(key)); } + } newOwner.flagAsChanged(); return clone; } diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/Variables.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/Variables.java index 42ceba7e4..10d8be469 100644 --- a/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/Variables.java +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/data/Variables.java @@ -4,6 +4,7 @@ */ package org.anjocaido.groupmanager.data; +import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Set; @@ -21,7 +22,7 @@ import java.util.Set; public abstract class Variables implements Cloneable { private DataUnit owner; - protected Map variables = new HashMap(); + protected final Map variables = Collections.synchronizedMap(new HashMap()); public Variables(DataUnit owner) { @@ -126,9 +127,10 @@ public abstract class Variables implements Cloneable { * * @return Set of all variable names. */ - public Set getVarKeyList() { - - return variables.keySet(); + public String[] getVarKeyList() { + synchronized(variables) { + return variables.keySet().toArray(new String[0]); + } } /** diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/GroupsDataHolder.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/GroupsDataHolder.java index eaaaace74..fdd099c87 100644 --- a/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/GroupsDataHolder.java +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/GroupsDataHolder.java @@ -1,6 +1,7 @@ package org.anjocaido.groupmanager.dataholder; import java.io.File; +import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -23,7 +24,7 @@ public class GroupsDataHolder { /** * The actual groups holder */ - private Map groups = new HashMap(); + private final Map groups = Collections.synchronizedMap(new HashMap()); /** * Constructor @@ -36,8 +37,10 @@ public class GroupsDataHolder { this.dataSource = dataSource; //push this data source to the users, so they pull the correct groups data. + synchronized(groups) { for (Group group : groups.values()) group.setDataSource(this.dataSource); + } } /** @@ -57,6 +60,7 @@ public class GroupsDataHolder { } /** + * Note: Iteration over this object has to be synchronized! * @return the groups */ public Map getGroups() { @@ -67,9 +71,8 @@ public class GroupsDataHolder { /** * @param groups the groups to set */ - public void setGroups(Map groups) { - - this.groups = groups; + public void resetGroups() { + this.groups.clear(); } /** diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/OverloadedWorldHolder.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/OverloadedWorldHolder.java index 84561b6e5..ef9f605ed 100644 --- a/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/OverloadedWorldHolder.java +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/OverloadedWorldHolder.java @@ -6,6 +6,7 @@ package org.anjocaido.groupmanager.dataholder; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.Map; import org.anjocaido.groupmanager.data.User; @@ -19,7 +20,7 @@ public class OverloadedWorldHolder extends WorldDataHolder { /** * */ - protected Map overloadedUsers = new HashMap(); + protected final Map overloadedUsers = Collections.synchronizedMap(new HashMap()); /** * @@ -112,29 +113,35 @@ public class OverloadedWorldHolder extends WorldDataHolder { if (groupName.equals(getDefaultGroup())) { return false; } + synchronized(getGroups()) { for (String key : getGroups().keySet()) { if (groupName.equalsIgnoreCase(key)) { getGroups().remove(key); + synchronized(getUsers()) { for (String userKey : getUsers().keySet()) { User user = getUsers().get(userKey); if (user.getGroupName().equalsIgnoreCase(key)) { user.setGroup(getDefaultGroup()); } + } } //OVERLOADED CODE + synchronized(overloadedUsers) { for (String userKey : overloadedUsers.keySet()) { User user = overloadedUsers.get(userKey); if (user.getGroupName().equalsIgnoreCase(key)) { user.setGroup(getDefaultGroup()); } + } } //END OVERLOAD setGroupsChanged(true); return true; } } + } return false; } @@ -146,6 +153,7 @@ public class OverloadedWorldHolder extends WorldDataHolder { public Collection getUserList() { Collection overloadedList = new ArrayList(); + synchronized(getUsers()) { Collection normalList = getUsers().values(); for (User u : normalList) { if (overloadedUsers.containsKey(u.getName().toLowerCase())) { @@ -154,6 +162,7 @@ public class OverloadedWorldHolder extends WorldDataHolder { overloadedList.add(u); } } + } return overloadedList; } diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/UsersDataHolder.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/UsersDataHolder.java index 665fe227d..8a3c4c102 100644 --- a/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/UsersDataHolder.java +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/UsersDataHolder.java @@ -1,6 +1,7 @@ package org.anjocaido.groupmanager.dataholder; import java.io.File; +import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -22,7 +23,7 @@ public class UsersDataHolder { /** * The actual groups holder */ - private Map users = new HashMap(); + private final Map users = Collections.synchronizedMap(new HashMap()); /** * Constructor @@ -35,12 +36,14 @@ public class UsersDataHolder { this.dataSource = dataSource; //push this data source to the users, so they pull the correct groups data. + synchronized(users) { for (User user : users.values()) user.setDataSource(this.dataSource); - + } } /** + * Note: Iteration over this object has to be synchronized! * @return the users */ public Map getUsers() { @@ -51,9 +54,8 @@ public class UsersDataHolder { /** * @param users the users to set */ - public void setUsers(Map users) { - - this.users = users; + public void resetUsers() { + this.users.clear(); } /** diff --git a/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/WorldDataHolder.java b/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/WorldDataHolder.java index aad59e5aa..4d85eff68 100644 --- a/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/WorldDataHolder.java +++ b/EssentialsGroupManager/src/org/anjocaido/groupmanager/dataholder/WorldDataHolder.java @@ -319,8 +319,9 @@ public class WorldDataHolder { * @return a collection of the groups */ public Collection getGroupList() { - - return getGroups().values(); + synchronized(getGroups()) { + return new ArrayList(getGroups().values()); + } } /** @@ -328,8 +329,9 @@ public class WorldDataHolder { * @return a collection of the users */ public Collection getUserList() { - - return getUsers().values(); + synchronized(getUsers()) { + return new ArrayList(getUsers().values()); + } } /** @@ -944,6 +946,7 @@ public class WorldDataHolder { Map groupsMap = new HashMap(); root.put("groups", groupsMap); + synchronized(ph.getGroups()) { for (String groupKey : ph.getGroups().keySet()) { Group group = ph.getGroups().get(groupKey); @@ -966,6 +969,7 @@ public class WorldDataHolder { aGroupMap.put("permissions", group.getPermissionList()); } + } if (!root.isEmpty()) { DumperOptions opt = new DumperOptions(); @@ -1031,6 +1035,7 @@ public class WorldDataHolder { Map usersMap = new HashMap(); root.put("users", usersMap); + synchronized(ph.getUsers()) { for (String userKey : ph.getUsers().keySet()) { User user = ph.getUsers().get(userKey); if ((user.getGroup() == null || user.getGroup().equals(ph.getDefaultGroup())) && user.getPermissionList().isEmpty() && user.getVariables().isEmpty() && user.isSubGroupsEmpty()) { @@ -1060,6 +1065,7 @@ public class WorldDataHolder { aUserMap.put("subgroups", user.subGroupListStringCopy()); // END SUBGROUPS NODE - BETA } + } if (!root.isEmpty()) { DumperOptions opt = new DumperOptions(); @@ -1159,11 +1165,13 @@ public class WorldDataHolder { if (users.HaveUsersChanged()) { return true; } + synchronized(users.getUsers()) { for (User u : users.getUsers().values()) { if (u.isChanged()) { return true; } } + } return false; } @@ -1184,11 +1192,13 @@ public class WorldDataHolder { if (groups.HaveGroupsChanged()) { return true; } + synchronized(groups.getGroups()) { for (Group g : groups.getGroups().values()) { if (g.isChanged()) { return true; } } + } return false; } @@ -1198,9 +1208,11 @@ public class WorldDataHolder { public void removeUsersChangedFlag() { setUsersChanged(false); + synchronized(getUsers()) { for (User u : getUsers().values()) { u.flagAsSaved(); } + } } /** @@ -1209,9 +1221,11 @@ public class WorldDataHolder { public void removeGroupsChangedFlag() { setGroupsChanged(false); + synchronized(getGroups()) { for (Group g : getGroups().values()) { g.flagAsSaved(); } + } } /** @@ -1260,18 +1274,18 @@ public class WorldDataHolder { public void resetGroups() { // setDefaultGroup(null); - groups.setGroups(new HashMap()); + groups.resetGroups(); } /** * Resets Users */ public void resetUsers() { - - users.setUsers(new HashMap()); + users.resetUsers(); } /** + * Note: Iteration over this object has to be synchronized! * @return the groups */ public Map getGroups() { @@ -1280,6 +1294,7 @@ public class WorldDataHolder { } /** + * Note: Iteration over this object has to be synchronized! * @return the users */ public Map getUsers() { -- cgit v1.2.3