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

com.univocity.api.engine.DataIntegrationEngine Maven / Gradle / Ivy

/*******************************************************************************
 * Copyright (c) 2013 uniVocity Software Pty Ltd. All rights reserved.
 * This file is subject to the terms and conditions defined in file
 * 'LICENSE.txt', which is part of this source code package.
 ******************************************************************************/
package com.univocity.api.engine;

import java.util.*;

import com.univocity.api.*;
import com.univocity.api.config.*;
import com.univocity.api.config.annotation.*;
import com.univocity.api.config.builders.*;
import com.univocity.api.data.*;

/**
 * The DataIntegrationEngine is the central component of uniVocity. With it you can define data mappings between entities of different data stores,
 * execute them, and control their execution.
 *
 * 

A DataIntegrationEngine depends on some essential configurations in an {@link EngineConfiguration} object * and can only be created via a {@link Univocity} instance. * *

A database with a set of tables to store metadata is required for non-trivial mappings. This configuration resides in a {@link MetadataSettings} object. * In case this is not configured in {@link EngineConfiguration#getMetadataSettings()}, * the DataIntegrationEngine will be started with an in-memory database. Note, however, that all metadata stored in this in-memory database * is lost once the DataIntegrationEngine is shut down (using {@link Univocity#shutdown(String)}). * *

The DataIntegrationEngine manages an internal scope ({@link EngineScope}) for variables, constants, {@link FunctionCall}s, and {@link DatasetProducer}s. * *

IMPORTANT: instances of DataIntegrationEngine are not thread safe. If multiple threads share the same instance, * synchronization must be managed externally. * * @see Univocity * @see EngineConfiguration * @see MetadataSettings * @see FunctionCall * @see DatasetProducer * @see EngineScope * * @author uniVocity Software Pty Ltd - [email protected] * */ public interface DataIntegrationEngine { /** * The name of the data integration engine. This name is unique and {@link Univocity} will always return the same engine instance for a given name. * @return the data integration engine name. */ public String getName(); /** * Creates a mapping configuration object between entities of two data stores. This is the first step in defining data mappings. * The {@link DataStoreMapping} instance is unique between two data stores and calling this method multiple times with the * same data store names will cause and exception. * * @param sourceDataStore the name of the source data store. * @param destinationDataStore the name of the destination data store. Source and destination data stores can be the same. * @return a new {@link DataStoreMapping} instance. */ public DataStoreMapping map(String sourceDataStore, String destinationDataStore); /** * Obtains the mapping configuration object between entities of two data stores. * * @param sourceDataStore the name of the source data store. * @param destinationDataStore the name of the destination data store. Source and destination data stores can be the same. * @return the existing {@link DataStoreMapping} instance associated with the given data store names, or {@code null} if no such mapping between them exists. */ public DataStoreMapping getMapping(String sourceDataStore, String destinationDataStore); /** * Removes the mapping between two data stores. All configuration settings defined in the underlying {@link DataStoreMapping} will be lost. * @param sourceDataStore the name of the source data store. * @param destinationDataStore the name of the destination data store. Source and destination data stores can be the same. */ public void removeMapping(String sourceDataStore, String destinationDataStore); /** * Adds a callback object that intercepts life cycle events produced within this engine. * @param interceptor the callback object that will be notified of this engine's life cycle events. */ public void addInterceptor(EngineLifecycleInterceptor interceptor); /** * Removes a {@link EngineLifecycleInterceptor} instance from this engine, so it stops being notified of updates in this engine's internal state. * @param interceptor the callback object to be removed */ public void removeInterceptor(EngineLifecycleInterceptor interceptor); /** * Associates a variable name to an expression. When the variable is accessed, the expression will be evaluated and the result will be * reused while the scope is active. These values are lost when the scope is deactivated. * For example, an expression variable associated with the {@link EngineScope#CYCLE} scope won't be accessible if a there is no mapping cycle execution in progress. * Attempting to read a variable whose scope is not active will yield an {@link IllegalStateException}. * *

Acceptable expressions conform to the following format: * *

    *
  • variables and constant names are prefixed with {@code $}
  • *
  • a function call is represented by its name and a sequence of parameters, if any, between {@code ()} and separated by commas. * Additional expressions such as function calls are accepted as parameters. *
  • *
  • a single expression can return multiple values. Each value must be separated by a comma and the result will be an array of objects
  • *
  • the word "null", without quotes, will be evaluated as a null object; 'null' will be evaluated to the "null" String. *
  • *
  • any value between single quotes is interpreted as a {@code String} literal. Single quotes are only required if the {@code String} literal contains: *
      *
    • leading or trailing whitespaces.
    • *
    • any of the following characters: $ ) ' ( ,
    • *
    • in case the single quote is part of the value, it must be escaped with an addition single quote: *

      the expression: "' '' this is escaped '' '" will be parsed as the {@code String}" ' this is escaped ' " *

    • *
    *
  • *
* * Example: assume the {@code concat} function concatenates any number of arguments into a {@code String}, and the variables b = 1 and e = 2: *

* "a, $b, concat( d, $e, 'f')" * * The expression result will be an object array with: ["a", 1, "d2f"]. * * @param scope the scope of this expression variable * @param name the name of the expression variable * @param expression the expression to be executed when the variable name is read for the first time in its scope. */ public void addExpression(EngineScope scope, String name, String expression); /** * Adds a custom function implementation to this engine. The result of a function call will be reused within a given scope. For example, * if the function "currentTime('yyyy-mm-dd')" is associated with the {@link EngineScope#CYCLE} scope, the value returned by this particular invocation * will be reused until a mapping cycle ends. * *

Note: functions are accessible from any scope. * * @param the function call type * @param scope the scope of values returned by the given function. The engine will retain and reuse the result of each function call into the given scope. * @param name the name of the given function. This name can be used in expressions, followed by the function arguments. * @param function the actual implementation of the function. */ public > void addFunction(EngineScope scope, String name, F function); /** * Creates a function backed by an implementation of {@link java.util.Map}. Functions based on a map accept only one parameter as an argument, which is used as the key * to retrieve a value from the map. This map can be modified externally at any time. * *

Examples:

*
	 *
	 * Map<String, String> languages = new HashMap<String, String>();
	 * locales.put("en_US", "American English");
	 * locales.put("en_GB", "British English");
	 * locales.put("en_AU", "Australian English");
	 *
	 * //creates a function named "languages" with values given in the languages map
	 * engine.addMap("languages", languages);
	 *
	 * //executes "languages(en_GB)" to obtain the description and maps it to the "language_description" field in the destination entity.
	 * mapping.value().copy("{languages(en_GB)}").to("language_description");
	 *
	 * //For each value extracted from the source "lang_code", calls the "languages" function
	 * //to obtain the description then writes to "language_description" in the destination
	 * mapping.value().copy("lang_code").to("language_description").readingWith("languages");
	 * 

* * @param the map type * @param name the name of the function * @param mapFunction the implementation of {@link java.util.Map} that will be used to store and fetch key-value pairs. */ public > void addMap(String name, F mapFunction); /** * Configures a query to be executed against a data store as a function. The query will be accessible from any {@link EntityMapping}s of this engine. * * The result of a query-based function call will be reused within a given scope. For example * if query named as "selectLocaleId" is associated with the {@link EngineScope#CYCLE} scope, the value returned by multiple invocations of * "selectLocaleId('en_US')" will be reused until the end of a data mapping cycle. * *

Note: The query-based function will be accessible from any scope.

* * @param scope the scope of values returned by the query. The engine will retain and reuse the result of each query call within the given scope. * @param queryName the name of the given query. This name can be used in expressions, followed by the query arguments. * @return an object used to properly configure the query as a function. */ public QuerySetup addQuery(EngineScope scope, String queryName); /** * Sets or adds then initializes a variable in the current scope. To read the value of a variable in expressions, prepend it with $. * For example: "$en_US" reads the value of the variable "en_US". * *

The scope of the new variable depends on the current active scope (see {@link EngineScope}).

* * @param name the name of the new variable * @param value the value of the variable to be set/created in the current scope. */ public void setVariable(String name, Object value); /** * Sets or adds then initializes a variable in the persistent scope ({@link EngineScope#PERSISTENT}). If no {@link ScopeStorageProvider} is defined * in {@link EngineConfiguration#getPersistentScopeStorageProvider()}, the variable will be added/set using {@link EngineScope#APPLICATION}. * *

To read the value of a variable in an expression, prepend it with $. * For example: "$en_US" reads the value of the variable "en_US".

* * @param name the name of the new variable added to the {@link EngineScope#PERSISTENT} scope * @param value the value of the variable to be set/created in the persistent scope. */ public void setPersistentVariable(String name, Object value); /** * Adds a constant value that can accessed from any scope. To read the value of a constant in expressions, prepend it with $. * For example: "$en_US" reads the value of the constant "en_US". * *

Constants cannot have their value modified.

* * @param name the name of the new constant * @param value the value of the constant */ public void setConstant(String name, Object value); /** * Reads the value of a variable or constant registered to this engine * * @param name the name of the variable * @return the value of the variable */ public Object readVariable(String name); /** * Creates new functions based on the methods annotated with {@link FunctionWrapper}. Object instances provided by the user are required, * as the object might have an internal state that should be updated with each function call. * @param objectsWithFunctions a sequence of objects whose classes define one or more methods annotated by with {@link FunctionWrapper}. */ public void addFunctions(Object... objectsWithFunctions); /** * Associates a {@link RowReader} implementation class to a name and a scope. When required, a row reader instance will be instantiated using the class's default * constructor. This instance will be reused within the given scope and destroyed when the scope is deactivated. * * @param scope the row reader scope that determines when its instances will be destroyed. * @param name the name of the given row reader. * @param reader the implementation of a {@link RowReader} to be instantiated when required. */ public void addRowReader(EngineScope scope, String name, Class reader); /** * Associates a {@link RowReader} instance to name. As this is a user-provided instance, it is the user's * responsibility to determine how its internal state, if any, should be managed. * * @param name the name of the given row reader * @param reader an instance of a row reader, managed by the user. */ public void addRowReader(String name, RowReader reader); /** * Adds a new {@link Dataset} to this engine. The given dataset can contain data and be used as a source or, if the dataset implements * {@link ModifiableDataset}, as the destination entity in entity mappings. The user can create his/her own implementation of this interface. * * *

As a convenience, many useful dataset implementations can be obtained through a {@link DatasetFactory}. * * @param name the name of the dataset * @param dataset the dataset implementation */ public void addDataset(String name, Dataset dataset); /** * Adds and configures a {@link DatasetProducer} for reading information from an entity accessible through this engine, and producing different * datasets as a result. The resulting datasets can then be used in entity mappings. The dataset producer is associated with a scope, therefore * the datasets will be kept while the scope is active. * * @param scope the scope of the datasets produced by the given producer * @param producer the object responsible for producing datasets. * @return a {@link DatasetProducerSetup} object for configuring the inputs and outputs of the given dataset producer. */ public DatasetProducerSetup addDatasetProducer(EngineScope scope, DatasetProducer producer); /** * Disables data modifications on a given set of records of a data entity that were already mapped. *
This will create a flag in uniVocity metadata tables for the given records, which prevents * data modifications on all rows already mapped. * *

Note: This only takes effect if the entity mapping configuration uses uniVocity metadata information (i.e. {@link PersistenceSetup#usingMetadata()}).

* * @param dataEntityName the name of the data entity to have some records disabled for updates. * @param dataset the dataset containing the identifiers of a mapped destination entity. */ public void disableUpdateOnRecords(String dataEntityName, Dataset dataset); /** * Disables data modifications to all records of this data entity that were already mapped. * New records introduced after another mapping cycle will be enabled for updates. *
This will create a flag in uniVocity metadata tables for the given entity, which prevents * data modifications on all rows already mapped. * *

Note: This only takes effect if the entity mapping configuration uses uniVocity metadata information (i.e. {@link PersistenceSetup#usingMetadata()}).

* * @param dataEntityName the name of the data entity to have all records already mapped disabled for updates. */ public void disableUpdateOnAllRecords(String dataEntityName); /** * Re-enables data modifications on a given set records of a data entity. This reverts the metadata changes made * with {@link #disableUpdateOnRecords(String, Dataset)} or {@link #disableUpdateOnAllRecords(String)} for the given records. * * @param dataEntityName the name of the data entity to have some records enabled for updates. * @param dataset the dataset containing the identifiers of a mapped destination entity. */ public void enableUpdateOnRecords(String dataEntityName, Dataset dataset); /** * Re-enables data modifications on all records of a data entity. This will any metadata changes made * with {@link #disableUpdateOnRecords(String, Dataset)} or {@link #disableUpdateOnAllRecords(String)}. * * @param dataEntityName the name of the data entity to have all of its records enabled for data updates. */ public void enableUpdateOnAllRecords(String dataEntityName); /** * Use this method to define the correct sequence of mappings that have to be executed in order to correctly process the default data mapping cycle * (started with {@link #executeCycle()} or {@link #executeCycle(DataIncrement)}). * *

By default, the mappings are executed in the order they were configured. However, entity mappings generated automatically (using * {@link DataStoreMapping#autodetectMappings()}) won't have the correct mapping sequence.

* *

This might be required to ensure data exclusions and updates occur in the proper sequence (which is usually the reverse order of insertion) and that * references to other entities are correctly populated.

* *

If there are duplicate names from different data stores, these names must be written in the format dataStoreName.entityName.

* * @param sequenceOfDestinationEntities the sequence of destination fields to be mapped. Not all destination entities need to be declared here. The ones that appear * in the sequence will be executed first, in the given order. Omitted data entities will have their mappings executed after the give sequence of mappings took place. */ public void setMappingSequence(String... sequenceOfDestinationEntities); /** * Executes a data mapping cycle with all mappings configured in this engine (i.e. via {@link #map(String, String)}). * A transactional operation for all mappings in this cycle will be created. */ public void executeCycle(); /** * Executes a data mapping cycle against a {@link DataIncrement} object with all mappings configured in this engine (i.e. via {@link #map(String, String)}). *

The data increment is used in place of one or more source data entities.

* * @param increment The increment with data changes for one or more source entities that should be applied to the destination using the configured mappings. */ public void executeCycle(DataIncrement increment); /** * Executes a data mapping cycle against the selected destination entities. If there are duplicate names from different data stores, these names must be written in * the format dataStoreName.entityName. The mappings will be executed in the same order the given entities are declared. * * @param destinationEntities the sequence of destination entities to receive data from the mappings. */ public void executeCycle(String... destinationEntities); /** * Executes a data mapping cycle against a {@link DataIncrement} object and a selection of destination entities. * If there are duplicate names from different data stores, these names must be written in the format dataStoreName.entityName. * The mappings will be executed in the same order the given entities are declared. * *

The data increment is used in place of one or more source data entities.

* * @param increment the object with additional data to be used in place of one or more source data entities in this cycle. * @param destinationEntities the sequence of destination entities to receive data from the mappings. */ public void executeCycle(DataIncrement increment, String... destinationEntities); /** * Executes a data mapping cycle with all mappings configured in this engine (i.e. via {@link #map(String, String)}). * @param transactionConfig the configuration that defines how transactions should be created while executing mappings in this cycle. */ public void executeCycle(Transactions transactionConfig); /** * Executes a data mapping cycle against a {@link DataIncrement} object with all mappings configured in this engine (i.e. via {@link #map(String, String)}). *

The data increment is used in place of one or more source data entities.

* * @param transactionConfig the configuration that defines how transactions should be created while executing mappings in this cycle. * @param increment The increment with data changes for one or more source entities that should be applied to the destination using the configured mappings. */ public void executeCycle(Transactions transactionConfig, DataIncrement increment); /** * Executes a data mapping cycle against the selected destination entities. If there are duplicate names from different data stores, these names must be written in * the format dataStoreName.entityName. The mappings will be executed in the same order the given entities are declared. * * @param transactionConfig the configuration that defines how transactions should be created while executing mappings in this cycle. * @param destinationEntities the sequence of destination entities to receive data from the mappings. */ public void executeCycle(Transactions transactionConfig, String... destinationEntities); /** * Executes a data mapping cycle against a {@link DataIncrement} object and a selection of destination entities. * If there are duplicate names from different data stores, these names must be written in the format dataStoreName.entityName. * The mappings will be executed in the same order the given entities are declared. * *

The data increment is used in place of one or more source data entities.

* * @param transactionConfig the configuration that defines how transactions should be created while executing mappings in this cycle. * @param increment the object with additional data to be used in place of one or more source data entities in this cycle. * @param destinationEntities the sequence of destination entities to receive data from the mappings. */ public void executeCycle(Transactions transactionConfig, DataIncrement increment, String... destinationEntities); }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy