camel-file component filter with cdi - apache-camel

I'm using camel without the Spring framework (using CDI instead).
How can I set a filter for the camel-file component?
My filter class looks like this:
#Named
#Stateless
public class MyFilter<T> implements GenericFileFilter<T> {
System.out.println("MyFilter was triggered");
.......
So I tried this:
<route>
<from uri="file://somewhere?filter=#myFilter"/>
<to uri="...."/>
</route>
But I'm getting:
java.lang.IllegalArgumentException: Could not find a suitable setter for
property: filter as there isn't a setter method with same type:
java.lang.String nor type conversion possible: No type converter
available to convert from type: java.lang.String to the required type:
org.apache.camel.component.file.GenericFileFilter with value #myFilter
What am I missing?
Update:
Please note that the bean is registered. If I use:
<to uri="ejb:java:global/Abc/MyFilter?method=accept"/>
then MyFilter was triggered is showing up in the log.
So the problem is about configuring the file component filter.

Update:
Since Camel-cdi uses JNDI-registry, the filter is configured like this:
filter=#java:global/Abc/MyFilter
Since I do not use Spring and the filter parameter is awaiting an instance and not only a classname, a TypeConverter is necessary
#Converter
public class MyGenericFileFilterConverter implements TypeConverters {
#Converter
public static GenericFileFilter toMYFilter(String filter){
return new MyFilter();
}
}

Did you add myFilter to your registry?
final CamelContext camelContext = getContext();
final org.apache.camel.impl.SimpleRegistry registry = new org.apache.camel.impl.SimpleRegistry();
final org.apache.camel.impl.CompositeRegistry compositeRegistry = new org.apache.camel.impl.CompositeRegistry();
compositeRegistry.addRegistry(camelContext.getRegistry());
compositeRegistry.addRegistry(registry);
((org.apache.camel.impl.DefaultCamelContext) camelContext).setRegistry(compositeRegistry);
registry.put("myFilter", new MyFilter());
That part should be in the configure method of your routeBuilder.

Related

Retrieve Max value from a field using Spring Data and MongoDB

I want to obtain the maximum value of the field code within my User entity, using Spring Data and MongoDB.
I have seen similar examples using as below,
".find({}).sort({"updateTime" : -1}).limit(1)"
But have no idea how to integrate it into my own repository using the #Query annotation.
Any alternative solution, than to return the maximum value of said field is also welcome.
Thank you.
You can write a custom method for your repository.
For example you have:
public interface UserRepository extends MongoRepository<User, String>, UserRepositoryCustom {
...
}
Additional methods for repository:
public interface UserRepositoryCustom {
User maxUser();
}
And then implementation of it:
public class UserRepositoryImpl implements UserRepositoryCustom {
#Autowired
private MongoTemplate mongoTemplate;
#Override
public User maxUser() {
final Query query = new Query()
.limit(1)
.with(new Sort(Sort.Direction.DESC, "updateTime"));
return mongoTemplate.findOne(query, User.class)
}
}
You can use the spring data method syntax like:
public User findTopByOrderByUpdateTimeAsc()
A reference can be found here: https://www.baeldung.com/jpa-limit-query-results#1first-ortop
Use this code in spring to get the latest updated time from mongodb: (mongoTemplate)
public List getTopPosts() {
Query query = new Query();
query.with(Sort.by(Sort.Direction.DESC, "postUploadedTime"));
return mongoTemplate.find(query,Post.class);
}

ApiTransformer for parametrized, unavailable type

I'm using Objectify and wish to have its Key<> type passed around in my API. I've created an ApiTransformer, but my questions is where to declare it, since the serialized Key<> class is not available, hence I cannot declare its transformer as a class annotation. I tried declaring it in the #Api annotation, but it doesn't work, I still get the error:
There was a problem generating the API metadata for your Cloud Endpoints classes: java.lang.IllegalArgumentException: Parameterized type com.googlecode.objectify.Key<[my package].User> not supported.
The ApiTransformer looks like:
public class KeyTransformer implements Transformer<Key<?>, String> {
public String transformTo(Key<?> in) {
return in.getString();
}
public Key<?> transformFrom(String in) {
return Key.valueOf(in);
}
}
And in my #Api I have:
#Api(name = "users", version = "v1",transformers = {KeyTransformer.class})
Unfortunately you can't. As you said you need to declare it on the Key class, your only chances to make this work are either.
1) Recompile the Key class for objectify with the #transformer annotation.
2) Extend the Key class with your own implementation and define the transformer there.
I don't really like any of those options so the way i usually resolve this is to hide the key object getter (by using #ApiResourceProperty(ignored=AnnotationBoolean.TRUE)) and only expose the id from that key.
That way you get a Endpoints frendly object, the only downside is you'll have to reconstitute the key using Key.create(YourClass.class, longId) manually whenever you need it.
You can add transforms to 3rd party classes by listing the transform in #Api annotation. I'm not dead sure it'll work parameterized class, but I don't see why not.
https://cloud.google.com/appengine/docs/java/endpoints/javadoc/com/google/api/server/spi/config/Api#transformers()

primefaces does not have the property 'handleDateSelect'

I just started using PrimeFaces and cannot figure what is wrong with my code. It is exactly the same as the show case sample with the exception of the bean names. I looked at this site for answers without success.
PrimeFaces:
<p:calendar value="#{securityForecastReturnBean.date}"
mode="inline" onSelectUpdate="inputsGrowl"
selectListener="#{securityForecastReturnBean.handleDateSelect}"
required="true" />
Java Bean:
#Component
#Scope("request")
#ManagedBean
public class SecurityForecastReturnBean {
public void handleDateSelect(DateSelectEvent event) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
FacesContext facesContext = FacesContext.getCurrentInstance();
facesContext.addMessage(null,
new FacesMessage(FacesMessage.SEVERITY_INFO, "Date Selected",
format.format(event.getDate())));
}
}
It should be really straightforward yet it is saying that my bean does not have this property??
Here is the exact error message:
javax.servlet.ServletException: /security_page.xhtml: The class 'com.ls.forecast.webui.beans.SecurityForecastReturnBean' does not have the property 'handleDateSelect'.
javax.faces.webapp.FacesServlet.service(FacesServlet.java:325)
com.sun.faces.context.ExternalContextImpl.dispatch(ExternalContextImpl.java:546)
com.sun.faces.application.view.JspViewHandlingStrategy.executePageToBuildView(JspViewHandlingStrategy.java:363)
com.sun.faces.application.view.JspViewHandlingStrategy.buildView(JspViewHandlingStrategy.java:154)
com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:100)
com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139)
javax.faces.webapp.FacesServlet.service(FacesServlet.java:313)
I am using PrimeFaces 2.2.1.
Any help would be greatly appreciated!
I figured out my issue. It had to do with using the wrong namespace. I had to use http://primefaces.org/ui instead of the old one.
This looks like it might be an error in the documentation:
From the Primefaces Guide 2.2:
Ajax Selection
Calendar supports instant ajax selection which means whenever a date is selected a server side
selectListener can be invoked with an org.primefaces.event.DateSelectEvent instance as a
parameter. Optional onSelectUpdate option allows updating other component(s) on page.
<p:calendar value="#{calendarBean.date}" onSelectUpdate="messages"
selectListener="#{calendarBean.handleDateSelect}" />
<p:messages id="messages" />
public void handleDateSelect(DateSelectEvent event) {
Date date = event.getDate();
//Add facesmessage
}
Programatically it seems to expect a property on the managed bean. You can try changing it to this and see if it makes a difference #{calendarBean.handleDateSelect()}. Are you absolutely sure that you are not referencing handleDateSelect elsewhere in the markup?
The source code example given in the PrimeFaces Showcase is wrong. The method should not be taking org.primefaces.event.SelectEvent, it should be taking org.primefaces.event.DateSelectEvent. A quick change to the source code example now looks like this:
public void handleDateSelect(DateSelectEvent event) {
FacesContext facesContext = FacesContext.getCurrentInstance();
SimpleDateFormat format = new SimpleDateFormat("d/M/yyyy");
facesContext.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Date Selected", format.format(event.getDate())));
}

Camel - extend Java DSL?

I've got a repeating pattern in my routes - a certain Processor needs the same 3 Headers set every time I call it, so I've got the following code in my routes about 10+ times:
.whatever()
.setHeader("foo1", "bar1")
.setHeader("foo2", "bar2")
.setHeader("foo3", "bar3")
.processRef("processorBazThatNeedsHeaders")
.whatever()
The headers are populated differently every time, so abstracting this out into a subroute doesn't really buy me anything.
What I love to be able to do is subclass RouteDefinition to have another method in my DSL that would allow me to do this:
.whatever()
.bazProcessor("bar1", "bar2", "bar3")
.whatever()
and in 'bazProcessor', set the headers and call the processor.
I've tried to do this but it seems that it's only possible with some serious probably-not-future-proof surgery, and it seems that others have had similar luck.
I need them to be set as headers as opposed to passing them as parameters directly to the processor because the values are also used after the processor for routing.
Is there some hidden facility to achieve something like this?
By subclassing the RouteDefinition your extension will only be visible direct after from(...). This could be a limitation if you would like to use the DSL extension for example after the filter(...) DSL.
A simpler approach would be to encapsulate the logic somewhere, and use it in a class that implements the org.apache.camel.Processor interface, and then call an overload of .process(...), or bean(...) in the route to use the logic. You will be actually very closed to a DSL extension if you use a meaningful name for the Processor instance or a method, that returns that Processor instance. Here is an example of the suggested approach. At the end, your code could look like:
.whatever()
.process(setTheHeadersForBaz)
.whatever()
Just for reference: if you really need to do a DSL, there is a project that extends the Camel DSL based on Groovy. I guess a Scala way based on the Camel Scala DSL could be also an option.
Though slightly irrelevant, following is an example of extending Scala DSL.
We can create an implicit methods to DSL trait via an implicit class.
object DSLImplicits {
implicit class RichDSL(val dsl: DSL) {
def get = dsl.setHeader(Exchange.HTTP_METHOD, _ => HttpMethods.GET.name)
def post = dsl.setHeader(Exchange.HTTP_METHOD, _ => HttpMethods.POST.name)
}
}
And use it like this.
import DSLImplicits.RichDSL
//----------------------------
from("someWhere")
//Do some processing
.get.to("http://somewhere.com")
More details #
http://siliconsenthil.in/blog/2013/07/11/apache-camel-with-scala-extending-dsl/
So you only set the headers because you want the Processor to have access to those values?
If so then a simple example using a Factory could look like this:
whatever()
.process(BazProcessorFactory.instance("bar1", "bar2", "bar3"))
.whatever()
Where the BazProcessorFactory is just a wrapper around your Processor:
public class BazProcessorFactory {
public Processor instance(final String...vals) {
return new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
//access your array of values here
System.out.println("Foo1 = "+vals[0]);
}
}
}
}

How to call getServletContext() equivalent in AppEngineMapper derived class?

I have a Mapper class which extends AppEngineMapper<Key, Entity, NullWritable, NullWritable>.
Now inside my map function (public void map(Key key, Entity value, Context context)), I need to get access to PersistenceManager. To get singleton PersistenceManager, I need ServletContext object.
Typically, in a HTTPServlet extended class, I call getServletContext() and pass it to get PersistenceManager object. But in Mapper extended class, I don't have or can call getServletContext().
Can anyone advice on how to get servletcontext in my mapper class or if there is a way to pass servlet context from my servlet to Mapper extended class? I am using auto-mapreduce (programmatically) through a cron job.

Resources