All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.marklogic.gradle.task.CorbTask.groovy Maven / Gradle / Ivy

/*
 * Copyright (c) 2023 MarkLogic Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.marklogic.gradle.task

import org.gradle.api.tasks.Input
import org.gradle.api.tasks.JavaExec
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.TaskAction

import java.lang.reflect.Modifier

class CorbTask extends JavaExec {

	@Input
  def corbOptions = [:]

  //default CORB option list
  private static String[] DEFAULT_CORB_OPTIONS = "BATCH-SIZE,BATCH-URI-DELIM,\
COLLECTION-NAME,COMMAND,COMMAND-FILE,COMMAND-FILE-POLL-INTERVAL,CONNECTION-POLICY,CONTENT-SOURCE-POOL,\
DECRYPTER,DISK-QUEUE,DISK-QUEUE-MAX-IN-MEMORY-SIZE,DISK-QUEUE-TEMP-DIR,\
ERROR-FILE-NAME,EXIT-CODE-NO-URIS,EXPORT_FILE_AS_ZIP,\
EXPORT-FILE-BOTTOM-CONTENT,EXPORT-FILE-DIR,EXPORT-FILE-HEADER-LINE-COUNT,\
EXPORT-FILE-NAME,EXPORT-FILE-PART-EXT,\
EXPORT-FILE-SORT,EXPORT-FILE-SORT-COMPARATOR,\
EXPORT-FILE-TOP-CONTENT,EXPORT-FILE-URI-TO-PATH,\
FAIL-ON-ERROR,INSTALL,INIT-MODULE,INIT-TASK,JASYPT-PROPERTIES-FILE,JOB-NAME,JOB-SERVER-PORT,\
LOADER-BASE64-ENCODE,LOADER-PATH,LOADER-SET-URIS-BATCH-REF,LOADER-USE-ENVELOPE,LOADER-VARIABLE,\
MAX-OPTS-FROM-MODULE,METADATA,METADATA-TO-PROCESS-MODULE,\
METRICS-COLLECTIONS,METRICS-DATABASE,METRICS-LOG-LEVEL,METRICS-MODULE,\
METRICS-NUM-FAILED-TRANSACTIONS,METRICS-NUM-SLOW-TRANSACTIONS,METRICS-ROOT,METRICS-SYNC-FREQUENCY,\
ML-LOG-LEVELS,MODULES-DATABASE,MODULE-ROOT,\
NUM-TPS-FOR-ETC,OPTIONS-FILE,\
POST-BATCH-MINIMUM-COUNT,POST-BATCH-MODULE,POST-BATCH-TASK,POST-BATCH-XQUERY-MODULE,\
PRE-BATCH-MINIMUM-COUNT,PRE-BATCH-MODULE,PRE-BATCH-TASK,PRE-BATCH-XQUERY-MODULE,PRE-POST-BATCH-ALWAYS-EXECUTE,\
PRIVATE-KEY-ALGORITHM,PRIVATE-KEY-FILE,\
PROCESS-MODULE,PROCESS-TASK,\
QUERY-RETRY-LIMIT,QUERY-RETRY-INTERVAL,QUERY-RETRY-ERROR-CODES,QUERY-RETRY-ERROR-MESSAGE\
SSL-CIPHER-SUITES,SSL-CONFIG-CLASS,SSL-ENABLED-PROTOCOLS,SSL-KEY-PASSWORD,\
SSL-KEYSTORE,SSL-KEYSTORE-PASSWORD,SSL-KEYSTORE-TYPE,SSL-PROPERTIES-FILE,\
TEMP-DIR,THREAD-COUNT,\
URIS_BATCH_REF,URIS-FILE,URIS-LOADER,URIS-MODULE,URIS-REDACTED,URIS-REPLACE-PATTERN,URIS-TOTAL-COUNT,\
XCC-CONNECTION-RETRY-LIMIT,XCC-CONNECTION-RETRY-INTERVAL,XCC-CONNECTION-HOST-RETRY-LIMIT,XCC-CONNECTION-URI,XCC-DBNAME,\
XCC-HOSTNAME,XCC-HTTPCOMPLIANT,XCC-PASSWORD,XCC-PORT,XCC-PROTOCOL,XCC-TIME-ZONE,XCC-URL-ENCODE-COMPONENTS,XCC-USERNAME,\
XML-FILE,XML-METADATA,XML-NODE,XML-SCHEMA,XML-TEMP-DIR,ZIP-FILE\
XQUERY-MODULE".tokenize(',')

  CorbTask() {
	  mainClass.set("com.marklogic.developer.corb.Manager")

	  String[] optionNames = DEFAULT_CORB_OPTIONS
    // obtain the options from CoRB Options class, to ensure that the latest available are applied to this task
    try {
        optionNames = Class.forName("com.marklogic.developer.corb.Options", true, Thread.currentThread().contextClassLoader)
        .declaredFields
        .findAll { (it.getModifiers() & (Modifier.PROTECTED | Modifier.PRIVATE)) == 0 &&
			String.class.equals(it.getType()) &&
			!it.synthetic }
		.collect { it.get(null) }
    } catch (ClassNotFoundException ex) {}

    //Augment with member variables and a mapping of CoRB2 Options
    corbOptions = optionNames.collectEntries { option ->

        String camelOption = option.toLowerCase().split('_|-').collect { it.capitalize() }.join('')
        // create Map entry gradle property and original values, for easy lookup/translation
        String lowerCamelOption = new StringBuffer(camelOption.length())
                                    .append(Character.toLowerCase(camelOption.charAt(0)))
                                    .append(camelOption.substring(1))
                                    .toString();

        //add the lowerCamelCased CoRB2 option as a member variable
        this.metaClass[lowerCamelOption] = null

        // Create a 'corb' prefixed CamelCased entry (i.e. URIS-FILE => corbUrisFile )
        // mapped to the original CoRB2 option for lookup/conversion
        [(CORB_PROPERTY_PREFIX + camelOption): option]
    }

    //ensure that CORB task is always executed
    outputs.upToDateWhen { false }

  }

  // prefix for corb project properties, to ensure no conflicts with other project properties
  private static final String CORB_PROPERTY_PREFIX = "corb"

	@Input
	@Optional
  String xccUrl //same as xccConnectionUri
  // It's common practice for the uris/transform modules to have the same prefix, so just set this if that's the
  // case - e.g. convert-uris.xqy and convert-transform.xqy
	@Input
	@Optional
  String modulePrefix
  // Otherwise, set processModule (formerly transformModule) and urisModule
	@Input
	@Optional
  String transformModule //same as processModule

	@Input
  def install = false // INSTALL

	@Input
  String moduleRoot = "/"  // MODULE-ROOT

  // corb defaults to 1, but 8 seems like a more common default
	@Input
  def threadCount = 8 // THREAD-COUNT

	@TaskAction
  @Override
  public void exec() {
    //By convention, if there is a corb configuration, use it to set the classpath
    if (getProject().configurations.findByName('corb')) {
      setClasspath(getProject().configurations.corb)
    }

    Map options = buildCorbOptions()
    //CoRB2 will evaluate System properties for options
    systemProperties(options)

    super.exec()
  }

  /**
  * Construct CoRB2 options from the following sources:
  * task variables - lowerCamelCase names that correspond to their CoRB2
  *                  option (i.e. optionsFile => OPTIONS-FILE)
  * project properties - Project properties with the naming convention
  *                      of a 'corb' prefix and CamelCased CoRB2 option name
  *                      (i.e. corbOptionsFile => OPTIONS-FILE)
  * System properties - Any System property with a CoRB2 option name
  *
  * If properties are defined in more than one place, System properties will take
  * precedence over Project properties, which take precedence over task member variables.
  *
  * @return Map of CoRB2 options
  */
  public Map buildCorbOptions() {
    //first, convert legacy task properties and generate options from conventions
    Map options = collectNormalizedOptions()
    //collect all of the corb task options (i.e. threadCount=12)
    options << collectMemberVariables()
    //apply any corb project properties (i.e. -PcorbThreadCount=12)
    options << collectCorbProjectProperties()
    //apply any CoRB2 System properties (i.e. -DTHREAD-COUNT=12)
    options << collectSystemProperties()
    options //return the merged options
  }

  /**
  * Normalize corb task properties
  * @return Map of CoRB2 options
  */
  public Map collectNormalizedOptions() {
    Map options = [:]

    if (xccUrl) {
      options['XCC-CONNECTION-URI'] = xccUrl
    }

    if (transformModule) {
      options['PROCESS-MODULE'] = transformModule
    }

    //if modulePrefix is specified, then generate the selector and transform filenames
    if (modulePrefix) {
      options['URIS-MODULE'] = modulePrefix + "-uris.xqy"
      options['PROCESS-MODULE'] = modulePrefix + "-transform.xqy"
    }

    String modulesDatabaseName = getProject().property("mlAppConfig").getModulesDatabaseName()
    if (modulesDatabaseName) {
      options['MODULES-DATABASE'] = modulesDatabaseName
    }
    options //return any options constructed from CorbTask conventions
  }

  /**
  * Inspect the Task member variables and convert into CoRB2 options
  * @return Map of CoRB2 options
  */
  public Map collectMemberVariables() {
    //look for member variables where name match corbOption naming conventions
    this.metaClass.getProperties().collectEntries {
      String corbOptionKey = CORB_PROPERTY_PREFIX + it.name.capitalize()
      //evaluate whether a value is set and the name matches the corbOptions key pattern
	  try {
	    if (corbOptions[corbOptionKey] && this[it.name]) {
	      [(corbOptions[corbOptionKey]): this[it.name] ]
	    } else {
	      [:]
	    }
	  } catch (groovy.lang.GroovyRuntimeException ex) {
	    return [:]
	  }
    }
  }

  /**
  * Collect all System.properties. This allows for any CoRB option to be set, including those not statically known such
  * as CoRB custom inputs (e.g. URIS-MODULE.foo, PROCESS-MODULE.bar, etc) as well as settings for other libraries, such
  * as xcc.httpCompliant to enable XCCS compatability for XCC.
  * @return all System.properties
  */
  public Map collectSystemProperties() {
    System.properties
  }

  /**
  * For each of project properties specified with the convention corbXxxYyy,
  * construct a CoRB2 option
  * @return Map of CoRB2 options
  */
  public Map collectCorbProjectProperties() {
    project.properties.keySet().intersect(corbOptions.keySet()).collectEntries {
      [(corbOptions[it]): project[it]]
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy