001: package org.drools.eclipse;
002:
003: /*
004: * Copyright 2005 JBoss Inc
005: *
006: * Licensed under the Apache License, Version 2.0 (the "License");
007: * you may not use this file except in compliance with the License.
008: * You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */
018:
019: import java.io.Reader;
020: import java.util.HashMap;
021: import java.util.Iterator;
022: import java.util.List;
023: import java.util.Map;
024: import java.util.MissingResourceException;
025: import java.util.ResourceBundle;
026:
027: import org.drools.compiler.DrlParser;
028: import org.drools.compiler.DroolsParserException;
029: import org.drools.compiler.PackageBuilder;
030: import org.drools.compiler.PackageBuilderConfiguration;
031: import org.drools.eclipse.DRLInfo.FunctionInfo;
032: import org.drools.eclipse.DRLInfo.RuleInfo;
033: import org.drools.eclipse.builder.DroolsBuilder;
034: import org.drools.eclipse.builder.Util;
035: import org.drools.eclipse.dsl.editor.DSLAdapter;
036: import org.drools.eclipse.editors.AbstractRuleEditor;
037: import org.drools.eclipse.preferences.IDroolsConstants;
038: import org.drools.eclipse.util.ProjectClassLoader;
039: import org.drools.lang.descr.PackageDescr;
040: import org.drools.rule.builder.dialect.java.JavaDialectConfiguration;
041: import org.eclipse.core.resources.IFile;
042: import org.eclipse.core.resources.IResource;
043: import org.eclipse.core.resources.IResourceVisitor;
044: import org.eclipse.core.runtime.CoreException;
045: import org.eclipse.core.runtime.IStatus;
046: import org.eclipse.core.runtime.Status;
047: import org.eclipse.debug.core.DebugException;
048: import org.eclipse.jdt.core.IJavaProject;
049: import org.eclipse.jdt.core.JavaCore;
050: import org.eclipse.jface.preference.IPreferenceStore;
051: import org.eclipse.jface.resource.ImageDescriptor;
052: import org.eclipse.jface.resource.ImageRegistry;
053: import org.eclipse.jface.util.IPropertyChangeListener;
054: import org.eclipse.jface.util.PropertyChangeEvent;
055: import org.eclipse.swt.graphics.Color;
056: import org.eclipse.swt.widgets.Display;
057: import org.eclipse.ui.forms.FormColors;
058: import org.eclipse.ui.plugin.AbstractUIPlugin;
059: import org.osgi.framework.BundleContext;
060:
061: /**
062: * The main plugin class to be used in the desktop.
063: *
064: * @author <a href="mailto:kris_verlaenen@hotmail.com">kris verlaenen </a>
065: */
066: public class DroolsEclipsePlugin extends AbstractUIPlugin {
067:
068: public static final int INTERNAL_ERROR = 120;
069: public static final String PLUGIN_ID = "org.drools.eclipse";
070: public static final String BUILD_RESULT_PACKAGE = "Package";
071: public static final String BUILD_RESULT_PACKAGE_DESCR = "PackageDescr";
072:
073: //The shared instance.
074: private static DroolsEclipsePlugin plugin;
075: //Resource bundle.
076: private ResourceBundle resourceBundle;
077: private Map colors = new HashMap();
078: private Map parsedRules = new HashMap();
079: private Map compiledRules = new HashMap();
080: private Map ruleInfoByClassNameMap = new HashMap();
081: private Map functionInfoByClassNameMap = new HashMap();
082: private boolean useCachePreference;
083:
084: private FormColors ruleBuilderFormColors;
085:
086: /**
087: * The constructor.
088: */
089: public DroolsEclipsePlugin() {
090: super ();
091: plugin = this ;
092: }
093:
094: /**
095: * This method is called upon plug-in activation
096: */
097: public void start(BundleContext context) throws Exception {
098: super .start(context);
099: IPreferenceStore preferenceStore = getPreferenceStore();
100: useCachePreference = preferenceStore
101: .getBoolean(IDroolsConstants.CACHE_PARSED_RULES);
102: preferenceStore
103: .addPropertyChangeListener(new IPropertyChangeListener() {
104: public void propertyChange(PropertyChangeEvent event) {
105: if (IDroolsConstants.CACHE_PARSED_RULES
106: .equals(event.getProperty())) {
107: useCachePreference = ((Boolean) event
108: .getNewValue()).booleanValue();
109: if (!useCachePreference) {
110: clearCache();
111: }
112: }
113: }
114: });
115:
116: }
117:
118: public void clearCache() {
119: parsedRules.clear();
120: compiledRules.clear();
121: ruleInfoByClassNameMap.clear();
122: functionInfoByClassNameMap.clear();
123: }
124:
125: /**
126: * This method is called when the plug-in is stopped
127: */
128: public void stop(BundleContext context) throws Exception {
129: super .stop(context);
130: plugin = null;
131: resourceBundle = null;
132: parsedRules = null;
133: compiledRules = null;
134: Iterator iterator = colors.values().iterator();
135: while (iterator.hasNext()) {
136: ((Color) iterator.next()).dispose();
137: }
138: }
139:
140: /**
141: * Returns the shared instance.
142: */
143: public static DroolsEclipsePlugin getDefault() {
144: return plugin;
145: }
146:
147: /**
148: * Returns the string from the plugin's resource bundle,
149: * or 'key' if not found.
150: */
151: public static String getResourceString(String key) {
152: ResourceBundle bundle = DroolsEclipsePlugin.getDefault()
153: .getResourceBundle();
154: try {
155: return (bundle != null) ? bundle.getString(key) : key;
156: } catch (MissingResourceException e) {
157: return key;
158: }
159: }
160:
161: /**
162: * Returns the plugin's resource bundle,
163: */
164: public ResourceBundle getResourceBundle() {
165: try {
166: if (resourceBundle == null)
167: resourceBundle = ResourceBundle
168: .getBundle("droolsIDE.DroolsIDEPluginResources");
169: } catch (MissingResourceException x) {
170: resourceBundle = null;
171: }
172: return resourceBundle;
173: }
174:
175: /**
176: * Returns an image descriptor for the image file at the given
177: * plug-in relative path.
178: * Uses the plug ins image registry to "cache" it.
179: *
180: * @param path the path
181: * @return the image descriptor
182: */
183: public static ImageDescriptor getImageDescriptor(String path) {
184:
185: DroolsEclipsePlugin plugin = getDefault();
186: ImageRegistry reg = plugin.getImageRegistry();
187: ImageDescriptor des = reg.getDescriptor(path);
188: if (des == null) {
189: des = AbstractUIPlugin.imageDescriptorFromPlugin(
190: "org.drools.eclipse", path);
191: reg.put(path, des);
192: }
193: return des;
194: }
195:
196: public static String getUniqueIdentifier() {
197: if (getDefault() == null) {
198: return PLUGIN_ID;
199: }
200: return getDefault().getBundle().getSymbolicName();
201: }
202:
203: public static void log(Throwable t) {
204: Throwable top = t;
205: if (t instanceof DebugException) {
206: DebugException de = (DebugException) t;
207: IStatus status = de.getStatus();
208: if (status.getException() != null) {
209: top = status.getException();
210: }
211: }
212: log(new Status(IStatus.ERROR, getUniqueIdentifier(),
213: INTERNAL_ERROR, "Internal error in Drools Plugin: ",
214: top));
215: }
216:
217: public static void log(IStatus status) {
218: getDefault().getLog().log(status);
219: }
220:
221: public Color getColor(String type) {
222: return (Color) colors.get(type);
223: }
224:
225: public void setColor(String type, Color color) {
226: colors.put(type, color);
227: }
228:
229: protected void initializeDefaultPreferences(IPreferenceStore store) {
230: store.setDefault(IDroolsConstants.BUILD_ALL, false);
231: store.setDefault(IDroolsConstants.EDITOR_FOLDING, true);
232: store.setDefault(IDroolsConstants.CACHE_PARSED_RULES, true);
233: }
234:
235: public DRLInfo parseResource(IResource resource, boolean compile)
236: throws DroolsParserException {
237: DRLInfo result = (DRLInfo) compiledRules.get(resource);
238: if (result == null && !compile) {
239: result = (DRLInfo) parsedRules.get(resource);
240: }
241: if (result != null) {
242: return result;
243: }
244: return generateParsedResource(resource, compile);
245: }
246:
247: public DRLInfo parseResource(AbstractRuleEditor editor,
248: boolean useUnsavedContent, boolean compile)
249: throws DroolsParserException {
250: IResource resource = editor.getResource();
251: if (!editor.isDirty() || !useUnsavedContent) {
252: DRLInfo result = (DRLInfo) compiledRules.get(resource);
253: if (result == null && !compile) {
254: result = (DRLInfo) parsedRules.get(resource);
255: }
256: if (result != null) {
257: return result;
258: }
259: }
260: if (!editor.isDirty()) {
261: return generateParsedResource(editor.getContent(),
262: resource, true, compile);
263: }
264: // TODO: can we cache result when using unsaved content as well?
265: return generateParsedResource(editor.getContent(), resource,
266: !useUnsavedContent, compile);
267: }
268:
269: public DRLInfo parseXLSResource(String content, IResource resource)
270: throws DroolsParserException {
271: DRLInfo result = (DRLInfo) compiledRules.get(resource);
272: if (result != null) {
273: return result;
274: }
275: return generateParsedResource(content, resource, false, true);
276: }
277:
278: public DRLInfo parseBRLResource(String content, IResource resource)
279: throws DroolsParserException {
280: DRLInfo result = (DRLInfo) compiledRules.get(resource);
281: if (result != null) {
282: return result;
283: }
284: return generateParsedResource(content, resource, false, true);
285: }
286:
287: public void invalidateResource(IResource resource) {
288: DRLInfo cached = (DRLInfo) compiledRules.remove(resource);
289: if (cached != null) {
290: RuleInfo[] ruleInfos = cached.getRuleInfos();
291: for (int i = 0; i < ruleInfos.length; i++) {
292: ruleInfoByClassNameMap.remove(ruleInfos[i]
293: .getClassName());
294: }
295: FunctionInfo[] functionInfos = cached.getFunctionInfos();
296: for (int i = 0; i < functionInfos.length; i++) {
297: functionInfoByClassNameMap.remove(functionInfos[i]
298: .getClassName());
299: }
300: }
301: parsedRules.remove(resource);
302: }
303:
304: private DRLInfo generateParsedResource(IResource resource,
305: boolean compile) throws DroolsParserException {
306: if (resource instanceof IFile) {
307: IFile file = (IFile) resource;
308: try {
309: String content = new String(Util
310: .getResourceContentsAsCharArray(file));
311: return generateParsedResource(content, file, true,
312: compile);
313: } catch (CoreException e) {
314: log(e);
315: }
316: }
317: return null;
318: }
319:
320: private DRLInfo generateParsedResource(String content,
321: IResource resource, boolean useCache, boolean compile)
322: throws DroolsParserException {
323: useCache = useCache && useCachePreference;
324: DrlParser parser = new DrlParser();
325: try {
326: Reader dslReader = DSLAdapter.getDSLContent(content,
327: resource);
328: ClassLoader oldLoader = Thread.currentThread()
329: .getContextClassLoader();
330: ClassLoader newLoader = DroolsBuilder.class
331: .getClassLoader();
332: PackageBuilderConfiguration builder_configuration = new PackageBuilderConfiguration();
333: if (resource.getProject().getNature(
334: "org.eclipse.jdt.core.javanature") != null) {
335: IJavaProject project = JavaCore.create(resource
336: .getProject());
337: newLoader = ProjectClassLoader
338: .getProjectClassLoader(project);
339: String level = project.getOption(
340: JavaCore.COMPILER_COMPLIANCE, true);
341: JavaDialectConfiguration javaConf = (JavaDialectConfiguration) builder_configuration
342: .getDialectConfiguration("java");
343: javaConf.setJavaLanguageLevel(level);
344: }
345: try {
346: builder_configuration.setClassLoader(newLoader);
347: Thread.currentThread().setContextClassLoader(newLoader);
348:
349: // first parse the source
350: PackageDescr packageDescr = null;
351: List parserErrors = null;
352: if (useCache) {
353: DRLInfo cachedDrlInfo = (DRLInfo) parsedRules
354: .get(resource);
355: if (cachedDrlInfo != null) {
356: packageDescr = cachedDrlInfo.getPackageDescr();
357: parserErrors = cachedDrlInfo.getParserErrors();
358: }
359: }
360:
361: if (packageDescr == null) {
362: if (dslReader != null) {
363: packageDescr = parser.parse(content, dslReader);
364: } else {
365: packageDescr = parser.parse(content);
366: }
367: parserErrors = parser.getErrors();
368: }
369: PackageBuilder builder = null;
370: DRLInfo result = null;
371: // compile parsed rules if necessary
372: if (compile && !parser.hasErrors()) {
373: builder = new PackageBuilder(builder_configuration);
374:
375: // check whether a .package file exists and add it
376: if (resource.getParent() != null) {
377: MyResourceVisitor visitor = new MyResourceVisitor();
378: resource.getParent().accept(visitor,
379: IResource.DEPTH_ONE, IResource.NONE);
380: IResource packageDef = visitor.getPackageDef();
381: if (packageDef != null) {
382: builder.addPackage(parseResource(
383: packageDef, false)
384: .getPackageDescr());
385: }
386: }
387:
388: builder.addPackage(packageDescr);
389: result = new DRLInfo(resource
390: .getProjectRelativePath().toString(),
391: packageDescr, parserErrors, builder
392: .getPackage(), builder.getErrors()
393: .getErrors());
394: } else {
395: result = new DRLInfo(resource
396: .getProjectRelativePath().toString(),
397: packageDescr, parserErrors);
398: }
399:
400: // cache result
401: if (useCache) {
402: if (compile && !parser.hasErrors()) {
403: parsedRules.remove(resource);
404: compiledRules.put(resource, result);
405: RuleInfo[] ruleInfos = result.getRuleInfos();
406: for (int i = 0; i < ruleInfos.length; i++) {
407: ruleInfoByClassNameMap.put(ruleInfos[i]
408: .getClassName(), ruleInfos[i]);
409: }
410: FunctionInfo[] functionInfos = result
411: .getFunctionInfos();
412: for (int i = 0; i < functionInfos.length; i++) {
413: functionInfoByClassNameMap.put(
414: functionInfos[i].getClassName(),
415: functionInfos[i]);
416: }
417: } else {
418: parsedRules.put(resource, result);
419: }
420: }
421: return result;
422: } finally {
423: Thread.currentThread().setContextClassLoader(oldLoader);
424: }
425: } catch (CoreException e) {
426: log(e);
427: }
428: return null;
429: }
430:
431: public RuleInfo getRuleInfoByClass(String ruleClassName) {
432: return (RuleInfo) ruleInfoByClassNameMap.get(ruleClassName);
433: }
434:
435: public FunctionInfo getFunctionInfoByClass(String functionClassName) {
436: return (FunctionInfo) functionInfoByClassNameMap
437: .get(functionClassName);
438: }
439:
440: /**
441: * Form Colors, default colors for now.
442: *
443: * @param display
444: * @return
445: */
446: public FormColors getRuleBuilderFormColors(Display display) {
447: if (ruleBuilderFormColors == null) {
448: ruleBuilderFormColors = new FormColors(display);
449: ruleBuilderFormColors.markShared();
450: }
451: return ruleBuilderFormColors;
452: }
453:
454: private class MyResourceVisitor implements IResourceVisitor {
455: private IResource packageDef;
456:
457: public boolean visit(IResource resource) throws CoreException {
458: if ("package".equals(resource.getFileExtension())) {
459: packageDef = resource;
460: }
461: return true;
462: }
463:
464: public IResource getPackageDef() {
465: return packageDef;
466: }
467: }
468: }
|