[rules-users] Multiple DSL files with Eclipse IDE

George Zhou pengcheng.zhou at gmail.com
Wed Mar 6 11:22:29 EST 2013


Coming from ILog JRule background, I start to use Drool 5.5 final version for
a new project and find this is still an issue for Eclipse drool plugin to
have multiple DSLs for one dslr. Not sure why JBRULES-1615 is closed. My
logical guess is that they closed from knowledge builder view, not eclipse
ide plugin view.

After seeing the source code and did a quick fix, it works perfectly for me.
Like to share my changes to contribute back this wonderful community since I
get a lot from this in early days.

Here assumes you use drools 5.5.0 final plugin, the other version should
work the same way
#1. backup eclipse-dir/plugins/org.drools.eclipse_5.5.0.Final.jar to
somewhere
#2. unjar eclipse/plugins/org.drools.eclipse_5.5.0.Final.jar to a work-dir
#3. replace the org.drools.eclipse.dsl.editor.DSLAdapter.class to the
following class in work-dir
#4. re-jar back to jar cvfm ../org.drools.eclipse_5.5.0.Final.jar
META-INF\MANIFEST.MF * in work-dir
#5. cp ../org.drools.eclipse_5.5.0.Final.jar from work-dir to
eclipse-dir/plugins/org.drools.eclipse_5.5.0.Final.jar
#6. start your eclipse, it should support multiple DSL files in eclipse IDE

Extra surprise is found that if you have multiple dslr files, instead of
each file has expander mydsl1.dsl; expander mydsl2.dsl; ...  you can define
all dsl expander into package file, whose name doesn't matter, but the file
ext must be .package, e.g. "dsl.package"


/*
 * Copyright 2010 JBoss Inc
 *
 * 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.dsl.editor;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.drools.eclipse.DroolsEclipsePlugin;
import org.drools.eclipse.builder.Util;
import org.drools.eclipse.editors.completion.DSLTree;
import org.drools.lang.dsl.DSLMapping;
import org.drools.lang.dsl.DSLMappingEntry;
import org.drools.lang.dsl.DSLTokenizedMappingFile;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.runtime.CoreException;

/**
 * This holds the DSL configuration for an editor instance.
 * When loading, it will find the DSL file, and load the applicable lists.
 * 
 * This provides a link between the editor and the DSL features of the rule
language.  
 * 
 * It will look for a DSL configuration, as named in the rule file, in the
same directory as the rule file.
 * Failing this, it will search one directory above the rule file. 
 * Failing that, it will search the root of the project in the workspace.
 */
public class DSLAdapter {

    private String dslConfigName;
    private boolean valid = false;
    private List conditionProposals = new ArrayList();
    private List consequenceProposals = new ArrayList();
    private DSLTree dslTree = new DSLTree();
    
    //to dig out the expander, without using the parser.
    private static final Pattern EXPANDER_PATTERN = Pattern.compile(
"\\n\\s*expander\\s*(.*)\\.dsl", 
                                                             Pattern.DOTALL
| Pattern.MULTILINE );
    // # george change #1 BGN - ADD
    private static final Pattern SINGLE_LINE_EXPANDER_PATTERN =
Pattern.compile( "\\n\\s*expander\\s*(.*)\\.dsl" );
    // # george change #1 END - ADD
    
    /**
     * This will sniff out the DSL config file name from the content.
     * It will then use the IFile input to search around for the file
itself.
     * TODO: provide an alternative that just loads off a stream (for non
IDEs workbenches like jlibrary).
     * @param content Rule source
     * @param input File from the FileEditorInput
     */
    public DSLAdapter(String content, IFile input) throws CoreException {
        dslConfigName = findDSLConfigName( content, input );
        if (dslConfigName == null) {
            return;
        }
        loadConfig( input );
    }
    
    /** Get a reader to the DSL contents */
    public static Reader getDSLContent(String ruleSource, IResource input)
throws CoreException {
        // # george change #2 BGN - CHANGE
        String[] dslFileNames = findDSLConfigNames( ruleSource, input );
        if (dslFileNames == null || dslFileNames.length == 0) {
            return null;
        }
        if (dslFileNames.length == 1) {
        	IResource res = findDSLResource( input, dslFileNames[0] );
	        if (res instanceof IFile) {
	            IFile dslConf = (IFile) res;
	            if (dslConf.exists()) {
	                return new InputStreamReader(dslConf.getContents());
	            }
	        }
        	return null;
        } else {
	        MultiReader ret = new MultiReader();
	        for (String dslFileName: dslFileNames) {
	        	IResource res = findDSLResource( input, dslFileName );
		        if (res instanceof IFile) {
		            IFile dslConf = (IFile) res;
		            if (dslConf.exists()) {
		                ret.add( new InputStreamReader(dslConf.getContents()) );
		            }
		        }
	        }
	        return ret;
        }
        // # george change #2 END - CHANGE
    }

	/**
     * This does the hunting around the projec to find the .dsl file.
     */
    private void loadConfig(IFile input) {
        IResource res = findDSLResource( input, dslConfigName );
        if (res instanceof IFile) {
            IFile dslConf = (IFile) res;
            if (dslConf.exists()) {
                InputStream stream = null;
                try {
                    stream = dslConf.getContents();
                    readConfig( stream );
                    valid = true;
                } catch ( Exception e ) {
                    throw new IllegalStateException("Unable to open DSL
config file. (Exception: " + e.getMessage() + ")");
                } finally {
                    closeStream( stream );
                }
                
            }
        }
    }

    private static IResource findDSLResource(IResource input, String
dslFileName) {
        IResource res = input.getParent().findMember( dslFileName );
        if (res == null) res = input.getParent().getParent().findMember(
dslFileName ); //try parent directory
        if (res == null) res = input.getProject().findMember( dslFileName );
//try root of project.
        return res;
    }

    
    /** This will load in the DSL config file, using the DSLMapping from
drools-compiler */
    void readConfig(InputStream stream) throws IOException, CoreException {
        DSLTokenizedMappingFile file = new DSLTokenizedMappingFile();
        file.parseAndLoad(new InputStreamReader(stream));

        DSLMapping grammar = file.getMapping();
        List conditions = grammar.getEntries( DSLMappingEntry.CONDITION );
        List consequences = grammar.getEntries( DSLMappingEntry.CONSEQUENCE
);
        
        conditionProposals = buildProposals(conditions);
        consequenceProposals = buildProposals(consequences);
        
        dslTree.buildTree(grammar);
    }

    private List buildProposals(List suggestions) {
        List result = new ArrayList(suggestions.size());
        Iterator iterator = suggestions.iterator();
        while (iterator.hasNext()) {
            DSLMappingEntry text = (DSLMappingEntry) iterator.next();
            result.add(text.getMappingKey());
        }
        return result;
    }

    private void closeStream(InputStream stream) {
        if (stream != null) try {
            stream.close();
        } catch ( IOException e ) {}
    }

    DSLAdapter() {
        
    }
    
    private static String findDSLConfigName(String content, IResource input)
throws CoreException {
        String dslConfigName = findDSLConfigName( content );
        if (dslConfigName == null)  {
            // try searching the .package file
            if (input != null && input.getParent() != null) {
                MyResourceVisitor visitor = new MyResourceVisitor();
                input.getParent().accept(visitor, IResource.DEPTH_ONE,
IResource.NONE);
                IResource packageDef = visitor.getPackageDef();
                if (packageDef != null) {
                    if (packageDef instanceof IFile) {
                        IFile file = (IFile) packageDef;
                        try {
                            String pContent = new
String(Util.getResourceContentsAsCharArray(file));
                            dslConfigName = findDSLConfigName( pContent );
                        } catch (CoreException e) {
                            DroolsEclipsePlugin.log(e);
                        }
                    }
                }
            }
        }
        return dslConfigName;
    }

    
    /** Sniffs out the expander/DSL config name as best it can. */
    static String findDSLConfigName(String content) {
        String name = null;
        Matcher matches = EXPANDER_PATTERN.matcher( content );
        if (matches.find()) {
            name = matches.group(1) + ".dsl";
        }
        return name;
    }

    // # george change #3 BGN - ADD    
    private static String[] findDSLConfigNames(String content, IResource
input) throws CoreException {
    	String[] ret = findDSLConfigNames(content);
    	if (ret == null || ret.length == 0) {
            // try searching the .package file
            if (input != null && input.getParent() != null) {
                MyResourceVisitor visitor = new MyResourceVisitor();
                input.getParent().accept(visitor, IResource.DEPTH_ONE,
IResource.NONE);
                IResource packageDef = visitor.getPackageDef();
                if (packageDef != null) {
                    if (packageDef instanceof IFile) {
                        IFile file = (IFile) packageDef;
                        try {
                            String pContent = new
String(Util.getResourceContentsAsCharArray(file));
                            ret = findDSLConfigNames( pContent );
                        } catch (CoreException e) {
                            DroolsEclipsePlugin.log(e);
                        }
                    }
                }
            }    		
    	}
    	return ret;
    }
    
    /** Sniffs out the expander/DSL config name as best it can. */
    static String[] findDSLConfigNames(String content) {
        List<String> names = new ArrayList<String>(4);
        Matcher matches = SINGLE_LINE_EXPANDER_PATTERN.matcher( content );
        while (matches.find()) {
        	names.add(matches.group(1) + ".dsl");
        }
        return names.toArray(new String[names.size()]);
    }
    // # george change #3 END - ADD    
    
    String getDSLConfigName() {
        return dslConfigName;
    }
    
    
    public boolean isValid() {
        return valid;
    }
    
    
    public boolean hasConditions() {
        return conditionProposals.size() > 0;
    }
    
    public boolean hasConsequences() {
        return consequenceProposals.size() > 0;
    }
    
    public List listConditionItems() {
        return conditionProposals;
    }
    
    public List listConsequenceItems() {
        return consequenceProposals;
    }
    
    public DSLTree getDSLTree() {
        return dslTree;
    }
    
    private static class MyResourceVisitor implements IResourceVisitor {
        private IResource packageDef;
        public boolean visit(IResource resource) throws CoreException {
            if ("package".equals(resource.getFileExtension())) {
                packageDef = resource;
            }
            return true;
        }
        public IResource getPackageDef() {
            return packageDef;
        }
    }
    
    public static class MultiReader extends Reader {
    	private final List<Reader> readers = new ArrayList<Reader>(4);
    	private int idx = 0;
    	
    	public void add(Reader r) {
    		readers.add(r);
    	}
    	
		@Override
		public int read(char[] cbuf, int off, int len) throws IOException {
			if (idx >= readers.size()) {
				return -1;
			}
			int ret = readers.get(idx).read(cbuf, off, len);
			while (ret == -1) {
				idx ++;
				if (idx >= readers.size()) {
					return -1;
				}
				ret = readers.get(idx).read(cbuf, off, len);
			}
			return ret;
		}

		@Override
		public void close() throws IOException {
			for (Reader r: readers) {
				r.close();
			}
		}
    }
}



 



--
View this message in context: http://drools.46999.n3.nabble.com/Multiple-DSL-files-with-Eclipse-IDE-tp4017797p4022714.html
Sent from the Drools: User forum mailing list archive at Nabble.com.


More information about the rules-users mailing list