001: package org.drools.eclipse.dsl.editor;
002:
003: import java.io.IOException;
004: import java.io.InputStream;
005: import java.io.InputStreamReader;
006: import java.io.Reader;
007: import java.util.ArrayList;
008: import java.util.Iterator;
009: import java.util.List;
010: import java.util.regex.Matcher;
011: import java.util.regex.Pattern;
012:
013: import org.drools.eclipse.DroolsEclipsePlugin;
014: import org.drools.eclipse.builder.Util;
015: import org.drools.eclipse.editors.completion.DSLTree;
016: import org.drools.lang.dsl.DSLMapping;
017: import org.drools.lang.dsl.DSLMappingEntry;
018: import org.drools.lang.dsl.DSLMappingFile;
019: import org.eclipse.core.resources.IFile;
020: import org.eclipse.core.resources.IResource;
021: import org.eclipse.core.resources.IResourceVisitor;
022: import org.eclipse.core.runtime.CoreException;
023:
024: /**
025: * This holds the DSL configuration for an editor instance.
026: * When loading, it will find the DSL file, and load the applicable lists.
027: *
028: * This provides a link between the editor and the DSL features of the rule language.
029: *
030: * It will look for a DSL configuration, as named in the rule file, in the same directory as the rule file.
031: * Failing this, it will search one directory above the rule file.
032: * Failing that, it will search the root of the project in the workspace.
033: *
034: * @author Michael Neale
035: * @author <a href="mailto:kris_verlaenen@hotmail.com">Kris Verlaenen</a>
036: */
037: public class DSLAdapter {
038:
039: private String dslConfigName;
040: private boolean valid = false;
041: private List conditionProposals = new ArrayList();
042: private List consequenceProposals = new ArrayList();
043: private DSLTree dslTree = new DSLTree();
044:
045: //to dig out the expander, without using the parser.
046: private static final Pattern EXPANDER_PATTERN = Pattern.compile(
047: "\\n\\s*expander\\s*(.*)\\.dsl\\s", Pattern.DOTALL
048: | Pattern.MULTILINE);
049:
050: /**
051: * This will sniff out the DSL config file name from the content.
052: * It will then use the IFile input to search around for the file itself.
053: * TODO: provide an alternative that just loads off a stream (for non IDEs workbenches like jlibrary).
054: * @param content Rule source
055: * @param input File from the FileEditorInput
056: */
057: public DSLAdapter(String content, IFile input) throws CoreException {
058: dslConfigName = findDSLConfigName(content, input);
059: if (dslConfigName == null) {
060: return;
061: }
062: loadConfig(input);
063: }
064:
065: /** Get a reader to the DSL contents */
066: public static Reader getDSLContent(String ruleSource,
067: IResource input) throws CoreException {
068: String dslFileName = findDSLConfigName(ruleSource, input);
069: if (dslFileName == null) {
070: return null;
071: }
072: IResource res = findDSLResource(input, dslFileName);
073: if (res instanceof IFile) {
074: IFile dslConf = (IFile) res;
075: if (dslConf.exists()) {
076: return new InputStreamReader(dslConf.getContents());
077: }
078: }
079: return null;
080: }
081:
082: /**
083: * This does the hunting around the projec to find the .dsl file.
084: */
085: private void loadConfig(IFile input) {
086: IResource res = findDSLResource(input, dslConfigName);
087: if (res instanceof IFile) {
088: IFile dslConf = (IFile) res;
089: if (dslConf.exists()) {
090: InputStream stream = null;
091: try {
092: stream = dslConf.getContents();
093: readConfig(stream);
094: valid = true;
095: } catch (Exception e) {
096: throw new IllegalStateException(
097: "Unable to open DSL config file. (Exception: "
098: + e.getMessage() + ")");
099: } finally {
100: closeStream(stream);
101: }
102:
103: }
104: }
105: }
106:
107: private static IResource findDSLResource(IResource input,
108: String dslFileName) {
109: IResource res = input.getParent().findMember(dslFileName);
110: if (res == null)
111: res = input.getParent().getParent().findMember(dslFileName); //try parent directory
112: if (res == null)
113: res = input.getProject().findMember(dslFileName); //try root of project.
114: return res;
115: }
116:
117: /** This will load in the DSL config file, using the DSLMapping from drools-compiler */
118: void readConfig(InputStream stream) throws IOException,
119: CoreException {
120: DSLMappingFile file = new DSLMappingFile();
121: file.parseAndLoad(new InputStreamReader(stream));
122:
123: DSLMapping grammar = file.getMapping();
124: List conditions = grammar.getEntries(DSLMappingEntry.CONDITION);
125: List consequences = grammar
126: .getEntries(DSLMappingEntry.CONSEQUENCE);
127:
128: conditionProposals = buildProposals(conditions);
129: consequenceProposals = buildProposals(consequences);
130:
131: dslTree.buildTree(grammar);
132: }
133:
134: private List buildProposals(List suggestions) {
135: List result = new ArrayList(suggestions.size());
136: Iterator iterator = suggestions.iterator();
137: while (iterator.hasNext()) {
138: DSLMappingEntry text = (DSLMappingEntry) iterator.next();
139: result.add(text.getMappingKey());
140: }
141: return result;
142: }
143:
144: private void closeStream(InputStream stream) {
145: if (stream != null)
146: try {
147: stream.close();
148: } catch (IOException e) {
149: }
150: }
151:
152: DSLAdapter() {
153:
154: }
155:
156: private static String findDSLConfigName(String content,
157: IResource input) throws CoreException {
158: String dslConfigName = findDSLConfigName(content);
159: if (dslConfigName == null) {
160: // try searching the .package file
161: if (input != null && input.getParent() != null) {
162: MyResourceVisitor visitor = new MyResourceVisitor();
163: input.getParent().accept(visitor, IResource.DEPTH_ONE,
164: IResource.NONE);
165: IResource packageDef = visitor.getPackageDef();
166: if (packageDef != null) {
167: if (packageDef instanceof IFile) {
168: IFile file = (IFile) packageDef;
169: try {
170: String pContent = new String(
171: Util
172: .getResourceContentsAsCharArray(file));
173: dslConfigName = findDSLConfigName(pContent);
174: } catch (CoreException e) {
175: DroolsEclipsePlugin.log(e);
176: }
177: }
178: }
179: }
180: }
181: return dslConfigName;
182: }
183:
184: /** Sniffs out the expander/DSL config name as best it can. */
185: static String findDSLConfigName(String content) {
186: String name = null;
187: Matcher matches = EXPANDER_PATTERN.matcher(content);
188: if (matches.find()) {
189: name = matches.group(1) + ".dsl";
190: }
191: return name;
192: }
193:
194: String getDSLConfigName() {
195: return dslConfigName;
196: }
197:
198: public boolean isValid() {
199: return valid;
200: }
201:
202: public boolean hasConditions() {
203: return conditionProposals.size() > 0;
204: }
205:
206: public boolean hasConsequences() {
207: return consequenceProposals.size() > 0;
208: }
209:
210: public List listConditionItems() {
211: return conditionProposals;
212: }
213:
214: public List listConsequenceItems() {
215: return consequenceProposals;
216: }
217:
218: public DSLTree getDSLTree() {
219: return dslTree;
220: }
221:
222: private static class MyResourceVisitor implements IResourceVisitor {
223: private IResource packageDef;
224:
225: public boolean visit(IResource resource) throws CoreException {
226: if ("package".equals(resource.getFileExtension())) {
227: packageDef = resource;
228: }
229: return true;
230: }
231:
232: public IResource getPackageDef() {
233: return packageDef;
234: }
235: }
236: }
|