portals-jetspeed-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From raphael.l...@networks.groupvu.com
Subject Re: Portlet API re-implementation
Date Tue, 14 May 2002 10:55:55 GMT
[Sorry to be late on this thread, I'm back to work... :(]

Glenn Golden wrote:
> Here is an annotated version of:
> 
> org\apache\jetspeed\portal\Portlet.java
> 
> our "portlet API".  In this annotation, I identify:
> 
> A) things that belong to the portal page definition, not the portlet
> B) things that belong to the portlet registry, not the portlet
> C) things that the real portlet class need to know / do
> D) things that I don't think belong in this API at all!
> 
> Terms:
> 
> [there may be more accepted terms for these concepts, please comment on this
> and I'll update]
> 
> Portlet - a java .class that can be instantiated into an object which is
> called upon to provide the content to aggregate into the portal page.  These
> are objects that implement the jetspeed.portal.Portlet API.  A Portlet class
> object is multi-use (multi-thread), can have no instance variables (they
> would be shared by all threads using it), and is used to provide output
> wherever the portlet is used in various pages and under various
> configurations.
> 

OK with this definition but be aware that the current
org.apache.jetspeed.portal.Portlet class was *not* created for this purpose as
can be easily seen. Initially, this class is a graphic widget that is then
included in a tree-like structure (recursive PortletSet) to create a page.

> Portlet Registration - an entry in the portlet registry which identifies a
> portlet class and provides other parameter information.  This is not usually
> modified at runtime - only initialized from the registry files.
> 

I think there are some valid reasons for runtime modification depending on what
is the role of teh protlet registry. More on this topic in another future mail...

> Portlet Instance - an Entry in a PSML portal page description which
> references a portlet registration (and thus a portlet class and parameters)
> and additionally provides parameter, layout, and display information.  This
> can be modified at runtime, needs to be stored back to the psml store (file
> or db), and once modified must be used as modified by all users and uses
> from then on.
> 

OK

> The overriding idea I'm proposing and working out here is:
> 
> 1) The Portlet is always called upon with a particular Portlet Instance in
> mind.
> 
> 2) The Portlet API provides some information that is not owned by the
> Portlet; it provides information from the Portlet, the Portlet Registration
> and the Portlet Instance.
> 
> 3) We introduce a new concept, "the burrito", which has reference to all
> three
> - Portlet
> - Portlet Registration
> - Portlet Instance
> 
> [ I'm open to a better term here! ]
> 
 > <snip>

I'm not sure I really like this approach. I'd propose another one (a bit more
disruptive) at the end of this mail.

> 
> My comments start ">grg>"
> 

Mine are >RL>.

> * * * * * * * * * *
> 
> package org.apache.jetspeed.portal;
> 
> /**
> A portlet is an implementation of a small control (usually rendered in HTML)
> that is available to a client application.  Portlets were designed to be
> extensible so that 3rd parties implement their own Portlets.
> 
> @author <a href="mailto:burton@apache.org">Kevin A. Burton</a>
> @version $Id: Portlet.java,v 1.43 2002/03/29 20:12:32 taylor Exp $
> */
> 
> public interface Portlet
> {
> 
>     public int PORTLET_NORMAL = 0;
>     public int PORTLET_MINIMIZED = 1;
>     public int PORTLET_MAXIMIZED = 2;
> 
> 
>>grg> this information is really part of the portal page session state, not
> the portlet...
> 

 >RL> +1

>     /**
>     Returns a name for this portlet.  This is used by PSML to identify a
> Portlet
>     within the PortletRegistry
>     */
>     public String getName();
> 
>     /**
>     Sets the name on this Portlet.
> 
>     @see #getName()
>     */
>     public void setName(String name);
> 
> 
>>grg> the name belongs to the Portlet Instance PSML Entry, and would be a
> 
> cover to that object
> 

 >RL> +1

>     /**
>     <p>
>     Allows a Portlet to define its title.  This can be used by a
> PortletControl
>     for rendering its content.
>     </p>
> 
>     <p>
>     In order to define a default title you should not override this but
> should
>     call setTitle() within your init() method
>     </p>
> 
>     <p>
>     This should return null if not specified.
>     </p>
>     */
>     public String getTitle();
> 
>     /**
>     Set the title for this Portlet
>     */
>     public void setTitle( String title );
> 
> 
>>grg> the title belongs to the Portlet Instance PSML Entry, and would be a
> 
> cover to that object 
> 

 >RL> +1

>    /**
>     <p>
>     Returns a description of this portlet.  This should describe what the
>     capabilities of the portlet and how it can help the user.
7>     </p>
> 
>     <p>
>     In order to define a default title you should not override (in the
>     AbstractPortlet implementation) this but should call setDescription()
>     within your init() method
>     </p>
> 
>     <p>
>     This should return null if not specified.
>     </p>
>     */
>     public String getDescription();
> 
>     /**
>     Set the description for this Portlet
>     */
>     public void setDescription( String description );
> 
> 
>>grg> the description belongs to the Portlet Instance PSML Entry, and would
> 
> be a cover to that object (might be transient in the Portlet Instance
> object)
> 

 >RL> +1. This is true for all content metadata. If we want to provide
component meta-data (like version, author, etc...) it should done in the
Registry.

>     /**
>     Returns an HTML representation of this portlet.  Usually a Portlet would
>     initialized itself within init() and then when getContent is called it
>     would return its presentation.
>     */
>     public ConcreteElement getContent(RunData rundata);
> 
> 
>>grg> Ah, getContent is something that the Portlet itself is responsible
> 
> for!
>

 >RL> Right, although if you use your above Portlet definition, it should really
      look different because you don't want to expose to programmers an API that
      depends on 2 others external API (Turbine and ECS) for no useful purpose.

      This could be modified to:

      public JetspeedContent getContent(JetspeedRequestContext jdata)

      or even follow a more servlet-like syntax.


>     /**
>     All initialization should be performed here.  If your Portlet wants to
>     do any work it should be done here.  You are not guaranteed that any
>     particular order of method call will happen just that init() will happen
>     first. Therefore if you have to calculate things like a title, a
>     description, etc it should happen here.
>     */
>     public void init( ) throws PortletException;
> 
> 
>>grg> init might just be called once per server run... Or should we
> 
> guarantee that it's called each time we pack a burrito up so it can look at
> all the info and set stuff like description...  Can't really do much in
> init.
> 

 >RL> init() should only be called once per Portlet lifecycle. But again you must
      remember that the class you're looking at was not designed to provide the
      service you expect from it.

>     /**
>     Set's the configuration of this servlet.
>     */
>     public void setPortletConfig(PortletConfig pc);
> 
> 
>>grg> THIS HAS TO GO!  No need for it - the config is "set" by the burrito
> 
> 

 >RL> +1000.

>     /**
>     Get the config of this servlet.
>     */
>     public PortletConfig getPortletConfig();
> 
> 
>>grg> This is a cover to (I'm not sure) the Portlet Instance (PSML Entry)?
> 
> The Registry information?  Both?  Whatever - it's a cover, and read only for
> our portlet at that.
> 

 >RL> Actually getPortletConfig() is quite complex as it provides access to:
      - content meta-data
      - aggregation context
      - personalization

>     /**
>     <p>Return true if this portlet is allowed to be edited in the rundata's
> context .</p>
> 
>     <p>Note:  PortletControl implementations should pay attention to this so
>     that they don't allow this option if it returns false.</p>
>     */
>     public boolean getAllowEdit( RunData rundata );
> 
> 
>>grg> I guess getAllowEdit() is also a Portlet responsibility!  Always
> 
> called in the burrito context, so that all that information is available to
> the portlet to make the decision.
> 
>     /**
>     <p>Return true if this portlets is allowed to be maximized.</p>
> 
>     <p>Note:  PortletControl implementations should pay attention to this so
>     that they don't allow this option if it returns false.</p>
>     */
>     public boolean getAllowMaximize( RunData rundata );
> 
> 
>>grg> I guess getAllowMaximize() is also a Portlet responsibility!  Always
> 
> called in the burrito context, so that all that information is available to
> the portlet to make the decision.
> 

 >RL> I'm not sure.

   Maximize and Edit should actually be treated differently IMO:

   - Maximize/Minimize should not be "allowed" by the portlet. This is really
     a task of the portlet control that can look up the relevant information
     either in the Registry or possible the PSML Entry.
   - Edit basically means whether the portlet supports customization. This is
     a role for the PortletControl in there that may want to check if the user has
     a right to edit a specific instance (possibly by using a combination of
     declarative flags in the Registry and some Security logic).

>     /**
>     Get the creation time for this Portlet
>     */
>     public long getCreationTime();
>     
>     /**
>     Set the creation time for this Portlet
>     */
>     public void setCreationTime( long creationTime );
>     
> 
>>grg> I know, creation time if for our caching - but hey - a portlet never
> 
> ages!  It is read-only, right?  It's being used all over the place for
> different instances, so we can't mess with it.  I suggest we drop this and
> drop the time issue from caching, if we cache.
> 

 >RL> Drop it for a "Portlet" as defined above. Thsi was really intended to be
      used to cache generated content stored inside the Portlet (check
      AbstractPortlet.setContent(...) ).

>     /**
>     Returns true portlet is able to output content for given mimetype
>     */
>     public boolean supportsType( MimeType mimeType );
> 
> 
>>grg> supportsType() is more good old fashioned Portlet class
> 
> responsibility.
> 

 >RL> I disagree. This should be part (and actually is implemented in) the
      Registry. Additionnally, mime-type is not precise enough to really
      work because I think there's a need to be able to support the same
      mime-type differently (for example full HTML 4 and HTML lite/cHTML/...)
      That's why media types were introduced, even though the implementation
      is very rudimentary currently.

>     /**
>     Retrieve a portlet attribute from persistent storage
> 
>     @param attrName The attribute to retrieve
>     @parm attrDefValue The value if the attr doesn't exists
>     @param rundata A RunData object
>     @return The attribute value
>     */
>     public String getAttribute( String attrName, String attrDefValue,
> RunData rundata );
> 
> 
>>grg> getAttribute() covers either the Portlet Instance or the Registry info
> 
> or both.
>

 >RL> +1

>     /**
>     Retrieve a unique portlet id 
>     */
>     public String getID();
> 
> 
>>grg> (my favorite) getID() covers the Portlet Instance's getId().  And why
> 
> ID() vs. Id()?
> 
>     public void setID(String id);
> 
> 
>>grg> Bad Bad Bad!  Drop setID()
> 
> 

 >RL> +1

>     /**
>     * @return true if the portlet does its own customization
>     */
>     public boolean providesCustomization();
> 
> 
>>grg> providesCustomization() a Portlet class thing.
> 
> 

 >RL> +0. This can probably considered purely part of the Regsitry.

> }
> 


I think we pretty much agree. IMO everything a "Portlet developper"
should see from a base API perspective is something like this :

interface Portlet {

	// Life cycle management	

	/* called only once. JetspeedConfig has pointers to
            portlet Registry information and Jetspeed general information
          */	
	public void init(PortletConfig) throws PortletException

         public void service(PortletRequest, PortletResponse, PortletContext)

         public void destroy()

         // Helper methods (optionnal, maybe defined in sub-interface)

         public void doDisplay(PortletRequest, PortletResponse, PortletContext)

         public void doMaximize(PortletRequest, PortletResponse, PortletContext)

         public void doMinimize(PortletRequest, PortletResponse, PortletContext)

         public void doEdit(PortletRequest, PortletResponse, PortletContext)

}

(There's some room for discussion in there...)

Additionnally, if the Registry in Jetspeed continues to play the same role than
today (ie both component regsitry (portlet type abstract and instance) and content
registry (portlet type ref) than I see a need to allow a portlet to register
programmatically new portlet refs (think for example of the RSS portlet which would
automatically register all the RSS sources available to her through the syndication
system).

Such method would be:

public void register(PortletRepository)

where PortletRepository provides a view to the Portlet components of all the
ref entries attached to this component.

Now how to go from today to there:

I would propose the the following path, whose ultimate goal is to deprecate then
remove the current portal package :

- introduce an "aggregation" package that basically recreates the current
   Portlet/PortletControl/PortletController structure, expect that the Portlet
   class does not implement the methods marked as "portlet instance". Maybe even
   get rid of Portlet completely and only use PortletControl and Controller.
   Such a package would become the default aggregation system for jetspeed and be
   invoked by JetspeedTool.
   It would be considered a "private" API that is only meaningful if somebody plans
   to modify/extend Jetspeed aggregation policy.

- introduce a "container" package with a clean public Portlet component API that
   can be used by developper to create modules. This package can for example be
   the new JSR API, the current IBM portlet_api or an intermediate...

- introduce in the Registry a "version" attribute when registering components,
   version "1.0" will be equal to the current broken "portal" package, "1.1" will
   be the new "container" package, etc...

- when building a page, the aggregation would use the following algorithm:

   - Examine root PSML container object
   - delegate its rendering to the appropriate controller
   - controller:
     for each PSML entry, delegate rendering to appropriate control
        control:
          for each PSML entry, find the corresponding Registry
          component version
          Instanciate the corresponding Portlet wrapper object
          wrapper:
             1.0 -> instanciate a new portal.Portlet instance, create
                    a PortletConfig, associate it to Portlet, invoke init(),
                    invoke getContent()
             1.1 -> From RunData object, create PortletRequest, PortletResponse
                    and PortletContext, invoke portlet.service method

The net effect of this being that we can then:
- deprecate the currently broken API
- provide a migration path from old API to new
- decorrelate the aggregation work from the portlet container
   which will make it easier to follow JSR work.

-- 
Raphael Luta - raphael.luta@networks.groupvu.com
Professional Services Manager
Vivendi Universal Networks - Paris


--
To unsubscribe, e-mail:   <mailto:jetspeed-dev-unsubscribe@jakarta.apache.org>
For additional commands, e-mail: <mailto:jetspeed-dev-help@jakarta.apache.org>


Mime
View raw message