package org.jboss.jsfunit.analysis.el;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.regex.MatchResult;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
*
* @author Jason
* @since 1.0
*/
public class ELExpressionIterator implements Iterator<ELBundle>
{
private static final Pattern EL_EXPRESSION_PATTERN =
Pattern.compile( "(?:\\s(\\S+?)\\s*=)?" + //Optional attribute name
"\\s*[\"']?\\s*" + //Separator junk
"([#$]\\{(.*?)})", //EL expression
Pattern.MULTILINE );
private final File file;
private ELBundle next;
private final Matcher matcher;
final Collection<Pattern> skipPatterns;
private static CharBuffer fileAsCharBuffer(final File f)
throws IOException
{
final FileChannel fc = new FileInputStream(f).getChannel();
final ByteBuffer bb =
fc.map(FileChannel.MapMode.READ_ONLY, 0, (int) fc.size());
final CharBuffer cb = Charset.forName("UTF-8").newDecoder().decode(bb);
return cb;
}
public ELExpressionIterator(final File file,
final Collection<Pattern> skipPatterns)
throws IOException
{
this.file = file;
this.skipPatterns = skipPatterns;
matcher = EL_EXPRESSION_PATTERN.matcher(fileAsCharBuffer(file));
}
private ELBundle makeELBundle(final MatchResult matchResult) {
final String expression, context;
switch(matchResult.groupCount()) {
//TODO: docs say group 0 not included in the count, which seems
//wrong?
case 2:
//just an EL expression, no attribute.
context = "";
expression = matchResult.group(1);
break;
case 3:
context = matchResult.group(1);
expression = matchResult.group(2);
break;
default:
final StringBuilder err = new StringBuilder("Unexpected match result:");
for(int i=0;i<matchResult.groupCount();i++) {
err.append(" " + i +": " + matchResult.group(i));
}
throw new RuntimeException(err.toString());
}
return new ELBundle(expression, file, context, matchResult.start());
}
public boolean hasNext()
{
top:
while(next == null && matcher.find()) {
for(final Pattern p: skipPatterns) {
if(p.matcher(matcher.group()).find()) {
continue top;
}
}
next = makeELBundle(matcher.toMatchResult());
}
return next != null;
}
public ELBundle next()
{
if(hasNext()) {
final ELBundle out = next;
next = null;
return out;
}
else {
throw new NoSuchElementException();
}
}
public void remove()
{
throw new UnsupportedOperationException();
}
}