3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.tyrannyofheaven.bukkit.zPermissions;
17 |
18 | import org.bukkit.entity.Player;
19 | import org.bukkit.event.HandlerList;
20 | import org.bukkit.event.player.PlayerEvent;
21 |
22 | /**
23 | * Bukkit event fired off whenever zPermissions might potentially change an
24 | * online player's permissions. This includes world changes, commands that affect
25 | * the groups or permissions of a player, as well as certain movement-based
26 | * events (when region-support is enabled).
27 | *
28 | * Note that unconditional permissions changes that occur during
29 | * standard Bukkit events (namely: PlayerLoginEvent, PlayerJoinEvent,
30 | * PlayerQuitEvent) do not fire off this event.
31 | *
32 | *
Also note that this event may be called even if the player's permissions
33 | * did not actually change. However, for its PlayerMoveEvent handler (when
34 | * region-support is enabled), zPermissions guarantees that this event will be
35 | * called only when the player crosses a region boundary.
36 | */
37 | public class ZPermissionsPlayerUpdateEvent extends PlayerEvent {
38 |
39 | private final Cause cause;
40 |
41 | /**
42 | * Creates a player permissions change event.
43 | *
44 | * @param who the affected player
45 | * @param cause the cause of this permissions change
46 | */
47 | public ZPermissionsPlayerUpdateEvent(Player who, Cause cause) {
48 | super(who);
49 | if (cause == null)
50 | throw new IllegalArgumentException("cause cannot be null");
51 | this.cause = cause;
52 | }
53 |
54 | /**
55 | * Returns the cause of this permissions change.
56 | *
57 | * @return the cause of this permissions change
58 | */
59 | public Cause getCause() {
60 | return cause;
61 | }
62 |
63 | private static final HandlerList handlers = new HandlerList();
64 |
65 | public HandlerList getHandlers() {
66 | return handlers;
67 | }
68 |
69 | public static HandlerList getHandlerList() {
70 | return handlers;
71 | }
72 |
73 | public static enum Cause {
74 | /**
75 | * Permissions change to the player caused by a command. Includes changes
76 | * through the API. Note that the settemp command cannot be covered since
77 | * there's no visibility as to when the permission goes away.
78 | */
79 | COMMAND,
80 |
81 | /**
82 | * An associated group was changed. Includes command line, changes
83 | * through the API, group membership expirations, and server-wide changes
84 | * (reload, refresh, etc. since these force a re-read from storage).
85 | */
86 | GROUP_CHANGE,
87 |
88 | /**
89 | * Player movement, including movement within the same world (if
90 | * region-support is enabled) and movement to a different world.
91 | */
92 | MOVEMENT;
93 | }
94 |
95 | }
96 |
--------------------------------------------------------------------------------
/src/main/java/org/tyrannyofheaven/bukkit/zPermissions/model/Membership.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 ZerothAngel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.tyrannyofheaven.bukkit.zPermissions.model;
17 |
18 | import java.util.Date;
19 | import java.util.UUID;
20 |
21 | import javax.persistence.Column;
22 | import javax.persistence.Entity;
23 | import javax.persistence.Id;
24 | import javax.persistence.ManyToOne;
25 | import javax.persistence.Table;
26 | import javax.persistence.Temporal;
27 | import javax.persistence.TemporalType;
28 | import javax.persistence.Transient;
29 | import javax.persistence.UniqueConstraint;
30 |
31 | import org.tyrannyofheaven.bukkit.util.uuid.UuidUtils;
32 |
33 | /**
34 | * Represents group membership.
35 | *
36 | * @author zerothangel
37 | */
38 | @Entity
39 | @Table(name="memberships")
40 | @UniqueConstraint(columnNames={"member", "group_id"})
41 | public class Membership {
42 |
43 | private Long id;
44 |
45 | private String member;
46 |
47 | private String displayName;
48 |
49 | private PermissionEntity group;
50 |
51 | private Date expiration;
52 |
53 | @Id
54 | public Long getId() {
55 | return id;
56 | }
57 |
58 | public void setId(Long id) {
59 | this.id = id;
60 | }
61 |
62 | public String getMember() {
63 | return member;
64 | }
65 |
66 | public void setMember(String member) {
67 | this.member = member;
68 | }
69 |
70 | public String getDisplayName() {
71 | return displayName;
72 | }
73 |
74 | public void setDisplayName(String displayName) {
75 | this.displayName = displayName;
76 | }
77 |
78 | @Column(name="group_id")
79 | @ManyToOne(optional=false)
80 | public PermissionEntity getGroup() {
81 | return group;
82 | }
83 |
84 | public void setGroup(PermissionEntity group) {
85 | this.group = group;
86 | }
87 |
88 | @Temporal(TemporalType.TIMESTAMP)
89 | public Date getExpiration() {
90 | return expiration;
91 | }
92 |
93 | public void setExpiration(Date expiration) {
94 | this.expiration = expiration;
95 | }
96 |
97 | @Transient
98 | public UUID getUuid() {
99 | return UuidUtils.uncanonicalizeUuid(getMember());
100 | }
101 |
102 | @Override
103 | public boolean equals(Object obj) {
104 | if (obj == this) return true;
105 | if (!(obj instanceof Membership)) return false;
106 | Membership o = (Membership)obj;
107 | return getMember().equals(o.getMember()) &&
108 | getGroup().equals(o.getGroup());
109 | }
110 |
111 | @Override
112 | public int hashCode() {
113 | int result = 17;
114 | result = 37 * result + getMember().hashCode();
115 | result = 37 * result + getGroup().hashCode();
116 | return result;
117 | }
118 |
119 | @Override
120 | public String toString() {
121 | return String.format("Membership[%s -> %s/%s]", getGroup().getName(), getMember(), getDisplayName());
122 | }
123 |
124 | }
125 |
--------------------------------------------------------------------------------
/src/main/java/org/tyrannyofheaven/bukkit/zPermissions/region/FactoidRegionStrategy.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 ZerothAngel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.tyrannyofheaven.bukkit.zPermissions.region;
17 |
18 | import java.util.Collections;
19 | import java.util.Set;
20 |
21 | import me.tabinol.factoid.Factoid;
22 | import me.tabinol.factoid.lands.Land;
23 |
24 | import org.bukkit.Bukkit;
25 | import org.bukkit.Location;
26 | import org.bukkit.entity.Player;
27 | import org.bukkit.event.EventHandler;
28 | import org.bukkit.event.Listener;
29 | import org.bukkit.event.server.PluginEnableEvent;
30 | import org.bukkit.plugin.Plugin;
31 | import org.tyrannyofheaven.bukkit.util.ToHLoggingUtils;
32 | import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsCore;
33 |
34 | /**
35 | * RegionStrategy implementation for Factoid.
36 | *
37 | * @author zerothangel, Tabinol
38 | */
39 | public class FactoidRegionStrategy implements RegionStrategy, Listener {
40 |
41 | private static final String RM_PLUGIN_NAME = "Factoid";
42 |
43 | private final Plugin plugin;
44 |
45 | private final ZPermissionsCore core;
46 |
47 | private boolean enabled;
48 |
49 | public FactoidRegionStrategy(Plugin plugin, ZPermissionsCore core) {
50 | this.plugin = plugin;
51 | this.core = core;
52 | }
53 |
54 | @Override
55 | public String getName() {
56 | return RM_PLUGIN_NAME;
57 | }
58 |
59 | @Override
60 | public boolean isPresent() {
61 | return Bukkit.getPluginManager().getPlugin(RM_PLUGIN_NAME) != null;
62 | }
63 |
64 | @Override
65 | public void init() {
66 | detectFactoidPlugin();
67 | if (!isEnabled()) {
68 | // Not yet loaded, listen for its enable event
69 | Bukkit.getPluginManager().registerEvents(this, plugin);
70 | }
71 | }
72 |
73 | @Override
74 | public boolean isEnabled() {
75 | return enabled;
76 | }
77 |
78 | @Override
79 | public void shutdown() {
80 | enabled = false;
81 | }
82 |
83 | @Override
84 | public Set getRegions(Location location, Player player) {
85 | Land land = Factoid.getLands().getLand(location);
86 | if (land != null) {
87 | return Collections.singleton(land.getName()); // Land name is always lower case
88 | }
89 | return Collections.emptySet();
90 | }
91 |
92 | @EventHandler
93 | public void onPluginEnable(PluginEnableEvent event) {
94 | if (!isEnabled() && RM_PLUGIN_NAME.equals(event.getPlugin().getName())) {
95 | detectFactoidPlugin();
96 | if (isEnabled()) {
97 | ToHLoggingUtils.log(plugin, "%s region support enabled.", getName());
98 | core.refreshPlayers();
99 | }
100 | }
101 | }
102 |
103 | private void detectFactoidPlugin() {
104 | Plugin plugin = Bukkit.getPluginManager().getPlugin(RM_PLUGIN_NAME);
105 | enabled = plugin != null && plugin.isEnabled();
106 | // Nothing else to do
107 | }
108 |
109 | }
110 |
--------------------------------------------------------------------------------
/src/main/java/org/tyrannyofheaven/bukkit/zPermissions/region/ResidenceRegionStrategy.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 ZerothAngel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.tyrannyofheaven.bukkit.zPermissions.region;
17 |
18 | import java.util.Collections;
19 | import java.util.Set;
20 |
21 | import org.bukkit.Bukkit;
22 | import org.bukkit.Location;
23 | import org.bukkit.entity.Player;
24 | import org.bukkit.event.EventHandler;
25 | import org.bukkit.event.Listener;
26 | import org.bukkit.event.server.PluginEnableEvent;
27 | import org.bukkit.plugin.Plugin;
28 | import org.tyrannyofheaven.bukkit.util.ToHLoggingUtils;
29 | import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsCore;
30 |
31 | import com.bekvon.bukkit.residence.Residence;
32 | import com.bekvon.bukkit.residence.protection.ClaimedResidence;
33 |
34 | /**
35 | * RegionStrategy implementation for Residence.
36 | *
37 | * @author zerothangel
38 | */
39 | public class ResidenceRegionStrategy implements RegionStrategy, Listener {
40 |
41 | private static final String RM_PLUGIN_NAME = "Residence";
42 |
43 | private final Plugin plugin;
44 |
45 | private final ZPermissionsCore core;
46 |
47 | private boolean enabled;
48 |
49 | public ResidenceRegionStrategy(Plugin plugin, ZPermissionsCore core) {
50 | this.plugin = plugin;
51 | this.core = core;
52 | }
53 |
54 | @Override
55 | public String getName() {
56 | return RM_PLUGIN_NAME;
57 | }
58 |
59 | @Override
60 | public boolean isPresent() {
61 | return Bukkit.getPluginManager().getPlugin(RM_PLUGIN_NAME) != null;
62 | }
63 |
64 | @Override
65 | public void init() {
66 | detectResidencePlugin();
67 | if (!isEnabled()) {
68 | // Not yet loaded, listen for its enable event
69 | Bukkit.getPluginManager().registerEvents(this, plugin);
70 | }
71 | }
72 |
73 | @Override
74 | public boolean isEnabled() {
75 | return enabled;
76 | }
77 |
78 | @Override
79 | public void shutdown() {
80 | enabled = false;
81 | }
82 |
83 | @Override
84 | public Set getRegions(Location location, Player player) {
85 | ClaimedResidence res = Residence.getResidenceManager().getByLoc(location);
86 | if (res != null) {
87 | return Collections.singleton(res.getName().toLowerCase());
88 | }
89 | return Collections.emptySet();
90 | }
91 |
92 | @EventHandler
93 | public void onPluginEnable(PluginEnableEvent event) {
94 | if (!isEnabled() && RM_PLUGIN_NAME.equals(event.getPlugin().getName())) {
95 | detectResidencePlugin();
96 | if (isEnabled()) {
97 | ToHLoggingUtils.log(plugin, "%s region support enabled.", getName());
98 | core.refreshPlayers();
99 | }
100 | }
101 | }
102 |
103 | private void detectResidencePlugin() {
104 | Plugin plugin = Bukkit.getPluginManager().getPlugin(RM_PLUGIN_NAME);
105 | enabled = plugin != null && plugin.isEnabled();
106 | // Nothing else to do
107 | }
108 |
109 | }
110 |
--------------------------------------------------------------------------------
/src/main/java/org/tyrannyofheaven/bukkit/zPermissions/ZPermissionsRankChangeEvent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 ZerothAngel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.tyrannyofheaven.bukkit.zPermissions;
17 |
18 | import org.bukkit.event.Event;
19 | import org.bukkit.event.HandlerList;
20 |
21 | /**
22 | * Bukkit event fired off whenever a rank command successfully completes.
23 | */
24 | public class ZPermissionsRankChangeEvent extends Event {
25 |
26 | private final String playerName;
27 |
28 | private final String track;
29 |
30 | private final String fromGroup;
31 |
32 | private final String toGroup;
33 |
34 | /**
35 | * Create a rank change event.
36 | *
37 | * @param playerName the name of the player
38 | * @param track the name of the track
39 | * @param fromGroup the previous group. May be null.
40 | * @param toGroup the new group. May be null.
41 | */
42 | public ZPermissionsRankChangeEvent(String playerName, String track, String fromGroup, String toGroup) {
43 | if (playerName == null || playerName.trim().isEmpty())
44 | throw new IllegalArgumentException("playerName must have a value");
45 | if (track == null || track.trim().isEmpty())
46 | throw new IllegalArgumentException("track must have a value");
47 | if (fromGroup != null && fromGroup.trim().isEmpty())
48 | fromGroup = null;
49 | if (toGroup != null && toGroup.trim().isEmpty())
50 | toGroup = null;
51 |
52 | this.playerName = playerName;
53 | this.track = track;
54 | this.fromGroup = fromGroup;
55 | this.toGroup = toGroup;
56 | }
57 |
58 | /**
59 | * The name of the player whose rank has changed. Note that there's no
60 | * guarantee about the letter case of the name (it will be as was entered
61 | * from the command line).
62 | *
63 | * @return the name of the player
64 | */
65 | public String getPlayerName() {
66 | return playerName;
67 | }
68 |
69 | /**
70 | * The name of the track. Note that there's no guarantee about the letter
71 | * case of the name.
72 | *
73 | * @return the name of the track
74 | */
75 | public String getTrack() {
76 | return track;
77 | }
78 |
79 | /**
80 | * The player's previous group. This may be null meaning the
81 | * player was not previously on any group in this track.
82 | *
83 | * @return the previous group
84 | */
85 | public String getFromGroup() {
86 | return fromGroup;
87 | }
88 |
89 | /**
90 | * The player's new group. This may be null meaning the player
91 | * was removed from all groups in this track.
92 | *
93 | * @return the new group
94 | */
95 | public String getToGroup() {
96 | return toGroup;
97 | }
98 |
99 | private static final HandlerList handlers = new HandlerList();
100 |
101 | public HandlerList getHandlers() {
102 | return handlers;
103 | }
104 |
105 | public static HandlerList getHandlerList() {
106 | return handlers;
107 | }
108 |
109 | }
110 |
--------------------------------------------------------------------------------
/src/test/java/org/tyrannyofheaven/bukkit/zPermissions/dao/NewAvajeDaoTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011, 2012 ZerothAngel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.tyrannyofheaven.bukkit.zPermissions.dao;
17 |
18 | import org.tyrannyofheaven.bukkit.zPermissions.model.EntityMetadata;
19 | import org.tyrannyofheaven.bukkit.zPermissions.model.Entry;
20 | import org.tyrannyofheaven.bukkit.zPermissions.model.Inheritance;
21 | import org.tyrannyofheaven.bukkit.zPermissions.model.Membership;
22 | import org.tyrannyofheaven.bukkit.zPermissions.model.PermissionEntity;
23 | import org.tyrannyofheaven.bukkit.zPermissions.model.PermissionRegion;
24 | import org.tyrannyofheaven.bukkit.zPermissions.model.PermissionWorld;
25 |
26 | import com.avaje.ebean.EbeanServer;
27 | import com.avaje.ebean.EbeanServerFactory;
28 | import com.avaje.ebean.config.DataSourceConfig;
29 | import com.avaje.ebean.config.ServerConfig;
30 |
31 | public class NewAvajeDaoTest extends AbstractDaoTest {
32 |
33 | private static EbeanServer ebeanServer;
34 |
35 | public NewAvajeDaoTest() {
36 | // Bleh. But Avaje doesn't like being initialized more than once.
37 | // And Maven instantiates this class for each test.
38 | synchronized (NewAvajeDaoTest.class) {
39 | if (ebeanServer == null) {
40 | ServerConfig config = new ServerConfig();
41 | config.setName(NewAvajeDaoTest.class.getSimpleName());
42 | config.setDefaultServer(false);
43 |
44 | DataSourceConfig dataSourceConfig = new DataSourceConfig();
45 | dataSourceConfig.setDriver("org.h2.Driver");
46 | dataSourceConfig.setUsername("username");
47 | dataSourceConfig.setPassword("password");
48 | dataSourceConfig.setUrl("jdbc:h2:NewAvajeDaoTest");
49 |
50 | config.setDataSourceConfig(dataSourceConfig);
51 |
52 | config.setDdlGenerate(true);
53 | config.setDdlRun(true);
54 |
55 | config.addClass(PermissionEntity.class);
56 | config.addClass(Inheritance.class);
57 | config.addClass(PermissionRegion.class);
58 | config.addClass(PermissionWorld.class);
59 | config.addClass(Entry.class);
60 | config.addClass(Membership.class);
61 | config.addClass(EntityMetadata.class);
62 |
63 | ebeanServer = EbeanServerFactory.create(config);
64 | }
65 | }
66 |
67 | getPermissionService().setPermissionDao(new AvajePermissionDao(getPermissionService(), ebeanServer, null));
68 | }
69 |
70 | EbeanServer getEbeanServer() {
71 | return ebeanServer;
72 | }
73 |
74 | @Override
75 | protected void begin() {
76 | getEbeanServer().beginTransaction();
77 | }
78 |
79 | @Override
80 | protected void commit() {
81 | getEbeanServer().commitTransaction();
82 | }
83 |
84 | @Override
85 | protected void end() {
86 | getEbeanServer().endTransaction();
87 | }
88 |
89 | @Override
90 | protected PermissionWorld getWorld(String name) {
91 | return getEbeanServer().find(PermissionWorld.class).where().eq("name", name).findUnique();
92 | }
93 |
94 | @Override
95 | protected PermissionRegion getRegion(String name) {
96 | return getEbeanServer().find(PermissionRegion.class).where().eq("name", name).findUnique();
97 | }
98 |
99 | }
100 |
--------------------------------------------------------------------------------
/src/test/java/org/tyrannyofheaven/bukkit/zPermissions/NewAvajeResolverTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 ZerothAngel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.tyrannyofheaven.bukkit.zPermissions;
17 |
18 |
19 | import java.util.Collections;
20 |
21 | import org.tyrannyofheaven.bukkit.zPermissions.dao.AvajePermissionDao;
22 | import org.tyrannyofheaven.bukkit.zPermissions.dao.InMemoryPermissionService;
23 | import org.tyrannyofheaven.bukkit.zPermissions.model.EntityMetadata;
24 | import org.tyrannyofheaven.bukkit.zPermissions.model.Entry;
25 | import org.tyrannyofheaven.bukkit.zPermissions.model.Inheritance;
26 | import org.tyrannyofheaven.bukkit.zPermissions.model.Membership;
27 | import org.tyrannyofheaven.bukkit.zPermissions.model.PermissionEntity;
28 | import org.tyrannyofheaven.bukkit.zPermissions.model.PermissionRegion;
29 | import org.tyrannyofheaven.bukkit.zPermissions.model.PermissionWorld;
30 |
31 | import com.avaje.ebean.EbeanServer;
32 | import com.avaje.ebean.EbeanServerFactory;
33 | import com.avaje.ebean.config.DataSourceConfig;
34 | import com.avaje.ebean.config.ServerConfig;
35 |
36 | public class NewAvajeResolverTest extends AbstractResolverTest {
37 |
38 | private static EbeanServer ebeanServer;
39 |
40 | public NewAvajeResolverTest() {
41 | // Bleh. But Avaje doesn't like being initialized more than once.
42 | // And Maven instantiates this class for each test.
43 | synchronized (NewAvajeResolverTest.class) {
44 | if (ebeanServer == null) {
45 | ServerConfig config = new ServerConfig();
46 | config.setName(NewAvajeResolverTest.class.getSimpleName());
47 | config.setDefaultServer(false);
48 |
49 | DataSourceConfig dataSourceConfig = new DataSourceConfig();
50 | dataSourceConfig.setDriver("org.h2.Driver");
51 | dataSourceConfig.setUsername("username");
52 | dataSourceConfig.setPassword("password");
53 | dataSourceConfig.setUrl("jdbc:h2:NewAvajeResolverTest");
54 |
55 | config.setDataSourceConfig(dataSourceConfig);
56 |
57 | config.setDdlGenerate(true);
58 | config.setDdlRun(true);
59 |
60 | config.addClass(PermissionEntity.class);
61 | config.addClass(Inheritance.class);
62 | config.addClass(PermissionRegion.class);
63 | config.addClass(PermissionWorld.class);
64 | config.addClass(Entry.class);
65 | config.addClass(Membership.class);
66 | config.addClass(EntityMetadata.class);
67 |
68 | ebeanServer = EbeanServerFactory.create(config);
69 | }
70 | }
71 |
72 | permissionService = new InMemoryPermissionService();
73 | permissionService.setPermissionDao(new AvajePermissionDao(permissionService, ebeanServer, null));
74 | resolver = new PermissionsResolver(permissionService);
75 | resolver.setDefaultGroup(TEST_GROUP1);
76 | resolver.setGroupPermissionFormats(Collections.singleton("group.%s"));
77 | resolver.setAssignedGroupPermissionFormats(Collections.singleton("assignedgroup.%s"));
78 | }
79 |
80 | EbeanServer getEbeanServer() {
81 | return ebeanServer;
82 | }
83 |
84 | protected void begin() {
85 | getEbeanServer().beginTransaction();
86 | }
87 |
88 | protected void commit() {
89 | getEbeanServer().commitTransaction();
90 | }
91 |
92 | protected void end() {
93 | getEbeanServer().endTransaction();
94 | }
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/src/main/java/org/tyrannyofheaven/bukkit/zPermissions/model/Entry.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 ZerothAngel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.tyrannyofheaven.bukkit.zPermissions.model;
17 |
18 | import javax.persistence.Column;
19 | import javax.persistence.Entity;
20 | import javax.persistence.Id;
21 | import javax.persistence.JoinColumn;
22 | import javax.persistence.ManyToOne;
23 | import javax.persistence.Table;
24 | import javax.persistence.UniqueConstraint;
25 |
26 | /**
27 | * A permission entry.
28 | *
29 | * @author zerothangel
30 | */
31 | @Entity
32 | @Table(name="entries")
33 | @UniqueConstraint(columnNames={"entity_id", "region_id", "world_id", "permission"})
34 | public class Entry {
35 |
36 | private Long id;
37 |
38 | private PermissionEntity entity;
39 |
40 | private PermissionRegion region;
41 |
42 | private PermissionWorld world;
43 |
44 | private String permission;
45 |
46 | private boolean value;
47 |
48 | @Id
49 | public Long getId() {
50 | return id;
51 | }
52 |
53 | public void setId(Long id) {
54 | this.id = id;
55 | }
56 |
57 | @JoinColumn(name="entity_id")
58 | @ManyToOne(optional=false)
59 | public PermissionEntity getEntity() {
60 | return entity;
61 | }
62 |
63 | public void setEntity(PermissionEntity owner) {
64 | this.entity = owner;
65 | }
66 |
67 | @JoinColumn(name="region_id")
68 | @ManyToOne(optional=true)
69 | public PermissionRegion getRegion() {
70 | return region;
71 | }
72 |
73 | public void setRegion(PermissionRegion region) {
74 | this.region = region;
75 | }
76 |
77 | @JoinColumn(name="world_id")
78 | @ManyToOne(optional=true)
79 | public PermissionWorld getWorld() {
80 | return world;
81 | }
82 |
83 | public void setWorld(PermissionWorld world) {
84 | this.world = world;
85 | }
86 |
87 | @Column(nullable=false)
88 | public String getPermission() {
89 | return permission;
90 | }
91 |
92 | public void setPermission(String permission) {
93 | this.permission = permission;
94 | }
95 |
96 | @Column(nullable=false)
97 | public boolean isValue() {
98 | return value;
99 | }
100 |
101 | public void setValue(boolean value) {
102 | this.value = value;
103 | }
104 |
105 | @Override
106 | public boolean equals(Object obj) {
107 | if (obj == this) return true;
108 | if (!(obj instanceof Entry)) return false;
109 | Entry o = (Entry)obj;
110 | return getEntity().equals(o.getEntity()) &&
111 | (getRegion() == null ? o.getRegion() == null : getRegion().equals(o.getRegion())) &&
112 | (getWorld() == null ? o.getWorld() == null : getWorld().equals(o.getWorld())) &&
113 | getPermission().equals(o.getPermission());
114 | }
115 |
116 | @Override
117 | public int hashCode() {
118 | int result = 17;
119 | result = 37 * result + getEntity().hashCode();
120 | result = 37 * result + (getRegion() == null ? 0 : getRegion().hashCode());
121 | result = 37 * result + (getWorld() == null ? 0 : getWorld().hashCode());
122 | result = 37 * result + getPermission().hashCode();
123 | return result;
124 | }
125 |
126 | @Override
127 | public String toString() {
128 | return String.format("%s%s%s -> %s",
129 | (getRegion() == null ? "" : getRegion().getName() + "/"),
130 | (getWorld() == null ? "" : getWorld().getName() + ":"),
131 | getPermission(),
132 | isValue());
133 | }
134 |
135 | }
136 |
--------------------------------------------------------------------------------
/src/main/java/org/tyrannyofheaven/bukkit/zPermissions/dao/DummyPermissionDao.java:
--------------------------------------------------------------------------------
1 | // Released to the public domain
2 | package org.tyrannyofheaven.bukkit.zPermissions.dao;
3 |
4 | import java.util.Collection;
5 |
6 | import org.tyrannyofheaven.bukkit.zPermissions.model.EntityMetadata;
7 | import org.tyrannyofheaven.bukkit.zPermissions.model.Entry;
8 | import org.tyrannyofheaven.bukkit.zPermissions.model.Inheritance;
9 | import org.tyrannyofheaven.bukkit.zPermissions.model.Membership;
10 | import org.tyrannyofheaven.bukkit.zPermissions.model.PermissionEntity;
11 | import org.tyrannyofheaven.bukkit.zPermissions.model.PermissionRegion;
12 | import org.tyrannyofheaven.bukkit.zPermissions.model.PermissionWorld;
13 |
14 | /*
15 | * Fairly straightforward, the PermissionDao is responsible for all CUD (Create,
16 | * Update, Delete) operations. Reading can also be handled here, but since reading
17 | * always involves reading the full store in one shot, it normally falls under
18 | * the purview of the matching StorageStrategy's init() & refresh() methods.
19 | *
20 | * There are a few rules to follow when implementing each method:
21 | * 1. NEVER block. If you must perform blocking I/O, do it asynchronously.
22 | * 2. Never modify the passed-in object.
23 | * 3. You may want to make a copy of any pertinent properties of the passed-in
24 | * object. It may not be wise to hold on to it, especially if acting async.
25 | *
26 | * There are at least two styles of implementation:
27 | * 1. Implement each method normally, e.g. createEntity() will actually perform
28 | * I/O to create that entity somewhere. AvajePermissionDao is an example.
29 | * 2. Each method simply sets a dirty flag. An asynchronous thread periodically
30 | * checks the dirty flag, and if dirty, will call InMemoryPermissionService's
31 | * getPlayer()/getGroups()/getWorlds()/getRegions() methods to get a snapshot
32 | * of the current state which is then written out somewhere. FilePermissionDao
33 | * is an example.
34 | *
35 | * Note, getPlayer()/getGroups() etc. should be in a single synchronized block,
36 | * synchronized on the InMemoryPermissionService instance. Also note that
37 | * the returned collections and objects by getPlayer() etc. MUST NEVER be
38 | * modified.
39 | *
40 | * Note, createRegion(), createWorld(), createEntity() should do nothing if the
41 | * object in question already exists.
42 | */
43 | public class DummyPermissionDao implements PermissionDao {
44 |
45 | @Override
46 | public void createRegion(PermissionRegion region) {
47 | }
48 |
49 | @Override
50 | public void createWorld(PermissionWorld world) {
51 | }
52 |
53 | @Override
54 | public void createEntity(PermissionEntity entity) {
55 | }
56 |
57 | @Override
58 | public void createOrUpdateEntry(Entry entry) {
59 | }
60 |
61 | @Override
62 | public void deleteEntry(Entry entry) {
63 | }
64 |
65 | @Override
66 | public void createOrUpdateMembership(Membership membership) {
67 | }
68 |
69 | @Override
70 | public void setEntityParent(PermissionEntity entity, PermissionEntity parent) {
71 | }
72 |
73 | @Override
74 | public void createOrUpdateInheritance(Inheritance inheritance) {
75 | }
76 |
77 | @Override
78 | public void deleteInheritance(Inheritance inheritance) {
79 | }
80 |
81 | @Override
82 | public void setEntityPriority(PermissionEntity entity, int priority) {
83 | }
84 |
85 | @Override
86 | public void deleteRegions(Collection regions) {
87 | }
88 |
89 | @Override
90 | public void deleteWorlds(Collection worlds) {
91 | }
92 |
93 | @Override
94 | public void deleteEntity(PermissionEntity entity) {
95 | }
96 |
97 | @Override
98 | public void deleteMembership(Membership membership) {
99 | }
100 |
101 | @Override
102 | public void createOrUpdateMetadata(EntityMetadata metadata) {
103 | }
104 |
105 | @Override
106 | public void deleteMetadata(EntityMetadata metadata) {
107 | }
108 |
109 | @Override
110 | public void updateDisplayName(PermissionEntity entity) {
111 | }
112 |
113 | @Override
114 | public void updateDisplayName(Membership membership) {
115 | }
116 |
117 | }
118 |
--------------------------------------------------------------------------------
/src/main/java/org/tyrannyofheaven/bukkit/zPermissions/vault/ChatCompatibility.java:
--------------------------------------------------------------------------------
1 | package org.tyrannyofheaven.bukkit.zPermissions.vault;
2 |
3 | import net.milkbowl.vault.chat.Chat;
4 | import net.milkbowl.vault.permission.Permission;
5 |
6 | import org.bukkit.Bukkit;
7 | import org.bukkit.OfflinePlayer;
8 |
9 | // Implementation of all non-OfflinePlayer-based player methods
10 | public abstract class ChatCompatibility extends Chat {
11 |
12 | public ChatCompatibility(Permission perms) {
13 | super(perms);
14 | }
15 |
16 | @Override
17 | public String getPlayerPrefix(String world, String player) {
18 | OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player);
19 | if (offlinePlayer == null) return "";
20 | return getPlayerPrefix(world, offlinePlayer);
21 | }
22 |
23 | @Override
24 | public void setPlayerPrefix(String world, String player, String prefix) {
25 | OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player);
26 | if (offlinePlayer == null) return;
27 | setPlayerPrefix(world, offlinePlayer, prefix);
28 | }
29 |
30 | @Override
31 | public String getPlayerSuffix(String world, String player) {
32 | OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player);
33 | if (offlinePlayer == null) return "";
34 | return getPlayerSuffix(world, offlinePlayer);
35 | }
36 |
37 | @Override
38 | public void setPlayerSuffix(String world, String player, String suffix) {
39 | OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player);
40 | if (offlinePlayer == null) return;
41 | setPlayerSuffix(world, offlinePlayer, suffix);
42 | }
43 |
44 | @Override
45 | public int getPlayerInfoInteger(String world, String player, String node, int defaultValue) {
46 | OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player);
47 | if (offlinePlayer == null) return defaultValue;
48 | return getPlayerInfoInteger(world, offlinePlayer, node, defaultValue);
49 | }
50 |
51 | @Override
52 | public void setPlayerInfoInteger(String world, String player, String node, int value) {
53 | OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player);
54 | if (offlinePlayer == null) return;
55 | setPlayerInfoInteger(world, offlinePlayer, node, value);
56 | }
57 |
58 | @Override
59 | public double getPlayerInfoDouble(String world, String player, String node, double defaultValue) {
60 | OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player);
61 | if (offlinePlayer == null) return defaultValue;
62 | return getPlayerInfoDouble(world, offlinePlayer, node, defaultValue);
63 | }
64 |
65 | @Override
66 | public void setPlayerInfoDouble(String world, String player, String node, double value) {
67 | OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player);
68 | if (offlinePlayer == null) return;
69 | setPlayerInfoDouble(world, offlinePlayer, node, value);
70 | }
71 |
72 | @Override
73 | public boolean getPlayerInfoBoolean(String world, String player, String node, boolean defaultValue) {
74 | OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player);
75 | if (offlinePlayer == null) return defaultValue;
76 | return getPlayerInfoBoolean(world, offlinePlayer, node, defaultValue);
77 | }
78 |
79 | @Override
80 | public void setPlayerInfoBoolean(String world, String player, String node, boolean value) {
81 | OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player);
82 | if (offlinePlayer == null) return;
83 | setPlayerInfoBoolean(world, offlinePlayer, node, value);
84 | }
85 |
86 | @Override
87 | public String getPlayerInfoString(String world, String player, String node, String defaultValue) {
88 | OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player);
89 | if (offlinePlayer == null) return defaultValue;
90 | return getPlayerInfoString(world, offlinePlayer, node, defaultValue);
91 | }
92 |
93 | @Override
94 | public void setPlayerInfoString(String world, String player, String node, String value) {
95 | OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player);
96 | if (offlinePlayer == null) return;
97 | setPlayerInfoString(world, offlinePlayer, node, value);
98 | }
99 |
100 | }
101 |
--------------------------------------------------------------------------------
/etc/gen-test-dump.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | import random
4 |
5 |
6 | WORLDS = [None] * 8 + ['world', 'world_nether', 'creative', 'hardcore']
7 |
8 | REGIONS = [None] * 20 + ['Region%d' % i for i in range(10)]
9 |
10 | NUM_PLAYERS = 100
11 |
12 | NUM_PERMISSIONS_PER_PLAYER = 50
13 |
14 | NUM_GROUPS = (3, 13, 23, 31, 41)
15 |
16 | NUM_PERMISSIONS_PER_GROUP = 50
17 |
18 | NUM_PLAYERS_PER_GROUP = 50
19 |
20 | PLAYER_MEMBER_POOL_SIZE = 1000
21 |
22 | METADATA_TYPES = [str, int, float, bool]
23 |
24 | STR_ALPHABET = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
25 |
26 | NUM_METADATA_PER_PLAYER = 10
27 |
28 | NUM_METADATA_PER_GROUP = 10
29 |
30 |
31 | groups_at_depth = []
32 | for i in range(len(NUM_GROUPS)):
33 | groups_at_depth.append([])
34 |
35 |
36 | def generate_metadata(name, is_group, count):
37 | for i in range(count):
38 | type = METADATA_TYPES[random.randint(0, len(METADATA_TYPES) - 1)]
39 | suffix = ''
40 | if type is str:
41 | length = random.randint(5,20)
42 | value = []
43 | for j in range(length):
44 | value.append(STR_ALPHABET[random.randint(0, len(STR_ALPHABET) - 1)])
45 | value = ''.join(value)
46 | elif type is int:
47 | suffix = 'int'
48 | value = random.randint(-10000, 10000)
49 | elif type is float:
50 | suffix = 'real'
51 | value = random.random() * 20000.0 - 10000.0
52 | elif type is bool:
53 | suffix = 'bool'
54 | value = random.randint(0,1)
55 | if value == 0:
56 | value = 'false'
57 | else:
58 | value = 'true'
59 | print('permissions %s %s metadata set%s metadata.%s.%d %s' % (
60 | is_group and 'group' or 'player',
61 | name,
62 | suffix,
63 | name.lower(),
64 | i,
65 | value))
66 |
67 |
68 | def generate_permissions(name, is_group, count):
69 | for i in range(count):
70 | region = REGIONS[random.randint(0, len(REGIONS) - 1)]
71 | if region is None:
72 | region = ''
73 | else:
74 | region += '/'
75 | world = WORLDS[random.randint(0, len(WORLDS) - 1)]
76 | if world is None:
77 | world = ''
78 | else:
79 | world += ':'
80 | print('permissions %s %s set %s%spermission.%s.%d true' % (
81 | is_group and 'group' or 'player',
82 | name,
83 | region.lower(),
84 | world.lower(),
85 | name.lower(),
86 | i))
87 |
88 |
89 | def generate_group(name, depth):
90 | if depth == 0:
91 | # Nothing special
92 | print('permissions group %s create' % name)
93 | else:
94 | print('permissions group %s create' % name)
95 | # Pick random parent of previous depth
96 | potential_parents = groups_at_depth[depth - 1]
97 | parent = potential_parents[random.randint(0, len(potential_parents) - 1)]
98 | print('permissions group %s setparents %s' % (name, parent))
99 | print('permissions group %s setweight 0' % name)
100 | assert name not in groups_at_depth[depth]
101 | groups_at_depth[depth].append(name)
102 |
103 |
104 | def generate_members(name, count):
105 | members = set([])
106 | while len(members) < count:
107 | p = random.randint(0, PLAYER_MEMBER_POOL_SIZE - 1)
108 | if p in members:
109 | continue
110 | members.add(p)
111 | print('permissions group %s add testplayer%d' % (name, p))
112 |
113 |
114 | def main():
115 | for p in range(NUM_PLAYERS):
116 | generate_permissions('TestPlayer%d' % p, False,
117 | NUM_PERMISSIONS_PER_PLAYER)
118 | generate_metadata('TestPlayer%d' % p, False, NUM_METADATA_PER_PLAYER)
119 |
120 | group_count = 0
121 | for depth, num_at_depth in enumerate(NUM_GROUPS):
122 | for g in range(num_at_depth):
123 | name = 'TestGroup%d' % group_count
124 | group_count += 1
125 | generate_group(name, depth)
126 | generate_permissions(name, True, NUM_PERMISSIONS_PER_GROUP)
127 | generate_members(name, NUM_PLAYERS_PER_GROUP)
128 | generate_metadata(name, True, NUM_METADATA_PER_GROUP)
129 |
130 |
131 | if __name__ == '__main__':
132 | main()
133 |
--------------------------------------------------------------------------------
/src/main/java/org/tyrannyofheaven/bukkit/zPermissions/util/RefreshTask.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012 ZerothAngel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.tyrannyofheaven.bukkit.zPermissions.util;
17 |
18 | import static org.tyrannyofheaven.bukkit.util.ToHLoggingUtils.debug;
19 | import static org.tyrannyofheaven.bukkit.util.ToHLoggingUtils.error;
20 | import static org.tyrannyofheaven.bukkit.util.ToHLoggingUtils.warn;
21 | import static org.tyrannyofheaven.bukkit.util.ToHStringUtils.delimitedString;
22 |
23 | import java.util.Collection;
24 | import java.util.LinkedHashSet;
25 | import java.util.LinkedList;
26 | import java.util.Queue;
27 | import java.util.Set;
28 | import java.util.UUID;
29 |
30 | import org.bukkit.Bukkit;
31 | import org.bukkit.plugin.Plugin;
32 | import org.tyrannyofheaven.bukkit.zPermissions.RefreshCause;
33 | import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsCore;
34 |
35 | /**
36 | * Periodically calls {@link ZPermissionsCore#refreshPlayer(UUID, RefreshCause)} on the
37 | * given queue of players.
38 | *
39 | * @author zerothangel
40 | */
41 | public class RefreshTask implements Runnable {
42 |
43 | private final ZPermissionsCore core;
44 |
45 | private final Plugin plugin;
46 |
47 | private int delay;
48 |
49 | private final Queue playersToRefresh = new LinkedList<>(); // synchronized on this
50 |
51 | private int taskId = -1; // synchronized on this
52 |
53 | public RefreshTask(ZPermissionsCore core, Plugin plugin) {
54 | this.core = core;
55 | this.plugin = plugin;
56 | }
57 |
58 | public void setDelay(int delay) {
59 | if (delay < 0)
60 | delay = 0;
61 | this.delay = delay;
62 | }
63 |
64 | public synchronized void start(Collection playerUuids) {
65 | if (playerUuids == null || playerUuids.isEmpty())
66 | return; // Nothing to do
67 |
68 | // Build a set to maintain uniqueness
69 | Set nextPlayersToRefresh = new LinkedHashSet<>(playersToRefresh);
70 |
71 | // Remember who to refresh
72 | nextPlayersToRefresh.addAll(playerUuids);
73 |
74 | // Replace queue with set
75 | playersToRefresh.clear();
76 | playersToRefresh.addAll(nextPlayersToRefresh);
77 |
78 | // Schedule task if not already scheduled
79 | if (taskId < 0) {
80 | debug(plugin, "Scheduling background refresh");
81 | scheduleTask();
82 | }
83 | }
84 |
85 | private void scheduleTask() {
86 | if ((taskId = Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, this, (long)delay)) < 0) {
87 | error(plugin, "Failed to schedule RefreshTask! Remaining players: %s", delimitedString(", ", playersToRefresh));
88 | }
89 | }
90 |
91 | public synchronized void stop() {
92 | if (taskId > -1) {
93 | warn(plugin, "RefreshTask cancelled prematurely! Remaining players: %s", delimitedString(", ", playersToRefresh));
94 | Bukkit.getScheduler().cancelTask(taskId);
95 | taskId = -1;
96 | }
97 | }
98 |
99 | @Override
100 | public synchronized void run() {
101 | taskId = -1;
102 |
103 | if (!playersToRefresh.isEmpty()) {
104 | UUID playerToRefresh = playersToRefresh.remove();
105 |
106 | // Refresh single player
107 | core.invalidateMetadataCache("ignored", playerToRefresh, false);
108 | core.refreshPlayer(playerToRefresh, RefreshCause.GROUP_CHANGE); // NB Assumes all who call start() are doing so for group- or server-wide changes
109 | }
110 |
111 | // Schedule next player
112 | if (!playersToRefresh.isEmpty()) {
113 | scheduleTask();
114 | }
115 | else
116 | debug(plugin, "Done doing background refresh!");
117 | }
118 |
119 | }
120 |
--------------------------------------------------------------------------------
/src/main/java/org/tyrannyofheaven/bukkit/zPermissions/region/FactionsRegionStrategy.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 ZerothAngel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.tyrannyofheaven.bukkit.zPermissions.region;
17 |
18 | import java.util.Collections;
19 | import java.util.Set;
20 |
21 | import org.bukkit.Bukkit;
22 | import org.bukkit.Location;
23 | import org.bukkit.entity.Player;
24 | import org.bukkit.event.EventHandler;
25 | import org.bukkit.event.Listener;
26 | import org.bukkit.event.server.PluginEnableEvent;
27 | import org.bukkit.plugin.Plugin;
28 | import org.tyrannyofheaven.bukkit.util.ToHLoggingUtils;
29 | import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsCore;
30 |
31 | import com.massivecraft.factions.Rel;
32 | import com.massivecraft.factions.entity.BoardColls;
33 | import com.massivecraft.factions.entity.Faction;
34 | import com.massivecraft.factions.entity.UPlayer;
35 | import com.massivecraft.mcore.ps.PS;
36 |
37 | /**
38 | * RegionStrategy implementation for Factions.
39 | *
40 | * @author zerothangel
41 | */
42 | public class FactionsRegionStrategy implements RegionStrategy, Listener {
43 |
44 | private static final String RM_PLUGIN_NAME = "Factions";
45 |
46 | private final Plugin plugin;
47 |
48 | private final ZPermissionsCore core;
49 |
50 | private boolean factionsEnabled;
51 |
52 | public FactionsRegionStrategy(Plugin plugin, ZPermissionsCore core) {
53 | this.plugin = plugin;
54 | this.core = core;
55 | }
56 |
57 | @Override
58 | public String getName() {
59 | return RM_PLUGIN_NAME;
60 | }
61 |
62 | @Override
63 | public boolean isPresent() {
64 | return Bukkit.getPluginManager().getPlugin(RM_PLUGIN_NAME) != null;
65 | }
66 |
67 | @Override
68 | public void init() {
69 | detectFactionsPlugin();
70 | if (!isEnabled()) {
71 | // Not yet loaded, listen for its enable event
72 | Bukkit.getPluginManager().registerEvents(this, plugin);
73 | }
74 | }
75 |
76 | @Override
77 | public boolean isEnabled() {
78 | return factionsEnabled;
79 | }
80 |
81 | @Override
82 | public void shutdown() {
83 | factionsEnabled = false;
84 | }
85 |
86 | @Override
87 | public Set getRegions(Location location, Player player) {
88 | if (isEnabled()) {
89 | // This indirection is necessary to avoid NoClassDefErrors when
90 | // Factions is not present.
91 | return FactionsHelper.getRegions(location, player);
92 | }
93 | return Collections.emptySet();
94 | }
95 |
96 | @EventHandler
97 | public void onPluginEnable(PluginEnableEvent event) {
98 | if (!isEnabled() && RM_PLUGIN_NAME.equals(event.getPlugin().getName())) {
99 | detectFactionsPlugin();
100 | if (isEnabled()) {
101 | ToHLoggingUtils.log(plugin, "%s region support enabled.", getName());
102 | core.refreshPlayers();
103 | }
104 | }
105 | }
106 |
107 | private void detectFactionsPlugin() {
108 | Plugin plugin = Bukkit.getPluginManager().getPlugin(RM_PLUGIN_NAME);
109 | factionsEnabled = plugin.isEnabled();
110 | }
111 |
112 | private static class FactionsHelper {
113 |
114 | private static Set getRegions(Location location, Player player) {
115 | Faction faction = BoardColls.get().getFactionAt(PS.valueOf(location));
116 | UPlayer uplayer = UPlayer.get(player);
117 | if (faction != null && uplayer != null) {
118 | Rel rel = uplayer.getRelationTo(faction);
119 | if (rel != null) {
120 | return Collections.singleton(rel.name().toLowerCase());
121 | }
122 | }
123 | return Collections.emptySet();
124 | }
125 |
126 | }
127 |
128 | }
129 |
--------------------------------------------------------------------------------
/doc/admins.md:
--------------------------------------------------------------------------------
1 | # For Server Admins #
2 |
3 | ## Database Setup ##
4 |
5 | As mentioned, zPermissions does **NOT** work with SQLite, the default database used by CraftBukkit. If you would like something similar to SQLite (a Java-based, embedded database), I recommend [H2](http://www.h2database.com/).
6 |
7 | Example bukkit.yml settings follow.
8 |
9 | ### MySQL ###
10 |
11 | MySQL is probably the easiest database to use, especially since CraftBukkit already includes its driver. The relevant settings in your bukkit.yml would look something like:
12 |
13 | database:
14 | username: bukkit
15 | isolation: SERIALIZABLE
16 | driver: com.mysql.jdbc.Driver
17 | password: walrus
18 | url: jdbc:mysql://127.0.0.1:3306/{NAME}
19 |
20 | If you do use the above URL (one database per plugin — extremely recommended), be sure to create a database for zPermissions before using it.
21 |
22 | ### H2 ###
23 |
24 | Setting up CraftBukkit to use H2 is bit involved. One way to do it is:
25 |
26 | 1. Put h2.jar in the same directory as craftbukkit.jar
27 |
28 | 2. Change the way you launch CraftBukkit so you add h2.jar to the Java classpath. Something like:
29 |
30 | java {your-normal-Java-options} -cp craftbukkit.jar:h2.jar org.bukkit.craftbukkit.Main
31 |
32 | 3. Your bukkit.yml database settings would look something like:
33 |
34 | database:
35 | username: bukkit
36 | isolation: SERIALIZABLE
37 | driver: org.h2.Driver
38 | password: walrus
39 | url: jdbc:h2:{DIR}{NAME}
40 |
41 | ### PostgreSQL ###
42 |
43 | Setting up for PostgreSQL is similar to H2.
44 |
45 | 1. Put postgresql.jar in the same directory as craftbukkit.jar
46 |
47 | 2. Change the way you launch CraftBukkit so you add postgresql.jar to the Java classpath. Something like:
48 |
49 | java {your-normal-Java-options} -cp craftbukkit.jar:postgresql.jar org.bukkit.craftbukkit.Main
50 |
51 | 3. Your bukkit.yml database settings would look something like:
52 |
53 | database:
54 | username: bukkit
55 | isolation: SERIALIZABLE
56 | driver: org.postgresql.Driver
57 | password: walrus
58 | url: jdbc:postgresql://127.0.0.1/{NAME}
59 |
60 | As in the MySQL case, this configuration assigns a database to each plugin. Be sure to create one for zPermissions ahead of time and **remember** PostgreSQL's names are case-sensitive, so be sure to use quotes:
61 |
62 | create database 'zPermissions' with owner bukkit;
63 |
64 | ### Others ###
65 |
66 | Other databases will probably work, provided it's supported by [Avaje Ebean](http://avaje.org/) and zPermissions's data model. The setup will probably be similar to PostgreSQL.
67 |
68 | ## Using a Test Database ##
69 |
70 | If your test Bukkit server happens to use the same database server as your production Bukkit server, you can specify a different database by simply prefixing or suffixing {NAME} in the URL with a string of your choice. For example:
71 |
72 | database:
73 | ... omitted ...
74 | url: jdbc:mysql://127.0.0.1:3306/{NAME}_test
75 |
76 | zPermissions on your test server would then use the database named zPermissions_test. Note that this will, of course, affect other plugins that also use Bukkit persistence.
77 |
78 | ## Permission Entry ##
79 |
80 | The fact that zPermissions only has an SQL backend means there are only two ways to enter permissions:
81 |
82 | 1. Through the command line (console or in-game... I recommend console)
83 | 2. If you're masochistic enough, INSERTing directly into zPermissions's SQL tables.
84 |
85 | I strongly recommend taking advantage of CraftBukkit's `permissions.yml` file (found in the server root), where you can define custom permissions with any number of children. For example:
86 |
87 | server.basics:
88 | description: Basic permissions for this server
89 | children:
90 | commandbook.motd: true
91 | commandbook.rules: true
92 | commandbook.say: true
93 | commandbook.say.me: true
94 | commandbook.who: true
95 |
96 | With that, when you give the `server.basics` permission to a player or group, that player or group automatically gets those 5 commandbook permissions.
97 |
98 | If you have a well-organized `permissions.yml`, you would ideally only need to assign a handful of permissions per group or player.
99 |
100 | ### There is Another... ###
101 |
102 | An advanced alternative is to abuse/take advantage of zPermissions's import feature. zPermissions's dump files are nothing more than text files with zPermissions commands. So you can enter all your commands in a file ahead of time, place it in zPermissions's dump directory (by default, the `zPermissions-dumps` directory off the server root), and then run the `/permissions import ` command.
103 |
104 | But note, your database must be absolutely empty (no players or groups). So either purge everyone/everything or drop zPermissions's tables or database...
105 |
--------------------------------------------------------------------------------
/src/main/java/org/tyrannyofheaven/bukkit/zPermissions/region/WorldGuardRegionStrategy.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 ZerothAngel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.tyrannyofheaven.bukkit.zPermissions.region;
17 |
18 | import java.util.ArrayList;
19 | import java.util.Collections;
20 | import java.util.LinkedHashSet;
21 | import java.util.List;
22 | import java.util.Set;
23 |
24 | import org.bukkit.Bukkit;
25 | import org.bukkit.Location;
26 | import org.bukkit.entity.Player;
27 | import org.bukkit.event.EventHandler;
28 | import org.bukkit.event.Listener;
29 | import org.bukkit.event.server.PluginEnableEvent;
30 | import org.bukkit.plugin.Plugin;
31 | import org.tyrannyofheaven.bukkit.util.ToHLoggingUtils;
32 | import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsCore;
33 |
34 | import com.google.common.collect.Iterables;
35 | import com.sk89q.worldedit.bukkit.BukkitAdapter;
36 | import com.sk89q.worldguard.WorldGuard;
37 | import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
38 | import com.sk89q.worldguard.protection.ApplicableRegionSet;
39 | import com.sk89q.worldguard.protection.regions.ProtectedRegion;
40 |
41 | /**
42 | * RegionStrategy implementation for WorldGuard.
43 | *
44 | * @author zerothangel
45 | */
46 | public class WorldGuardRegionStrategy implements RegionStrategy, Listener {
47 |
48 | private static final String RM_PLUGIN_NAME = "WorldGuard";
49 |
50 | private final Plugin plugin;
51 |
52 | private final ZPermissionsCore core;
53 |
54 | private WorldGuardPlugin worldGuardPlugin;
55 |
56 | public WorldGuardRegionStrategy(Plugin plugin, ZPermissionsCore core) {
57 | this.plugin = plugin;
58 | this.core = core;
59 | }
60 |
61 | @Override
62 | public String getName() {
63 | return RM_PLUGIN_NAME;
64 | }
65 |
66 | @Override
67 | public boolean isPresent() {
68 | return Bukkit.getPluginManager().getPlugin(RM_PLUGIN_NAME) != null;
69 | }
70 |
71 | @Override
72 | public void init() {
73 | detectWorldGuardPlugin();
74 | if (!isEnabled()) {
75 | // Not yet loaded, listen for its enable event
76 | Bukkit.getPluginManager().registerEvents(this, plugin);
77 | }
78 | }
79 |
80 | @Override
81 | public boolean isEnabled() {
82 | return worldGuardPlugin != null;
83 | }
84 |
85 | @Override
86 | public void shutdown() {
87 | worldGuardPlugin = null;
88 | }
89 |
90 | @Override
91 | public Set getRegions(Location location, Player player) {
92 | if (isEnabled()) {
93 | ApplicableRegionSet ars = WorldGuard.getInstance().getPlatform().getRegionContainer()
94 | .createQuery().getApplicableRegions(BukkitAdapter.adapt(location));
95 | // Note, sorted from high to low priority, i.e. reverse application order
96 | List sorted = new ArrayList<>();
97 | Iterables.addAll(sorted, ars);
98 | Collections.reverse(sorted); // Now it is in application order
99 |
100 | Set result = new LinkedHashSet<>(); // Preserve ordering for resolver
101 | for (ProtectedRegion pr : sorted) {
102 | // Ignore global region
103 | if (!"__global__".equals(pr.getId())) // NB: Hardcoded and not available as constant in WorldGuard
104 | result.add(pr.getId().toLowerCase());
105 | }
106 | return result;
107 | }
108 | return Collections.emptySet();
109 | }
110 |
111 | @EventHandler
112 | public void onPluginEnable(PluginEnableEvent event) {
113 | if (!isEnabled() && RM_PLUGIN_NAME.equals(event.getPlugin().getName())) {
114 | detectWorldGuardPlugin();
115 | if (isEnabled()) {
116 | ToHLoggingUtils.log(plugin, "%s region support enabled.", getName());
117 | core.refreshPlayers();
118 | }
119 | }
120 | }
121 |
122 | private void detectWorldGuardPlugin() {
123 | Plugin plugin = Bukkit.getPluginManager().getPlugin(RM_PLUGIN_NAME);
124 | if (plugin instanceof WorldGuardPlugin && plugin.isEnabled()) {
125 | worldGuardPlugin = (WorldGuardPlugin)plugin;
126 | }
127 | else {
128 | worldGuardPlugin = null;
129 | }
130 | }
131 |
132 | }
133 |
--------------------------------------------------------------------------------
/src/main/java/org/tyrannyofheaven/bukkit/zPermissions/storage/DummyStorageStrategy.java:
--------------------------------------------------------------------------------
1 | // Released to the public domain
2 | package org.tyrannyofheaven.bukkit.zPermissions.storage;
3 |
4 | import java.util.Map;
5 |
6 | import org.tyrannyofheaven.bukkit.util.transaction.NullTransactionStrategy;
7 | import org.tyrannyofheaven.bukkit.util.transaction.TransactionStrategy;
8 | import org.tyrannyofheaven.bukkit.zPermissions.dao.DummyPermissionDao;
9 | import org.tyrannyofheaven.bukkit.zPermissions.dao.InMemoryPermissionService;
10 | import org.tyrannyofheaven.bukkit.zPermissions.dao.PermissionService;
11 |
12 | /*
13 | * This is the top-level storage interface. A custom implementation can be used
14 | * by setting the custom-storage-strategy option in zPermissions' config.yml.
15 | *
16 | * To be used this way, this class must have a no-arg constructor.
17 | *
18 | * Note that init() and refresh() are usually responsible for loading from
19 | * whatever store you use. However, loading can be delegated to the PermissionDao
20 | * implementation, if it makes more sense to do it that way (and it usually does).
21 | *
22 | * Loading usually consists of:
23 | * 1. Instantiating a new MemoryState instance
24 | * 2. Using the static methods in InMemoryPermissionService to create entities
25 | * (and filling out their permissions and metadata) and memberships. Note,
26 | * letter case matters for certain properties: Entry#permission, EntityMetadata#name,
27 | * Membership#member. When in doubt, check the loading code in AvajePermissionDao &
28 | * FilePermissionDao.
29 | * 3. Calling your InMemoryPermissionService instance's setMemoryState() method.
30 | *
31 | * Also see javadocs for StorageStrategy.
32 | */
33 | public class DummyStorageStrategy implements StorageStrategy {
34 |
35 | private final InMemoryPermissionService permissionService = new InMemoryPermissionService();
36 |
37 | private final DummyPermissionDao permissionDao = new DummyPermissionDao(); // You may want to pass permissionService to the constructor
38 |
39 | private final TransactionStrategy transactionStrategy = new NullTransactionStrategy();
40 |
41 | public DummyStorageStrategy() {
42 | permissionService.setPermissionDao(permissionDao);
43 | }
44 |
45 | @Override
46 | public void init(Map configMap) {
47 | /*
48 | * Perform initialization. Feel free to use blocking I/O.
49 | * Simple implementations may simply call refresh(true, null)
50 | */
51 | }
52 |
53 | @Override
54 | public void shutdown() {
55 | /*
56 | * Perform cleanup or final I/O. Can also block.
57 | */
58 | }
59 |
60 | @Override
61 | public void refresh(boolean force, Runnable finishTask) {
62 | /*
63 | * Normal calls to this should NEVER block. (However, if called from init()
64 | * above, it should block so initialization does not continue until
65 | * everything has loaded. See AvajeStorageStrategy for an example of how
66 | * this is handled.)
67 | *
68 | * Only execute finishTask if in-memory representation changed
69 | * (i.e. InMemoryPermissionService#setMemoryState() was called) and
70 | * finishTask != null
71 | *
72 | * If you do execute finishTask, remember the contract dictates that it
73 | * must execute in the main thread.
74 | */
75 | }
76 |
77 | @Override
78 | public PermissionService getPermissionService() {
79 | /*
80 | * Should return your PermissionService implementation, which should
81 | * basically be an InMemoryPermissionService instance (unless you
82 | * feel like re-implementing THAT interface)
83 | */
84 | return permissionService;
85 | }
86 |
87 | /*
88 | * In the olden days (pre-1.0), there were two distinct TransactionStrategy
89 | * instances. However, if you use InMemoryPermissionService as your
90 | * PermissionService implementation, the distinction doesn't matter anymore.
91 | *
92 | * Both getters should return the same instance, and it will usually be
93 | * one of two implementations:
94 | *
95 | * NullTransactionStrategy - If you don't actually do any I/O in PermissionDao, e.g.
96 | * you just set a dirty flag and perform I/O elsewhere (similar to FilePermissionDao).
97 | * AsyncTransactionStrategy - If your store is transactional (e.g. requires a real
98 | * TransactionStrategy implementation) and your I/O would normally block.
99 | * Databases fall under this. (Also see AvajePermissionDao.)
100 | *
101 | * If your I/O is blocking but not transactional, you can probably get away
102 | * with using NullTransactionStrategy.
103 | */
104 |
105 | @Override
106 | public TransactionStrategy getTransactionStrategy() {
107 | return transactionStrategy;
108 | }
109 |
110 | @Override
111 | public TransactionStrategy getRetryingTransactionStrategy() {
112 | return transactionStrategy;
113 | }
114 |
115 | }
116 |
--------------------------------------------------------------------------------
/src/main/java/org/tyrannyofheaven/bukkit/zPermissions/model/EntityMetadata.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 ZerothAngel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.tyrannyofheaven.bukkit.zPermissions.model;
17 |
18 | import javax.persistence.Column;
19 | import javax.persistence.Entity;
20 | import javax.persistence.Id;
21 | import javax.persistence.JoinColumn;
22 | import javax.persistence.ManyToOne;
23 | import javax.persistence.Table;
24 | import javax.persistence.Transient;
25 | import javax.persistence.UniqueConstraint;
26 |
27 | @Entity
28 | @Table(name="metadata")
29 | @UniqueConstraint(columnNames={"entity_id", "name"})
30 | public class EntityMetadata {
31 |
32 | private Long id;
33 |
34 | private PermissionEntity entity;
35 |
36 | private String name;
37 |
38 | private String stringValue;
39 |
40 | private Long integerValue;
41 |
42 | private Double realValue;
43 |
44 | private Boolean booleanValue;
45 |
46 | @Id
47 | public Long getId() {
48 | return id;
49 | }
50 |
51 | public void setId(Long id) {
52 | this.id = id;
53 | }
54 |
55 | @JoinColumn(name="entity_id")
56 | @ManyToOne(optional=false)
57 | public PermissionEntity getEntity() {
58 | return entity;
59 | }
60 |
61 | public void setEntity(PermissionEntity entity) {
62 | this.entity = entity;
63 | }
64 |
65 | @Column(nullable=false)
66 | public String getName() {
67 | return name;
68 | }
69 |
70 | public void setName(String name) {
71 | this.name = name;
72 | }
73 |
74 | public String getStringValue() {
75 | return stringValue;
76 | }
77 |
78 | public void setStringValue(String stringValue) {
79 | this.stringValue = stringValue;
80 | }
81 |
82 | public Long getIntegerValue() {
83 | return integerValue;
84 | }
85 |
86 | public void setIntegerValue(Long integerValue) {
87 | this.integerValue = integerValue;
88 | }
89 |
90 | public Double getRealValue() {
91 | return realValue;
92 | }
93 |
94 | public void setRealValue(Double realValue) {
95 | this.realValue = realValue;
96 | }
97 |
98 | public Boolean getBooleanValue() {
99 | return booleanValue;
100 | }
101 |
102 | public void setBooleanValue(Boolean booleanValue) {
103 | this.booleanValue = booleanValue;
104 | }
105 |
106 | @Transient
107 | public Object getValue() {
108 | if (getStringValue() != null)
109 | return getStringValue();
110 | else if (getIntegerValue() != null)
111 | return getIntegerValue();
112 | else if (getRealValue() != null)
113 | return getRealValue();
114 | else if (getBooleanValue() != null)
115 | return getBooleanValue();
116 | else
117 | return null;
118 | }
119 |
120 | public void setValue(Object value) {
121 | setStringValue(null);
122 | setIntegerValue(null);
123 | setRealValue(null);
124 | setBooleanValue(null);
125 |
126 | if (value instanceof String) {
127 | setStringValue((String)value);
128 | }
129 | else if (value instanceof Integer) {
130 | setIntegerValue(((Number)value).longValue());
131 | }
132 | else if (value instanceof Long) {
133 | setIntegerValue((Long)value);
134 | }
135 | else if (value instanceof Float) {
136 | setRealValue(((Number)value).doubleValue());
137 | }
138 | else if (value instanceof Double) {
139 | setRealValue((Double)value);
140 | }
141 | else if (value instanceof Boolean) {
142 | setBooleanValue((Boolean)value);
143 | }
144 | else
145 | throw new IllegalArgumentException("Invalid metadata value");
146 | }
147 |
148 | @Override
149 | public boolean equals(Object obj) {
150 | if (obj == this) return true;
151 | if (!(obj instanceof EntityMetadata)) return false;
152 | EntityMetadata o = (EntityMetadata)obj;
153 | return getEntity().equals(o.getEntity()) &&
154 | getName().equals(o.getName());
155 | }
156 |
157 | @Override
158 | public int hashCode() {
159 | int result = 17;
160 | result = 37 * result + getEntity().hashCode();
161 | result = 37 * result + getName().hashCode();
162 | return result;
163 | }
164 |
165 | @Override
166 | public String toString() {
167 | return String.format("EntityMetadata[%s]", getName());
168 | }
169 |
170 | }
171 |
--------------------------------------------------------------------------------
/src/main/java/org/tyrannyofheaven/bukkit/zPermissions/util/GlobPattern.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Licensed to the Apache Software Foundation (ASF) under one
3 | * or more contributor license agreements. See the NOTICE file
4 | * distributed with this work for additional information
5 | * regarding copyright ownership. The ASF licenses this file
6 | * to you under the Apache License, Version 2.0 (the
7 | * "License"); you may not use this file except in compliance
8 | * with the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package org.tyrannyofheaven.bukkit.zPermissions.util;
20 |
21 | import java.util.regex.Pattern;
22 | import java.util.regex.PatternSyntaxException;
23 |
24 | /**
25 | * A class for POSIX glob pattern with brace expansions.
26 | */
27 | public class GlobPattern {
28 | private static final char BACKSLASH = '\\';
29 | private Pattern compiled;
30 | private boolean hasWildcard = false;
31 |
32 | /**
33 | * Construct the glob pattern object with a glob pattern string
34 | * @param globPattern the glob pattern string
35 | */
36 | public GlobPattern(String globPattern) {
37 | set(globPattern);
38 | }
39 |
40 | /**
41 | * @return the compiled pattern
42 | */
43 | public Pattern compiled() {
44 | return compiled;
45 | }
46 |
47 | /**
48 | * Compile glob pattern string
49 | * @param globPattern the glob pattern
50 | * @return the pattern object
51 | */
52 | public static Pattern compile(String globPattern) {
53 | return new GlobPattern(globPattern).compiled();
54 | }
55 |
56 | /**
57 | * Match input against the compiled glob pattern
58 | * @param s input chars
59 | * @return true for successful matches
60 | */
61 | public boolean matches(CharSequence s) {
62 | return compiled.matcher(s).matches();
63 | }
64 |
65 | /**
66 | * Set and compile a glob pattern
67 | * @param glob the glob pattern string
68 | */
69 | public void set(String glob) {
70 | StringBuilder regex = new StringBuilder();
71 | int setOpen = 0;
72 | int curlyOpen = 0;
73 | int len = glob.length();
74 | hasWildcard = false;
75 |
76 | for (int i = 0; i < len; i++) {
77 | char c = glob.charAt(i);
78 |
79 | switch (c) {
80 | case BACKSLASH:
81 | if (++i >= len) {
82 | error("Missing escaped character", glob, i);
83 | }
84 | regex.append(c).append(glob.charAt(i));
85 | continue;
86 | case '.':
87 | case '$':
88 | case '(':
89 | case ')':
90 | case '|':
91 | case '+':
92 | // escape regex special chars that are not glob special chars
93 | regex.append(BACKSLASH);
94 | break;
95 | case '*':
96 | regex.append('.');
97 | hasWildcard = true;
98 | break;
99 | case '?':
100 | regex.append('.');
101 | hasWildcard = true;
102 | continue;
103 | case '{': // start of a group
104 | regex.append("(?:"); // non-capturing
105 | curlyOpen++;
106 | hasWildcard = true;
107 | continue;
108 | case ',':
109 | regex.append(curlyOpen > 0 ? '|' : c);
110 | continue;
111 | case '}':
112 | if (curlyOpen > 0) {
113 | // end of a group
114 | curlyOpen--;
115 | regex.append(")");
116 | continue;
117 | }
118 | break;
119 | case '[':
120 | if (setOpen > 0) {
121 | error("Unclosed character class", glob, i);
122 | }
123 | setOpen++;
124 | hasWildcard = true;
125 | break;
126 | case '^': // ^ inside [...] can be unescaped
127 | if (setOpen == 0) {
128 | regex.append(BACKSLASH);
129 | }
130 | break;
131 | case '!': // [! needs to be translated to [^
132 | regex.append(setOpen > 0 && '[' == glob.charAt(i - 1) ? '^' : '!');
133 | continue;
134 | case ']':
135 | // Many set errors like [][] could not be easily detected here,
136 | // as []], []-] and [-] are all valid POSIX glob and java regex.
137 | // We'll just let the regex compiler do the real work.
138 | setOpen = 0;
139 | break;
140 | default:
141 | }
142 | regex.append(c);
143 | }
144 |
145 | if (setOpen > 0) {
146 | error("Unclosed character class", glob, len);
147 | }
148 | if (curlyOpen > 0) {
149 | error("Unclosed group", glob, len);
150 | }
151 | compiled = Pattern.compile(regex.toString());
152 | }
153 |
154 | /**
155 | * @return true if this is a wildcard pattern (with special chars)
156 | */
157 | public boolean hasWildcard() {
158 | return hasWildcard;
159 | }
160 |
161 | private static void error(String message, String pattern, int pos) {
162 | throw new PatternSyntaxException(message, pattern, pos);
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/doc/developers.md:
--------------------------------------------------------------------------------
1 | # For Plugin Developers #
2 |
3 | ## If you really must have an API... ##
4 |
5 | Since 0.9.8, zPermissions has provided an API for common, read-only operations. It was originally developed with [Vault](http://dev.bukkit.org/server-mods/vault/) in mind, but of course, anyone can use it.
6 |
7 | The API methods are exposed via the [ZPermissionsService](https://github.com/ZerothAngel/zPermissions/blob/master/src/main/java/org/tyrannyofheaven/bukkit/zPermissions/ZPermissionsService.java) interface.
8 |
9 | First, you will need to add zPermissions-X.Y.Z.jar to your build path somehow. If your project uses Maven, add the following repository to your POM:
10 |
11 |
12 | tyrannyofheaven.org
13 | http://maven.tyrannyofheaven.org/
14 |
15 |
16 | Then add the following dependency:
17 |
18 |
19 | org.tyrannyofheaven.bukkit
20 | zPermissions
21 | [0.9.8,)
22 | provided
23 |
24 |
25 | If you don't use Maven (and why not?), you can visit my [Maven repository](http://maven.tyrannyofheaven.org/org/tyrannyofheaven/bukkit/zPermissions/) directly and download any version > 0.9.8.
26 |
27 | Next, to get an actual implementation of this interface, your plugin should do something like the following:
28 |
29 | ZPermissionsService service = null;
30 | try {
31 | service = Bukkit.getServicesManager().load(ZPermissionsService.class);
32 | }
33 | catch (NoClassDefFoundError e) {
34 | // Eh...
35 | }
36 | if (service == null) {
37 | // zPermissions not found, do something else
38 | }
39 |
40 | Ideally, you would do the lookup once (e.g. store the result in an instance or static variable) and, in addition to your plugin's onEnable(), possibly also perform the check inside a PluginEnableEvent handler. But the above is the general gist of it.
41 |
42 | Note that if you are only checking for ZPermissionsService in your plugin's onEnable() method then you will need to add a line like the following to your plugin.yml:
43 |
44 | softdepend: [zPermissions]
45 |
46 | Finally, if you look at the actual interface, you'll see that it only covers read-only operations. Operations that modify the state of zPermissions are still **only supported via the command line.** So you would probably use something like Bukkit.dispatchCommand().
47 |
48 | What follows is the old (and of course, still supported!), non-zPermissions-specific Bukkit-only method of interacting with zPermissions...
49 |
50 | ## Checking Group Membership ##
51 |
52 | As far as checking group membership, I strongly advocate the method hinted at by Dinnerbone in his [Permissions FAQ](http://forums.bukkit.org/threads/permissions-faq.25080/). Namely, using permissions to denote group membership.
53 |
54 | zPermissions follows the convention put forth by the developers of WorldEdit, WorldGuard, etc., that is, check group membership by checking for a specific permission of the form:
55 |
56 | group.
57 |
58 | So a player in the `visitor` group will have the `group.visitor` permission automatically set to true. A player in the `admin` group will have the `group.admin` permission set to true, etc.
59 |
60 | (And, of course, in zPermissions, the form of this permission is configurable — see the `group-permission` option in config.yml.)
61 |
62 | Despite zPermissions doing this automatically, the beautiful thing about this convention is that *any* Superperms provider can provide the required permission. If necessary, server admins can just manually add the permission to each of their groups.
63 |
64 | ## Enumerating a Player's Groups ##
65 |
66 | This can be easily done using only the Bukkit permissions API. For example:
67 |
68 | private static final String GROUP_PREFIX = "group.";
69 |
70 | ...
71 |
72 | public Set getGroupsForPlayer(Player player) {
73 | Set groups = new HashSet();
74 | for (PermissionAttachmentInfo pai : player.getEffectivePermissions()) {
75 | if (!pai.getPermission().startsWith(GROUP_PREFIX) || !pai.getValue())
76 | continue;
77 | groups.add(pai.getPermission().substring(GROUP_PREFIX.length()));
78 | }
79 | return groups;
80 | }
81 |
82 | It is **STRONGLY** recommended that you actually make `GROUP_PREFIX` configurable. Do not hardcode it. This gives the server admin more flexibility.
83 |
84 | ## Changing Group Membership / Promoting / Demoting ##
85 |
86 | I have no plans to provide any sort of public API for changing group memberships. I absolutely abhor writing to implementations (see what it's like for a modern plugin to support the half dozen or so economy plugins... although that might be a bad example due to the existence of Vault/Register API :P).
87 |
88 | Unless Bukkit someday provides a groups management API (which seems like a bad idea, as it would be dictating an implementation detail to Superperms providers), the only supported method to programmatically modify group memberships in zPermissions **is through the command line**.
89 |
90 | Excuting another plugin's commands is easy. And the awesome thing about using commands: you can make it configurable. Instead of compiling against X different plugins, just provide a command template that the server admin can easily change. For example, for zPermissions:
91 |
92 | permissions player %player% setgroup %group%
93 |
94 | And the plugin would make the necessary substitutions before handing the command off to the server to be executed.
95 |
96 | Actual implementation left up to any enterprising developers... ;)
97 |
--------------------------------------------------------------------------------
/src/main/java/org/tyrannyofheaven/bukkit/zPermissions/listener/ZPermissionsPlayerListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 ZerothAngel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.tyrannyofheaven.bukkit.zPermissions.listener;
17 |
18 | import static org.tyrannyofheaven.bukkit.util.ToHLoggingUtils.debug;
19 |
20 | import org.bukkit.Bukkit;
21 | import org.bukkit.event.EventHandler;
22 | import org.bukkit.event.EventPriority;
23 | import org.bukkit.event.Listener;
24 | import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
25 | import org.bukkit.event.player.PlayerChangedWorldEvent;
26 | import org.bukkit.event.player.PlayerJoinEvent;
27 | import org.bukkit.event.player.PlayerLoginEvent;
28 | import org.bukkit.event.player.PlayerQuitEvent;
29 | import org.bukkit.plugin.Plugin;
30 | import org.tyrannyofheaven.bukkit.util.uuid.UuidResolver;
31 | import org.tyrannyofheaven.bukkit.zPermissions.RefreshCause;
32 | import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsCore;
33 |
34 | /**
35 | * PlayerListener for zPermissions. Simply updates or removes the zPermissions
36 | * permissions as appropriate.
37 | *
38 | * @author zerothangel
39 | */
40 | public class ZPermissionsPlayerListener implements Listener {
41 |
42 | private final ZPermissionsCore core;
43 |
44 | private final Plugin plugin;
45 |
46 | private final UuidResolver uuidResolver;
47 |
48 | public ZPermissionsPlayerListener(ZPermissionsCore core, Plugin plugin, UuidResolver uuidResolver) {
49 | this.core = core;
50 | this.plugin = plugin;
51 | this.uuidResolver = uuidResolver;
52 | }
53 |
54 | @EventHandler(priority=EventPriority.MONITOR)
55 | public void onAsyncPlayerPreLogin(AsyncPlayerPreLoginEvent event) {
56 | if (event.getLoginResult() == AsyncPlayerPreLoginEvent.Result.ALLOWED) {
57 | // Update display name
58 | core.updateDisplayName(event.getUniqueId(), event.getName());
59 | }
60 | }
61 |
62 | // Do this early for the benefit of anything listening on the same event
63 | @EventHandler(priority=EventPriority.LOWEST)
64 | public void onPlayerLogin(PlayerLoginEvent event) {
65 | debug(plugin, "%s logged in", event.getPlayer().getName());
66 | core.setBukkitPermissions(event.getPlayer(), event.getPlayer().getLocation(), true, null);
67 | // NB don't bother with expirations until join
68 | }
69 |
70 | @EventHandler(priority=EventPriority.MONITOR)
71 | public void onPlayerLoginMonitor(PlayerLoginEvent event) {
72 | // If they aren't sticking around...
73 | if (event.getResult() != PlayerLoginEvent.Result.ALLOWED) {
74 | // Forget about them
75 | debug(plugin, "%s is not allowed to log in", event.getPlayer().getName());
76 | core.removeBukkitPermissions(event.getPlayer(), false); // They're getting booted, no need to recalc
77 | }
78 | }
79 |
80 | @EventHandler(priority=EventPriority.LOWEST)
81 | public void onPlayerJoin(PlayerJoinEvent event) {
82 | debug(plugin, "%s joining", event.getPlayer().getName());
83 | // NB eventCause is null because it's a given that the player's permissions has changed on join
84 | // (ignore the fact that it actually changed on login for now)
85 | core.setBukkitPermissions(event.getPlayer(), event.getPlayer().getLocation(), true, null); // Does this need to be forced again?
86 | // Wait for next tick...
87 | Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
88 | @Override
89 | public void run() {
90 | core.refreshExpirations();
91 | }
92 | });
93 | }
94 |
95 | @EventHandler(priority=EventPriority.MONITOR)
96 | public void onPlayerJoinMonitor(PlayerJoinEvent event) {
97 | // Make default group membership explicit, if configured to do so...
98 | core.handleExplicitDefaultGroupMembership(event.getPlayer().getUniqueId(), event.getPlayer().getName());
99 | }
100 |
101 | @EventHandler(priority=EventPriority.MONITOR)
102 | public void onPlayerQuit(PlayerQuitEvent event) {
103 | debug(plugin, "%s quitting", event.getPlayer().getName());
104 | core.removeBukkitPermissions(event.getPlayer(), false); // They're leaving, no need to recalc
105 | // Wait for next tick...
106 | Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
107 | @Override
108 | public void run() {
109 | core.refreshExpirations();
110 | }
111 | });
112 | // Pre-load cache of UuidResolver
113 | uuidResolver.preload(event.getPlayer().getName(), event.getPlayer().getUniqueId());
114 | }
115 |
116 | @EventHandler(priority=EventPriority.LOWEST)
117 | public void onPlayerChangedWorld(PlayerChangedWorldEvent event) {
118 | core.setBukkitPermissions(event.getPlayer(), event.getPlayer().getLocation(), false, RefreshCause.MOVEMENT);
119 | }
120 |
121 | }
122 |
--------------------------------------------------------------------------------
/src/main/java/org/tyrannyofheaven/bukkit/zPermissions/service/DefaultPlayerPrefixHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 ZerothAngel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.tyrannyofheaven.bukkit.zPermissions.service;
17 |
18 | import java.util.ArrayList;
19 | import java.util.Collections;
20 | import java.util.HashMap;
21 | import java.util.List;
22 | import java.util.Map;
23 | import java.util.UUID;
24 |
25 | import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsConfig;
26 | import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsService;
27 | import org.tyrannyofheaven.bukkit.zPermissions.util.MetadataConstants;
28 |
29 | public class DefaultPlayerPrefixHandler implements PlayerPrefixHandler {
30 |
31 | private final ZPermissionsConfig config;
32 |
33 | public DefaultPlayerPrefixHandler(ZPermissionsConfig config) {
34 | this.config = config;
35 | }
36 |
37 | /* (non-Javadoc)
38 | * @see org.tyrannyofheaven.bukkit.zPermissions.vault.PlayerPrefixHandler#getPlayerPrefix(java.lang.String)
39 | */
40 | @Override
41 | public String getPlayerPrefix(ZPermissionsService service, UUID uuid) {
42 | String prefix;
43 |
44 | if (config.getVaultPlayerPrefixFormat().isEmpty()) {
45 | prefix = service.getPlayerMetadata(uuid, MetadataConstants.PREFIX_KEY, String.class);
46 | if (prefix == null && config.isVaultPrefixIncludesGroup())
47 | prefix = service.getGroupMetadata(service.getPlayerPrimaryGroup(uuid), MetadataConstants.PREFIX_KEY, String.class);
48 | }
49 | else {
50 | prefix = getFormattedPrefixSuffix(service, uuid, config.getVaultPlayerPrefixFormat(), true);
51 | }
52 |
53 | if (prefix == null)
54 | return "";
55 | else
56 | return prefix;
57 | }
58 |
59 | /* (non-Javadoc)
60 | * @see org.tyrannyofheaven.bukkit.zPermissions.vault.PlayerPrefixHandler#getPlayerSuffix(java.lang.String)
61 | */
62 | @Override
63 | public String getPlayerSuffix(ZPermissionsService service, UUID uuid) {
64 | String suffix;
65 |
66 | if (config.getVaultPlayerSuffixFormat().isEmpty()) {
67 | suffix = service.getPlayerMetadata(uuid, MetadataConstants.SUFFIX_KEY, String.class);
68 | if (suffix == null && config.isVaultPrefixIncludesGroup())
69 | suffix = service.getGroupMetadata(service.getPlayerPrimaryGroup(uuid), MetadataConstants.SUFFIX_KEY, String.class);
70 | }
71 | else {
72 | suffix = getFormattedPrefixSuffix(service, uuid, config.getVaultPlayerSuffixFormat(), false);
73 | }
74 |
75 | if (suffix == null)
76 | return "";
77 | else
78 | return suffix;
79 | }
80 |
81 | private String getFormattedPrefixSuffix(ZPermissionsService service, UUID uuid, String format, boolean isPrefix) {
82 | Map subMap = new HashMap<>();
83 | // Scan format, only calculate tokens that exist in it
84 | if (format.contains("%p")) {
85 | // Player
86 | String value = service.getPlayerMetadata(uuid, isPrefix ? MetadataConstants.PREFIX_KEY : MetadataConstants.SUFFIX_KEY, String.class);
87 | if (value == null) value = "";
88 | subMap.put("%p", value);
89 | }
90 | if (format.contains("%g")) {
91 | // Primary Group
92 | String value = service.getGroupMetadata(service.getPlayerPrimaryGroup(uuid), isPrefix ? MetadataConstants.PREFIX_KEY : MetadataConstants.SUFFIX_KEY, String.class);
93 | if (value == null) value = "";
94 | subMap.put("%g", value);
95 | }
96 | if (format.contains("%a")) {
97 | // All Groups
98 | List groups = getPlayerGroups(service, uuid);
99 | Collections.reverse(groups); // groups is in application order. We actually want it in display order.
100 | StringBuilder sb = new StringBuilder();
101 | for (String group : groups) {
102 | String value = service.getGroupMetadata(group, isPrefix ? MetadataConstants.PREFIX_KEY : MetadataConstants.SUFFIX_KEY, String.class);
103 | if (value == null) value = "";
104 | sb.append(value);
105 | }
106 | subMap.put("%a", sb.toString());
107 | }
108 | if (format.contains("%A")) {
109 | // All Groups Reversed
110 | List groups = getPlayerGroups(service, uuid);
111 | StringBuilder sb = new StringBuilder();
112 | for (String group : groups) {
113 | String value = service.getGroupMetadata(group, isPrefix ? MetadataConstants.PREFIX_KEY : MetadataConstants.SUFFIX_KEY, String.class);
114 | if (value == null) value = "";
115 | sb.append(value);
116 | }
117 | subMap.put("%A", sb.toString());
118 | }
119 |
120 | // Perform substitution
121 | String result = format;
122 | for (Map.Entry me : subMap.entrySet()) {
123 | result = result.replaceAll(me.getKey(), me.getValue());
124 | }
125 | return result;
126 | }
127 |
128 | private List getPlayerGroups(ZPermissionsService service, UUID uuid) {
129 | if (config.isVaultGetGroupsUsesAssignedOnly())
130 | return service.getPlayerAssignedGroups(uuid);
131 | else
132 | return new ArrayList<>(service.getPlayerGroups(uuid));
133 | }
134 |
135 | }
136 |
--------------------------------------------------------------------------------
/src/main/java/org/tyrannyofheaven/bukkit/zPermissions/util/SearchTask.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 ZerothAngel
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.tyrannyofheaven.bukkit.zPermissions.util;
17 |
18 | import static org.tyrannyofheaven.bukkit.util.ToHLoggingUtils.log;
19 | import static org.tyrannyofheaven.bukkit.zPermissions.util.Utils.formatPlayerName;
20 |
21 | import java.util.HashMap;
22 | import java.util.List;
23 | import java.util.Map;
24 | import java.util.Set;
25 | import java.util.UUID;
26 | import java.util.concurrent.atomic.AtomicInteger;
27 |
28 | import org.bukkit.Bukkit;
29 | import org.bukkit.plugin.Plugin;
30 | import org.tyrannyofheaven.bukkit.util.transaction.TransactionCallback;
31 | import org.tyrannyofheaven.bukkit.zPermissions.PermissionsResolver;
32 | import org.tyrannyofheaven.bukkit.zPermissions.model.Entry;
33 | import org.tyrannyofheaven.bukkit.zPermissions.model.PermissionEntity;
34 | import org.tyrannyofheaven.bukkit.zPermissions.storage.StorageStrategy;
35 |
36 | public class SearchTask implements Runnable {
37 |
38 | private static final AtomicInteger searchIdGenerator = new AtomicInteger();
39 |
40 | private final int searchId;
41 |
42 | private final Plugin plugin;
43 |
44 | private final StorageStrategy storageStrategy;
45 |
46 | private final PermissionsResolver resolver;
47 |
48 | private final String permission;
49 |
50 | private final List players;
51 |
52 | private final List groups;
53 |
54 | private final boolean effective;
55 |
56 | private final String world;
57 |
58 | private final Set regions;
59 |
60 | private final boolean showUuid;
61 |
62 | private int batchSize = 1;
63 |
64 | private int delay = 5;
65 |
66 | public SearchTask(Plugin plugin, StorageStrategy storageStrategy, PermissionsResolver resolver, String permission, List players, List groups, boolean effective, String world, Set regions, boolean showUuid) {
67 | this.searchId = searchIdGenerator.incrementAndGet();
68 | this.plugin = plugin;
69 | this.storageStrategy = storageStrategy;
70 | this.resolver = resolver;
71 | this.permission = permission.toLowerCase();
72 | this.players = players;
73 | this.groups = groups;
74 | this.effective = effective;
75 | this.world = world;
76 | this.regions = regions;
77 | this.showUuid = showUuid;
78 | }
79 |
80 | public int getSearchId() {
81 | return searchId;
82 | }
83 |
84 | public int getBatchSize() {
85 | return batchSize;
86 | }
87 |
88 | public void setBatchSize(int batchSize) {
89 | this.batchSize = batchSize;
90 | }
91 |
92 | public int getDelay() {
93 | return delay;
94 | }
95 |
96 | public void setDelay(int delay) {
97 | this.delay = delay;
98 | }
99 |
100 | @Override
101 | public void run() {
102 | int size = 0;
103 |
104 | while (size < getBatchSize() && !players.isEmpty()) {
105 | UUID uuid = players.remove(0);
106 |
107 | PermissionEntity entity = storageStrategy.getPermissionService().getEntity("ignored", uuid, false);
108 | if (entity != null && !entity.getPermissions().isEmpty()) {
109 | if (checkPermissions(entity) || (effective && checkEffectivePermissions(entity))) {
110 | log(plugin, "Search result (#%d): player %s", getSearchId(), formatPlayerName(entity, showUuid));
111 | }
112 | }
113 |
114 | size++;
115 | }
116 |
117 | while (size < getBatchSize() && !groups.isEmpty()) {
118 | String groupName = groups.remove(0);
119 |
120 | PermissionEntity entity = storageStrategy.getPermissionService().getEntity(groupName, null, true);
121 | if (entity != null && !entity.getPermissions().isEmpty()) {
122 | if (checkPermissions(entity) || (effective && checkEffectivePermissions(entity))) {
123 | log(plugin, "Search result (#%d): group %s", getSearchId(), entity.getDisplayName());
124 | }
125 | }
126 |
127 | size++;
128 | }
129 |
130 | if (players.isEmpty() && groups.isEmpty()) {
131 | log(plugin, "Search result (#%d): All done!", getSearchId());
132 | }
133 | else {
134 | Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, this, getDelay());
135 | }
136 | }
137 |
138 | private boolean checkPermissions(PermissionEntity entity) {
139 | for (Entry e : entity.getPermissions()) {
140 | if (e.getPermission().contains(permission))
141 | return true;
142 | }
143 | return false;
144 | }
145 |
146 | private boolean checkEffectivePermissions(final PermissionEntity entity) {
147 | Map rootPermissions = storageStrategy.getTransactionStrategy().execute(new TransactionCallback