Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

THIS PAGE IS A WORK IN PROGRESS.  Some of the class names are already out of date.

Overview

This page discusses generation and application of custom configuration elements, as well as their interaction with the ClusterConfigurationService interface.

...

Note that all of the above discusses only those classes containing configuration information.  To reiterate, these configuration classes are themselves distinct from any instantiated extension object or service.  Until the internal reliance on XML has been overcome, it will remain that any extension class must implement Extension.

TODO: Extension is still an internal API.  Am I advocating the right approach here?

  In particular, this includes providing the XmlGenerator for your extension class.

WORK IN PROGRESS: It appears that Extension is an internal interface.  I will now write a proposal about publicizing the Extension API, which will be linked here in a future revision. 

 

Placement of Configuration Elements within the Configuration

The configuration format In the past, the format of a configuration, as represented internally as XML, is specified in the file cache-1.0.xsd.  This XSD motivates the generation of our Java configuration objects, as we move away from our reliance on XML.

This specification allows for custom configuration elements to appear in one of two places: in the top-level "cache" or in the first child-level "region."  Remember that separate

Separate (non-conflicting) configuration information can exist for the entire cluster as well as each member group; the designation of "cache" and "region" is orthogonal to the designation of members to groups.  Do not confuse the "cache" level to mean a global configuration.  Every member group will define its own Indeed, each group can define different aspects of the total "cache" configuration.

The "cache" level is intended to contain configuration elements that effect cache member state and operation, where the "region" level is intended to contain configuration elements that effect management of data.  For instance, the Lucene Index configuration object will be is stored as a "region" element, since it acts on a region's data.

...

Creating Configuration Classes

WORK IN PROGRESS: The interface name and structure is probably going to change soon.

Whether your configuration element will exist at the "cache" level or at the "region" level, your custom configuration class should implement org.apache.geode.cache.configuration.CacheElement.  This requires your configuration object to be Serializable and Identifiable<String>.

If your custom configuration elements are themselves defined by an XSD, compatible configuration classes can be generated using JAXB.  A simple bindings file similar to that below can impose implementation of CacheElement on generated classes.  Episode files may also be passed as a JAXB binding to indicate that Geode configuration classes have already been generated.  These episode files can be found in <geode root>/etc/.Generation can be See the Resources section below for example bindings and scripts to generate classes using JAXB and the command-line tool xjc.  Alternatively, generation can be performed by some IDEs, such as IDEA IntelliJ, and XJC plugins exist for Maven, Ant, and Gradle build systyems.  Alternatively, the command-line tool xjc can be used to generate classes.  As the common denominator example, we provide a command-line xjc task in each of :geode-core:geode-connectors, and :geode-lucene, reproduced below for your conveniencesystems.

JAXB generation provides a good starting point for your configuration classes.  However, manual adjustment of generated classes may will likely be required.  For instance, if your configuration object does not define an id field, the generated class will need to be updated to implement a getId as part of the CacheElement interface.

Interacting with the Cluster Configuration Service

A typical use case is to create, modify, or remove your configuration object from the cache configuration service in a method belonging to a class extending GfshCommand.  The LuceneIndexCommands.java class demonstrates these cases.

The following pattern is useful in many of these commands.  First, the GfshCommand (acting on a locator to which you are connected) instantiates the configuration object, sets desired values, and distributes the configuration object (perhaps with additional parameters) to the cluster members that require configuration.  Each member then uses the configuration object to create / update / halt the service that the configuration defines.  Results are aggregated back to the locator.  The locator then decides, based on reported success or failures, if the cache configuration should be updated.   This is typically achieved by passing the ClusterConfigurationService the configuration object used.  For instance:

Code Block
@CliCommand(value = LuceneCliStrings.LUCENE_CREATE_INDEX,
    help = LuceneCliStrings.LUCENE_CREATE_INDEX__HELP)
@CliMetaData(relatedTopic = {CliStrings.TOPIC_GEODE_REGION, CliStrings.TOPIC_GEODE_DATA})
public Result createIndex(@CliOption(key = LuceneCliStrings.LUCENE__INDEX_NAME, mandatory = true,
    help = LuceneCliStrings.LUCENE_CREATE_INDEX__NAME__HELP) final String indexName,

    @CliOption(key = LuceneCliStrings.LUCENE__REGION_PATH, mandatory = true,
        optionContext = ConverterHint.REGION_PATH,
        help = LuceneCliStrings.LUCENE_CREATE_INDEX__REGION_HELP) final String regionPath,

    @CliOption(key = LuceneCliStrings.LUCENE_CREATE_INDEX__FIELD, mandatory = true,
        help = LuceneCliStrings.LUCENE_CREATE_INDEX__FIELD_HELP) final String[] fields,

    @CliOption(key = LuceneCliStrings.LUCENE_CREATE_INDEX__ANALYZER,
        help = LuceneCliStrings.LUCENE_CREATE_INDEX__ANALYZER_HELP) final String[] analyzers,
    @CliOption(key = LuceneCliStrings.LUCENE_CREATE_INDEX__SERIALIZER,
        help = LuceneCliStrings.LUCENE_CREATE_INDEX__SERIALIZER_HELP) final String serializer) {

  // Every lucene index potentially writes to disk.
  authorize(Resource.CLUSTER, Operation.MANAGE, LucenePermission.TARGET);

  // Build Lucene Index Configuration object
  Index indexConfig = new Index();
  indexConfig.setName(indexName);

  DeclarableType declarableSerializer = new DeclarableType();
  declarableSerializer.setClassName(serializer);
  indexConfig.setSerializer(declarableSerializer);

  List<Index.Field> indexFields = new ArrayList<>();
  for (int i = 0; i < analyzers.length; i++) {
    Index.Field thisField = new Index.Field();
    thisField.setAnalyzer(analyzers[i].trim());
    thisField.setName(fields[i].trim());
  }
  indexConfig.getField().addAll(indexFields);

  // Perform the index creation on relevant members.
  LuceneIndexInfo indexInfo = new LuceneIndexInfo(indexConfig, regionPath);
  ResultCollector<?, ?> rc = executeFunctionOnAllMembers(createIndexFunction, indexInfo);
  List<CliFunctionResult> funcResults = (List<CliFunctionResult>) rc.getResult();

  // Build results display
  final TabularResultData tabularResult = ResultBuilder.createTabularResultData();
  for (final CliFunctionResult cliFunctionResult : funcResults) {
    tabularResult.accumulate("Member", cliFunctionResult.getMemberIdOrName());

    if (cliFunctionResult.isSuccessful()) {
      tabularResult.accumulate("Status", "Successfully created lucene index");
    } else {
      tabularResult.accumulate("Status", "Failed: " + cliFunctionResult.getMessage());
    }
  }

  // Determine if the configuration was successful and, if so, persist the change.
  boolean creationSuccessful =
      funcResults.stream().map(CliFunctionResult::isSuccessful).reduce(true, (x, y) -> x && y);
  if (creationSuccessful) {
    getConfigurationService().saveCustomRegionElement("cache", regionPath, indexConfig);
  }
  return ResultBuilder.buildResult(tabularResult);
}

 

See the documentation of the ClusterConfigurationService interface for more details.

...

See the Cluster Configuration Service proposals for examples on how your configuration object will interact with the configuration persistence service.

Resources