I need to use GWT with a service-based domain layer - not beans with DAOs. Is the GWT 2.1 architecture with MVP and RequestFactory fitted for this? Or should I stay with RPC?
Thanks
GWT 2.1.1 adds a Locator and ServiceLocator mechanism to allow you to control how the RequestFactory server code obtains references to entities and service object instances.
For example, you can declare code like
class MyService.class {
// Note that this is not a static method
public void doSomething() {....};
}
class MyServiceLocator implements ServiceLocator {
public Object getInstance(Class<?> clazz) {
// Or use Guice, Spring, whatever provides instances of MyService
return new MyService();
}
}
interface MyRequestFactory extends RequestFactory {
#Service(value=MyService.class, locator=MyServiceLocator.class)
interface ServiceRequest extends RequestContext {
Request<Void> doSomething();
}
ServiceRequest myService();
}
If you need even more control over how RequestFactory interacts with your server domain objects or service code, you can inject instances of ServiceLayerDecorator into the service layer.
Related
I have situation like this
I have controller code
#RestController
public class MyController implements SomeApi {
#Autowired
private final MyService myService ;
public ResponseEntity<AnswerObject> getSomething (RestModelObject obj) {
myService.getSomething(obj);
}
Below Service code:
#Service
public class MyServiceImpl implements MyService {
#Autowired
private final EntityRepository entityRepository;
public AnswerObject getSomething (RestModelObject obj) {
Entity entity = entityRepository.getSomething(obj);
AnswerObject answerObject = map(entity, new AnswerObject());
return answerObject;
}
}
I have here few layers as I can see - rest layer, business layer, persistence layer (let's suppose I have few data sources - DB and elastic, each have some repository bean).
As we can see Business layer (service) aware about entities, which is not really good I think.
So question is what is the best practices for this situation?
Mapping should happen on persistence layer?
Or Is it good idea to create some additional layer adapter which will be responsible for mappings between rest models to internal data models, and inject it to the service bean ?
Appreciate any good mature examples.
I think, it can be done on controller's level, like in example here. Correct me If I am wrong.
I read a lot about the possibility of injection with jax rs 2.0 and in particular with jersey.
I even read that ejb injection is expected in jax rs 2.0 spec. But i still haven't found a unique solution among the variety of posts i read over the net.
In my use case i'm working with:
WildFly 9.0 and Jersey 2.x
I have a webapplication exposing my REST services and importing a jar implementing my model data.
This is the CDI approach:
#RequestScoped
#Path("/myPath")
public class ModelRetriever {
#Context
SecurityContext securityContext;
#Inject
private IMyModel MyModel;
#Path("{i}")
#GET
#Produces("application/json")
public Response countries(#PathParam("i") String countryId)
throws JSONException, Failure, IOException {
MyModel.doSomething();
}
This is my IMyModel interface
public interface IKasPrincipal extends Principal {
public void doSomething();
}
And this is MyModel implementation:
#RequestScope
public class MyModelImpl implements IMyModel {
public void doSomehting() {
doSomething();
}
}
Another method i tried is to use EJB injection changing my previous annotations like this:
#Stateless
#Path("/myPath")
public class ModelRetriever {
#EJB
private IMyModel MyModel;
#Path("{i}")
#GET
#Produces("application/json")
public Response countries(#PathParam("i") String countryId)
throws JSONException, Failure, IOException {
MyModel.doSomething();
}
This is my IMyModel interface
#Local
public interface IKasPrincipal extends Principal {
public void doSomething();
}
And this is MyModel implementation:
#Stateless
public class MyModelImpl implements IMyModel {
public void doSomehting() {
doSomething();
}
}
i get a null object using EJB approach and i get this exception using CDI
Caused by: org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=IMyModel,parent=ModelRetriever,qualifiers={},position=-1,optional=false,self=false,unqualified=null,616459318)
at org.jvnet.hk2.internal.ThreeThirtyResolver.resolve(ThreeThirtyResolver.java:75)
at org.jvnet.hk2.internal.ClazzCreator.resolve(ClazzCreator.java:211)
at org.jvnet.hk2.internal.ClazzCreator.resolveAllDependencies(ClazzCreator.java:234)
So is there anything i'm missing?
see other Stack Overflow related posts:
Dependency injection with Jersey 2.0
HK2 Jersey EJB 3 injection
The problem you are having is that HK2 does not know about anything that was not registered directly into it, and HK2 tries to to satisfy all dependency in your Jersey aware class.
I has this issue a while back. Then I discovered that Jersey uses HK2 internally. HK2 is a JSR-330 implementation (CDI).
One would think that a open-source project would declares it's CDI beans and use them regardless of the CDI implementation, but it looks like its not that way.
see : https://java.net/jira/browse/JERSEY-1933
see : https://hk2.java.net/integration.html
You can register your components into HK2...
see : https://jersey.java.net/documentation/latest/ioc.html
For all I know, you cannot inject CDI components (or anything else, as EJB) into Jersey's classes using your own (or your container's) CDI implementation, unless you use Glassfish (which personally I would never use) which in turn uses HK2 as its CDI implementation.
To me, this is a major draw back. But the only(?) draw back of Jersey.
-Maybe I missed something (which is very possible)
-Maybe this is a trick from Oracle so that you can't use Jersey in, let's say, your Websphere app which uses OpenWeb Beans as CDI implementation.
-Maybe they hardwired it to HK2, and just don't care that Jersey can't be used as a drop in component in your application, which relies on CDI or EJB
I'm not aware of why #EJB not worked, but, you can use #Produces/#Disposes bean.
#ApplicationScoped // or some other scoped
public class MyModelProducer {
#Produces public MyModel produceMyModel() {
}
public void disposeMyModel#Disposes final MyModel model) {
}
}
I'm writing a Java EE 6 application that makes use of Morphia to persist objects to MongoDB. I'd like to be able to #Inject my DAO classes where necessary, so I created a Factory class that instantiates the DAO appropriately. It looks something like this:
public class MyDAOFactory {
#Inject
private Datastore mongoDatastore = null;
/**
* Creates the DAO
*/
#Produces
#ApplicationScoped
public MyDAO createDAO() {
MyDAO dao = new MyDAO(
this.mongoDatastore);
return dao;
}
}
The code compiles fine, but when I run my application on JBoss EAP 6.1 it complains because MyDAO does not have a no-arg constructor. I would add one, but the Morphia BasicDAO class does not have one either, so I don't know that it would work that way.
Is there a way to #Inject a DAO instance into my EJB, Servlet, etc.? Or do I need to manually instantiate it every time?
It seems that CDI needs the no-arg constructor for MyDAO for some reason. Maybe because of how you use this bean (see specs ch.5.4 "Client Proxies" for possible reasons).
You cannot create a default constructor, because the base class does not have one and, from what I see from the code the super constructors make immediate use of their args. Therefore passing null to super() from a no-arg constructor will throw errors.
My suggestion is to create an interface (optionally extending org.mongodb.morphia.dao.DAO), e.g. MyDAOInterface that has all public business methods of MyDAO. Then modify MyDAO to implement this interface and change your producer to return MyDAOInterface:
public interface MyDAOInterface extends DAO {...}
public class MyDAO implements MyDAOInterface {
// same implementation
}
public class MyDAOFactory {
#Inject
private Datastore mongoDatastore = null;
/**
* Creates the DAO
*/
#Produces
#ApplicationScoped
public MyDAOInterface createDAO() {
MyDAO dao = new MyDAO(this.mongoDatastore);
return dao;
}
}
By the way, programming to interfaces has the extra benefit of making your code more testable, so it is worth the minor hassle.
I have my OrganizationRequestContext interface, which works great:
#Service(OrganizationDAO.class)
public interface OrganizationRequestContext extends RequestContext
{
Request<OrganizationProxy> findOrganization(Long id);
InstanceRequest<OrganizationProxy, Void> persist();
InstanceRequest<OrganizationProxy, Void> remove();
}
Now I want to take those last two functions and put them in a PersistentRequestContext of my own design so that I can treat all of my RequestContexts the same in my client code:
public interface PersistableRequestContext<T extends BaseProxy>
{
InstanceRequest<T, Void> persist();
InstanceRequest<T, Void> remove();
}
...
#Service(OrganizationDAO.class)
public interface OrganizationRequestContext extends RequestContext, PersistentRequestContext<OrganizationProxy>
{
Request<OrganizationProxy> findOrganization(Long id);
}
But this fails validation: the server complains that
[ERROR] com.activegrade.shared.data.PersistableRequestContext is not a RequestContext
If I make PersistableRequestContext extend RequestContext, then the server complains that it is not linked to any particular DAO service.
Is there any way to extend a common interface besides RequestContext in my various RequestContext interfaces?
This issue has been fixed in GWT 2.4. Thanks Google!
http://code.google.com/p/google-web-toolkit/issues/detail?id=6035
I have some questions regarding gwt-dispatch and guice. I'm using Guice 2.0, gwt-dispatch 1.1.0 snapshot, mvp4g 1.1.0 and GIN 1.0
First of all, I have defined simple action, result and handler:
ListContactsAction.java
public class ListContactsAction implements Action<ListContactsResult>{
public ListContactsAction() {
}
}
ListContactsResult.java
public class ListContactsResult implements Result {
private List<Contact> contactList;
public ListContactsResult() {
}
public ListContactsResult(List<Contact> contactList) {
this.contactList = contactList;
}
public List<Contact> getContactList() {
return contactList;
}
}
ListContactsHandler.java
public class ListContactsHandler implements ActionHandler<ListContactsAction, ListContactsResult>{
#Inject
private SqlSessionFactory factory;
public Class<ListContactsAction> getActionType() {
return ListContactsAction.class;
}
public ListContactsResult execute(ListContactsAction a, ExecutionContext ec) throws DispatchException {
// some code using SqlSessionFactory and returning ListContactResult
// with list of contacts
}
public void rollback(ListContactsAction a, ListContactsResult r, ExecutionContext ec) throws DispatchException {
/* get action - no rollback needed */
}
}
In previous version of my app, which was using rpc service instead of command pattern, I had a method which was providing SqlSessionFactory for injections, something like this:
#Provides
public SqlSessionFactory getSqlSessionFactory(){
// some code here
}
I read on gwt-dispatch getting started that I have to provide binding between my action and it's handler, which should look something like that:
public class ContactModule extends ActionHandlerModule{
#Override
protected void configureHandlers() {
bindHandler(ListContactsAction.class, ListContactsHandler.class);
}
}
But I have problem wiring it all with Guice, because this example from gwt-dispatch site:
public class DispatchServletModule extends ServletModule {
#Override
public void configureServlets() {
serve( "/path/to/dispatch" ).with( DispatchServiceServlet.class );
}
}
doesn't work, since there is no DispatchServiceServlet in the package.
My questions are:
How should I write DispatchServletModule and how to make it going (with what I should serve path)
what should I put in the web.xml file of my app to be able to correctly execute actions from my presenter, which has GIN injected DispatcherAsync implementation
Where should I put my SqlSessionFactory providing method (in which module) to be able to inject SqlSessionFactory where I need it
How I instantiate the injector so then I can use it in other action handlers properly
I think that is all and I made myself clear. If something isn't clear enough, I'll try to be more specific.
Have you created a GuiceServletConfig class? This is where you setup your Dispatch servlet module as well as your action handler module with Guice.
plubic class GuiceServletConfig extends GuiceServletContextListener {
#Override
protected Injector getInjector() {
return Guice.createInjector(new HandlerModule(), new DispatchServletModule());
}
}
The HandlerModule is your ActionHandler module class, so from your code you would put your ContactModule class.
For your SqlSessionFactory, you could setup the binding for it in your ContactModule, with my code I only have a single ServerModule that sets up all my service and action handler bindings. This is mainly for the sake of simplicity.
GWT-Platform framework uses a gwt-dispatch fork to handle rpc requests. There's a lot of code, which you probably had to wtite yourself, if you think of seriously using dispatcher and Guice. I highly recommend it.
Firstly, I sympathise. Putting this all together isn't documented in any one spot. I'll answer each of your questions in turn. Add comments to my answer if any of it is unclear.
QU: How should I write DispatchServletModule and how to make it going (with what I should serve path)?
There's a GuiceStandardDispatchServlet class in the net.customware.gwt.dispatch.server.guice package; use that. I'm not 100 percent sure why, but the path I use includes the name of my GWT module, followed by '/dispatch'. You might have to experiment with that.
public class MyServletModule extends ServletModule {
#Override protected void configureServlets() {
serve("/com.my.module.name/dispatch")
.with(GuiceStandardDispatchServlet.class);
}
}
QU: what should I put in the web.xml file of my app to be able to correctly execute actions from my presenter, which has GIN injected DispatcherAsync implementation?
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<filter>
<filter-name>guiceFilter</filter-name>
<filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>guiceFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>com.myapp.whatever.MyContextListener</listener-class>
</listener>
...
</web-app>
... and then you'll need a custom context listener that creates a Guice injector as follows. Notice that I've included your ContactModule, which binds action handlers.
public class MyContextListener extends GuiceServletContextListener {
#Override protected Injector getInjector() {
return Guice.createInjector(new MyServletModule(),
new ContactModule(), new SQLStuffModule());
}
}
QU: Where should I put my SqlSessionFactory providing method (in which module) to be able to inject SqlSessionFactory where I need it?
Notice that I included a new SQLStuffModule in the previous code snippet; that would be a good place to put your SqlSessionFactory binding. There's no harm having multiple modules, and I find that it keeps the various concerns nicely separated.
QU: How I instantiate the injector so then I can use it in other action handlers properly?
For the server-side, see the MyContextListener code snippet above.
On the client side, you'll need a custom injector interface something like this:
#GinModules(StandardDispatchModule.class, MyClientModule.class)
public interface MyGinjector extends Ginjector {
MyWidgetMainPanel getMainPanel();
}
...and you can bind your MVP stuff in a custom Gin module as follows. I'm sorry that I'm not familiar with mvp4g, but I assume that you'll need to wire the views and presenters together in the module class.
public class MyClientModule extends AbstractGinModule {
#Override protected void configure() {
bind(...).to(...);
...
}
}