/* (c) 2014 Open Source Geospatial Foundation - all rights reserved
* (c) 2001 - 2013 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.ows;
import java.util.ArrayList;
import java.util.List;
import org.geoserver.ows.util.KvpUtils;
/**
* A kvp parser which parses a value consisting of tokens in a nested list.
* <p>
* A value in nested form is a number of lists of tokens, seperated by an outer
* delimeter. The tokens in each list are serarated by an inner delimiter
* The default outer delimiter is are parentheses ( '()' ) , the default inner
* delimter is a comma ( ',' ). Example:
* </p>
* <pre><code>
* key=(token11,token12,...,token1N)(token21,token22,...,token2N)(...)(tokenM1,tokenM2,...,tokenMN)
*
* where N = number of tokens in each set, and M = number of sets.
* </code>
* </pre>
* <p>
* Upon processing of each token, the token is parsed into an instance of
* {@link #getBinding()}. Subclasses should override the method
* {@link #parseToken(String)}.
* </p>
* <p>
* By default, the {@link #parse(String)} method returns a list of lists. Each
* of which contains instances of {@link #getBinding()}. The {@link #parseTokenSet(List)}
* method may be overidden to return a differnt type of object.
* </p>
* @author Justin Deoliveira, The Open Planning Project, jdeolive@openplans.org
*
* TODO: add a method to convert return value as to not force returning a list
*/
public class NestedKvpParser extends KvpParser {
/**
* Constructs the nested kvp parser specifying the key and class binding.
*
* @param key The key to bind to.
* @param binding The class of each token in the value.
*/
public NestedKvpParser(String key, Class binding) {
super(key, binding);
}
/**
* Tokenizes the value and delegates to {@link #parseToken(String)} to
* parse each token.
*/
public Object parse(String value) throws Exception {
List tokenSets = KvpUtils.readNested(value);
for (int i = 0; i < tokenSets.size(); i++) {
List tokens = (List) tokenSets.get(i);
List parsed = new ArrayList(tokens.size());
for (int j = 0; j < tokens.size(); j++) {
String token = (String) tokens.get(j);
parsed.add(parseToken(token));
}
tokenSets.set(i, parseTokenSet(parsed));
}
return parse(tokenSets);
}
/**
* Parses the token into an instance of {@link #getBinding()}.
* <p>
* Subclasses should override this method, the default implementation
* just returns token passed in.
* </p>
* @param token Part of the value being parsed.
*
* @return The token parsed into an object.
*
*/
protected Object parseToken(String token) throws Exception {
return token;
}
/**
* Parses the set of tokens into a final represetnation.
* <p>
* Subclasses may choose to override this method. The default implementation
* just return the list passed in.
* </p>
* @param tokenSet The parsed tokens, each value is an instance of {@link #getBinding()}.
*
* @return The final object.
*/
protected Object parseTokenSet(List tokenSet) throws Exception {
return tokenSet;
}
/**
* Parses the set of token sets into a final representation.
* <p>
* Subclasses may choose to override this method. The default implementation
* just return the list passed in.
* </p>
* @param values The parsed token sets, each value is an instance of the
* class returned from {@link #parseTokenSet(List)}.
*
* @return The final object.
*/
protected Object parse(List values) throws Exception {
return values;
}
}