package org.exist.client.xacml;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.apache.log4j.Logger;
import org.exist.Namespaces;
import org.exist.security.xacml.XACMLConstants;
import com.sun.xacml.cond.FunctionBase;
import com.sun.xacml.cond.FunctionFactory;
import com.sun.xacml.cond.MatchFunction;
/**
* Abbreviates the constants used in XACML to something
* shorter and hopefully more user-friendly. The getFullXXX
* methods should generally only be called with an argument
* obtained as the result of the corresponding getAbbreviatedXXX
* method.
*/
public class Abbreviator
{
private static final Logger LOG = Logger.getLogger(Abbreviator.class);
private static final String[][] comparisonMap = { {"equal", "="},
{"less-than-or-equal", "<="}, {"less-than", "<"},
{"greater-than-or-equal", ">="}, {"greater-than", ">"} };
private Map attributeIdMap = new HashMap(8);
private Map typeMap = new HashMap(8);
private Map functionMap = new HashMap(8);
public Abbreviator() {}
public String getAbbreviatedId(URI uri)
{
if(uri == null)
return null;
String toString = uri.toString();
if(toString.startsWith(XACMLConstants.EXIST_XACML_NS))
{
toString = toString.substring(XACMLConstants.EXIST_XACML_NS.length());
int i = toString.lastIndexOf('#');
if(i == -1)
{
i = toString.lastIndexOf('/');
if(i != -1)
toString = toString.substring(i+1);
}
else
toString = toString.substring(i+1);
}
else if(toString.startsWith(XACMLConstants.VERSION_1_0_BASE))
{
toString = toString.substring(XACMLConstants.VERSION_1_0_BASE.length());
int i = toString.lastIndexOf(':');
if(i != -1)
toString = toString.substring(i+1);
}
else
return toString;
attributeIdMap.put(toString, uri);
return toString;
}
public URI getFullIdURI(String abbrev)
{
return get(attributeIdMap, abbrev);
}
public String getAbbreviatedType(URI type)
{
if(type == null)
return null;
String toString = type.toString();
if(toString.startsWith(XACMLConstants.XACML_DATATYPE_BASE))
toString = toString.substring(XACMLConstants.XACML_DATATYPE_BASE.length());
else if(toString.startsWith(Namespaces.SCHEMA_NS))
toString = toString.substring(Namespaces.SCHEMA_NS.length()+1);
else if(toString.startsWith(XACMLConstants.XQUERY_OPERATORS_NS))
toString = toString.substring(XACMLConstants.XQUERY_OPERATORS_NS.length()+1);
else
return toString;
typeMap.put(toString, type);
return toString;
}
public URI getFullTypeURI(String abbrev)
{
return get(typeMap, abbrev);
}
public String getAbbreviatedCombiningID(URI uri)
{
if(uri == null)
return null;
String toString = uri.toString();
if(toString.startsWith(XACMLConstants.RULE_COMBINING_BASE))
toString = toString.substring(XACMLConstants.RULE_COMBINING_BASE.length());
else if(toString.startsWith(XACMLConstants.POLICY_COMBINING_BASE))
toString = toString.substring(XACMLConstants.POLICY_COMBINING_BASE.length());
else
return toString;
return toString;
}
public URI getFullCombiningURI(String abbrev, boolean isRuleAlg)
{
if(abbrev == null)
return null;
String prefix = isRuleAlg ? XACMLConstants.RULE_COMBINING_BASE : XACMLConstants.POLICY_COMBINING_BASE;
return URI.create(prefix + abbrev);
}
public String getAbbreviatedFunctionId(URI functionId)
{
if(functionId == null)
return null;
String toString = functionId.toString();
if(toString.startsWith(FunctionBase.FUNCTION_NS))
toString = toString.substring(FunctionBase.FUNCTION_NS.length());
else
{
functionMap.put(functionId, toString);
return toString;
}
if(toString.equals("regexp-string-match"))
toString = "string-match";
for(int i = 0; i < comparisonMap.length; ++i)
{
if(toString.endsWith(comparisonMap[i][0]))
{
toString = comparisonMap[i][1];
return toString;
}
}
functionMap.put(functionId, toString);
return toString;
}
public URI getFullFunctionId(String abbrev, URI dataType)
{
if(abbrev == null || dataType == null)
return null;
URI uri = (URI)functionMap.get(abbrev);
if(uri != null)
return uri;
String abbrevType = getAbbreviatedType(dataType);
if(abbrev.equals("match") && abbrevType.equals("string"))
return URI.create(MatchFunction.NAME_REGEXP_STRING_MATCH);
for(int i = 0; i < comparisonMap.length; ++i)
{
if(abbrev.equals(comparisonMap[i][1]))
{
abbrev = abbrevType + "-" + comparisonMap[i][0];
break;
}
}
return URI.create(FunctionBase.FUNCTION_NS + abbrev);
}
//TODO: not valid for date-related conversions
public Set getAbbreviatedTargetFunctions(URI dataType)
{
//note that sunxacml includes logical functions in the target
//instance
//this is almost certainly wrong
//abbrevTargetFunctionId filters these out because they do
//not include the data type in their name (not, and, or, n-or)
FunctionFactory factory = FunctionFactory.getTargetInstance();
Set functionIds = factory.getSupportedFunctions();
Set ret = new HashSet();
String abbrevType = getAbbreviatedType(dataType);
String functionId;
for(Iterator it = functionIds.iterator(); it.hasNext();)
{
functionId = (String)it.next();
functionId = abbrevTargetFunctionId(functionId, abbrevType);
if(functionId != null)
ret.add(functionId);
}
return ret;
}
public String getAbbreviatedTargetFunctionId(URI functionId, URI dataType)
{
if(functionId == null || dataType == null)
return null;
return abbrevTargetFunctionId(functionId.toString(), getAbbreviatedType(dataType));
}
private String abbrevTargetFunctionId(String functionId, String abbrevType)
{
if(functionId.startsWith(FunctionBase.FUNCTION_NS))
functionId = functionId.substring(FunctionBase.FUNCTION_NS.length());
else
return null;
if(functionId.equals("regexp-string-match"))
functionId = "string-match";
if(functionId.startsWith(abbrevType))
{
functionId = functionId.substring(abbrevType.length() + 1);
for(int i = 0; i < comparisonMap.length; ++i)
{
if(functionId.equals(comparisonMap[i][0]))
{
functionId = comparisonMap[i][1];
return functionId;
}
}
return functionId;
}
return null;
}
private static URI get(Map map, String abbrev)
{
URI ret = (URI)map.get(abbrev);
return (ret == null) ? parse(abbrev) : ret;
}
private static URI parse(String abbrev)
{
try
{
return new URI(abbrev);
}
catch (URISyntaxException e)
{
LOG.warn("Invalid URI '" + abbrev + "'", e);
return null;
}
}
}