/* * Copyright 2010 Red Hat, Inc. and/or its affiliates. * * Licensed 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.drools.eclipse; import java.util.ArrayList; import java.util.List; import org.drools.compiler.compiler.BaseKnowledgeBuilderResultImpl; import org.drools.compiler.compiler.Dialect; import org.drools.compiler.compiler.DialectCompiletimeRegistry; import org.drools.compiler.compiler.DroolsError; import org.drools.compiler.lang.descr.AttributeDescr; import org.drools.compiler.lang.descr.BaseDescr; import org.drools.compiler.lang.descr.ConditionalElementDescr; import org.drools.compiler.lang.descr.FunctionDescr; import org.drools.compiler.lang.descr.PackageDescr; import org.drools.compiler.lang.descr.PatternDescr; import org.drools.compiler.lang.descr.RuleDescr; import org.drools.core.base.ClassObjectType; import org.drools.core.definitions.InternalKnowledgePackage; import org.drools.core.definitions.rule.impl.RuleImpl; import org.drools.core.rule.DialectRuntimeRegistry; import org.drools.core.rule.GroupElement; import org.drools.core.rule.LineMappings; import org.drools.core.rule.Pattern; import org.drools.core.rule.RuleConditionElement; import org.drools.core.spi.ObjectType; import org.eclipse.core.resources.IResource; public class DRLInfo { private static final DroolsError[] EMPTY_DROOLS_ERROR_ARRAY = new DroolsError[0]; private final String sourcePathName; private final PackageDescr packageDescr; private List<BaseKnowledgeBuilderResultImpl> parserErrors; private InternalKnowledgePackage compiledPackage; private DroolsError[] builderErrors; // cached entry private transient RuleInfo[] ruleInfos; private transient FunctionInfo[] functionInfos; private DialectCompiletimeRegistry dialectRegistry; private IResource resource; public DRLInfo( String sourcePathName, PackageDescr packageDescr, List<BaseKnowledgeBuilderResultImpl> parserErrors, DialectCompiletimeRegistry dialectRegistry ) { if (sourcePathName == null) { throw new IllegalArgumentException("Invalid sourcePathName " + sourcePathName); } this.sourcePathName = sourcePathName; this.packageDescr = packageDescr; this.parserErrors = parserErrors; this.builderErrors = EMPTY_DROOLS_ERROR_ARRAY; this.dialectRegistry = dialectRegistry; } public DRLInfo( String pathName, PackageDescr packageDescr, List<BaseKnowledgeBuilderResultImpl> parserErrors, InternalKnowledgePackage compiledPackage, DroolsError[] builderErrors, DialectCompiletimeRegistry dialectRegistry ) { this(pathName, packageDescr, parserErrors, dialectRegistry); if (compiledPackage == null) { throw new IllegalArgumentException("Null package"); } this.compiledPackage = compiledPackage; this.builderErrors = builderErrors == null ? EMPTY_DROOLS_ERROR_ARRAY : builderErrors; } public String getSourcePathName() { return sourcePathName; } public PackageDescr getPackageDescr() { return packageDescr; } public List<BaseKnowledgeBuilderResultImpl> getParserErrors() { return parserErrors; } public void addError(DroolsError error) { parserErrors.add(error); } public InternalKnowledgePackage getPackage() { return compiledPackage; } public DroolsError[] getBuilderErrors() { return builderErrors; } public String getPackageName() { return packageDescr == null ? null : packageDescr.getName(); } public boolean isCompiled() { return compiledPackage != null; } public RuleInfo[] getRuleInfos() { if (ruleInfos == null) { List<RuleInfo> ruleInfosList = new ArrayList<RuleInfo>(); if (packageDescr != null) { for (RuleDescr ruleDescr: packageDescr.getRules()) { RuleInfo ruleInfo = new RuleInfo(packageDescr, compiledPackage, ruleDescr, dialectRegistry, sourcePathName); ruleInfosList.add(ruleInfo); } } ruleInfos = (RuleInfo[]) ruleInfosList.toArray(new RuleInfo[0]); } return ruleInfos; } public RuleInfo getRuleInfo(int drlLineNumber) { RuleInfo[] ruleInfos = getRuleInfos(); int ruleLine = -1; RuleInfo result = null; for (int i = 0; i < ruleInfos.length; i++) { int ruleDrlLineNumber = ruleInfos[i].getDrlLineNumber(); if (ruleDrlLineNumber > ruleLine && ruleDrlLineNumber <= drlLineNumber + 1) { ruleLine = ruleDrlLineNumber; result = ruleInfos[i]; } } return result; } public DialectCompiletimeRegistry getDialectRegistry() { return dialectRegistry; } public IResource getResource() { return resource; } public void setResource(IResource resource) { this.resource = resource; } public static class RuleInfo { private final PackageDescr packageDescr; private final InternalKnowledgePackage compiledPackage; private final RuleDescr ruleDescr; private final DialectCompiletimeRegistry dialectRegistry; private final String sourcePathName; // cached entries private transient String className; private transient int consequenceJavaLineNumber = -1; private transient List<PatternInfo> patternInfos = null; private transient int endPatternsCharacter = -1; public RuleInfo(PackageDescr packageDescr, InternalKnowledgePackage compiledPackage, RuleDescr ruleDescr, DialectCompiletimeRegistry dialectRegistry, String sourcePathName) { if (ruleDescr == null) { throw new IllegalArgumentException("Null ruleDescr"); } this.packageDescr = packageDescr; this.compiledPackage = compiledPackage; this.ruleDescr = ruleDescr; this.dialectRegistry = dialectRegistry; this.sourcePathName = sourcePathName; } public String getDialectName() { String dialectName = null; dialectName = ruleDescr.getAttributes().get("dialect").getValue(); if (dialectName == null && packageDescr != null) { for (AttributeDescr attribute: packageDescr.getAttributes()) { if ("dialect".equals(attribute.getName())) { dialectName = (String) attribute.getValue(); break; } } } return dialectName; } public Dialect getDialect() { String dialectName = getDialectName(); if (dialectName == null) { return null; } return dialectRegistry.getDialect(dialectName); } public String getSourcePathName() { return sourcePathName; } public String getClassName() { // ruleDescr is only filled in during compilation if (!isCompiled()) { throw new IllegalArgumentException("Package has not been compiled"); } if (className == null) { String packageName = getPackageName(); className = (packageName == null ? "" : packageName + ".") + ruleDescr.getClassName(); } return className; } public int getConsequenceStart() { return endPatternsCharacter + 5; } public int getConsequenceEnd() { return getRuleEnd(); } public int getRuleStart() { return ruleDescr.getStartCharacter() + 5; } public int getRuleEnd() { return ruleDescr.getEndCharacter() - 4; } public int getDrlLineNumber() { return ruleDescr.getLine(); } public int getConsequenceDrlLineNumber() { return ruleDescr.getConsequenceLine(); } public int getConsequenceJavaLineNumber() { if (consequenceJavaLineNumber == -1) { if (!isCompiled()) { throw new IllegalArgumentException("Package has not been compiled"); } DialectRuntimeRegistry datas = compiledPackage.getDialectRuntimeRegistry(); LineMappings mappings = datas.getLineMappings(className); consequenceJavaLineNumber = mappings.getOffset(); } return consequenceJavaLineNumber; } public boolean isCompiled() { return compiledPackage != null; } public String getPackageName() { return packageDescr == null ? null : packageDescr.getName(); } public String getRuleName() { return ruleDescr.getName(); } public RuleImpl getRule() { return compiledPackage.getRule(getRuleName()); } public String toString() { return ruleDescr.toString(); } public List<PatternInfo> getPatternInfos() { if (patternInfos == null && isCompiled()) { patternInfos = findPatternInfos(); } return patternInfos; } private List<PatternInfo> findPatternInfos() { List<PatternInfo> patternInfos = new ArrayList<PatternInfo>(); traversePatternTree(patternInfos, getRule().getLhs().getChildren(), ruleDescr.getLhs().getDescrs()); return patternInfos; } @SuppressWarnings("unchecked") private void traversePatternTree(List<PatternInfo> patternInfos, List<RuleConditionElement> ruleElements, List<BaseDescr> lhsDescrs) { if (ruleElements.size() != lhsDescrs.size()) { throw new RuntimeException("Cannot traverse pattern tree"); } for (int i = 0; i < ruleElements.size(); i++) { RuleConditionElement ruleElement = ruleElements.get(i); BaseDescr lhsDescr = lhsDescrs.get(i); if (ruleElement instanceof Pattern && lhsDescr instanceof PatternDescr) { patternInfos.add(new PatternInfo((PatternDescr)lhsDescr, (Pattern)ruleElement)); endPatternsCharacter = Math.max(endPatternsCharacter, ((PatternDescr)lhsDescr).getEndCharacter()); } else if (ruleElement instanceof GroupElement && lhsDescr instanceof ConditionalElementDescr) { traversePatternTree(patternInfos, ((GroupElement)ruleElement).getChildren(), (List<BaseDescr>)((ConditionalElementDescr)lhsDescr).getDescrs()); } else { throw new RuntimeException("Cannot traverse pattern tree"); } } } } public static class PatternInfo { private final PatternDescr patternDescr; private final Pattern pattern; private PatternInfo(PatternDescr patternDescr, Pattern pattern) { this.patternDescr = patternDescr; this.pattern = pattern; } public String getPatternTypeName() { ObjectType objectType = pattern.getObjectType(); return objectType instanceof ClassObjectType ? ((ClassObjectType)objectType).getClassType().getName() : ""; } public int getStart() { return patternDescr.getStartCharacter(); } public int getEnd() { return patternDescr.getEndCharacter(); } public String toString() { return patternDescr.toString(); } } public FunctionInfo[] getFunctionInfos() { if (functionInfos == null) { List<FunctionInfo> functionInfosList = new ArrayList<FunctionInfo>(); if (packageDescr != null) { for (FunctionDescr functionDescr: packageDescr.getFunctions()) { FunctionInfo functionInfo = new FunctionInfo(packageDescr, compiledPackage, functionDescr, sourcePathName); functionInfosList.add(functionInfo); } } functionInfos = (FunctionInfo[]) functionInfosList.toArray(new FunctionInfo[0]); } return functionInfos; } public FunctionInfo getFunctionInfo(int drlLineNumber) { FunctionInfo[] functionInfos = getFunctionInfos(); int functionLine = -1; FunctionInfo result = null; for (int i = 0; i < functionInfos.length; i++) { int functionDrlLineNumber = functionInfos[i].getDrlLineNumber(); if (functionDrlLineNumber > functionLine && functionDrlLineNumber <= drlLineNumber + 1) { functionLine = functionDrlLineNumber; result = functionInfos[i]; } } return result; } public static class FunctionInfo { private final PackageDescr packageDescr; private final InternalKnowledgePackage compiledPackage; private final FunctionDescr functionDescr; private final String sourcePathName; // cached entries private transient String className; private transient int javaLineNumber = -1; public FunctionInfo(PackageDescr packageDescr, InternalKnowledgePackage compiledPackage, FunctionDescr functionDescr, String sourcePathName) { if (functionDescr == null) { throw new IllegalArgumentException("Null functionDescr"); } this.packageDescr = packageDescr; this.compiledPackage = compiledPackage; this.functionDescr = functionDescr; this.sourcePathName = sourcePathName; } public String getSourcePathName() { return sourcePathName; } public String getClassName() { // functionDescr is only filled in during compilation if (!isCompiled()) { throw new IllegalArgumentException("Package has not been compiled"); } if (className == null) { className = functionDescr.getClassName(); } return className; } public int getDrlLineNumber() { return functionDescr.getLine(); } public int getJavaLineNumber() { if (javaLineNumber == -1) { if (!isCompiled()) { throw new IllegalArgumentException("Package has not been compiled"); } javaLineNumber = compiledPackage.getDialectRuntimeRegistry().getLineMappings(className).getOffset(); } return javaLineNumber; } public String getPackageName() { return packageDescr == null ? null : packageDescr.getName(); } public String getFunctionName() { return functionDescr.getName(); } public int getFunctionStart() { return functionDescr.getStartCharacter() + 8; } public int getFunctionEnd() { return functionDescr.getEndCharacter() - 1; } public boolean isCompiled() { return compiledPackage != null; } } }