Re: WebObjects and dependency injection (DI)
On Sep 22, 2009, at 11:31 AM, Andrus Adamchik wrote: We normally use Class.forName().newInstance() in some way or other to handle that. So can DI help me there? If yes, how? Also there's a number of standard scenarios, where you can swap the actual service implementation behind the immutable injected interface proxy for a short period of time (e.g. within a request thread). A backend service may have request object injected in it, and when a service method is called within the request scope, the right request object is dynamically bound to the interface proxy. (Of course WORequest is not an interface, so it will require more indirection in WO). In the same way you can bind your own request-scoped implementations of your custom services somewhere in the beginning of the request. And this transparently sets the execution context for all you other services and components. Andrus ___ Do not post admin requests to the list. They will be ignored. Webobjects-dev mailing list (Webobjects-dev@lists.apple.com) Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/webobjects-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: WebObjects and dependency injection (DI)
On Sep 22, 2009, at 9:07 AM, Anjo Krank wrote: My argument being, I have a lot of code that depends on various "services" and their instantiation. But 90% of the time, this code depends on user input, program state and external stuff. It's very rare that I actually know at compile time what implementation I have. We normally use Class.forName().newInstance() in some way or other to handle that. So can DI help me there? If yes, how? DI is just an environment to help you with your interface-based design. Nothing prevents you from writing a dynamic strategy-based service. At the same time DI it can simplify the public API of your services in many cases by removing environment-specific arguments from your method signatures. E.g.: ERXSQLHelper sqlHelper = ERXSQLHelper.newSQLHelper(ec, model.name()); ERXSQLHelper sqlHelper = ERXSQLHelper.newSQLHelper(ec, dbc); ERXSQLHelper sqlHelper = ERXSQLHelper.newSQLHelper(ec, channel); may become ERXSQLHelper sqlHelper = sqlHelperService.newSQLHelper(model.name()); ERXSQLHelper sqlHelper = sqlHelperService.newSQLHelper(dbc); ERXSQLHelper sqlHelper = sqlHelperService.newSQLHelper(channel); So here you don't need to pass ec to the method as it is injected in sqlHelperService behind the scenes. This means that you don't need to carry over all needed parameters through the call chain, just to pass it down to some method. It creates some really nice refactoring opportunities, and again - it reduces coupling of the public API. I should say I didn't get DI in theory until I tried it. Just like many programming optimizations (say OO vs. procedural) this is about a better abstraction which is not really obvious until you start using it. Andrus ___ Do not post admin requests to the list. They will be ignored. Webobjects-dev mailing list (Webobjects-dev@lists.apple.com) Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/webobjects-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: WebObjects and dependency injection (DI)
On Sep 22, 2009, at 10:50 AM, Lachlan Deck wrote: Yeah, this is what I assumed Anjo was getting at - after some thought, of course (as Anjo's usually the king of succinctness :) It seems to me that factory instantiations (as above) and/or making use of delegates provides all the opportunities for environment/ context-based switching that DI promises. i.e., both delegate style and DI style require the declaration of injection points and interfaces to implement, factories providing all the opportunities for custom implementations etc... so Andrus would you like to elaborate on why you think DI would be particularly advantageous over these given that it would require hacks? I haven't said it would be advantageous under WO. This remains to be seen. WO is not built for DI, so slapping it on top is going against the flow. That much I can see already. Andrus ___ Do not post admin requests to the list. They will be ignored. Webobjects-dev mailing list (Webobjects-dev@lists.apple.com) Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/webobjects-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: WebObjects and dependency injection (DI)
On 22/09/2009, at 1:18 AM, Henrique Prange wrote: Andrus Adamchik wrote: I know it is not the traditional "WO way" of doing things, but from my experience using a dependency injection container in your app (Spring, Guice, etc.) is one single thing that you can do to dramatically improve the design quality, and produce flexible and maintainable code. We have been using Guice with WO for some time in our projects. Our code become easier to test without requiring too much boilerplate code using a DI container. Are you able to provide (if you've got time) some more concrete examples of what was easier? WO does a bit of that on its own (such as session and application injection in components), but doesn't bundle a container that a developer could use for the custom "services" (unlike say Tapestry, that does have a DI container at its core). Say I have a WO application and I'd like to use Spring or Guice to inject custom services in the WOComponents, instead of looking them up in WOApplication (or worse - defining them as static singletons somewhere). This sounds easy on the surface. I don't remember all the component creation internals now (it's been a while since I poked around the framework code), but I am pretty sure I can create them with my own factory that is DI container aware. On the other hand (also because I've been out of the loop on WO for quite some time), I am sure I am missing some pieces of the puzzle that would make such setup less practical or outright painful. Instead of changing component creation internals, we've created an extension of ERXComponent that obtain the injector and inject the required members. It is not a perfect solution (you can't use constructor injection this way), but it is easy to implement. Why would you want constructor injection for WOComponents? This and the fact that DI capabilities don't seem to bother the rest of the community, I figured I'd ask the list on your opinions, while I am trying to wire this thing up in the background. So anybody played with DI-on-WO in some form with any success? We have an audit framework completely based on Guice. We have created extensions of other important classes to make it possible, like ERXGenericRecord and ERXEC and we have created a @WOSessionScoped scope to create/obtain objects per WOSession. Just a question, Henrique: wouldn't it be better to use an ERXEC custom factory so that every ec created (even by included frameworks) are able to be scoped correctly in this sense? We are planning to create an open source framework with this stuff. We are just polishing what we've done to use some new features of Guice 2.0. Cheers, Henrique ___ Do not post admin requests to the list. They will be ignored. Webobjects-dev mailing list (Webobjects-dev@lists.apple.com) Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/webobjects-dev/lachlan.deck%40gmail.com This email sent to lachlan.d...@gmail.com with regards, -- Lachlan Deck ___ Do not post admin requests to the list. They will be ignored. Webobjects-dev mailing list (Webobjects-dev@lists.apple.com) Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/webobjects-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: WebObjects and dependency injection (DI)
On 22/09/2009, at 4:07 PM, Anjo Krank wrote: I'm not sure you understand... the String thing is only the bottleneck. I have caller code like: ERXSQLHelper sqlHelper = ERXSQLHelper.newSQLHelper(ec, model.name ()); ERXSQLHelper sqlHelper = ERXSQLHelper.newSQLHelper(ec, dbc); ERXSQLHelper sqlHelper = ERXSQLHelper.newSQLHelper(ec, channel); Surely you don't suggest I need to create a "module" in every top- level caller? My argument being, I have a lot of code that depends on various "services" and their instantiation. But 90% of the time, this code depends on user input, program state and external stuff. It's very rare that I actually know at compile time what implementation I have. We normally use Class.forName().newInstance() in some way or other to handle that. So can DI help me there? If yes, how? Yeah, this is what I assumed Anjo was getting at - after some thought, of course (as Anjo's usually the king of succinctness :) It seems to me that factory instantiations (as above) and/or making use of delegates provides all the opportunities for environment/ context-based switching that DI promises. i.e., both delegate style and DI style require the declaration of injection points and interfaces to implement, factories providing all the opportunities for custom implementations etc... so Andrus would you like to elaborate on why you think DI would be particularly advantageous over these given that it would require hacks? And Kieran: properties are there to make things *easier* I wouldn't want to avoid if's at the cost of putting every constructor in there... I dread the guy who has to deal with that after you... Cheers, Anjo Am 22.09.2009 um 00:11 schrieb Henrique Prange: Hi Anjo, You would not need a static method to create new ERXSQLHelper objects if you were using a DI container. For example, using Guice you could declare a helper property that must be injected. @Inject ERXSQLHelper helper; If you were too lazy you could let the user define which implementation to use. For example, using Guice this is achieved with a Module with the following binding: bind(ERXSQLHelper.class).to(OracleSQLHelper.class); If I had to implement this using Guice, I would create an ERXSQLHelper provider that would return the right ERXSQLHelper based on the chosen database. Of course, to avoid the same code (nested ifs) inside the provider, I would refactor the way the database type is defined too. IMHO, one advantage of this approach is I could create my own extension of ERXSQLHelper class and bind to all ERXSQLHelper declarations easily. I just need to create my own Module with the following code: bind(ERXSQLHelper.class).to(MyOwnSQLHelper.class); I could do the same thing with the current implementation, but I need to set a property that is not type safe and you had to write a lot of boilerplate code to support this. Guice fail fast mechanism also helps to find problems earlier. If something is wrong with the bindings, an exception is thrown as soon as you create the Injector. In your example, I would get a NoClassDefFound in runtime, during a very important presentation, of course. :p And last, but not least, you could bind a MockERXSQLHelper class when unit testing classes that depend upon ERXSQLHelper. Cheers, Henrique Anjo Krank wrote: U-huh. So how about a real world example and not these cooked up things. Take a look at the ERXSQLHelper. Depending on various types of input it creates a concrete subclass. Can DI change this to sth more "clean"? Cheers, Anjo public static ERXSQLHelper newSQLHelper(String databaseProductName) { synchronized (_sqlHelperMap) { ERXSQLHelper sqlHelper = _sqlHelperMap.get(databaseProductName); if (sqlHelper == null) { try { String sqlHelperClassName = ERXProperties.stringForKey (databaseProductName + ".SQLHelper"); if (sqlHelperClassName == null) { if (databaseProductName.equalsIgnoreCase("frontbase")) { sqlHelper = new FrontBaseSQLHelper(); } else if (databaseProductName.equalsIgnoreCase("mysql")) { sqlHelper = new MySQLSQLHelper(); } else if (databaseProductName.equalsIgnoreCase("oracle")) { sqlHelper = new OracleSQLHelper(); } else if (databaseProductName.equalsIgnoreCase ("postgresql")) { sqlHelper = new PostgresqlSQLHelper(); } else if (databaseProductName.equalsIgnoreCase ("openbase")) { sqlHelper = new OpenBaseSQLHelper(); } else if (databaseProductName.equalsIgnoreCase("derby")) { sqlHelper = new DerbySQLHelper(); } else if (databaseProductName.equalsIgnoreCase ("microsoft")) { sqlHelper = new MicrosoftSQLHelper(); } else { try { sqlHelper = (ERXSQLHel
Re: WebObjects and dependency injection (DI)
I'm not sure you understand... the String thing is only the bottleneck. I have caller code like: ERXSQLHelper sqlHelper = ERXSQLHelper.newSQLHelper(ec, model.name ()); ERXSQLHelper sqlHelper = ERXSQLHelper.newSQLHelper(ec, dbc); ERXSQLHelper sqlHelper = ERXSQLHelper.newSQLHelper(ec, channel); Surely you don't suggest I need to create a "module" in every top- level caller? My argument being, I have a lot of code that depends on various "services" and their instantiation. But 90% of the time, this code depends on user input, program state and external stuff. It's very rare that I actually know at compile time what implementation I have. We normally use Class.forName().newInstance() in some way or other to handle that. So can DI help me there? If yes, how? And Kieran: properties are there to make things *easier* I wouldn't want to avoid if's at the cost of putting every constructor in there... I dread the guy who has to deal with that after you... Cheers, Anjo Am 22.09.2009 um 00:11 schrieb Henrique Prange: Hi Anjo, You would not need a static method to create new ERXSQLHelper objects if you were using a DI container. For example, using Guice you could declare a helper property that must be injected. @Inject ERXSQLHelper helper; If you were too lazy you could let the user define which implementation to use. For example, using Guice this is achieved with a Module with the following binding: bind(ERXSQLHelper.class).to(OracleSQLHelper.class); If I had to implement this using Guice, I would create an ERXSQLHelper provider that would return the right ERXSQLHelper based on the chosen database. Of course, to avoid the same code (nested ifs) inside the provider, I would refactor the way the database type is defined too. IMHO, one advantage of this approach is I could create my own extension of ERXSQLHelper class and bind to all ERXSQLHelper declarations easily. I just need to create my own Module with the following code: bind(ERXSQLHelper.class).to(MyOwnSQLHelper.class); I could do the same thing with the current implementation, but I need to set a property that is not type safe and you had to write a lot of boilerplate code to support this. Guice fail fast mechanism also helps to find problems earlier. If something is wrong with the bindings, an exception is thrown as soon as you create the Injector. In your example, I would get a NoClassDefFound in runtime, during a very important presentation, of course. :p And last, but not least, you could bind a MockERXSQLHelper class when unit testing classes that depend upon ERXSQLHelper. Cheers, Henrique Anjo Krank wrote: U-huh. So how about a real world example and not these cooked up things. Take a look at the ERXSQLHelper. Depending on various types of input it creates a concrete subclass. Can DI change this to sth more "clean"? Cheers, Anjo public static ERXSQLHelper newSQLHelper(String databaseProductName) { synchronized (_sqlHelperMap) { ERXSQLHelper sqlHelper = _sqlHelperMap.get(databaseProductName); if (sqlHelper == null) { try { String sqlHelperClassName = ERXProperties.stringForKey (databaseProductName + ".SQLHelper"); if (sqlHelperClassName == null) { if (databaseProductName.equalsIgnoreCase("frontbase")) { sqlHelper = new FrontBaseSQLHelper(); } else if (databaseProductName.equalsIgnoreCase("mysql")) { sqlHelper = new MySQLSQLHelper(); } else if (databaseProductName.equalsIgnoreCase("oracle")) { sqlHelper = new OracleSQLHelper(); } else if (databaseProductName.equalsIgnoreCase ("postgresql")) { sqlHelper = new PostgresqlSQLHelper(); } else if (databaseProductName.equalsIgnoreCase ("openbase")) { sqlHelper = new OpenBaseSQLHelper(); } else if (databaseProductName.equalsIgnoreCase("derby")) { sqlHelper = new DerbySQLHelper(); } else if (databaseProductName.equalsIgnoreCase ("microsoft")) { sqlHelper = new MicrosoftSQLHelper(); } else { try { sqlHelper = (ERXSQLHelper) Class.forName (ERXSQLHelper.class.getName() + "$" + databaseProductName + "SQLHelper").newInstance(); } catch (ClassNotFoundException e) { sqlHelper = new ERXSQLHelper(); } } } else { sqlHelper = (ERXSQLHelper) Class.forName (sqlHelperClassName).newInstance(); } _sqlHelperMap.put(databaseProductName, sqlHelper); } catch (Exception e) { throw new NSForwardException(e, "Failed to create sql helper for the database with the product name '" + databaseProductName + "'."); } } return sqlH
Re: WebObjects and dependency injection (DI)
Hi Anjo, Anjo Krank wrote: Just so I know: does DI make anything simpler aside from unit testing? Is it worth the cost of un-readbility and un-debugablity? I mean, for foreign code i totally rely on eclipse call graphs... these are a nightmare with interfaces, not to mention missing constructors. You can produce detailed object graph description using Guice Grapher extension (of course, you must use Guice as a DI container). I've never tried it, but it seems to work. There is also a Guice plug-in for Eclipse that promises to help in this direction. Cheers, Henrique Cheers, Anjo Am 21.09.2009 um 21:17 schrieb Andrus Adamchik: Hi Henrique, Nice, thanks for sharing this info. Yeah, going through WOApplication and WOComponentDefinition, I realized I was too optimistic. Most interesting methods that would've enabled DI integration are all private. Quite a bit of code to rewrite to make it work. I was even thinking of limiting injection to just the Application class. Great that you are willing to open source your work in this area. Even if you load your code in its current state to a public SVN (ObjectStyle.org is always an option) or git somewhere, it will be a rather helpful example. Cheers, Andrus - Andrus Adamchik Apache Cayenne ORM: http://cayenne.apache.org/ Creator of Cayenne, VP Apache Software Foundation On Sep 21, 2009, at 6:18 PM, Henrique Prange wrote: Hi Andrus, Andrus Adamchik wrote: I know it is not the traditional "WO way" of doing things, but from my experience using a dependency injection container in your app (Spring, Guice, etc.) is one single thing that you can do to dramatically improve the design quality, and produce flexible and maintainable code. We have been using Guice with WO for some time in our projects. Our code become easier to test without requiring too much boilerplate code using a DI container. WO does a bit of that on its own (such as session and application injection in components), but doesn't bundle a container that a developer could use for the custom "services" (unlike say Tapestry, that does have a DI container at its core). Say I have a WO application and I'd like to use Spring or Guice to inject custom services in the WOComponents, instead of looking them up in WOApplication (or worse - defining them as static singletons somewhere). This sounds easy on the surface. I don't remember all the component creation internals now (it's been a while since I poked around the framework code), but I am pretty sure I can create them with my own factory that is DI container aware. On the other hand (also because I've been out of the loop on WO for quite some time), I am sure I am missing some pieces of the puzzle that would make such setup less practical or outright painful. Instead of changing component creation internals, we've created an extension of ERXComponent that obtain the injector and inject the required members. It is not a perfect solution (you can't use constructor injection this way), but it is easy to implement. This and the fact that DI capabilities don't seem to bother the rest of the community, I figured I'd ask the list on your opinions, while I am trying to wire this thing up in the background. So anybody played with DI-on-WO in some form with any success? We have an audit framework completely based on Guice. We have created extensions of other important classes to make it possible, like ERXGenericRecord and ERXEC and we have created a @WOSessionScoped scope to create/obtain objects per WOSession. We are planning to create an open source framework with this stuff. We are just polishing what we've done to use some new features of Guice 2.0. Cheers, Henrique ___ Do not post admin requests to the list. They will be ignored. Webobjects-dev mailing list (Webobjects-dev@lists.apple.com) Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/webobjects-dev/anjo%40krank.net This email sent to a...@krank.net ___ Do not post admin requests to the list. They will be ignored. Webobjects-dev mailing list (Webobjects-dev@lists.apple.com) Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/webobjects-dev/hprange%40gmail.com This email sent to hpra...@gmail.com ___ Do not post admin requests to the list. They will be ignored. Webobjects-dev mailing list (Webobjects-dev@lists.apple.com) Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/webobjects-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: WebObjects and dependency injection (DI)
Hi Anjo, You would not need a static method to create new ERXSQLHelper objects if you were using a DI container. For example, using Guice you could declare a helper property that must be injected. @Inject ERXSQLHelper helper; If you were too lazy you could let the user define which implementation to use. For example, using Guice this is achieved with a Module with the following binding: bind(ERXSQLHelper.class).to(OracleSQLHelper.class); If I had to implement this using Guice, I would create an ERXSQLHelper provider that would return the right ERXSQLHelper based on the chosen database. Of course, to avoid the same code (nested ifs) inside the provider, I would refactor the way the database type is defined too. IMHO, one advantage of this approach is I could create my own extension of ERXSQLHelper class and bind to all ERXSQLHelper declarations easily. I just need to create my own Module with the following code: bind(ERXSQLHelper.class).to(MyOwnSQLHelper.class); I could do the same thing with the current implementation, but I need to set a property that is not type safe and you had to write a lot of boilerplate code to support this. Guice fail fast mechanism also helps to find problems earlier. If something is wrong with the bindings, an exception is thrown as soon as you create the Injector. In your example, I would get a NoClassDefFound in runtime, during a very important presentation, of course. :p And last, but not least, you could bind a MockERXSQLHelper class when unit testing classes that depend upon ERXSQLHelper. Cheers, Henrique Anjo Krank wrote: U-huh. So how about a real world example and not these cooked up things. Take a look at the ERXSQLHelper. Depending on various types of input it creates a concrete subclass. Can DI change this to sth more "clean"? Cheers, Anjo public static ERXSQLHelper newSQLHelper(String databaseProductName) { synchronized (_sqlHelperMap) { ERXSQLHelper sqlHelper = _sqlHelperMap.get(databaseProductName); if (sqlHelper == null) { try { String sqlHelperClassName = ERXProperties.stringForKey(databaseProductName + ".SQLHelper"); if (sqlHelperClassName == null) { if (databaseProductName.equalsIgnoreCase("frontbase")) { sqlHelper = new FrontBaseSQLHelper(); } else if (databaseProductName.equalsIgnoreCase("mysql")) { sqlHelper = new MySQLSQLHelper(); } else if (databaseProductName.equalsIgnoreCase("oracle")) { sqlHelper = new OracleSQLHelper(); } else if (databaseProductName.equalsIgnoreCase("postgresql")) { sqlHelper = new PostgresqlSQLHelper(); } else if (databaseProductName.equalsIgnoreCase("openbase")) { sqlHelper = new OpenBaseSQLHelper(); } else if (databaseProductName.equalsIgnoreCase("derby")) { sqlHelper = new DerbySQLHelper(); } else if (databaseProductName.equalsIgnoreCase("microsoft")) { sqlHelper = new MicrosoftSQLHelper(); } else { try { sqlHelper = (ERXSQLHelper) Class.forName(ERXSQLHelper.class.getName() + "$" + databaseProductName + "SQLHelper").newInstance(); } catch (ClassNotFoundException e) { sqlHelper = new ERXSQLHelper(); } } } else { sqlHelper = (ERXSQLHelper) Class.forName(sqlHelperClassName).newInstance(); } _sqlHelperMap.put(databaseProductName, sqlHelper); } catch (Exception e) { throw new NSForwardException(e, "Failed to create sql helper for the database with the product name '" + databaseProductName + "'."); } } return sqlHelper; } } Am 21.09.2009 um 23:24 schrieb Andrew Lindesay: Hi Anjo; I guess this could be helpful in _some_ situations; I take for example, the Jetty server. Jetty can have a number of "handlers" added to it. Each handler does something like re-writes, feeds disk-based content, runs servlets etc.. etc.. The Jetty authors could not have envisaged all of the possible handlers that might have been written for Jetty, but because of the configuration style which follows the same line of thinking as Andrus is describing, it is possible to configure additional handlers. So that's a good example of where this seems quite helpful and Andrus' other examples also feel like good examples, but I agree that it seems like over-kill for many situations. cheers. Thanks for the write-up, but yeah, this can all be achieved w/o it. I really don't see why I shouldn't configure my app with if(Configration.isStaging())... and instead use DI. At least my way I easily find all the occurrences and have full logic support if(!Configuration.isStaging()). How is D
Re: WebObjects and dependency injection (DI)
To keep stuff like this below 'clean', I define a list of properties and lookup the property to get the class name er .extensions.sqlHelper.className.mysql=er.extensions.jdbc.MySQLSQLHelper er.extensions.sqlHelper.className.frontbase =er.extensions.jdbc.FrontBaseSQLHelper etc. .. and create it like this Class.forName( "er.extensions.sqlHelper.className." + databaseProductName ).newInstance() YMMV, Kieran On Sep 21, 2009, at 5:30 PM, Anjo Krank wrote: U-huh. So how about a real world example and not these cooked up things. Take a look at the ERXSQLHelper. Depending on various types of input it creates a concrete subclass. Can DI change this to sth more "clean"? Cheers, Anjo public static ERXSQLHelper newSQLHelper(String databaseProductName) { synchronized (_sqlHelperMap) { ERXSQLHelper sqlHelper = _sqlHelperMap.get(databaseProductName); if (sqlHelper == null) { try { String sqlHelperClassName = ERXProperties.stringForKey(databaseProductName + ".SQLHelper"); if (sqlHelperClassName == null) { if (databaseProductName.equalsIgnoreCase("frontbase")) { sqlHelper = new FrontBaseSQLHelper(); } else if (databaseProductName.equalsIgnoreCase("mysql")) { sqlHelper = new MySQLSQLHelper(); } else if (databaseProductName.equalsIgnoreCase("oracle")) { sqlHelper = new OracleSQLHelper(); } else if (databaseProductName.equalsIgnoreCase("postgresql")) { sqlHelper = new PostgresqlSQLHelper(); } else if (databaseProductName.equalsIgnoreCase("openbase")) { sqlHelper = new OpenBaseSQLHelper(); } else if (databaseProductName.equalsIgnoreCase("derby")) { sqlHelper = new DerbySQLHelper(); } else if (databaseProductName.equalsIgnoreCase("microsoft")) { sqlHelper = new MicrosoftSQLHelper(); } else { try { sqlHelper = (ERXSQLHelper) Class.forName(ERXSQLHelper.class.getName() + "$" + databaseProductName + "SQLHelper").newInstance(); } catch (ClassNotFoundException e) { sqlHelper = new ERXSQLHelper(); } } } else { sqlHelper = (ERXSQLHelper) Class.forName(sqlHelperClassName).newInstance(); } _sqlHelperMap.put(databaseProductName, sqlHelper); } catch (Exception e) { throw new NSForwardException(e, "Failed to create sql helper for the database with the product name '" + databaseProductName + "'."); } } return sqlHelper; } } Am 21.09.2009 um 23:24 schrieb Andrew Lindesay: Hi Anjo; I guess this could be helpful in _some_ situations; I take for example, the Jetty server. Jetty can have a number of "handlers" added to it. Each handler does something like re-writes, feeds disk-based content, runs servlets etc.. etc.. The Jetty authors could not have envisaged all of the possible handlers that might have been written for Jetty, but because of the configuration style which follows the same line of thinking as Andrus is describing, it is possible to configure additional handlers. So that's a good example of where this seems quite helpful and Andrus' other examples also feel like good examples, but I agree that it seems like over-kill for many situations. cheers. Thanks for the write-up, but yeah, this can all be achieved w/o it. I really don't see why I shouldn't configure my app with if(Configration.isStaging())... and instead use DI. At least my way I easily find all the occurrences and have full logic support if(!Configuration.isStaging()). How is DI "cleaner" in any way when: - I have any number of DI containers and their various syntax to chose from - I can't *find* the dependencies when I really want or need them. Have you ever tried to debug such an app that wasn't written by yourself? Take a look at the Red5 Media server for some fun... ___ Andrew Lindesay www.lindesay.co.nz ___ Do not post admin requests to the list. They will be ignored. Webobjects-dev mailing list (Webobjects-dev@lists.apple.com) Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/webobjects-dev/kieran_lists%40mac.com This email sent to kieran_li...@mac.com ___ Do not post admin requests to the list. They will be ignored. Webobjects-dev mailing list (Webobjects-dev@lists.apple.com) Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/webobjects-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: WebObjects and dependency injection (DI)
U-huh. So how about a real world example and not these cooked up things. Take a look at the ERXSQLHelper. Depending on various types of input it creates a concrete subclass. Can DI change this to sth more "clean"? Cheers, Anjo public static ERXSQLHelper newSQLHelper(String databaseProductName) { synchronized (_sqlHelperMap) { ERXSQLHelper sqlHelper = _sqlHelperMap.get(databaseProductName); if (sqlHelper == null) { try { String sqlHelperClassName = ERXProperties.stringForKey (databaseProductName + ".SQLHelper"); if (sqlHelperClassName == null) { if (databaseProductName.equalsIgnoreCase("frontbase")) { sqlHelper = new FrontBaseSQLHelper(); } else if (databaseProductName.equalsIgnoreCase("mysql")) { sqlHelper = new MySQLSQLHelper(); } else if (databaseProductName.equalsIgnoreCase("oracle")) { sqlHelper = new OracleSQLHelper(); } else if (databaseProductName.equalsIgnoreCase ("postgresql")) { sqlHelper = new PostgresqlSQLHelper(); } else if (databaseProductName.equalsIgnoreCase ("openbase")) { sqlHelper = new OpenBaseSQLHelper(); } else if (databaseProductName.equalsIgnoreCase("derby")) { sqlHelper = new DerbySQLHelper(); } else if (databaseProductName.equalsIgnoreCase ("microsoft")) { sqlHelper = new MicrosoftSQLHelper(); } else { try { sqlHelper = (ERXSQLHelper) Class.forName (ERXSQLHelper.class.getName() + "$" + databaseProductName + "SQLHelper").newInstance(); } catch (ClassNotFoundException e) { sqlHelper = new ERXSQLHelper(); } } } else { sqlHelper = (ERXSQLHelper) Class.forName (sqlHelperClassName).newInstance(); } _sqlHelperMap.put(databaseProductName, sqlHelper); } catch (Exception e) { throw new NSForwardException(e, "Failed to create sql helper for the database with the product name '" + databaseProductName + "'."); } } return sqlHelper; } } Am 21.09.2009 um 23:24 schrieb Andrew Lindesay: Hi Anjo; I guess this could be helpful in _some_ situations; I take for example, the Jetty server. Jetty can have a number of "handlers" added to it. Each handler does something like re-writes, feeds disk- based content, runs servlets etc.. etc.. The Jetty authors could not have envisaged all of the possible handlers that might have been written for Jetty, but because of the configuration style which follows the same line of thinking as Andrus is describing, it is possible to configure additional handlers. So that's a good example of where this seems quite helpful and Andrus' other examples also feel like good examples, but I agree that it seems like over-kill for many situations. cheers. Thanks for the write-up, but yeah, this can all be achieved w/o it. I really don't see why I shouldn't configure my app with if (Configration.isStaging())... and instead use DI. At least my way I easily find all the occurrences and have full logic support if(! Configuration.isStaging()). How is DI "cleaner" in any way when: - I have any number of DI containers and their various syntax to chose from - I can't *find* the dependencies when I really want or need them. Have you ever tried to debug such an app that wasn't written by yourself? Take a look at the Red5 Media server for some fun... ___ Andrew Lindesay www.lindesay.co.nz ___ Do not post admin requests to the list. They will be ignored. Webobjects-dev mailing list (Webobjects-dev@lists.apple.com) Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/webobjects-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: WebObjects and dependency injection (DI)
Hi Anjo; I guess this could be helpful in _some_ situations; I take for example, the Jetty server. Jetty can have a number of "handlers" added to it. Each handler does something like re-writes, feeds disk- based content, runs servlets etc.. etc.. The Jetty authors could not have envisaged all of the possible handlers that might have been written for Jetty, but because of the configuration style which follows the same line of thinking as Andrus is describing, it is possible to configure additional handlers. So that's a good example of where this seems quite helpful and Andrus' other examples also feel like good examples, but I agree that it seems like over-kill for many situations. cheers. Thanks for the write-up, but yeah, this can all be achieved w/o it. I really don't see why I shouldn't configure my app with if(Configration.isStaging())... and instead use DI. At least my way I easily find all the occurrences and have full logic support if(! Configuration.isStaging()). How is DI "cleaner" in any way when: - I have any number of DI containers and their various syntax to chose from - I can't *find* the dependencies when I really want or need them. Have you ever tried to debug such an app that wasn't written by yourself? Take a look at the Red5 Media server for some fun... ___ Andrew Lindesay www.lindesay.co.nz ___ Do not post admin requests to the list. They will be ignored. Webobjects-dev mailing list (Webobjects-dev@lists.apple.com) Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/webobjects-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: WebObjects and dependency injection (DI)
Am 21.09.2009 um 22:46 schrieb Andrus Adamchik: To be sure all of that can be achieved without DI. DI just makes it declarative and cleaner, and actually encourages you to follow this specific development pattern. Thanks for the write-up, but yeah, this can all be achieved w/o it. I really don't see why I shouldn't configure my app with if (Configration.isStaging())... and instead use DI. At least my way I easily find all the occurrences and have full logic support if(! Configuration.isStaging()). How is DI "cleaner" in any way when: - I have any number of DI containers and their various syntax to chose from - I can't *find* the dependencies when I really want or need them. Have you ever tried to debug such an app that wasn't written by yourself? Take a look at the Red5 Media server for some fun... Cheers, Anjo ___ Do not post admin requests to the list. They will be ignored. Webobjects-dev mailing list (Webobjects-dev@lists.apple.com) Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/webobjects-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: WebObjects and dependency injection (DI)
Personally I don't even care that much about unit testing web applications. In data-driven apps, even with DI, it is hard to create good mock data for most of your services, as it may depend on a pretty deep object graph. To me DI is all about clean design and decoupling of functionality from configuration. Implementing core application services as interfaces is one part of it (not really dependent on DI), but DI serves as a glue for those services. At the end it gives you flexibility to tweak things by swapping implementations of services without touching the components or writing endless if/else manual configuration code. One real-life example is a CMS system that would generate vhost based URLs when in production (http://vhost.example.org) and path-based URLs in development environment with no DNS capability (http://localhost/vhost ). Another one from the CMS realm is a cache service that is implemented differently depending on whether the same application is in live mode vs. preview mode, allowing for instantaneous page refreshing in preview mode and best performance on a live site. Then there's all the interceptors that you can build around interface method calls. I don't use it too often personally, but on a rare occasion when you need it, this is priceless. To be sure all of that can be achieved without DI. DI just makes it declarative and cleaner, and actually encourages you to follow this specific development pattern. Andrus On Sep 21, 2009, at 11:22 PM, Anjo Krank wrote: Just so I know: does DI make anything simpler aside from unit testing? Is it worth the cost of un-readbility and un-debugablity? I mean, for foreign code i totally rely on eclipse call graphs... these are a nightmare with interfaces, not to mention missing constructors. Cheers, Anjo Am 21.09.2009 um 21:17 schrieb Andrus Adamchik: Hi Henrique, Nice, thanks for sharing this info. Yeah, going through WOApplication and WOComponentDefinition, I realized I was too optimistic. Most interesting methods that would've enabled DI integration are all private. Quite a bit of code to rewrite to make it work. I was even thinking of limiting injection to just the Application class. Great that you are willing to open source your work in this area. Even if you load your code in its current state to a public SVN (ObjectStyle.org is always an option) or git somewhere, it will be a rather helpful example. Cheers, Andrus - Andrus Adamchik Apache Cayenne ORM: http://cayenne.apache.org/ Creator of Cayenne, VP Apache Software Foundation On Sep 21, 2009, at 6:18 PM, Henrique Prange wrote: Hi Andrus, Andrus Adamchik wrote: I know it is not the traditional "WO way" of doing things, but from my experience using a dependency injection container in your app (Spring, Guice, etc.) is one single thing that you can do to dramatically improve the design quality, and produce flexible and maintainable code. We have been using Guice with WO for some time in our projects. Our code become easier to test without requiring too much boilerplate code using a DI container. WO does a bit of that on its own (such as session and application injection in components), but doesn't bundle a container that a developer could use for the custom "services" (unlike say Tapestry, that does have a DI container at its core). Say I have a WO application and I'd like to use Spring or Guice to inject custom services in the WOComponents, instead of looking them up in WOApplication (or worse - defining them as static singletons somewhere). This sounds easy on the surface. I don't remember all the component creation internals now (it's been a while since I poked around the framework code), but I am pretty sure I can create them with my own factory that is DI container aware. On the other hand (also because I've been out of the loop on WO for quite some time), I am sure I am missing some pieces of the puzzle that would make such setup less practical or outright painful. Instead of changing component creation internals, we've created an extension of ERXComponent that obtain the injector and inject the required members. It is not a perfect solution (you can't use constructor injection this way), but it is easy to implement. This and the fact that DI capabilities don't seem to bother the rest of the community, I figured I'd ask the list on your opinions, while I am trying to wire this thing up in the background. So anybody played with DI-on-WO in some form with any success? We have an audit framework completely based on Guice. We have created extensions of other important classes to make it possible, like ERXGenericRecord and ERXEC and we have created a @WOSessionScoped scope to create/obtain objects per WOSession. We are planning to create an open source framework with this stuff. We are just po
Re: WebObjects and dependency injection (DI)
Just so I know: does DI make anything simpler aside from unit testing? Is it worth the cost of un-readbility and un-debugablity? I mean, for foreign code i totally rely on eclipse call graphs... these are a nightmare with interfaces, not to mention missing constructors. Cheers, Anjo Am 21.09.2009 um 21:17 schrieb Andrus Adamchik: Hi Henrique, Nice, thanks for sharing this info. Yeah, going through WOApplication and WOComponentDefinition, I realized I was too optimistic. Most interesting methods that would've enabled DI integration are all private. Quite a bit of code to rewrite to make it work. I was even thinking of limiting injection to just the Application class. Great that you are willing to open source your work in this area. Even if you load your code in its current state to a public SVN (ObjectStyle.org is always an option) or git somewhere, it will be a rather helpful example. Cheers, Andrus - Andrus Adamchik Apache Cayenne ORM: http://cayenne.apache.org/ Creator of Cayenne, VP Apache Software Foundation On Sep 21, 2009, at 6:18 PM, Henrique Prange wrote: Hi Andrus, Andrus Adamchik wrote: I know it is not the traditional "WO way" of doing things, but from my experience using a dependency injection container in your app (Spring, Guice, etc.) is one single thing that you can do to dramatically improve the design quality, and produce flexible and maintainable code. We have been using Guice with WO for some time in our projects. Our code become easier to test without requiring too much boilerplate code using a DI container. WO does a bit of that on its own (such as session and application injection in components), but doesn't bundle a container that a developer could use for the custom "services" (unlike say Tapestry, that does have a DI container at its core). Say I have a WO application and I'd like to use Spring or Guice to inject custom services in the WOComponents, instead of looking them up in WOApplication (or worse - defining them as static singletons somewhere). This sounds easy on the surface. I don't remember all the component creation internals now (it's been a while since I poked around the framework code), but I am pretty sure I can create them with my own factory that is DI container aware. On the other hand (also because I've been out of the loop on WO for quite some time), I am sure I am missing some pieces of the puzzle that would make such setup less practical or outright painful. Instead of changing component creation internals, we've created an extension of ERXComponent that obtain the injector and inject the required members. It is not a perfect solution (you can't use constructor injection this way), but it is easy to implement. This and the fact that DI capabilities don't seem to bother the rest of the community, I figured I'd ask the list on your opinions, while I am trying to wire this thing up in the background. So anybody played with DI-on-WO in some form with any success? We have an audit framework completely based on Guice. We have created extensions of other important classes to make it possible, like ERXGenericRecord and ERXEC and we have created a @WOSessionScoped scope to create/obtain objects per WOSession. We are planning to create an open source framework with this stuff. We are just polishing what we've done to use some new features of Guice 2.0. Cheers, Henrique ___ Do not post admin requests to the list. They will be ignored. Webobjects-dev mailing list (Webobjects-dev@lists.apple.com) Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/webobjects-dev/anjo%40krank.net This email sent to a...@krank.net ___ Do not post admin requests to the list. They will be ignored. Webobjects-dev mailing list (Webobjects-dev@lists.apple.com) Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/webobjects-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: WebObjects and dependency injection (DI)
Hi Henrique, Nice, thanks for sharing this info. Yeah, going through WOApplication and WOComponentDefinition, I realized I was too optimistic. Most interesting methods that would've enabled DI integration are all private. Quite a bit of code to rewrite to make it work. I was even thinking of limiting injection to just the Application class. Great that you are willing to open source your work in this area. Even if you load your code in its current state to a public SVN (ObjectStyle.org is always an option) or git somewhere, it will be a rather helpful example. Cheers, Andrus - Andrus Adamchik Apache Cayenne ORM: http://cayenne.apache.org/ Creator of Cayenne, VP Apache Software Foundation On Sep 21, 2009, at 6:18 PM, Henrique Prange wrote: Hi Andrus, Andrus Adamchik wrote: I know it is not the traditional "WO way" of doing things, but from my experience using a dependency injection container in your app (Spring, Guice, etc.) is one single thing that you can do to dramatically improve the design quality, and produce flexible and maintainable code. We have been using Guice with WO for some time in our projects. Our code become easier to test without requiring too much boilerplate code using a DI container. WO does a bit of that on its own (such as session and application injection in components), but doesn't bundle a container that a developer could use for the custom "services" (unlike say Tapestry, that does have a DI container at its core). Say I have a WO application and I'd like to use Spring or Guice to inject custom services in the WOComponents, instead of looking them up in WOApplication (or worse - defining them as static singletons somewhere). This sounds easy on the surface. I don't remember all the component creation internals now (it's been a while since I poked around the framework code), but I am pretty sure I can create them with my own factory that is DI container aware. On the other hand (also because I've been out of the loop on WO for quite some time), I am sure I am missing some pieces of the puzzle that would make such setup less practical or outright painful. Instead of changing component creation internals, we've created an extension of ERXComponent that obtain the injector and inject the required members. It is not a perfect solution (you can't use constructor injection this way), but it is easy to implement. This and the fact that DI capabilities don't seem to bother the rest of the community, I figured I'd ask the list on your opinions, while I am trying to wire this thing up in the background. So anybody played with DI-on-WO in some form with any success? We have an audit framework completely based on Guice. We have created extensions of other important classes to make it possible, like ERXGenericRecord and ERXEC and we have created a @WOSessionScoped scope to create/obtain objects per WOSession. We are planning to create an open source framework with this stuff. We are just polishing what we've done to use some new features of Guice 2.0. Cheers, Henrique ___ Do not post admin requests to the list. They will be ignored. Webobjects-dev mailing list (Webobjects-dev@lists.apple.com) Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/webobjects-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: WebObjects and dependency injection (DI)
Hi Andrus, Andrus Adamchik wrote: I know it is not the traditional "WO way" of doing things, but from my experience using a dependency injection container in your app (Spring, Guice, etc.) is one single thing that you can do to dramatically improve the design quality, and produce flexible and maintainable code. We have been using Guice with WO for some time in our projects. Our code become easier to test without requiring too much boilerplate code using a DI container. WO does a bit of that on its own (such as session and application injection in components), but doesn't bundle a container that a developer could use for the custom "services" (unlike say Tapestry, that does have a DI container at its core). Say I have a WO application and I'd like to use Spring or Guice to inject custom services in the WOComponents, instead of looking them up in WOApplication (or worse - defining them as static singletons somewhere). This sounds easy on the surface. I don't remember all the component creation internals now (it's been a while since I poked around the framework code), but I am pretty sure I can create them with my own factory that is DI container aware. On the other hand (also because I've been out of the loop on WO for quite some time), I am sure I am missing some pieces of the puzzle that would make such setup less practical or outright painful. Instead of changing component creation internals, we've created an extension of ERXComponent that obtain the injector and inject the required members. It is not a perfect solution (you can't use constructor injection this way), but it is easy to implement. This and the fact that DI capabilities don't seem to bother the rest of the community, I figured I'd ask the list on your opinions, while I am trying to wire this thing up in the background. So anybody played with DI-on-WO in some form with any success? We have an audit framework completely based on Guice. We have created extensions of other important classes to make it possible, like ERXGenericRecord and ERXEC and we have created a @WOSessionScoped scope to create/obtain objects per WOSession. We are planning to create an open source framework with this stuff. We are just polishing what we've done to use some new features of Guice 2.0. Cheers, Henrique ___ Do not post admin requests to the list. They will be ignored. Webobjects-dev mailing list (Webobjects-dev@lists.apple.com) Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/webobjects-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com