001: /*
002: * Copyright 2006 JBoss Inc
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.drools.rule.builder.dialect.java;
018:
019: import java.util.ArrayList;
020: import java.util.Comparator;
021: import java.util.Iterator;
022: import java.util.List;
023: import java.util.Map;
024: import java.util.TreeSet;
025:
026: import org.drools.base.accumulators.AccumulateFunction;
027: import org.drools.base.accumulators.JavaAccumulatorFunctionExecutor;
028: import org.drools.compiler.Dialect;
029: import org.drools.lang.descr.AccumulateDescr;
030: import org.drools.lang.descr.BaseDescr;
031: import org.drools.lang.descr.PatternDescr;
032: import org.drools.rule.Accumulate;
033: import org.drools.rule.Declaration;
034: import org.drools.rule.Pattern;
035: import org.drools.rule.RuleConditionElement;
036: import org.drools.rule.builder.AccumulateBuilder;
037: import org.drools.rule.builder.PatternBuilder;
038: import org.drools.rule.builder.RuleBuildContext;
039: import org.drools.rule.builder.dialect.java.parser.JavaLocalDeclarationDescr;
040:
041: /**
042: * A builder for the java dialect accumulate version
043: *
044: * @author etirelli
045: */
046: public class JavaAccumulateBuilder extends AbstractJavaBuilder
047: implements AccumulateBuilder {
048:
049: public RuleConditionElement build(final RuleBuildContext context,
050: final BaseDescr descr) {
051: return build(context, descr, null);
052: }
053:
054: public RuleConditionElement build(final RuleBuildContext context,
055: final BaseDescr descr, final Pattern prefixPattern) {
056:
057: final AccumulateDescr accumDescr = (AccumulateDescr) descr;
058:
059: final PatternBuilder patternBuilder = (PatternBuilder) context
060: .getDialect().getBuilder(PatternDescr.class);
061:
062: final Pattern sourcePattern = (Pattern) patternBuilder.build(
063: context, accumDescr.getInputPattern());
064:
065: if (sourcePattern == null) {
066: return null;
067: }
068:
069: Accumulate accumulate = null;
070:
071: if (accumDescr.isExternalFunction()) {
072: // if it is an external function, build a method for it
073:
074: final JavaAnalysisResult analysis = (JavaAnalysisResult) context
075: .getDialect().analyzeBlock(context, accumDescr,
076: accumDescr.getExpression());
077:
078: final List[] usedIdentifiers = analysis
079: .getBoundIdentifiers();
080:
081: final List tupleDeclarations = new ArrayList();
082: for (int i = 0, size = usedIdentifiers[0].size(); i < size; i++) {
083: tupleDeclarations.add(context.getDeclarationResolver()
084: .getDeclaration(
085: (String) usedIdentifiers[0].get(i)));
086: }
087:
088: final Declaration[] previousDeclarations = (Declaration[]) tupleDeclarations
089: .toArray(new Declaration[tupleDeclarations.size()]);
090: final String[] requiredGlobals = (String[]) usedIdentifiers[1]
091: .toArray(new String[usedIdentifiers[1].size()]);
092: final Declaration[] sourceDeclArr = (Declaration[]) sourcePattern
093: .getOuterDeclarations().values().toArray(
094: new Declaration[0]);
095:
096: final String className = "accumulateExpression"
097: + context.getNextId();
098:
099: final Map map = createVariableContext(className,
100: (String) accumDescr.getExpression(), context,
101: previousDeclarations, sourceDeclArr,
102: requiredGlobals);
103:
104: AccumulateFunction function = context.getConfiguration()
105: .getAccumulateFunction(
106: accumDescr.getFunctionIdentifier());
107:
108: JavaAccumulatorFunctionExecutor accumulator = new JavaAccumulatorFunctionExecutor(
109: function);
110:
111: accumulate = new Accumulate(sourcePattern,
112: previousDeclarations, sourceDeclArr, accumulator);
113:
114: generatTemplates("returnValueMethod", "returnValueInvoker",
115: context, className, map, accumulator, accumDescr);
116: } else {
117: // ELSE, if it is not an external function, build it using the regular java builder
118: final String className = "Accumulate" + context.getNextId();
119: accumDescr.setClassName(className);
120:
121: final JavaAnalysisResult initCodeAnalysis = (JavaAnalysisResult) context
122: .getDialect().analyzeBlock(context, accumDescr,
123: accumDescr.getInitCode());
124: final Dialect.AnalysisResult actionCodeAnalysis = context
125: .getDialect().analyzeBlock(context, accumDescr,
126: accumDescr.getActionCode());
127: final Dialect.AnalysisResult resultCodeAnalysis = context
128: .getDialect().analyzeExpression(context,
129: accumDescr, accumDescr.getResultCode());
130:
131: final List requiredDeclarations = new ArrayList(
132: initCodeAnalysis.getBoundIdentifiers()[0]);
133: requiredDeclarations.addAll(actionCodeAnalysis
134: .getBoundIdentifiers()[0]);
135: requiredDeclarations.addAll(resultCodeAnalysis
136: .getBoundIdentifiers()[0]);
137:
138: final List requiredGlobals = new ArrayList(initCodeAnalysis
139: .getBoundIdentifiers()[1]);
140: requiredGlobals.addAll(actionCodeAnalysis
141: .getBoundIdentifiers()[1]);
142: requiredGlobals.addAll(resultCodeAnalysis
143: .getBoundIdentifiers()[1]);
144:
145: if (accumDescr.getReverseCode() != null) {
146: final Dialect.AnalysisResult reverseCodeAnalysis = context
147: .getDialect().analyzeBlock(context, accumDescr,
148: accumDescr.getActionCode());
149: requiredDeclarations.addAll(reverseCodeAnalysis
150: .getBoundIdentifiers()[0]);
151: requiredGlobals.addAll(reverseCodeAnalysis
152: .getBoundIdentifiers()[1]);
153: }
154:
155: final Declaration[] declarations = new Declaration[requiredDeclarations
156: .size()];
157: for (int i = 0, size = requiredDeclarations.size(); i < size; i++) {
158: declarations[i] = context.getDeclarationResolver()
159: .getDeclaration(
160: (String) requiredDeclarations.get(i));
161: }
162: final Declaration[] sourceDeclArr = (Declaration[]) sourcePattern
163: .getOuterDeclarations().values().toArray(
164: new Declaration[0]);
165:
166: final String[] globals = (String[]) requiredGlobals
167: .toArray(new String[requiredGlobals.size()]);
168:
169: final Map map = createVariableContext(className, null,
170: context, declarations, null, globals);
171:
172: map.put("className", accumDescr.getClassName());
173: map.put("innerDeclarations", sourceDeclArr);
174:
175: final String initCode = this .fixInitCode(initCodeAnalysis,
176: accumDescr.getInitCode());
177: final String actionCode = accumDescr.getActionCode();
178: final String resultCode = accumDescr.getResultCode();
179:
180: String[] attributesTypes = new String[initCodeAnalysis
181: .getLocalVariablesMap().size()];
182: String[] attributes = new String[initCodeAnalysis
183: .getLocalVariablesMap().size()];
184: int index = 0;
185: for (Iterator it = initCodeAnalysis.getLocalVariablesMap()
186: .entrySet().iterator(); it.hasNext();) {
187: Map.Entry entry = (Map.Entry) it.next();
188: attributes[index] = (String) entry.getKey();
189: attributesTypes[index] = ((JavaLocalDeclarationDescr) entry
190: .getValue()).getType();
191: }
192:
193: map.put("attributes", attributes);
194: map.put("attributesTypes", attributesTypes);
195:
196: map.put("initCode", initCode);
197: map.put("actionCode", actionCode);
198: map.put("resultCode", resultCode);
199: if (accumDescr.getReverseCode() == null) {
200: map.put("reverseCode", "");
201: map.put("supportsReverse", "false");
202: } else {
203: map.put("reverseCode", accumDescr.getReverseCode());
204: map.put("supportsReverse", "true");
205: }
206:
207: map.put("hashCode", new Integer(actionCode.hashCode()));
208:
209: accumulate = new Accumulate(sourcePattern, declarations,
210: sourceDeclArr);
211:
212: generatTemplates("accumulateInnerClass",
213: "accumulateInvoker", context, className, map,
214: accumulate, accumDescr);
215: }
216:
217: return accumulate;
218: }
219:
220: protected String fixInitCode(JavaAnalysisResult analysis,
221: final String originalCode) {
222: TreeSet locals = new TreeSet(new Comparator() {
223: public int compare(Object o1, Object o2) {
224: JavaLocalDeclarationDescr d1 = (JavaLocalDeclarationDescr) o1;
225: JavaLocalDeclarationDescr d2 = (JavaLocalDeclarationDescr) o2;
226: return d1.getStart() - d2.getStart();
227: }
228: });
229:
230: for (Iterator it = analysis.getLocalVariablesMap().values()
231: .iterator(); it.hasNext();) {
232: locals.add(it.next());
233: }
234:
235: StringBuffer initCode = new StringBuffer();
236: int lastAdded = 0;
237: for (Iterator it = locals.iterator(); it.hasNext();) {
238: JavaLocalDeclarationDescr d = (JavaLocalDeclarationDescr) it
239: .next();
240: // adding chunk
241: initCode.append(originalCode.substring(lastAdded, d
242: .getStart()));
243: lastAdded = d.getEnd();
244: // adding variable initializations
245: for (Iterator vars = d.getIdentifiers().iterator(); vars
246: .hasNext();) {
247: JavaLocalDeclarationDescr.IdentifierDescr id = (JavaLocalDeclarationDescr.IdentifierDescr) vars
248: .next();
249: initCode.append(originalCode.substring(id.getStart(),
250: id.getEnd()));
251: initCode.append(";");
252: lastAdded = id.getEnd();
253: while (lastAdded < originalCode.length()
254: && (Character.isWhitespace(originalCode
255: .charAt(lastAdded)) || originalCode
256: .charAt(lastAdded) == ';')) {
257: lastAdded++;
258: }
259: }
260: }
261: initCode.append(originalCode.substring(lastAdded));
262:
263: // TODO Auto-generated method stub
264: return initCode.toString();
265: }
266: }
|