/* * Licensed to the Apache Software Foundation (ASF) under one or more contributor license * agreements. See the NOTICE file distributed with this work for additional information regarding * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the License. You may obtain a * copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package org.apache.geode.cache.query.internal; import java.lang.reflect.*; import java.util.*; import org.apache.geode.cache.query.AmbiguousNameException; import org.apache.geode.cache.query.NameResolutionException; import org.apache.geode.cache.query.QueryInvocationTargetException; import org.apache.geode.cache.query.NameNotFoundException; import org.apache.geode.cache.query.QueryService; import org.apache.geode.cache.query.Struct; import org.apache.geode.cache.query.TypeMismatchException; import org.apache.geode.cache.query.internal.parse.OQLLexerTokenTypes; import org.apache.geode.cache.query.types.*; import org.apache.geode.cache.query.internal.types.*; /** * Class Description * * @version $Revision: 1.1 $ */ public class PathUtils { public static String[] tokenizePath(String path) { ArrayList alist = new ArrayList(); StringTokenizer tokenizer = new StringTokenizer(path, "."); while (tokenizer.hasMoreTokens()) { alist.add(tokenizer.nextToken()); } return (String[]) alist.toArray(new String[alist.size()]); } public static String buildPathString(String[] path) { Support.assertArg(path != null && path.length > 0, "path should not be null or empty"); StringBuffer buf = new StringBuffer(); buf.append(path[0]); for (int i = 1; i < path.length; i++) { buf.append('.'); buf.append(path[i]); } return buf.toString(); } public static Object evaluateAttribute(Object target, String attribute) throws NameNotFoundException, QueryInvocationTargetException { if (target instanceof Struct) { Struct struct = (Struct) target; try { return struct.get(attribute); } catch (Exception e) { throw new NameNotFoundException(attribute); } } try { return new AttributeDescriptor(attribute).read(target); } catch (NameNotFoundException nfe) { if (DefaultQueryService.QUERY_HETEROGENEOUS_OBJECTS || DefaultQueryService.TEST_QUERY_HETEROGENEOUS_OBJECTS) { return QueryService.UNDEFINED; } else { throw nfe; } } } /* * This was added as part of CQ performance changes. The change is done to re-use the * AttributeDescriptor object instead of creating it each time. */ /* * public static Object evaluateAttribute(Object target, String attribute, AttributeDescriptor * attributeDescriptor) throws NameNotFoundException, QueryInvocationTargetException { if(target * instanceof Struct){ Struct struct = (Struct)target; try{ return struct.get(attribute); * }catch(Exception e){ throw new NameNotFoundException(attribute); } } return * attributeDescriptor.read(target); } */ /** * @param pathArray the path starting with an attribute on the initial type. * @return array of types starting with the initialType and ending with the type of the last * attribute in the path. * @throws NameNotFoundException if could not find an attribute along path * */ public static ObjectType[] calculateTypesAlongPath(ObjectType initialType, String[] pathArray) throws NameNotFoundException { ObjectType[] types = new ObjectType[pathArray.length + 1]; // initialClass goes in front types[0] = initialType; for (int i = 1; i < types.length; i++) { ObjectType currentType = types[i - 1]; Member member = new AttributeDescriptor(pathArray[i - 1]).getReadMember(currentType); if (member instanceof Field) types[i] = TypeUtils.getObjectType(((Field) member).getType()); else if (member instanceof Method) types[i] = TypeUtils.getObjectType(((Method) member).getReturnType()); } return types; } public static ObjectType computeElementTypeOfExpression(ExecutionContext context, CompiledValue expr) throws AmbiguousNameException { try { ObjectType type = TypeUtils.OBJECT_TYPE; List exprSteps = new ArrayList(); while (true) { if (expr instanceof CompiledPath) { CompiledPath path = (CompiledPath) expr; exprSteps.add(0, path.getTailID()); expr = path.getReceiver(); } else if (expr instanceof CompiledOperation) { CompiledOperation operation = (CompiledOperation) expr; if (operation.getArguments().size() > 0) { return TypeUtils.OBJECT_TYPE; } exprSteps.add(0, operation.getMethodName() + "()"); expr = operation.getReceiver(context); if (expr == null) { expr = context.resolveImplicitOperationName(operation.getMethodName(), operation.getArguments().size(), true); } } else if (expr instanceof CompiledID) { expr = context.resolve(((CompiledID) expr).getId()); } else if (expr instanceof CompiledRegion) { QRegion qrgn = (QRegion) ((CompiledRegion) expr).evaluate(context); type = qrgn.getCollectionType(); break; } else if (expr instanceof RuntimeIterator) { type = ((RuntimeIterator) expr).getElementType(); break; } else { return TypeUtils.OBJECT_TYPE; } } if (!TypeUtils.OBJECT_TYPE.equals(type)) { Class clazz = type.resolveClass(); for (int i = 0; i < exprSteps.size(); i++) { Member member; String stepStr = (String) exprSteps.get(i); // System.out.println("step = "+step); if (stepStr.endsWith("()")) { stepStr = stepStr.substring(0, stepStr.length() - 2); member = clazz.getMethod(stepStr, (Class[]) null); } else { member = new AttributeDescriptor(stepStr).getReadMember(clazz); } if (member instanceof Field) { clazz = ((Field) member).getType(); } else if (member instanceof Method) { clazz = ((Method) member).getReturnType(); } type = TypeUtils.getObjectType(clazz); } return type; } } catch (NoSuchMethodException e) { } catch (NameResolutionException e) { } catch (TypeMismatchException e) { } return TypeUtils.OBJECT_TYPE; } /** * Collects all the compiled values in the path , starting from the self at position 0 in the * returned List * * @param expr * @return List of CompiledValues ( includes the RuntimeIterator) * @throws TypeMismatchException * @throws AmbiguousNameException */ public static List<CompiledValue> collectCompiledValuesInThePath(CompiledValue expr, ExecutionContext context) throws AmbiguousNameException, TypeMismatchException { boolean toContinue = true; List<CompiledValue> retList = new ArrayList<CompiledValue>(); int exprType = expr.getType(); while (toContinue) { switch (exprType) { case OQLLexerTokenTypes.RegionPath: retList.add(expr); toContinue = false; break; case OQLLexerTokenTypes.METHOD_INV: retList.add(expr); CompiledOperation operation = (CompiledOperation) expr; expr = operation.getReceiver(null/* * pass the ExecutionContext as null, thus never * implicitly resolving to RuntimeIterator */); if (expr == null) { expr = operation; toContinue = false; } break; case CompiledValue.PATH: retList.add(expr); expr = ((CompiledPath) expr).getReceiver(); break; case OQLLexerTokenTypes.ITERATOR_DEF: retList.add(expr); toContinue = false; break; case OQLLexerTokenTypes.TOK_LBRACK: retList.add(expr); expr = ((CompiledIndexOperation) expr).getReceiver(); break; case OQLLexerTokenTypes.Identifier: CompiledID cid = (CompiledID) expr; expr = context.resolve(cid.getId()); break; default: toContinue = false; break; } if (toContinue) exprType = expr.getType(); } return retList; } }