Check runtime allowed dynamic loading of check projects. In this chapter we describe the API used by dynamically pluggable checks.

Check catalog files within a check project generate code which is executed at run-time. One check catalog will result in half a dozen files being generated, whereas one of those represents the actual validator executed by the check run-time.

We explain the derived resources of a check catalog by example.

Assume we are about to write a Static Code Analysis library for our Format DSL. Here is a possible structure of an SCA plugin with one Check catalog.

Sample SCA project with one Check catalog
SCA Project with FormatConventions Check catalog

Example

In our example FormatConventions is an empty catalog

package com.avaloq.tools.xtext.format.sca

/**
 *  Check catalog for com.avaloq.tools.ddk.xtext.format.Format
 */
catalog FormatConventions

for grammar com.avaloq.tools.ddk.xtext.format.Format {

}

FormatConventionsQuickfixProvider.java

Check project wizard creates FormatConventionsQuickfixProvider is a stub for future Quck Fixes

package com.avaloq.tools.xtext.format.sca;

import com.avaloq.tools.ddk.check.runtime.quickfix.ICoreQuickfixProvider;

/**
 * Default quickfix provider for FormatConventions.
 * <p>
 * Note that this class name must start with the catalog name and have <em>QuickfixProvider</em>
 * as suffix. It must be located in the same Java package as the catalog file.
 * </p>
 */

public class FormatConventionsQuickfixProvider implements ICoreQuickfixProvider  {

//  @CoreFix(value = MyIssueCodes.NAME_ENTITY_0)
//  public void fixEntityNameFirstUpper(final Issue issue,
//      ICoreIssueResolutionAcceptor acceptor) {
//    acceptor.accept(issue, "Correct entity name",
//        "Correct name by setting first letter to upper case.",
//        null, new ICoreSemanticModification() {
//          public void apply(EObject element, ICoreModificationContext context) {
//            if (element instanceof Entity) {
//              final Entity entity = (Entity) element;
//              String newName = String.valueOf(entity.getName().charAt(0)).toUpperCase();
//              if (entity.getName().length() > 1) {
//                newName += entity.getName().substring(1, entity.getName().length());
//              }
//              entity.setName(newName);
//            }
//          }
//        });
//  }

}

As developers we only work with *.check and *QuickfixProvider.java files. The remainig glue code is generated by the DSL Developer Kit.

Activation in IDE via plugin.xml

Both FormatConventions catalog and FormatConventionsQuickfixProvider are registered using the generated plugin.xml.

<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
   <extension
         id="com.avaloq.tools.xtext.format.sca.formatconventions.validator"
         name="Check extension for FormatConventions"
         point="com.avaloq.tools.ddk.check.runtime.core.check">
      <validator
            catalog="com/avaloq/tools/xtext/format/sca/FormatConventions.check"
            language="com.avaloq.tools.ddk.xtext.format.Format"
            targetClass="com.avaloq.tools.xtext.format.sca.FormatConventionsCheckImpl">
      </validator>
   </extension>
   <extension
         id="com.avaloq.tools.xtext.format.sca.formatconventions.quickfix"
         name="Check quickfix extension for FormatConventions"
         point="com.avaloq.tools.ddk.check.runtime.core.checkquickfix">
      <provider
            language="com.avaloq.tools.ddk.xtext.format.Format"
            targetClass="com.avaloq.tools.xtext.format.sca.FormatConventionsQuickfixProvider">
      </provider>
   </extension>
   <extension
         id="com.avaloq.tools.xtext.format.sca.formatconventions.preference"
         name="Preferences extension for FormatConventions"
         point="org.eclipse.core.runtime.preferences">
      <initializer
            class="com.avaloq.tools.xtext.format.sca.FormatConventionsPreferenceInitializer">
      </initializer>
   </extension>
   <extension
         name="Context sensitive help for check"
         point="org.eclipse.help.contexts">
      <contexts
            file="docs/contexts.xml">
      </contexts>
   </extension>
   <extension
         name="Help extension for Check"
         point="org.eclipse.help.toc">
      <toc
            file="docs/toc.xml"
            primary="false">
      </toc>
   </extension>
</plugin>

Notice the important extension points used to contribute checks

  • com.avaloq.tools.ddk.check.runtime.core.check

  • com.avaloq.tools.ddk.check.runtime.core.checkquickfix

  • org.eclipse.core.runtime.preferences

Activation in standalone builder

For headless standalone builder Check catalog is also registered as a service for a non-OSGi environment.

Each check project has the following file

META-INF/services/com.avaloq.tools.ddk.check.runtime.registry.ICheckValidatorStandaloneSetup

For our example this files contains only one service implementation registered

com.avaloq.tools.xtext.format.sca.FormatConventionsStandaloneSetup

which is used to initialize our catalog for a standalone builder.

Here is a sample of generated standalone setup

package com.avaloq.tools.xtext.format.sca;

import org.apache.log4j.Logger;
import com.avaloq.tools.ddk.check.runtime.configuration.ModelLocation;
import com.avaloq.tools.ddk.check.runtime.registry.ICheckCatalogRegistry;
import com.avaloq.tools.ddk.check.runtime.registry.ICheckValidatorRegistry;
import com.avaloq.tools.ddk.check.runtime.registry.ICheckValidatorStandaloneSetup;

/**
 * Standalone setup for FormatConventions as required by the standalone builder.
 */

@SuppressWarnings("nls")
public class FormatConventionsStandaloneSetup implements ICheckValidatorStandaloneSetup {

  private static final Logger LOG = Logger.getLogger(FormatConventionsStandaloneSetup.class);
  private static final String GRAMMAR_NAME = "com.avaloq.tools.ddk.xtext.format.Format";
  private static final String CATALOG_FILE_PATH = "com/avaloq/tools/xtext/format/sca/FormatConventions.check";

  /** {@inheritDoc} */
  public void doSetup() {
    ICheckValidatorRegistry.INSTANCE.registerValidator(GRAMMAR_NAME, new FormatConventionsCheckImpl());
    ICheckCatalogRegistry.INSTANCE.registerCatalog(GRAMMAR_NAME, new ModelLocation(
      FormatConventionsStandaloneSetup.class.getClassLoader().getResource(CATALOG_FILE_PATH), CATALOG_FILE_PATH));
    LOG.info("Standalone setup done for com/avaloq/tools/xtext/format/sca/FormatConventions.check");
  }

  @Override
  public String toString() {
    return "CheckValidatorSetup(/resource/com.avaloq.tools.xtext.format.sca/src/com/avaloq/tools/xtext/format/sca/FormatConventions.check)";
  }

}

As you can notice standalone setup similarly to plugin.xml registers FormatConventionsCheckImpl as a validator for the Format language.