cross-file reference and link in xtext [message #1716632] |
Sun, 06 December 2015 21:10  |
Eclipse User |
|
|
|
I created a new DSL by using xtext as follows. (Actually I will access the DSL on RCP application.)
grammar org.xtext.example.mydsl.MyDsl with org.eclipse.xtext.common.Terminals
generate myDsl "...www.xtext.org/example/mydsl/MyDsl"
Configuration:
components+=(Component)*;
Component:
'Component' name=ID
'{'
(('display' display=STRING) &
('dependency' dependency=[Component|ID])?)
'}'
;
I have two files: sample1.mydsl
Component comp1 {
display "comp1"
children comp2
}
sampl2.mydsl
Component comp2 {
display "comp2"
}
On RCP Application, I will compose a tree view with the Configuration model. But when I get comp2 object from getChildren() method of comp1 object, sometimes I couldn't get the comp2 object exactly.
I loaded the model data as below:
private List<ConfigurationItem> itemList;
void loadData() {
project = ResourcesPlugin.getWorkspace().getRoot().getProject("test");
XtextResourceSet resourceSet = (XtextResourceSet) injector
.getInstance(XtextResourceSetProvider.class)
.get(project);
resourceSet.addLoadOption(XtextResource.OPTION_RESOLVE_ALL, Boolean.TRUE);
IFile[] samples = findFiles(resources);
List<Resource> resourceList = new ArrayList<Resource>();
for (IFile sample : samples) {
Resource resourceSample = resourceSet.getResource(
URI.createURI(sample.getLocationURI().toString(), true), true);
resourceList.add(resourceSample);
}
for (Resource resource : resourceList) {
System.out.println("resource = " + resource.toString());
try {
resource.load(null);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
EcoreUtil.resolveAll(resource);
}
// add all to configuration item list
for (Resource rc : resourceList) {
Configuration config = (Configuration) rc.getContents().get(0);
itemList.addAll(config.getConfigurationItems().toArray(new ConfigurationItem[config.getConfigurationItems().size()]));
}
}
test code
for (ConfigurationItem item : itemList) {
if (item.getName().equals("comp1") {
Component[] comps = item.getChildren();
for (Component comp : comps) {
if (comp != null) {
System.out.println("comp display : " + comp.getDisplay());
}
}
}
}
result
I expected the result to be "comp display : comp2".
But Sometimes the result is "comp display : comp2"
and sometimes the result is "comp display : null"
I think it is because of the lazy linking of xtext.
How can always I get correct result -> "comp display : comp2"?
I Hope someone can help me solve it. Thanks.
[Updated on: Sun, 06 December 2015 22:39] by Moderator
|
|
|
|
|
|
|
|
|
|
|
|
|
Re: cross-file reference and link in xtext [message #1716817 is a reply to message #1716665] |
Tue, 08 December 2015 06:44   |
Eclipse User |
|
|
|
I made up a sample for analysis.
Please check below.
1. The code below is my sample test code. I call
new SampleConfigLoadOperation3().run(monitor); on my RCP Application.
SampleConfigLoadOperation3.java
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.jface.operation.IRunnableWithProgress;
import com.mdstec.ide.kcdsl.ConfigDSL.ConfigurationItem;
import com.mdstec.ide.kcdsl.ConfigDSL.Configuration;
public class SampleConfigLoadOperation3 implements IRunnableWithProgress {
// Progress message
final String loadConfigTaskBeginMsg = "load configuration.";
IProject project;
DataListener dataListener;
/**
* Constructor for project configuration object
*
* @param prjConfig
* the project configuration object
*/
public SampleConfigLoadOperation3() {
// TODO Auto-generated constructor stub
}
public SampleConfigLoadOperation3(IProject project, DataListener listner) {
// TODO Auto-generated constructor stub
this.project = project;
this.dataListener = listner;
}
@Override
public void run(IProgressMonitor monitor) throws InvocationTargetException,
InterruptedException {
// TODO Auto-generated method stub
if (monitor != null) {
monitor.beginTask(loadConfigTaskBeginMsg, IProgressMonitor.UNKNOWN);
}
try {
loadConfigData(monitor);
} catch (Exception e) {
throw new InvocationTargetException(e, "Loading error" + ": "
+ e.getMessage());
} finally {
if (monitor != null) {
monitor.done();
}
}
if (monitor != null) {
if (monitor.isCanceled()) {
throw new InterruptedException("Cancel loading");
}
}
}
private void loadConfigData(IProgressMonitor monitor) {
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IWorkspaceRoot workspaceRoot = workspace.getRoot();
project = workspaceRoot.getProject("testproject");
IFolder sampleFolder = project.getFolder("data");
//at this point, no resources have been created
try {
if (!project.exists())
project.create(null);
if (!project.isOpen())
project.open(null);
} catch (CoreException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
if (!sampleFolder.exists()) {
try {
sampleFolder.create(IResource.NONE, true, null);
} catch (CoreException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
copyDataFileToProject("sample1.cdl", "data");
copyDataFileToProject("sample2.cdl", "data");
// copyDataFileToProject("sample3.cdl", "data");
ResourceSet resourceSet = new ResourceSetImpl();
IResource[] resources = null;
try {
resources = sampleFolder.members();
} catch (CoreException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
if (resources != null) {
IFile[] samples = findFiles(resources);
List<Resource> resourceList = new ArrayList<Resource>();
for (IFile sample : samples) {
Resource resourceSample = resourceSet.getResource(
URI.createURI(sample.getFullPath().toString()), true);
resourceList.add(resourceSample);
}
// add all to configuration item list
List<ConfigurationItem> configItemList = new ArrayList<ConfigurationItem>();
for (Resource rc : resourceList) {
Configuration config = (Configuration) rc
.getContents().get(0);
configItemList.addAll(config.getConfigurationItems());
}
// root model
List<ConfigurationItem> rootItemList = new ArrayList<ConfigurationItem>();
// set root list in configuration item list
for (int i = 0; i < configItemList.size(); i++) {
ConfigurationItem item = configItemList.get(i);
if (item instanceof com.mdstec.ide.kcdsl.ConfigDSL.Package) {
if (((com.mdstec.ide.kcdsl.ConfigDSL.Package) item)
.isIsRoot()) {
rootItemList.add(item);
}
}
}
// set parents
for (int i = 0; i < rootItemList.size(); i++) {
ConfigurationItem root = rootItemList.get(i);
ConfigurationItem[] children = (ConfigurationItem[]) root
.getChildren().toArray();
setParent(children, root);
}
System.out.println("root size = " + rootItemList.size());
for (ConfigurationItem item : rootItemList) {
findChildren(item);
}
}
}
private void copyDataFileToProject(String fileName, String prjDir) {
// TODO Auto-generated method stub
File file = new File("C:/test/data/" + fileName);
URL sourceURL = null;
try {
sourceURL = file.toURL(); // using .toURI().toURL()
// fails,
// due to
// spaces substitution
} catch (MalformedURLException e) {
e.printStackTrace();
}
InputStream in = null;
try {
in = sourceURL.openStream();
} catch (IOException e) {
e.printStackTrace();
}
IFile iFile = project.getFile(prjDir + "/" + fileName);
if (!iFile.exists()) {
try {
iFile.create(in, true, null);
iFile.refreshLocal(IResource.DEPTH_ONE, null);
} catch (CoreException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private void findChildren(ConfigurationItem item) {
// TODO Auto-generated method stub
ConfigurationItem[] children = (ConfigurationItem[]) item.getChildren()
.toArray();
if (children != null && children.length > 0) {
for (ConfigurationItem child : children) {
System.out.println("child name of " + item.getName() + " : "
+ child.getName());
findChildren(child);
}
}
}
private void setParent(ConfigurationItem[] children,
ConfigurationItem parent) {
// TODO Auto-generated method stub
if (children != null && children.length > 0) {
for (ConfigurationItem child : children) {
child.setParent(parent);
setParent((ConfigurationItem[]) child.getChildren().toArray(),
child);
}
}
}
private IFile[] findFiles(IResource[] resources) {
List<IFile> fileList = new ArrayList<IFile>();
find(resources, fileList);
return fileList.toArray(new IFile[fileList.size()]);
}
private void find(IResource[] resources, List<IFile> fileList) {
// TODO Auto-generated method stub
if (resources != null && resources.length > 0) {
for (IResource res : resources) {
if (res instanceof IFile) {
fileList.add((IFile) res);
} else if (res instanceof IFolder) {
IResource[] reses;
try {
reses = ((IFolder) res).members();
find(reses, fileList);
} catch (CoreException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
}
2. I defined my DSL using xtext as below and generated the models and parser.
ConfigDSL.xtext
generate ConfigDSL "............."
Configuration:
((configurationItems+=ConfigurationItem)*
;
ConfigurationItem:
Package | Component
;
Package:
'Package' name=ID
'{'
(('display' display=STRING) &
('description' description=STRING)? &
('children' children += [ConfigurationItem|ID] (',' children += [ConfigurationItem|ID])*)? &
('parent' parent = [ConfigurationItem|ID])? &
('isRoot' isRoot=BOOLEAN)?
)
'}'
;
Component:
'Component' name=ID
'{'
(('display' display=STRING) &
('parent' parent = [ConfigurationItem|ID])?
)
'}'
;
terminal BOOLEAN returns ecore::EBoolean
: 'true' | 'false';
3. I created two DSL files (sample1.cdl, sample2.cdl) as below and located in "C:/test/data" directory.
sample1.cdl
Component ds1 {
display "ds1"
}
Component ds2 {
display "ds2"
}
Package pk1 {
display "pk1"
children ds1, ds2, ds3
isRoot true
}
sample2.cdl
Component ds3 {
display "ds3"
}
4. When I call "new SampleConfigLoadOperation3().run(monitor);" on my RCP Application, the result is as follows.
root size = 1
child name of pk1 : ds1
child name of pk1 : ds2
child name of pk1 : null
I don't know why the result of the 3rd line is "child name of pk1 : null".
I expected the result is "child name of pk1 : ds3".
|
|
|
|
|
|
Re: cross-file reference and link in xtext [message #1716937 is a reply to message #1716923] |
Wed, 09 December 2015 01:54  |
Eclipse User |
|
|
|
I solved the problem.
When creating ResourceSet object, I Modified the codes as below.
Now it works well.
Injector injector = new MyDSLStandaloneSetup().createInjectorAndDoEMFRegistration();
XtextResourceSet resourceSet = injector.getInstance(XtextResourceSet.class);
I understood wrong that MyDSLStandaloneSetup() should not use in RCP.
|
|
|
Powered by
FUDForum. Page generated in 0.49593 seconds