/* * 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.ofbiz.base.util; import java.io.File; import java.util.Collection; import java.util.HashSet; import java.util.Set; import org.apache.ofbiz.base.component.ComponentConfig; /** * Java Source Parsing Utilities * * NOTE: the approach here is not the best and it may be better to use a parser, line one based on antlr, or using a Java Bytecode parser to look at .class files. * */ public final class UtilJavaParse { public static final String module = UtilJavaParse.class.getName(); // FIXME: Not thread safe private static Set<String> serviceMethodNames = new HashSet<String>(); private static Set<String> entityMethodNames = new HashSet<String>(); static { serviceMethodNames.add("runSync"); serviceMethodNames.add("runSyncIgnore"); serviceMethodNames.add("runAsync"); serviceMethodNames.add("runAsyncWait"); serviceMethodNames.add("registerCallback"); serviceMethodNames.add("schedule"); // NOTE: the service name may be the 1st, 2nd or 3rd param for variations on this serviceMethodNames.add("addRollbackService"); serviceMethodNames.add("addCommitService"); entityMethodNames.add("getModelEntity"); entityMethodNames.add("getEntityGroupName"); entityMethodNames.add("getModelEntityMapByGroup"); entityMethodNames.add("getGroupHelperName"); entityMethodNames.add("getEntityHelperName"); entityMethodNames.add("getEntityHelper"); entityMethodNames.add("makeValue"); entityMethodNames.add("makeValueSingle"); entityMethodNames.add("makeValidValue"); entityMethodNames.add("makePK"); entityMethodNames.add("makePKSingle"); entityMethodNames.add("create"); entityMethodNames.add("createSingle"); entityMethodNames.add("removeByAnd"); entityMethodNames.add("removeByCondition"); entityMethodNames.add("create"); entityMethodNames.add("createSingle"); entityMethodNames.add("removeByAnd"); entityMethodNames.add("removeByCondition"); entityMethodNames.add("storeByCondition"); entityMethodNames.add("removeAll"); entityMethodNames.add("findOne"); entityMethodNames.add("findByPrimaryKey"); entityMethodNames.add("findByPrimaryKeyCache"); entityMethodNames.add("findAllCache"); entityMethodNames.add("findByAnd"); entityMethodNames.add("findByOr"); entityMethodNames.add("findByAndCache"); entityMethodNames.add("findByLike"); entityMethodNames.add("findByCondition"); entityMethodNames.add("findByConditionCache"); entityMethodNames.add("findListIteratorByCondition"); entityMethodNames.add("find"); entityMethodNames.add("findList"); entityMethodNames.add("findCountByAnd"); entityMethodNames.add("findCountByCondition"); } private UtilJavaParse () {} public static String findRealPathAndFileForClass(String fullyQualifiedClassName) { // search through the component directories, in the src directory for each, using the class path as the path within it String sourceSubPath = fullyQualifiedClassName.substring(0, fullyQualifiedClassName.lastIndexOf(".")).replace('.', File.separatorChar); String classFileName = fullyQualifiedClassName.substring(fullyQualifiedClassName.lastIndexOf(".")+1) + ".java"; Collection<ComponentConfig> allComponentConfigs = ComponentConfig.getAllComponents(); for (ComponentConfig cc: allComponentConfigs) { String rootDirectory = cc.getRootLocation(); if (!rootDirectory.endsWith(File.separatorChar + "")) rootDirectory += File.separatorChar; rootDirectory += "src" + File.separatorChar; File rootDirFile = new File(rootDirectory); if (!rootDirFile.exists()) { // no src directory, move along continue; } String classDir = rootDirectory + sourceSubPath; File classDirFile = new File(classDir); if (!classDirFile.exists()) { // no src class sub-directory, move along continue; } String fullPathAndFile = classDir + File.separatorChar + classFileName; File classFile = new File(fullPathAndFile); if (classFile.exists()) { if (Debug.verboseOn()) Debug.logVerbose("In findRealPathAndFileForClass for [" + fullyQualifiedClassName + "]: [" + fullPathAndFile + "]", module); return fullPathAndFile; } } return null; } public static int findServiceMethodBlockStart(String methodName, String javaFile) { if (Debug.verboseOn()) Debug.logVerbose("In findServiceMethodBlockStart for " + methodName, module); // starts with something like this: public static Map exportServiceEoModelBundle(DispatchContext dctx, Map context) { // start with the main pattern int methodNameIndex = javaFile.indexOf("public static Map " + methodName + "(DispatchContext dctx, Map context) {"); // try a little less... and some nice messy variations... if (methodNameIndex < 0) methodNameIndex = javaFile.indexOf(" Map " + methodName + "(DispatchContext "); if (methodNameIndex < 0) methodNameIndex = javaFile.indexOf(" Map " + methodName + "(DispatchContext "); if (methodNameIndex < 0) methodNameIndex = javaFile.indexOf(" Map " + methodName + " (DispatchContext "); if (methodNameIndex < 0) methodNameIndex = javaFile.indexOf(" Map " + methodName + "(DispatchContext "); if (methodNameIndex < 0) methodNameIndex = javaFile.indexOf(" Map " + methodName + " (DispatchContext "); // not found! if (methodNameIndex < 0) return -1; // find the open brace and return its position return javaFile.indexOf("{", methodNameIndex); } public static int findEndOfBlock(int blockStart, String javaFile) { //Debug.logInfo("In findEndOfBlock for blockStart " + blockStart, module); int nextOpen = javaFile.indexOf("{", blockStart+1); int nextClose = javaFile.indexOf("}", blockStart+1); if (nextOpen > 0 && nextClose > 0 && nextClose > nextOpen) { javaFile.substring(nextOpen, nextClose); } // if no close, end with couldn't find if (nextClose < 0) return -1; // while nextOpen is found and is before the next close, then recurse (list while (nextOpen > -1 && nextOpen < nextClose) { int endOfSubBlock = findEndOfBlock(nextOpen, javaFile); if (endOfSubBlock < 0) return -1; nextOpen = javaFile.indexOf("{", endOfSubBlock+1); nextClose = javaFile.indexOf("}", endOfSubBlock+1); } // at this point there should be no nextOpen or nextOpen is after the nextClose, meaning we're at the end of the block return nextClose; } public static Set<String> findServiceCallsInBlock(int blockStart, int blockEnd, String javaFile) { Set<String> serviceNameSet = new HashSet<String>(); int dispatcherIndex = javaFile.indexOf("dispatcher.", blockStart+1); while (dispatcherIndex > 0 && dispatcherIndex < blockEnd) { // verify it is a call we're looking for int openParenIndex = javaFile.indexOf("(", dispatcherIndex); String curMethodName = javaFile.substring(dispatcherIndex + 11, openParenIndex).trim(); if (serviceMethodNames.contains(curMethodName)) { // find the service name int openQuoteIndex = javaFile.indexOf("\"", openParenIndex); int closeQuoteIndex = javaFile.indexOf("\"", openQuoteIndex+1); if (openQuoteIndex - openParenIndex <= 3 && openQuoteIndex >= 0 && closeQuoteIndex >= 0) { //more than two spaces/chars between quote and open paren... consider it something other than what we are looking for String serviceName = javaFile.substring(openQuoteIndex+1, closeQuoteIndex).trim(); serviceNameSet.add(serviceName); } } dispatcherIndex = javaFile.indexOf("dispatcher.", openParenIndex); } return serviceNameSet; } public static Set<String> findEntityUseInBlock(int blockStart, int blockEnd, String javaFile) { Set<String> entityNameSet = new HashSet<String>(); int delegatorIndex = javaFile.indexOf("delegator.", blockStart+1); while (delegatorIndex > 0 && delegatorIndex < blockEnd) { // verify it is a call we're looking for int openParenIndex = javaFile.indexOf("(", delegatorIndex); String curMethodName = javaFile.substring(delegatorIndex + 10, openParenIndex).trim(); if (entityMethodNames.contains(curMethodName)) { // find the entity name int openQuoteIndex = javaFile.indexOf("\"", openParenIndex); int closeQuoteIndex = javaFile.indexOf("\"", openQuoteIndex+1); if (openQuoteIndex - openParenIndex <= 3 && openQuoteIndex >= 0 && closeQuoteIndex >= 0) { //more than two spaces/chars between quote and open paren... consider it something other than what we are looking for String entityName = javaFile.substring(openQuoteIndex+1, closeQuoteIndex).trim(); entityNameSet.add(entityName); } } delegatorIndex = javaFile.indexOf("delegator.", openParenIndex); } return entityNameSet; } public static String stripComments(String javaFile) { StringBuilder strippedFile = new StringBuilder(); int commentOpen = javaFile.indexOf("/*"); int commentClose = javaFile.indexOf("*/"); if (commentOpen > -1) { if (commentOpen > 0) { strippedFile.append(javaFile.substring(0, commentOpen)); } commentOpen = javaFile.indexOf("/*", commentClose); while (commentOpen > -1) { strippedFile.append(javaFile.substring(commentClose + 2, commentOpen)); commentClose = javaFile.indexOf("*/", commentOpen); commentOpen = javaFile.indexOf("/*", commentClose); } strippedFile.append(javaFile.substring(commentClose + 2)); } else { strippedFile.append(javaFile); } String lineSeparator = System.getProperty("line.separator"); int lineComment = strippedFile.indexOf("//"); while (lineComment > -1) { int endOfLine = strippedFile.indexOf(lineSeparator, lineComment); strippedFile.delete(lineComment, endOfLine); lineComment = strippedFile.indexOf("//", lineComment); } return strippedFile.toString(); } }