/* * 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.editors.outline; import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.drools.compiler.compiler.DroolsParserException; import org.drools.eclipse.DRLInfo; import org.drools.eclipse.DroolsEclipsePlugin; import org.drools.eclipse.core.DroolsElement; import org.drools.eclipse.core.DroolsModelBuilder; import org.drools.eclipse.core.Package; import org.drools.eclipse.core.RuleSet; import org.drools.eclipse.core.ui.DroolsContentProvider; import org.drools.eclipse.core.ui.DroolsGroupByRuleGroupContentProvider; import org.drools.eclipse.core.ui.DroolsLabelProvider; import org.drools.eclipse.core.ui.DroolsTreeSorter; import org.drools.eclipse.core.ui.FilterActionGroup; import org.drools.eclipse.editors.AbstractRuleEditor; import org.drools.compiler.lang.descr.AttributeDescr; import org.drools.compiler.lang.descr.PackageDescr; import org.drools.compiler.lang.descr.RuleDescr; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.IStatusLineManager; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.ui.views.contentoutline.ContentOutlinePage; /** * Simple outline view of a DRL file. At present this is not wired in with the Parser, so it is fault * tolerant of incorrect syntax. * Should provide navigation assistance in large rule files. */ public class RuleContentOutlinePage extends ContentOutlinePage { private AbstractRuleEditor editor; private RuleSet ruleSet = DroolsModelBuilder.createRuleSet(); private Map<String, RuleDescr> rules; private boolean groupByRulegroup = false; private TreeViewer viewer = null; /////////////////////////////////// // Patterns that the parser uses // TODO: this should just reuse the existing parser to avoid inconsistencies // with for example comments /////////////////////////////////// private static final Pattern RULE_PATTERN1 = Pattern.compile( "\\n\\s*rule\\s+\"([^\"]+)\"", Pattern.DOTALL); private static final Pattern RULE_PATTERN2 = Pattern.compile( "\\n\\s*rule\\s+([^\\s;#\"]+)", Pattern.DOTALL); private static final Pattern PACKAGE_PATTERN = Pattern.compile( "\\s*package\\s+([^\\s;#]+);?", Pattern.DOTALL); private static final Pattern FUNCTION_PATTERN = Pattern.compile( "\\n\\s*function\\s+(\\S+)\\s+(\\S+)\\(.*?\\)", Pattern.DOTALL); private static final Pattern TEMPLATE_PATTERN = Pattern.compile( "\\n\\s*template\\s+([^\\s;#\"]+)", Pattern.DOTALL); private static final Pattern IMPORT_PATTERN = Pattern.compile( "\\n\\s*import\\s+([^\\s;#]+);?", Pattern.DOTALL); private static final Pattern EXPANDER_PATTERN = Pattern.compile( "\\n\\s*expander\\s+([^\\s;#]+);?", Pattern.DOTALL); private static final Pattern GLOBAL_PATTERN = Pattern.compile( "\\n\\s*global\\s+(\\S+)\\s+([^\\s;#]+);?", Pattern.DOTALL); private static final Pattern QUERY_PATTERN1 = Pattern.compile( "\\n\\s*query\\s+\"([^\"]+)\"", Pattern.DOTALL); private static final Pattern QUERY_PATTERN2 = Pattern.compile( "\\n\\s*query\\s+([^\\s;#\"]+)", Pattern.DOTALL); public RuleContentOutlinePage(AbstractRuleEditor editor) { this.editor = editor; } DroolsContentProvider contentProvider = null; DroolsGroupByRuleGroupContentProvider groupByRuleGroupContentProvider = null; private void setContentProvider() { IPreferenceStore preferenceStore= DroolsEclipsePlugin.getDefault().getPreferenceStore(); groupByRulegroup = preferenceStore.getBoolean("GroupByRuleGroupAction.isChecked"); contentProvider = new DroolsContentProvider(); groupByRuleGroupContentProvider = new DroolsGroupByRuleGroupContentProvider(); if (groupByRulegroup) { viewer.setContentProvider(groupByRuleGroupContentProvider); } else { viewer.setContentProvider(contentProvider); } } public void createControl(Composite parent) { super.createControl(parent); viewer = getTreeViewer(); setContentProvider(); viewer.setLabelProvider(new DroolsLabelProvider()); viewer.setSorter(new DroolsTreeSorter()); viewer.setInput(ruleSet); FilterActionGroup filterActionGroup = new FilterActionGroup( viewer, "org.drools.eclipse.editors.outline.RuleContentOutlinePage"); filterActionGroup.fillActionBars(getSite().getActionBars()); update(); // add the listener for navigation of the rule document. super.addSelectionChangedListener(new ISelectionChangedListener() { public void selectionChanged(SelectionChangedEvent event) { Object selectionObj = event.getSelection(); if (selectionObj != null && selectionObj instanceof StructuredSelection) { StructuredSelection sel = (StructuredSelection) selectionObj; DroolsElement element = (DroolsElement) sel.getFirstElement(); if (element != null) { editor.selectAndReveal(element.getOffset(), element.getLength()); } } } }); } /** * Updates the outline page. */ public void update() { TreeViewer viewer = getTreeViewer(); if (viewer != null) { Control control = viewer.getControl(); if (control != null && !control.isDisposed()) { initRules(); populatePackageTreeNode(); viewer.refresh(); control.setRedraw(false); viewer.expandToLevel(2); control.setRedraw(true); } } } /** * populates the PackageTreeNode with all of its child elements * * @param packageTreeNode the node to populate */ public void populatePackageTreeNode() { String ruleFileContents = editor.getContent(); populatePackageTreeNode(ruleFileContents); } void populatePackageTreeNode(String ruleFileContents) { DroolsModelBuilder.clearRuleSet(ruleSet); Matcher matcher = PACKAGE_PATTERN.matcher(ruleFileContents); String packageName = null; int startChar = 0; int endChar = 0; if (matcher.find()) { packageName = matcher.group(1); startChar = matcher.start(1); endChar = matcher.end(1); } Package pkg = DroolsModelBuilder.addPackage(ruleSet, packageName, startChar, endChar - startChar); matcher = RULE_PATTERN1.matcher(ruleFileContents); while (matcher.find()) { String ruleName = matcher.group(1); RuleDescr descr = (RuleDescr) rules.get(ruleName); if (descr != null) { DroolsModelBuilder.addRule(pkg, ruleName, null, matcher.start(1), matcher.end(1) - matcher.start(1), extractAttributes(descr)); } } matcher = RULE_PATTERN2.matcher(ruleFileContents); while (matcher.find()) { String ruleName = matcher.group(1); RuleDescr descr = (RuleDescr) rules.get(ruleName); if (descr != null) { DroolsModelBuilder.addRule(pkg, ruleName, null, matcher.start(1), matcher.end(1) - matcher.start(1), extractAttributes(descr)); } } matcher = FUNCTION_PATTERN.matcher(ruleFileContents); while (matcher.find()) { String functionName = matcher.group(2); DroolsModelBuilder.addFunction(pkg, functionName + "()", null, matcher.start(2), matcher.end(2) - matcher.start(2)); } matcher = EXPANDER_PATTERN.matcher(ruleFileContents); if (matcher.find()) { String expanderName = matcher.group(1); DroolsModelBuilder.addExpander(pkg, expanderName, null, matcher.start(1), matcher.end(1) - matcher.start(1)); } matcher = IMPORT_PATTERN.matcher(ruleFileContents); while (matcher.find()) { String importName = matcher.group(1); DroolsModelBuilder.addImport(pkg, importName, null, matcher.start(1), matcher.end(1) - matcher.start(1)); } matcher = GLOBAL_PATTERN.matcher(ruleFileContents); while (matcher.find()) { String globalType = matcher.group(1); String globalName = matcher.group(2); String name = globalName + " : " + globalType; DroolsModelBuilder.addGlobal(pkg, name, null, matcher.start(2), matcher.end(2) - matcher.start(2)); } matcher = QUERY_PATTERN1.matcher(ruleFileContents); while (matcher.find()) { String queryName = matcher.group(1); DroolsModelBuilder.addQuery(pkg, queryName, null, matcher.start(1), matcher.end(1) - matcher.start(1)); } matcher = QUERY_PATTERN2.matcher(ruleFileContents); while (matcher.find()) { String queryName = matcher.group(1); DroolsModelBuilder.addQuery(pkg, queryName, null, matcher.start(1), matcher.end(1) - matcher.start(1)); } matcher = TEMPLATE_PATTERN.matcher(ruleFileContents); while (matcher.find()) { String templateName = matcher.group(1); DroolsModelBuilder.addTemplate(pkg, templateName, null, matcher.start(1), matcher.end(1) - matcher.start(1)); } } RuleSet getRuleSet() { return ruleSet; } private Map<String, String> extractAttributes(RuleDescr ruleDescr) { Map<String, String> attributes = null; if (ruleDescr != null) { attributes = new HashMap<String, String>(); for (AttributeDescr attribute: ruleDescr.getAttributes().values()) { if (attribute != null && attribute.getName() != null) { attributes.put(attribute.getName(), attribute.getValue()); } } } return attributes; } public void initRules() { rules = new HashMap<String, RuleDescr>(); try { DRLInfo drlInfo = DroolsEclipsePlugin.getDefault().parseResource(editor, true, false); if (drlInfo != null) { PackageDescr packageDescr = drlInfo.getPackageDescr(); if (packageDescr != null) { for (RuleDescr ruleDescr: packageDescr.getRules()) { if (ruleDescr != null && ruleDescr.getName() != null) { rules.put(ruleDescr.getName(), ruleDescr); } } } } } catch (DroolsParserException e) { DroolsEclipsePlugin.log(e); } } class GroupByRuleGroupAction extends Action { public GroupByRuleGroupAction() { super(); setText("Group by Rule Group"); setToolTipText("Group by Rule Group"); setDescription("Group by agenda-group, activation-group or ruleflow-group"); setChecked(groupByRulegroup); } @Override public void run() { setGroupByRuleGroup(!groupByRulegroup); } private void setGroupByRuleGroup(boolean groupBy) { groupByRulegroup = groupBy; setChecked(groupBy); IPreferenceStore preferenceStore= DroolsEclipsePlugin.getDefault().getPreferenceStore(); preferenceStore.setValue("GroupByRuleGroupAction.isChecked", groupBy); setContentProvider(); viewer.refresh(true); } } @Override public void makeContributions(IMenuManager menuManager, IToolBarManager toolBarManager, IStatusLineManager statusLineManager) { // TODO Auto-generated method stub GroupByRuleGroupAction groupByAction = new GroupByRuleGroupAction (); menuManager.add(groupByAction); super.makeContributions(menuManager, toolBarManager, statusLineManager); } }