I am working on camel’s dynamic router to derive and dispatch to the relevant queue by referring http://camel.apache.org/dynamic-router.html
Following is the camel config xml:
<route id="dynamicRouter" autoStartup="true">
<from uri="vm://service1?concurrentConsumers=10&timeout=0" />
<choice>
<when>
<simple>${body.documentStatus} == 'SUCCESS' </simple>
<log message="routing to dynamic router" />
<dynamicRouter>
<!-- use a method call on a bean as dynamic router -->
<method ref="messageRouter" method="route" />
</dynamicRouter>
</when>
</choice>
</route>
Following is my dynamic router bean:
public class MessageRouter {
private static final String QUEUE_BROKER = "activemq";
private static final String DEFAULT_QUEUE = "queue";
/**
*
* #param obj
* message
* #return the dynamically generated queue name
*/
public String route(ServiceObject obj) {
RecordObject record = obj.getRecordObject();
if(record != null){
return QUEUE_BROKER + ":"
+ record.getId() + "." + DEFAULT_QUEUE;
}
return null;
}
}
I am able to en-queue messages in dynamically created queue but messages are getting enqueued infinitely. Any help in identifying what could be the reason would be of great help.
Thanks in advance!!!
Read the documentation about dynamic router at
http://camel.apache.org/dynamic-router.html
And see the beware box, it says the method must return null to signal to the dynamic router to break out.
So in your code above, then this code line
RecordObject record = obj.getRecordObject();
... the record object is never null and therefore the dynamic router keeps going forever.
If you only want this dynamic routing one time then use the dynamic receipient list eip instead, see
http://camel.apache.org/how-to-use-a-dynamic-uri-in-to.html
http://camel.apache.org/recipient-list.html
And your xml route is
<recipientList>
<!-- use a method call on a bean as dynamic router -->
<method ref="messageRouter" method="route" />
</recipientList>
Related
We are using spring-integration with S3. We have s3-inbound-streaming-channel-adapter to read from S3. What is happening is that if the "get" fails the s3-inbound-streaming-channel-adapter put the filename in "acceptOnceFilter" and doesn't retry on failure.
Q1. What we want is when the s3-inbound-streaming-channel-adapter "gets" a file from S3 and say for some reason this "get" fails... how do we get the s3-inbound-streaming-channel-adapter to retry this "get" request again for the same file?
Q2. On failure, an exception is sent to default "errorChannel" from s3-inbound-streaming-channel-adapter. Would the Message in the exception contain "filename" that failed?
<int:channel id="s3FileProcessingChannel">
<int:queue capacity="15"/>
</int:channel>
<bean id="metadataStore" class="org.springframework.integration.metadata.SimpleMetadataStore"/>
<bean id="acceptOnceFilter"
class="org.springframework.integration.aws.support.filters.S3PersistentAcceptOnceFileListFilter">
<constructor-arg index="0" ref="metadataStore"/>
<constructor-arg index="1" value="streaming"/>
</bean>
<int-aws:s3-inbound-streaming-channel-adapter id="s3Region1"
channel="s3FileProcessingChannel"
session-factory="s3SessionFactory"
filter="acceptOnceFilter"
remotedirectoryexpression="'${s3.sourceBucket}/emm'">
<int:poller fixed-delay="1000" max-messages-per-poll="15"/>
</int-aws:s3-inbound-streaming-channel-adapter>
Thanks
GM
The S3PersistentAcceptOnceFileListFilter implements:
/**
* A {#link FileListFilter} that can be reset by removing a specific file from its
* state.
* #author Gary Russell
* #since 4.1.7
*
*/
public interface ResettableFileListFilter<F> extends FileListFilter<F> {
/**
* Remove the specified file from the filter so it will pass on the next attempt.
* #param f the element to remove.
* #return true if the file was removed as a result of this call.
*/
boolean remove(F f);
}
And S3StreamingMessageSource populates headers like these:
return getMessageBuilderFactory()
.withPayload(session.readRaw(remotePath))
.setHeader(IntegrationMessageHeaderAccessor.CLOSEABLE_RESOURCE, session)
.setHeader(FileHeaders.REMOTE_DIRECTORY, file.getRemoteDirectory())
.setHeader(FileHeaders.REMOTE_FILE, file.getFilename())
.setHeader(FileHeaders.REMOTE_FILE_INFO,
this.fileInfoJson ? file.toJson() : file);
When error happened you just need to use that FileHeaders.REMOTE_FILE to call the mention above remove() and your failed file is going to be picked up from the S3 on the next poll cycle.
I have following defined in
struts-config.xml:
<struts-config>
<form-beans>
<form-bean name="LoginForm" type="com.actionform.LoginForm"/>
</form-beans>
<action-mappings>
<!-- action for login -->
<action input="/views/login.jsp" name="LoginForm" path="/Login" scope="session" type="com.actions.LoginAction"
parameter="method" validate="true">
<forward name="success" path="/views/Frameset.html" />
</action>
</action-mappings>
<message-resources parameter="/WEB-INF/ApplicationResources"/>
<!-- ========================= Validator plugin ================================= -->
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property
property="pathnames"
value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/>
</plug-in>
</struts-config>
The login form:
public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
ActionErrors errors = new ActionErrors();
if (userName == null || userName.length() < 1) {
System.out.println("in validate ---");
errors.add("userName", new ActionMessage("error.userName.required"));
// TODO: add 'error.name.required' key to your resources
}
if (password == null || password.length() < 1) {
errors.add("password", new ActionMessage("error.password.required"));
// TODO: add 'error.name.required' key to your resources
}
return errors;
}
login.jsp:
<html:form action="/Login?method=loginUser">
<html:errors/>
<html:text name="LoginForm" property="userName" />
<html:messages id="err_userName" property="userName">
<bean:write name="err_userName" />
</html:messages>
</html:form>
Property file:
error.userName.required = User Name is required.
error.password.required = Password is required.
Where am I doing wrong? I am getting the following error
javax.servlet.jsp.JspException: Cannot find bean error in any scope
I just want to display the error in the same JSP.
After you obtain the ActionMessages/ActionErrors object which contains the messages or errors you want to display in your input page (using <html:messages> tags or <html:errors> tags), you must call one of the following methods from your Action object to place the result of your validation in scope:
addMessages(HttpServletRequest request, ActionMessages messages)
or
addErrors(HttpServletRequest request, ActionMessages errors)
Are you doing that?
I'm really do not care how about struts handles an exception. Using old raw code from 1.2 generally when overriding a RequestProcesor, I should probably replace the two methods - process and processException. First thing is happy about catching exception from the request after processValidation has been made. The fragment of code could look like
Exception exception = null;
if (needValidation)
try {
if (! processValidate(request, response, form, mapping)) {
return;
}
exception = (Exception)request.getAttribute(Globals.EXCEPTION_KEY);
} catch (InvalidCancelException ex) {
exception = ex;
}
ActionForward forward;
// Check out if exception occurred
if (exception != null){
forward = processException(request, response, exception, form, mapping);
The second is pretty easy if you have configured the errors forward. The errors forward is usually one of the global forwards that easily found from the mapping. Once it found, it likes to display your error message on the page. I think those would probably enough for processing an exception
exception.printStackTrace();
log.error(exception);
request.setAttribute("error", exception.getMessage());
return mapping.findForward("error");
It has been done because validate method from ActionForm or ValidatorForm doesn't throw any exceptions and I couldn't properly override this method without throwing some. Once thrown, who will care about it?!
I am trying to do form validation in Spring Web Flow. For this I am using a validator class, which is named after the model. Just like it is stated in the documentation.
The validator gets instantiated as a bean but is never called during validation. Any pointers on that issue?
flow config
<?xml version="1.0" encoding="UTF-8"?>
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow-2.4.xsd">
<view-state id="createTotpKeyView" view="/templates/totp/create/create" model="key">
<on-entry>
<evaluate expression="createTotpKeyAction"/>
</on-entry>
<transition on="submit" to="successfullyCreated" bind="true" validate="true"/>
</view-state>
<end-state id="successfullyCreated" view="/templates/totp/create/success"/>
</flow>
This is the action that is called in the view-state.
createTotpKeyAction
#Component
public class CreateTotpKeyAction implements Action
{
String uid = "random";
#Override
public Event execute(RequestContext context) throws Exception
{
try
{
// Create a TOTP key and put it in the view scope
TOTPKey totpKey = client.createTotpKeyForUid(uid, null);
context.getViewScope().put("key", totpKey);
return new Event(this, "success");
}
catch (Exception e)
{
log.error("Error while creating TOTP key for user: " + uid + ".\n" + e.getMessage());
// Put response message in flash scope to show it once
context.getFlashScope().put("fetchingError", true);
return new Event(this, "error");
}
}
}
This is the validator I am trying to use. EDIT renamed to match documentation.
KeyValidator
#Component
public class KeyValidator
{
[...]
public void validateCreateTotpKeyView(TOTPKey key, ValidationContext context)
{
System.out.println("VALIDATE VIEW STATE");
}
public void validate(TOTPKey key, ValidationContext context)
{
System.out.println("DEFAULT VALIDATE");
}
}
I also tried different naming schemes such as TOTPKeyValidator or TotpKeyValidator. None of them worked.
The only thing that is working, is creating a validation method in the TOTPKey class, but I don't want to use that approach.
In addition this is the log file produced during the attempted validation
Log
Mapping request with URI '/totp/create' to flow with id 'totp/create'
Resuming flow execution with key 'e5s1
Locking conversation 5
Getting flow execution with key 'e5s1'
Getting FlowDefinition with id 'totp/create'
Resuming in org.springframework.webflow.mvc.servlet.MvcExternalContext#2b551393
Restoring [FlowVariable#3b66a2de name = 'key', valueFactory = [BeanFactoryVariableValueFactory#2fbc89 type = TOTPKey]]
Processing user event 'submit'
Resolved model twofa.core.domain.TOTPKey#505439d0
Binding to model
Adding default mapping for parameter 'execution'
Adding default mapping for parameter 'totpKeyId'
Adding default mapping for parameter 'token'
Adding empty value mapping for parameter 'eventId_submit'
Validating model
Event 'submit' returned from view [ServletMvcView#19f8532f view = org.springframework.web.servlet.view.velocity.VelocityLayoutView: name '/templates/totp/create/create'; URL [/templates/totp/create/create.vm]]
Executing [Transition#2feb5361 on = submit, to = successfullyCreated]
Exiting state 'createTotpKeyView'
Entering state 'successfullyCreated' of flow 'totp/create'
Executing org.springframework.webflow.action.ViewFactoryActionAdapter#423fa131
Rendering MVC [org.springframework.web.servlet.view.velocity.VelocityLayoutView: name '/templates/totp/create/success'; URL [/templates/totp/create/success.vm]] with model map [{currentUser=null, flashScope=map[[empty]], flowRequestContext=[RequestControlContextImpl#70144045 externalContext = org.springframework.webflow.mvc.servlet.MvcExternalContext#2b551393, currentEvent = submit, requestScope = map[[empty]], attributes = map[[empty]], messageContext = [DefaultMessageContext#149807b4 sourceMessages = map[[null] -> list[[empty]]]], flowExecution = [FlowExecutionImpl#1c4b2c3e flow = 'totp/create', flowSessions = list[[FlowSessionImpl#6eea5d26 flow = 'totp/create', state = 'successfullyCreated', scope = map['key' -> twofa.core.domain.TOTPKey#73f32d0a]]]]], flowExecutionKey=e5s1, flowExecutionUrl=/totp/create?execution=e5s1, key=twofa.core.domain.TOTPKey#73f32d0a}]
Finished executing org.springframework.webflow.action.ViewFactoryActionAdapter#423fa131; result = success
Completed transition execution. As a result, the flow execution has ended
Removing flow execution '[Ended execution of 'totp/create']' from repository
Ending conversation 5
Unlocking conversation 5
It says Validating Model but nothing happens...
It came down to a wrong import statement in my validator class.
Using org.relaxng.datatype.ValidationContext instead of org.springframework.binding.validation.ValidationContext will not work.
I'm trying to call a URL which should return me a XML file.
I want to Display this XML file.
Right now I don't know how to make the call to get the return file.
I tryied it with a <p:commandButton process="#this" action="http://..." value="Test" /> but I get 2 warnings.
Warning for file: Couldn't find a Mime-Type, add a Mime-Type mapping in your web.xml
Warning for Ressource: Can not be found or operated.
You need to use for example restfull client to get your xml and parse it.
Here's your content of actionlistener that will be called from your button:
Client client = ClientBuilder.newClient( new ClientConfig().register( LoggingFilter.class ) );
WebTarget webTarget = client.target("http://localhost:8080/JerseyDemos/rest").path("employees");
Invocation.Builder invocationBuilder = webTarget.request(MediaType.APPLICATION_XML);
Response response = invocationBuilder.get();
Employees employees = response.readEntity(Employees.class);
List<Employee> listOfEmployees = employees.getEmployeeList();
(from http://howtodoinjava.com/jersey/jersey-restful-client-examples/#get-list)
Try this:
action=#{yourBean.yourAction}
Inside your bean:
public void yourAction() {
FacesContext fc = FacesContext.getCurrentInstance();
fc.getExternalContext().redirect("http://...");
fc.responseComplete();
}
I'm not sure if it's needed, but also you might wanna set ajax=false on p:commandButton
am new to Spring Integration
my objective is passing message to one channel to another (chain process)
Channel1 ---> chennal2 --> chennal3 ---> chennal4.
(Msg1) (Msg2) (Msg3) (Msg4)
\ \ / /
\ \ / /
errorChennal (Msg5)
1. Msg1(EmployeeObject), Msg2 (DetailsObjet), Msg3(VerificationObject), Msg4(FinalObject), Msg5(ErrorObject)
Each channel payloads will have different Class Objects.
All the channel need to be communicated to "errorChennal" in case of Exception, validation error, etc.
Tried:
1. when I tried with #transformer am not able to communicate to "erroeChannel".
when I tried with #Router(header-value-router) Message transform not happing. Msg1 object is to all object
Question:
How do i route one channel to specific channel with message transformer?
FOUND ANSWER
Configuration:
<int:channel id="channel1"/>
<int:channel id="channel2"/>
<int:channel id="channel3"/>
<int:channel id="channel4"/>
<int:service-activator input-channel="channel1" ref="firstChannel" method="doProcess1" />
<int:service-activator input-channel="channel2" ref="secondChannel" method="doProcess2" />
<int:service-activator input-channel="channel3" ref="thirdChannel" method="doProcess3" />
<int:service-activator input-channel="channel4" ref="forthChannel" method="doProcess4" />
<int:service-activator input-channel="errorChannel" ref="errorHandlerChannel" method="doErrorProcess" />
Java Code:
public FirstChannel {
private Map<String, MessageChannel> msgChannels;
boolean isError = false;
#Autowired
public ScheduleParser(Map<String, MessageChannel> msgChannels) {
super();
this.msgChannels = msgChannels;
}
public void doprocess1(Message<?> message){
File file = (File) message.getPayload();
//business code
if(!isError)
//transforming the messae
msgChannels.get("channel2").send(new GenericMessage(EmployeeVO , headersMap));
else
msgChannels.get("errorChannel").send(new GenericMessage(ObjectVO , headersMap));
}
}
Same way Other channels Code will be
Channels aren't connected to each other they are connected to endpoints.
Transformers don't route, routers route.
You need something like
channel1->payload-type-router
type1Channel->...
type2Channel->...
...
possibly with a different transformer for each payload type downstream.
It's generally better to show the configuration you have tried rather than some abstraction like you have shown.
The error flow configuration depends on what starts your flow (gateway, poller, etc) - i.e. what is upstream of channel1.
EDIT
Your configuration is completely wrong. For example, you currently have two subscribers on channel1 - a header value router and service activator.
Messages arriving on channel1 will alternately go to one or the other - messages going to the service activator will never go to the router.
Without knowing the complete picture, I am guessing you need something like...
channel1->serviceActivator1->channel1toRouter->router(channel2 or failed)
channel2->serviceActivator2->channel2toRouter->router(channel2 or failed)
...