/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jackrabbit.core.security.authorization;
import javax.jcr.security.AccessControlEntry;
import javax.jcr.security.AccessControlException;
import javax.jcr.security.AccessControlList;
import javax.jcr.security.Privilege;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import javax.jcr.PropertyType;
import java.security.Principal;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Collections;
import java.util.HashMap;
import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
/**
* An implementation of the <code>AccessControlList</code> interface that only
* allows for reading. The write methods
* ({@link #addAccessControlEntry(Principal principal, Privilege[] privileges) addAccessControlEntry}
* and {@link #removeAccessControlEntry(AccessControlEntry) removeAccessControlEntry})
* throw an <code>AccessControlException</code>.
*/
public class UnmodifiableAccessControlList implements JackrabbitAccessControlList {
private final AccessControlEntry[] accessControlEntries;
private final Map<String, Integer> restrictions;
private final String path;
private int hashCode = 0;
/**
* Construct a new <code>UnmodifiableAccessControlList</code>
*
* @param acl The AccessControlList to be wrapped in order to prevent
* it's modification.
* @throws RepositoryException The the entries cannot be retrieved from the
* specified <code>AccessControlList</code>.
*/
public UnmodifiableAccessControlList(AccessControlList acl) throws RepositoryException {
if (acl instanceof JackrabbitAccessControlList) {
JackrabbitAccessControlList jAcl = (JackrabbitAccessControlList) acl;
accessControlEntries = acl.getAccessControlEntries();
path = jAcl.getPath();
Map<String, Integer> r = new HashMap<String, Integer>();
for (String name: jAcl.getRestrictionNames()) {
r.put(name, jAcl.getRestrictionType(name));
}
restrictions = Collections.unmodifiableMap(r);
} else {
accessControlEntries = acl.getAccessControlEntries();
path = null;
restrictions = Collections.emptyMap();
}
}
/**
* Construct a new <code>UnmodifiableAccessControlList</code>
*
* @param accessControlEntries A list of {@link AccessControlEntry access control entries}.
*/
public UnmodifiableAccessControlList(List<? extends AccessControlEntry> accessControlEntries) {
this(accessControlEntries, null, Collections.<String, Integer>emptyMap());
}
/**
* Construct a new <code>UnmodifiableAccessControlList</code>
*
* @param accessControlEntries
* @param path
* @param restrictions
*/
public UnmodifiableAccessControlList(List<? extends AccessControlEntry> accessControlEntries, String path, Map<String, Integer>restrictions) {
this.accessControlEntries = accessControlEntries.toArray(new AccessControlEntry[accessControlEntries.size()]);
this.path = path;
this.restrictions = restrictions;
}
//--------------------------------------------------< AccessControlList >---
/**
* @see AccessControlList#getAccessControlEntries()
*/
public AccessControlEntry[] getAccessControlEntries()
throws RepositoryException {
return accessControlEntries;
}
/**
* @see AccessControlList#addAccessControlEntry(Principal, Privilege[])
*/
public boolean addAccessControlEntry(Principal principal,
Privilege[] privileges)
throws AccessControlException, RepositoryException {
throw new AccessControlException("Unmodifiable ACL. Use AccessControlManager#getApplicablePolicies in order to obtain an modifiable ACL.");
}
/**
* @see AccessControlList#removeAccessControlEntry(AccessControlEntry)
*/
public void removeAccessControlEntry(AccessControlEntry ace)
throws AccessControlException, RepositoryException {
throw new AccessControlException("Unmodifiable ACL. Use AccessControlManager#getApplicablePolicies in order to obtain an modifiable ACL.");
}
//----------------------------------------< JackrabbitAccessControlList >---
/**
* @see org.apache.jackrabbit.api.security.JackrabbitAccessControlList#getRestrictionNames()
*/
public String[] getRestrictionNames() {
return restrictions.keySet().toArray(new String[restrictions.size()]);
}
/**
* @see org.apache.jackrabbit.api.security.JackrabbitAccessControlList#getRestrictionType(String)
*/
public int getRestrictionType(String restrictionName) {
if (restrictions.containsKey(restrictionName)) {
return restrictions.get(restrictionName);
} else {
return PropertyType.UNDEFINED;
}
}
/**
* @see org.apache.jackrabbit.api.security.JackrabbitAccessControlList#isEmpty()
*/
public boolean isEmpty() {
return accessControlEntries.length == 0;
}
/**
* @see org.apache.jackrabbit.api.security.JackrabbitAccessControlList#size()
*/
public int size() {
return accessControlEntries.length;
}
/**
* @see org.apache.jackrabbit.api.security.JackrabbitAccessControlList#addEntry(Principal, Privilege[], boolean)
*/
public boolean addEntry(Principal principal, Privilege[] privileges, boolean isAllow) throws AccessControlException {
throw new AccessControlException("Unmodifiable ACL. Use AccessControlManager#getPolicy or #getApplicablePolicies in order to obtain an modifiable ACL.");
}
/**
* @see org.apache.jackrabbit.api.security.JackrabbitAccessControlList#addEntry(Principal, Privilege[], boolean, Map)
*/
public boolean addEntry(Principal principal, Privilege[] privileges, boolean isAllow, Map<String, Value> restrictions) throws AccessControlException {
throw new AccessControlException("Unmodifiable ACL. Use AccessControlManager#getPolicy or #getApplicablePolicies in order to obtain an modifiable ACL.");
}
public boolean addEntry(Principal principal, Privilege[] privileges, boolean isAllow, Map<String, Value> restrictions, Map<String, Value[]> mvRestrictions) throws AccessControlException, RepositoryException {
throw new AccessControlException("Unmodifiable ACL. Use AccessControlManager#getPolicy or #getApplicablePolicies in order to obtain an modifiable ACL.");
}
/**
* @see org.apache.jackrabbit.api.security.JackrabbitAccessControlList#orderBefore(AccessControlEntry, AccessControlEntry)
*/
public void orderBefore(AccessControlEntry srcEntry, AccessControlEntry destEntry) throws AccessControlException {
throw new AccessControlException("Unmodifiable ACL. Use AccessControlManager#getPolicy or #getApplicablePolicy in order to obtain a modifiable ACL.");
}
/**
* @see org.apache.jackrabbit.api.security.JackrabbitAccessControlList#getPath()
*/
public String getPath() {
return path;
}
//-------------------------------------------------------------< Object >---
/**
* @see Object#hashCode()
*/
@Override
public int hashCode() {
if (hashCode == 0) {
int result = 17;
result = 37 * result + (path != null ? path.hashCode() : 0);
for (AccessControlEntry entry : accessControlEntries) {
result = 37 * result + entry.hashCode();
}
for (String restrictionName : restrictions.keySet()) {
result = 37 * (restrictionName + "." + restrictions.get(restrictionName)).hashCode();
}
hashCode = result;
}
return hashCode;
}
/**
* @see Object#equals(Object)
*/
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof UnmodifiableAccessControlList) {
UnmodifiableAccessControlList acl = (UnmodifiableAccessControlList) obj;
return ((path == null) ? acl.path == null : path.equals(acl.path)) &&
Arrays.equals(accessControlEntries, acl.accessControlEntries) &&
restrictions.equals(acl.restrictions);
}
return false;
}
}