Don Brown wrote:
I'll respond in more detail later, but I wanted to correct a quick
misconception.  OSGi allows you to deploy multiple versions of the
same API via different bundles.  No special package namespace, no
hassles from the standpoint of the user - just declare what version
you need and it all just works.

Here is how it could look:

Struts 2 -> OSGi plugin (with container) -> API impl bundles -> API bundles

Therefore, multiple API versions and multiple implementations could be
running at the same time, with OSGi hooking them together as
appropriate.  This is only possible with OSGi.
I think either I'm mis-understanding the point of this thread or you are mis-understanding what I feel the issue is. In either case, there is a disconnect. I'll jump off the thread because my main concern is still API compatibility and breaking compatibility at the API level can't be solved by a tool. This problem is a compile time problem that needs to be handled by developers. OSGi is a runtime dynamic loader, not a compile time dynamic method binder or a runtime dynamic method invocation layer.

-bp


Don

On Sat, Apr 26, 2008 at 3:45 AM, Brian Pontarelli <[EMAIL PROTECTED]> wrote:
 Ian Roughley wrote:

Maybe I'm overstepping my knowledge from fact, but I thought the benefit
of OSGi was that you could have completely different implementations (i.e.
PackageConfig) running on the same JVM, with OSGi providing the classloading
magic so that the implementations don't collide.
It actually is a compile time issue first and then later is a method
invocation issue and has nothing to do with OSGi. Think of it this way, you
have an interface:


 org.apache.struts.api.SomeInterface

 It has two versions 1.0 and 2.0. They are very different and look like:

 1.0
 ----------------------
 public void method1();
 public String method2();
 public Object method3(String);
 public Object method4(String, int);

 2.0
 ----------------------
 public void method1();
 public int method2();
 public Object method4(int, String);
 public Object method5(long);

 As you can see, method1 is the same, but the rest of it is changed
drastically. The issue is now that the interface is still in the same
package and has the same name. How do you compile against both versions?
Furthermore, how would OSGi be able to resolve the method invocations at
runtime to the two different versions?

 Very difficult problems that I've done some work on. There isn't any good
solution. The only way to make it work is to follow the Java Virtual Machine
specifications for compatibility or implement dynamic method translation at
runtime. I've done that for fun to see if it works and it does, but requires
translators for each interface and then you have loads of more code to
manage and TONS of edge cases. But, it was a cool weekend project I whipped
up to see if it was possible using CGLIB and some other tools.



My question with Don's proposal is with item #4.  Is it new features of
the same webapp that use new APIs or new webapps that use the new APIs?
Option one is going to be hard, and may not be possible even with OSGi.  For
option 2, I'm wondering if OSGi is overkill (i.e. would webapps be separated
enough via the container).  A better question might be is it the webapps
that need to change the APIs they are using, or is it the plugins?
Yeah, my thoughts were along the same lines. Not sure OSGi really helps
that much. Here's the main case I want to cover and OSGi doesn't really
provide a solution:

   You are writing something that uses Struts2 (plugin, extension, fork,
webapp, whatever) and want to upgrade from 2.0 to 2.1. Since traditionally
these are "minor" versions, the changes should be minor, meaning they should
be compatible. Therefore, you should be able to "just drop the JAR in the
classpath" and everything should work. This is the ultimate definition of
compatibility and something I feel Struts needs to start ensuring.

 -bp





/Ian

Brian Pontarelli wrote:

Yours and mine are the same because you still have implementations
inside Struts for some of the API interfaces. For example,
org.apache.struts2.config.PackageProvider (yeah, I did move this from XWork
to Struts for my example ;), will be an API interface that applications can
implement. Struts2 also implements this API.
Another case is a non-interface POJO like PackageConfig. This class can
be instantiated by app1 and then passed back to struts. Likewise, app4 might
instantiate a different version and pass it back. You have to separate these
into namespaces in order to compile Struts if the versions of PackageConfig
are fundamentally different.
If we take the concrete example of 2.0.* and 2.1 for PackageConfig, one
is mutable, the other is immutable with the Builder pattern. However, they
have the same package and classname. The issue is that at compile time
Struts needs to import and use PackageConfig. The only way I know how to
pull this off is extract a common interface (Java interface that is - public
interface IPackageConfig) and make adapters OR to separate them into
namespaces.
  org.apache.struts.config.PackageConfig_2_0
  org.apache.struts.config.PackageConfig_2_1

Then you can see the ensuing code inside Struts to deal with these:

  org.apache.struts.config.ConfigurationManager_2_0
  org.apache.struts.config.ConfigurationManager_2_1

And then you need some method of determining the version of the API that
the application is using and then select a configuration manager based on
that.
Now, there might be some type of tricks and things that OSGi can provide
to make this happen, but I'm not familiar enough with advanced bundling and
classloading to know how it would work. From what I understand of OSGi, any
bundle can only use a version of a dependent bundle that is compatible with
the version of that dependent bundle it compiled against.
For example, if I compiled against log4j 1.0, I can use 1.3 because they
are compatible at runtime and compile time. However, I can't use log4j 2.0
because the interfaces changed and things will blow up nicely at runtime.
What OSGi does provide is the ability to have one bundle using log4j 1.x and
another bundle using log4j 2.x in the same VM. I'm not aware that they have
gone any further than that.
Ian Roughley wrote:

Is this the case, or was the thinking more like:

                                    - app 1
               - api 1.0 --{
              /                     - app 2
Struts ---{
              \                     - app 4
               - api 2.0 --{
                                    - app 3

I think this is how I perceived it.  I also agree with Brian that
there will be a burden on s2 to provide the necessary features for all APIs,
but I think it's less of a burden in this layout.
/Ian


Brian Pontarelli wrote:

Here's a few things I think about when considering API versioning:

1. How many implementors are there? It sounds like there will be one
- Struts2
2. Do you want to allow implementors to implement multiple APIs?
Sounds like yes.
3. How much is shared between APIs? Probably a lot.

From what it sounds like, and correct me if I'm wrong, you are
looking to do something like this:
API 1.0----------\
               |----------- Struts2
API 2.0----------/

If this is the case, it will require some interesting coding
tactics. Sun and IBM have some white papers on these types of cases. OSGi
will shield the two APIs from each other so there aren't any conflicts,
however, the implementor will have the unfortunate task of implementing
both. This becomes difficult without proper structure at compile time
because struts2 will need to implement multiple interfaces from both
versions and these interfaces might overlap.
I've done some of this type of work before and in order to truly
break compatibility between 1.0 and 2.0, you need namespaces in order to
allow Struts2 to implement both. Otherwise you get naming conflicts that
cannot be resolved by the compiler. I've do things like this before:
org.apache.struts.api1.SomeInterface
org.apache.struts.api2.SomeInterface

This is the same interface, but breaks compatibility between the API
versions. Only by separating the namespaces will you be able to implement
both at compile time. I've also worked with other situations like this:
org.apache.struts.api.SomeInterface_1_0
org.apache.struts.api.SomeInterface_2_0

What it comes down to is that if you are going to break
compatibility at the API level you need to actually create a brand new API.
When you look at it from this perspective, OSGi really isn't needed, just
nice to have. Since the two API versions are in different namespaces, there
aren't any collisions at compile-time or runtime, eliminating the need for
bundle separation.
Having done some of these types of solutions before, I can attest to
the pain that they can cause. They can also become complex to manage. Which
sorta leads back to my original statements about compatibility. I'd much
rather see something like this:
1. The APIs locked down
2. These APIs called Struts3
3. No APIs break compatibility until Struts4

Therefore, 3.0, 3.1, 3.2, etc are all compatible. Then when Struts4
start wanting to break compatibility, you branch Struts3, and start breaking
away on Trunk.
-bp



Don Brown wrote:

As I learn more and more about OSGi, I wonder if it might be the
solution to several big problems we seem to have at the moment:
poor
reloadability and the lack of a solid API.  With OSGi, you can
drop
bundles in and out of the system at runtime, even running multiple
versions of the same bundle side-by-side, but the feature I'm most
interested in right now is how it would allow us to put in a
proper
API while maintaining full backwards-compatibility.

Evolving a web framework is hard because apps tend to be written
on a
specific version, and to migrate them to new versions has two
problems: development may not be continuously funded and the
upgrade
may require too many changes to the application.  On the other
hand,
if you don't evolve your web framework, you quickly go out-of-date
and
lose interest from new developers.  In our case, despite being a
relatively new framework, we have legacy code around from 2004
that we
can't just remove, yet we want to provide an attractive, modern,
clean
framework for new development.

The specific issue it hand that I've been thinking about is how to
get
a proper API into Struts 2 yet keep backwards compatibility, and I
think OSGi might provide a solution.  What about this:
 1. Struts 2 and its plugins remain the way they are now - 100%
backwards-compatibility
 2. An OSGi plugin provides the platform for the next generation
of Struts 2
 3. A new API bundle is created, implemented by the underlying
Struts
2 framework
 4. Old apps can continue to write and deploy code against Struts
2,
yet new development can start to use the new API
 5. Later, when we want to write API version 2, we create a new
bundle
that runs side-by-side the old bundle, both implemented by Struts
2
Basically, OSGi would allow us to write a clean layer on top of a
framework, much like how Grails builds on Spring, but we get, as a
side benefit, all the architectural advantages of OSGi for free.
Furthermore, if we do it right, users don't have to know or care
that
OSGi is under the hood - all they know is they write a jar, drop
it in
a directory or upload it via a form and they just installed part
of
their application at runtime.

Don


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]




---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]


 ---------------------------------------------------------------------
 To unsubscribe, e-mail: [EMAIL PROTECTED]
 For additional commands, e-mail: [EMAIL PROTECTED]



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to