Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    Guice server-side

    I am trying to use guice to instantiate my server-side objects used by my DMI objects.

    So I have for example:
    Code:
    public class DokumenteDMIHandler {
        private MyService myService;
        
    @Inject
        public DokumenteDMIHandler(MyService myService) {
    this.myService = myService;
        }
    This is throwing the exception shown in the screenshot. Click image for larger version

Name:	Bildschirmfoto 2016-10-27 um 16.16.31.png
Views:	216
Size:	89.3 KB
ID:	241034




    So I changed it to: (although I do not like this)

    Code:
    public class DokumenteDMIHandler {
        @Inject
        private MyService myService;
        
        public DokumenteDMIHandler() {
        }
    Then I get a NullPointerException when trying to use MyService.
    So I guess the DokumenteDMIHandler is not being managed by Guice.

    I read the startup guide and tried by adding the lookup-style to the serverObject, hoping that it would be created by guice :

    Code:
    <operationBinding operationType="add" operationId="myOperationId">
                <serverObject className="de.mks_infofabrik.kids.server.dmi.DokumenteDMIHandler"
                    methodName="wikitaImport" lookupStyle="cdi" />
            </operationBinding>
    As I read in the quick start guide, either either "bean" or "className" is needed, so I left my className.

    But now I get:
    Code:
    === 2016-10-27 17:36:35,779 [ec-2] INFO  ServerObject - DMI on CDI bean: de.mks_infofabrik.kids.server.dmi.DokumenteDMIHandler
    === 2016-10-27 17:36:35,784 [ec-2] WARN  RequestContext - dsRequest.execute() failed:
    java.lang.RuntimeException: javax.naming.NameNotFoundException: Name [BeanManager] is not bound in this Context. Unable to find [BeanManager].
        at com.isomorphic.cdi.CDIBeanManager.getBeanManager(CDIBeanManager.java:63)
        at com.isomorphic.cdi.CDIBeanManager.getBean(CDIBeanManager.java:89)
        at com.isomorphic.rpc.ServerObject.<init>(ServerObject.java:257)
        at com.isomorphic.datasource.DataSourceDMI.execute(DataSourceDMI.java:230)
        at com.isomorphic.datasource.DataSourceDMI.execute(DataSourceDMI.java:64)
        at com.isomorphic.datasource.DSRequest.execute(DSRequest.java:2719)
        at com.isomorphic.servlet.IDACall.handleDSRequest(IDACall.java:230)
        at com.isomorphic.servlet.IDACall.processRPCTransaction(IDACall.java:187)
        at com.isomorphic.servlet.IDACall.processRequest(IDACall.java:152)
        at com.isomorphic.servlet.IDACall._processRequest(IDACall.java:119)
        at com.isomorphic.servlet.IDACall.doPost(IDACall.java:79)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
        at com.isomorphic.servlet.BaseServlet.service(BaseServlet.java:162)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
        at com.google.inject.servlet.ServletDefinition.doService(ServletDefinition.java:263)
        at com.google.inject.servlet.ServletDefinition.service(ServletDefinition.java:178)
        at com.google.inject.servlet.ManagedServletPipeline.service(ManagedServletPipeline.java:91)
        at com.google.inject.servlet.FilterChainInvocation.doFilter(FilterChainInvocation.java:62)
        at de.mks_infofabrik.kids.server.filter.GWTCacheControlFilter.doFilter(GWTCacheControlFilter.java:53)
        at com.google.inject.servlet.FilterDefinition.doFilter(FilterDefinition.java:163)
        at com.google.inject.servlet.FilterChainInvocation.doFilter(FilterChainInvocation.java:58)
        at com.isomorphic.servlet.CompressionFilter._doFilter(CompressionFilter.java:260)
        at com.isomorphic.servlet.BaseFilter.doFilter(BaseFilter.java:88)
        at com.google.inject.servlet.FilterDefinition.doFilter(FilterDefinition.java:163)
        at com.google.inject.servlet.FilterChainInvocation.doFilter(FilterChainInvocation.java:58)
        at com.google.inject.servlet.ManagedFilterPipeline.dispatch(ManagedFilterPipeline.java:118)
        at com.google.inject.servlet.GuiceFilter.doFilter(GuiceFilter.java:113)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:217)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
        at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518)
        at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091)
        at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:673)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1500)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1456)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:745)
    Caused by: javax.naming.NameNotFoundException: Name [BeanManager] is not bound in this Context. Unable to find [BeanManager].
        at org.apache.naming.NamingContext.lookup(NamingContext.java:818)
        at org.apache.naming.NamingContext.lookup(NamingContext.java:152)
        at org.apache.naming.NamingContext.lookup(NamingContext.java:829)
        at org.apache.naming.NamingContext.lookup(NamingContext.java:166)
        at org.apache.naming.SelectorContext.lookup(SelectorContext.java:157)
        at javax.naming.InitialContext.lookup(InitialContext.java:417)
        at com.isomorphic.cdi.CDIBeanManager.getBeanManager(CDIBeanManager.java:61)
        ... 44 more
    What am I doing wrong?

    Using smartgwt 6.0-p20161005 power.
    Attached Files

    #2
    The lookupStyle attributes work as they say they do - if you use lookupStyle:"new" we're going to do the equivalent of "new YourClass()" via standard Java reflection, so there would be no reason the Guice would somehow be in the call chain.

    As far as the trouble with CDI, the exception says your bean is not registered. As soon as you can retrieve your bean via direct coding again CDI APIs, you should see that SmartGWT can as well.

    Comment


      #3
      ok, I am new to CDI, so what I am actually trying to do is use Guice, which I know.
      As far as I know, Guice does not need Beans,... so how to use Guice in order to create DMI-Objects? I guess lookupstyle="cdi" is not correct here, but there is no "guice" option, so how to use it ?

      Comment


        #4
        We haven't added any built-in support for Guice. If it's key to use it, the best approach would probably be to use one of the existing DMI lookupStyle options to invoke some code in a normal bean, then use Guice from there.

        Comment


          #5
          Hi Isomorphic
          I am returning to this so I am now trying to configure guice with smartgwt.
          First question: have you added any guice support since then ?
          If not, I would try to apply your advice in #4, so I added a factory:

          serverCall.ds.xml
          Code:
          <DataSource ID="serverCall" serverType="generic">
          
              <operationBindings>
                  <operationBinding operationType="custom" operationId="serverCall">
                      <serverObject
                          className="com.smartgwt.sample.server.DmiFactory"
                          methodName="doCallServer"
                          lookupStyle="factory" />
                  </operationBinding>
          
              </operationBindings>
          
          </DataSource>
          DmiFactory
          Code:
          public class DmiFactory {
          
              public DmiFactory() {
              }
          
          
              public Object create(DSRequest dsRequest) throws Exception {
                  DataSource ds = dsRequest.getDataSource();
                  String dsName = ds.getName();
                  String dmiName = dsName.substring(0, 1).toLowerCase() + dsName.substring(1) + "DMI";
                  //dmiName is in this case serverCallDMI
          
          
                  ServletContext servletContext = dsRequest.getHttpServletRequest().getServletContext();
                  Injector injector = (Injector) servletContext.getAttribute(Injector.class.getName());
                  Object serverCallObject = (ServerCall) injector.getInstance(ServerCall.class);
                  return serverCallObject;
          
              }
          }
          Here I get the injector instance which contains all the injected instances. These are all correct, as I can see in the object "serverCallObject". Specifically, the TestService testService is correctly injected:

          ServerCall:
          Code:
          public class ServerCall {
          
              @Inject
              TestService testService;
          
              public DSResponse doCallServer(DSRequest dsRequest, HttpServletResponse servletResponse, RPCManager rpcManager)
                      throws Exception {
          
                  System.out.println("Test service: " + testService);
          
                  return new DSResponse();
              }
          }
          So my question is:

          looking at this code snippet:
          Code:
          Injector injector = (Injector) servletContext.getAttribute(Injector.class.getName());
          Object serverCallObject = (ServerCall) injector.getInstance(ServerCall.class);
          you see that I am creating the ServerCall instance directly (using ServerCall.class). How can I derive this from inside the create(DSRequest dsRequest) method ?
          I looked also at:
          String dmiName = dsName.substring(0, 1).toLowerCase() + dsName.substring(1) + "DMI";
          This yields "serverCallDMI". I could rename my "ServerCall" to "serverCallDMI", so the name would be correct. But of course I would need the complete path:
          Code:
          Class<?> myClass = Class.forName("path.to.serverCallDMI");
          injector.getInstance(myClass);
          but how can I set in my serverCall.ds.xml the path ? Normally, I would use the className property of the serverObject. But this is already using the className of the factory ...

          I am on the right way or am I doing something completely wrong?

          Thanks
          Using smartgwt 6.1p power

          Comment


            #6
            We haven't added direct support for Guice and we aren't especially familiar with it. It looks like you are trying to map DataSource calls to similarly named Guice beans. If so, then if some Java package is required as a prefix, you could add it as a custom attribute in your .ds.xml file, then retrieve it via BasicDataSource.getProperty().

            Comment


              #7
              Hi Isomorphic
              yes, this seems to be correct. I couldn't find how to add a custom attribute to the .ds.xml file. I checked https://www.smartclient.com/smartgwt...ataSource.html but I didn't find it, but maybe I missed something.
              And is this also possible per OperationBinding? Or only per Datasource?

              Comment


                #8
                Hi Isomorphic
                since you have direct support for CDI, I would like to try this. It may be an alternative to my guice approach. Do you have any simple example of a CDI bean integrated into smartgwt ? What is necessary for this? According to this: https://docs.oracle.com/javaee/6/tut...doc/gjfzi.html , a cdi bean is a simple concrete class with an @Inject constructor or no parameters. So how to integrate this simple class with smartgwt ? I guess using lookupStyle="cdi", but what to put in the name ? How to set the name of the cdi bean?
                And do you need any special jars or only the standard smartgwt jars for integrating cdi ?

                Comment


                  #9
                  As we mentioned, the approach for a custom property is BasicDataSource.getProperty(). You are looking instead at just DataSource.

                  No there is not currently a documented way to retrieve a custom property set on an operationBinding, but you could have custom DataSource properties that corresponded to your operationBindings, if you actually needed more than one property (which doesn't really appear necessary).

                  As far as CDI, you need only the documented .jars, and if you check the docs for the properties of serverObject, CDI usage is explained.

                  Comment


                    #10
                    Hi Isomorphic

                    for CDI, what would you recommend? As an EE environment is needed. I currently use tomcat, which has no EE environment.
                    Would you recommend changing to TomEE ? Or would you rather recommend using a CDI implementation on tomcat, e.g. Weld?

                    Comment


                      #11
                      Well, overall, we don't particularly recommend CDI, Guice or Spring unless you have a special, specific need that goes beyond ordinary data storage and querying, such that dependency injection is really worth the complexity these frameworks can introduce. So we would need to know quite a bit about your needs to recommend any particular framework here.

                      Comment


                        #12
                        Hi Isomorphic
                        I solved my issue with the factory method I posted, sending the complete ServerCall class name as datasource parameter.
                        Wouldn't it be easy to support guice out-of-the-box as you support spring? The only change would be to create the objects with the guice injector, which is available in the servletContext:
                        Code:
                        Injector injector = (Injector) servletContext.getAttribute(Injector.class.getName());
                        Object serverCallObject = (ServerCall) injector.getInstance(ServerCall.class);
                        Back to your question:
                        What I want to do with injection is have a collection of services and their default implementations. Then, if I need those services in some server-side code, I want to just @Inject them and have all their dependencies and their default implementations be set by guice.
                        --> Why would you not recommend to use dependency injection in this case ?

                        Comment


                          #13
                          We'll look at possibly supporting Guide directly. Doesn't seem like it saves a lot of code, but there is a little bit of savings.

                          As far as dependency injection in general, we did not recommend against it, see previous post.

                          Comment


                            #14
                            Hi Isomorphic

                            yes, it only saves the DmiFactory code. But with this code, all datasources wanting to use guice need the new datasource parameter. And: if a same datasource definition wants to use more than one class, it is not possible without modification. And the modification would be very cumbersome.

                            I think the easiest would be:
                            Code:
                            <operationBinding operationType="custom" operationId="serverCall">
                                        <serverObject
                                            className="com.smartgwt.sample.server.MyDoCallServerClass"
                                            methodName="doCallServer"
                                            lookupStyle="guice" />
                            and when this lookupStyle is given (guice), then create the new objects not with new MyDoServerClass, but with:
                            Code:
                            Injector injector = (Injector) servletContext.getAttribute(Injector.class.getName());
                            Class<?> myClass = Class.forName(className);
                            Object myInstance = injector.getInstance(myClass.class);
                            that's it. A similar approach is working for me, only having to go through a DmiFactory and passing the className as a datasource property.

                            To the dependency injection question:
                            "we don't particularly recommend CDI, Guice or Spring unless you have a special, specific need that goes beyond ordinary data storage and querying, such that dependency injection is really worth the complexity these frameworks can introduce"
                            I understand this as CDI, Guice or Spring introducing complexity, and you say these may be only worth this complexity for special, specific needs that go beyond ordinary data storage and querying.
                            I don't have these special needs, since I mentioned why I am trying to use Guice (only for automatically managing my server services)
                            Or am I understanding something wrong ?

                            Thanks!

                            Comment


                              #15
                              Hi Isomorphic
                              any updates on this?

                              Comment

                              Working...
                              X