DefaultSftpSessionFactory using privateKey string - spring-integration

I am looking for a way to create DefaultSftpSessionFactory using private key string. The different functions available in this are using the private Key Resource(local file) instead.
Any ideas to create SessionFactory needed for SftpRemoteFileTemplate? I have the user, host and the private key as a String.
-Thanks

The setter takes a Resource...
/**
* Allows you to set a {#link Resource}, which represents the location of the
* private key used for authenticating against the remote host. If the privateKey
* is not provided, then the {#link DefaultSftpSessionFactory#setPassword(String) password}
* property is mandatory (or {#link #setUserInfo(UserInfo) userInfo} that returns a
* password.
* #param privateKey The private key.
* #see JSch#addIdentity(String)
* #see JSch#addIdentity(String, String)
*/
public void setPrivateKey(Resource privateKey) {
this.privateKey = privateKey;
}
There are many kinds of Resource, including ByteArrayResource, where you can use
setPrivateKey(new ByteArrayResource(myKeyString.getBytes());

Related

Spring integration - how to initiate a database transaction on the flow?

I have an integration flow that sinks DML queries at the end.
I have a config file to log transactions:
logging.level.org.springframework.transaction.interceptor=TRACE
logging.level.org.springframework.transaction.support=DEBUG
The sinkSql method is called but there is no transaction log.
If I just call e.transactional(true) I get an error because there are two transaction managers (one is from the source database).
#Bean(name = SYBASE_TRAN_MANAGER)
public PlatformTransactionManager transactionManager(#Qualifier(SYBASE_DS) final DataSource sybaseDataSource) {
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(sybaseDataSource);
return dataSourceTransactionManager;
}
#Bean
public TransactionInterceptor sybaseTransactionInterceptor(#Qualifier(SYBASE_TRAN_MANAGER) final TransactionManager tm) {
return new TransactionInterceptorBuilder(true)
.transactionManager(tm)
.isolation(Isolation.READ_COMMITTED)
.propagation(Propagation.REQUIRES_NEW)
.readOnly(false)
.build();
}
#Bean
public IntegrationFlow sinkSqlFlow(final TransactionInterceptor sybaseTransactionInterceptor) {
return IntegrationFlows.from(SYBASE_SINK_SQL)
.enrichHeaders(h -> h.header(MessageHeaders.ERROR_CHANNEL, SYBASE_ERROR))
.handle(this::sinkSql, e -> e.transactional(sybaseTransactionInterceptor))
.get();
}
public void sinkSql(final Message<?> message) {
//jdbcTemplate logic here
}
Not sure why is the question since TransactionAspectSupport does just this plain fallback if we don't provide an explicit TransactionManager to the interceptor configuration:
if (defaultTransactionManager == null) {
defaultTransactionManager = this.beanFactory.getBean(TransactionManager.class);
this.transactionManagerCache.putIfAbsent(
DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
}
where that getBean(Class aClass) indeed is going to fail if several beans of type is present in the application context. So, what you did so far with a sybaseTransactionInterceptor bean definition is OK.
You can use an overloaded Java DSL method though:
/**
* Specify a {#link TransactionInterceptor} {#link Advice} with the provided
* {#code PlatformTransactionManager} and default
* {#link org.springframework.transaction.interceptor.DefaultTransactionAttribute}
* for the {#link MessageHandler}.
* #param transactionManager the {#link TransactionManager} to use.
* #param handleMessageAdvice the flag to indicate the target {#link Advice} type:
* {#code false} - regular {#link TransactionInterceptor}; {#code true} -
* {#link org.springframework.integration.transaction.TransactionHandleMessageAdvice}
* extension.
* #return the spec.
*/
public S transactional(TransactionManager transactionManager, boolean handleMessageAdvice) {
Although having your sink contract as void sinkSql(final Message<?> message), there is no need in that true: the transaction is going to be applied for a handleMessage() method which is really the end of your flow anyway.

DelayHandler messageGroupId

From the Spring Integration documentation (https://docs.spring.io/spring-integration/docs/5.1.7.RELEASE/reference/html/#delayer) it is not clear to me what the messageGroupId in the DelayHandler means exactly and which value I have to set there exactly (is it arbitrary?). This value does not exist in the xml configuration, but does in the Java configuration.
#ServiceActivator(inputChannel = "input")
#Bean
public DelayHandler delayer() {
DelayHandler handler = new DelayHandler("delayer.messageGroupId"); // THIS constructor parameter is not clear to me
handler.setDefaultDelay(3_000L);
handler.setDelayExpressionString("headers['delay']");
handler.setOutputChannelName("output");
return handler;
}
It is explained in the JavaDocs of that constructor:
/**
* Create a DelayHandler with the given 'messageGroupId' that is used as 'key' for
* {#link MessageGroup} to store delayed Messages in the {#link MessageGroupStore}.
* The sending of Messages after the delay will be handled by registered in the
* ApplicationContext default
* {#link org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler}.
* #param messageGroupId The message group identifier.
* #see #getTaskScheduler()
*/
public DelayHandler(String messageGroupId) {
It is not required because the groupId is based on the required id attribute:
String id = element.getAttribute(ID_ATTRIBUTE);
if (!StringUtils.hasText(id)) {
parserContext.getReaderContext().error("The 'id' attribute is required.", element);
}
...
builder.addConstructorArgValue(id + ".messageGroupId");
It is really mentioned and explained a little bit in the docs: https://docs.spring.io/spring-integration/docs/current/reference/html/messaging-endpoints.html#delayer-namespace.
The value indeed is arbitrary, but it must be unique per your application, so different delayers don't steal messages from each other.

Change output names in API return object

I am very new to nodejs and typescript.
I have try to provide an API via express.
I have try to return a custom object on my API who looks like that :
export class Auction {
private _currentPrice:number = 0;
private _auctionName:string;
public constructor(currentPrice: number , auctionName: string) {
this._currentPrice = currentPrice;
this._auctionName = auctionName;
}
/**
* Getter auctionName
* #return {string}
*/
public get auctionName(): string {
return this._auctionName;
}
/**
* Setter auctionName
* #param {string} value
*/
public set auctionName(value: string) {
this._auctionName = value;
}
/**
* Setter currentPrice
* #param {number } value
*/
public set currentPrice(value: number ) {
this._currentPrice = value;
}
/**
* Getter currentPrice
* #return {number }
*/
public get currentPrice(): number {
return this._currentPrice;
}
}
But what I have seen is that the answer of my API is something like :
{"_currentPrice":0,"_auctionName":"toto"}
I was expecting something like
{"currentPrice":0,"auctionName":"toto"}
Is there any way to automaticaly convert it to the format I want ?
This is happening because when the TypeScript is compiled to JavaScript, objects created by that class have public _currentPrice and _auctionName properties (because TypeScript "private" properties are only private in terms of TypeScript's type system) and they don't have their own currentPrice and auctionName properties (they inherit them from their prototype, which has them as accessor properties). JSON.stringify only includes "own" properties.
You can deal with it in a few ways:
By using simple properties for currentPrice and auctionName. You have public accessors for both get and set for both properties, so there doesn't seem to be any reason to use private properties to hold their values. Or,
By providing your own toJSON method for the class:
toJSON() {
return {currentPrice: this._currentPrice, auctionName: this._auctionName};
}
Despite the name "toJSON", this method isn't supposed to return JSON; it's supposed to return the value for the object that should be converted to JSON. So in this case, you return an object with the properties you want the returned JSON to have.
A third solution would be to use JavaScript's own private properties (they're supported in up-to-date Node.js versions) and "own" accessors for them on the objects, but I don't think TypeScript supports JavaScript's private properties yet.

Spring Integration DSL: Transformer using headers

I want to use Java DSL for Spring Integration, but I can't figure out how to use message headers during transformation.
My old implementation had a Transformer like this:
#Transformer(inputChannel = "inputChannel", outputChannel = "outputChannel")
public EventB transform(
EventA eventA,
#Header("a_header") String aHeader,
#Header("other_header") String otherHeader){
return new EventB(eventA.getSomeField(), aHeader, otherHeader);
}
Now I have the following DSL:
#Bean
public IntegrationFlow aFlow(){
return IntegrationFlows.from(EventASink.INPUT)
.filter("headers['operation'] == 'OPERATION_A'")
.transform() //<-- What should I do here?
.handle(Http.outboundGateway(uri).httpMethod(HttpMethod.POST))
.get();
}
I looked at the implementation of transform() method and I found that it can receive a GenericTransformer as parameter, but it seems to work only with message payload and I also need the headers.
I also saw that some kind of reflection can be used, but I don't like it because its not refactor-safe.
Any advice? Thanks in advance.
Since the DSL is a part of the Framework and it is compiled before you start to use it, we can't infer any custom POJO methods, therefore there is no so clean way to count with any custom headers like in your sample.
The closet way to re-use your transform() with those annotations on parameters is with this .transform() contract:
/**
* Populate the {#code MessageTransformingHandler} for the {#link MethodInvokingTransformer}
* to invoke the service method at runtime.
* #param service the service to use.
* #param methodName the method to invoke.
* #return the current {#link IntegrationFlowDefinition}.
* #see MethodInvokingTransformer
*/
public B transform(Object service, String methodName)
So, you would need to declare a bean with that method and use it in the service argument meanwhile mention the method in the methodName argument.
Another way to get access to headers is to request the whole Message type for lambda:
/**
* Populate the {#link MessageTransformingHandler} instance for the provided
* {#link GenericTransformer} for the specific {#code payloadType} to convert at
* runtime.
* Use {#link #transform(Class, GenericTransformer)} if you need access to the
* entire message.
* #param payloadType the {#link Class} for expected payload type. It can also be
* {#code Message.class} if you wish to access the entire message in the transformer.
* Conversion to this type will be attempted, if necessary.
* #param genericTransformer the {#link GenericTransformer} to populate.
* #param <P> the payload type - 'transform from' or {#code Message.class}.
* #param <T> the target type - 'transform to'.
* #return the current {#link IntegrationFlowDefinition}.
* #see MethodInvokingTransformer
* #see LambdaMessageProcessor
*/
public <P, T> B transform(Class<P> payloadType, GenericTransformer<P, T> genericTransformer) {
In this case the code could be like this:
.transform(Message.class, m -> m.getHeaders())
I had the same issue. I needed both headers and payload. After a lot of tinkering I found a solution. I used .handle instead of .transform. GenericHandler's handle method provides both payload and headers.
In your case it would look something like:
#Bean
public IntegrationFlow aFlow(){
return IntegrationFlows.from(EventASink.INPUT)
.filter("headers['operation'] == 'OPERATION_A'")
.<EventA>handle((eventA, h) -> new EventB(
eventA.getSomeField(),
h.get("a_header", String.class),
h.get("other_header", String.class)))
.handle(Http.outboundGateway(uri).httpMethod(HttpMethod.POST))
.get();
}

configure phpmailer with DKIM

I installed DKIM on my server following this tutorial:
http://www.howtoforge.com/set-up-dkim-domainkeys-identified-mail-working-with-postfix-on-centos-using-opendkim
However phpmailer wants the following fields to use DKIM:
/**
* Used with DKIM DNS Resource Record
* #var string
*/
public $DKIM_selector = '';
/**
* Used with DKIM DNS Resource Record
* optional, in format of email address 'you#yourdomain.com'
* #var string
*/
public $DKIM_identity = '';
/**
* Used with DKIM DNS Resource Record
* #var string
*/
public $DKIM_passphrase = '';
/**
* Used with DKIM DNS Resource Record
* optional, in format of email address 'you#yourdomain.com'
* #var string
*/
public $DKIM_domain = '';
/**
* Used with DKIM DNS Resource Record
* optional, in format of email address 'you#yourdomain.com'
* #var string
*/
public $DKIM_private = '';
I know the selector and the private key. But what is the passphrase?
Also, for identy, can I just put *#mydomain.com?

Resources