David Jencks wrote:
My comments below are based on not having looked at the pluto 1.1
implementation at all and the pluto 1.0.x implementation years ago.
On Feb 8, 2008, at 11:18 AM, Ate Douma wrote:
Dear committers, community,
Jetspeed-2 currently still uses Pluto 1.0.1 as its JSR-168 container,
but we want and need to upgrade and migrate to the latest Pluto
container under
development, aka the not yet released Pluto 2.0 targeted as the
JSR-286 RI.
This however is currently impossible to do because of the
architectural changes Pluto underwent from version 1.0.x to 1.1.x.
Technically, viewed from the POV of an easy to embed container for the
Pluto Portal Driver, or environments which only need the
out-of-the-box features
provided, these architectural changes have resulted in a much simpler
and easier to understand and maintain model and API, and as such these
changes were great!
But... for a portal like Jetspeed-2, which provides a much enhanced
usage and feature list *on container level*, these architectural
changes have, simply put,
completely broken with the functional and technical "contract"
provided by Pluto 1.0.x and as such make it now impossible for us to
migrate to the current Pluto
container.
As it is the primary mission and goal of the Pluto project to provide
an embeddable portlet container for portals like its Apache Portals
sibling project
Jetspeed-2, it is our view (as Jetspeed-2 committers) that we need to
discuss what needs and can to be done, on both Jetspeed-2 and Pluto
side, to bring our
projects back together, and how to restore the original *functional*
contract Pluto provided with version 1.0.x.
To this end, we'll present our (short) assessment how the current
Pluto container API and implementation has changed and broken with the
old Pluto 1.0.x
features which Jetspeed-2 depends upon to be able to maintain our
current Jetspeed-2 features, as well as what we think needs to be done
*functionally* to
restore these features.
To be very clear: we're not asking nor suggesting to restore the old
Pluto 1.0.x API and SPI as is. We fully expect and are willing to
adapt Jetspeed-2 to the
new Pluto architecture as much as needed, even while that most likely
will now cause Jetspeed-2 itself to have to break with its own public
API and thus lose
(some) backwards compatibility. After all, Pluto now has had several
releases based on its new Pluto 1.1.x architecture and we (as Apache
Portals community)
have the obligation to maintain as much backwards compatibility for
the users of these versions as well.
So, what we will propose later on is to work towards a solution which
will restore the ability for Jetspeed to properly use and embed the
new Pluto 2.0
container but still maintain the lightweight and simple configuration
and usage of the container for portals like the Pluto Portal Driver
and other use-cases
without breaking its current "contract".
But first lets get down to some of the issues we have identified so
far. This is most likely not the complete list but covers the most
important ones.
The Pluto 1.0.x object model API (OM)
=====================================
Pluto 1.0.x provided a fully interface based object model to represent
the web and portlet deployment descriptors (web.xml and portlet.xml).
Through factory methods, the Pluto 1.0.x container only used these
interfaces in its implementation. That allowed Jetspeed and other
portals to supply its own
implementation of the OM and use that to provide enhanced features
like database persistence, extended meta data, caching control, etc.
Of course, Pluto 1.0.x also provided its own implementation classes of
the OM and Jetspeed uses these as base classes but provides extended
implementations to
hook them up and into its own backend and management features.
Pluto 1.1.x completely dropped all of this. Instead, a new descriptor
API was provided with a complete new set of classes (no interfaces!)
which are used and
instantiated directly within the container with no factory support or
any other way of extending the current implementation.
As such, the current container only allows usage of the web.xml and
portlet.xml descriptors and features derived from them as provided by
the container.
Furthermore, as the loading and management of the descriptors is now
done directly (and only) by the container itself, there is no way for
Jetspeed to hook into
this process anymore.
Effectively, this means that descriptor persistence, caching, custom
extensions, *standard* support for custom portlet mode or window-state
mapping,
etc. all no longer are possible with the current Pluto container. Not
just for Jetspeed but any portal needing and depending on these features.
I suggest that there be a very clear separation between deployment code
that might look at web.xml, portlet.xml, annotations, or some other
source and use these to construct objects describing the portlets, and
the "engine" that "runs" these objects. Rewriting the deployment code
to create your own objects is pretty simple and lets you just use
objects without needing the complexity of interfaces or factories.
Also, everyone has their favorite xml technology and this lets you
replace whatever pluto might choose with one you like better. I've done
this with the jetty integration in geronimo and like the results.
Agreed, and that is more or less what I propose.
I have no problem with a basic runtime object model api based on the formal deployment descriptor structure, nor with an implementation which just and only uses
that model for management at runtime. As long as these two are separated and a different implementation can be provided too.
The Pluto 1.1.x/2.0 PortletContextManager, PortletDescriptorRegistry
and PortletServlet
=======================================================================================
With the switch to Pluto 1.1.x, the container added control and
management of the above mentioned deployment descriptors and fully
integrated them with the
container interaction which now depend on this management
*implementation*, and also hooked that up on the portlet application
context.
This means that now you need a separate container instance for each
portlet application and that the container itself loads and manages
the descriptors.
Also, interaction with the container now requires the use of the Pluto
provided PortletServlet (although that one possibly can be extended)
as it is tied to the
PortletContextManager directly (which in turn is tied to the
PortletDescriptorRegistry).
Besides the obvious problem that this effectively blocks delegating
management of the context and descriptors for the portal, it also
forces the usage and
interaction with portlets to the Pluto provided implementation.
For instance, Pluto delegates interaction to each portlet through a
separate instance of its PortletServlet, while Jetspeed currently has
its own more generic
JetspeedContainerServlet which is not tied to a single portlet. The
Jetspeed solution allows for dynamically enabling/adding portlets (as
defined in
portlet.xml) without any need to rewrite the web.xml. But using the
Pluto PortletServlet requires changing the web.xml (and thus reloading
the context) to do so.
I don't think I'll understand this issue without studying the code
extensively. However, from this description it looks like perhaps the
"deploy time" translation of xml/annotations to more descriptive
internally usable objects is too tied to the "execution" of these
objects?
Exactly, to be precise: I guess up to 100% so.
I'd expect there would be some kind of
"PortletApplicationContext" object that would have a collection of
Portlet objects and you could programatically add more Portlet objects
to it. If there is enough separation between the deploy time and run
time code this should not be a problem even if the Portlet object didn't
come from xml.
In Jetspeed we call that the "Registry" which we seed initially from our own parsing of the deployment descriptors after which we don't even look back at the
descriptors for runtime access to the "managed" objects in the Registry.
I don't see a necessary problem with the PortletApplicationContext being
the container instance if this simplifies the code.
Jetspeed provides a centralized management of the Registry across portlet
applications, even while they are offline.
I don't have a
strong opinion on the
servlet-per-portlet/servelt-per-portlet-application question: it seems
to me that with an appropriate servlet container that allows adding
servlets to a running web app they would have the same capabilities and
each would make some features easier to implement. For instance adding
a servlet to a running web app is harder than not adding it, but
implementing portlet role permissions seems easier to me with a
servlet-per-portlet approach.
The portlet context is not managed by the web container but the portlet container. As we are (or want to be) in control of the portlet container, managing those
type of features on the fly is much easier than trying to hook into the web container which might be quite different (or even impossible) depending on the
product (e.g. Tomcat/Jetty/OC4J/Websphere/Bea etc.)
The Pluto 1.1.x service provider interfaces (SPI)
=================================================
Although the new Pluto SPI (comprising of the
RequiredContainerServices and OptionalContainerServices) generally
provides a nice and simple interface to plugin
portal specific implementations, certain features available with Pluto
1.0.x are no longer available.
With Pluto 1.0.x, critical components as the PortletContext and
PortletWindow were accessed by the container through factory classes.
These no longer exist and the pluto container directly instantiates
its own implementations for these components.
Jetspeed however very much depends on its own extensions of these
components to provide support for features like parallel rendering,
clustering and attaching
additional meta data (or even preferences) to a PortletWindow or
PortletEntity.
Additionally, while Pluto 1.0.x allowed managing multiple
PortletWindows for a PortletEntity, this *Portlet Spec* feature has
been removed from the current
Pluto 1.1.x/2.0 container.
Lastly, not all of services referenced through these SPI interfaces
are only accessed through it.
For instance, the OptionalContainerService.getPortletRegistryService()
is by default implemented by the PortletContextManager. But, this
implementation is very
much directly used (as static instance even) within the container.
Effectively, the interface is now only an API portals might use, but
it cannot be replaced
and thereby cannot be regarded as a proper SPI interface anymore.
Here the long time since I've studied this code is really hurting me.
IIRC this all relates to classes that describe a portlet's environment
at runtime that are populated by the portal (e.g. jetspeed) and used by
the portlet container (pluto) or populated by both the portal and
portlet container and used by both.
Basically what I'd like to see is a strongly typed system (no fishing
for services in 6 levels of nested hash maps) based entirely on
dependency injection.
Objects describing the portlet app injected into the portlet container
by some deployment system, either plutos or something else
Environment information supplied by the portal injected from the portal
Objects that need to be created by the portlet container that also need
to be customized for the portal environment created by factories
injected by the portal environment. (I don't really understand how this
can be necessary, but if it is then a factory seems like the way to do it).
Solution
========
As indicated earlier, solving the above issues such that Pluto 2.0 can
be made embeddable again, in Jetspeed or other portals, needs to be
done in a way which
maintains backwards compatibility for current Pluto 1.1.x users.
Is this really a requirement? If a substantial improvement can be made
in the design I wonder if backwards compatibility is essential.
Well, for Jetspeed-2 itself it wouldn't really matter as we never did embed
Pluto 1.1.x
But there are others who do and I think it is important for our community not
to break backwards compatibility if not really necessary.
Pluto 2.0 is still also a JSR-168 container too, so for users who don't need JSR-286 but would like to upgrade for general improvements/fixes, backwards
compatibility is very much important.
Of course, if nobody thinks backwards compatibility is important, I would have
no problem with breaking it either.
But I don't think this is/will be the case (e.g. like for uPortal, see Eric
Dalquist his reply too).
Although we don't have a clear proposal for this, our current idea is to:
- define new OM interfaces to be implemented by the current descriptor
api classes
- enhance the OptionalContainerServices SPI to provide additional
services for loading and managing the deployment descriptors
- enhance the OptionalContainerServices SPI to provide additional
services for accessing components like PortletContext, PortletWindow etc.
- refactor the container implementation to only use the OM interfaces
- refactor the container implementation to only use the SPI provided
services and no longer directly binding to its service implementations
When done properly, the above changes should still allow using the
current implementation without any functional or even technical
consequence.
Now, the above changes will mean a lot of work and lots of testing as
well to make sure everything remains working as expected.
We, as primary Jetspeed committers have much at stake here so we are
definitely willing to help out and do much of the grunt work.
And of course, we will have a large amount of work to do at Jetspeed
Portal side as well: all our Pluto Factory implementations have become
useless, all Pluto
OM packages (and some interfaces) have changed, and we will need to
provide new implementations for the Pluto SPI container services.
For our implementations of the Pluto SPI container services, we will
definitely look at the current Pluto provided implementations and
where possible try to
make use of them as much as possible. To that end, we will probably
also need to be able to hook in our own extensions which might require
some additional
refactoring but should not result in functional or technical changes
of the default Pluto services.
Note: we want to migrate to Pluto 2.0 for our next Jetspeed 2.2
release. But, for that release we'll stick to only using the JSR-168
container features.
Then, for the following major release, version 2.3 which we currently
have scheduled sometime this summer, we will provide full JSR-286
compliance.
So, our initial goal is to get Pluto 2.0 working again with Jetspeed-2
but stick to our current features.
This all is clearly not something which can be done or will be ready
overnight, nor possible to do all by ourselves.
But we do need to start resolving this ASAP so it won't hold up the
release of both Pluto 2.0 and Jetspeed 2.2 longer than needed.
As said: the above proposal is still just an idea. And of course how
to do all this, is fully open for debate and we are very interested in
hearing the opinions
of other committers and community members (also from other portals
embedding Pluto 1.1.x).
So please, provide feedback and ideas how to solve these issues. And
suggestions for alternative solutions will very much appreciated too
With kind regards,
Dennis Dam
David Sean Taylor
Ate Douma
I hope my partially-informed opinions are helpful and not overly
intrusive.
David, your opinions and insight always have been and I expect always will be
very helpful and are very much appreciated.
Unfortunately I can't promise I'll have much time to
actually study the code soon, but I am certainly hoping to. I'll
certainly try to explain what I'm talking about more if anyone is
interested.
Thanks a lot David, we're interested :)
Regards,
Ate
thanks
david jencks