⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 query.java

📁 webwork source
💻 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 + -