1 2 3 4 5 Previous Next 72 Replies Latest reply on Nov 13, 2009 8:15 PM by gavin.king Go to original post
      • 60. Re: Outjection vs. Producer method
        asookazian

        Bob Lee wrote on Nov 12, 2009 20:22:



        Arbi Sookazian wrote on Nov 12, 2009 19:21:


        What apps have you used that allow user to come back tomorrow to complete processing a shopping cart, for example?


        Amazon. All apps should. Why would you throw away a user's data? That's hostile to your users. Is disk space so scarce?



        Amazon.  I've used amazon.com dozens of times and never noticed this.  how is this designed/implemented?  Are you talking about the wish list or cart?

        • 61. Re: Outjection vs. Producer method
          gavin.king

          We store conversation state in the session, so from a serialization standpoint, it's OK to have references in either direction.

          OK, that's fair. In Guice, you're targeting a particular implementation. CDI doesn't require that implementation, but I agree it will be a common approach.


          The problem is that we also have an extensible context model here. So when you start trying to account for things like cluster scopes, business process scopes, etc, these serialization issues pop up.


          Yes, you can work around these issues with hacks like Provider and static fields, etc, etc, but we think it's better to simply have the container solve those problems for you. So you don't even have to think about. So you have the same programming model no matter what scopes you are dealing with. So the user doesn't have to ask themself what scopes do these two objects have? when they try to figure out how to use them together.



          We run Guice in Gmail, Wave, AdWords, YouTube, etc. I think we know a little bit about scalability. :-)

          I have no doubt that Google knows something about scalability. Of a very specific kind of data. With a very specific kind of infrastructure. That is totally different to what exists in most IT shops.



          Also, you didn't answer my question: Is ServiceLocator.get(someClass()) statically checkable?

          Certainly, the compiler does some checking. The type returned by ServiceLocator can be matched against by the type of the class object returned by someClass(). Of course, someClass() could return an interface that no bean implements. So yes, Provider is a nice refinement of the pattern, that allows a little more type checking.


          But this is a tangemt. I'm not trying to argue the merits of the old pre-generics ServiceLocator vs. the new pattern that is used in JSRs 330 and 299. I'm just pointing out that you require the user to write specific, Guice-specific code, to code around the problems with scopes. CDI doesn't. The container handles it more or less transparently.


          You started this argument, not me.

          • 62. Re: Outjection vs. Producer method
            crazybob.seamframework.crazybob.org

            Gavin King wrote on Nov 12, 2009 20:42:

            Yes, you can work around these issues with hacks like Provider and static fields, etc, etc, but we think it's better to simply have the container solve those problems for you.


            I agree that it would be better if the framework could just do the right thing, That's not possible with Guice because you can have more than one injector. For example, we use child injectors to implement private bindings, assisted injection, etc. If I have multiple private bindings to ScopedFoo in different parts of my app, the framework doesn't know which one to use when you deserialize a ScopedFoo. CDI doesn't have this issue because it only supports one injector (per deployment) at the moment.


            In the Guice world, the user would have to somehow tell the framework which injector to use at deserialization time. It won't necessarily be just one injector--you could have different proxies from multiple injectors in the same object graph. This would also mean the user would likely have to keep static references to injectors, something we'd rather they not do. It gets ugly really quickly. It turns out to be a lot easier to just write:


              @Inject static Provider<ScopedFoo> fooProvider;



            So you don't even have to think about. So you have the same programming model no matter what scopes you are dealing with. So the user doesn't have to ask themself what scopes do these two objects have? when they try to figure out how to use them together.


            The only problem I have with that is even if the user writing the code may not care about the scopes, the person who reads the code almost certainly does.



            I have no doubt that Google knows something about scalability. Of a very specific kind of data. With a very specific kind of infrastructure. That is totally different to what exists in most IT shops.


            AdWords has a pretty conventional architecture. We use MySQL and serializable sessions, for example. (That's actually the reason I'm so against serializable sessions now!)

            • 63. Re: Outjection vs. Producer method
              asookazian

              Bob Lee wrote on Nov 12, 2009 22:07:


              AdWords has a pretty conventional architecture. We use MySQL and serializable sessions, for example. (That's actually the reason I'm so against serializable sessions now!)



              Hadoop is an open-sourced version of Google's Map/Reduce.  A lot of companies are using these frameworks for very large-scale computing (hundreds or thousands of nodes in a cluster) such as N.Y. Times to digitize books:



              As an example The New York Times used 100 Amazon EC2 instances and a Hadoop application to process 4TB of raw image TIFF data (stored in S3) into 11 million finished PDFs in the space of 24 hours at a computation cost of about $240 (not including bandwidth).

              so does the AdWords project use Map/Reduce or equivalent??  AdWords is supposed to be Google's biggest revenue generators and I've heard you guys have multiple SCRUM masters on that project...


              http://en.wikipedia.org/wiki/Hadoop


              What is the JBoss Hadoop equivalent?



              Why is Infinispan sexy?

              are you kidding me?

              • 64. Re: Outjection vs. Producer method
                asookazian

                well, since this thread has spun completely and recklessly out of control (but sticking to tech speak all the while!), can we start bashing (or congratulating?) Microsoft for finally shipping ASP.NET in an actual MCV framework version???


                http://www.asp.net/learn/mvc-videos/video-8145.aspx


                I love the amount and quality of the Microsoft programming videos!  Redhat/JBoss needs to comply!

                • 65. Re: Outjection vs. Producer method
                  asookazian

                  well apparently it's been out since 2007 in CTP:


                  http://en.wikipedia.org/wiki/ASP.NET_MVC_Framework


                  anyways, anybody using Weld with a non-MVC framework (whether it's Swing or what not)?  I wonder if MVC will one of these days (since the 80's with Smalltalk) become out of style?  Or ORM and OOP/AOP?  How could it all go away one day?

                  • 66. Re: Outjection vs. Producer method
                    gavin.king

                    I agree that it would be better if the framework could just do the right thing, That's not possible with Guice because you can have more than one injector. For example, we use child injectors to implement private bindings, assisted injection, etc.

                    I don't have a complete mental model of everything that can be done with child injectors in Guice, though I did look at it briefly at your docs when we were working on the modularity stuff in CDI. We decided against exposing these details to the user, at least in 1.0.


                    What CDI has instead of the explicit notion of child injectors is the idea that what can be injected depends upon the module you are in, and the class accessibility rules of the module architecture you happen to be using, together with module-private activation of @Alternatives.


                    I believe that the models are at some level not very different - though the CDI spec expresses this stuff at a more abstract level, in terms of an abstract module architecture. Certainly the actual BeanManager object is a module-level thing, so I think it maps approximately to the notion of a child injector.


                    Well, actually I'm not sure. Certainly I imagine that there are some different capabilities between the two models. Specifically, I would not be at all surprised to find out that there are some things you can do in Guice that you could not do in CDI without a quite sophisticated module architecture (JAM or whatever).


                    But the strong directive from Sun was that we shouldn't be building a module system in 299. That we should wait for Java7 to deliver something at the language level. To be honest, I only just managed to sneak @Alternative in.



                    If I have multiple private bindings to ScopedFoo in different parts of my app, the framework doesn't know which one to use when you deserialize a ScopedFoo. CDI doesn't have this issue because it only supports one injector (per deployment) at the moment.

                    Not really true. It's more like one BeanManager per module. But yes, the proxy knows how to find the Bean and BeanManager that created it.



                    In the Guice world, the user would have to somehow tell the framework which injector to use at deserialization time. It won't necessarily be just one injector--you could have different proxies from multiple injectors in the same object graph. This would also mean the user would likely have to keep static references to injectors, something we'd rather they not do. It gets ugly really quickly.

                    I'm not certain of all the details of our implementation, but certainly its true that the proxy has to go to some kind of static registry to find the right Bean and BeanManager. But of course that's hidden from the user.


                    What I don't understand is why you think its ugly to store references to injectors in a static, in a way that can be hidden from the user, but that it's ok to make the user put references to injected beans in statics.

                    • 67. Re: Outjection vs. Producer method
                      crazybob.seamframework.crazybob.org

                      Gavin King wrote on Nov 13, 2009 00:34:

                      I don't have a complete mental model of everything that can be done with child What CDI has instead of the explicit notion of child injectors is the idea that what can be injected depends upon the module you are in,


                      Child injectors are orthogonal to modules (in the JSR-294 sense of module). While it might make sense to have one injector per module by convention, child injectors are also used in very find-grained contexts. Users don't typically interact directly with child injectors--they're a low level feature exposed through the SPI. Other features are built on top of child injectors.


                      For example, private modules use child injectors under the covers. Private modules enable you to say, when injecting type A's deps, bind Apple to Fruit. When injecting type B's deps, bind Orange to Fruit. Of course, you could implement private modules in other ways, but the same problems we've been discussing remain (i.e. how do I know which private binding instance to use?).



                      What I don't understand is why you think its ugly to store references to injectors in a static, in a way that can be hidden from the user, but that it's ok to make the user put references to injected beans in statics.


                      I don't like the statics, but the real problem is tying the proxy back to an injector that could have created it. The user could tell us which injector to use, but as you can imagine, the injector isn't even exposed to the user many times (like with private modules). Manually injecting a provider into a static field sucks, but it's better than any API I can come up with for telling the framework which injector to use for a given proxy.


                      These problems are analogous to class loading. For normal classes, you can just use the thread context class loader during deserialization, but when you generate classes and you have numerous fine-grained class loaders (like you see w/ cglib, etc.), things get tricky.

                      • 68. Re: Outjection vs. Producer method
                        asookazian

                        Bob Lee wrote on Nov 13, 2009 01:41:


                        These problems are analogous to class loading. For normal classes, you can just use the thread context class loader during deserialization, but when you generate classes and you have numerous fine-grained class loaders (like you see w/ cglib, etc.), things get tricky.



                        hence OSGi-based servers like Spring dm server or Java 7 module support...

                        • 69. Re: Outjection vs. Producer method
                          asookazian

                          The goal of this Project is to design and implement a simple, low-level module system focused narrowly upon the goal of modularizing the JDK, and to apply that system to the JDK itself. We expect the resulting module system to be useful to developers for their own code, and it will be fully supported by Sun for that purpose, but it will not be an official part of the Java SE 7 Platform Specification and it might not be supported by other SE 7 implementations.

                          http://openjdk.java.net/projects/jigsaw/

                          • 70. Re: Outjection vs. Producer method
                            gavin.king

                            For example, private modules use child injectors under the covers. Private modules enable you to say, when injecting type A's deps, bind Apple to Fruit. When injecting type B's deps, bind Orange to Fruit. Of course, you could implement private modules in other ways, but the same problems we've been discussing remain (i.e. how do I know which private binding instance to use?).


                            Right, so now you describe it like this, I know this is just like our modularity stuff.


                            We have:


                            class A { 
                               @Inject Fruit fruit; //apple
                            }



                            class B { 
                               @Inject Fruit fruit; //orange
                            }



                            So, to do this in CDI, you've got two choices:


                            Option 1 Orange and Apple are in different modules


                            The easy case.


                            Just deploy class A in module A, which has Apple in the classpath, but not Orange, and class B in module B, which has Orange in the classpath, but not Apple.


                            Option 2 Orange and Apple are in the same module


                            In this case we need to explicitly choose between them.


                            Add the @Alternative annotation to Orange and Apple.


                            Deploy class A in module A, with the following descriptor:


                            <beans><alternatives><class>Apple</class></alternatives></beans>



                            And deploy class B in module B, with the following descriptor:


                            <beans><alternatives><class>Orange</class></alternatives></beans>




                            Child injectors are orthogonal to modules (in the JSR-294 sense of module). While it might make sense to have one injector per module by convention, child injectors are also used in very find-grained contexts. Users don't typically interact directly with child injectors--they're a low level feature exposed through the SPI. Other features are built on top of child injectors.

                            Right, so 299 doesn't have this at a finer granularity than module. We don't let you declare alternatives at the package or class level. Personally, I think that if you've got things that vary at the granularity of a class, you are much better off adding a qualifier than putting this shit in a descriptor.


                            i.e. what I'm saying is that if you've got classes A and B of the example above in the same module, you should annotate the injection points with a qualifier, to let other people reading this code realize that A.fruit is not the same thing as B.fruit.


                            My guess is that most of the people using child injectors in Guice are using them at the granularity of one per module, or are using them to try and emulate a modular architecture in an environment like Java SE which does not have modules.


                            Now, I could be wrong about this, and perhaps people will beg us to add more granular alternative activation. In which case we can revisit this issue in 1.1. But my guess is that there won't be very many people who will want this.



                            I don't like the statics, but the real problem is tying the proxy back to an injector that could have created it. The user could tell us which injector to use, but as you can imagine, the injector isn't even exposed to the user many times (like with private modules). Manually injecting a provider into a static field sucks, but it's better than any API I can come up with for telling the framework which injector to use for a given proxy.

                            Now this is where you lose me. This problem is fixable. Why does the application need to be involved in this? Why the hell can't Guice just solve this under the covers like Weld does. We just stick enough state in the proxy to be able to find our way back to the right BeanManager.

                            • 71. Re: Outjection vs. Producer method
                              crazybob.seamframework.crazybob.org

                              Gavin King wrote on Nov 13, 2009 04:29:

                              Right, so 299 doesn't have this at a finer granularity than module. We don't let you declare alternatives at the package or class level. Personally, I think that if you've got things that vary at the granularity of a class, you are much better off adding a qualifier than putting this shit in a descriptor.


                              Private modules in Guice solve what we refer to as the robot legs problem. For example:


                              class Leg {
                                @Inject Hip;
                              }
                              
                              class Hip {
                                @Inject Thigh
                              }
                              
                              class Thigh {
                                @Inject Knee
                              }
                              
                              class Knee {
                                @Inject Calf;
                              }
                              
                              class Calf {
                                @Inject Ankle;
                              }
                              
                              class Ankle {
                                @Inject Foot;
                              }
                              
                              interface Foot {}
                              
                              class LeftFoot implements Foot {}
                              
                              class RightFoot implements Foot {}



                              The idea is that you have an @Left Leg and an @Right Leg where everything is the same except the Foot. To solve this with qualifiers, you'd have to create left and right copies of all these classes.


                              Guice enables you to configure this very concisely. I won't get into the details, but you can basically say, for @Left Leg, use LeftFoot, for @Right Leg, use RightFoot, ignoring all the dependencies in between. The actual configuration can be inline and very lightweight. If those interstitial dependencies change, your configuration doesn't have to change.


                              If a real module system enables you to create a new module that doesn't introduce any new classes but adds some DI configuration that exposes just an @Left Leg from one module and an @Right Leg from another, you can pull off the same.



                              Now this is where you lose me. This problem is fixable. Why does the application need to be involved in this? Why the hell can't Guice just solve this under the covers like Weld does. We just stick enough state in the proxy to be able to find our way back to the right BeanManager.


                              I don't know how to associate an injector in one VM with an injector in another VM. I assume that in Weld, you have one BeanManager per module, and you can just use the module name to look up that module. Guice's modules don't have globally unique names (i.e., I can reuse the same module implementation in two different private contexts). I suppose I could capture a stack trace when I create the injector, and then use that full stack trace as a transportable key to the injector, but that would be inefficient (bloating the serialized state), and it would break if I run slightly different but otherwise compatible versions of my code in different VMs. I could ask the user to provide a unique string ID for each injector, but they don't always know an injector is being created. I guess I could ask them to name private modules when they install them, and then I'd construct some sort of name hierarchy, but that isn't much less brittle than the stack trace idea. I suppose I'd just like to avoid the equivalent of class loader hell.

                              • 72. Re: Outjection vs. Producer method
                                gavin.king

                                If a real module system enables you to create a new module that doesn't introduce any new classes but adds some DI configuration that exposes just an @Left Leg from one module and an @Right Leg from another, you can pull off the same.

                                Right. There's no really good built-in solution for this problem in CDI.


                                What you would need is a portable extension that allowed a module to import classes from another jar, thereby having its own beans for the classes in that jar. Nobody has written a portable extension like that yet. I guess it would look something like this.


                                In leftleg.jar:


                                class LeftFoot {}



                                class LeftLeg {
                                
                                   @Produces @Left Leg get(Leg leg) { return leg; }
                                
                                }



                                <more-beans>
                                   <imports>
                                      <class>Leg</class>
                                      <class>Hip</class>
                                      <class>Thigh</class>
                                      <class>Knee</class>
                                      <class>Calf</class>
                                      <class>Ankle</class>
                                   </imports>
                                </more-beans>



                                And then in the client module:


                                class Body {
                                    @Inject @Left Leg leg; //from |leftleg.jar|
                                    @Inject @Right Leg leg;  //from |rightleg.jar|
                                }



                                Perhaps, if people like this feature, we could add something like <imports> to beans.xml.


                                I agree that the need to split the code into modules is inconvenient in this case.

                                1 2 3 4 5 Previous Next