Apache Camel: Instantiate a class using its multiparameter constructor - apache-camel

How do I go about invoking a method on a class object by having it instantiated with its multiparameter constructor in a Camel route using Spring DSL with bean binding first?
For example this one:
package org.my.package;
public class SomeClass {
public SomeClass() {}
public SomeClass(String param1, String param2) {
...
}
public void doSomething() {
}
}
Method invokation using the default (no-args) constructor is clear:
<to uri="bean:org.my.package.SomeClass?method=doSomething" />

You can instantiate a class instance only using default no-argument constructor. But you can use bean properties for set class fields.
Bean
<bean class="org.my.pack.SomeClass" factor:bean-type="DEFAULT"
id="SomeClass" name="SomeClass">
<property name="param1" value="Value1"/>
<property name="param2" value="Value2"/>
</bean>
Class
package org.my.pack;
public class SomeClass {
public String param1;
public String param2;
public String getParam1() {
return param1;
}
public void setParam1(String param1) {
this.param1 = param1;
}
public String getParam2() {
return param2;
}
public void setParam2(String param2) {
this.param2 = param2;
}
public String doSomething() {
return "Param1 - " + param1 + " Param2 - " + param2;
}
public static void main(String[] args) {
}
}
Or you can also use annotations for method parameters and take values from headers for example (https://camel.apache.org/manual/latest/parameter-binding-annotations.html)
public String doSomething(#Header("param1") String param1, #Header("param2") String param2) {
return "Param1 - " + param1 + " Param2 - " + param2;
}

Related

camel jpa #Consumed is not being called

I'm trying to use #Consumed on jpa entity with camel.
this is my route :
<route id="incomingFileHandlerRoute">
<from
uri="jpa://com.menora.inbal.incomingFileHandler.Jpa.model.MessageToDB?consumer.nativeQuery=select
* from file_message where mstatus = 'TODO'&consumer.delay=5000&consumeDelete=false&consumeLockEntity=true&consumer.SkipLockedEntity=true" />
<to uri="bean:incomingFileHandler" />
</route>
and my entity:
#Entity
#Table(name = "file_message")
public class MessageToDB implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
private String uuid;
private String fileName;
private String body;
private String mstatus;
#Temporal(TemporalType.TIMESTAMP)
private Date mtimestamp;
#Consumed
public void updateMstatus() {
setMstatus(MessageStatus.DONE.name());
}
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public String getMstatus() {
return mstatus;
}
public void setMstatus(String mstatus) {
this.mstatus = mstatus;
}
public Date getMtimestamp() {
return mtimestamp;
}
public void setMtimestamp(Date mtimestamp) {
this.mtimestamp = mtimestamp;
}
}
I do get to incomingFileHandler bean with results from db but I do not get to the Consumed method updateMstatus . The incomingFileHandler bean is getting called continuously as always there are results from db
I have a similar implementation with camel-jpa and annotations #Consumed and #PreConsumed in the entity but none of these methods is called.
I look the camel-jpa source code and found this in JpaConsumer.java:
protected DeleteHandler<Object> createPreDeleteHandler() {
// Look for #PreConsumed to allow custom callback before the Entity has been consumed
final Class<?> entityType = getEndpoint().getEntityType();
if (entityType != null) {
// Inspect the method(s) annotated with #PreConsumed
if entityType is null the entity class inst inspect the method annotated with #Consumed and #PreConsumed.
Solution: add entityType=com.xx.yy.MessageToDB to your URI to set Endpoint Entity type.

testng how to dynamically set groups from Factory?

Before I setup a test class like the code below:
1. the Factory and test Dataprovider both used excel as the dataprovider.
2. In the Factory dataprovider table, it has a list of url
3. Each time, it will find one of the url in the factory dataprovider table, and run the test in each test methods..
public class Test {
WebDriver driver;
private String hostName;
private String url;
#Factory(dataProvider = "xxxx global variables", dataProviderClass = xxxx.class)
public GetVariables(String hostName, String url) {
this.hostName = hostName;
this.url = url;
}
#BeforeMethod
#Parameters("browser")
public void start(String browser) throws Exception {
driver = new FirefoxDriver();
driver.get(url);
Thread.sleep(1000);
}
#Test(priority = 10, dataProvider = "dataprovider Test A", dataProviderClass = xxx.class)
public void TestA(Variable1,
Variable2,Variable3) throws Exception {
some test here...
}
#Test(priority = 20, dataProvider = "dataprovider Test B", dataProviderClass = xxx.class)
public void TestB(Variable1,
Variable2,Variable3)
throws Exception {
some test here...
}
#AfterMethod
public void tearDown() {
driver.quit();
}
Now I want to dynamically assign different group for each test for different url. I am thinking add a variable 'flag' in the #Factory dataprovider:
#Factory(dataProvider = "xxxx global variables", dataProviderClass = xxxx.class)
public GetVariables(String hostName, String url, String flag) {
this.hostName = hostName;
this.url = url;
this.flag = flag;
}
That when flag.equals("A"), it will only run test cases in test groups={"A"}.
When flag.equals("B"), it will only run test cases in test groups ={"B"},
When flag.equals("A,B"), it will only run test cases in test groups ={"A","B"}
Is there any way I can do that?
Thank you!
TestNG groups provides "flexibility in how you partition your tests" but it isn't for conditional test sets. For that you simply use plain old Java.
You can use inheritance or composition (I recommend the latter, see Item 16: Favor composition over inheritance from Effective Java).
Either way the general idea is the same: use a Factory to create your test class instances dynamically creating the appropriate class type with the appropriate test annotations and/or methods that you want to run.
Examples:
Inheritance
import org.testng.annotations.Factory;
import org.testng.annotations.Test;
public class DemoTest {
#Factory
public static Object[] createTests() {
return new Object[]{
new FlavorATest(),
new FlavorBTest(),
new FlavorABTest()
};
}
/**
* Base test class with code for both A-tests and B-tests.
*
* Note that none of these test methods are annotated as tests so that
* subclasses may pick which ones to annotate.
*/
public static abstract class BaseTest {
protected void testA() {
// test something specific to flavor A
}
protected void testB() {
// test something specific to flavor B
}
}
// extend base but only annotate A-tests
public static class FlavorATest extends BaseTest {
#Test
#Override
public void testA() {
super.testA();
}
}
// extend base but only annotate B-tests
public static class FlavorBTest extends BaseTest {
#Test
#Override
public void testB() {
super.testB();
}
}
// extend base and annotate both A-tests and B-tests
public static class FlavorABTest extends BaseTest {
#Test
#Override
public void testA() {
super.testA();
}
#Test
#Override
public void testB() {
super.testB();
}
}
}
Composition
import org.testng.annotations.Factory;
import org.testng.annotations.Test;
public class DemoTest {
#Factory
public static Object[] createTests() {
return new Object[]{
new FlavorATest(),
new FlavorBTest(),
new FlavorABTest()
};
}
private static void testA() {
// test something specific to flavor A
}
private static void testB() {
// test something specific to flavor B
}
// only create A-test methods and delegate to shared code above
public static class FlavorATest {
#Test
public void testA() {
DemoTest.testA();
}
}
// only create B-test methods and delegate to shared code above
public static class FlavorBTest {
#Test
public void testB() {
DemoTest.testB();
}
}
// create A-test and B-test methods and delegate to shared code above
public static class FlavorABTest {
#Test
public void testA() {
DemoTest.testA();
}
#Test
public void testB() {
DemoTest.testB();
}
}
}
Your factory methods won't be as simple as you'll need to use your "flag" from your test data to switch off of and create instances of the appropriate test classes.

Objectify throws IllegalArgumentException: No class 'com.app.db.client.model.ProductType' was registered

I am using Objectify 5.1.7 with Objectify Spring extension in my Spring-MVC application.
Here are my entity classes:
Product.java
#Entity
public class Product extends RelatedDataObject {
#Parent
private Ref<Vendor> vendor;
#Load
private Ref<ProductCategory> productCategory;
#Load
private Ref<ProductType> productType;
#Index
private String nativeId;
private Double costPrice;
private String modelId;
private String serviceLocations;
private Map<String, String> attributes;
public Double getCostPrice() {
return costPrice;
}
public String getModelId() {
return modelId;
}
public String getServiceLocations() {
return serviceLocations;
}
public Map<String, String> getAttributes() {
return attributes;
}
public void setCostPrice(Double costPrice) {
this.costPrice = costPrice;
}
public void setModelId(String modelId) {
this.modelId = modelId;
}
public void setServiceLocations(String serviceLocations) {
this.serviceLocations = serviceLocations;
}
public void setAttributes(Map<String, String> attributes) {
this.attributes = attributes;
}
public void addAttribute(String key, String value) {
if(key == null || value == null) {
throw new IllegalArgumentException("Key or value is null.");
}
if(attributes == null) {
attributes = new HashMap<String, String>();
}
attributes.put(key, value);
}
public ProductCategory getProductCategory() {
return productCategory.get();
}
public ProductType getProductType() {
return productType.get();
}
public String getNativeId() {
return nativeId;
}
public void setNativeId(String nativeId) {
this.nativeId = nativeId;
}
public void setProductCategory(ProductCategory productCategory) {
this.productCategory = Ref.create(productCategory);
}
public void setProductType(ProductType productType) {
this.productType = Ref.create(productType);
}
public Vendor getVendor() {
return vendor.get();
}
public void setVendor(Vendor vendor) {
this.vendor = Ref.create(vendor);
}
public Key<Product> getKeyByParentVendor() {
if (getId() == null) {
throw new IllegalArgumentException("Product id is not set.");
}
if (vendor == null) {
throw new IllegalArgumentException("Parent vendor is not set.");
}
return Key.create(this.vendor.key(), Product.class, getId());
}
}
ProductType.java
#Entity
public class ProductType extends RelatedDataObject {
}
RelatedDataObject.java
public class RelatedDataObject extends DataObject {
private String description;
private boolean approved;
public RelatedDataObject() {
super();
approved = false;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public boolean isApproved() {
return approved;
}
public void setApproved(boolean approved) {
this.approved = approved;
}
}
DataObject.java
public class DataObject {
#Id
private String id;
#Index
private String name;
private boolean inactive;
public DataObject() {
super();
inactive = false;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public void setId(String id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public boolean isInactive() {
return inactive;
}
public void setInactive(boolean inactive) {
this.inactive = inactive;
}
}
And here is my spring bean xml configuration. All my entity classes are inside the package: com.app.db.client.client.model
<bean id="objectifyFactory" class="com.googlecode.objectify.spring.ObjectifyFactoryBean">
<property name="basePackage" value="com.app.db.client.model"/>
</bean>
<bean id="dbClient" class="com.app.db.client.impl.DbClientImpl">
<property name="objectifyFactory" ref="objectifyFactory"/>
</bean>
DBClientImpl.java
public class DbClientImpl implements DbClient {
private ObjectifyFactory objectifyFactory;
public void setObjectifyFactory(ObjectifyFactory objectifyFactory) {
this.objectifyFactory = objectifyFactory;
}
#Override
public <T extends DataObject> void createObject(T object) {
Objectify ofy = objectifyFactory.begin();
ofy.save().entity(object).now();
}
}
When the GAE devserver boots my spring MVC application, all entity classes are loaded. Here are the log messages:
[INFO] 2015-09-10 13:20:15 INFO ObjectifyFactoryBean:115 - Registered entity class [com.app.db.client.model.Product]
[INFO] 2015-09-10 13:20:15 INFO ObjectifyFactoryBean:115 - Registered entity class [com.app.db.client.model.ProductCategory]
[INFO] 2015-09-10 13:20:15 INFO ObjectifyFactoryBean:115 - Registered entity class [com.app.db.client.model.ProductType]
[INFO] 2015-09-10 13:20:15 INFO ObjectifyFactoryBean:115 - Registered entity class [com.app.db.client.model.Vendor]
When I try to save Product entity:
Product product = new Product();
product.setName("new product");
product.setProductType(productType);
product.setProductCategory(productCategory);
product.setNativeId(productNativeId);
product.setCostPrice(createProductParam.getCostPrice());
dbclient.createObject(product);
I get this error from Objectify:
[INFO] java.lang.IllegalArgumentException: No class 'com.app.db.client.model.ProductType' was registered
[INFO] at com.googlecode.objectify.impl.Registrar.getMetadataSafe(Registrar.java:120)
[INFO] at com.googlecode.objectify.impl.Keys.getMetadataSafe(Keys.java:53)
[INFO] at com.googlecode.objectify.impl.Keys.getMetadataSafe(Keys.java:62)
[INFO] at com.googlecode.objectify.impl.Keys.rawKeyOf(Keys.java:36)
[INFO] at com.googlecode.objectify.impl.Keys.keyOf(Keys.java:29)
[INFO] at com.googlecode.objectify.Key.create(Key.java:62)
[INFO] at com.googlecode.objectify.Ref.create(Ref.java:31)
[INFO] at com.app.db.client.model.Product.setProductType(Product.java:93)
Please help me resolve this problem.
I have got the same Issue and solved as in below steps.
1) Write your own ObjectifyFactoryBean (Just copy from https://github.com/marceloverdijk/objectify-appengine-spring) and update one line in afterPropertiesSet() method.
this.objectifyFactory = new ObjectifyFactory();
// Set the factory to ObjectifyService
ObjectifyService.setFactory(objectifyFactory);
2) Use this to in spring
<bean id="objectifyFactory" class="com.yourcompany.ObjectifyFactoryBean" >
<property name="basePackage" value="com.yourcompany.model" />
</bean>
3) Use objectifyFactory in your DAO classes as spring bean.
4) Add the Filter in your web.xml.
<!-- ObjectifyFilter filter -->
<filter>
<filter-name>objectifyFilter</filter-name>
<filter-class>com.googlecode.objectify.ObjectifyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>objectifyFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Explanation : I don't know how old version of Objectify work and based on that ObjectifyFactoryBean written, but in latest version of Objectify 5.x it internally use ObjectifyService in Ref operation, which was using the different objectifyFactory instance, So to make it use the same instance of objectifyFactory in whole application, we have set ObjectifyService.setFactory(objectifyFactory) inside our ObjectifyFactoryBean class.
A filter ObjectifyFilter is also require in web application, because this filter will make call to ObjectifyService.begin() for Objectify session, Normally we call ObjectifyService.begin() only when we do Datastore Operation and but is case of like Ref operation, ObjectifyFilter will do this job for us.
Hope this solve the issue!
The spring extension hasn't been updated since 2012 so it's entirely possible that it does not work with current versions of Objectify. I don't know - I would contact the author.
The problem is that your ProductType entity has not been registered. Presumably the spring extension is supposed to do that but isn't.
Like #stickfigure already mentioned this library hasn't been updated for a long time. That said the Objectify version it depends on - and tested with - is 2.2.x.
However from your logging it seems that the entities have been registered.
To verify if it works with the latest Objectify version you could:
clone the lib from https://github.com/marceloverdijk/objectify-appengine-spring
update the objectify version
run the tests
If that works you at least know the lib works with the latest Objectify version.

Get custom attribute on method from Castle Windsor interceptor

I am trying to access a custom attribute applied to a method within a castle interceptor, but method Attribute.GetCustomAttribute() return null.
public class MyIntecept : Castle.DynamicProxy.IInterceptor
{
public void Intercept(IInvocation invocation)
{
// myAttr is null.
var myAttr = (MyAttribute)Attribute.GetCustomAttribute(
invocation.Method, typeof(MyAttribute));
}
}
[AttributeUsage(AttributeTargets.All, Inherited = true, AllowMultiple = true)]
public class MyAttribute : Attribute
{
readonly string _value;
public MyAttribute(string value)
{
this._value = value;
}
public string Value
{
get { return this._value; }
}
}
public interface IMyInterface
{
void Do();
}
public class MyClass : IMyInterface
{
[MyAttribute("MyValue")]
public void Do()
{
Console.WriteLine("Do");
}
}
How can i get 'MyAttribute'?
P.S. I'am using Castle.Core 3.3.3
Put the attribute "MyAttribute" on the method inside the interface and not inside the class

Camel Velocity Template - access java object properties

I have a camel route which uses Velocity template and in the body I have an object defined as following:
class MailImpl extends AbstractMail{
private BodyContext bodyContext;
public BodyContext getBodyContext() {
return bodyContext;
}
public void setBodyContext(BodyContext bodyContext) {
this.bodyContext = bodyContext;
}
private String test;
public String getTest() {
return test;
}
public void setTest(String test) {
this.test = test;
}
#Override
public String toString() {
return "MailImpl{" +
"bodyContext=" + bodyContext +
'}';
}
}
class BodyContext{
private String value;
public BodyContext(String value) {
this.value = value;
}
public BodyContext() {
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
#Override
public String toString() {
return "BodyContext{" +
"value='" + value + '\'' +
'}';
}
In the velocity template I would like to access the MailImpl object properties, for example I use ${body.test} and ${body.bodyContext.value} but velocity template does not transform those values (it returns as string ${body.test} and ${body.bodyContext.value}).
One solution could be creating headers for each of of the value I need to use in the template, but as my route is dynamic (I select velocity template based on header) I would like to access the body properties in the velocity context. Is this somehow possible?
You can setup a custom Velocity Context by setting the message header "CamelVelocityContext" (since Camel v2.14). From Camel's test case:
Map<String, Object> variableMap = new HashMap<String, Object>();
Map<String, Object> headersMap = new HashMap<String, Object>();
headersMap.put("name", "Willem");
variableMap.put("headers", headersMap);
variableMap.put("body", "Monday");
variableMap.put("exchange", exchange);
VelocityContext velocityContext = new VelocityContext(variableMap);
exchange.getIn().setHeader(VelocityConstants.VELOCITY_CONTEXT, velocityContext);
exchange.setProperty("item", "7");
With following template:
Dear ${headers.name}. You ordered item ${exchange.properties.item} on ${body}.
You get:
Dear Willem. You ordered item 7 on Monday.

Resources