How to prevent redundant persistence calls from GWT RequestFactory context? - java

In a project of mine I have a GWT EntityProxy simplified as follows:
#ProxyFor(value = Item.class, locator = ItemService.class)
public interface ItemProxy extends EntityProxy
{
String getName();
// other getters and setters here
}
with a corresponding entity implementation that is a simple JPA annotated entity bean.
I also have a request context:
#Service(value = ItemService.class, locator = InjectingServiceLocator.class)
public interface ItemRequestContext extends RequestContext
{
Request<List<ItemProxy>> findItems();
}
And the corresponding service and locator implementations:
public class ItemService extends Locator<Item, Long>
{
#Override
public Item find(Class<? extends Item> clazz, Long id)
{
return getItemFromJpa(id);
}
public List<Item> findItems()
{
return getAllItemsFromJpa();
}
// Remaining Locator and JPA methods skipped
}
When I invoke the findItems method in the GWT request context from the RPC perspective everything seems to work as expected and I get the items list in the callback method to work with in the client.
But from the persistence perspective the implementation does not work as expected: On the server side the method findItems is called as expected fetches my items from the persistence and returns them. Then for every single item the method find is called with the item's id and of course retrieves the items again from persistence one after each other.
What causes GWT request factory context to make these useless invocations and how can I prevent it from doing so?

Before returning to the browser, RequestFactory will check each and every domain object it saw (either from the request, or in the service methods' return value) to see whether it still exists or not, and thus determine whether it should tell the client that the object has been deleted (generate an EntityProxyChange event with WriteOperation.DELETE).
This check is done by calling the locator's isLive method, whose default implementation calls find with the object's ID and checks whether the return value is null.
In other words, you can simply override isLive in your locator to provide your own logic, and possibly bypass the call to the persistence layer.

Related

Java - Send a method as parameter and decide if there is need to call it

I am currently making an app and I am implementing cache in it. The thing is the DAOs are implemented in another service.
The idea that I had, to avoid code repeating, is having a generic cache in my service. Then, acording to the method called it verifies the respective cache and, in case it doesn't exist, calls the DAO associated with the method passed as parameter. Is there any way to do this?
NOTE: I am using java 1.6 in my application
I suppose you need an Adapter pattern. Naive realisation could be
class AdapterA implements Adapter<A> {
private A;
#Override
public void getValue() { return getA();}
}
and then when you get instance of A, B or C you wrap it in appropriate Adapter. Later you could call just getValue regardless specific type under hood.
Another approach. I would be grateful if someone say what the pattern is (possibly Proxy?):
class ProxyImpl implements Proxy {
#Override
public void doAction(<? extends DAO> dao) {
if (dao instance of A) { ((A)dao).getA()
} else if (dao instance of B) { ((B)dao).getB()

GWT Request Factory - Multiple queries for collection from the "ServiceLayerDecorator.isLive()" - method

I had the problem, that every time i retrieved a collection from the gwt request factory, there was the "findEntity()"-method called for every entity in that collection. And this "findEntity()"-method calls the SQL-Database.
I found out that this happens because request factory checks the "liveness" of every entity in the "ServiceLayerDecorator.isLive()"-method (also described here: requestfactory and findEntity method in GWT)
So i provided my own RequestFactoryServlet:
public class MyCustomRequestFactoryServlet extends RequestFactoryServlet {
public MyCustomRequestFactoryServlet() {
super(new DefaultExceptionHandler(), new MyCustomServiceLayerDecorator());
}
}
And my own ServiceLayerDecorator:
public class MyCustomServiceLayerDecorator extends ServiceLayerDecorator {
/**
* This check does normally a lookup against the db for every element in a collection
* -> Therefore overridden
*/
#Override
public boolean isLive(Object domainObject) {
return true;
}
}
This works so far and I don't get this massive amount of queries against the database.
Now I am wondering if I will get some other issues with that? Or is there a better way to solve this?
RequestFactory expects a session-per-request pattern with the session guaranteeing a single instance per entity (i.e. using a cache).
The proper fix is to have isLive hit that cache, not the database. If you use JPA or JDO, they should do that for you for free. What matters is what "the request" thinks about it (if you issued a delete request, isLive should return false), not really what's exactly stored in the DB, taking into account what other users could have done concurrently.
That being said, isLive is only used for driving EntityProxyChange events on the client side, so if you don't use them, it shouldn't cause any problem unconditionally returning true like you do.

GWT RF: How to share the same code in client and server

I would like to use the same code to sort and manipulate objects in client and server sides.
But I am facing a problem since in client we need a proxy interface representing the class of the server.
Is there a way to use the same interface in both?, I know RF has a mechanism to copy bean attributes from the server instance to the client instance when it is sent through the wire.
One way to use the same API is to use interfaces that both your proxies extend and your domain objects implement.
// common interfaces
interface Foo { … }
interface Bar<T extends Foo> {
int getX();
void setX(int x);
// setters need to use generics
List<T> getFoos();
void setFoos(List<T> foos);
// with only a getter, things get easier:
Bar getParent();
}
// domain objects
class RealFoo implements Foo { … }
class RealBar implements Bar<RealFoo> {
int x;
List<RealFoo> foos;
RealBar parent;
#Override
public RealBar getParent() { return parent; }
// other getters and setters
}
// proxy interfaces
#ProxyFor(RealFoo.class)
interface FooProxy extends Foo { … }
#ProxyFor(RealBar.class)
interface BarProxy extends Bar<FooProxy> {
#Override
BarProxy getParent();
// other getters and setters
}
You can then use a Comparator<Foo> or Comparator<Bar> in both client and server side.
I generally only implement traits (aspects, facets, call them the way you like) that way though (HasId, HasLabel, HasPosition, etc.), not complete domain objects' APIs. I can then use HasId to get the key of any object to put them in a map or compare for equality, HasLabel for displays (custom Cells on the client-side, error messages on the server-side that are sent to the client, etc.), HasPosition for sorting, etc.
As Thomas says in his answer, the only way in current GWT to have shared code in client and sever is implementing the same interface in both sides and using it in your shared code.
Since RF copies attributes from the server to the client as you say in your query, in theory we could use the same interface (the proxy one) in both sides (simpler code), setting the #ValueFor value pointing to itself.
Lets see an example:
// Shared interface in client and server sides
#ProxyFor(Foo.class)
interface Foo extends ValueProxy {
String getBar();
}
// Server side implementation
class FooImpl implements Foo {
String getBar(){return "bar";};
}
As information, we use this approach in our product, so as we can sell 2 backend solutions (one is based on GAE and other on couchdb).
The code above works for client code which does not create new values, but if you want to create them, it is enough to define a value locator:
// Say RF which locator to use to create classes in server side
#ProxyFor(value = Foo.class, locator ALocator.class)
interface Foo extends ValueProxy {
}
public class ALocator extends Locator<Foo, String> {
public Foo create(Class<? extends Foo> clazz) {
return new FooImpl();
}
...
}
Unfortunately, RF does not deal with interfaces in the server side see issues: 7509 and 5762.
But, as you can read in the issues comments, there is already a fix for this (pending for review). Hopefully it would be included in a next release of GWT.
In the meanwhile, you can use this approach, just copying the file ResolverServiceLayer.java in your src folder and applying this patch to it.
The point of RequestFactory is that it does not do use the same type. Each request context describes a set of operations to perform when the call gets to the server (create and find things, then apply setters, then run service methods). As calls are described as just proxies to the real thing on the server, you need a 'fake' model object like a EntityProxy or ValueProxy to ensure that the only calls that can be made are getters and setters - and that sometimes, setters are not allows (when an object has been read from the server but before it has been edited).
If your models are simple, i.e. not holding other objects, but only string, date, and primitives, you can have both the entity and the proxy implement the same interface. However, if the model holds sub-objects, then this is more difficult - the only way possible is to leave out those getters and setters. Otherwise, you can't override those methods in the proxy type to specify the proxy version of that nested object.
Consider using RPC isntead if you actually want to reuse the same types on the client and server.

spring singleton bean fields are not populated

I need a service (singleton fits) with some internal fields, like a list of pending threads (yes everything is written to be thread safe) the problem is that if I #autowire this bean, fields appear to be empty. Debugging I see that the proxy correctly binds to the instance (fields CGLIB$CALLBACK_X are correctly linked to the populated bean) with populated fields, but the fields it offers are empty.
The following lines of codes give a general idea of what i'm talking about.
#Service
public class myService{
#Autowired
private Monitor monitor;
public List getSomething(){
return monitor.getList();
}
}
#Service
public class myStatefulService{
//This field will be populated for sure by someone before getSomething() is called
private List list;
public synchronized List getSomething(){
return this.list;
}
//Called by other services that self inject this bean
public synchronized void addToList(Object o){
this.list.add(o);
}
}
Debugging the variable monitor during the getList call I get
monitor => instance of correct class
fields:
CGLIB$BOUND => true
CGLIB$CALLBACK_0.advised => proxyFactory (correct)
CGLIB$CALLBACK_1.target (reference to the correct instance of myStatefulService class)
fields:
list => [.........] (correctly populated)
CGLIB$CALLBACK_2 .....
......
......
......
list => [] (the list that would be populated is empty instead)
Are you curious or you have some real issue? Nevertheless here is an explanation.
When using CGLIB to proxy classes Spring will create a subclass called something like myService$EnhancerByCGLIB. This enhanced class will override some if not all of your business methods to apply cross-cutting concerns around your actual code.
Here comes the real surprise. This extra subclass does not call super methods of the base class. Instead it creates second instance of myService and delegates to it. This means you have two objects now: your real object and CGLIB enhanced object pointing to (wrapping) it.
The enhanced class is just a dummy proxy. It still has the same fields as your base class (inherited from it) but they are not used. When you call addToList() on myService$EnhancerByCGLIB object it will first apply some AOP logic, call addToList() of myService (which it wraps) and apply remaining AOP logic on return. The myService$EnhancerByCGLIB.list field is never touched.
Why can't Spring use the same class and delegate via super? I guess for simplicity: first create "raw" bean and then apply AOP proxying during post-processing.
"This field will be populated for sure by someone before getSomething() is called"
By someone? No, the Spring bean factory. If you don't configure it, nothing will be populated.
Not every bean needs to be under Spring's control. It sounds like you want to have a List that clients can add and remove items to in a thread-safe way. If that's true, remove the #Autowired annotation, create a new List, and expose methods to add and remove.
I'd recommend a List from the new concurrent collections.
CGLIB will proxy protected getters.
So you can have:
#Autowired
private Monitor monitor;
protected Monitor getMonitor() { return monitor; }
public List getSomething(){
return getMonitor().getList();
}
getMonitor() will be proxied to call getMonitor() on the other instance which has monitor injected.

Does GWT RequestFactory support implementation of optimistic concurrency control?

In a GWT app I present items that can be edited by users. Loading and saving the items is perfomed by using the GWT request factory. What I now want to achive is if two users concurrently edit an item that the user that saves first wins in the fashion of optimistic concurrency control. Meaning that when the second user saves his changes the request factory backend recognizes that the version or presence of the item stored in the backend has changed since it has been transfered to the client and the request factory/backend then somehow prevents the items from being updated/saved.
I tried to implement this in the service method that is used to save the items but this will not work because request factory hands in the items just retrieved from the backend with applied user's changes meaning the versions of these items are the current versions from the backend and a comparison pointless.
Are there any hooks in the request factory processing I coud leverage to achieve the requested behaviour? Any other ideas? Or do I have to use GWT-RPC instead...
No: http://code.google.com/p/google-web-toolkit/issues/detail?id=6046
Until the proposed API is implemented (EntityLocator, in comment #1, but it's not clear to me how the version info could be reconstructed from its serialized form), you'll have to somehow send the version back to the server.
As I said in the issue, this cannot be done by simply making the version property available in the proxy and setting it; but you could add another property: getting it would always return null (or similar nonexistent value), so that setting it on the client-side to the value of the "true" version property would always produce a change, which guaranties the value will be sent to the server as part of the "property diff"; and on the server-side, you could handle things either in the setter (when RequestFactory applies the "property diff" and calls the setter, if the value is different from the "true" version, then throw an exception) or in the service methods (compare the version sent from the client –which you'd get from a different getter than the one mapped on the client, as that one must always return null– to the "true" version of the object, and raise an error if they don't match).
Something like:
#ProxyFor(MyEntity.class)
interface MyEntityProxy extends EntityProxy {
String getServerVersion();
String getClientVersion();
void setClientVersion(String clientVersion);
…
}
#Entity
class MyEntity {
private String clientVersion;
#Version private String serverVersion;
public String getServerVersion() { return serverVersion; }
public String getClientVersion() { return null; }
public void setClientVersion(String clientVersion) {
this.clientVersion = clientVersion;
}
public void checkVersion() {
if (Objects.equal(serverVersion, clientVersion)) {
throw new OptimisticConcurrencyException();
}
}
}
Note that I haven't tested this, this is pure theory.
We came up with another workaround for optimistic locking in our app. Since the version can't be passed with the proxy itself (as Thomas explained) we are passing it via HTTP GET parameter to the request factory.
On the client:
MyRequestFactory factory = GWT.create( MyRequestFactory.class );
RequestTransport transport = new DefaultRequestTransport() {
#Override
public String getRequestUrl() {
return super.getRequestUrl() + "?version=" + getMyVersion();
}
};
factory.initialize(new SimpleEventBus(), transport);
On the server we create a ServiceLayerDecorator and read version from the RequestFactoryServlet.getThreadLocalRequest():
public static class MyServiceLayerDecorator extends ServiceLayerDecorator {
#Override
public final <T> T loadDomainObject(final Class<T> clazz, final Object domainId) {
HttpServletRequest threadLocalRequest = RequestFactoryServlet.getThreadLocalRequest();
String clientVersion = threadLocalRequest.getParameter("version") );
T domainObject = super.loadDomainObject(clazz, domainId);
String serverVersion = ((HasVersion)domainObject).getVersion();
if ( versionMismatch(serverVersion, clientVersion) )
report("Version error!");
return domainObject;
}
}
The advantage is that loadDomainObject() is called before any changes are applied to the domain object by RF.
In our case we're just tracking one entity so we're using one version but approach can be extended to multiple entities.

Categories