001: package org.drools.eclipse.rulebuilder.editors;
002:
003: import java.io.ByteArrayInputStream;
004: import java.io.IOException;
005: import java.io.InputStream;
006: import java.io.PrintWriter;
007: import java.io.Reader;
008: import java.io.StringReader;
009: import java.io.StringWriter;
010: import java.util.ArrayList;
011: import java.util.List;
012:
013: import org.drools.brms.client.modeldriven.SuggestionCompletionEngine;
014: import org.drools.brms.server.rules.SuggestionCompletionLoader;
015: import org.drools.brms.server.util.BRDRLPersistence;
016: import org.drools.brms.server.util.BRXMLPersistence;
017: import org.drools.compiler.DrlParser;
018: import org.drools.eclipse.DroolsEclipsePlugin;
019: import org.drools.eclipse.dsl.editor.DSLAdapter;
020: import org.drools.eclipse.editors.DRLDocumentProvider;
021: import org.drools.eclipse.editors.DRLRuleEditor;
022: import org.drools.eclipse.util.ProjectClassLoader;
023: import org.drools.lang.dsl.DSLMappingFile;
024: import org.eclipse.core.internal.resources.Container;
025: import org.eclipse.core.resources.IFile;
026: import org.eclipse.core.resources.IResource;
027: import org.eclipse.core.resources.IResourceChangeEvent;
028: import org.eclipse.core.resources.IResourceChangeListener;
029: import org.eclipse.core.resources.IResourceDelta;
030: import org.eclipse.core.resources.ResourcesPlugin;
031: import org.eclipse.core.runtime.CoreException;
032: import org.eclipse.core.runtime.IPath;
033: import org.eclipse.core.runtime.IProgressMonitor;
034: import org.eclipse.jdt.core.IJavaProject;
035: import org.eclipse.jdt.core.JavaCore;
036: import org.eclipse.jface.text.Document;
037: import org.eclipse.jface.text.IDocument;
038: import org.eclipse.swt.widgets.Display;
039: import org.eclipse.ui.IEditorInput;
040: import org.eclipse.ui.IEditorPart;
041: import org.eclipse.ui.IWorkbenchPage;
042: import org.eclipse.ui.PartInitException;
043: import org.eclipse.ui.editors.text.TextEditor;
044: import org.eclipse.ui.forms.editor.FormEditor;
045: import org.eclipse.ui.forms.widgets.FormToolkit;
046: import org.eclipse.ui.ide.ResourceUtil;
047: import org.eclipse.ui.part.FileEditorInput;
048: import org.eclipse.ui.texteditor.DocumentProviderRegistry;
049: import org.eclipse.ui.texteditor.IDocumentProvider;
050:
051: public class RuleEditor extends FormEditor implements
052: IResourceChangeListener {
053:
054: private BrlPage guidedEditor;
055:
056: private TextEditor xmlEditor = new TextEditor();
057:
058: private SuggestionCompletionEngine completion;
059:
060: private SuggestionCompletionLoader loader;
061:
062: private FileEditorInput packageEditorInput;
063:
064: private final Document drlDocument;
065:
066: private IResourceChangeListener packageFileTracker = new IResourceChangeListener() {
067:
068: public void resourceChanged(IResourceChangeEvent event) {
069: IResourceDelta delta = getRootDelta(event.getDelta());
070:
071: IPath p1 = delta.getFullPath();
072: IPath p2 = packageEditorInput.getFile().getFullPath();
073: if (p1.equals(p2)) {
074: reloadCompletionEngine();
075: }
076:
077: }
078:
079: };
080:
081: public RuleEditor() {
082: super ();
083: ResourcesPlugin.getWorkspace().addResourceChangeListener(this );
084: ResourcesPlugin.getWorkspace().addResourceChangeListener(
085: packageFileTracker, IResourceChangeEvent.POST_CHANGE);
086: drlDocument = new Document();
087:
088: }
089:
090: protected FormToolkit createToolkit(Display display) {
091: // Create a toolkit that shares colors between editors.
092: return new FormToolkit(DroolsEclipsePlugin.getDefault()
093: .getRuleBuilderFormColors(display));
094: }
095:
096: protected void addPages() {
097: guidedEditor = new BrlPage(this );
098: try {
099: addPage(guidedEditor);
100: addPage(xmlEditor, getEditorInput());
101:
102: DRLRuleEditor drlEditor = new DRLRuleEditor() {
103: protected IDocumentProvider createDocumentProvider() {
104: return new DRLDocumentProvider() {
105: public boolean isReadOnly(Object element) {
106: return true;
107: }
108:
109: public boolean isModifiable(Object element) {
110: return false;
111: }
112:
113: protected IDocument getParentDocument(
114: Object element) {
115: return drlDocument;
116: }
117: };
118: }
119:
120: };
121:
122: addPage(drlEditor, xmlEditor.getEditorInput());
123:
124: IPath packagePath = getCurrentDirectoryPath(
125: getEditorInput()).append("rule.package");
126:
127: IFile file = ResourcesPlugin.getWorkspace().getRoot()
128: .getFile(packagePath);
129:
130: IJavaProject javaProject = JavaCore.create(file
131: .getProject());
132:
133: ClassLoader classLoader = ProjectClassLoader
134: .getProjectClassLoader(javaProject);
135:
136: loader = new SuggestionCompletionLoader(classLoader);
137:
138: if (!file.exists()) {
139: String defaultHeader = "//This is a package configuration file";
140: defaultHeader += "\n//Add imports, globals etc here which will be used by all the rule assets in thise folder.";
141: InputStream is = new ByteArrayInputStream(defaultHeader
142: .getBytes());
143: try {
144: file.create(is, true, null);
145: } catch (CoreException e) {
146: DroolsEclipsePlugin.log(e);
147: }
148: }
149:
150: packageEditorInput = new FileEditorInput(file);
151:
152: reloadCompletionEngine();
153:
154: setPageText(1, "BRL Source");
155:
156: setPageText(2, "Generated DRL (read-only)");
157:
158: updateName(false);
159:
160: } catch (PartInitException e) {
161: DroolsEclipsePlugin.log(e);
162: }
163: }
164:
165: private void updateName(boolean forced) {
166: String name = xmlEditor.getTitle();
167: setPartName(name);
168:
169: //TODO Add support for other than .brl extensions
170: if (guidedEditor.getModeller() != null
171: && guidedEditor.getModeller().getModel() != null
172: && (guidedEditor.getModeller().getModel().name == null || forced)) {
173: String shortName = name.substring(0, name.length()
174: - ".brl".length());
175: guidedEditor.getModeller().getModel().name = shortName;
176: }
177:
178: updateDRLPage();
179:
180: }
181:
182: private IPath getCurrentDirectoryPath(IEditorInput editorInput) {
183: return ((FileEditorInput) editorInput).getFile().getFullPath()
184: .removeLastSegments(1).addTrailingSeparator();
185: }
186:
187: private void reloadCompletionEngine() {
188: try {
189:
190: // Load all .dsl files from current dir
191: IPath p = (packageEditorInput).getFile().getFullPath()
192: .removeLastSegments(1);
193:
194: Container folder = (Container) ResourcesPlugin
195: .getWorkspace().getRoot().findMember(p, false);
196:
197: IResource[] files = folder.members(false);
198:
199: List dslList = new ArrayList();
200:
201: for (int i = 0; i < files.length; i++) {
202: if (files[i].getName().endsWith(".dsl")) {
203: String contents = getFileContents((IFile) files[i]);
204: DSLMappingFile dsl = new DSLMappingFile();
205:
206: if (dsl.parseAndLoad(new StringReader(contents))) {
207: dslList.add(dsl);
208: } else {
209: //TODO report dsl parse error
210: }
211: }
212: }
213:
214: // Load suggestion engine
215: String str = getFileContents(packageEditorInput.getFile());
216:
217: completion = loader.getSuggestionEngine(str, dslList,
218: dslList);
219:
220: } catch (Exception e) {
221: DroolsEclipsePlugin.log(e);
222: }
223: }
224:
225: private String getFileContents(IFile file) {
226:
227: InputStream is;
228: try {
229: is = file.getContents();
230:
231: StringBuffer out = new StringBuffer();
232: byte[] b = new byte[4096];
233: for (int n; (n = is.read(b)) != -1;) {
234: out.append(new String(b, 0, n));
235: }
236:
237: return out.toString();
238: } catch (CoreException e) {
239: //TODO Report problem with the file loading
240: return "";
241: } catch (IOException e) {
242: //TODO Report problem with the file loading
243: return "";
244: }
245:
246: }
247:
248: public boolean isDirty() {
249: return xmlEditor.isDirty() || guidedEditor.isDirty();
250: }
251:
252: protected void pageChange(int newPageIndex) {
253: super .pageChange(newPageIndex);
254:
255: IDocument document = getInputDocument();
256:
257: if (newPageIndex == 0) {
258:
259: boolean newModel = guidedEditor.getModeller().getModel() == null;
260: if (xmlEditor.isDirty() || newModel) {
261: guidedEditor.setModelXML(document.get());
262: if (newModel) {
263: guidedEditor.getModeller().setDirty(false);
264: }
265: updateName(false);
266: }
267:
268: guidedEditor.refresh();
269:
270: } else if (newPageIndex == 1) {
271:
272: if (guidedEditor.isDirty()) {
273: document.set(BRXMLPersistence.getInstance().marshal(
274: guidedEditor.getRuleModel()));
275: }
276: } else if (newPageIndex == 2) {
277:
278: //Updating main document for proper workflow when page is switched back to "0"
279: if (guidedEditor.isDirty()) {
280: document.set(BRXMLPersistence.getInstance().marshal(
281: guidedEditor.getRuleModel()));
282: } else if (xmlEditor.isDirty()) {
283: guidedEditor.setModelXML(document.get());
284: }
285:
286: updateDRLPage();
287:
288: updateName(false);
289:
290: }
291:
292: }
293:
294: private void updateDRLPage() {
295:
296: String drl = "";
297: try {
298: drl = BRDRLPersistence.getInstance().marshal(
299: guidedEditor.getRuleModel());
300:
301: IResource resource = ResourceUtil.getResource(xmlEditor
302: .getEditorInput());
303:
304: Reader reader = DSLAdapter.getDSLContent(drl, resource);
305: DrlParser parser = new DrlParser();
306:
307: if (reader != null) {
308: drl = parser.getExpandedDRL(drl, reader);
309: }
310:
311: } catch (Throwable t) {
312:
313: StringWriter strwriter = new StringWriter();
314: t.printStackTrace(new PrintWriter(strwriter));
315: drl = "\nPROBLEM WITH THE DRL CONVERSION!\n\n\nDRL:\n"
316: + drl + "\n\nSTACKTRACE:\n" + strwriter.toString();
317: }
318: drlDocument.set(drl);
319: }
320:
321: public void doSave(IProgressMonitor monitor) {
322: IDocument document = getInputDocument();
323:
324: if (xmlEditor.isDirty()) {
325: guidedEditor.setModelXML(document.get());
326: } else if (guidedEditor.isDirty()) {
327: document.set(BRXMLPersistence.getInstance().marshal(
328: guidedEditor.getRuleModel()));
329: }
330:
331: xmlEditor.doSave(monitor);
332:
333: guidedEditor.getModeller().setDirty(false);
334:
335: guidedEditor.refresh();
336:
337: }
338:
339: private IDocument getInputDocument() {
340: IEditorInput input = getEditorInput();
341: IDocumentProvider docProvider = DocumentProviderRegistry
342: .getDefault().getDocumentProvider(input);
343: IDocument document = docProvider.getDocument(input);
344: return document;
345: }
346:
347: public void doSaveAs() {
348: xmlEditor.doSaveAs();
349: guidedEditor.getModeller().setDirty(false);
350: updateName(true);
351: setInput(xmlEditor.getEditorInput());
352:
353: guidedEditor.refresh();
354:
355: }
356:
357: public boolean isSaveAsAllowed() {
358: return true;
359: }
360:
361: public void resourceChanged(final IResourceChangeEvent event) {
362: if (event.getType() == IResourceChangeEvent.PRE_CLOSE) {
363: Display.getDefault().asyncExec(new Runnable() {
364: public void run() {
365: IWorkbenchPage[] pages = getSite()
366: .getWorkbenchWindow().getPages();
367: for (int i = 0; i < pages.length; i++) {
368: if (((FileEditorInput) xmlEditor
369: .getEditorInput()).getFile()
370: .getProject().equals(
371: event.getResource())) {
372: IEditorPart editorPart = pages[i]
373: .findEditor(xmlEditor
374: .getEditorInput());
375: pages[i].closeEditor(editorPart, true);
376: }
377: }
378: }
379: });
380: }
381: }
382:
383: public void dispose() {
384: ResourcesPlugin.getWorkspace().removeResourceChangeListener(
385: this );
386: ResourcesPlugin.getWorkspace().removeResourceChangeListener(
387: packageFileTracker);
388: super .dispose();
389: }
390:
391: public void dirtyPropertyChanged() {
392: firePropertyChange(IEditorPart.PROP_DIRTY);
393: guidedEditor.refresh();
394: }
395:
396: public SuggestionCompletionEngine getCompletionEngine() {
397: return completion;
398: }
399:
400: private IResourceDelta getRootDelta(IResourceDelta delta) {
401: if (delta.getAffectedChildren().length > 0) {
402: return getRootDelta(delta.getAffectedChildren()[0]);
403: }
404: return delta;
405: }
406:
407: }
|