When I first laid hands on a computer and wrote my first Basic program (on an Apple II), I had this thrilling moment where I thought, "I can do anything with this." The software industry was young (so was I). Opportunity was everywhere. All I needed was a good idea and a computer and I could make it happen. I feel the same way when using Adobe's Flex Framework and Google's App Engine together. I can write and deploy a rich, responsive, engaging internet application that scales (to Google-scale) with just my laptop. Oh yeah, and it's easy (certainly way easier that JSP/J2EE) That is awesome. That is powerful. I can do anything with that.
I feel young again.
Tuesday, January 5, 2010
Friday, April 24, 2009
Self Injection for Fun and Profit
The Spring Framework (www.springsource.org) is an amazing piece of software. It has really changed the way that I code. It's dependancy injection features make decoupling and junit testing much easier than when using factories or service locators. The best thing about Spring I've found is declarative transaction management. Once configured, it's as easy as adding the @Transactional annotation to the method that you want be be transactional. When the method is called, it is intercepted by a proxy that wraps the method call in a transaction. On entry, a transaction is started. If your method completes normally, the transaction is commited. If your method throws a runtime exception, then the transaction is rolled back. Way easy.
This ease of use can be like a drug however. You still need to make sure that your transactions are short lived, to avoid contention on the database and resulting dropped locks. The other thing that you need to remember is that you can only apply @Transactional to public methods exposed using an Interface type. This is because Spring creates a dynamic proxy based on the Interface type. You aren't directly calling your implementation, your calling a proxy that calls your implementation. Errors associated with this can be hard to find and confusing.
@Transactional has been so easy to use that I had not dived into AOP itself. However, once I started running into problems, I found that it is really good to understand how Spring uses dynamic proxies and AOP to implement the @Transactional behavior. The Spring documentation is really amazingly good. Better than any software package I have ever used, open source or commercial. See chapter 6 of the Spring Reference for a discusion of AOP. Goto pg 158 for a discussion of how calls to the proxy and calls within the proxied bean are handled. This discussion is useful to understand the problems that I discuss below.
The most important thing you have to know is that your bean must implement an Interface type for any of this magic to work. Secondly, you must use Spring retrieve your bean, either through dependancy injection or using ApplicationContext.getBean(). Together, these two steps give Spring an opportunity to provide you with a dynamic proxy based on the Interface type. When you make calls to a bean created this way, you are really calling the proxy, which then calls your bean. The proxy does all the magic.
A common error is to forget to create an Iterface type and make your bean implement the interface. If your bean is not an implementation of an interface, Spring cannot create a proxy. Instead, it will simply new() a version of the class directly and will not create a proxy. In this case, any @Transactional annotation in your bean is non-funcation. Worse, you will not get an error or warning. Your method will simply not be transactional.
A similar issue happens if you mark a method as @Transactional, but that method is not part of the Interface type. Because it is not part of the declared interface, Spring does not proxy it. This case can be even more confusing because some @Transactional methods, those that are part of the Interface type, will work correctly. Those that are not part of the Interface type will not work and you will not get an error or warning.
This next thing may seem obvious, but legacy code may be involved so you may not even know this is happening. You must inject your bean using Spring or make a call to ApplicationContext.getBean() to retrieve the bean so it can be proxied by Spring. If you new() your bean rather than inject it using Spring, Spring will never be able to get in the way and create a proxy, so any @Transactional annotation in the bean is useless. Again, you will not be warned in any way. Your method will simply not be transactional.
This last error is a bit of a mind-blower. Calls to your bean from other classes will be proxied correctly. However, if you call your bean from within one of it's own methods, it will _not_ be proxied. This is because external calls are really calling through the proxy. However, internal calls are calling through the 'this' reference and so are 'inside' the proxy. So, if you call an @Transactional method from another method in the same bean, the call will not be tranacational because it does not go through the proxy. The same thing is true of calls down into the super() class because these are also made through the 'this' reference.
One way to fix this issue is to refactor and break out the @Transactional methods into their own bean which can be proxied. That can be a bunch of work and may mess up your well designed bean. The way I solved my problem is slightly icky, but it works well. Since my bean is a singleton, I can inject a proxied copy of the bean into itself using the spring configuration. I simply add a field that is based on the bean's own Interface type and inject it. I then make internal bean calls to transactional methods through the injected reference and all is well.
The example below uses self-injection so it can call proxied versions of it's own methods through the thisProxy field. Here is the bean definition:
<bean id="foo" class="Foo" >
<property name="foo" ref="foo" />
</bean>
Here is how a intra-class proxied call would look:
public class FooImpl implements Foo
{
private Foo thisProxy; // this get's injected by Spring
public setFoo(Foo proxiedFoo)
{
thisProxy = proxiedFoo;
}
public Foo()
{
}
public void someFoo()
{
thisProxy.someTransactionalFoo();
}
@Transactional
public void someTransactionalFoo()
{
// fooing within a transaction....
}
}
Don't try this if you use scope=prototype however. In that case, your injected thisProxy will be pointing to a different copy of Foo!
This ease of use can be like a drug however. You still need to make sure that your transactions are short lived, to avoid contention on the database and resulting dropped locks. The other thing that you need to remember is that you can only apply @Transactional to public methods exposed using an Interface type. This is because Spring creates a dynamic proxy based on the Interface type. You aren't directly calling your implementation, your calling a proxy that calls your implementation. Errors associated with this can be hard to find and confusing.
@Transactional has been so easy to use that I had not dived into AOP itself. However, once I started running into problems, I found that it is really good to understand how Spring uses dynamic proxies and AOP to implement the @Transactional behavior. The Spring documentation is really amazingly good. Better than any software package I have ever used, open source or commercial. See chapter 6 of the Spring Reference for a discusion of AOP. Goto pg 158 for a discussion of how calls to the proxy and calls within the proxied bean are handled. This discussion is useful to understand the problems that I discuss below.
The most important thing you have to know is that your bean must implement an Interface type for any of this magic to work. Secondly, you must use Spring retrieve your bean, either through dependancy injection or using ApplicationContext.getBean(). Together, these two steps give Spring an opportunity to provide you with a dynamic proxy based on the Interface type. When you make calls to a bean created this way, you are really calling the proxy, which then calls your bean. The proxy does all the magic.
A common error is to forget to create an Iterface type and make your bean implement the interface. If your bean is not an implementation of an interface, Spring cannot create a proxy. Instead, it will simply new() a version of the class directly and will not create a proxy. In this case, any @Transactional annotation in your bean is non-funcation. Worse, you will not get an error or warning. Your method will simply not be transactional.
A similar issue happens if you mark a method as @Transactional, but that method is not part of the Interface type. Because it is not part of the declared interface, Spring does not proxy it. This case can be even more confusing because some @Transactional methods, those that are part of the Interface type, will work correctly. Those that are not part of the Interface type will not work and you will not get an error or warning.
This next thing may seem obvious, but legacy code may be involved so you may not even know this is happening. You must inject your bean using Spring or make a call to ApplicationContext.getBean() to retrieve the bean so it can be proxied by Spring. If you new() your bean rather than inject it using Spring, Spring will never be able to get in the way and create a proxy, so any @Transactional annotation in the bean is useless. Again, you will not be warned in any way. Your method will simply not be transactional.
This last error is a bit of a mind-blower. Calls to your bean from other classes will be proxied correctly. However, if you call your bean from within one of it's own methods, it will _not_ be proxied. This is because external calls are really calling through the proxy. However, internal calls are calling through the 'this' reference and so are 'inside' the proxy. So, if you call an @Transactional method from another method in the same bean, the call will not be tranacational because it does not go through the proxy. The same thing is true of calls down into the super() class because these are also made through the 'this' reference.
One way to fix this issue is to refactor and break out the @Transactional methods into their own bean which can be proxied. That can be a bunch of work and may mess up your well designed bean. The way I solved my problem is slightly icky, but it works well. Since my bean is a singleton, I can inject a proxied copy of the bean into itself using the spring configuration. I simply add a field that is based on the bean's own Interface type and inject it. I then make internal bean calls to transactional methods through the injected reference and all is well.
The example below uses self-injection so it can call proxied versions of it's own methods through the thisProxy field. Here is the bean definition:
<bean id="foo" class="Foo" >
<property name="foo" ref="foo" />
</bean>
Here is how a intra-class proxied call would look:
public class FooImpl implements Foo
{
private Foo thisProxy; // this get's injected by Spring
public setFoo(Foo proxiedFoo)
{
thisProxy = proxiedFoo;
}
public Foo()
{
}
public void someFoo()
{
thisProxy.someTransactionalFoo();
}
@Transactional
public void someTransactionalFoo()
{
// fooing within a transaction....
}
}
Don't try this if you use scope=prototype however. In that case, your injected thisProxy will be pointing to a different copy of Foo!
Sunday, March 1, 2009
Flex Custom Components in Design Mode
I'm just learning Flex, but I already love it. Flex Builder/Eclipse is a descent development environment. The Flex Framework is very nice. The component and event model is pretty solid. It allows you to get started very quickly using MXML and then go deep using AS3. The integration between these modes is really well done. AS3 is a nice language - very easy for Javans and Sharpies to learn. The biggest benefit, however, is that I can draw anything I want and it will look and act the same in just about any browser. And I mean draw - not just layout. I can draw to a cross-platform graphics canvas in the browser. Cool.
Yesterday I started experimenting with custom components. The Flex documentation includes a good explanation of creating custom components using MXML and AS3 (download the pdf at http://livedocs.adobe.com/flex/3/createcomps_flex3.pdf, or view the live docs at http://livedocs.adobe.com/flex/3/html/help.html?content=Part4_CreateComps_1.html). For my purposes, I just needed a simple text object with rounded corners. It didn't seem like the TextArea control allowed rounded corners, so I subclassed VBox and included a TextArea control within it. I started first by creating a example of what I wanted using MXML. I then moved to AS3 and recreated the component. In both cases I found out something that many other folks already know; custom components generally don't draw themselves correctly in design mode. Frak. That's annoying.
When I deployed my swf, it looked correct. But inside Flex Builder's design mode, the controls were essentially blank. I tried any number of programming hacks to attempt to force the component to draw the TextArea, but all failed. An internet search found a number of posts on the subject. The consensus was that design mode is just frak'd and will not work with custom components. There was one dissenting opinion - a single line in a reply to one of those bleak posts suggested moving the component to an SWC file. That poster turned out to be on to something. Putting the component into an SWC yields another really nice bonus, which you will find out about near the end of this post (don't skip to the frak'n end!)
It's true. Components draw themselves correctly in Flex Builder design mode when they are first be compiled into an SWC file, then included as a library in the target project. Here is a quick summary on how I moved my components into an SWC file.
Using Flex Builder, I created a library project using the File/New/Flex Library Project menu item. I had pre-existing components that I wanted to put into the SWC file, so I first duplicated the package structure of the original project (the folder structure within the src folder) in the library project. I then moved the component source files to the new library project by selecting the component source files in the Flex Navigator tab and using the File/Move... menu item. Once I had my packages and source setup in the library project, I used the Project/Build Project menu item to build the SWC file.
Now I had my components in an SWC file, but I needed my target project to use it. I handled this in the target project's properties dialog. The project properties dialog is opened by selecting the project in the Flex Navigator tab, then selecting the Project/Properties... menu item (or right click on the project in Flex Navigator tab and select Properties from the contextual menu). Once the project properties dialog is open, the Flex Build Path can be selected in the list on the left. That shows the Flex Build Path panel. Selecting the Library Path tab shows the list of included libraries.
Project properties showing library path
It is possible, using the Add SWC... button, to add the SWC file directly to the target project. That would work. However, I think the best way to use your own components is to add the component library project itself to the target projects. The advantage that this approach has is that the SWC file will automatically be built by the projects that use it. This allows you to make modifications to a component and have those modifications automagically reflected in the projects that include it. The resulting work flow is natural and similar to having the component source directly in the target project. The big bonus is that the components can now be easily re-used in any number of projects.
So, I added the component library project to the target project by selecting the Add Project... button in the target project's Library Path properties, then I selected the component library in the resulting file dialog. That process effectively made the component project a library to the target project. Building the project shows how this arrangement works. When I make any modification to the components' source in the component library project and go back to the target project and choose the Project/Build Project menu item, I can observe the build process in the window that appears. The component library project is built before the target project is built.
Now when I look at the target application in Design Mode, the component draws itself correctly (mostly). That, of course, was the original purpose of this exercise. It still turns out that design mode is not perfect when showing custom components. It seems like it may keep a cache of the components, so some of your changes may not be reflected immediately. A workaround is to close and open the target project. That seems to synchronize with the latest version of the components. So, not perfect. Custom components in design mode still needs a little work. If I figure anything else out, I'll let you know. However, I think you will find that creating your own components in a library project offers other important benefits, so it should become your standard method for integrating your custom components into a project.
Subscribe to:
Posts (Atom)