Change camel route parameters at runtime - apache-camel

I want to transfer file from endpoint A to endpoint B depending on actual date.
myFileNamePattern=
String.format("(.)*%s.json",LocalDate.now().format("yyyymmdd"));
from("endpointA").filter((header(AWS2S3Constants.KEY).regex(myFileNamePattern))).to("endpointB);
The route will only consume files that have the same date as the creation date of the route and won't transfer files for next dates.
What can I do to change the date in my file name pattern at runtime without stopping and restarting the route ?

If the pattern is dynamic, you could (for instance) use a bean to implement the filtering logic:
MyDynamicFilter mdf = new MyDynamicFilter();
from("endpointA")
.filter().method(mdf, "withSameDate")
.to("...);
public MyDynamicFilter {
private String pattern;
public synchronized void updatePattern(String newPattern) {
this.pattern = newPattern;
}
public boolean withSameDate(#Header(AWS2S3Constants.KEY) String header) {
... // compare with this.pattern
}
}

Related

Calling a camel route using Producer Template

My use case is based on the rest controller input I need to fetch or move files from different source system to destination system.
Route :-
#Component
public class MoveFile extends RouteBuilder {
#override
public void configure() throws Exception {
from("file:tmp/${header.inPath}")
.to("file:/tmp${header.outPath}?fileName=${header.fileName}")
.setBody().constant("File - ${header.inPath}/${header.fileName} Moved Succesfully")
}
}
My rest controller will pass the jobName along the getMapping to invoke this specific route inPath , outPath and File Names
#Resource(name=RouteProperties)
private Prosperties props;
#GetMapping("/runJob/{jobToInvoke}")
public String runJob (#PathVariable final String jobToInvoke){
String inPath=props.getProperty("inPath"+jobToInvoke)
String outPath=props.getProperty("outPath"+jobToInvoke)
String fileName=props.getProperty("fileName"+jobToInvoke)
String jobStatus = ProducerTemplate.withHeader("inPath",inPath)
.
.
.to(??)
.request(String.class)
}
I need help to use Producer Template to pass the properties using to ?
I tried some search on the google, but there is an example available in youtube (link) , But in that Video it is calling uri , (Direct:sendMessage) and from in the route also has that.
How to handle in this scenario ?
Thanks in Advance
A route beginning with a direct: endpoint can be invoked programmatically from Java code. In the route, the pollEnrich component invokes a consumer endpoint to read a file and replace the exchange message body with the file contents.
from("direct:start")
.pollEnrich().simple("file:/tmp?fileName=${header.inPath}")
.toD("file:/tmp?fileName=${header.outPath}")
.setBody().simple("File - ${header.inPath} Moved Successfully");
To invoke the route from Java code:
String jobStatus = producerTemplate.withHeader("inPath", inPath)
.withHeader("outPath", outPath)
.to("direct:start")
.request(String.class);
I don't know if these dynamic file URIs in from work, but at least the Camel File documentation states
Also, the starting directory must not contain dynamic expressions with
${ } placeholders. Again use the fileName option to specify the
dynamic part of the filename.
So the docs are suggesting to change
from("file:tmp/${header.inPath}")
into
from("file:tmp?fileName=${header.inPath}")
The fileName option can be a relative path (not just a filename).
If that change works for you, your question becomes obsolete because the route URI is no more dynamic.
.withHeader("inPath",inPath)
.to("file:tmp")

Dynamic Apache Camel Output Route

Hi i want to compute a dynamic output route using apache Camel. I receive a bunch of files in a folder location, based on its contents i want to move the file to dynamic output folder. The name of the ouput folder will be constructed based on the input content of the file. How do i acheive it.
The Following piece of code read the files, processes them, but i am not sure how to set the value of ${foldername} based on the contents of the file
from("file:D:\\camel\\input\\one?recursive=true&delete=true")
.process(new LogProcessor())
.to("file:D:\\camel\\output\\${foldername}")
Please assist
You could create a custom processor to construct the foldername and insert into a header.
public class DirectoryNameProcessor implements Processor {
#Override
public void process(Exchange exchange) {
Message in = exchange.getIn();
// Get the contents of the processed file
String body = in.getBody(String.class);
//Get the original file name
String fileName = in.getHeader("CamelFileName", String.class);
// Perform your logic
in.setHeader("foldername");
}
}
Then in your route you could access the newly created foldername-header:
.to("file:D:\\camel\\output\\${header.foldername}");
The short answer is, you can use the dynamic to endpoint toD.
http://camel.apache.org/message-endpoint.html#MessageEndpoint-DynamicTo
It would look like:
from("file:D:\\camel\\input\\one?recursive=true&delete=true")
.process(new LogProcessor())
.toD("file:D:\\camel\\output\\${foldername}")

Camel File component - skip file

I'm using the camel file component to poll files from a directory.
Before I can handle a file some conditions have to be satisfied,
if not camel should skip the file without deleting/moving it and
go to the next one.
To do this I use this:
public InputStream myMethod(#Body InputStream is, #Headers .....) {
if( !checkPrerequisites )
throw new MyRuntimeException("conditions not satisfied yet");
So I'm wondering if there is another way to archive the desired behaviour.
You could implement a GenericFileFilter. Create the filter, like so:
public class AnotherFileExistsFilter<T> implements GenericFileFilter<T> {
#Override
public boolean accept(GenericFile<T> firstFile) {
return Files.exists(Paths.get("/some/other/folder/" + firstFile.getFileName()));
}
}
Add it to your endpoint using filter=#anotherFileExistsBeanName.
If you want to keep checking the file, set idempotent=false, and I recommend setting a delay (delay=xxx in ms) in order to not poll the folder continuously.
More details are on the Apache Camel File2 page.

What is the best way to store user specific files in Wicket?

I am creating a file that is user specific. This file is basically a results csv that is created with the option for the user to download or not. When the user leaves the page, or ends their session I want to be able to delete this file. What is the best way to handle this?
Currently I am using the File class for Java.
Thanks!
You don't have to write a file in the first place. Create the content on the fly and stream it back to the client. Wicket has a few classes in the package org.apache.wicket.request.resource to help with that.
As a starting point, look at Wicket 6 resource management and Wicket 1.5 Mounting resources
You basically mount a resource in the WicketApplication.init():
mountResource("somePath/${param1}/${param2}", new SomeResourceReference());
Than the SomeResourceReference:
public class SomeResourceReference extends ResourceReference {
#Override
public IResource getResource() {
return new SomeResource();
}
}
And finally in SomeResource:
public class SomeResource extends AbstractResource {
#Override
public AbstractResource.ResourceResponse
newResourceResponse(Attributes attributes) {
// get the parameters
PageParameters parameters = attributes.getParameters();
final String param1 = parameters.get("param1").toStringObject();
AbstractResource.ResourceResponse response
= new AbstractResource.ResourceResponse();
response.setContentType("application/CSV");
response.setCacheDuration(Duration.NONE);
response.setCacheScope(WebResponse.CacheScope.PRIVATE);
response.setContentDisposition(ContentDisposition.INLINE);
response.setWriteCallback(new AbstractResource.WriteCallback() {
#Override
public void writeData(final Attributes attributes) throws IOException {
// create your data here
attributes.getResponse().write(dataAsString);
}
});
return response;
}
}
Wicket doesn't control destroying the session. It is the concern of the servlet container you are using.
If you want to create a file in Wicket and delete the file when the session is destroyed or user want logout, it has two parts:
User logout (in Wikcet)
Store the file path or the file reference in the WebSession (Wicket)
Override the method invalidate() of your WebSession or AutheticatedWebSession, see http://ci.apache.org/projects/wicket/apidocs/6.x/org/apache/wicket/protocol/http/WebSession.html#invalidate%28%29
Session destroyed
Store the file path or the file reference into the container session and write your listener and add it to the your servlet context (e.g. tomcat using web.xml file).
See http://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpSessionListener.html

Storing the Cursor for App Engine Pagination

I'm trying to implement pagination using App Engine's RPC and GWT (it's an app engine connected project).
How can I pass both the query results and the web-safe cursor object to the GWT client from the RPC?
I've seen examples using a servlet but I want to know how to do it without a servelt.
I've considered caching the cursor on the server using memcache but I'm not sure if that's appropriate or what should be used as the key (session identifier I would assume, but I'm not sure how those are handled on App Engine).
Links to example projects would be fantastic, I've been unable to find any.
OK, so the best way to do this is to store the cursor as a string on the client.
To do this you have to create a wrapper class that is transportable so you can pass back it to the client via RequestFactory that can hold the results list and the cursor string. To do that you create a normal POJO and then a proxy for it.
here's what the code looks like for the POJO:
public class OrganizationResultsWrapper {
public List<Organization> list;
public String webSafeCursorString;
public List<Organization> getList() {
return list;
}
public void setList(List<Organization> list) {
this.list = list;
}
public String getWebSafeCursorString() {
return this.webSafeCursorString;
}
public void setWebSafeCursorString(String webSafeCursorString) {
this.webSafeCursorString = webSafeCursorString;
}
}
for the proxy:
#ProxyFor(OrganizationResultsWrapper.class)
public interface OrganizationResultsWrapperProxy extends ValueProxy{
List<OrganizationProxy> getList();
void setList(List<OrganizationProxy> list);
String getWebSafeCursorString();
void setWebSafeCursorString(String webSafeCursorString);
}
set up your service and requestFactory to use the POJO and proxy respectively
// service class method
#ServiceMethod
public OrganizationResultsWrapper getOrganizations(String webSafeCursorString) {
return dao.getOrganizations(webSafeCursorString);
}
// request factory method
Request<OrganizationResultsWrapperProxy> getOrganizations(String webSafeCursorString);
Then make sure and run the RPC wizard so that your validation process runs otherwise you'll get a request context error on the server.
Here's the implementation in my data access class:
public OrganizationResultsWrapper getOrganizations(String webSafeCursorString) {
List<Organization> list = new ArrayList<Organization>();
OrganizationResultsWrapper resultsWrapper = new OrganizationResultsWrapper();
Query<Organization> query = ofy().load().type(Organization.class).limit(50);
if (webSafeCursorString != null) {
query = query.startAt(Cursor.fromWebSafeString(webSafeCursorString));
}
QueryResultIterator<Organization> iterator = query.iterator();
while (iterator.hasNext()) {
list.add(iterator.next());
}
resultsWrapper.setList(list);
resultsWrapper.setWebSafeCursorString(iterator.getCursor().toWebSafeString());
return resultsWrapper;
}
a second option would be to save the webSafeCursorString in the memcache, as you already mentioned.
my idea looks like this:
the client sends always request like this "getMyObjects(Object... myParams, int maxResults, String clientPaginationString)". the clientPaginationString is uniquely created like shown below
server receives request and looks into the memcache if there is a webSafeCursorString for the key clientPaginationString
if the server finds nothing, he creates the query and save the webSafeCursorString into memcache with the clientPaginationString as the key. -> returns the results
if the server finds the webSafeCursorString he restarts the query with it and returns the results
the problems are how to clean the memcache and how to find a unique clientPaginationString:
a unique clientPaginationString should be the current UserId + the params of the current query + timestemp. this should work just fine!
i really can't think of a easy way how to clean the memcache, however i think we do not have to clean it at all.
we could store all the webSafeCursorStrings and timestemps+params+userid in a WebSafeCursor-Class that contains a map and store all this in the memcache... and clean this Class ones in a while (timestamp older then...).
one improvement i can think of is to save the webSafeCursorString in the memcache with a key that is created on the server (userSessionId + servicename + servicemethodname + params). however, important is that the client sends an information if he is interested in a new query (memcache is overriden) or wants the next pagination results (gets webSafeCursorString from memcache). a reload of the page should work. a second tap in the browser would be a problem i think...
what would you say?

Resources