JmxPermission.java

package com.ziesemer.utils.jmx.server.authorization;

import java.security.Permission;
import java.security.PermissionCollection;
import java.util.HashSet;
import java.util.Set;

/**
 * <p>An alternative to {@link javax.management.MBeanPermission}, used by
 * 		{@link JmxPermissionPrincipal} to provide a concept of JMX roles
 * 		around the individual &quot;permissions&quot; otherwise exposed by
 * 		{@link javax.management.MBeanPermission}.</p>
 * <p>Should typically be used with {@link JmxPermissionAuthorizer}.
 * 	Can also be used directly with
 * 		{@link javax.security.auth.Subject#getSubject(java.security.AccessControlContext)}
 * 		and {@link java.security.AccessController#getContext()}, without the need for
 * 		a specific {@link SecurityManager}.
 * 	See also: {@link JmxPermissionPrincipal#getCurrent()}.</p>
 * <p>A common set of roles (permissions) are defined as singletons on this class.
 * 	Additional and/or alternate subclasses may be created and used,
 * 		but should also be kept as singletons.</p>
 * @author Mark A. Ziesemer
 * 	<a href="http://www.ziesemer.com.">&lt;www.ziesemer.com&gt;</a>
 */
public abstract class JmxPermission extends Permission{
	
	private static final long serialVersionUID = 1L;
	
	protected final Set<JmxPermission> implies = new HashSet<JmxPermission>();
	
	/**
	 * <p>Required for performing any JMX operation.
	 * 	Allows reading of any attributes and invocation of any &quot;read-only&quot; operations.
	 * 	Will typically include invocation of any operation marked with
	 * 		{@link javax.management.MBeanOperationInfo#INFO}, or allowed by {@link ReadOnlyInvokeHandler}.</p>
	 */
	public static final JmxPermission CONNECT = new ConnectPermission();
	private static final class ConnectPermission extends JmxPermission{
		private static final long serialVersionUID = 1L;
		protected ConnectPermission(){
			super("Connect");
		}
	}
	
	/**
	 * <p>Required for performing &quot;extended&quot; read-only operations,
	 * 	including those that may be computationally expensive.
	 * Includes {@link #CONNECT}.</p>
	 */
	public static final JmxPermission READ_EX = new ReadExPermission();
	private static final class ReadExPermission extends JmxPermission{
		private static final long serialVersionUID = 1L;
		protected ReadExPermission(){
			super("Read extended", CONNECT);
		}
	}
	
	/**
	 * <p>Required for setting most attributes and invocation of most methods
	 * 		not already covered by {@link #READ_EX}.
	 * 	Will typically include invocation of any operation marked with
	 * 		{@link javax.management.MBeanOperationInfo#ACTION} or
	 * 		{@link javax.management.MBeanOperationInfo#ACTION_INFO}.
	 * 	Includes {@link #READ_EX}.</p>
	 */
	public static final JmxPermission INVOKE = new InvokePermission();
	private static final class InvokePermission extends JmxPermission{
		private static final long serialVersionUID = 1L;
		protected InvokePermission(){
			super("Invoke", READ_EX);
		}
	}
	
	/**
	 * <p>Allows all actions included by any other {@link JmxPermission},
	 * 	including those that may have more significant impact than allowed by {@link #INVOKE}.
	 * No other role (permission) should exist that includes more rights.</p>
	 */
	public static final JmxPermission ADMIN = new AdminPermission();
	private static final class AdminPermission extends JmxPermission{
		private static final long serialVersionUID = 1L;
		protected AdminPermission(){
			super("Admin");
		}
		@Override
		public boolean implies(final Permission permission){
			return permission instanceof JmxPermission;
		}
	}
	
	protected JmxPermission(final String name, final JmxPermission... implies){
		super(name);
		this.implies.add(this);
		for(final JmxPermission p : implies){
			initImplies(p);
		}
	}
	
	private void initImplies(final JmxPermission p){
		if(implies.add(p)){
			for(final JmxPermission cp : p.implies){
				initImplies(cp);
			}
		}
	}
	
	@Override
	public String getActions(){
		return null;
	}
	
	@Override
	public boolean implies(final Permission permission){
		return implies.contains(permission);
	}
	
	@Override
	public PermissionCollection newPermissionCollection(){
		return new JmxPermissions();
	}
	
	@Override
	public boolean equals(final Object obj){
		if(obj == null){
			return false;
		}
		return getClass().equals(obj.getClass());
	}
	
	@Override
	public int hashCode(){
		return getClass().hashCode();
	}
	
}