001    package org.bukkit.permissions;
002    
003    import java.util.HashMap;
004    import java.util.HashSet;
005    import java.util.LinkedList;
006    import java.util.List;
007    import java.util.Map;
008    import java.util.Set;
009    import java.util.logging.Level;
010    import org.bukkit.Bukkit;
011    import org.bukkit.plugin.Plugin;
012    
013    /**
014     * Base Permissible for use in any Permissible object via proxy or extension
015     */
016    public class PermissibleBase implements Permissible {
017        private ServerOperator opable = null;
018        private Permissible parent = this;
019        private final List<PermissionAttachment> attachments = new LinkedList<PermissionAttachment>();
020        private final Map<String, PermissionAttachmentInfo> permissions = new HashMap<String, PermissionAttachmentInfo>();
021    
022        public PermissibleBase(ServerOperator opable) {
023            this.opable = opable;
024    
025            if (opable instanceof Permissible) {
026                this.parent = (Permissible) opable;
027            }
028    
029            recalculatePermissions();
030        }
031    
032        public boolean isOp() {
033            if (opable == null) {
034                return false;
035            } else {
036                return opable.isOp();
037            }
038        }
039    
040        public void setOp(boolean value) {
041            if (opable == null) {
042                throw new UnsupportedOperationException("Cannot change op value as no ServerOperator is set");
043            } else {
044                opable.setOp(value);
045            }
046        }
047    
048        public boolean isPermissionSet(String name) {
049            if (name == null) {
050                throw new IllegalArgumentException("Permission name cannot be null");
051            }
052    
053            return permissions.containsKey(name.toLowerCase());
054        }
055    
056        public boolean isPermissionSet(Permission perm) {
057            if (perm == null) {
058                throw new IllegalArgumentException("Permission cannot be null");
059            }
060    
061            return isPermissionSet(perm.getName());
062        }
063    
064        public boolean hasPermission(String inName) {
065            if (inName == null) {
066                throw new IllegalArgumentException("Permission name cannot be null");
067            }
068    
069            String name = inName.toLowerCase();
070    
071            if (isPermissionSet(name)) {
072                return permissions.get(name).getValue();
073            } else {
074                Permission perm = Bukkit.getServer().getPluginManager().getPermission(name);
075    
076                if (perm != null) {
077                    return perm.getDefault().getValue(isOp());
078                } else {
079                    return Permission.DEFAULT_PERMISSION.getValue(isOp());
080                }
081            }
082        }
083    
084        public boolean hasPermission(Permission perm) {
085            if (perm == null) {
086                throw new IllegalArgumentException("Permission cannot be null");
087            }
088    
089            String name = perm.getName().toLowerCase();
090    
091            if (isPermissionSet(name)) {
092                return permissions.get(name).getValue();
093            }
094            return perm.getDefault().getValue(isOp());
095        }
096    
097        public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value) {
098            if (name == null) {
099                throw new IllegalArgumentException("Permission name cannot be null");
100            } else if (plugin == null) {
101                throw new IllegalArgumentException("Plugin cannot be null");
102            } else if (!plugin.isEnabled()) {
103                throw new IllegalArgumentException("Plugin " + plugin.getDescription().getFullName() + " is disabled");
104            }
105    
106            PermissionAttachment result = addAttachment(plugin);
107            result.setPermission(name, value);
108    
109            recalculatePermissions();
110    
111            return result;
112        }
113    
114        public PermissionAttachment addAttachment(Plugin plugin) {
115            if (plugin == null) {
116                throw new IllegalArgumentException("Plugin cannot be null");
117            } else if (!plugin.isEnabled()) {
118                throw new IllegalArgumentException("Plugin " + plugin.getDescription().getFullName() + " is disabled");
119            }
120    
121            PermissionAttachment result = new PermissionAttachment(plugin, parent);
122    
123            attachments.add(result);
124            recalculatePermissions();
125    
126            return result;
127        }
128    
129        public void removeAttachment(PermissionAttachment attachment) {
130            if (attachment == null) {
131                throw new IllegalArgumentException("Attachment cannot be null");
132            }
133    
134            if (attachments.contains(attachment)) {
135                attachments.remove(attachment);
136                PermissionRemovedExecutor ex = attachment.getRemovalCallback();
137    
138                if (ex != null) {
139                    ex.attachmentRemoved(attachment);
140                }
141    
142                recalculatePermissions();
143            } else {
144                throw new IllegalArgumentException("Given attachment is not part of Permissible object " + parent);
145            }
146        }
147    
148        public void recalculatePermissions() {
149            clearPermissions();
150            Set<Permission> defaults = Bukkit.getServer().getPluginManager().getDefaultPermissions(isOp());
151            Bukkit.getServer().getPluginManager().subscribeToDefaultPerms(isOp(), parent);
152    
153            for (Permission perm : defaults) {
154                String name = perm.getName().toLowerCase();
155                permissions.put(name, new PermissionAttachmentInfo(parent, name, null, true));
156                Bukkit.getServer().getPluginManager().subscribeToPermission(name, parent);
157                calculateChildPermissions(perm.getChildren(), false, null);
158            }
159    
160            for (PermissionAttachment attachment : attachments) {
161                calculateChildPermissions(attachment.getPermissions(), false, attachment);
162            }
163        }
164    
165        public synchronized void clearPermissions() {
166            Set<String> perms = permissions.keySet();
167    
168            for (String name : perms) {
169                Bukkit.getServer().getPluginManager().unsubscribeFromPermission(name, parent);
170            }
171    
172            Bukkit.getServer().getPluginManager().unsubscribeFromDefaultPerms(false, parent);
173            Bukkit.getServer().getPluginManager().unsubscribeFromDefaultPerms(true, parent);
174    
175            permissions.clear();
176        }
177    
178        private void calculateChildPermissions(Map<String, Boolean> children, boolean invert, PermissionAttachment attachment) {
179            Set<String> keys = children.keySet();
180    
181            for (String name : keys) {
182                Permission perm = Bukkit.getServer().getPluginManager().getPermission(name);
183                boolean value = children.get(name) ^ invert;
184                String lname = name.toLowerCase();
185    
186                permissions.put(lname, new PermissionAttachmentInfo(parent, lname, attachment, value));
187                Bukkit.getServer().getPluginManager().subscribeToPermission(name, parent);
188    
189                if (perm != null) {
190                    calculateChildPermissions(perm.getChildren(), !value, attachment);
191                }
192            }
193        }
194    
195        public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value, int ticks) {
196            if (name == null) {
197                throw new IllegalArgumentException("Permission name cannot be null");
198            } else if (plugin == null) {
199                throw new IllegalArgumentException("Plugin cannot be null");
200            } else if (!plugin.isEnabled()) {
201                throw new IllegalArgumentException("Plugin " + plugin.getDescription().getFullName() + " is disabled");
202            }
203    
204            PermissionAttachment result = addAttachment(plugin, ticks);
205    
206            if (result != null) {
207                result.setPermission(name, value);
208            }
209    
210            return result;
211        }
212    
213        public PermissionAttachment addAttachment(Plugin plugin, int ticks) {
214            if (plugin == null) {
215                throw new IllegalArgumentException("Plugin cannot be null");
216            } else if (!plugin.isEnabled()) {
217                throw new IllegalArgumentException("Plugin " + plugin.getDescription().getFullName() + " is disabled");
218            }
219    
220            PermissionAttachment result = addAttachment(plugin);
221    
222            if (Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new RemoveAttachmentRunnable(result), ticks) == -1) {
223                Bukkit.getServer().getLogger().log(Level.WARNING, "Could not add PermissionAttachment to " + parent + " for plugin " + plugin.getDescription().getFullName() + ": Scheduler returned -1");
224                result.remove();
225                return null;
226            } else {
227                return result;
228            }
229        }
230    
231        public Set<PermissionAttachmentInfo> getEffectivePermissions() {
232            return new HashSet<PermissionAttachmentInfo>(permissions.values());
233        }
234    
235        private class RemoveAttachmentRunnable implements Runnable {
236            private PermissionAttachment attachment;
237    
238            public RemoveAttachmentRunnable(PermissionAttachment attachment) {
239                this.attachment = attachment;
240            }
241    
242            public void run() {
243                attachment.remove();
244            }
245        }
246    }