Commit ecfe8e91 authored by Cyril Dangerville's avatar Cyril Dangerville

Merge branch 'develop' of

https://matrice.dev.theresis.org/authzforce/authzforce-core-authzforce
into develop

Conflicts:
	src/main/java/com/sun/xacml/PDP.java
	
Other changes:
Merge branch 'develop' of
https://matrice.dev.theresis.org/authzforce/authzforce-core-authzforce
into develop

Conflicts:
	src/main/java/com/sun/xacml/PDP.java

- Fix AUTHZFORCE-18, AUTHZFORCE-19; in particular,
constructor/getInstance method has been added to use JAXB for parsing
XACML elements instead of the DOM API
- Improved PolicyReference to handle PolicyIdReference as well as
PolicySetIdReference without code specific to Policy/PolicySet
(polymorphism with IPolicy, same way AbstractPolicy was used in original
Sunxacml for PolicyReference), PolicySetReference now useless
- Refactoring/simplification using IPolicy interface implemented by
AbstractPolicySet, xacmlv3.Policy, PolicyReference (meant to replace use
of AbstractPolicy in original sunxacml version, but this abstract class
cannot be used for that because Policy* classes already inherit an
abstract JAXB class)
- Refactoring of xacmlv3.Expression* classes: getInstance() in
Expression, and getInstance() in ExpressionTools -> all getInstance() in
ExpressionTools
parents c0c63d29 24109ae2
/target
/.classpath
/.project
/bin
/.settings
/.settings/org.eclipse.jdt.core.prefs
/.settings/org.eclipse.core.resources.prefs
/.settings/org.eclipse.wst.common.component
/.settings/org.eclipse.wst.common.project.facet.core.xml
/.settings/org.sonar.ide.eclipse.core.prefs
*.log
/target
/.classpath
/.project
/bin
/.settings
/.settings/org.eclipse.jdt.core.prefs
/.settings/org.eclipse.core.resources.prefs
/.settings/org.eclipse.wst.common.component
/.settings/org.eclipse.wst.common.project.facet.core.xml
/.settings/org.sonar.ide.eclipse.core.prefs
*.log
-------------------------
AuthZForce CORE version @version- Release Notes
-------------------------
-------------------
-- Version @version
-------------------
-------------------
-- Version 3.4.2
-------------------
Fixing bug on Rule Algorithm:
- DenyUnlessPermitRuleAlg.java
- PermitUnlessDenyRuleAlg.java.
=> A cast was misplaced and an error occured on the combination of rules
-------------------
-- Version 3.4.0
-------------------
Implementation working with XACML 3.0 requests and policies. Based on OASIS model (xsd)
Artifact name refactored => authzforce-core-authzforce in order to be more clear in the Nexus repository
Partial implementation of the Multi Decision Request. The Multi Request is not implemented yet
Functionnal tests added for XACML 3.0 model. This is actually the OASIS functionnal tests translated to a v3.O model
BasicV3 => OK
BasicFunctionV3 => OK
ConformanceV3 => OK
Implementation of the "Include in result" attribute
Full support of obligations
Full support of advices
Apache 2.0 licence headers added to every source file
Audit log based on annotations for Rule and Policies.
Use @Audit(type = [RULE || POLICY]) over a method returning a result. You can also use @Audit(type = DISPLAY) to display and clear the logs.
Non exhaustif list of improvement and implementation
Combining algorithm
OK urn:oasis:names:tc:xacml:3.0:rule-combining-algorithm:deny-unless-permit
OK urn:oasis:names:tc:xacml:3.0:policy-combining-algorithm:deny-unless-permit
OK urn:oasis:names:tc:xacml:3.0:rule-combining-algorithm:permit-unless-deny
OK urn:oasis:names:tc:xacml:3.0:policy-combining-algorithm:permit-unless-deny
Functions
OK urn:oasis:names:tc:xacml:3.0:function:string-starts-with
OK urn:oasis:names:tc:xacml:3.0:function:string-ends-with
OK urn:oasis:names:tc:xacml:3.0:function:string-contains
OK urn:oasis:names:tc:xacml:3.0:function:string-substring
-------------------
-- Version 2.1.4
-------------------
Stable version working with XACML 2.0
-------------------------
AuthZForce CORE version @version- Release Notes
-------------------------
-------------------
-- Version @version
-------------------
-------------------
-- Version 3.4.2
-------------------
Fixing bug on Rule Algorithm:
- DenyUnlessPermitRuleAlg.java
- PermitUnlessDenyRuleAlg.java.
=> A cast was misplaced and an error occured on the combination of rules
-------------------
-- Version 3.4.0
-------------------
Implementation working with XACML 3.0 requests and policies. Based on OASIS model (xsd)
Artifact name refactored => authzforce-core-authzforce in order to be more clear in the Nexus repository
Partial implementation of the Multi Decision Request. The Multi Request is not implemented yet
Functionnal tests added for XACML 3.0 model. This is actually the OASIS functionnal tests translated to a v3.O model
BasicV3 => OK
BasicFunctionV3 => OK
ConformanceV3 => OK
Implementation of the "Include in result" attribute
Full support of obligations
Full support of advices
Apache 2.0 licence headers added to every source file
Audit log based on annotations for Rule and Policies.
Use @Audit(type = [RULE || POLICY]) over a method returning a result. You can also use @Audit(type = DISPLAY) to display and clear the logs.
Non exhaustif list of improvement and implementation
Combining algorithm
OK urn:oasis:names:tc:xacml:3.0:rule-combining-algorithm:deny-unless-permit
OK urn:oasis:names:tc:xacml:3.0:policy-combining-algorithm:deny-unless-permit
OK urn:oasis:names:tc:xacml:3.0:rule-combining-algorithm:permit-unless-deny
OK urn:oasis:names:tc:xacml:3.0:policy-combining-algorithm:permit-unless-deny
Functions
OK urn:oasis:names:tc:xacml:3.0:function:string-starts-with
OK urn:oasis:names:tc:xacml:3.0:function:string-ends-with
OK urn:oasis:names:tc:xacml:3.0:function:string-contains
OK urn:oasis:names:tc:xacml:3.0:function:string-substring
-------------------
-- Version 2.1.4
-------------------
Stable version working with XACML 2.0
......@@ -58,7 +58,6 @@
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>com.thalesgroup.ktd.scis</groupId>
......
......@@ -613,7 +613,7 @@ public abstract class AbstractPolicy extends oasis.names.tc.xacml._3_0.core.sche
((CombinerElement) (it.next())).encode(output, indenter);
}
if (obligationExpressions.getObligationExpressions().size() != 0) {
if (obligationExpressions != null && !obligationExpressions.getObligationExpressions().isEmpty()) {
PrintStream out = new PrintStream(output);
String indent = indenter.makeString();
......@@ -628,6 +628,22 @@ public abstract class AbstractPolicy extends oasis.names.tc.xacml._3_0.core.sche
out.println(indent + "</Obligations>");
indenter.out();
}
if (adviceExpressions != null && !adviceExpressions.getAdviceExpressions().isEmpty()) {
PrintStream out = new PrintStream(output);
String indent = indenter.makeString();
out.println(indent + "<AssociateAdvice>");
indenter.in();
it = adviceExpressions.getAdviceExpressions().iterator();
while (it.hasNext()) {
((Obligation) (it.next())).encode(output, indenter);
}
out.println(indent + "</AssociateAdvice>");
indenter.out();
}
}
@Override
......
......@@ -41,12 +41,12 @@ import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Unmarshaller;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.Advice;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.AdviceExpression;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.AssociatedAdvice;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeAssignment;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeAssignmentExpression;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.CombinerParametersType;
......@@ -67,7 +67,7 @@ import com.sun.xacml.combine.PolicyCombinerElement;
import com.sun.xacml.combine.PolicyCombiningAlgorithm;
import com.sun.xacml.ctx.Result;
import com.sun.xacml.xacmlv3.AdviceExpressions;
import com.sun.xacml.xacmlv3.Policy;
import com.sun.xacml.xacmlv3.IPolicy;
import com.sun.xacml.xacmlv3.Target;
/**
......@@ -77,7 +77,7 @@ import com.sun.xacml.xacmlv3.Target;
* @author Seth Proctor
* @author Marco Barreno
*/
public abstract class AbstractPolicySet extends oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicySet {
public abstract class AbstractPolicySet extends oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicySet implements IPolicy {
// atributes associated with this policy
// private URI idAttr;
......@@ -202,17 +202,26 @@ public abstract class AbstractPolicySet extends oasis.names.tc.xacml._3_0.core.s
this.version = version;
}
// FIXME: this needs to fill in the meta-data correctly
metaData = null;
metaData = new PolicyMetaData(PolicyMetaData.XACML_3_0_IDENTIFIER, defaultVersion);
if (obligations == null) {
this.obligationExpressions = new oasis.names.tc.xacml._3_0.core.schema.wd_17.ObligationExpressions();
/*
* obligationExpressions must be null by default, if you create new
* ObligationExpressions() in this case, the result Obligations will be marshalled to
* empty <Obligations /> element which is NOT VALID against the XACML schema.
*/
this.obligationExpressions = null;
} else {
this.obligationExpressions = obligations;
}
if (advices == null) {
this.adviceExpressions = new oasis.names.tc.xacml._3_0.core.schema.wd_17.AdviceExpressions();
/*
* adviceExpressions must be null by default, if you create new
* AdviceExpressions() in this case, the result AssociatedAdvice will be marshalled to
* empty <AssociatedAdvice /> element which is NOT VALID against the XACML schema.
*/
this.adviceExpressions = null;
} else {
this.adviceExpressions = advices;
}
......@@ -297,9 +306,19 @@ public abstract class AbstractPolicySet extends oasis.names.tc.xacml._3_0.core.s
metaData = new PolicyMetaData(root.getNamespaceURI(), defaultVersion);
// now read the remaining policy elements
obligationExpressions = new oasis.names.tc.xacml._3_0.core.schema.wd_17.ObligationExpressions();
/*
* obligationExpressions must be null by default, if you create new
* ObligationExpressions() in this case, the result Obligations will be marshalled to
* empty <Obligations /> element which is NOT VALID against the XACML schema.
*/
obligationExpressions = null;
this.policySetsAndPoliciesAndPolicySetIdReferences = new ArrayList();
adviceExpressions = new oasis.names.tc.xacml._3_0.core.schema.wd_17.AdviceExpressions();
/*
* obligationExpressions must be null by default, if you create new
* AdviceExpressions() in this case, the result AssociatedAdvice will be marshalled to
* empty <AssociatedAdvice /> element which is NOT VALID against the XACML schema.
*/
adviceExpressions = null;
_children = root.getChildNodes();
List myPolicies = new ArrayList();
......@@ -442,11 +461,7 @@ public abstract class AbstractPolicySet extends oasis.names.tc.xacml._3_0.core.s
return version;
}
/**
* Returns the combining algorithm used by this policy
*
* @return the combining algorithm
*/
@Override
public CombiningAlgorithm getCombiningAlg() {
return combiningAlg;
}
......@@ -467,6 +482,7 @@ public abstract class AbstractPolicySet extends oasis.names.tc.xacml._3_0.core.s
*
* @return the description or null
*/
@Override
public String getDescription() {
return description;
}
......@@ -496,8 +512,9 @@ public abstract class AbstractPolicySet extends oasis.names.tc.xacml._3_0.core.s
*
* @return a <code>List</code> of child nodes
*/
@Override
public List getChildren() {
return children;
return policySetsAndPoliciesAndPolicySetIdReferences;
}
/**
......@@ -508,8 +525,9 @@ public abstract class AbstractPolicySet extends oasis.names.tc.xacml._3_0.core.s
*
* @return a <code>List</code> of <code>CombinerElement</code>s
*/
@Override
public List getChildElements() {
return childElements;
return policySetsAndPoliciesAndPolicySetIdReferences;
}
/**
......@@ -524,6 +542,7 @@ public abstract class AbstractPolicySet extends oasis.names.tc.xacml._3_0.core.s
/**
* Returns the meta-data associated with this policy
*/
@Override
public PolicyMetaData getMetaData() {
return metaData;
}
......@@ -539,6 +558,7 @@ public abstract class AbstractPolicySet extends oasis.names.tc.xacml._3_0.core.s
*
* @return the result of trying to match the policy and the request
*/
@Override
public MatchResult match(EvaluationCtx context) {
/**
* Romain Ferrari (Thales)
......@@ -598,25 +618,26 @@ public abstract class AbstractPolicySet extends oasis.names.tc.xacml._3_0.core.s
*
* @return the result of evaluation
*/
@Override
public Result evaluate(EvaluationCtx context) {
Result result = null;
List policies = new ArrayList();
List<IPolicy> policies = new ArrayList<>();
CombinerParametersType combParams = new CombinerParametersType();
for (Object element : this.policySetsAndPoliciesAndPolicySetIdReferences) {
if (element instanceof PolicyCombinerElement) {
if (((PolicyCombinerElement) element).getElement() instanceof Policy) {
policies.add((Policy) ((PolicyCombinerElement) element)
.getElement());
} else if (((PolicyCombinerElement) element).getElement() instanceof PolicySet) {
policies.add((PolicySet) ((PolicyCombinerElement) element)
.getElement());
final Object combinerElt = ((PolicyCombinerElement) element).getElement();
if (combinerElt instanceof IPolicy) {
policies.add((IPolicy) combinerElt);
} else {
continue;
}
}
}
// evaluate
result = this.combiningAlg.combine(context, combParams, policies);
if (obligationExpressions.getObligationExpressions().size() > 0) {
if (obligationExpressions != null && !obligationExpressions.getObligationExpressions().isEmpty()) {
// now, see if we should add any obligations to the set
int effect = result.getDecision().ordinal();
......@@ -634,13 +655,23 @@ public abstract class AbstractPolicySet extends oasis.names.tc.xacml._3_0.core.s
}
}
/* If we have advice, it's definitely a 3.0 policy */
if (adviceExpressions.getAdviceExpressions().size() > 0) {
if (adviceExpressions != null && !adviceExpressions.getAdviceExpressions().isEmpty()) {
int effect = result.getDecision().ordinal();
if ((effect == DecisionType.INDETERMINATE.ordinal()) || (effect == DecisionType.NOT_APPLICABLE.ordinal())) {
// we didn't permit/deny, so we never return advices
return result;
}
final AssociatedAdvice returnAssociatedAdvice = result.getAssociatedAdvice();
final AssociatedAdvice newAssociatedAdvice;
if(returnAssociatedAdvice == null) {
newAssociatedAdvice = new AssociatedAdvice();
result.setAssociatedAdvice(newAssociatedAdvice);
} else {
newAssociatedAdvice = returnAssociatedAdvice;
}
for (AdviceExpression adviceExpr : adviceExpressions.getAdviceExpressions()) {
if (adviceExpr.getAppliesTo().ordinal() == effect) {
Advice advice = new Advice();
......@@ -655,6 +686,8 @@ public abstract class AbstractPolicySet extends oasis.names.tc.xacml._3_0.core.s
myAttrAssType.setIssuer(attrExpr.getIssuer());
advice.getAttributeAssignments().add(myAttrAssType);
}
newAssociatedAdvice.getAdvices().add(advice);
}
}
}
......@@ -680,7 +713,7 @@ public abstract class AbstractPolicySet extends oasis.names.tc.xacml._3_0.core.s
((CombinerElement) (it.next())).encode(output, indenter);
}
if (obligationExpressions.getObligationExpressions().size() != 0) {
if (obligationExpressions != null && !obligationExpressions.getObligationExpressions().isEmpty()) {
PrintStream out = new PrintStream(output);
String indent = indenter.makeString();
......@@ -695,6 +728,22 @@ public abstract class AbstractPolicySet extends oasis.names.tc.xacml._3_0.core.s
out.println(indent + "</Obligations>");
indenter.out();
}
if (adviceExpressions != null && !adviceExpressions.getAdviceExpressions().isEmpty()) {
PrintStream out = new PrintStream(output);
String indent = indenter.makeString();
out.println(indent + "<AssociatedAdvice>");
indenter.in();
it = adviceExpressions.getAdviceExpressions().iterator();
while (it.hasNext()) {
((Obligation) (it.next())).encode(output, indenter);
}
out.println(indent + "</AssociatedAdvice>");
indenter.out();
}
}
@Override
......
......@@ -38,11 +38,13 @@
package com.sun.xacml;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.validation.SchemaFactory;
/**
*
......@@ -123,12 +125,6 @@ public class BindingUtility {
return docBuilder;
}
};
public static oasis.names.tc.xacml._3_0.core.schema.wd_17.ObjectFactory contextFac =
new oasis.names.tc.xacml._3_0.core.schema.wd_17.ObjectFactory();
public static oasis.names.tc.xacml._3_0.core.schema.wd_17.ObjectFactory policyFac =
new oasis.names.tc.xacml._3_0.core.schema.wd_17.ObjectFactory();
/**
* Get thread-local document builder. The client must call the {@link DocumentBuilder#reset()} after calling any parse() methods to preserve thread-safety..
......
/**
*
* Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistribution of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
* ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN")
* AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
* AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
* REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
* INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
* OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed or intended for use in
* the design, construction, operation or maintenance of any nuclear facility.
*/
package com.sun.xacml;
import org.w3c.dom.Node;
public class DOMHelper {
public static String getLocalName(Node child) {
String localName = child.getLocalName();
if (localName == null)
return child.getNodeName();
return localName;
}
/**
*
* Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistribution of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
* ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN")
* AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
* AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
* REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
* INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
* OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed or intended for use in
* the design, construction, operation or maintenance of any nuclear facility.
*/
package com.sun.xacml;
import org.w3c.dom.Node;
public class DOMHelper {
public static String getLocalName(Node child) {
String localName = child.getLocalName();
if (localName == null)
return child.getNodeName();
return localName;
}
}
\ No newline at end of file
/**
*
* Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistribution of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
* ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN")
* AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
* AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
* REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
* INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
* OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed or intended for use in
* the design, construction, operation or maintenance of any nuclear facility.
*/
package com.sun.xacml;
import java.util.Arrays;
/**
* Provides flexible indenting for XML encoding. This class generates
* strings of spaces to be prepended to lines of XML. The strings are
* formed according to a specified indent width and the given depth.
*
* @since 1.0
* @author Marco Barreno
* @author Seth Proctor
*/
public class Indenter
{
/**
* The default indentation width
*/
public static final int DEFAULT_WIDTH = 2;
// The width of one indentation level
private int width;
// the current depth
private int depth;
/**
* Constructs an <code>Indenter</code> with the default indent
* width.
*/
public Indenter() {
this(DEFAULT_WIDTH);
}
/**
* Constructs an <code>Indenter</code> with a user-supplied indent
* width.
*
* @param userWidth the number of spaces to use for each indentation level
*/
public Indenter(int userWidth) {
width = userWidth;
depth = 0;
}
/**
* Move in one width.
*/
public void in() {
depth += width;
}
/**
* Move out one width.
*/
public void out() {
depth -= width;
}
/**
* Create a <code>String</code> of spaces for indentation based on the
* current depth.
*
* @return an indent string to prepend to lines of XML
*/
public String makeString() {
// Return quickly if no indenting
if (depth <= 0) {
return "";
}
// Make a char array and fill it with spaces
char[] array = new char[depth];
Arrays.fill(array, ' ');
// Now return a string built from that char array
return new String(array);
}
}
/**
*
* Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*