{
/**
* create a new instance from the non-null {@code firstGroup} specified.
*/
T apply(String firstGroup);
}
/**
* shortcut for new TransformFirstGroup(pattern, applyFirstGroup){}
when
* {@code String} is the type you are decoding into.
*
* Ex. to pull the first interesting element from an xml response:
*
*
* decodeFirstDirPoolID = firstGroup("<DirPoolID[ˆ>]*>([ˆ<]+)</DirPoolID>");
*
*/
public static Decoder.TextStream firstGroup(String pattern) {
return new TransformFirstGroup(pattern, IDENTITY) {
};
}
/**
* shortcut for new TransformEachFirstGroup(pattern, applyFirstGroup){}
when
* {@code List} is the type you are decoding into.
* Ex. to pull a list zones names, which are http paths starting with
* {@code /Rest/Zone/}:
*
*
* decodeListOfZonesNames = eachFirstGroup("/REST/Zone/([ˆ/]+)/");
*
*/
public static Decoder.TextStream> eachFirstGroup(String pattern) {
return new TransformEachFirstGroup(pattern, IDENTITY) {
};
}
private static String toString(Reader reader) throws IOException {
return TO_STRING.decode(reader, null).toString();
}
private static final StringDecoder TO_STRING = new StringDecoder();
private static final ApplyFirstGroup IDENTITY = new ApplyFirstGroup() {
@Override
public String apply(String firstGroup) {
return firstGroup;
}
};
/**
* The first match group is applied to {@code applyGroups} and result
* returned. If no matches are found, the response is null;
* Ex. to pull the first interesting element from an xml response:
*
*
* decodeFirstDirPoolID = new TransformFirstGroup<Long>("<DirPoolID[ˆ>]*>([ˆ<]+)</DirPoolID>", ToLong.INSTANCE) {
* };
*
*/
public static class TransformFirstGroup implements Decoder.TextStream {
private final Pattern patternForMatcher;
private final ApplyFirstGroup applyFirstGroup;
/**
* You must subclass this, in order to prevent type erasure on {@code T}
* . In addition to making a concrete type, you can also use the
* following form.
*
*
*
*
* new TransformFirstGroup<Foo>(pattern, applyFirstGroup) {
* }; // note the curly braces ensures no type erasure!
*
*/
protected TransformFirstGroup(String pattern, ApplyFirstGroup applyFirstGroup) {
this.patternForMatcher = compile(checkNotNull(pattern, "pattern"), DOTALL);
this.applyFirstGroup = checkNotNull(applyFirstGroup, "applyFirstGroup");
}
@Override
public T decode(Reader reader, Type type) throws IOException {
Matcher matcher = patternForMatcher.matcher(Decoders.toString(reader));
if (matcher.find()) {
return applyFirstGroup.apply(matcher.group(1));
}
return null;
}
@Override
public String toString() {
return format("decode groups from %s into %s", patternForMatcher, applyFirstGroup);
}
}
/**
* On the each find the first match group is applied to
* {@code applyFirstGroup} and added to the list returned. If no matches are
* found, the response is an empty list;
* Ex. to pull a list zones constructed from http paths starting with
* {@code /Rest/Zone/}:
*
*
*
*
* decodeListOfZones = new TransformEachFirstGroup("/REST/Zone/([ˆ/]+)/", ToZone.INSTANCE) {
* };
*
*/
public static class TransformEachFirstGroup implements Decoder.TextStream> {
private final Pattern patternForMatcher;
private final ApplyFirstGroup applyFirstGroup;
/**
* You must subclass this, in order to prevent type erasure on {@code T}
* . In addition to making a concrete type, you can also use the
* following form.
*
*
*
*
* new TransformEachFirstGroup<Foo>(pattern, applyFirstGroup) {
* }; // note the curly braces ensures no type erasure!
*
*/
protected TransformEachFirstGroup(String pattern, ApplyFirstGroup applyFirstGroup) {
this.patternForMatcher = compile(checkNotNull(pattern, "pattern"), DOTALL);
this.applyFirstGroup = checkNotNull(applyFirstGroup, "applyFirstGroup");
}
@Override
public List decode(Reader reader, Type type) throws IOException {
Matcher matcher = patternForMatcher.matcher(Decoders.toString(reader));
List result = new ArrayList();
while (matcher.find()) {
result.add(applyFirstGroup.apply(matcher.group(1)));
}
return result;
}
@Override
public String toString() {
return format("decode %s into list elements, where each group(1) is transformed with %s",
patternForMatcher, applyFirstGroup);
}
}
}