DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
Securing Your Software Supply Chain with JFrog and Azure
Register Today

Trending

  • Constructing Real-Time Analytics: Fundamental Components and Architectural Framework — Part 2
  • Introduction to Domain-Driven Design
  • Tech Hiring: Trends, Predictions, and Strategies for Success
  • Avoiding Pitfalls With Java Optional: Common Mistakes and How To Fix Them [Video]

Trending

  • Constructing Real-Time Analytics: Fundamental Components and Architectural Framework — Part 2
  • Introduction to Domain-Driven Design
  • Tech Hiring: Trends, Predictions, and Strategies for Success
  • Avoiding Pitfalls With Java Optional: Common Mistakes and How To Fix Them [Video]

Associating Xtext editors to file names, instead of file extensions

Alex Ruiz user avatar by
Alex Ruiz
·
Jan. 13, 12 · Interview
Like (1)
Save
Tweet
Share
7.60K Views

Join the DZone community and get the full member experience.

Join For Free

I’m currently working on a Xtext-based editor for Google’s BUILD language, as described in our Google Engineering Blog. BUILD files do not contain an extension, they are simply named “BUILD.” This naming convention make working with Xtext quite challenging. I needed to change Xtext’s default behavior: instead of associating Xtext editors to file extensions, I needed to associate them to file names. In this blog post I’m describing how I was able to accomplish this.

In this post I’ll be using a brand-new Xtext project. To keep things simple, I’ll use the default file extension (mydsl) and grammar. You can get the source code of this post from Xtext Samples, a new open source project where I plan to store the code I use in Xtext-related posts. All code is released under the Eclipse Public License (EPL) 1.0.

The following steps assume we are going to associate our Xtext editor with the file name “MyDsl.”

  1. Modify the plug-in’s XtextEditor to make it understand file names, instead of file extensions.
  2. Create a ContentHandler that describes the content of files with name “MyDsl.” As part of this step we need to create a new content type for “MyDsl” files.
  3. Create an IResourceServiceProvider that provides services (e.g. validation, content description, encoding) to files with name “MyDsl.”
  4. Register the classes created in the previous steps, to make them visible to EMF and Xtext.

1. Modify the plug-in’s XtextEditor to make it understand file names

This is the easiest of all steps:

  1. Open the file plugin.xml in the “ui” project.
  2. Select the “plugin.xml” tab at the bottom of the editor, to edit the XML code directly.
  3. In the editor element, replace extensions="mydsl" with filenames="MyDsl"

2. Create a ContentHandler that describes the content of files with name “MyDsl”

Here is a simplified version of our ContentHandler. You can find the complete file here.

public class MyDslContentHandler extends ContentHandlerImpl {
  public static final String MY_DSL_FILE_CONTENT_TYPE = "com.google.eclipse.MyDsl";
 
  @Override public boolean canHandle(URI uri) {
    return isMyDslFile(uri);
  }
 
  @Override public Map<String, Object> contentDescription(URI uri, InputStream inputStream,
      Map<?, ?> options, Map context) throws IOException {
    Map<String, Object> description = super.contentDescription(uri, inputStream, options, context);
    if (canHandle(uri)) {
      description.put(VALIDITY_PROPERTY, VALID);
      description.put(CONTENT_TYPE_PROPERTY, MY_DSL_FILE_CONTENT_TYPE);
    }
    return description;
  }
}

Line 2: We define a new content type for “MyDsl” files. We keep the constant public since we will be using it later.
Line 4: We specify that file names with name “MyDsl” can be handled by the ContentHandler. We call the utility method isMyDslFile(URI) from the class URIs.
Line 8: We declare the content of “MyDsl” files as valid and associate its type to the one defined in line 2.

3. Create an IResourceServiceProvider that provides services to files with name “MyDsl”

Here is a simplified version of our IResourceServiceProvider. You can find the complete file here.

public class MyDslResourceServiceProvider extends DefaultResourceServiceProvider {
  @Override public boolean canHandle(URI uri) {
    return isMyDslFile(uri);
  }
}

We call the utility method isMyDslFile(URI) from the class URIs to specify that this IResourceServiceProvider can handle files with names “MyDsl.”

4. Register the classes created in the previous steps, to make them visible to EMF and Xtext

Now it’s time to wire up everything together. First, we bind IResourceServiceProvider to our MyDslResourceServiceProvider in the plug-in runtime module:

 public Class<? extends IResourceServiceProvider> bindIResourceServiceProvider() {
    return MyDslResourceServiceProvider.class;
  }

Now we tell Xtext and EMF, in MyDslUiModule‘s constructor, to understand files named “MyDsl.”

public class MyDslUiModule extends AbstractMyDslUiModule {
 
  public MyDslUiModule(AbstractUIPlugin plugin) {
    super(plugin);
    configureXtextToWorkWithFileNames(new InjectorProvider());
  }
}

We pass an InjectorProvider that obtains the plugin’s Injector only at the moment when it is needed. At this point we cannot pass the Injector directly, since it has not been fully constructed when configureXtextToWorkWithFileNames is called.

The method configureXtextToWorkWithFileNames(InjectorProvider) is defined in XtextSetup:

final class XtextSetup {
 
  static void configureXtextToWorkWithFileNames(InjectorProvider injectorProvider) {
    register(new MyDslContentHandler());
    register(new ResourceFactoryDescriptor(injectorProvider));
    register(new ResourceServiceProvider(injectorProvider));
  }
 
  private static void register(ContentHandler h) {
    ContentHandler.Registry registry = ContentHandler.Registry.INSTANCE;
    registry.put(HIGH_PRIORITY, h);
  }
 
  private static void register(Resource.Factory.Descriptor d) {
    Resource.Factory.Registry registry = Resource.Factory.Registry.INSTANCE;
    registry.getContentTypeToFactoryMap().put(MY_DSL_FILE_CONTENT_TYPE, d);
  }
 
  private static void register(Provider<IResourceServiceProvider> p) {
    IResourceServiceProvider.Registry registry = IResourceServiceProvider.Registry.INSTANCE;
    registry.getContentTypeToFactoryMap().put(MY_DSL_FILE_CONTENT_TYPE, p);
  }
}

Line 4: We register the ContentHandler we created in step 2.
Line 5: We associate the IResourceFactory in the plug-in’s Guice module with the content type defined in step 2.
Line 6: We associate the IResourceServiceProvider we created in step 3 (and later on registered in the plug-in’s Guice module) with the content type defined in step 2.

Testing the editor

To run the editor, right-click any of the projects and select “Run As” > “Eclipse Application” from the context menu.

Here is a screenshot of the editor opening a file named “MyDsl”

Summary

In this post I have shown how to make Xtext understand file names in four easy steps. You can find the code for this post in the project Xtext Samples. You can checkout the code, browse it or download it.

Even though I spent a good amount of time reading Xtext and EMF code to figure this out, I cannot claim my solution is the best one. Please let me know if you know a better way to do what I described in this post :)

Feedback is always welcome.

 

From http://alexruiz.developerblogs.com/?p=2080

Opinions expressed by DZone contributors are their own.

Trending

  • Constructing Real-Time Analytics: Fundamental Components and Architectural Framework — Part 2
  • Introduction to Domain-Driven Design
  • Tech Hiring: Trends, Predictions, and Strategies for Success
  • Avoiding Pitfalls With Java Optional: Common Mistakes and How To Fix Them [Video]

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com

Let's be friends: