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