/*
* 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.wicket.security.hive.config;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.reflect.Constructor;
import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.wicket.security.actions.ActionFactory;
import org.apache.wicket.security.actions.WaspAction;
import org.apache.wicket.security.hive.BasicHive;
import org.apache.wicket.security.hive.Hive;
import org.apache.wicket.security.hive.SimpleCachingHive;
import org.apache.wicket.security.hive.authorization.EverybodyPrincipal;
import org.apache.wicket.security.hive.authorization.Permission;
import org.apache.wicket.security.hive.authorization.Principal;
import org.apache.wicket.security.hive.authorization.permissions.AllPermissions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A factory to produce Hive's based on policy files. This factory is designed to make a
* best effort when problems occur. Meaning any malconfiguration in the policy file is
* logged and then skipped. This factory accepts the following policy format<br>
*
* <pre>
* grant[ principal <principal class> "name"]
* {
* permission <permission class> "name",[ "actions"];
* };
* </pre>
*
* where [] denotes an optional block, <> denotes a classname.<br>
* For brevity aliases are allowed in / for classnames and permission-, principal names.
* An alias takes the form of ${foo} the alias (the part between {}) must be at least 1
* character long and must not contain one of the following 4 characters "${} For example:
* permission ${ComponentPermission} "myname.${foo}", "render";<br>
* Note that:
* <ul>
* <li>names and action must be quoted</li>
* <li>a permission statement must be on a single line and terminated by a ;</li>
* <li>the grant block must be terminated by a ;</li>
* <li>if you don't specify a principal after the grant statement, everybody will be given
* those permissions automagically</li>
* <li>using double quotes '"' is not allowed, instead use a single quote '''</li>
* <li>aliases may be chained but not nested, so ${foo}${bar} is valid but not
* ${foo${bar}}</li>
* <li>aliases are not allowed in actions or reserved words (grant, permission, principal)
* </li>
* <li>aliases are case sensitive</li>
* By default the following aliases is available: AllPermissions for
* org.apache.wicket.security.hive.authorization.permissions.AllPermissions
*
*
* @author marrink
*/
public class PolicyFileHiveFactory implements HiveFactory
{
private static final Logger log = LoggerFactory.getLogger(PolicyFileHiveFactory.class);
// TODO use JAAS to check for enough rights
private Set<URL> policyFiles;
private Set<InputStream> inputStreams;
private Set<Reader> inputReaders;
private static final Pattern principalPattern =
Pattern.compile("\\s*(?:grant(?:\\s+principal\\s+([^\"]+)\\s+\"([^\"]+)\")?){1}\\s*");
private static final Pattern permissionPattern =
Pattern
.compile("\\s*(?:permission\\s+([^\",]+?)\\s+(?:(?:\"([^\"]+)\"){1}?(?:\\s*,\\s*\"([^\"]*)\")?)?\\s*;){1}\\s*");
private static final Pattern aliasPattern = Pattern.compile("(\\$\\{[^\"\\{\\}\\$]+?\\})+?");
private static final Class< ? >[][] constructorArgs =
new Class[][] {new Class[] {String.class, WaspAction.class},
new Class[] {String.class, String.class},
new Class[] {String.class, ActionFactory.class}, new Class[] {String.class}};
private Map<String, String> aliases = new HashMap<String, String>();
private boolean useHiveCache = true;
private boolean closeInputStreams = true;
private int currentLineNr;
private final ActionFactory actionFactory;
/**
*
* Constructs a new factory that builds a Hive out of one (1) or more policy files. It
* registers an alias for {@link AllPermissions}.
*
* @param actionFactory
* factory required to create the actions for the permissions
* @throws IllegalArgumentException
* if the factory is null
*/
public PolicyFileHiveFactory(ActionFactory actionFactory)
{
this.actionFactory = actionFactory;
if (actionFactory == null)
throw new IllegalArgumentException("Must provide an ActionFactory");
policyFiles = new HashSet<URL>();
inputStreams = new HashSet<InputStream>();
inputReaders = new HashSet<Reader>();
setAlias("AllPermissions",
"org.apache.wicket.security.hive.authorization.permissions.AllPermissions");
}
/**
* Adds a new Hive policy file to this factory. The file is not used until
* {@link #createHive()} is executed. Url's are always retained for possible re-use.
*
* @param file
* @return true, if the file was added, false otherwise
*/
public final boolean addPolicyFile(URL file)
{
if (file == null)
{
log.warn("Can not add null as an url.");
return false;
}
return policyFiles.add(file);
}
/**
* A readonly view of the policy files added to this factory.
*
* @return a set containing {@link URL}'s
*/
protected final Set<URL> getPolicyFiles()
{
return Collections.unmodifiableSet(policyFiles);
}
/**
* Adds a new Hive policy to this factory. The stream is not read until
* {@link #createHive()} is executed. Depending on the state of the flag
* {@link #isCloseInputStreams()} the stream is closed or left untouched after it is
* read. In all cases the stream is removed from the factory after being read. The
* format of the inputstream must be the same as that of a regular policy file.
*
* @param stream
* @return true, if the stream was added, false otherwise
*/
public final boolean addStream(InputStream stream)
{
if (stream == null)
{
log.warn("Can not add null as a stream.");
return false;
}
return inputStreams.add(stream);
}
/**
* A readonly view of the streams added to this factory.
*
* @return a set containing {@link InputStream}s
*/
protected final Set<InputStream> getStreams()
{
return Collections.unmodifiableSet(inputStreams);
}
/**
* Adds a new Hive policy to this factory. The reader is not read until
* {@link #createHive()} is executed. Depending on the state of the flag
* {@link #isCloseInputStreams()} the reader is closed or left untouched after it is
* read. In all cases the reader is removed from the factory after being read. The
* format of the inputstream must be the same as that of a regular policy file.
*
* @param input
* @return true, if the reader was added, false otherwise
*/
public final boolean addReader(Reader input)
{
if (input == null)
{
log.warn("Can not add null as a reader.");
return false;
}
return inputReaders.add(input);
}
/**
* A readonly view of the readers added to this factory.
*
* @return a set containing {@link Reader}s
*/
protected final Set<Reader> getReaders()
{
return Collections.unmodifiableSet(inputReaders);
}
/**
* Returns the value of the alias.
*
* @param key
* the part between the ${}
* @return the value or null if that alias does not exist
*/
public final String getAlias(String key)
{
return aliases.get(key);
}
/**
* Sets the value for an alias, overwrites any existing alias with the same name
*
* @param key
* the part between the ${}
* @param value
* the value the alias is replaced with at hive creation time.
* @return the previous value or null
*/
public final String setAlias(String key, String value)
{
return aliases.put(key, value);
}
/**
* The current line being read.
*
* @return the line number
*/
protected final int getCurrentLineNr()
{
return currentLineNr;
}
/**
* Checks raw input for aliases and then replaces those with the registered values.
* Note that if the encountered alias is not allowed it is left unresolved and will
* probably later in the creation of the factory be skipped or cause a failure.
*
* @param raw
* the raw input
* @return the input with as much aliases resolved
*/
private String resolveAliases(String raw)
{
Matcher m = aliasPattern.matcher(raw);
StringBuffer buff = new StringBuffer(raw.length() + 30); // guess
int index = 0;
while (m.find())
{
if (m.start() > index)
{
buff.append(raw.substring(index, m.start()));
replaceAlias(raw, m, buff);
}
else if (m.start() == index)
{
replaceAlias(raw, m, buff);
}
else
// should not happen
throw new IllegalStateException("These aliases are not supported: " + raw);
index = m.end();
}
if (index < raw.length())
buff.append(raw.substring(index, raw.length()));
String temp = buff.toString();
if (temp.indexOf("${") >= 0)
throw new IllegalStateException("Nesting aliases is not supported: " + raw);
return temp;
}
/**
* Replaces the alias with the actual value.
*
* @param raw
* the raw input string
* @param m
* the matcher holding the alias
* @param buff
* output for the value
*/
private void replaceAlias(String raw, Matcher m, StringBuffer buff)
{
String key = raw.substring(m.start() + 2, m.end() - 1);
String alias = getAlias(key);
if (alias == null) // will probably be skipped later on
{
alias = key;
if (log.isDebugEnabled())
log.debug("failed to resolve alias: " + key);
}
else if (log.isDebugEnabled())
log.debug("resolved alias: " + key + " to " + alias);
buff.ensureCapacity(buff.length() + alias.length());
buff.append(alias);
}
/**
* Changeable by subclasses to return there own hive subclass. Note that the actual
* filling with content happens in {@link #createHive()}. Default implementation
* return either a {@link SimpleCachingHive} or a {@link BasicHive} depending on
* {@link #isUsingHiveCache()}
*
* @return {@link BasicHive} subclass.
*/
protected BasicHive constructHive()
{
if (isUsingHiveCache())
return new SimpleCachingHive();
return new BasicHive();
}
/**
* This method is not thread safe.
*
* @see org.apache.wicket.security.hive.config.HiveFactory#createHive()
*/
public final Hive createHive()
{
BasicHive hive = constructHive();
boolean readAnything = false;
for (URL file : policyFiles)
{
readAnything = true;
try
{
readPolicyFile(file, hive);
}
catch (IOException e)
{
log.error("Could not read from " + file, e);
}
}
for (InputStream stream : inputStreams)
{
readAnything = true;
try
{
readInputStream(stream, hive);
}
catch (IOException e)
{
log.error("Could not read from stream", e);
}
}
inputStreams.clear();
for (Reader stream : inputReaders)
{
readAnything = true;
try
{
readInputReader(stream, hive);
}
catch (IOException e)
{
log.error("Could not read from reader", e);
}
}
inputReaders.clear();
if (!readAnything)
log.warn("No policyFiles or inputstreams were added to the factory!");
hive.lock();
return hive;
}
/**
* Reads principals and permissions from a file, found items are added to the hive.
*
* @param file
* the file to read
* @param hive
* the hive where found items are appended to.
* @throws IOException
* if a problem occurs while reading the file
* @see #readStream(InputStream, BasicHive)
*/
protected final void readPolicyFile(URL file, BasicHive hive) throws IOException
{
notifyFileStart(file);
InputStream stream = null;
try
{
stream = file.openStream();
readStream(stream, hive);
}
finally
{
notifyFileClose(file, currentLineNr);
if (stream != null)
stream.close();
}
}
/**
* Reads principals and permissions from a stream, found items are added to the hive.
* The stream is closed depending on the {@link #isCloseInputStreams()} flag.
*
* @param stream
* the stream to read
* @param hive
* the hive where found items are appended to.
* @throws IOException
* if a problem occurs while reading the file
* @see #isCloseInputStreams()
* @see #setCloseInputStreams(boolean)
* @see #readStream(InputStream, BasicHive)
*/
protected final void readInputStream(InputStream stream, BasicHive hive) throws IOException
{
notifyStreamStart(stream);
try
{
readStream(stream, hive);
}
finally
{
notifyStreamEnd(stream, currentLineNr);
if (closeInputStreams)
stream.close();
}
}
/**
* Reads principals and permissions from a {@link Reader}, found items are added to
* the hive. The reader is closed depending on the {@link #isCloseInputStreams()}
* flag.
*
* @param input
* the reader to read
* @param hive
* the hive where found items are appended to.
* @throws IOException
* if a problem occurs while reading the file
* @see #isCloseInputStreams()
* @see #setCloseInputStreams(boolean)
* @see #readStream(InputStream, BasicHive)
*/
protected final void readInputReader(Reader input, BasicHive hive) throws IOException
{
notifyReaderStart(input);
try
{
readReader(input, hive);
}
finally
{
notifyReaderEnd(input, currentLineNr);
if (closeInputStreams)
input.close();
}
}
/**
* Reads principals and permissions from a {@link Reader}, found items are added to
* the hive. Subclasses should override this method or
* {@link #readStream(InputStream, BasicHive)} if they want do do something different
* from the default. No need to call the notifyMethods as that is handled by
* {@link #readInputReader(Reader, BasicHive)} and
* {@link #readInputStream(InputStream, BasicHive)} respectively. Default
* implementation is to call {@link #read(Reader, BasicHive)}. This method never
* closes the reader.
*
* @param input
* @param hive
* @throws IOException
*/
protected void readReader(Reader input, BasicHive hive) throws IOException
{
read(input, hive);
}
/**
* Notifies that the stream will be read no further. Typically this is because the end
* of the stream is reached but it is also called when an exception occurs while
* reading the stream.
*
* @param stream
* @param lineNr
* number of lines processed
*/
protected void notifyStreamEnd(InputStream stream, int lineNr)
{
}
/**
* Notifies that a reader is about to be read.
*
* @param input
* the reader
*/
protected void notifyReaderStart(Reader input)
{
}
/**
* Notifies that the {@link Reader} will be read no further. Typically this is because
* the end of the stream is reached but it is also called when an exception occurs
* while reading the reader.
*
* @param input
* @param lineNr
* number of lines processed
*/
protected void notifyReaderEnd(Reader input, int lineNr)
{
}
/**
* Notifies that a stream is about to be read.
*
* @param stream
* the stream
*/
protected void notifyStreamStart(InputStream stream)
{
}
/**
* Reads principals and permissions from a {@link InputStream} , found items are added
* to the hive. This method never closes the input stream.
*
* @param input
* @param hive
* @throws IOException
*/
protected void readStream(InputStream input, BasicHive hive) throws IOException
{
read(new InputStreamReader(input), hive);
}
/**
* Reads principals and permissions from a {@link Reader} , found items are added to
* the hive. This method never closes the reader.
*
* @param input
* @param hive
* @throws IOException
*/
protected final void read(Reader input, BasicHive hive) throws IOException
{
BufferedReader reader;
if (input instanceof BufferedReader)
reader = (BufferedReader) input;
else
reader = new BufferedReader(input);
boolean inPrincipalBlock = false;
Principal principal = null;
Set<Permission> permissions = null;
currentLineNr = 0;
String line = reader.readLine();
while (line != null)
{
currentLineNr++;
if (inPrincipalBlock)
{
String trim = line.trim();
boolean startsWith = trim.startsWith("{");
if (startsWith)
{
if (permissions != null || principal == null)
skipIllegalPrincipal(currentLineNr, principal, permissions);
permissions = new HashSet<Permission>();
}
boolean endsWith = trim.endsWith("};");
if (endsWith)
{
inPrincipalBlock = false;
if (permissions != null && permissions.size() > 0)
hive.addPrincipal(principal, permissions);
else
skipEmptyPrincipal(currentLineNr, principal);
permissions = null;
principal = null;
}
if (!(startsWith || endsWith))
{
Matcher m = permissionPattern.matcher(line);
if (m.matches())
{
String classname = m.group(1);
if (classname == null)
{
skipPermission(currentLineNr, null);
line = reader.readLine();
continue;
}
try
{
Class< ? > permissionClass = Class.forName(resolveAliases(classname));
if (!Permission.class.isAssignableFrom(permissionClass))
{
skipPermission(currentLineNr, permissionClass);
line = reader.readLine();
continue;
}
String name = resolveAliases(m.group(2));
String actions = m.group(3);
Permission temp =
createPermission(permissionClass.asSubclass(Permission.class),
name, actions);
if (temp == null)
{
line = reader.readLine();
continue;
}
if (permissions == null)
{
skipIllegalPermission(currentLineNr, principal, temp);
line = reader.readLine();
continue;
}
if (!permissions.add(temp))
skipPermission(currentLineNr, principal, temp);
else
notifyPermission(currentLineNr, principal, temp);
}
catch (ClassNotFoundException e)
{
skipPermission(currentLineNr, classname, e);
line = reader.readLine();
continue;
}
}
else
{
// skip this line
skipLine(currentLineNr, line);
}
}
}
else
{
Matcher m = principalPattern.matcher(line);
if (m.matches())
{
String classname = m.group(1);
if (classname == null)
principal = new EverybodyPrincipal();
else
{
try
{
Class< ? > readPrincipalClass =
Class.forName(resolveAliases(classname));
if (!Principal.class.isAssignableFrom(readPrincipalClass))
{
skipPrincipalClass(currentLineNr, readPrincipalClass);
line = reader.readLine();
continue;
}
Class< ? extends Principal> principalClass =
readPrincipalClass.asSubclass(Principal.class);
Constructor< ? extends Principal> constructor = null;
try
{
constructor =
principalClass
.getConstructor(constructorArgs[constructorArgs.length - 1]);
}
catch (SecurityException e)
{
log.error("No valid constructor found for "
+ principalClass.getName(), e);
}
catch (NoSuchMethodException e)
{
log.error("No valid constructor found for "
+ principalClass.getName(), e);
}
if (constructor == null)
{
skipPrincipal(currentLineNr, principalClass);
line = reader.readLine();
continue;
}
try
{
principal =
constructor
.newInstance(new Object[] {resolveAliases(m.group(2))});
}
catch (Exception e)
{
skipPrincipal(currentLineNr, principalClass, e);
line = reader.readLine();
continue;
}
}
catch (ClassNotFoundException e)
{
skipPrincipalClass(currentLineNr, classname, e);
line = reader.readLine();
continue;
}
}
notifyOfPrincipal(currentLineNr, principal);
inPrincipalBlock = true;
}
else
{
skipLine(currentLineNr, line);
}
}
line = reader.readLine();
}
// catch forgotten closeStatement
if (inPrincipalBlock)
{
warnUnclosedPrincipalBlock(principal, currentLineNr);
inPrincipalBlock = false;
if (permissions != null && permissions.size() > 0)
hive.addPrincipal(principal, permissions);
else
skipEmptyPrincipal(currentLineNr, principal);
permissions = null;
principal = null;
}
}
/**
* Tries to create a permission. Only a few constructors are tried before giving up.
*
* @param permissionClass
* @param name
* @param actions
* @return the permission or null if it could not be created.
* @see #findConstructor(Class, String)
*/
private Permission createPermission(Class< ? extends Permission> permissionClass, String name,
String actions)
{
Constructor< ? extends Permission> constructor = findConstructor(permissionClass, actions);
if (constructor == null)
{
skipPermission(currentLineNr, permissionClass);
return null;
}
Object[] argValues = null;
if (match(constructor.getParameterTypes(), constructorArgs[0]))
argValues = new Object[] {name, getActionFactory().getAction(actions)};
else if (match(constructor.getParameterTypes(), constructorArgs[1]))
argValues = new Object[] {name, actions};
else if (match(constructor.getParameterTypes(), constructorArgs[2]))
argValues = new Object[] {name, actionFactory};
else if (match(constructor.getParameterTypes(), constructorArgs[3]))
argValues = new Object[] {name};
else
{
// should not happen
String msg =
"Unable to handle constructor " + constructor + ", at line nr " + currentLineNr;
log.error(msg);
throw new RuntimeException(msg);
}
try
{
return constructor.newInstance(argValues);
}
catch (Exception e)
{
skipPermission(currentLineNr, permissionClass, argValues, e);
}
return null;
}
/**
* Signals a match between to arrays of classes. A match is found when every class in
* the second array is either the same or a subclass of the class in the first array
* with the same index. Used to compare constructor arguments.
*
* @param args1
* reference array
* @param args2
* this array should match the first array
* @return true if both arrays are a match, false otherwise.
*/
private boolean match(Class< ? >[] args1, Class< ? >[] args2)
{
if (args1 == args2)
return true;
if (args1 == null || args2 == null)
return false;
if (args1.length != args2.length)
return false;
for (int i = 0; i < args1.length; i++)
{
if (!args1[i].isAssignableFrom(args2[i]))
return false;
}
return true;
}
/**
* Tries to find a constructor for a {@link Permission}.
*
* @param permissionClass
* @param actions
* a comma separated list of actions (optional)
* @return a matching constructor. or null if none can be found.
*/
private Constructor< ? extends Permission> findConstructor(
Class< ? extends Permission> permissionClass, String actions)
{
int index = 0;
if (actions == null)
index = 2;
return findConstructor(permissionClass, index);
}
/**
* Tries to find a constructor matching the constructor arguments at the specified
* index for {@link #constructorArgs}. If no such constructor is found it recursivly
* tries to find another.
*
* @param permissionClass
* @param index
* @return a suitable constructor or null if none was found.
*/
private Constructor< ? extends Permission> findConstructor(
Class< ? extends Permission> permissionClass, int index)
{
if (index >= constructorArgs.length)
return null;
Class< ? >[] args = constructorArgs[index];
Constructor< ? extends Permission> constructor = null;
try
{
constructor = permissionClass.getConstructor(args);
}
catch (SecurityException e)
{
log.debug("No valid constructor found for " + permissionClass.getName(), e);
notifyPermission(currentLineNr, permissionClass, args);
if (index < constructorArgs.length)
return findConstructor(permissionClass, index + 1);
}
catch (NoSuchMethodException e)
{
log.debug("No valid constructor found for " + permissionClass.getName(), e);
notifyPermission(currentLineNr, permissionClass, args);
if (index < constructorArgs.length)
return findConstructor(permissionClass, index + 1);
}
return constructor;
}
/**
* Warning when the last principal of a file is not properly closed. Although the
* principal is automatically closed the user should complete the block statement for
* the principal.
*
* @param principal
* @param lineNr
*/
protected void warnUnclosedPrincipalBlock(Principal principal, int lineNr)
{
log.warn("The principal " + principal + " running to line " + lineNr
+ " is not properly closed with '};'.");
}
/**
* Notifies when a file is closed, either because the end of the file was reached or
* because an uncaught exception was thrown. Default is noop.
*
* @param file
* the file
* @param lineNr
* the last line read
*/
protected void notifyFileClose(URL file, int lineNr)
{
}
/**
* Notifies when a new file is about to be read. Default is noop.
*
* @param file
* the file
*/
protected void notifyFileStart(URL file)
{
}
/**
* Notifies when a permission class could not be found. Default is to log the
* exception
*
* @param lineNr
* the faulty line
* @param classname
* the class of the permission
* @param e
* the exception thrown when trying to locate the class
*/
protected void skipPermission(int lineNr, String classname, ClassNotFoundException e)
{
log.error("Permission class not found: " + classname + ", line " + lineNr, e);
}
/**
* Notifies when a permission is added to a principal. Default is noop.
*
* @param lineNr
* the currently process line
* @param principal
* the current principal
* @param permission
* the permission added to the principal
*/
protected void notifyPermission(int lineNr, Principal principal, Permission permission)
{
}
/**
* Notifies of duplicate permissions for a principal. Default is to log an exception.
* Note that the duplicates might appear in different files.
*
* @param lineNr
* the duplicate line
* @param principal
* the principal
* @param permission
* the duplicate permission
*/
protected void skipPermission(int lineNr, Principal principal, Permission permission)
{
log.debug(permission + " skipped because it was already added to the permission set for "
+ principal + ", line nr " + lineNr);
}
/**
* Notifies of permissions located outside the { and }; block statements but after a
* valid principal was found.
*
* @param lineNr
* the line declaring the illegal permission
* @param principal
* the declared principal
* @param permission
* the declared permission
*/
protected void skipIllegalPermission(int lineNr, Principal principal, Permission permission)
{
log.debug(permission + " skipped because the pricipal " + principal
+ " has not yet declared its opening block statement '{', line nr " + lineNr);
}
/**
* Notifies when a Principal class could not be found. Default is to log the
* exception.
*
* @param lineNr
* the faulty line
* @param classname
* the class of the Principal
* @param e
* the exception thrown when the class could not be found
*/
protected void skipPrincipalClass(int lineNr, String classname, ClassNotFoundException e)
{
log.error("Unable to find principal of class " + classname + " at line nr " + lineNr, e);
}
/**
* Notifies when the principal does not have an accessible constructor for a single
* {@link String} argument. Default is to log the exception.
*
* @param lineNr
* the faulty line
* @param principalClass
* the class of the Principal
*/
protected void skipPrincipal(int lineNr, Class< ? extends Principal> principalClass)
{
log.error("No valid constructor found for " + principalClass.getName() + " at line "
+ lineNr);
}
/**
* Notifies of a new Principal read in the policy file. Default is noop.
*
* @param lineNr
* the line currently processed
* @param principal
* the principl
*/
protected void notifyOfPrincipal(int lineNr, Principal principal)
{
}
/**
* Notifies when a new instance of the principl could not be created. Default is to
* log the exception.
*
* @param lineNr
* the line currently read
* @param principalClass
* the class of the principal
* @param e
* the exception thrown when trying to create a new instance
*/
protected void skipPrincipal(int lineNr, Class< ? extends Principal> principalClass, Exception e)
{
log.error("Unable to create new instance of " + principalClass.getName() + " at line nr "
+ lineNr, e);
}
/**
* Notifies when a classname is not a {@link Principal}. Default is to log the
* exception.
*
* @param lineNr
* the faulty line
* @param principalClass
* the class which is not a subclass of Principal
*/
protected void skipPrincipalClass(int lineNr, Class< ? > principalClass)
{
log.error(principalClass.getName() + "is not a subclass of " + Principal.class.getName()
+ ", line nr " + lineNr);
}
/**
* Notifies when a line is skipped because it was not understood for any other reason.
* Default is to print this debug info.
*
* @param lineNr
* the number of the line in the file
* @param line
* the line that was skipped
*/
protected void skipLine(int lineNr, String line)
{
log.debug("skipping line " + lineNr + ": " + line);
}
/**
* Notified when a new instance of the permission could not be created. Default is to
* log the exception
*
* @param lineNr
* the faulty line
* @param permissionClass
* the class trying to instantiate
* @param argValues
* the constructor argument(s)
* @param e
* the exception thrown when trying to create a new instance
*/
protected void skipPermission(int lineNr, Class< ? extends Permission> permissionClass,
Object[] argValues, Exception e)
{
log.error("Unable to create new instance of class " + permissionClass.getName()
+ " using the following argument(s) " + arrayToString(argValues) + ", line nr "
+ lineNr, e);
}
/**
* Generates a comma (,) separated string of all the items in the array
*
* @param array
* the input
* @return a comma separated string, an empty string or null if the input array has 1
* or more items, zero items or is null respectively.
*/
protected final String arrayToString(Object[] array)
{
if (array == null)
return null;
if (array.length < 1)
return "";
StringBuffer buffer = new StringBuffer(array.length * 12);// guess
for (int i = 0; i < array.length; i++)
{
buffer.append(array[i]);
if (i < array.length - 1)
buffer.append(", ");
}
return buffer.toString();
}
/**
* Notifies when a Permission could not be created because no suitable constructor was
* found. Default is to log an exception.
*
* @param lineNr
* the faulty line
* @param permissionClass
* the class of the permission
* @param args
* the number and type of constructor arguments
*
*/
protected void notifyPermission(int lineNr, Class< ? extends Permission> permissionClass,
Class< ? >[] args)
{
log.debug("No constructor found matching argument(s) " + arrayToString(args)
+ " for class " + permissionClass.getName() + ", line nr " + lineNr);
}
/**
* Notifies when a Class is skipped because it is not a Permission or no valid
* constructors could be found. Default is to log an exception.
*
* @param lineNr
* the faulty line
* @param permissionClass
* the class (if available)
*
*/
protected void skipPermission(int lineNr, Class< ? > permissionClass)
{
if (permissionClass == null)
log.error("Missing permission class at line " + lineNr);
else if (Permission.class.isAssignableFrom(permissionClass))
log.error("No valid constructor found for class " + permissionClass.getName()
+ ", line nr " + lineNr);
else
log.error(permissionClass.getName() + " is not a subclass of "
+ Permission.class.getName());
}
/**
* Notifies when a principal is skipped because there are no permissions attached.
* Default is to log an exception.
*
* @param lineNr
* the line closing the principal.
* @param principal
* the skipped principal
*/
protected void skipEmptyPrincipal(int lineNr, Principal principal)
{
if (log.isDebugEnabled())
log.debug("skipping principal " + principal + ", no permissions found before line nr "
+ lineNr);
}
/**
* Notifies when a {@link Principal} begins at an illegal place in the file. Default
* is to log an exception.
*
* @param lineNr
* the faulty line
* @param principal
* the principal we are currently working on
* @param permissions
* the permission collected for the current principal so far.
*/
protected void skipIllegalPrincipal(int lineNr, Principal principal, Set<Permission> permissions)
{
log.error("Illegal principal block detected at line " + lineNr);
}
/**
* Flag indicating if caching for the {@link Hive} is enabled or disabled. Default is
* enabled.
*
* @return useHiveCache
*/
public final boolean isUsingHiveCache()
{
return useHiveCache;
}
/**
* Sets useHiveCache.
*
* @param useCache
* enable or disable caching
*/
public final void useHiveCache(boolean useCache)
{
this.useHiveCache = useCache;
}
/**
* Gets closeInputStreams.
*
* @return closeInputStreams
*/
public final boolean isCloseInputStreams()
{
return closeInputStreams;
}
/**
* Sets closeInputStreams.
*
* @param closeInputStreams
* closeInputStreams
*/
public final void setCloseInputStreams(boolean closeInputStreams)
{
this.closeInputStreams = closeInputStreams;
}
/**
* Gets actionFactory.
*
* @return actionFactory
*/
protected final ActionFactory getActionFactory()
{
return actionFactory;
}
}