/* The contents of this file are subject to the license and copyright terms
* detailed in the license directory at the root of the source tree (also
* available online at http://fedora-commons.org/license/).
*/
package org.fcrepo.test;
import java.io.FileInputStream;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Properties;
import java.util.Set;
import org.antlr.stringtemplate.StringTemplate;
/**
* Iterator that takes a set of attribute values from a values file
* and iterates by repeatedly substituting in the next set of values into the
* template
*
* values file format: java properties, with
* template.attribute.sets.count=n :
* number of sets to iterate over
* template.attribute.set.0.someattribute1=value1:
* template.attribute.set.0.someattribute2=value2:
* when on set iteration 0, substitute $someattribute1$ with value1
* and similarly $someattribute2$ with value2
* nb: sets are zero-indexed, numbered 0 to count - 1
* escape backslashes to \\
*
* @author Stephen Bayliss
* @version $Id$
*/
public class TemplatedResourceIterator implements Iterator<String> {
// template source
private final String m_templateSource;
// properties file contains attributes and values to substitute
private final String m_valuesFilename;
private final Properties m_values;
private final Set<String> m_propertyNames;
// number of sets to iterate
private final int m_setCount;
// index of next set to return with next()
private int m_nextSet = -1;
// for validation of consistent attribute counts across sets
int m_lastAttributeCount = -1;
// character escaping to perform
private final boolean m_escapeXML;
public TemplatedResourceIterator(String template, String valuesFilename) throws Exception {
this(template, valuesFilename, false);
}
public TemplatedResourceIterator(String template, String valuesFilename, boolean escapeXML) throws Exception {
m_escapeXML = escapeXML;
m_values = new Properties();
m_valuesFilename = valuesFilename;
m_values.load(new FileInputStream(m_valuesFilename));
m_setCount = Integer.parseInt(m_values.getProperty("template.attribute.sets.count"));
m_propertyNames = m_values.stringPropertyNames();
// the stuff to template
m_templateSource = template;
}
@Override
public boolean hasNext() {
return (m_nextSet + 1 < m_setCount);
}
@Override
public String next() {
if (m_nextSet++ >= m_setCount)
throw new NoSuchElementException();
// all properties in the current set start with...
String setPropertyNamePrefix = "template.attribute.set." + m_nextSet + ".";
StringTemplate tpl = new StringTemplate(m_templateSource);
int attributeCount = 0; // count number of attributes specified for replacement
for (String propertyName : m_propertyNames) {
// property for an attribute for the current set?
if (propertyName.startsWith(setPropertyNamePrefix)) {
// get attribute name and value
String attributeName = propertyName.replace(setPropertyNamePrefix, "");
String attributeValue = m_values.getProperty(propertyName);
// escape value if necessary
String value;
if (m_escapeXML) {
value = escapeXML(attributeValue);
} else {
value = attributeValue;
}
tpl.setAttribute(attributeName, value);
attributeCount++;
}
}
// some checks
if (attributeCount == 0)
throw new RuntimeException("No attributes found for set " + m_nextSet + " (" + m_valuesFilename + ")" );
if (m_lastAttributeCount != -1) {
if (m_lastAttributeCount != attributeCount)
throw new RuntimeException("Number of attributes is different in sets " + (m_nextSet -1) + " and " + m_nextSet + " (" + m_valuesFilename + ")" );
}
m_lastAttributeCount = attributeCount;
return tpl.toString();
}
public String getAttributeValue(String attributeName) {
// gets a named attribute for the current set
String propertyName = "template.attribute.set." + m_nextSet + "." + attributeName;
return m_values.getProperty(propertyName);
}
@Override
public void remove() {
throw new UnsupportedOperationException("Method remove() is not supported");
}
// TODO: make generic, allow different forms of escaping?
private String escapeXML(String toEscape) {
String res = toEscape;
// standard xml entities
// nb cast to CharSequence to prevent regex matching
res = res.replace("\"", """);
res = res.replace("'", "'");
res = res.replace("&", "&");
res = res.replace("<", "<");
res = res.replace(">", ">");
return res;
}
}