Eclipse as a technology platform for 1C:Enterprise Development Tools

Probably, Eclipse no longer needs a special introduction. Many people are familiar with Eclipse thanks to the Eclipse Java development tools (JDT). It is this popular open-source Java IDE that most developers associate with the word “Eclipse”. However, Eclipse is both an extensible platform for integrating development tools (Eclipse Platform), and a number of IDEs built on top of it, including JDT. Eclipse is both the Eclipse Project, the top-level project that coordinates the development of the Eclipse Platform and the JDT, and the Eclipse SDK, the deliverable result of that development. Finally, Eclipse is an open-source Foundation with a huge community of projects, not all of which are written in Java or related to development tools (for example, projects Eclipse IoT и Eclipse Science). The world of Eclipse is very diverse.

In this review article, we will try to consider some of the basics of the Eclipse architecture as a platform for building integrated development tools and give an initial idea of ​​​​the Eclipse components that form the foundation of the technological platform for the “new Configurator” 1C: Enterprise, 1C:Enterprise Development Tools. Of course, such a review will inevitably be largely superficial and rather limited, also because we are targeting not only Eclipse developers as the target audience. However, we hope that even experienced Eclipse developers will be able to find interesting information in the article. For example, we will talk about one of the "secrets of Eclipse", a relatively new and little-known project so far. Eclipse Handy, which was founded and maintained by 1C.
Eclipse as a technology platform for 1C:Enterprise Development Tools

Introduction to the Eclipse architecture

Let's first look at some general aspects of the Eclipse architecture using an example Eclipse Java development tools (JDT). The choice of JDT as an example is not accidental. This is the first IDE to appear in Eclipse. Other *DT Eclipse projects, such as the Eclipse C/C++ Development Tooling (CDT), were created later and borrowed both the main architectural principles and source code fragments from the JDT. The fundamentals of the architecture laid down in the JDT are relevant to this day for almost any IDE built on top of the Eclipse Platform, including 1C:Enterprise Development Tools.

First of all, it should be noted that Eclipse is characterized by a fairly clear architectural stratification, with the separation of language-independent functionality from the functionality designed to support specific programming languages, and the separation of UI-independent "core" (core) components from components related to user support. interface.

For example, the Eclipse Platform defines a common, language-independent infrastructure, and the Java development tools add a full-featured Java IDE to Eclipse. Both the Eclipse Platform and the JDT are made up of several components, each of which is either a UI-independent "core" or a UI layer (Figure 1).

Eclipse as a technology platform for 1C:Enterprise Development Tools
Rice. 1. Eclipse Platform and JDT

We list the main components of the Eclipse Platform:

  • Runtime - Defines the plugin infrastructure. Eclipse has a modular architecture. Essentially, Eclipse is a collection of "extension points" and "extensions".
  • workspace - Manages one or more projects. A project consists of folders and files that map directly to the file system.
  • Standard Widget Toolkit (SWT) - Provides basic user interface elements that are integrated with the operating system.
  • JFace - Provides a range of UI frameworks built on top of SWT.
  • Workbench - Defines the Eclipse UI paradigm: editors, views, perspectives.

I must say that the Eclipse Platform provides many other useful components for building integrated development tools, among which are Debug, Compare, Search, and Team. We should also mention JFace Text - the basis for building "smart editors" of the source code. Unfortunately, even a cursory review of these components, as well as the UI layer component, is not possible within the framework of this article, so in the rest of this section we will limit ourselves to reviewing the main "core" components of the Eclipse Platform and JDT.

core runtime

The Eclipse Plugin Framework is based on OS Gi and provided by the project Eclipse Equinox. Every Eclipse plugin is an OSGi bundle. The OSGi specification defines, among other things, versioning and dependency resolution mechanisms. In addition to these standard mechanisms, Equinox introduces the concept extension points. Each plugin can define its own extension points, as well as add additional functionality (“extensions”) to the system using extension points defined by the same or other plugins. Any detailed description of the OSGi and Equinox mechanisms is beyond the scope of this article. We only note that modularization in Eclipse is total (any subsystem, including the Runtime, consists of one or more plugins), and almost everything in Eclipse is an extension. Moreover, these principles were incorporated into the Eclipse architecture long before the introduction of OSGi (at that time, their own technology was used, in many respects similar to OSGi).

core workspace

Almost any IDE built on top of the Eclipse Platform works with the Eclipse workspace. It is the workspace that usually contains the source code of the application being developed in the IDE. Workspace maps directly to the file system and consists of projects that contain folders and files. These projects, folders, and files are called the resources workspace. The implementation of workspace in Eclipse serves as a cache in relation to the file system, which can significantly speed up resource tree traversal. In addition, workspace provides a number of additional services, including resource change notification mechanism и incremental builder infrastructure.

The Core Resources component (org.eclipse.core.resources plugin) is responsible for supporting the workspace and its resources. In particular, this component provides programmatic access to the workspace in the form resource models. To work effectively with this model, clients need a simple way to represent a link to a resource. At the same time, it would be desirable to hide the object that directly stores the state of the resource in the model from client access. Otherwise, in the case of, for example, deleting a file, the client could continue to hold an object that is no longer in the model, with the ensuing problems. Eclipse solves this problem using the so-called handle resource. Handle acts as a key (it only knows the path to the resource in the workspace) and completely controls access to the internal model object, which directly stores information about the state of the resource. This design is a variation of the pattern Handle/Body.

Rice. 2 illustrates the Handle/Body idiom as applied to a resource model. The IResource interface represents the handle of a resource and is an API, unlike the Resource class that implements this interface, and the ResourceInfo class that represents body, which are not APIs. We emphasize that handle only knows the path to the resource relative to the workspace root and does not contain a link to resource info. Resource info objects form what is known as an "element tree". This data structure is fully materialized in memory. To find a resource info instance corresponding to some handle, the element tree is traversed according to the path stored in that handle.

Eclipse as a technology platform for 1C:Enterprise Development Tools
Rice. 2. IResource and ResourceInfo

As we will see later, the basic design of the resource model (you can call it handle-based) is used in Eclipse and for other models. In the meantime, here are some of the distinguishing features of this design:

  • Handle is a value object. Value objects are immutable objects whose equality is not based on identity. Such objects can be safely used as a key in hashed containers. Multiple instances of handle can refer to the same resource. To compare them, use the equals(Object) method.
  • Handle defines the behavior of the resource, but does not contain information about the state of the resource (the only data it stores is the "key", the path to the resource).
  • Handle can refer to a resource that does not exist (either a resource that has not yet been created, or a resource that has already been deleted). The existence of a resource can be checked using the IResource.exists() method.
  • Some operations can be implemented based solely on the information stored in the handle itself (the so-called handle-only operations). Examples are IResource.getParent(), getFullPath(), etc. The resource does not need to exist for such an operation to succeed. Operations that require the resource to exist in order to succeed throw an exception (CoreException) if the resource does not exist.

Eclipse provides an efficient mechanism for notifying changes to workspace resources (Figure 3). Resources can change both as a result of actions performed in the Eclipse IDE itself, and as a result of synchronization with the file system. In both cases, customers who subscribe to the notifications are provided with detailed information about the changes in the form of "resource deltas" (resource delta). A delta describes changes between two states of a workspace resource (sub-)tree and is itself a tree, each node of which describes a change to some resource and contains a list of next-level deltas that describe changes to child resources.

Eclipse as a technology platform for 1C:Enterprise Development Tools
Rice. 3. IResourceChangeEvent and IResourceDelta

The notification mechanism based on resource deltas has the following characteristics:

  • A single change and a lot of changes are described using the same structure, since the delta is built according to the principle of recursive composition. Subscriber clients can process resource change notifications by recursively descending the delta tree.
  • The delta contains complete information about the change of the resource, including its movement and/or change of the "markers" associated with it (markers represent, for example, compilation errors).
  • Because resource references are made through the handle, the delta can naturally refer to a remote resource.

As we will see shortly, the main design elements of the resource model change notification mechanism are relevant for other handle-based models as well.

JDT Core

The Eclipse workspace resource model is a fundamental language-independent model. The JDT Core component (org.eclipse.jdt.core plugin) provides an API for navigating and analyzing the workspace structure from a Java perspective, the so-called "Java model" (java model). This API is defined in terms of Java elements, as opposed to the underlying resource model API, which is defined in terms of folders and files. The main interfaces of the Java element tree are shown in Fig. 4.

Eclipse as a technology platform for 1C:Enterprise Development Tools
Rice. 4. Java Model Elements

The Java model uses the same handle/body idiom as the resource model (Figure 5). IJavaElement is the handle and JavaElementInfo is the body. The IJavaElement interface defines a protocol common to all Java elements. Some of its methods are handle-only: getElementName(), getParent(), and so on. The JavaElementInfo object stores the state of the corresponding element: its structure and attributes.

Eclipse as a technology platform for 1C:Enterprise Development Tools
Rice. 5. IJavaElement and JavaElementInfo

The Java model has some differences in the implementation of the basic handle/body design compared to the resource model. As noted above, in a resource model, an element tree whose nodes are resource info objects is entirely contained in memory. But a Java model can have a much larger number of elements than a resource tree, because it also contains the internal structure of .java and .class files: types, fields, and methods.

To avoid completely materializing the entire element tree in memory, the Java model implementation uses a size-limited element info LRU cache, where the key is handle IJavaElement. Element info objects are created on demand as the element tree is navigated. In this case, the least frequently used elements are evicted from the cache, and the memory consumption of the model remains limited by the specified cache size. This is another advantage of handle-based design, which completely hides such implementation details from client code.

The mechanism for notifying changes to Java elements is broadly similar to the mechanism for tracking workspace resource changes discussed above. A client that wants to track changes in the Java model subscribes to notifications, which are represented as an ElementChangedEvent object that contains an IJavaElementDelta (Figure 6).

Eclipse as a technology platform for 1C:Enterprise Development Tools
Rice. 6.ElementChangedEvent and IJavaElementDelta

The Java model does not contain information about the body of methods or name resolution, so for a detailed analysis of code written in Java, JDT Core provides an additional (non-handle-based) model: abstract syntax tree (abstract syntax tree, AST). AST represents the result of parsing the original text. AST nodes correspond to source module structure elements (declarations, operators, expressions, etc.) and contain information about the coordinates of the corresponding element in the source text, as well as (optionally) name resolution information in the form of links to so-called bindings. Bindings are objects that represent named entities such as types, methods, and variables known to the compiler. Unlike AST nodes that form a tree, bindings support cross-references and generally form a graph. The abstract class ASTNode is the common base class for all AST nodes. Subclasses of ASTNode correspond to certain syntax constructs of the Java language.

Because syntax trees can consume a significant amount of memory, the JDT caches only one AST, per active editor. Unlike the Java model, the AST is generally viewed as an "intermediate", "temporary" model whose elements should not be retained by clients outside the context of the operation that created the AST.

These three models (Java model, AST, bindings) together form the basis for building “intelligent development tools” in JDT, including a powerful Java editor with various “helpers”, various actions for processing source code (including organizing a name import list and formatting according to the customized style), search and refactoring tools. In this case, the Java model plays a special role, since it is it that is used as the basis for the visual representation of the structure of the developed application (for example, in the Package Explorer, Outline, Search, Call Hierarchy, and Type Hierarchy).

Eclipse components used in 1C:Enterprise Developments Tools

On fig. Figure 7 shows the Eclipse components that form the foundation of the technology platform for 1C:Enterprise Development Tools.

Eclipse as a technology platform for 1C:Enterprise Development Tools
Rice. 7. Eclipse as a platform for 1C:Enterprise Development Tools

Eclipse Platform provides the basic infrastructure. We covered some aspects of this infrastructure in the previous section.

Eclipse Modeling Framework (EMF) provides a general framework for modeling structured data. EMF is integrated with the Eclipse Platform, but can also be used standalone in regular Java applications. Quite often, novice Eclipse developers are already quite familiar with EMF, although they do not yet fully understand the intricacies of the Eclipse Platform. One of the reasons for such well-deserved popularity is the universal design, which includes, among other things, a unified meta-level API, which allows you to work with any EMF model in general. The base implementations provided by EMF for model objects and the subsystem for generating model code from the meta-model significantly increase the speed of development and reduce the number of errors. EMF also contains mechanisms for serializing models, tracking changes in the model, and much more.

Like any truly versatile tool, EMF is suitable for a wide range of modeling tasks, but some classes of models (for example, the handle-based models discussed above) may need more specialized modeling tools. Talking about EMF is a thankless task, especially within the limited framework of one article, since this is the subject of a separate book, and quite a thick one. We only note that the qualitative system of generalizations underlying the EMF allowed the birth of a whole range of modeling projects that are included in the top-level project Eclipse Modeling along with the EMF itself. One such project is Eclipse Xtext.

Eclipse Xtext provides a "text modeling" infrastructure. Xtext uses ANTLR for parsing the source text and EMF to represent the resulting ASG (abstract semantic graph, which, in fact, is a combination of AST and bindings), also called the "semantic model". The grammar of a language modeled with Xtext is described in Xtext's native language. This allows not only to generate a grammar description for ANTLR, but also to get the AST serialization mechanism (i.e. Xtext provides both parser and unparser), context hint, and a number of other language components. On the other hand, the grammar description language used in Xtext is less flexible than, say, the grammar description language in ANTLR. Therefore, sometimes it is necessary to “bend” the implemented language to Xtext, which is usually not a problem when it comes to a language developed from scratch, but may be unacceptable for languages ​​with an already established syntax. Despite this, Xtext is currently the most mature, feature-rich, and versatile tool in Eclipse for building programming languages ​​and development tools for them. In particular, it is an ideal tool for rapid prototyping. domain-specific languages (domain-specific language, DSL). In addition to the ANTLR and EMF-based “language core” mentioned above, Xtext provides many useful higher-level components, including indexing mechanisms, incremental building, a “smart editor”, and much, much more, but leaves out the handle-based language models. Like EMF, Xtext is a subject worthy of a separate book, and we can hardly even briefly describe all its capabilities now.

1C:Enterprise Development Tools actively use both EMF itself and a number of other Eclipse Modeling projects. In particular, Xtext is one of the foundations of development tools for such 1C:Enterprise languages ​​as the built-in programming language and query language. Another basis for these development tools is the Eclipse Handly project, which we will dwell on in more detail (of the Eclipse components listed, it is still the least known).

Eclipse Handy, a sub-project of the Eclipse Technology high-level project, emerged from an initial code contribution to the Eclipse Foundation by 1C in 2014. Since then, 1C continues to support the development of the project: Handly committers are employees of the company. The project is small, but it occupies a fairly unique niche in Eclipse: its main goal is to support the development of handle-based models.

The basic architectural principles of handle-based models, such as the handle/body idiom, were discussed above using the resource model and the Java model as an example. It also noted that both the resource model and the Java model are important foundations for the Eclipse Java development tools (JDT). And since almost all Eclipse *DT projects have an architecture similar to JDT, it would not be a big exaggeration to say that handle-based models underlie many, if not all IDEs built on top of the Eclipse Platform. For example, Eclipse C/C++ Development Tooling (CDT) has a handle-based C/C++ model that plays the same role in the CDT architecture as the Java model does in the JDT.

Prior to Handly, Eclipse did not offer specialized libraries for building handle-based language models. Models that exist today were created mainly by directly adapting the Java model code (aka copy/paste), in cases where it allows Eclipse Public License (EPL). (Obviously, for, say, Eclipse's own projects, this is usually not a legal issue, which is not the case for closed source products.) In addition to its characteristic haphazardness, this technique leads to well-known problems: code duplication introduced by when adapting to mistakes, etc. Even worse, the resulting models remain "things in themselves" and do not use the existing potential for unification. But the allocation of common concepts and protocols for language handle-based models could lead to the creation of reusable components for working with them, similar to what happened in the case of EMF.

This is not to say that Eclipse did not have an understanding of these problems. Back in 2005 Martin Aeschlimann, summarizing the experience of developing a CDT prototype, argued the need to create a common infrastructure for language models, including handle-based models. But, as it often happens, due to higher priority tasks, the implementation of these ideas did not reach the hands then. Meanwhile, code factorization of *DT projects is still one of the underdeveloped topics in Eclipse.

In a certain sense, the Handly project is designed to solve approximately the same tasks as EMF, but for handle-based models, and primarily language ones (that is, representing elements of the structure of a programming language). The following are the main design goals for Handly:

  • Isolation of the main abstractions of the subject area.
  • Reducing the effort and improving the quality of the implementation of language handle-based models through code reuse.
  • Providing a unified meta-level API to the resulting models, making it possible to create common IDE components that work with language handle-based models.
  • Flexibility and scalability.
  • Integration with Xtext (in a separate layer).

To highlight common concepts and protocols, the existing implementations of language handle-based models were analyzed. The main interfaces and base implementations provided by Handly are shown in Figure 8-XNUMX. XNUMX.

Eclipse as a technology platform for 1C:Enterprise Development Tools
Rice. 8. Common interfaces and basic implementations of Handly elements

The IElement interface represents the handle of an element and is common to elements of all Handly-based models. The abstract class Element implements a generic handle/body mechanism (Figure 9).

Eclipse as a technology platform for 1C:Enterprise Development Tools
Rice. 9. IElement and generic implementation of handle/body

In addition, Handly provides a generalized notification mechanism for changing model elements (Fig. 10). As you can see, in general terms, it is similar to the notification mechanisms implemented in the resource model and the Java model, and uses IElementDelta to provide a unified representation of element change information.

Eclipse as a technology platform for 1C:Enterprise Development Tools
Rice. 10. Common interfaces and basic implementations of the Handly notification mechanism

The part of Handly considered above (Fig. 9 and 10) can be used to represent almost any handle-based models. For creating linguistic models, the project offers additional functionality - in particular, common interfaces and base implementations for source text structure elements, the so-called source elements (Fig. 8). The ISourceFile interface represents a source file, and ISourceConstruct represents an element within the source file. The abstract classes SourceFile and SourceConstruct implement generic mechanisms to support working with source files and their elements, for example, working with text buffers, binding to element coordinates in the source text, reconciling the model with the current contents of the working copy buffer, etc. Implementing these mechanisms is usually quite a challenge, and Handly can significantly reduce the effort of developing handle-based language models by providing quality base implementations.

In addition to the core mechanisms listed above, Handly provides a text buffer and snapshot infrastructure, support for integration with source code editors (including out-of-the-box integration with the Xtext editor), as well as some common UI components that work with Handly models such as the outline framework. To illustrate its capabilities, the project provides several examples, including the implementation of the Java model on Handly. (Compared to the full implementation of the Java model in the JDT, this model is intentionally somewhat simplified for better clarity.)

As noted earlier, Handly's initial design and development was and continues to be heavily focused on scalability and flexibility.

In principle, handle-based models scale well “by design”. For example, the handle/body idiom allows you to limit the amount of memory consumed by the model. But there are also nuances. So, when testing Handly for scalability, a problem was found in the implementation of the notification mechanism - when changing a large number of elements, building deltas took too much time. It turned out that the same problem is present in the Java JDT model, from which the corresponding code was adapted at one time. We fixed a bug in Handly and prepared a similar patch for JDT, which was gratefully received. This is just one example where implementing Handly into existing model implementations could be potentially beneficial, as it would be possible to fix such a bug in just one place.

To make embedding Handly into existing model implementations technically feasible, the library must be highly flexible. The main problem is to maintain backward compatibility with the model API. This problem was solved in Handy 0.5 by clearly separating the model-specific API, defined and fully controlled by the developer, from the unified meta-level API provided by the library. This not only makes it technically possible to implement Handly into existing implementations, but also gives the developer of the new model a lot of freedom in API design.

Flexibility has other aspects as well. For example, Handly imposes almost no restrictions on the structure of the model and can be used to model general-purpose languages ​​as well as domain-specific languages. When constructing the source file structure, Handly does not prescribe any particular form of AST representation and in principle does not even require the presence of an AST itself, thus ensuring compatibility with almost any parsing mechanism. Finally, Handly supports full integration with the Eclipse workspace, but can also work directly with file systems thanks to its integration with Eclipse File System (EFS).

Current version Handy 0.6 released in December 2016. Despite the fact that the project is currently in a state of incubation and the API has not yet been finally fixed, Handly is already used in two large commercial products that have ventured into the role of "early adopters" and, I must say, do not regret it yet.

As noted above, one of these products is 1C:Enterprise Development Tools, where Handly is used from the very beginning to model elements of the high-level structure of such 1C:Enterprise languages ​​as an embedded programming language and a query language. Another product is less known to the general public. This Codasip Studio, an integrated design environment for problem-oriented processors (application-specific instruction-set processor, ASIP), used both within the Czech company Codasip itself and by its customers, including AMD, AVG, Mobileye, Sigma Designs. Codasip has been using Handly in production since 2015, starting with Handly 0.2. The latest release of Codasip Studio currently uses version 0.5 released in June 2016. Ondřej Ilčík, who leads the development of the IDE at Codasip, is in contact with the project, providing critical feedback on behalf of the "third party adopter". He was even able to find some free time to directly contribute to the development of the project by implementing a UI layer (~4000 lines of code) for one of the Handly examples, a Java model. For more first-hand information about the use of Handly by adapters, see Success Stories the project.

We hope that after the release of version 1.0 with a guarantee of API stability and the exit of the project from the state of incubation, Handly will also have new adopters. In the meantime, the project continues to test and refine the API further, with two "big" releases per year, in June (the same date as the concurrent Eclipse release) and December, providing a predictable schedule that adopters can rely on. We can also add that the “bug rate” of the project remains at a consistently low level and Handly has been working reliably in the products of early adopters since the very first versions. For further familiarity with Eclipse Handly, you can use Getting Started Tutorial и Architectural Overview.

Source: habr.com

Add a comment