spring Integration configuration logging channel adaptor - configuration

Currently using spring integration 4.2.8.
I have managed quite a lot of my previous question about this but I have 1 piece of xml configuration I can't work out how to replace in the new configuration class: it is the logging-channel-adapter there doesn't seem to be a matching class.
The only class I can find is the LoggingChannelAdapterParser but that is just designed to read the xml and output something ( AbstractBeanDefinition)
How do I specify a logging output in the recipientListRouter?
<int:logging-channel-adapter id="dlq-logger" level="ERROR" expression="'Unknown action type ['
.concat(headers.actionType)
.concat('] for message with payload ')
.concat(payload)"/>
<int:recipient-list-router input-channel="jms-inbound" id="action-type-router">
<int:recipient channel="inbound1" selector-expression="headers.actionType == 'CREATE'"/>
<int:recipient channel="inbound2" selector-expression="headers.actionType == 'UPDATE'"/>
<int:recipient channel="dlq-logger" selector-expression="headers.actionType != 'UPDATE' and headers.actionType != 'CREATE' "/>
</int:recipient-list-router>
Here is the recipinetListRouter constructor
#ServiceActivator(inputChannel = "routingChannel")
#Bean
RecipientListRouter actionTypeRouter(){
RecipientListRouter router = new RecipientListRouter();
router.setChannels()
router.addRecipient("Inbound1", "headers.actionType == 'CREATE'")
router.addRecipient("Inbound2", "headers.actionType == 'UPDATE'")
router.addRecipient("dlqLogger", "headers.actionType != 'UPDATE' and headers.actionType != 'CREATE' ")
}
Edit - from gary's answer
If as does seem sensible this is the most likely answer which way do I wire it, can a logging handler be a recipient? if so do i still need the ServiceActivator annotation?
Or is it a 2 way relationship?
#Bean
#ServiceActivator(inputChannel = "logChannel")
public LoggingHandler logging() {
LoggingHandler adapter = new LoggingHandler(LoggingHandler.Level.DEBUG);
adapter.setLoggerName("TEST_LOGGER");
adapter.setLogExpressionString("headers.id + ': ' + payload");
return adapter;
}

It's called LoggingHandler - see the documentation.
#Bean
#ServiceActivator(inputChannel = "logChannel")
public LoggingHandler logging() {
LoggingHandler adapter = new LoggingHandler(LoggingHandler.Level.DEBUG);
adapter.setLoggerName("TEST_LOGGER");
adapter.setLogExpressionString("headers.id + ': ' + payload");
return adapter;
}
EDIT from Artem Bilan
Also pay attention to the docs of the <int:logging-channel-adapter>:
<xsd:element name="logging-channel-adapter">
<xsd:annotation>
<xsd:documentation>
Defines a Message Producing Endpoint for the
'org.springframework.integration.handler.LoggingHandler'.
</xsd:documentation>
</xsd:annotation>
And then go to this Docs for more understanding the model: https://docs.spring.io/spring-integration/reference/html/overview.html#_finding_class_names_for_java_and_dsl_configuration
Comment From Gary:
Consuming endpoints consist of 2 beans; a consumer (with the input channel) and message handler; the XML generates both; with Java Configuration, the #Bean creates the handler and the #ServiceActivator defines the consumer. So in your case, it would be #ServiceActivator(inputChannel="dlqLogger"). The router has the selector expressions. –

Related

"Invalid JSON Number" Spring Data Mongo 2.0.2

** FIXED **
All I had to do is add an apostrophe before and after each argument index,
i.e, change:
#Query(value = "{'type': 'Application','name': ?0,'organizationId': ?1}", fields = "{_id:1}")
To:
#Query(value = "{'type': 'Application','name': '?0','organizationId': '?1'}", fields = "{_id:1}")
===================
I recently upgraded my MongoDB and my Spring-Data-MongoDB Driver.
I used to access my MongoDB through mongoRepository using this code:
#Query(value = "{'type': 'Application','name': ?0,'organizationId': ?1}", fields = "{_id:1}")
Policies findPolicyByNameAndOrganizationId(String name, String organizationId);
Where Policies is the object I want to consume.
After performing an update to Spring, I get the following Error now when accessing the method above:
org.bson.json.JsonParseException: Invalid JSON number
I fear this is because I use Spring's MongoCoverter (in the case of this specific object only) to map documents to object.
Here's is my Reader Converter:
public class ApplicationPolicyReadConverotor implements Converter<Document, ApplicationPolicy > {
private MongoConverter mongoConverter;
public ApplicationPolicyReadConverotor(MongoConverter mongoConverter) {
this.mongoConverter = mongoConverter;
}
//#Override
public ApplicationPolicy convert(Document source) {
ApplicationPolicyEntity entity = mongoConverter.read(ApplicationPolicyEntity.class, source);
ApplicationPolicy policy = new ApplicationPolicy();
addFields(policy, entity);
addPackages(policy, entity);
return policy;
}
And here's is my Writer Converter:
public class ApplicationPolicyWriteConvertor implements Converter<ApplicationPolicy, Document>{
private MongoConverter mongoConverter;
public ApplicationPolicyWriteConvertor(MongoConverter mongoConverter) {
this.mongoConverter = mongoConverter;
}
#Override
public Document convert(ApplicationPolicy source) {
System.out.println("mashuWrite");
ApplicationPolicyEntity target = new ApplicationPolicyEntity();
copyFields(source, target);
copyPackages(source, target);
Document Doc = new Document();
mongoConverter.write(target, Doc);
return Doc;
}
I checked Spring reference (2.0.2) regarding MongoConverter and how it works and at this stage I think I'm doing it correctly.
Other object who do not use mapping/conversions suffer no problems.
Same did this Object (ApplicationPolicy) untill I upgraded my mongo and my spring driver.
My mongodb is 3.4.10 and Spring data mongo driver is 2.0.2.
Here's the code that initializes the MappingMongoCoverter Object:
(Adds my custom Converters).
SimpleMongoDbFactory simpleMongoDbFactory = new SimpleMongoDbFactory(client, dbName);
DefaultDbRefResolver defaultDbRefResolver = new DefaultDbRefResolver(simpleMongoDbFactory);
MongoMappingContext mongoMappingContext = new MongoMappingContext();
MappingMongoConverter mappingMongoConverter = new MappingMongoConverter(defaultDbRefResolver,
mongoMappingContext);
mappingMongoConverter.setMapKeyDotReplacement("_dot_");
// Adding custom read and write converters for permission policy.
mappingMongoConverter.setCustomConversions(new MongoCustomConversions(Arrays.asList(
new ApplicationPolicyWriteConvertor(mappingMongoConverter), new ApplicationPolicyReadConverotor(
mappingMongoConverter))));
mappingMongoConverter.afterPropertiesSet();
final MongoTemplate template = new MongoTemplate(simpleMongoDbFactory, mappingMongoConverter);
return template;
I know for sure that ReaderConverter WORKS legit (at least in some cases) since other aspects of the software use the custom ReaderConverter I've written and it works as expected.
Also when using debug mode (Intellij) I do not reach to the conversion code block when invoking the following:
#Query(value = "{'type': 'Application','name': ?0,'organizationId': ?1}", fields = "{_id:1}")
Policies findPolicyByNameAndOrganizationId(String name, String organizationId);
So basically I'm kinda clueless. I have a sense my converter Implementation is messy but couldn't fix it..

How to unit test Spring IntegrationFlow?

I have been using Spring Integration DSL to implement some messaging processing flow.
How can I actually unit test a single IntegrationFlow, can anyone provide me with an example on how to unit test i.e. transform part of this bean:
#Bean
public IntegrationFlow transformMessage(){
return message -> message
.transform(new GenericTransformer<Message<String>, Message<String>>() {
#Override
public Message<String> transform(Message<String> message) {
MutableMessageHeaders headers =
new MutableMessageHeaders(message.getHeaders());
headers.put("Content-Type", "application/json");
headers.put("Accept", "application/json");
String payload = "Long message";
ObjectMapper mapper = new ObjectMapper();
HashMap<String, String> map = new HashMap<>();
map.put("payload", payload);
String jsonString = null;
try {
jsonInString = mapper.writeValueAsString(map);
} catch (JsonProcessingException e) {
logger.error("Error:" + e.getMessage());
}
Message<String> request = new GenericMessage<String>(jsonString
, headers);
return request;
}
})
.handle(makeHttpRequestToValidateAcdrMessage())
.enrichHeaders(h -> h.header("someHeader", "blah", true))
.channel("entrypoint");
}
How can I test it?
Regards!
Seems for me "unit testing" means check the behavior of the particular part of the system, some small component.
So, in your case it is about that new GenericTransformer.
so, just make it as a top-level component and perform tests against its isolated instances!
The integration tests can be performed against the target IntegrationFlow as well.
Each EIP-component in the flow definition is surrounded with
MessageChannels - input and output. Even if you don't declare .channel() there, the Framework build implicit DirrectChannel to wire endpoints to the flow.
Those implicit get the bean name like:
channelBeanName = flowNamePrefix + "channel" +
BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR + channelNameIndex++;
So, since your IntegrationFlow is from Lambda, the input channel form the .transform() is just input of the flow - transformMessage.input.
The channel between .transform() and the next .handle() has bean name like: transformMessage.channel#0, because it will be a first implicit channel declaration.
The idea that you can #Autowired both of this channels to your test-case and add ChannelInterceptor to them before testing.
The ChannelInterceptor may play verificator role to be sure that you send to the transformer and receive from the a proper data as it is expected.
More info can be found here: https://github.com/spring-projects/spring-integration-java-dsl/issues/23
The same techniques described in the testing-samples project in the samples repo can be used here.
The send a message to channel transform.input and subscribe to entrypoint to get the result (or change it to a QueueChannel in your test case.
Example of DSL IntegrationFlows testing is on github.

Stateless Bean Cannot Persist Simple Entity

All the code below resolves to one simple em.persist(entity) call that fails, when everything I read says this should work. Everything behaves as expected until I call em.persist().
Can anyone see where I'm going wrong?
My database is MySql.
The relevant MySql database is "godb".
It contains a table named "loggedins".
I used PK INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY to Create the table's primary key.
I used the Glassfish Admin Console to:
Configure a Glassfish JDBC Connection Pool named "GoSQLPool". I gave it additional properties so that when I PING it I get "Ping Successful".
And I Configured a JDBC Resource named "jdbc/go". It uses "GoSqlPool". Its JNDI name is "jdbc/go"
This is my persistance.xml file:
<persistence xmlns="http://java.sun.com/xml/ns/persistence"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0">
<persistence-unit name ="goDataBase">
<jta-data-source>jdbc/go</jta-data-source>
</persistence-unit>
</persistence>
persistence.xml is deployed in an ear package, which is where I read it's supposed to be:
go.ear
META-INF
application.xml
persistence.xml
go.war
go-server.jar
My entity bean is annotated as follows:
#Entity(name="LoggedIn")
#Table(name="loggedins")
public class LoggedIn extends EntityParent implements Serializable, DataItemsValues {
//constructors
public LoggedIn() {
this.id = ""; this.pw = ""; this.hash = "";
}
public LoggedIn(String id, String pw, String hash) {
this.id = id; this.pw = pw; this.hash = hash;
}
In case it matters, EntityParent is just an abstract class that reminds me I need to have get id, pw and hash methods in all entities whether they are for persisted fields or transient ones.
public abstract class EntityParent {
abstract public String getId ();
abstract public String getPw ();
abstract public String getHash();
}
My stateless java bean is annotated as follows:
#Stateless
public class LoggerBean {
#PersistenceContext(unitName = "goDataBase")
private EntityManager em;
This is the method in LoggerBean that throws the exception:
private Integer login (LoggedIn entity, String hash, String id,
String pw, StringBuffer sb)
throws GoExceptionServer {
U.upMarginS();
String iAm = U.getIAmS (Thread.currentThread ().getStackTrace ());
sb.append("\r\n" + iAm + "beg");
try {
sb.append("\r\n " + iAm + "persiting entity: " + entity);
///////////THIS IS THE ONLY NON PRINTING CODE///////////////////
this.em.persist(entity);
sb.append("\r\n" + iAm + "end");
U.downMarginS();
return null;
} catch (Exception e) {
sb.append("\r\n " + iAm + "caught: " + e.getClass().getName());
sb.append("\r\n " + iAm + "msg: " + e.getMessage());
sb.append("\r\n " + iAm + "cause : " + e.getCause());
sb.append("\r\n " + iAm + "Throwing a GoExceptionServer.");
sb.append("\r\n" + iAm + "end");
U.downMarginS();
throw new GoExceptionServer(MessageValues.MSG_KEY_UNEXPECTED_EXCEPTION);
}
This is the log output from the above system.out statements:
LoggerBean.login.............................beg
LoggerBean.login.............................persisting entity: LoggedInBean: PK(null) MBR_ID(G) MBR_PW(G)
LoggerBean.login.............................caught: java.lang.IllegalStateException
LoggerBean.login.............................msg: Unable to retrieve EntityManagerFactory for unitName goDataBase
LoggerBean.login.............................cause : null
LoggerBean.login.............................Throwing a GoExceptionServer.
LoggerBean.login.............................end
I'm lost. Can anyone suggest a way to make this work?
The fact that the LoggedIn entity has a null PK (primary key field) bothers me, but since the table auto-generates them I can't assign one before it is persisted.
Any suggestions or corrections are appreciated.
Everything seems to be OK, the error is that it is not possible to find configuration for goDataBase persistence unit. The file persistence.xml should be in folder META-INF, but according to your listing, the folder is named META_INF, which is not correct.

JUnit 4 API Get Handle to a #Test Method

Using JUnit 4 API, is there a way to get a handle to a method in a test class that are annotated with #Test?
Here's what I am currently doing:
JUnitCore core = new JUnitCore();
Request request = Request.aClass(MyTest.class);
Result result = core.run(request);
if(result.wasSuccessful())
System.out.println("SUCCESS"); // or do something else
This code will run all tests in MyTest. However, what I want is to just specify the test class name at the beginning (MyTest.class) and do following in a loop:
Get next #Test annotated test in the class.
Print details
Run the test (possibly using Request.method(MyTest.class, "myTestMethod")
I can perhaps use reflection to get the method names and check if they are annotated with Test, but wanted to see if the JUnit API already provides this functionality.
You can use TestClass:
public void runTests(Class<?> clazz) {
TestClass testClass = new TestClass(MyTest.class);
List<FrameworkMethod> tests = testClass.getAnnotatedMethods(
Test.class);
for (FrameworkMethod m : tests) {
String methodName = m.getName();
Request request = Request.method(clazz, methodName);
JUnitCore core = new JUnitCore();
Result result = core.run(request);
if (result.wasSuccessful())
System.out.println(m + ": SUCCESS");
}
}
}
Note that this is an inefficient way to run tests, especially if you have class rules or you use #BeforeClass or #AfterClass

Restlet POST Form to send to client resource via JSON

I am getting a 415 Error when sending a form entry to another client resource via JSON. The target URI in my code below ("/message") works when not using the form (i.e. hit "/message" with a test mock object).
Here is my code to get the values of the form and do the post to the target resource. Am I missing something that needs to be done?
I am using the following:
Restlet: 2.1 RC5
GAE: 1.6.1
Form Restlet:
#Post
public void handlePost(Representation entity) {
final Form webForm = new Form(entity);
MessageEntity newMessage = new MessageEntity();
String subject = webForm.getFirstValue("subject");
String sendto = webForm.getFirstValue("email");
String message = webForm.getFirstValue("message");
newMessage.setCategoryID(subject);
newMessage.setAccountID(sendto);
newMessage.setMessageText(message);
ClientResource cr = new ClientResource(getRootRef()+ "/message");
cr.post(newMessage, MediaType.APPLICATION_JSON);
}
Target Resource ("/message")
#Post("json")
public void HandleRequest(MessageEntity messageEntity) {
// Logic here
}
Please let me know if you need more information
Thanks!
I have code that is very similar to yours that works fine. I am also running similar versions of Restlet and GAE. First question I have is are there other #Post methods in your Target Resource as sometimes the ordering matters.
Here are two versions of code that I have that work....
1)
public Representation postHandler() {
Reference commitsRef = new Reference(Consts.RESOURCE_BASE + "commitments/");
ClientResource commitsResource = new ClientResource(getContext(), commitsRef);
....
Representation commitsRep = commitsResource.post(commitForm);
That is posting a form to a Target resource that handles both #Post("json") and #Post("form")
2)
public Representation doPostFromGet() {
Reference takeActRef = new Reference(Consts.RESOURCE_BASE + "commitment/"
+ commitmentId + "/userActs/");
ClientResource takeActResource = new ClientResource(getContext(), takeActRef);
...
Representation takeActRep = takeActResource.post(newAct);
That is posting a Java object to a form that uses what I call the "Peierls magic". See:
http://tembrel.blogspot.com/2012/03/converting-forms-in-restlet-to-pojos.html
It allows you to have one post() in the Target and accept both forms and pojos.
On a minor note, if you are doing a post to add a new message, should the url be "/messages/" (plural) - and perhaps there is a typo somewhere? (An unlikely possibility, but I thought I would mention it).
Good luck,
RB