Spring Webflow Exception-Handler for Action-State - java

I created a Spring Webflow exception-handler for my application and defined it in my abstract parent flow.
In this handler I add FacesMessages to display several errors in a generic way.
Now i got the problem that i can't handle an exception that occures in an action-state. I try to go back to the last valid view-state or something like that (or maybe go to the start-state). Anyway, I don't want the application to crash or show a blank page.
#Override
public void handle(FlowExecutionException exception, RequestControlContext context) {
Object testState = context.getCurrentState();
if(testState instanceof ActionState){
//what to do here?
}
}
I am using Spring Webflow Version 2.3.0.RELEASE with JSF 2 on MyFaces.
Best regards,
Patrick

You can execute a transition to another state (the transition must exist). So, inside your if statement you could do the following:
TransitionDefinition errorDefinition = context.getMatchingTransition("errorState");
Transition errorTransition = (Transition)errorDefinition;
context.execute(errorTransition);
The transition could be a global transition to a generic error page.
Regards.

Related

Using AOP and DI itself causes Spring ApplicationListener to be fired twice

Software versions
Spring Version 5.3.18 and earlier
JDK Version 1.8.0_202
Overview
When I use Spring ApplicationListener, in order to prevent transaction invalidation, my ApplicationListener implementation class writes the following code (of course, the code can be written differently to avoid this problem), which will cause my listener to trigger twice after the event is published. I think it's not normal, but not sure if it's a bug, so I want to ask everyone's opinion.
#Component
public class EventDemoListener implements ApplicationListener<EventDemo> {
#Autowired
DemoService1 demoService1;
#Autowired
DemoService2 demoService2;
#Autowired
EventDemoListener eventDemoListener;
#Override
public void onApplicationEvent(EventDemo event) {
eventDemoListener.testTransaction();
System.out.println("receiver " + event.getMessage());
}
#Transactional(rollbackFor = Exception.class)
public void testTransaction() {
demoService1.doService();
demoService2.doService();
}
}
Through this demo project, this problem can be reproduced. Please read the README.md document before running.
https://github.com/ZiFeng-Wu/spring-study
Analysis
After analysis, because here DI itself , When EventDemoListener is created, property filling will trigger DefaultSingletonBeanRegistry#getSingleton(String, boolean) in advance.
Then singletonFactory.getObject() executed in getSingleton() will cause the unproxyed EventDemoListener object to be put into AbstractAutoProxyCreator#earlyProxyReferences.
After the properties are filled, calling AbstractAutowireCapableBeanFactory#initializeBean(String, Object, RootBeanDefinition) and executing ApplicationListenerDetector#postProcessAfterInitialization(Object, String) will cause the unproxyed EventDemoListener object to be put into the AbstractApplicationEventMulticaster.DefaultListenerRetriever#applicationListeners container.
Then when the event is published, execute AbstractApplicationEventMulticaster.DefaultListenerRetriever#getApplicationListeners() and use ApplicationListener<?> listener =beanFactory.getBean(listenerBeanName, ApplicationListener.class) to obtain the listener is the proxied EventDemoListener object.
At this time, there are only unproxyed EventDemoListener object in the applicationListeners container, so the proxied EventDemoListener object will be added to the final returned allListeners collection, as shown in the figure below, which will eventually cause the listener to be triggered twice.
Updated answer
Now with your updated GitHub project, I can reproduce the problem. It also occurs when using a Spring AOP aspect targeting the listener class, not just in the special case of self-injection + #Transactional. IMO, it is a Spring Core bug, which is why I created PR #28322 in order to fix the issue #28283 you raised either before or after cross-posting here. You should have linked to that issue in your question, I just found it because I was searching for key words before creating an issue for it myself.
See also my comment in the issue, starting with this one.
Original answer (for reference)
OK, in your main class I changed
String configFile = "src/main/resources/spring-context.xml";
AbstractApplicationContext context = new FileSystemXmlApplicationContext(configFile);
to
AbstractApplicationContext context = new AnnotationConfigApplicationContext("com.zifeng.spring");
Now the application starts, also without DB configuration. It simply prints:
receiver test
There is no exception. I.e., if for you it does not work, probably there is a bug in your XML configuration. But actually, you really do not need it, because you used component and service annotations already.
So if I need a database setup in order to reproduce this, please, like I said in my comment, update the project to provide an H2 configuration which works out of the box.

When and how cglib-proxied component instance is created

I'd like to learn if there are some rules / conditions that a Spring component is wrapped (proxied) by CGLIB. For example, take this case:
#Component
public class TestComponent {
}
#Service
//#Transactional(rollbackFor = Throwable.class)
public class ProcessComponent {
#Autowired
private TestComponent testComponent;
public void doSomething(int key) {
// try to debug "testComponent" instance here ...
}
}
If we let it like this and debug the testComponent field inside the method, then we'll see that it's not wrapped by CGLIB.
Now if we uncomment the #Transactional annotation and debug, we'll find that the instance is wrapped: it's of type ProcessComponent$$EnhancerByCGLIB$$14456 or something like that. It's clearly because Spring needs to create a proxy class to handle the transaction support.
But I'm wondering, is there any way that we can detect how and when does this wrapping happen ? For example, some specific locations in Spring's source code to debug into to find more information; or some documentations on the rules of how they decide to create a proxy.
For your information, I need to know about this because I'm facing a situation where some component (not #Transactional, above example is just for demonstrating purpose) in my application suddenly becomes proxied (I found a revision a bit in the past where it is not). The most important issue is that this'll affect such components that also contain public final methods and another issue (also of importance) is that there must have been some unexpected changes in the design / structure of classes. For these kind of issues, of course we must try to find out what happened / who did the change that led to this etc...
One note is that we have just upgraded our application from Spring Boot 2.1.0RELEASE to 2.1.10RELEASE. And checking the code revision by revision up till now is not feasible, because there have been quite a lot of commits.
Any kind of help would be appreciated, thanks in advance.
You could debug into org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean(Class, String, TargetSource).
If any advisor is found, the bean will be proxied.
If you use a #Lookup method injection it will also proxy the component class.

OSGI Declarative Services (DS): What is a good way of using service component instances

I am just getting started with OSGI and Declarative Services (DS) using Equinox and Eclipse PDE.
I have 2 Bundles, A and B.
Bundle A exposes a component which is consumed by Bundle B. Both bundles also expose this service to the OSGI Service registry again.
Everything works fine so far and Equinox is wireing the components together, which means the Bundle A and Bundle B are instanciated by Equinox (by calling the default constructor) and then the wireing happens using the bind / unbind methods.
Now, as Equinox is creating the instances of those components / services I would like to know what is the best way of getting this instance?
So assume there is third class class which is NOT instantiated by OSGI:
Class WantsToUseComponentB{
public void doSomethingWithComponentB(){
// how do I get componentB??? Something like this maybe?
ComponentB component = (ComponentB)someComponentRegistry.getComponent(ComponentB.class.getName());
}
I see the following options right now:
1. Use a ServiceTracker in the Activator to get the Service of ComponentBundleA.class.getName() (I have tried that already and it works, but it seems to much overhead to me) and make it available via a static factory methods
public class Activator{
private static ServiceTracker componentBServiceTracker;
public void start(BundleContext context){
componentBServiceTracker = new ServiceTracker(context, ComponentB.class.getName(),null);
}
public static ComponentB getComponentB(){
return (ComponentB)componentBServiceTracker.getService();
};
}
2. Create some kind of Registry where each component registers as soon as the activate() method is called.
public ComponentB{
public void bind(ComponentA componentA){
someRegistry.registerComponent(this);
}
or
public ComponentB{
public void activate(ComponentContext context){
someRegistry.registerComponent(this);
}
}
}
3. Use an existing registry inside osgi / equinox which has those instances? I mean OSGI is already creating instances and wires them together, so it has the objects already somewhere. But where? How can I get them?
Conclusion
Where does the class WantsToUseComponentB (which is NOT a Component and NOT instantiated by OSGI) get an instance of ComponentB from? Are there any patterns or best practises? As I said I managed to use a ServiceTracker in the Activator, but I thought that would be possible without it.
What I am looking for is actually something like the BeanContainer of Springframework, where I can just say something like Container.getBean(ComponentA.BEAN_NAME). But I don't want to use Spring DS.
I hope that was clear enough. Otherwise I can also post some source code to explain in more detail.
Thanks
Christoph
UPDATED:
Answer to Neil's comment:
Thanks for clarifying this question against the original version, but I think you still need to state why the third class cannot be created via something like DS.
Hmm don't know. Maybe there is a way but I would need to refactor my whole framework to be based on DS, so that there are no "new MyThirdClass(arg1, arg2)" statements anymore.
Don't really know how to do that, but I read something about ComponentFactories in DS. So instead of doing a
MyThirdClass object = new MyThirdClass(arg1, arg2);
I might do a
ComponentFactory myThirdClassFactory = myThirdClassServiceTracker.getService(); // returns a
if (myThirdClassFactory != null){
MyThirdClass object = objectFactory.newInstance();
object.setArg1("arg1");
object.setArg2("arg2");
}
else{
// here I can assume that some service of ComponentA or B went away so MyThirdClass Componenent cannot be created as there are missing dependencies?
}
At the time of writing I don't know exactly how to use the ComponentFactories but this is supposed to be some kind of pseudo code :)
Thanks
Christoph
Christoph,
Thanks for clarifying this question against the original version, but I think you still need to state why the third class cannot be created via something like DS.
DS causes components to be published as services, therefore the only way to "get" any component from DS is to access it via the service registry. Unfortunately the service registry can be hard to use correctly using the lower level APIs because it is dynamic, so you have to cope with the possibility of services going away or not being available at precisely the moment you want them to be available, and so on. This is why DS exists: it gives you an abstraction for depending on services and managing the lifecycle of your components based on the availability of services that they reference.
If you really need to access a service without using DS or something like it (and there is quite a choice of "things like it" e.g. Spring-DM, iPOJO, Guice/Peaberry, etc) then you should use ServiceTracker. I agree there is a lot of overhead -- again, this is why DS exists instead.
To answer your suggestion no (2), no you should not create your own registry of services because the service registry already exists. If you created a separate parallel registry then you would still have to handle all the dynamics, but you would have to handle it in two places instead of one. The same applies to suggestion (3).
I hope this helps.
Regards,
Neil
UPDATED: Incidentally, although Spring has the Container.getBean() backdoor, you notice that in all Spring documentation it is strongly recommended not to use that backdoor: to get hold of a Spring bean, just create another bean that references it. The same applies to DS, i.e. the best way to get hold of a DS component is to create another DS component.
Also note that in the OSGi world, even if you're using Spring-DM there is no easy way to just call getBean() because you need to get hold of the Spring ApplicationContext first. That is itself an OSGi service, so how to you get that service?
christoph,
dont know if I really understand your problem.
per ex.
Bundle A is providing a service using DS component:
<service>
<provide interface="org.redview.lnf.services.IRedviewLnfSelectedService"/>
Bundle B requires this service using DS component:
<implementation class="ekke.xyz.rcp.application.internal.XyzApplicationLnfComponent"/>
as soon as Bundle A provides the Service, Bundle B "gets" it through the bind() methode of the implementation class:
public class XyzApplicationLnfComponent {
public void bind(IRedviewLnfSelectedService lnfSelectedService) {
// here it is
}
hope this helps
ekke
Easy way: Inject the DS component into your Activator class with Riena:
http://wiki.eclipse.org/Riena_Getting_Started_with_injecting_services_and_extensions
Then you can call it from everywhere: Activator.getDefault().getWhateverService()

JSF: navigation

I have to warn you: the question may be rather silly, but I can't seem to wrap my head around it right now.
I have two managed beans, let's say A and B:
class A
{
private Date d8; // ...getters & setters
public String search()
{
// search by d8
}
}
class B
{
private Date d9; //...getters & setters
public String insert()
{
// insert a new item for date d9
}
}
and then I have two JSP pages, pageA.jsp (the search page) and pageB.jsp (the input page).
What I would like to do is placing a commandbutton in pageB so to open the search page pageA passing the parameter d9 somehow, or navigating to pageA directly after b.insert(). What I would like to do is showing the search result after the insertion.
Maybe it's just that I can't see the clear, simple solution, but I'd like to know what the best practice might be here, also...
I though of these possible solutions:
including **A** in **B** and linking the command button with **b.a.search**
passing **d9** as a **hiddenInput** and adding a new method **searchFromB** in **A** (ugly!)
collapsing the two beans into one
JSF 1.1/1.2 raw doesn't provide an easy way to do this. Seam/Spring both have ways around this and there are a couple of things you can do. JSF 2 should also have solutions to this once it is released.
Probably the easiest and most expedient would be to collapse the two beans into one and make it session scoped. The worry, of course, is that this bean will not get removed and stay in session until the session times out. Yay Memory leaks!
The other solution would be to pass the date on as a GET parameter. For instance, you action method could call the
FacesContext.getCurrentInstance().getExternalContext().redirect("pageB?d9=" + convertDateToLong(d9));
and then get the parameter on the other side.
You should configure the navigation flow in faces-config.xml. In ideal scenario you would return a "status" message which would decide the flow. Read more at following link:
http://www.horstmann.com/corejsf/faces-config.html
http://publib.boulder.ibm.com/infocenter/rtnlhelp/v6r0m0/index.jsp?topic=/com.businessobjects.integration.eclipse.doc.devtools/developer/JSF_Walkthrough8.html
As far as passing the values from one page to another is concerned you can use backing beans. More about backing beans here:
http://www.netbeans.org/kb/articles/jAstrologer-intro.html
http://www.coderanch.com/t/214065/JSF/java/backing-beans-vs-managed-beans
Hope i have understood and answered correctly to your question
Way to share values between beans
FacesContext facesContext = FacesContext.getCurrentInstance();
Application app = facesContext.getApplication();
ExpressionFactory elFactory = app.getExpressionFactory();
ELContext elContext = facesContext.getELContext();
ValueExpression valueExp = elFactory.createValueExpression(elContext, expression, Object.class);
return valueExp.getValue(elContext);
In above code "expression" would be something like #{xyzBean.beanProperty}
Since JSF uses singleton instances, you should be able to access the values from other beans. If you find more details on this technique, I am sure you'll get what you are looking for.
Add commandButton action attribute referencing to B'insert method
<h:commandLink action="#{b.insert}" value="insert"/>
In B'insert method,add d9 parameter as request parameter. Then return an arbitrary string from insert method.
FacesContext fc = FacesContext.getCurrentInstance();
fc.getExternalContext().getRequestMap().put("d9", d9);
Then go to faces context and add navigation from B to A with "from-outcome" as the arbitrary String you returned from insert method. But don't add redirect tag to navigation tags as it will destroy the request coming from B and the parameter you added (d9) will be cleared.
<from-outcome>return string of insert method</from-outcome>
<to-view-id>address of A</to-view-id>
Then you might get the "d9" in A class by fetching it from request map at its constructor or in a place where its more appropriate (getters). You might add it into a session scope or place it to a hidden variable if you want to keep track of it later.
in class A, when page is navigated, A should be initialized as it will be referenced.
FacesContext fc = FacesContext.getCurrentInstance();
fc.getExternalContext().getRequestMap().get("d9", d9);
Sorry i cant give full code, as i have no ide at here, its internet machine at work. I could not give details therefore.
In my opinion, the simplest way is 3-rd option - have both query and insert methods in same class. And you can do something like that:
public String query () {
//...
}
public String Insert() {
//insert
return Query(); }
If your classes are managed Beans you can load class A from class B and call A.query() in your insert method at the end. Also class A can have
<managed-bean-scope>session</managed-bean-scope>
parameter in faces-config.xml and it wouldn't be instantiated again when loaded.

Seam/Hibernate validator listener

We use a standard SEAM setup here ... complete with the validation system that uses hibernate.
Basically what happens is a user enters a value into an html input and seam validates the value they entered using the hibernate validation.
Works fine for the most part except here's my problem: We need to record the results of validation on each field and I can't figure out a good way to do it ... ideally it would be done through communicating with the seam/hibernate validation system and just recording the validation results but as far as I can tell there isn't a way to do this?
Has anyone done anything like this in the past? There are a couple nasty work arounds but I'd prefer to do it cleanly.
Just a quick overview of the process that we have happening right now for context:
1) user enters field value
2) onblur value is set with ajax (a4j:support) at this point the validators fire and the div is re-rendered, if any validation errors occured they're now visible on the page
What I'd like to have happen at step2 is a 'ValidationListener' or something similar is called which would allow us to record the results of the validation.
Thanks if anyone is able to help :o
You should be able to do it by creating a Bean that has a method observing the org.jboss.seam.validationFailed event. That method can then do whatever logging you want.
#Name("validationObserver")
public class ValidationObserver() {
#Observer("org.jboss.seam.validationFailed")
public void validationFailed() {
//Do stuff
}
}
The validationFailed event doesn't pass any parameters so you'll have to interrogate the FacesMessages or possibly the Hibernate Validation framework itself if you want to record what the error was.
I you are only using Hibernate for validation, you can use the Hibernate ClassValidator in the validationFailed() method, as recommended by Damo.
Example:
public <T> InvalidValue[] validateWithHibernate(T object) {
ClassValidator<T> validator = new ClassValidator(object.getClass());
InvalidValue[] invalidValues = validator.getInvalidValues(object);
return invalidValues;
}

Categories