|
Friday, August 18, 2006
|
|
|
One of the key features that first hooked me on Eclipse was its (Java) refactoring capabilities. Refactoring is an indispensable tool in the Java code jockeys toolbox, and Eclipse makes it easy. The Eclipse Language Toolkit (LTK) provides a framework within which to build refactorings.
As we move into the realm of service-oriented programming, developing services that can be deployed on Enterprise Service Buses, I'd like to see the same level of refactoring available for SOA artifacts. By SOA artifacts I mean things like WSDL, BPEL, deployment descriptors, as well as Java classes and other language files. At the detail level, the relationships between these artifacts can be complex.
With WSDL described services, when the WSDL changes some refactoring often happens automatically i.e. tooling can regenerate the proxy code for a service when the WSDL describing the service changes. But beyond this kind of thing, more sophisticated refactoring is required. In fact, whether this refactoring is done explicitly by the user, or implicitly by the tooling reacting to changes in WSDL and automatically altering other artifacts, much of what needs to be done is the same.
The use case I'm starting with is a simple one. A BPEL script implements a service defined using WSDL. The BPEL script invokes another service also defined in WSDL. It should be possible to rename a portType operation by highlighting the operation in the WTP WSDL Editor in Eclipse, right clicking and choosing Refactor | Rename. I'm considering both the cases of the service implemented and the service invoked.
It is worth noting that the WSDL editor in Eclipse 3.2 provides a basic rename refactoring feature, but to date I think its pretty limited.
The LTK provides a high level framework for refactoring, within which I'm going to put the framework for SOA artifact refactoring. The basic steps are something like this:
- Identify the refactoring the user wishes to perform e.g. renaming a WSDL portType operation.
- Find all the projects and artifacts in the workspace that should be changed.
- Perform the initial sanity check.
- Ask the user for more information if necessary.
- Calculate the changes required to each artifact.
- Check that each artifact will still be valid after the changes.
- Present the changes to the user for acceptance or alteration.
- Commit the changes.
Lets have a look at a snippet from a really simple WSDL file, HelloWorld.wsdl, that shows an operation called sayHello:
<wsdl:portType
name="HelloWorld"> <wsdl:operation
name="sayHello"> <wsdl:input
message="tns:sayHelloRequest"/> <wsdl:output
message="tns:sayHelloResponse"/>
</wsdl:operation> </wsdl:portType> Lets suppose this WSDL operation has a SOAP binding. The operation name also appears in the binding and in the soapAction attribute in the binding:
<wsdl:binding
name="HelloWorldBinding" type="tns:HelloWorld"> <soap:binding
style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation
name="sayHello"> <soap:operation
soapAction="cc:HelloWorldService:HelloWorld#sayHello"/> ...
</wsdl:operation> </wsdl:binding>
As in the example, by convention message names often follow the form: Request, Response. It would be great if the user could choose to also rename these as an optional part of renaming the operation name.
One of the Eclipse plugins I'm going to develop will house the framework core. The implementations of the various parts of the framework can be contributed via extension points.
Lets consider the problem of finding all the relevant artifacts and the projects that house them across the Eclipse workspace. While this first use case considers just WSDL and BPEL, the search-for-artifacts step, at a high level, is general enough.
The job of the Artifact Finders is to find projects and their artifacts that require changing in response to the operation rename.
Consider the case where the HelloWorld.wsdl file lives in one project, some projects have a link to it and others have a copy of it. The projects with a link to it are easy enough to find. Any projects that contain a file called HelloWorld.wsdl are also candidates, but just because one WSDL file has the same name as another does not mean they represent the same service, or the same version of the service. A trickier case again is where the WSDL file is indirectly referenced e.g. it is imported by another WSDL file, or referenced in a descriptor file. For these latter cases we may require some deep searching, which could be time consuming, so we need to bear that in mind.
Artifact Finders are one element of the framework. The Artifact Finder interface will look something like this:
public interface IArtifactFinder { public RefactoringParticipant[] findArtifacts(SOAArtifactRefactoringArguments args); }
And the extension point is defined like this:
<extension
point="org.codecurl.soa.refactor.finders"> <artifact-finder
id="foo.id" name="Foo Refactor BPEL
Artifact Finder"
class="org.codecurl.soa.refactor.finders.FooFinderImpl"/> </extension>
Lets look next at the changes required to the BPEL script, considering first the case where the BPEL service implements the interface defined by the HelloWorld.wsdl file. The variable definitions for the input and output messages may need be to changed (if the user has chosen to also rename the input and output message types):
<bpws:variable
name="sayHelloRequest" messageType="ns:sayHelloRequest"/> <bpws:variable
name="sayHelloResponse" messageType="ns:sayHelloResponse"/>
For consistency, we should allow the user to rename the variables too if the message type names are changing. The receive starts the process:
<bpws:receive
partnerLink="HelloWorld" portType="ns:HelloWorld" operation="sayHello"
variable="sayHelloRequest"
createInstance="yes"> </bpws:receive>
So the operation name is changing and maybe also the variable name. And the process ends with a reply:
<bpws:reply
partnerLink="HelloWorld" portType="ns:HelloWorld" operation="sayHello"
variable="sayHelloResponse"> </bpws:reply>
Again, the operation name and possibly the variable name will change.
In the case where the BPEL process is invoking the HelloWorld service, we need to consider the invoke element. The operation name attribute value will change, and the inputVariable and outputVariable attribute values may change:
<bpws:invoke
partnerLink="HelloWorld" portType="ns:HelloWorld" operation="sayHello"
inputVariable="sayHelloRequest"
outputVariable="sayHelloResponse"> </bpws:invoke>
We need to set up the invoke call by populating the sayHelloRequest message, so we should look for assign elements that use the variables:
<bpws:assign>
<bpws:copy>
<bpws:from><xs:string>Bob</xs:string></bpws:from> <bpws:to
variable="sayHelloRequest"/>
</bpws:copy> </bpws:assign>
Callbacks (onMessage) also need to be considered.
One of things I want is APIs for refactoring the various models (WSDL, BPEL, whatever). I like to start with a "perfect" API for something like this, and then implement that with off the shelf components (like WSDL4J) and whatever additional code is required.
Once I have the framework plugin working for this simple example, I will look at contributing to the appropriate Eclipse project/area. Maybe the SOA Tools Platform and/or the LTK.
8:29:26 AM
|
|
|
|
© Copyright
2006
David Black.
Last update:
9/11/2006; 2:11:50 PM.
This theme is based on the SoundWaves
(blue) Manila theme. |
|
August 2006 |
Sun |
Mon |
Tue |
Wed |
Thu |
Fri |
Sat |
|
|
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
|
|
Jul Sep |
|