GWT Autobean frozen when saving graph - java

I am using GWT 2.4 with the editor and request factory frameworks. I have a model, Trip, which has an Address 'origin' and an Address 'destination'. When creating a Trip via the UI, the two addresses are created automatically and assigned to the Trip. User fills out details and saves. For some reason, I am getting the 'autobean frozen error' when trying to persist to the server. This code worked in GWT 2.3 and I cant switch back. I am hoping its not a bug in GWT 2.4. Here is some sample code of what I am doing:
RequestContext request = requestFactory.request();
TripProxy trip = request.create(TripProxy.class);
trip.setOrigin(request.create(AddressProxy.class));
trip.setDestination(request.create(AddressProxy.class));
driver.edit(trip, request);
this.trip = trip;
// … on save button clicked (different method)
RequestContext request = driver.flush();
request.save(trip).with(driver.getPaths()).fire(someReceiverImpl);
Results in:
java.lang.IllegalStateException: The AutoBean has been frozen
at com.google.web.bindery.autobean.shared.impl.AbstractAutoBean.checkFrozen(AbstractAutoBean.java:195)
at com.google.web.bindery.autobean.shared.impl.AbstractAutoBean.setProperty(AbstractAutoBean.java:270)
at sun.reflect.GeneratedMethodAccessor53.invoke(Unknown Source)
The call to fire completes successfully but somewhere from within requestfactory, the above error is thrown. Curiously, the entity is saved on the server however, validations are not enforced. When I simplify the model and remove the Address associations, the validation and save works. My main issue is the autobean frozen error; the validation stuff is secondary.
EDIT: On further investigation I found that the entities are making it to the server okay and persisting as expected. Its upon return that the above exception is thrown. AddressProxy is a ValueProxy and it looks like RF doesnt like Trip coming back with these associations. Returning null 'fixes' the problem but this obviously wont work long term.

I know this is a lot more than you're asking for, but these 3 tips have helped me out (from here):
Trying to edit locked entity.
If an entity is frozen ( locked for changes) you cannot:
change its properties
use it in requestContext method calls.
If you try to do it, you will receive the exception : java.lang.IllegalStateException: The AutoBean has been frozen.
When entity may be frozen?
every entity returned as a response is frozen
every entity which has been used in requestContext call will be frozen.
In first situation solution is easy – you just have to unlock given entity. In order to do that you must use instance of your RequestContext class and call edit() method.
StudentRequest req1 = requestFactory.studentRequest();
StudentProxy s2 = req1.edit(s1);
In second situation you should not use given entity any more, It cannot be edited because it has already a requestContext assigned. If you want to change it you must retrieve instance of this entity from server again and follow instructions for point a).
Trying to call requestContext.edit() on entity which already has a requestContext assigned.
If you have retrieved the entity from the server or created a new one, and afterwords you are trying to use ANOTHER RequestContext to edit it e.g. in this way:
StudentRequest req = requestFactory.studentRequest();
s1 = req.create(StudentProxy.class);
// s1 is connected with "req" and one context is just enough for it
StudentRequest reqZZZ = requestFactory.studentRequest();
reqZZZ.edit(s1); // you cannot do it - here exception will be thrown
you will surely recieve an exception:
java.lang.IllegalArgumentException: Attempting to edit an EntityProxy previously edited by another RequestContext
You may run into this problem in situations where you have a bean, but you have no track of request context which has created or edited the bean in some previous method call. In this situation you must save the previous requestContext somewhere, or send it along with the entity to the point of interest. The best solution may be to create some special layer which holds currently used request.
Trying to reuse a Request Context which has already been fired.
You can use a request context to create and edit many different entities (also of a different type). You can also accumulate the methods which should be fired. But what you cannot do is to try to use it twice to fire a request. If you have created a request and call the fire() method on it, you cannot do it again. If you do you will get: java.lang.IllegalStateException:A request is already in progress exception.
The solution is to simply create a new requestContext.

This was caused by not using the same EntityManager on the server.

Related

Spring MVC Binding Command Object Using Get Request

I need to implement a controller that has a command object that is backing a filtering form for a search across multiple entries.
The problem is that the i was asked to do that without using POST request, instead using GET request only, and there before loosing the functionality of the default data binding that springs makes happily for us.
So i tried to implement a method, inside my controller, that looks like this:
#Override
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
throws Exception {
if (isSearchRequest(request)) {
MyCommandObject myCommandObject = (MyCommandObject) getCommand(request);
System.out.println(managePositionsForm);
}
return super.handleRequestInternal(request, response);
}
But the getCommand returns me a brand new CommandObject with no values, despite that the values are present in the request object (i could retrieve then using the getParameter method of HttpServletRequest). But there isn't any binding.
So the question :
1) Is there any way to archive this?
2) Also is very important, that all the values in the form, are lost and, eventually (if this problem is solved) i will need to "persist" the filters for the users in order to avoid re entering after the first search.
Auto Response : setSessionForm(true); looks like can do the work! (According to javadoc)
Thanks to all!
Greetings
Victor.
Okey, i found a way to archive what a was looking for.
I will explain for the sake of those have the same problem before, and hoping to find a experienced user to validate this method... some quiet common is there a multiple ways to do a same thing and as human beings is very difficult to know without proper acknowledge the right path.. so this i a found looking inside the AbstractFormController (that is excellently documented with javadoc).
So what i did was the following, on my controller constructor i add these lines at the end :
setSessionForm(true);
setBindOnNewForm(true);
That all the magic!
But is not enought with setSessionForm(true). According to javadoc the setBindOnNewForm(boolean) method does the following :
/**
* Set if request parameters should be bound to the form object
* in case of a non-submitting request, i.e. a new form.
*/
So my guess are that these two flags are necessary to be marked as true, because :
The setSessionForm makes posible to store as a session attribute the form object, so "is stored in the session to keep the form object instance between requests, instead of creating a new one on each request" (according to javadoc of the setSessionForm method).
The setBindOnNewForm allows the population of the form object with the initial request (despites what type of request method we have). According the javadoc found the AbstractFormController "Only if bindOnNewForm is set to true, then ServletRequestDataBinder gets applied to populate the new form object with initial request parameters..."
But still i noticed, following the controller flow with a debugger, that the population is happening inside the method "getErrorsForNewForm(HttpServletRequest request)".. that is where a concrete object of type ServletRequestDataBinder is used IF the setBindOnNewForm is true, and later (as the javadoc stated) the onBindOnNewForm method is invoked, allowing the programmer to overwrite it with custom behavior, the default behavior is just empty (again this was double checked against the code of AbstractFormController).
I have an strong felling to validate my thoughts here, so if anyone can help me, that would be alright, besides the problem is solved!
Thanks to all in advance!
Greetings.

Is ActionContext in Struts 2 unique to the current request?

I'm using a custom interceptor which creates a new db connection, and sets this connection onto the current action before executing the action. After that, the interceptor closes the connection.
I'm looking for a convenient way to share this db connection with other classes / static methods (such as Models) that are used by the action. E.g so I can call static method like User.get( id ) or User.getEmail( id ) without having to pass the db connection to each method separately.
I could set the db connection onto the ActionContext from the interceptor, by doing:
ServletActionContext.getActionContext().put("db", db );
And then I could access this db connection from a static method, such as:
public class User implements Model
{
public static String getEmail(int id)
{
Connection db =
(Connection) ServletActionContext.getActionContext().get("db");
//...
}
}
My question is, would a new ActionContext be generated for every given request, so I can be sure that a new db connection will be used each time? E.g if I have 500 people visiting mysite.com/fooAction, could I be sure that each of those 500 requests is generating a unique ActionContext, and each call to User.getEmail() would access only the db connection which is unique to the given request?
Thanks.
To answer the question :
My question is, would a new ActionContext be generated for every given
request, so I can be sure that a new db connection will be used each
time?
Is yes. Reference is the java-doc. It similar to the one provided by Alfredo Osorio only it refers to 2.3.x version.
Can you say what struts2 version is being used?
I was not able to find any version that uses
ServletActionContext.getActionContext()
but instead the signature is
ServletActionContext.getActionContext(javax.servlet.http.HttpServletRequest)
To answer the comment regarding thread-local being static and still the ActionContext instance being unique per request its because the doing a
ActionContext.getContext()
internally invokes a get on the thread local instance.
actionContext.get()
You may find the following post helpful in this regard.
However to delve deeper, the method
ServletActionContext.getActionContext(javax.servlet.http.HttpServletRequest)
takes a different route than using the thread-local.
public static ActionContext getActionContext(HttpServletRequest req) {
ValueStack vs = getValueStack(req);
if (vs != null) {
return new ActionContext(vs.getContext());
} else {
return null;
}
}
public static ValueStack getValueStack(HttpServletRequest req) {
return (ValueStack) req.getAttribute(STRUTS_VALUESTACK_KEY);
}
getActionContext
getValueStack
Below are some additional references (source code).
ValueStack
OgnlValueStack
ActionContext
The following posts may also be helpful.
will-a-new-actioncontext-and-valuestack-be-created-for-every-new-action-object
struts2-actioncontext-and-valuestack
Update 2 :
Wanted to add as mentioned here (Link 1 above) that in case of ActionChaining being involved, the action is invoked with its own interceptor stack and result.
The thread in which its executed, however is the same.
The value-stack and parameters are copied over. See - ActionChainResult#execute(ActionInvocation).
Once the chain-invocation is complete, the state of the action-context is reset. (See DefaultActionProxy#execute() ).
Partial Information : Although the action-invocation is set in DefaultActionInvocation#init(ActionProxy) I was not able to determine if or where it is reset.
Sources :
DefaultActionInvocation
DefaultActionProxy
DefaultActionProxyFactory
ActionChainResult
FilterDispatcher(Deprecated)
My question is, would a new ActionContext be generated for every given
request, so I can be sure that a new db connection will be used each
time?
Since ActionContext uses ThreadLocal it is thread safe. Struts 2 creates an ActionContext for each request, and each request has its own thread. So yes, if you create a new connection and store it in the ActionContext every thread will have its own connection. But I don't recommend you to store the connection in the ActionContext because this couple you to Struts 2 which is not a good thing, also your services shouldn't be calling web specific classes because it also couple them.
From Struts 2 Javadoc:
The ActionContext is the context in which an Action is executed. Each
context is basically a container of objects an action needs for
execution like the session, parameters, locale, etc.
The ActionContext is thread local which means that values stored in
the ActionContext are unique per thread. See the
ActionContext.ActionContextThreadLocal class for more information. The
benefit of this is you don't need to worry about a user specific
action context, you just get it:
ActionContext context = ActionContext.getContext(); Finally, because
of the thread local usage you don't need to worry about making your
actions thread safe.
ActionContext excerpt:
public class ActionContext implements Serializable {
static ThreadLocal<ActionContext> actionContext = new ThreadLocal<ActionContext>();
....
}

How to read parameters passed by extjs record.set(values) in an rest service coded in java?

I am new to extjs and am trying to implement the update operation. I tried to Google but could not find a solution.
I have form which is used for updating records in a store. For this, I am using the following code in the controller,
var formPanel = Ext.getCmp('displayForm');
var record = formPanel.getRecord();
var values = formPanel.getValues();
record.set(values);
companyStore.sync();
The record.set() method calls the method(i.e.rest service) pointed by the URL specified for update operation in the store’s proxy.
How can I read the values passed by the record.set() method in the rest service coded in java.
I tried with,
#POST
#Produces({"application/xml"})
#Path("/updateData")
public CompanyDataService updateData(#QueryParam("company") Company companyObj){
//code
}
but companyObj is unable to capture the parameter values
There is no "values" parameter being passed. Based on the configuration of your store proxy's Writer (http://docs.sencha.com/extjs/4.2.1/#!/api/Ext.data.writer.Json), the parameters will either be a single root value (if encode configuration is true), or as individually named parameters, one per model field being persisted.
How is your Writer configured?
Also, just to clarify, record.set() doesn't trigger the proxy call unless autoSync is configured to true. In you example, I suspect the proxy call is happening because you explicitly call sync().

GWT manually serialize domain object on server

The first thing my GWT app does when it loads is request the current logged in user from the server via RequestFactory. This blocks because I need properties of the User to know how to proceed. This only takes < 500ms, but it really annoys me that the app is blocked during this time. I already have the User on the server when the jsp is generated, so why not just add the serialized User to the jsp and eliminate this request altogether?
I have two problems keeping me from doing this:
I need to transform User to UserProxy
I need to serialize UserProxy in a way that is easy for GWT to deserialize.
I have not figured out a good way to do #1. This logic appears to be buried in ServiceLayerDecorator without an easy way to isolate? I may be wrong here.
The second one seems easier via ProxySerializer But how do I get my hands on the requestfactory when I am on the server? You cannot call GWT.create on the server.
I have been looking into AutoBeans but this does not handle #1 above. My UserProxy has references to collections of other EntityProxy's that I would like to maintain.
It is possible using AutoBeans if you create an AutoBeanFactory for your proxies:
To transform User to UserProxy:
Create a server side RequestFactory and invoke the same normal request. Response will contain UserProxy (but on the server).
To serialize UserProxy:
AutoBean<UserProxy> bean = AutoBeanUtils.getAutoBean(receivedUserProxy);
String json = AutoBeanCodex.encode(bean).getPayload();
To deserialize UserProxy on client:
AutoBean<UserProxy> bean = AutoBeanCodex.decode(userAutoBeanFactory, UserProxy.class, json);
Creating an in-process RequestFactory on the server (tutorial):
public static <T extends RequestFactory> T create( Class<T> requestFactoryClass ) {
ServiceLayer serviceLayer = ServiceLayer.create();
SimpleRequestProcessor processor = new SimpleRequestProcessor( serviceLayer );
T factory = RequestFactorySource.create( requestFactoryClass );
factory.initialize( new SimpleEventBus(), new InProcessRequestTransport(processor) );
return factory;
}
You could use AutoBeans for this as well if you are able to make User implements UserProxy. It works since Proxies are interfaces with getters/setters:
interface UserFactory implements AutoBeanFactory
{
AutoBean<UserProxy> user(UserProxy toWrap); // wrap existing instance in an AutoBean
}
Then on server you can create the autobean and serialize to json:
UserFactory factory = AutoBeanFactorySource.create(UserFactory.class)
AutoBean<UserProxy> userProxyBean = factory.user( existingUserPojo );
// to convert AutoBean to JSON
String json = AutoBeanCodex.encode(userProxyBean).getPayload();
On the client you can just use AutoBeanCodex.decode to deserialize JSON back to a bean
You cannot call GWT.create on the server (or from any real JVM), but in many cases you can call a JVM-compatible method designed for server use instead. In this case, take a look at RequestFactorySource.create.
It can be a little messy to get the server to read from itself and print out data using RequestFactory - here is a demo example of how this can work (using gwt 2.4, the main branch has the same thing for 2.3 or so) https://github.com/niloc132/tvguide-sample-parent/blob/gwt-2.4.0/tvguide-client/src/main/java/com/acme/gwt/server/TvViewerJsonBootstrap.java - not quite the same thing that you are after, but it may be possible to use this same idea to populate a string in a proxy store that can be read in the client (seen here https://github.com/niloc132/tvguide-sample-parent/blob/gwt-2.4.0/tvguide-client/src/main/java/com/acme/gwt/client/TvGuide.java).
The basic idea is to create a request (including ids, invocations, and with() arguments so the proxy builder makes all the right pieces in a consistent way), and pass it into a SimpleRequestProcessor instance, which will then run it through the server pieces it normally would. (Any entity management system probably should still have the entities cached to avoid an additional lookup, otherwise you need to model some of the work SRP doesn internally.) The ProxySerializer, which wraps a ProxyStore, expects to have full RF messages as sent from the server, so a fair bit of message bookkeeping needs to be done correctly.
I found the answer on the GWT Google Group. All credits go to Nisha Sowdri NM.
Server side encoding:
DefaultProxyStore store = new DefaultProxyStore();
ProxySerializer ser = requests.getSerializer(store);
final String key = ser.serialize(userProxy);
String message = key + ":" + store.encode();
Client side decoding:
String[] parts = message.split(":", 2);
ProxyStore store = new DefaultProxyStore(parts[1]);
ProxySerializer ser = requests.getSerializer(store);
UserProxy user = ser.deserialize(UserProxy.class, parts[0]);

Hibernate Lazy Load Error after merge

I'm using vanilla Spring MVC with a custom FlashScope implementation. We basically use it to follow the Post-Redirect-Get pattern.
I've run into an odd situation. In my Post I do some searching for the parameters the user entered, and I set those instances onto FlashScope. I see those pieces working just fine.
In the object I place onto FlashScope I have a lazy loaded collection, however when I attempt to access the collection like so:
entity.getLazyLoadedCollection();
I receive the following stacktrace:
ERROR org.hibernate.LazyInitializationException IP127.0.0.1 CV#4c44559c-c576-4732 P#75004 - could not initialize proxy - no Session
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:167)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:215)
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)
at core.model.entities.WorkflowState_$$_javassist_36.getFunctions(WorkflowState_$$_javassist_36.java)
The odd thing is that right before the call above I merge it onto the session in my service layer:
getSession().merge(entity);
Hibernate Documentation states that I should call update if I know that I'm working with a new session, but the JavaDocs make it seem like I should call merge...
As a workaround I've done the following:
if (getSession().contains(entity)) {
getHibernateTemplate().merge(person);
} else {
getSession.update(entity);
}
What should I be doing here?
Read the javadoc that you linked carefully: "Return the persistent instance. If the given instance is unsaved, save a copy of and return it as a newly persistent instance. The given instance does not become associated with the session."
No matter what you pass to merge(), that object doesn't get associated to the session. You need to be working with the object returned from merge().
Never worked with FlashScope, but your error apeears to be because you are trying to access a LAZY collection which has not been initialized, and you are no longer in a layer of your app which has access to the Hibernate Session. If that assumption is correct, you need to initialize the collection where you have access to the Session (e.g., your DAO). Here are 2 basic ways:
Hibernate.initialize(object.getMyLazyCollection());
or
if(object.getMyLazyCollection() != null) {
object.getMyLazyCollection().size(); // forces a collection load
}

Categories