SEAM: Component "disinjected" "too soon" in interceptor? - seam

Let's say I have the following interceptor in a SEAM app:
public class MyInterceptor {
#In
private Monitor myMonitor;
#AroundInvoke
public Object aroundInvoke(InvocationContext ctx) throws Exception {
try {
myMonitor.a();
return ctx.proceed();
}
finally {
myMonitor.b();
}
}
}
myMonitor.a() works (so Monitor is correctly injected), myMonitor.b() fails because Monitor is already null. Seam Doc says: "Injected values are disinjected (i.e., set to null) immediately after method completion and outjection."
Is that what is happening? Can I do something to tell SEAM to "not yet" "disinject" the component? I can of course also do something like XContext.get(..), but I'm wondering whether this is a bug or a mistake from my side. thanks!

Try this one instead
Object response = null;
try {
myMonitor.a();
response = ctx.proceed();
} finally {
myMonitor.b();
}
return response;
regards,

Avoid using injection.
Try working around this problem. I see you have some sort of monitoring going on. Look at this interceptor that captures the amount of time a method is executed in Seam components. Try modifying your code to match that.
It works great!
Here is the link

Seam is working as advertised.
You could just ignore the disinjection:
public class MyInterceptor {
private Monitor myMonitor;
#In
private void setMonitor(Monitor aMonitor) {
if (aMonitor != null) {
myMonitor = aMonitor;
}
}
#AroundInvoke
public Object aroundInvoke(InvocationContext ctx) throws Exception {
try {
myMonitor.a();
return ctx.proceed();
}
finally {
myMonitor.b();
myMonitor = null; //perform disinjection yourself
}
}
}
The caveat here is that Seam is disinjecting the reference for a reason. Seam wants to control the lifecycle and identity of "myMonitor" and by keeping a reference to it, you are not abiding by your contract with Seam. This could lead to unexpected behavior.
For instance, if myMonitor were for some reason in the Stateless scope, Seam might destroy it before ctx.proceed() returns, leaving you with a reference to a broken proxy. Best advice is to know the scope and lifecycle of what you are retaining since you are "living on the edge."

Related

"Add" appears to be working in WebFlux, but seems like there must be a "more accepted way"

New to WebFlux, reactive, and handlers.
I am able to get a Mono<> from a ServerRequest and process the contained POJO to add a new tuple to a database. But, it seems like there should be a "better" or "more accepted" way to write this code.
Any help/input with the code in AccountRequestHandler would be appreciated, especially with explanations of the rationale behind the recommend change(s).
Router implementation (stripped down to only "POST")...
#Configuration
public class AccountRequestRouter {
#Bean
public RouterFunction<ServerResponse> route(AccountRequestHandler requestHandler) {
return nest(path("/v2"),
nest(accept(APPLICATION_JSON),
.andRoute(RequestPredicates.POST("/accounts"), requestHandler::addAccount)
));
}
}
Handler implementation...
The code where I'm actually doing the add, and then separately creating a ServerResponse, is what I'm focused on. It seems "clunky", especially since AccountService.addAccount() returns a Mono on completion.
#Component
public class AccountRequestHandler {
#Autowired
private mil.navy.ccop.service.accounts.account.AccountService accountService;
public Mono<ServerResponse> addAccount(ServerRequest request) {
return request.bodyToMono(Account.class).flatMap(account -> {
accountService.addAccount(account);
return ServerResponse.ok().build();
})
.switchIfEmpty(ServerResponse.badRequest()
.contentType(APPLICATION_JSON)
.build(Mono.empty()));
}
}
AccountService implementation (again, stripped down)...
#Service
class AccountService {
#Autowired
private AccountRepository accounts;
public AccountService() {
}
public Mono<Void> addAccount(Account account) {
Account proxy;
// make sure that accountId is set to support auto-generation of synthetic key value
proxy = new Account(-1, account.getShortName(), account.getLongName(), account.getDescription());
accounts.save(proxy);
return Mono.empty();
}
}
Appreciating all the help in ramping up on this style of programming....
well first of all, you have 2 addAccount, that can be a bit confusing.
Second of all, what kind of "repository" are you writing too? if its an sql repo you need to properly wrap it in a Mono.fromCallable() otherwise it will block the Reactive thread pool and you can have really bad performance.
Yes there are other ways of doing things. A lot of people tend to do things in flatmap or map and sure it is completely possible to do things here, but for the semantics i'd say it is less good.
map and flatmap are usually used to perform some sort of computation on the inner value of the mono and then return the same or a new value and or type inside the mono.
i would rewrite this like such.
return void here:
public void addAccount(Account account) {
Account proxy;
// make sure that accountId is set to support auto-generation of synthetic key value
proxy = new Account(-1, account.getShortName(), account.getLongName(), account.getDescription());
accounts.save(proxy);
}
And here:
public Mono<ServerResponse> addAccount(ServerRequest request) {
return request.bodyToMono(Account.class)
.doOnSuccess(account -> {
accountService.addAccount(account);
}).then(ServerResponse.ok().build())
.switchIfEmpty(ServerResponse.badRequest()
.contentType(APPLICATION_JSON)
.build());
}
there are a number of different doOn methods that are ment to be used to consume and do "side effects" on things. Like doOnSuccess, doOnError, doOnCancel etc. etc.
you also have then and thenReturn which will just return whatever you put in them. Then returns whatever Mono you put in it. thenReturn wraps whatever value you put into it into a Mono and returns it.

jsf2 spring webflow transition exception handling does not work with exceptions during render phase

I am not sure either I missed a point in the concept of exception handling in webflow, or this is a bug.
I hope someone can help me to understand it, or I will file a bug in webflow/spring mvc.
Following situation.
JSF2 (2.1.X) with webflow 2.4.0 and spring faces (2.4.0)
A RuntimeException is thrown during render phase. Not nice, but can happen.
Exceptionhandling kicks in, a it tries a make a new tansition to an error site. Works like expected.
ErrorState is resolved, it tries to make a transition to it. Everything is ok so far. Now here is the problem. The transition will never be executed.
org.springframework.webflow.engine.ViewState
protected void doEnter(RequestControlContext context) throws FlowExecutionException {
context.assignFlowExecutionKey();
ExternalContext externalContext = context.getExternalContext();
if (externalContext.isResponseComplete()) {
if (!externalContext.isResponseCompleteFlowExecutionRedirect()) {
clearFlash(context);
}
} else {
if (shouldRedirect(context)) {
context.getExternalContext().requestFlowExecutionRedirect();
if (popup) {
context.getExternalContext().requestRedirectInPopup();
}
} else {
View view = viewFactory.getView(context);
context.setCurrentView(view);
render(context, view);
}
}
}
Transition will only be done if the response is not already completed.
This will never happen for any exception in the render phase, because in
org.springframework.faces.mvc.JsfView in the finally block there will be always a responseComplete.
/**
* Performs the standard duties of the JSF RENDER_RESPONSE phase.
*/
public void render() throws IOException {
FacesContext facesContext = FlowFacesContext.getCurrentInstance();
if (facesContext.getResponseComplete()) {
return;
}
facesContext.setViewRoot(this.viewRoot);
try {
logger.debug("Asking faces lifecycle to render");
this.facesLifecycle.render(facesContext);
} finally {
logger.debug("View rendering complete");
facesContext.responseComplete();
}
}
For me it looks like a bug. How is the webflow exceptionhandling to work with exceptions in the renderphase?
There is no way to change the responseComplete-Flag, in org.springframework.webflow.context.servlet.ServletExternalContext
It is a private field with only the possibility to set it to true via
public void recordResponseComplete() {
responseComplete = true;
}
I changed in the debugger-session the flag to false. Then everything works like expected, and the user sees can see the error page.

Setting exception handled in Web API ExceptionFilterAttribute

Is there any way in ASP.NET Web API to mark an exception as handled in an ExceptionFilterAttribute?
I want to handle the exception at the method level with an exception filter and stop the propagation to a globally registered exception filter.
Filter used on a controller action:
public class MethodExceptionFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
if (context.Exception is NotImplementedException)
{
context.Response = new HttpResponseMessage(HttpStatusCode.InternalServerError)
{
Content = new StringContent(context.Exception.Message)
};
// here in MVC you could set context.ExceptionHandled = true;
}
}
}
The globally registered filter:
public class GlobalExceptionFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
if (context.Exception is SomeOtherException)
{
context.Response = new HttpResponseMessage(HttpStatusCode.SomethingElse)
{
Content = new StringContent(context.Exception.Message)
};
}
}
}
Try throwing an HttpResponseException at the end of your local handling. By design, they are not caught by exception filters.
throw new HttpResponseException(context.Response);
Web API 2 is designed with inversion of control in mind. You consider the possibility for the exception to already be handled, rather than interrupting the filter execution after you handle it.
In this sense, attributes deriving from ExceptionFilterAttribute should check if the exception is already handled, which your code already does since is operator returns false for null values. In addition, after you handle the exception, you set context.Exception to null in order to avoid further handling.
To achieve this in your code, you need to replace your comment from MethodExceptionFilterAttribute with context.Exception = null to clear the exception.
It is important to note that it is not a good idea to register more than one global exception filter, due to ordering issues. For information about the execution order of attribute filters in Web API, see the following thread Order of execution with multiple filters in web api.

ObjectDisposedException While using Include - why?

My page calls a Services layer method that uses a Generic Repository "Find" method. In the services layer method, I do the following:
using (IUnitOfWork unitOfWork = new DBContext())
{
GenericRepository<Operator> operatorRepos = new GenericRepository<Operator>(unitOfWork);
{
try
{
var oper = operatorRepos.Find(o => o.OperatorID == operatorID).Include(o => o.cmn_Address).Single();
return oper;
}
catch (InvalidOperationException exc)
{
//handle exception
}
}
}
The Find method for my repository:
public IQueryable<T> Find(Func<T, bool> predicate)
{
return _objectSet.Where<T>(predicate).AsQueryable();
}
On the page, I try to access the cmn_address Navigation property of the Operator and I get the following error:
The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
I realize that this is caused by the using statement to dispose of the context, but I thought the Include method will eager load the cmn_Address object. I don't understand why this doesn't work as I expected.
You are using Func<> instead of Expression<Func<>> in your where condition. That makes it Linq-to-objects. This change is permanent. Calling AsQueryable doesn't make it Linq-to-entities again.

JSF data binding

I am having trouble using JSF just wanted to run it by so if there is anything obvious someone can spot. I have a managed bean which is giving me trouble. In my faces-config.xml I have:
<managed-bean>
<description>Info Bean</description>
<managed-bean-name>InfoBean</managed-bean-name>
<managed-bean-class>bean.InfoBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
In my JSF I have the following:
<h:outputText value="#{InfoBean.deviceModel}" rendered="true"></h:outputText>
I have a POJO for InfoBean as follows:
public class InfoBean {
String deviceModel;
String userEmail;
String active;
public InfoBean() {
// TODO Auto-generated constructor stub
}
public String getDeviceModel() {
return deviceModel;
}
public void setDeviceModel(String deviceModel) {
this.deviceModel = deviceModel;
}
public String getUserEmail() {
return userEmail;
}
public void setUserEmail(String userEmail) {
this.userEmail = userEmail;
}
public String getActive() {
return active;
}
public void setActive(String active) {
this.active = active;
}
}
There is a no arg constructor in POJO too, but for some reason the deviceModel value does not get displayed to the screen and I cannot figure out why! Any help much appreciated. I have a handler which is also in the faces-config as a separate managed bean, when the user clicks a button, control goes to handler class which calls a service that populates fields in the POJO InfoBean, so as I can see it should appear but it does not!
Any help much appreciated.
I have sorted out the issue and the solution is that since I had a model like this: JSP button is clicked->call goes to Handler->handler calls method in service->Service populates the managed bean InfoBean and returns it to handler
The managed bean even though declared in the config file with scope as session was NOT actually part of the session. In my handler after returning the InfoBean I added:
HttpSession session = (HttpSession)FacesContext.getCurrentInstance().getExternalContext().getSession(false);
session.setAttribute("InfoBean", InfoBean);
This placed it in the session and immediately and values started appearing! :-))
I have read several articles about this and never seen this mentioned, so I am wondering how it is done otherwise. One other suggestion I got was make InfoBean a private instance of the Handler with getters and setters, this way it will get created with the handler and will also be olk. I have not tried this approach though. Thanks to all who helped.
How your deviceModel property of the bean is populated?
Are you sure that it is not null? You can eventually check that by putting a log in the getter method:
public String getDeviceModel() {
System.out.println("Getter called: " + deviceModel + ".");
return deviceModel;
}
Eventually, you can modify the scope of the bean to set it as session.
Your post shows it being defined in request scope not session scope. If you change it to session, you won't need put it in using setAttribute(). Or maybe I'm missing something.
Despite changign the scope to session, it was not working, the above code where I add it to the HttpSession is necessary in order for this to work, or so I have found.
Thanks.

Resources