📄 query.java
字号:
/*
* WebWork, Web Application Framework
*
* Distributable under Apache license.
* See terms of license at opensource.org
*/
package webwork.util;
import java.util.HashMap;
import java.util.Map;
/**
* ValueStack Query. This class parsers the ValueStack Query string
* and caches the parsed query.
*
* @author Maurice C. Parker (maurice@vineyardenterprise.com)
* @version $Revision: 1.24 $
*/
public class Query {
// Static -------------------------------------------------------
protected static Map queries = new ConcurrentReaderHashMap();
public static final Query CURRENT = getQuery(".");
/**
* Create a new Query and cache it for faster processing;
*
*/
public static Query getQuery(String queryString) {
//LogFactory.getLog(this.getClass()).debug( "GET_QUERY: " + queryString );
Query query = (Query) queries.get(queryString);
if (query == null) {
query = new Query(queryString);
queries.put(queryString, query);
}
return query;
}
// Attributes ----------------------------------------------------
private final static char LPAREN = '(';
private final static char RPAREN = ')';
private final static char RBRACE = '}';
private final static char LBRACE = '{';
private final static char LBRACKET = '[';
private final static char RBRACKET = ']';
private final static char PARAM = '$';
private final static char ATTR = '@';
private final static char SLASH = '/';
private final static char SQUOTE = '\'';
private final static char PERIOD = '.';
private final static char COMMA = ',';
private QuerySegment[] segments = new QuerySegment[5];
private int segmentsIdx = 0;
private String queryString;
// Constructor ---------------------------------------------------
private Query(String queryString) {
// Trim the query of any surrounding whitespace
this.queryString = queryString.trim();
char[] query = this.queryString.toCharArray();
// Current value on top of stack
if (query[0] == PERIOD && query.length == 1) {
add(new QuerySegment(QuerySegment.CURRENT));
return;
}
// Root value of stack
if (query[0] == SLASH && query.length == 1) {
add(new QuerySegment(QuerySegment.ROOT));
return;
}
// Strings
if (query[0] == SQUOTE) {
if (query[query.length - 1] != SQUOTE)
throwIllegalArgumentException(query, "missing matching end quote");
// create the new string constant
String id = new String(query, 1, query.length - 2);
add(new QuerySegment(id, QuerySegment.STRING));
return;
}
// Parameters
if (query[0] == PARAM) {
String id = new String(query, 1, query.length - 1);
add(new QuerySegment(id, QuerySegment.PARAMETER));
return;
}
// The true keyword
if (query.length == 4 &&
query[0] == 't' && query[1] == 'r' &&
query[2] == 'u' && query[3] == 'e') {
add(new QuerySegment(QuerySegment.TRUE));
return;
}
// The false keyword
if (query.length == 5 &&
query[0] == 'f' && query[1] == 'a' &&
query[2] == 'l' && query[3] == 's' &&
query[4] == 'e') {
add(new QuerySegment(QuerySegment.FALSE));
return;
}
// The null keyword
if (query.length == 4 &&
query[0] == 'n' && query[1] == 'u' &&
query[2] == 'l' && query[3] == 'l') {
add(new QuerySegment(QuerySegment.NULL));
return;
}
// Integers (first check to see if the first character is a number)
// If it is a number starting with . then there must be at least
// one more character and it must be a number
if ((query[0] < ':' && query[0] > '/') || query[0] == '-' ||
(query[0] == '.' && query.length > 1 && (query[1] < ':' && query[1] > '/'))) {
Object val;
try {
String s = new String(query, 0, query.length);
if (s.indexOf('.') >= 0) {
val = new Double(s);
} else {
val = new Integer(s);
}
QuerySegment qs = new QuerySegment(QuerySegment.NUMBER);
qs.addValue(val);
add(qs);
return;
} catch (NumberFormatException nfe) {
}
}
// Always leave the query index on a token
int queryIdx = -1;
// Attributes
if (query[0] == ATTR) {
// search for the beginning of the next name element and create the attribute name
for (queryIdx = 1;
queryIdx < query.length && query[queryIdx] != SLASH && query[queryIdx] != LBRACKET;
queryIdx++) {
}
String id = new String(query, 1, queryIdx - 1);
//Category.getInstance(this.getClass()).debug("getting attribute name: " + attrName);
add(new QuerySegment(id, QuerySegment.ATTRIBUTE));
// if we are done at this point, don't fall through the rest of the method
if (queryIdx == query.length)
return;
// if the index is sitting on a left bracket, back it off by one. the next phase
// of the parser expects slashes to be skipped, but not other elements.
if (query[queryIdx] == LBRACKET)
queryIdx--;
}
int lastExprIdx;
int begParenIdx;
int begBracketIdx;
int endBracketIdx;
int begBraceIdx;
int endBraceIdx;
int paramStart;
int paramEnd;
int[] paramIdxs = new int[10];
int commaNbr;
int parenDepth;
int braceDepth;
int bracketDepth;
int squoteDepth;
do // this loop is to search through the query elements
{
lastExprIdx = queryIdx;
begParenIdx = -1;
begBracketIdx = -1;
endBracketIdx = -1;
begBraceIdx = -1;
endBraceIdx = -1;
paramIdxs[0] = -1;
paramIdxs[1] = -1;
paramIdxs[2] = -1;
paramIdxs[3] = -1;
paramIdxs[4] = -1;
paramIdxs[5] = -1;
paramIdxs[6] = -1;
paramIdxs[7] = -1;
paramIdxs[8] = -1;
paramIdxs[9] = -1;
commaNbr = 0;
parenDepth = 0;
braceDepth = 0;
bracketDepth = 0;
squoteDepth = 0;
while (true) {
queryIdx++;
if (queryIdx == query.length)
break;
//Category.getInstance(this.getClass()).debug("queryIdx: " + queryIdx + " query position: " + query[queryIdx] );
if (query[queryIdx] == SLASH) {
// check to make sure that this isn't an embedded slash
if ((parenDepth > 0) || (braceDepth > 0) || (bracketDepth > 0) || (squoteDepth > 0)) {
//Category.getInstance(this.getClass()).debug("skipping embedded slash at pos: " + queryIdx );
continue;
} else if (queryIdx == 0) {
//Category.getInstance(this.getClass()).debug("root query segment found");
add(new QuerySegment(QuerySegment.ROOT));
lastExprIdx = 0;
continue;
} else {
//Category.getInstance(this.getClass()).debug("breaking element parse loop at pos: " + queryIdx );
break;
}
}
// parens
else if (query[queryIdx] == LPAREN) {
parenDepth++;
if (begParenIdx < 0 && braceDepth == 0 && bracketDepth == 0 && squoteDepth == 0)
begParenIdx = queryIdx;
} else if (query[queryIdx] == RPAREN) {
parenDepth--;
paramIdxs[commaNbr] = queryIdx;
}
// brackets
else if (query[queryIdx] == LBRACKET) {
bracketDepth++;
if (begBracketIdx < 0 && parenDepth == 0 && braceDepth == 0 && squoteDepth == 0)
begBracketIdx = queryIdx;
} else if (query[queryIdx] == RBRACKET) {
bracketDepth--;
endBracketIdx = queryIdx;
}
// braces
else if (query[queryIdx] == LBRACE) {
braceDepth++;
if (begBraceIdx < 0 && parenDepth == 0 && bracketDepth == 0 && squoteDepth == 0)
begBraceIdx = queryIdx;
} else if (query[queryIdx] == RBRACE) {
braceDepth--;
endBraceIdx = queryIdx;
}
// single quotes
else if (query[queryIdx] == SQUOTE) {
// we can only quote one level deep
if (squoteDepth < 1)
squoteDepth++;
else
squoteDepth--;
} else if (query[queryIdx] == COMMA) {
// only look for commas that are in the current method and
// not embedded in a quoted string
if (parenDepth == 1 && squoteDepth == 0) {
paramIdxs[commaNbr] = queryIdx;
commaNbr++;
}
}
}
if (squoteDepth > 0)
throwIllegalArgumentException(query, "missing matching end quote");
//-- Expression Expansion
if (begBraceIdx > -1) {
if (endBraceIdx < 0)
throwIllegalArgumentException(query, "missing matching brace");
String id = new String(query, begBraceIdx + 1, endBraceIdx - (begBraceIdx + 1));
Query expandQuery = getQuery(id);
add(new QuerySegment(id, expandQuery, QuerySegment.EXPAND));
}
//-- Method
else if (begParenIdx > -1) {
if (paramIdxs[0] < 0)
throwIllegalArgumentException(query, "missing matching parenthesis");
// parse out the name of the method
String id = new String(query, lastExprIdx + 1, begParenIdx - (lastExprIdx + 1));
QuerySegment qs = new QuerySegment(id, QuerySegment.METHOD);
// parse out the method parameters
paramStart = begParenIdx + 1;
commaNbr = -1;
// build the parameters for the method
while (paramIdxs[++commaNbr] > -1) {
// set the end to be one less than the token position
paramEnd = paramIdxs[commaNbr] - 1;
// trim it out any white space
while ((paramStart < paramEnd) && (query[paramStart] <= ' ')) {
paramStart++;
}
while ((paramStart < paramEnd) && (query[paramEnd] <= ' ')) {
paramStart--;
}
// create the parsed parameter and add it to the query segment
String parameter = new String(query, paramStart, (paramEnd - paramStart) + 1).trim();
// If it is the first and only parameter and it is not empty, then don't add it
if (commaNbr==0 && paramIdxs[commaNbr+1] <= -1 && parameter.length()==0)
qs.createValues();
else
{
Query paramQuery = getQuery(parameter);
qs.addValue(paramQuery);
}
// bump the start one past the end token position
paramStart = paramIdxs[commaNbr] + 1;
}
add(qs);
}
//-- Parent Access
else if (lastExprIdx + 2 < query.length &&
query[lastExprIdx + 1] == PERIOD &&
query[lastExprIdx + 2] == PERIOD) {
add(new QuerySegment(QuerySegment.PARENT));
}
//-- Current Access
else if (lastExprIdx + 1 < query.length &&
query[lastExprIdx + 1] == PERIOD) {
add(new QuerySegment(QuerySegment.CURRENT));
}
// check to see if this will be a collection only access
else if (lastExprIdx + 1 != begBracketIdx) {
int propertyEnd;
if (begBracketIdx > -1)
propertyEnd = begBracketIdx;
else
propertyEnd = queryIdx;
// Parse out the property name
String id = new String(query, lastExprIdx + 1, propertyEnd - (lastExprIdx + 1));
add(new QuerySegment(id, QuerySegment.PROPERTY));
}
//-- Collection access
if (begBracketIdx > -1) {
if (endBracketIdx < 0)
throwIllegalArgumentException(query, "missing matching bracket");
// parse out the name of the key
String key = new String(query, begBracketIdx + 1, endBracketIdx - (begBracketIdx + 1));
Query queryKey = getQuery(key);
add(new QuerySegment(key, queryKey, QuerySegment.COLLECTION));
}
} while (queryIdx < query.length);
}
// Public --------------------------------------------------------
/**
* Returns the parsed query segments.
*/
public QuerySegment[] getSegments() {
return segments;
}
/**
* String representation of this object.
*/
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("query=\"").append(queryString).append("\"");
for (int i = 0; i < segments.length; i++) {
QuerySegment segment = segments[i];
if (segment!=null) {
sb.append(" {").append(segment).append("}");
}
}
return sb.toString();
}
// Private -------------------------------------------------------
/**
* Always throws IllegalArgumentException.
*/
private Object throwIllegalArgumentException(char[] query, String message) {
throw new IllegalArgumentException(message + " for query: " + new String(query));
}
/**
* Add another segment to the segments array.
*/
private void add(QuerySegment qs) {
if (segmentsIdx == segments.length-1) {
QuerySegment[] resize = new QuerySegment[segments.length + 5];
System.arraycopy(segments, 0, resize, 0, segments.length);
segments = resize;
}
segments[segmentsIdx++] = qs;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -