Skip navigation

That title sounds bizarre, did you just throw lots of techy words into it for keyword effect?

Could have done but actually its accurate to what I've been doing for the last week or so.

 

So, what are you talking about?

In Komodo, and Teiid Designer, we have developed an eclipse plugin that will connect to all versions of Teiid going back to 7.7.x. This plugin takes the changes from each new version of the Teiid codebase's client and unifies them in one plugin. Some differences are very minor while others can be quite large or detailed. Consequently, it is often not enough to just assume that, because it was Teiid code, it will naturally still work. Therefore, I have ported over Teiid's unit tests as well.

 

Interesting! That explains the 'Unit Testing' but pretty standard stuff really... Oh and what's this Arquillian?

Initially, the unit tests have been standard stuff. Looking at the teiid client test plugin in Designer, it aims to test as many teiid client versions as possible but all the tests use junit 4, are located in a fragment and only test individual portions of the client code such as the parser. While important, a connection to a jboss server with installed Teiid instance was never tested. The main reason for this is because that use-case moves into the area of integration testing.

 

The Teiid project already does integration testing and this is where Arquillian is introduced. Essentially, the Arquillian project satisfies the very problem of client/server integration testing by constructing an on-the-fly container for a test hence no need for leaving servers running just for testing purposes. Teiid already uses it in their integration tests so it made sense for Komodo to start using it too.

 

So quick configuration and off we go?

Not quite... Immediately there appeared a couple of hitches with Arquillian in an Eclipse plugin world.

 

  1. Teiid uses standard java projects rather than Eclipse plugins. All dependent libraries are determined by the <dependencies> tag in its maven pom file. Concepts such as Bundles and Context Loaders are just not factors that have to be considered.
  2. Arquillian has been developed with Maven as the central building tool of any java project. This make a lot of sense when one observes the number of libraries it needs to get a container (server instance) up and running for a set of integration tests. However, this leads to the pom file being central for determining the dependencies whereas a plugin tends to prefer its manifest being paramount. In order to build plugins with Maven, Tycho was introduced preserving the power of the Maven's building with a manifest-first approach to dependencies.

 

Hmm ... sounds hard and complex. Give up?

Well no! The dividends of being able to start up a jboss server on the fly, fully configured to the test's own configuration then blow it away is definitely worth a bit of 'hard and complex'.

 

Okay! Just tell me how you did it already

Well there are 2 distinct ways of doing it with the first being limited to a non-Tycho environment. Since this was limited and not ultimately used, I'll spin over it rather quickly but the code is here for your own perusal. Essentially, I did the following:

  1. Created a Maven/m2e project in Eclipse for use with Arquillian in the same manner as described in the project's 'Getting Started' Guide;
  2. With that done, none of the Teiid client classes could be compiled since the project was not a plugin and there existed no manifest. Therefore, the project was converted from a pure maven project to a plugin project using Eclipse's Configure->Convert to Plugin function. This adds a few more natures to the project's .project file:

 

<natures>
  <nature>org.eclipse.m2e.core.maven2Nature</nature>
  <nature>org.eclipse.jdt.core.javanature</nature>
  <nature>org.maven.ide.eclipse.maven2Nature</nature>
  <nature>org.hibernate.eclipse.console.hibernateNature</nature>
  <nature>org.jboss.tools.jst.web.kb.kbnature</nature>
  <nature>org.jboss.tools.cdi.core.cdinature</nature>
  <nature>org.eclipse.pde.PluginNature</nature>
</natures>


  1. By further converting the test plugin into a fragment, its possible for the project to 'see' both maven dependencies, ie. Arquillian's, and the test plugin manifest dependencies at the same time.
  2. Ultimately, this hybrid test fragment could successfully execute tests as Eclipse 'JUnit Tests'. However, (and here is the limitation) the fragment could not execute tests as Eclipse 'JUnit Plugin Tests' running the tests in a newly loaded Eclipse IDE test environment. The reason being is that Eclipse could not find the maven dependencies, ie. lots of Arquillian-related errors. Likewise, using Tycho in the pom and building/testing on the command line failed as well for the same reason. When the project's pom sets the packaging configuration to 'eclipse-plugin' or 'eclipse-test-plugin' (rather than jar) then Tycho ignores all non-plugin dependencies hence does not know how to compile anything from Arquillian.

 

So at this point, it is looking bleak...

 

Basically, the test fragment wants to use a manifest approach and Arquillian wants to use maven dependencies. Thankfully, a concept long used in Designer came to the rescue.

 

Often a plugin in Designer has required the use of a library that has never been wrapped in an Eclipse plugin but exists as a versioned jar in Maven's repositories. Eclipse can allow it to be used but the only way requires the jar to be downloaded to a lib/ directory in the plugin and a classpath reference added to the plugin's manifest. This is fine except that a binary file is now in the codebase and annoyingly changing to a new version of that jar would require physical replacement in the codebase. To solve this requires a little ant, maven and Eclipse's external tool builder...

 

  • Eclipse's external tool builder executes an ant script (or some other tool) when a build (or clean) is executed. It can do anything that's possible in ant. For example, it can fork a maven build process;
  • Maven contains the maven-dependencies:copy-plugin which copies dependencies outlined in a pom file to a configured destination. Thus, it is possible to create a pom file which essentially downloads all the Arquillian libraries to a local maven repository then copies them to a lib/ directory in the Eclipse plugin, as shown h

That title sounds bizarre, did you just throw lots of techy words into it for keyword effect?

Could have done but actually its accurate to what I've been doing for the last week or so.

 

So, what are you talking about?

In Komodo, and Teiid Designer, we have developed an eclipse plugin that will connect to all versions of Teiid going back to 7.7.x. This plugin takes the changes from each new version of the Teiid codebase's client and unifies them in one plugin. Some differences are very minor while others can be quite large or detailed. Consequently, it is often not enough to just assume that, because it was Teiid code, it will naturally still work. Therefore, I have ported over Teiid's unit tests as well.

 

Interesting! That explains the 'Unit Testing' but pretty standard stuff really... Oh and what's this Arquillian?

Initially, the unit tests have been standard stuff. Looking at the teiid client test plugin in Designer, it aims to test as many teiid client versions as possible but all the tests use junit 4, are located in a fragment and only test individual portions of the client code such as the parser. While important, a connection to a jboss server with installed Teiid instance was never tested. The main reason for this is because that use-case moves into the area of integration testing.

 

The Teiid project already does integration testing and this is where Arquillian is introduced. Essentially, the Arquillian project satisfies the very problem of client/server integration testing by constructing an on-the-fly container for a test hence no need for leaving servers running just for testing purposes. Teiid already uses it in their integration tests so it made sense for Komodo to start using it too.

 

So quick configuration and off we go?

Not quite... Immediately there appeared a couple of hitches with Arquillian in an Eclipse plugin world.

 

  1. Teiid uses standard java projects rather than Eclipse plugins. All dependent libraries are determined by the <dependencies> tag in its maven pom file. Concepts such as Bundles and Context Loaders are just not factors that have to be considered.
  2. Arquillian has been developed with Maven as the central building tool of any java project. This make a lot of sense when one observes the number of libraries it needs to get a container (server instance) up and running for a set of integration tests. However, this leads to the pom file being central for determining the dependencies whereas a plugin tends to prefer its manifest being paramount. In order to build plugins with Maven, Tycho was introduced preserving the power of the Maven's building with a manifest-first approach to dependencies.

 

Hmm ... sounds hard and complex. Give up?

Well no! The dividends of being able to start up a jboss server on the fly, fully configured to the test's own configuration then blow it away is definitely worth a bit of 'hard and complex'.

 

Okay! Just tell me how you did it already

Well there are 2 distinct ways of doing it with the first being limited to a non-Tycho environment. Since this was limited and not ultimately used, I'll spin over it rather quickly but the code is here for your own perusal. Essentially, I did the following:

  1. Created a Maven/m2e project in Eclipse for use with Arquillian in the same manner as described in the project's 'Getting Started' Guide;
  2. With that done, none of the Teiid client classes could be compiled since the project was not a plugin and there existed no manifest. Therefore, the project was converted from a pure maven project to a plugin project using Eclipse's Configure->Convert to Plugin function. This adds a few more natures to the project's .project file:

 

<natures>

  <nature>org.eclipse.m2e.core.maven2Nature</nature>

  <nature>org.eclipse.jdt.core.javanature</nature>

  <nature>org.maven.ide.eclipse.maven2Nature</nature>

  <nature>org.hibernate.eclipse.console.hibernateNature</nature>

  <nature>org.jboss.tools.jst.web.kb.kbnature</nature>

  <nature>org.jboss.tools.cdi.core.cdinature</nature>

  <nature>org.eclipse.pde.PluginNature</nature>

</natures>

  1. By further converting the test plugin into a fragment, its possible for the project to 'see' both maven dependencies, ie. Arquillian's, and the test plugin manifest dependencies at the same time.
  2. Ultimately, this hybrid test fragment could successfully execute tests as Eclipse 'JUnit Tests'. However, (and here is the limitation) the fragment could not execute tests as Eclipse 'JUnit Plugin Tests' running the tests in a newly loaded Eclipse IDE test environment. The reason being is that Eclipse could not find the maven dependencies, ie. lots of Arquillian-related errors. Likewise, using Tycho in the pom and building/testing on the command line failed as well for the same reason. When the project's pom sets the packaging configuration to 'eclipse-plugin' or 'eclipse-test-plugin' (rather than jar) then Tycho ignores all non-plugin dependencies hence does not know how to compile anything from Arquillian.

 

So at this point, it is looking bleak...

 

Basically, the test fragment wants to use a manifest approach and Arquillian wants to use maven dependencies. Thankfully, a concept long used in Designer came to the rescue.

 

Often a plugin in Designer has required the use of a library that has never been wrapped in an Eclipse plugin but exists as a versioned jar in Maven's repositories. Eclipse can allow it to be used but the only way requires the jar to be downloaded to a lib/ directory in the plugin and a classpath reference added to the plugin's manifest. This is fine except that a binary file is now in the codebase and annoyingly changing to a new version of that jar would require physical replacement in the codebase. To solve this requires a little ant, maven and Eclipse's external tool builder...

 

  • Eclipse's external tool builder executes an ant script (or some other tool) when a build (or clean) is executed. It can do anything that's possible in ant. For example, it can fork a maven build process;
  • Maven contains the maven-dependencies:copy-plugin which copies dependencies outlined in a pom file to a configured destination. Thus, it is possible to create a pom file which essentially downloads all the Arquillian libraries to a local maven repository then copies them to a lib/ directory in the Eclipse plugin, as shown here in the finished test plugin;
  • An ant build script in the plugin bridges Maven and Eclipse build systems. It is executed via an external tool builder and is responsible for calling Maven via a forked process which then copies in the dependencies. The ant script for the test plugin is here while its parent ant script, responsible for actually calling the mvn process is here.

 

This meant that both an Eclipse IDE build and a Maven/Tycho build could both run Arquillian-based tests on the teiid client test fragment and its host plugin. All library dependencies could be found correctly and all the tests would go green!

 

There's another slight problem isn't there?

Yes there was. The Arquillian jboss container implementation requires the environment variable JBOSS_HOME to be set to point to the location of the jboss runtime. Without the an error would be generated in the junit log indicating that 'jbossHome could not be null'. However, specifying such an environment variable would require creating a .launch configuration file in the test plugin and that just seemed a little wrong. Teiid avoids this problem since such configuration properties could be set in the pom file and then picked up by Maven but this is not sufficient when running as plugin tests in Eclipse.

Thankfully, Arquillian also allows this property to be configured using an 'arquillian.xml' file that can be added to the root of the plugin's source, ie. not inside any package. This also works for fragments with the proviso in both situations that it must be added to the build.properties file of the plugin. Seems obvious I know, but not realising straight-away cost 2 hours of debugging!

 

So you now have an Eclipse Fragment testing an Eclipse plugin's ability to connect to an Arquillian-created jboss server installed with a version of Teiid?

That's right. It may not be the most common use-case for Arquillian but does mean that Eclipse plugins are able to perform integration testing against different Arquillian server containers without needing to configure separate external servers.

 

Any footnotes or post-scripts?

As an experiment I tried generalising the arquillian libraries into their own plugin. As soon as I had configured it and executed, everything broke again since it could not see the library plugin could not find the arquillian.xml file resulting in the 'jbossHome was null' error. However, it was possible to workaround this:

  1. Set the Eclipse-BuddyPolicy attribute in the manifest of the library plugin to 'registered';
  2. Add the Eclipse-RegisterBuddy attribute in the test fragment's manifest to the bundle symbolic name of the library plugin;
  3. Convert the test fragment back to a plugin. This is annoying but necessary since the registered buddy-policy in Eclipse does not seem to work for fragments as the wiring attributes are gleaned from the host plugin rather than the fragment. Consequently, the Eclipse-RegisterBuddy attribute either needs to be in the host plugin or the test fragment must be converted to a plugin.
  4. Tests executed successfully. I was going to use the plugin configuration going-forward but the limitation of changing to a plugin and having to export certain packages of the host plugin just made the experiment a little tarnished IMHO.

 

Hope that helps.

 

back to code...


PGR

  • ere in the finished test plugin;
  • An ant build script in the plugin bridges Maven and Eclipse build systems. It is executed via an external tool builder and is responsible for calling Maven via a forked process which then copies in the dependencies. The ant script for the test plugin is here while its parent ant script, responsible for actually calling the mvn process is here.

 

This meant that both an Eclipse IDE build and a Maven/Tycho build could both run Arquillian-based tests on the teiid client test fragment and its host plugin. All library dependencies could be found correctly and all the tests would go green!

 

There's another slight problem isn't there?

Yes there was. The Arquillian jboss container implementation requires the environment variable JBOSS_HOME to be set to point to the location of the jboss runtime. Without the an error would be generated in the junit log indicating that 'jbossHome could not be null'. However, specifying such an environment variable would require creating a .launch configuration file in the test plugin and that just seemed a little wrong. Teiid avoids this problem since such configuration properties could be set in the pom file and then picked up by Maven but this is not sufficient when running as plugin tests in Eclipse.

Thankfully, Arquillian also allows this property to be configured using an 'arquillian.xml' file that can be added to the root of the plugin's source, ie. not inside any package. This also works for fragments with the proviso in both situations that it must be added to the build.properties file of the plugin. Seems obvious I know, but not realising straight-away cost 2 hours of debugging!

 

So you now have an Eclipse Fragment testing an Eclipse plugin's ability to connect to an Arquillian-created jboss server installed with a version of Teiid?

That's right. It may not be the most common use-case for Arquillian but does mean that Eclipse plugins are able to perform integration testing against different Arquillian server containers without needing to configure separate external servers.

 

Any footnotes or post-scripts?

As an experiment I tried generalising the arquillian libraries into their own plugin. As soon as I had configured it and executed, everything broke again since it could not see the library plugin could not find the arquillian.xml file resulting in the 'jbossHome was null' error. However, it was possible to workaround this:

  1. Set the Eclipse-BuddyPolicy attribute in the manifest of the library plugin to 'registered';
  2. Add the Eclipse-RegisterBuddy attribute in the test fragment's manifest to the bundle symbolic name of the library plugin;
  3. Convert the test fragment back to a plugin. This is annoying but necessary since the registered buddy-policy in Eclipse does not seem to work for fragments as the wiring attributes are gleaned from the host plugin rather than the fragment. Consequently, the Eclipse-RegisterBuddy attribute either needs to be in the host plugin or the test fragment must be converted to a plugin.
  4. Tests executed successfully. I was going to use the plugin configuration going-forward but the limitation of changing to a plugin and having to export certain packages of the host plugin just made the experiment a little tarnished IMHO.

 

Hope that helps.

 

back to code...


PGR

Well finally its done!

 

Everyone please welcome into the world org.teiid.runtime.client.

 

Architecture of the plugin

     The same framework is used for accessing the client from the rest of Designer as was previously the case with the deprecated client plugins. Namely, an extension point provides an implementation of Designer's org.teiid.designer.runtime.spi.IExecutionAdminFactory. Thus, changes to Designer's architecture has been minimised with the new plugin becoming largely a drop-in replacement.

 

     That's said, there have been changes to this interface's API methods in that they all require either an ITeiidServer or ITeiidServerVersion as a parameter. This allows the ExecutionAdminFactory implementation to know the Teiid version of the instance being connected to. With this knowledge, the single implementation is able to decide how sql is parsed, what data types are available etc...

 

Handling multiple versions

For a single implementation able to cope with different versions of Teiid, it has been necessary to take the original Teiid client and retrofit it with a framework that determines results based on a given Teiid version.

 

Annotations have been introduced for providing version metadata for classes, fields and methods. For example, where a new data type has been added in a new Teiid version, this field has been added to the client but with a @Since annotation that describes the first version of Teiid where it appeared. The annotation is then read by any code making use of the field and if the version of Teiid is earlier than the annotation's then the field is ignored. Likewise, a @Removed annotation does the opposite, ie. where a field has been removed in a later version of Teiid then this is left in the client code and its annotation observed by any calling code. An example of using these annotations is the DataTypeManagerService, which replaces Teiid's original DataTypeManager:

 

public enum DefaultDataTypes {

        STRING ("string", DataTypeName.STRING, String.class, 256, DataTypeAliases.VARCHAR), //$NON-NLS-1$
        ....
        CLOB ("clob", DataTypeName.CLOB, ClobType.class),
        XML ("xml", DataTypeName.XML, XMLType.class),
        @Since(Version.TEIID_8_0)
        VARBINARY ("varbinary", DataTypeName.VARBINARY, BinaryType.class);
}


The enum value VARBINARY was introduced in Teiid 8.0 hence it has an annotation to this effect. Instead of client code using DefaultDataTypes.values() to get the contents of this enum, a new static method getValues(ITeiidServerVersion) is used instead:

 

public static List<DefaultDataTypes> getValues(ITeiidServerVersion teiidVersion) {
     List<DefaultDataTypes> appDataTypes = valueCache.get(teiidVersion);
     if (appDataTypes == null) {
          appDataTypes = new ArrayList<DefaultDataTypes>();
          for (DefaultDataTypes dataType : DefaultDataTypes.values()) {
               if (! AnnotationUtils.isApplicable(dataType, teiidVersion))
                    continue;
               appDataTypes.add(dataType);
          }

          valueCache.put(teiidVersion, appDataTypes);
     }

     return appDataTypes;
}


The getValues() method uses the AnnotationUtils class to test the applicability of each data type in the enum and returns only those that are applicable to the given Teiid instance version.

 

     The QueryParser employs a couple of different techniques for achieving the same result. Teiid's parser wraps an implementation called SQLParser, which is generated from a javacc template. The single plugin takes the template as the foundation of its own TeiidParser implementation that is wrapped by the QueryParser. However, it was recognised early on that the parser templates for Teiid versions 7 and 8 were so fundamentally different that both have been included in the client and the QueryParser creates an instance of one or the other given the version of Teiid.

 

     Beginning with the version 8 template, caveats have been placed in the code that requires a certain version of Teiid in order for the language syntax to be parsed acceptable. As such the following method is used extensively:

 

private void requiresVersionAtLeast(Version version) throws ParseException {
     if (! versionAtLeast(version))
          throw new ParseException(Messages.getString(
                Messages.TeiidParser.teiid_version_atleast_failure, version.get().toString(),
                                                                      getVersion().toString()));
}


The idea is that if syntax is used that belongs to a later Teiid version than the version the parser has been initialised against then a parse exception is the result.

 

Examples of 'testing version' methods proliferate the client implementation. For example, the LanguageVisitor class, which is extended by all client Visitor classes, requires a Teiid Version and provides convenience functions for testing against this version. The SQLStringVisitor, responsible for turning SQL text into java pojos, makes heavy use of these functions since different syntax was required for Teiid's 7 and 8.

 

So far so good!

 

Back to code...


PGR

Subsequent to my previous post, I was feeling really good about the teiid runtime client plugin. Having successfully created a QueryParser which constructs either a Teiid7Parser or a Teiid8Parser depending on a given TeiidServerVersion, one even purloined the Teiid unit tests in order to fully test-drive the parser and AST nodes. This was a great move given the number of bugs and omissions in the nodes.

 

Falling Down the Rabbit Hole!

After the parser, comes the SyntaxFactory (factory for creating AST Nodes in Designer). The inevitable conclusion of this is that the SyntaxFactory requires implementing the SPI interface ISyntaxFactory (otherwise Designer would have to have 768 problems to fix). One likes the SPI plugin given it has decoupled Designer's required interfaces from their implementations. Some of the interfaces are a little odd due to the use of generics but that has aided its decoupling and its flexibility. However, ISyntaxFactory demands that all of the AST nodes implement their respective interfaces, eg. Function implements IFunction. This has just been a laborious day-and-a-half of grunt-work. It could have been automated but doing it manually was of benefit in cleaning up some code.

 

One of the decisions taken a month or so back was to NOT depend on any Teiid library. One of the reasons was the DataTypeManager class which is used pervasively for dealing with types. This class added new types between versions 7.7 and 8.0 hence a fresh version was needed that could be decorated with annotations allowing for a TeiidServerVersion to dictate which types would be returned by a call from any other Designer/Teiid code. This seems quite a small thing but has become most fundamental to ensuring backward compatibility in a client able to understand the limitations of an older version over a newer one. Consequently, the plugin could not just depend on Teiid's Engine library as their internal DataTypeManager would get used by internal classes and the plugin would be back to square 1!

 

Turns out not depending on the Teiid library is potentially very beneficial from the perspective of really understanding what Teiid code is really required but at the same time inevitably involves porting over classes from the Teiid codebase and as one might expect one class tends to depend on another. For example, in resolving the Function AST node, a FunctionDescriptor field is initialised. In order to port over this field, it would require the FunctionMethod and FunctionParameter classes as well. Likewise, the QueryNode is going to require UpdateInfo which seems to require the UpdateValidator and a whole group of related scary classes. Am I just copying Teiid 1 class at a time?

 

Where Next?

The goal of this work was to construct a backward-compatible Teiid client that could parse, resolve and validate an SQL string. The parsing was the problem for current Teiid releases in that the parser just was never designed to be backward-compatible. That problem has at least a solution, while the resolver and validator are 'already backward-compatible' hence one should be able to plug straight into them? Well... not quite since the resolver takes a Command AST node created from the parser, one cannot just give Teiid's resolver any old AST node; it requires Teiid's version and again backward-compatibility disappears since a Teiid 8 Command has no idea what an HasCriteria node is anymore since that was only in Teiid 7.

 

The only possibility is to take the Resolver and its ancillary component classes and make them deal with the new parser's AST nodes. There seems little alternative?? ... still a bit of a break might shed some light on the subject!

 

Back to code ... (not before a little break!)


PGR

It has long been an issue in Designer that the development of the Teiid project has meant supporting multiple versions of Teiid when parsing, resolving and validating SQL transformations. At first, a single set of teiid client libraries was added to the Designer codebase, implying a 1-1 relationship with a version of Teiid. When Designer 8.1 came along, an attempt was made (by me) to support multiple versions of Teiid.

 

Broadly speaking, this has appeared to work (albeit a rather crude implementation). A user can choose a Teiid version synonymous with their Teiid instance and a default version is set in Designer. The user then has confidence that SQL validation in Designer has parity with what will happen on the . The whole idea being that the model validates in Designer and so will validate when deployed to Teiid.

 

The downside... (always is really!)

The development model used whereby the Teiid codebase is forked and a new submodule is generated in the Designer codebase is unsustainable. There are already 3 submodules (7.7, 8.3, 8.4)! Strictly speaking, 8.3 is unnecessary but at the time there was always some question over compatibility between Teiid 8.3 and 8.4 so for historical reasons it lives on.

 

With the advent of the next generation of Designer tool (codenamed Komodo), we wanna move totally away from submodules BUT we need a teiid client runtime that can still support multiple versions of Teiid. This is tricky since some objects in Teiid are backward-compatible, eg. the resolver, but other objects are not, eg. the parser, admin client (between 7 and 8). We need to support all of them.

 

So, what's the plan??

Jboss tools has the same issues in supporting multiple versions. One of that project's solutions is to provide generic interfaces and where objects have to differ, create internal version-specific implementations but present them under the one interface. Thus, one teiid-client-runtime plugin that is wholly backward-compatible between Teiid versions (back to 7.7.x) and where necessary implements v7, v8 ... objects that are used depending on a required Teiid version.

 

Simple really!

Indeed, but getting the framework up and running is a challenge and just getting 2 versions of the parser up to parity has taken quite an effort. Current work is maintained on my teiid-runtime branch (careful! I force push this branch with any work-in-progress so let me know if you pull from it).

 

Back to code...


PGR

The Teiid Designer team will be posting development comments here designed to aid in collaboration with each others' efforts as well as informing the community of development progress.

 

Feel free to follow along!

 

Back to code...

 

PGR