The framework provides built-in services that you can inject by type in components and actions.
Lisf of built-in services
Type | Description |
---|---|
|
Provides a small abstraction to cache data that does not need to be recomputed very often. Commonly used by actions for UI interactions. |
|
Allows to resolve a dependency from its Maven coordinates. It can either try to resolve a local file or (better) creates for you a preinitialized classloader. |
|
A JSON-B instance. If your model is static and you don’t want to handle the serialization manually using JSON-P, you can inject that instance. |
|
A JSON-P instance. Prefer other JSON-P instances if you don’t exactly know why you use this one. |
|
A JSON-P instance. It is recommended to use this one instead of a custom one to optimize memory usage and speed. |
|
A JSON-P instance. It is recommended to use this one instead of a custom one to optimize memory usage and speed. |
|
A JSON-P instance. It is recommended to use this one instead of a custom one to optimize memory usage and speed. |
|
A JSON-P instance. It is recommended to use this one instead of a custom one to optimize memory usage and speed. |
|
A JSON-P instance. It is recommended to use this one instead of a custom one to optimize memory usage and speed. |
|
Allows to resolve files from Maven coordinates (like |
|
Utility to inject services in fields marked with |
|
Allows to instantiate an object from its class name and properties. |
|
Allows to instantiate a record. |
|
Allows to instantiate a |
|
Represents the local configuration that can be used during the design. It is not recommended to use it for the runtime because the local configuration is usually different and the instances are distinct. You can also use the local cache as an interceptor with |
Every interface that extends |
Lets you define an HTTP client in a declarative manner using an annotated interface. See the Using HttpClient for more details. |
All these injected services are serializable, which is important for big data environments. If you create the instances yourself, you cannot benefit from these features, nor from the memory optimization done by the runtime. Prefer reusing the framework instances over custom ones. |
LocalConfiguration
The local configuration uses system properties and the environment (replacing dots per underscores) to look up the values.
You can also put a TALEND-INF/local-configuration.properties
file with default values. This allows to use the local_configuration:<key>
syntax in @Ui
annotation. Here is an example to read the default value of a property from the configuration:
@Option
@DefaultValue("local_configuration:myfamily.model.key")
private String value;
Ensure your key is unique across all components to avoid global overrides on the JVM. In practice, it is strongly recommended to always use the family as a prefix. Also note that you can use @Configuration("prefix") to inject a mapping of the LocalConfiguration in a component. It uses the same rules as for any configuration object.
If you prefer to inject you configuration in a service, ensure to wrap it in a Supplier to always have
an up to date version.
|
If you want to ignore the local-configuration.properties
, you can set the system property: talend.component.configuration.${componentPluginId}.ignoreLocalConfiguration=true
.
Here a sample @Configuration
model:
@Data // from lombok, optional
public class MyConfig {
@Option
private String defaultUrl;
}
Here is how to use it from a service:
@Service
public class ConfiguredService {
@Configuration("myprefix")
private Supplier<MyConfig> config;
}
And finally, here is how to use it in a component:
@Service
public class ConfiguredComponent {
public ConfiguredComponent(@Configuration("myprefix") final MyConfig config) {
// ...
}
}
it is recommended to convert this configuration in a runtime model in components to avoid to transport more than desired during the job distribution. |
Using HttpClient
You can access the API reference in the Javadocs.
The HttpClient usage is described in this section by using the REST API example below. Assuming that it requires a basic authentication header:
GET |
- |
POST |
JSON payload to be created: |
To create an HTTP client that is able to consume the REST API above, you need to define an interface that extends HttpClient
.
The HttpClient
interface lets you set the base
for the HTTP address that the client will hit.
The base
is the part of the address that needs to be added to the request path to hit the API.
Every method annotated with @Request
in the interface defines an HTTP request.
Every request can have a @Codec
parameter that allows to encode or decode the request/response payloads.
You can ignore the encoding/decoding for String and Void payloads.
|
public interface APIClient extends HttpClient {
@Request(path = "api/records/{id}", method = "GET")
@Codec(decoder = RecordDecoder.class) //decoder = decode returned data to Record class
Record getRecord(@Header("Authorization") String basicAuth, @Path("id") int id);
@Request(path = "api/records", method = "POST")
@Codec(encoder = RecordEncoder.class, decoder = RecordDecoder.class) //encoder = encode record to fit request format (json in this example)
Record createRecord(@Header("Authorization") String basicAuth, Record record);
}
The interface should extend HttpClient .
|
In the codec classes (that implement Encoder/Decoder), you can inject any of your service annotated with @Service
or @Internationalized
into the constructor.
Internationalization services can be useful to have internationalized messages for errors handling.
The interface can be injected into component classes or services to consume the defined API.
@Service
public class MyService {
private APIClient client;
public MyService(...,APIClient client){
//...
this.client = client;
client.base("http://localhost:8080");// init the base of the api, often in a PostConstruct or init method
}
//...
// Our get request
Record rec = client.getRecord("Basic MLFKG?VKFJ", 100);
//...
// Our post request
Record newRecord = client.createRecord("Basic MLFKG?VKFJ", new Record());
}
By default, /+json are mapped to JSON-P and /+xml to JAX-B if the model has a @XmlRootElement annotation.
|
Customizing HTTP client requests
For advanced cases, you can customize the Connection
by directly using @UseConfigurer
on the method. It calls your custom instance of Configurer
. Note that you can use @ConfigurerOption
in the method signature to pass some Configurer
configurations.
For example, if you have the following Configurer
:
public class BasicConfigurer implements Configurer {
@Override
public void configure(final Connection connection, final ConfigurerConfiguration configuration) {
final String user = configuration.get("username", String.class);
final String pwd = configuration.get("password", String.class);
connection.withHeader(
"Authorization",
Base64.getEncoder().encodeToString((user + ':' + pwd).getBytes(StandardCharsets.UTF_8)));
}
}
You can then set it on a method to automatically add the basic header with this kind of API usage:
public interface APIClient extends HttpClient {
@Request(path = "...")
@UseConfigurer(BasicConfigurer.class)
Record findRecord(@ConfigurerOption("username") String user, @ConfigurerOption("password") String pwd);
}
Built-In configurer
The framework provides in the component-api
an OAuth1.Configurer
which can be used as an example
of configurer implementation. It expects a single OAuth1.Configuration
parameter to be passed
to the request as a @ConfigurationOption
.
Here is a sample showing how it can be used:
public interface OAuth1Client extends HttpClient {
@Request(path = "/oauth1")
@UseConfigurer(OAuth1.Configurer.class)
String get(@ConfigurerOption("oauth1") final OAuth1.Configuration configuration);
}
Big data streams
By default, the client loads in memory the payload. In case of big payloads, it can consume too much memory.
For these cases, you can get the payload as an InputStream
:
public interface APIClient extends HttpClient {
@Request(path = "/big/http/data")
InputStream getData();
}
You can use the Response wrapper, or not.
|