Introducing the eXo Platform

来源:百度文库 编辑:神马文学网 时间:2024/04/28 02:23:20
This article overviews the eXo platform and of all its modules. It focuses on thearchitecture, underlining the design decisions we made while building the platform. Many aspects of theJava 2 Enterprise Edition (such as J2EEdeclarative security, servlet/jsp, EJB) have been used and the way we leverage them will be detailed.Note that some knowledge of UML[1]is required to understand some of the diagrams. A basic understandingof the J2EE platform would be helpful as well, although we willintroduce most of the notions.
The binaries and thesource code of the eXo platform 1.0 beta2 will be downloadable at theeXo site.The eXo platform only requires a Java virtual machine on your computer. Once you have installed it, you must pointthe JAVA_HOME environment variable to your java distribution directory.Go to exo-jboss/bin and launch the run script. Open your browser athttp://localhost:8080/exo/faces/public/layout/blue-lagoon/portal.jsp.
If you want to build the platform from the source code that is in the SourceForge Current Versioning System (CVS)repository you will need to check out several modules :
the ExoBuild module
the ExoPortal module
the ExoServices module
the ExoPortletContainer module
the ExoDeployer
the ExoCMS module
the ExoPortlets module
the ExoCommon module
In ExoBuild you need to update build.properties and run ant build.exo.portal.
The eXo project started two years ago with the idea of providing enhanced communicationstools (asynchronous and synchronous) to make online Math courses possible. After we had developed a LearningManagement System (LMS), we decided to provide a custom web site as the basis for a Learning Content ManagementSystem (LCMS). The portal development started nine months ago. When we first planned to implement a portal welooked at the jetspeed cvs and found a portlet API draft that had been written and given to the communityby Stefan Hepper from IBM. We read it, and as it was well designed, and decided to implement it.A bit later we realised that this draft was much like the lastWebsphere portlet API. When we finally discovered that Stefan Hepper was one of the spec leads of the JSR 168team, and it became clear to us that implementing the Websphere API was the way to go...
For the time being, there are two distributions of the platform available (both under the GPL licence):
exo-express
This distribution does not include the Enterprise Java Bean (EJB) container. The organization model isbuilt using Hibernate.The version is intended to be used by personal and community sites. Since we first advertised theplatform on TheServerSide.com (/news/thread.tss?thread_id=21102), we did not have any problems with the online demo.The server we are using is an Athlon 750 with300MB Ram running on Linux. We successfully handled 10K requests per day, the JavaVirtual Machine (JVM) consummation never surpassing 80MB of Ram. However, stress tests will be done before theversion 1.0 release.
exo-enterprise
This version of the platform has been designed to fulfill enterprise needs.Based on the exo-express version described above,it offers an EJB container and a workflow system. The organization model uses Hibernatebut an EJB version can also be implemented.Note that this distribution consumes much more memory (between 128 and256 MB for a normal load). The exo-enterprise is an enterprise level portal that can be used inany Intranet. Moreover, workflow functionalities allow you to add Business Process Management (BPM)and Enterprise Application Integration (EAI). The set of Business Processes (BP) will gradually growto manage Human Resources and Customer Relationship (CRM) management and, finally, adapt tocustom business logic.A partnership with a bank company has been established to introduce the eXo portal as the Intranet enterpriseportal solution and to provide Human Resources business processes.
In the exo-express/ and the exo-enterprise/ directories we can find:
Figure 1. eXo express and enterprise main directory

The lib/ and the exo-lib/ directories contain some specific library archives necessary to run the platform.The conf directory allows you to configure some deployment and security information as well as thelogin tool. If you need to debug something you should go to this directory and set up log4j.xmlas you wish. The log directory will contain the log files as defined in the configuration file above.
There are four deployment directories, each having its own purpose. The container-deploy/ directory containsarchives and files related to the platform - you will probably never have to use it. The deploy directory containsthe web application archives (WAR) that are not portlets, as JBoss does it. The portlet-deploy directory is the placeto drop your portlet WARs. Finally, the services-deploy directory allows you to drop all the eXo services archive files(.es files). Note that thisdirectory structure has only been built for convenience; in fact, you can drop your archives in any x-deploy directory.However, we do not encourage you to do so.
All the archive files are hot deployable, which means that you can add/remove/replace them when the serveris started.
Figure 2. eXo overview

The eXo deployers
For the time being, the eXo platform must be deployed in a Java application server that provides at leastthe hot deployment feature. However, we are currently working on a more general solution that would allowthe adaptation of our portal to other servers.The default portal is built using JBossMX (the JBoss implementation of the Java JMX API) and its servicearchitecture that provides an easy environment for deployers development. The ExoDeployers moduleis the application server dependant module.
Two deployers have to be created :
A portlet application deployer based on the web application deployer. The default web server is Tomcat but a Jetty deployer has been created. The deployer registers the portlet application in the portlet container.
Our portlet deployer for JBoss is based on the JBoss-Tomcat deployer. We extend the EmbeddedCatalinaService41 to leverage the WAR deployer and Tomcat. The deployer is also registered in JBoss as the WebServer MBean. Our custom deployer unmarshalls the portlet.xml file, creates the PortletApplicationProxy object and registers it in the portlet container. The ServletContext and the class loader of the web application are put into the portlet application object. We will study the portlet container design in greater detail below:
public class TomcatWebAndPortletDeployer extends EmbeddedCatalinaService41 implements TomcatWebAndPortletDeployerMBean { ... protected void performDeploy(WebApplication webApplication, String warURL, WebDescriptorParser webDescriptorParser) throws Exception { super.performDeploy(webApplication, warURL, webDescriptorParser); //perform usual web application deployment URL url = new URL(warURL + "/WEB-INF/portlet.xml" ); InputStream in = null; try { in = url.openStream(); //unmarshall portlet.xml JAXBContext jc = JAXBContext.newInstance("exo.portal.container.portlet"); Unmarshaller u = jc.createUnmarshaller(); PortletApp portletApp_ = (PortletApp) u.unmarshal(in); //get the portlet container facade ExoPortletContainerFacade facade = ExoPortletContainerFacade.getInstance(); //creates the PortletApplicationProxy to add to the eXo portlet container ServletContext sC = ((org.apache.catalina.core.StandardContext) webApplication.getAppData()). getServletContext(); URLClassLoader cl = (URLClassLoader) ((org.apache.catalina. core.StandardContext) webApplication.getAppData()). getLoader().getClassLoader(); PortletApplicationProxy portletApp = new PortletApplicationProxy(sC, cl, portletApp_); //register the portlet application to the container facade.addPortletApplication(portletApp); } catch (java.io.IOException e) { //not a portlet just a normal web application } } public void performUndeploy(String warURL) throws Exception { super.performUndeploy(warURL);//perform usual web application undeployment WebApplication appInfo = getDeployedApp(warURL); DeploymentInfo di = appInfo.getDeploymentInfo(); InputStream in = di.localCl.getResourceAsStream("WEB-INF/portlet.xml"); if (in != null) { ExoPortletContainerFacade facade = ExoPortletContainerFacade.getInstance(); facade.removePortletApplication(appInfo.getName()); } } }
A service deployer that deploys Exo Services archives and registers them in the services container. It scans the services-deploy/ directory to detect new .es archives.
This deployer code is quite different from the previous one as it implements SubDeployer and extends SubDeployerSupport. We tell the deployer which file extension to scan (.es). When the deployment occurs, we unmarshall the exo-service.xml file creating a Services object: The latter is put into the SeviceContext along with the class loader. Finally, this context is registered in the service container.
public class ExoServicesDeployer extends SubDeployerSupport implements SubDeployer, ExoServicesDeployerMBean{ //tells which extension to look for public boolean accepts(DeploymentInfo deploymentInfo) throws DeploymentException { String URLString = deploymentInfo.url.toString(); return URLString.endsWith("es") || URLString.endsWith("es/"); } [...] public synchronized void start(DeploymentInfo di) throws DeploymentException { super.start(di); InputStream in = di.localCl.getResourceAsStream("META-INF/exo-service.xml"); JAXBContext jc = null; try { //unmarshall the exo service XML file jc = JAXBContext.newInstance("exo.portal.services.model"); Unmarshaller u = jc.createUnmarshaller(); Services services = (Services) u.unmarshal(in); //creates and register the Service Context object to the ServiceManager ServiceContext sC = new ServiceContext(di.localCl, services); ServicesManager.getInstance().addService(sC); } catch (JAXBException e) { e.printStackTrace(); } } public void stop(DeploymentInfo di) throws DeploymentException { super.stop(di); InputStream in = di.localCl.getResourceAsStream("META-INF/exo-service.xml"); JAXBContext jc = null; try { jc = JAXBContext.newInstance("exo.portal.services.model"); Unmarshaller u = jc.createUnmarshaller(); Services services = (Services) u.unmarshal(in); ServiceContext sC = new ServiceContext(di.localCl, services); ServicesManager.getInstance().removeService(sC); } catch (JAXBException e) { e.printStackTrace(); } } [...] }
The eXo kernel
The kernel of the platform is based on 5 modules, independant from the application server:
The services container
The services container is based on Pico so as to provide an Inversion of Control(IoC) services manager.Therefore, the services are not responsible for the instantiation of the components they depend on;object creation is delegated to a singleton object: the ServiceManager.This architecture provides a loosely coupled design where dependant services can be transparentlyexchanged at runtime.
Let‘s look at an example: imagine an organization service that manages users, groups andmemberships between them. It needs a connection to the CMS services in order to persist the data.As we use Pico Container, the dependency must be declared in the OrganizationService constructor.
...public OrganizationService {private CMSService service;public OrganizationService(CMSService service) {this.service = service;}//methods that use the CMSService interface...}
Both services are then registered in the manager service that will resolve the dependencies during theinstantiationprocess. The implementation of the CMSService can be replaced at runtime by another one while still ensuring thatthe whole tree ofdependencies will be resolved again. Our CMS implementation - using AspectJ - could be hot replacedby a JBossAOP implementation at runtime, without changing a single line code in theOrganizationServiceclass. The newly deployed service only needs to implement the CMSService interface.
Figure 3. The services class diagram

The services are registered in the manager by the service deployer that is application server dependant.To add a service in the container you or the deployer need to provide a ServiceContext object. This classreferences services under the same class loader. Each time a ServiceContext is added to the service manager,the main class loader is updated with the one given by the context, using the usualparent/children class loader paradigm. The Services themselves are described by Services classesthat have been generated by JAXB. The model package on the previous class diagram is the generated one.The scheme used to create the Java classes goes as follows:
Figure 4. The eXo services scheme

The deployer uses the associated XML files with JAXB in order to unmarshall the file and to populate the Javaobjects. The exo services have to be packaged in an Exo Services (.es) archive and deployed under theservice-deploy/ directory. The exo-services.xml file has to be located under the META-INF/ directoryof the archive.
OrganizationExoServiceOrganization service based on Hibernateexo.portal.services.organization.hibernate.Service
Thus, when the deployer - which is scanning the service-deploy/ directory - finds a new .es jar, itdeploys it : the exo-services.xml file is then unmarshalled and the resulting object is put into theServiceContext with theassociated class loader. Then the manager rebuilds the object tree with the correct dependencies.
CMS AOP
The ExoCMS module is a content management module, that will implement JSR 170 as soon as it isavailable. This module is based on the composite design pattern which is described in the famousGang of Four(GoF) book.
Figure 5. The composite design pattern

The ExoCMS module can be seen as a low level content management framework. In short, it provides ahierarchy organization of binary objects that can be stored in any database or a file systemwith a small and easy amount of code to implement for each storage system. In other words, to storeXML documents, a native XML database can be used (eXist or Software AG‘s Tamino) while objects can bestored either in a relational database (using blogs) or in an object database.Each component may be either a node or a leaf. In the case of the eXo CMS, the directories can beseen as nodes while the files in those directories are the leaves. We have recreated an index tablethat is placed in memory and stored in a relational database with all the object metadata.The object leaves are loaded into memory from the custom persistence storage system and then cached with thefile system table. Therefore the node does not directly reference its children orits parent, as in usual Java trees, but indirectly references them using a string URI with the samesyntax conventions as the Unix file system.
Figure 6. The composite design pattern in the eXo case

Why the composite pattern?We used this pattern because we wanted to have a unique repository for all types of content and to provide thedeveloper with a small set of powerful interfaces and extensible capabilities. Combiningthis pattern with aspect oriented programming (Aspectj), the eXo CMS offers all the features of a contentmanagement system such as caching, versioning, locking, indexing and searching. For indexing, we use theLucene engine and for caching the Apache JCS project. Thus the client can access,add, remove and modify any content object in the repository via getNodeByUri() , addChild(),removeChild(), appendChild() and getParentNode().
The following AspectJ code shows two methods as well as the constructor of one of the ObjectNode aspects:the JDBCPersistentAspect. This aspect saves the object‘s metadata in arelational database, delegatesthe saving of the object itself to the ObjectNode.setNodeContent() method and caches the result inmemory. It uses the JCS cache library from the Jakarta project as well as a JDBCHelperobject. The constructor instantiates both the cache and the jdbc object helpers. The methods arethe ObjectNode.appendChild(ObjectNode) and ObjectNode ObjectNode.save(). The ObjectNode class has thegetUri() method that is the key used to cache the object. A syntax similar to the Unix filesystem is used:newChildUri = parentUri + "/" + newChild.getLocalName() to create a child uri ;
aspect JDBCPersistentAspect {private JCS jcsCache_ ;private JDBCHelper jdbcHelper_ ;public JDBCPersistentInterceptor() throws Exception {JCS.setConfigFilename("/exo/content/aop/common/cache.ccf") ;jcsCache_ = JCS.getInstance( "ExoCms" );jdbcHelper_ = new JDBCHelper() ;}ObjectNode around(ObjectNode parentNode, ObjectNode newChild) :target(parentNode) && call(ObjectNodeObjectNode.appendChild(ObjectNode))&& args(newChild){try {String parentUri = parentNode.getUri() ;if (parentUri == null || parentUri.charAt(0) != ‘/‘) {throw new Exception ("parent node need to save first") ;}if ("/".equals(parentUri)) {parentUri = "" ;}String uri = parentUri + "/" + newChild.getLocalName() ;newChild.setUri(uri) ;newChild.setParentUri(parentNode.getUri()) ;newChild = jdbcHelper_.saveNode(newChild);jcsCache_.put( uri , newChild ) ;return newChild ;} catch (Exception ex) {ex.printStackTrace() ;throw new SoftException (ex) ;}}ObjectNode around(ObjectNode node) :target(node) && call(ObjectNode ObjectNode.save()){try {if (node.getUri() == null ) {throw new Exception ("Node is new , use appendchild instead") ;}node = jdbcHelper_.saveNode(node);jcsCache_.put(node.getUri() , node) ;return node ;} catch (Exception ex) {throw new SoftException (ex) ;}}[...]}
Why another CMS?Before our decision to write the ExoCMS module, we spent a lot of time doingresearche on the Jakarta-slide project. We even wrote a jetspeed portlet that could access the slidekernel, allowing you to modify/update the content of the slide repository.Despite the fact that Slide is undoubtedly a good project, it has a number of drawbacks such asits slow implementation speed and poor documentation. Moreover, the laststable release, 1.0.16, dates from Nov 2001.
This module is wrapped in a service that is accessed by the PortletContainer as well as by the Portal. Most of the persistence issues have been resolved using this modulebut it could be easily replaced by a custom persistence implementation.
Portlet Container
This eXo platform component can be used by any Portal provider. Its goal is to manage the portletlifecycle as well as to interact with JSR 168 compatible portlets. The portlet container interacts with theCMS module in order to implement the persistent part required in the portlet API specifications. The module isbased on thePico Container so as to manage the lifecycle and the lazy instantiation.The eXo portlet container competes with the JSR 168 reference implementation, Pluto, provided by IBM.
The design of the container is simple. The ExoPortletContainerFacade, an implementationof the Facade design pattern, is the main entry point to the container. The deployers registerPortletApplicationProxy objects using the addPortletApplication(PortletApplicationProxy) method.The equivalentremove method must be called when the portlet application is undeployed. The facade referencesan aggregation of PortletApplicationProxy objects. When the application is registered, the facade willcall the protected methods of the application proxy to load, register and instantiate the portlets.The Pico Container is used underneath to provide instantiation facilities as well as the incominglaziness support. The next sequence diagram focuses on the init phase.
Figure 7. The eXo Portlet Container init sequence diagram

The PortletApplicationProxy object is created by the deployer itself and populated with the war classloader, the ServletContext, as well as with the JAXB generated portlet data objects(portlet.xml unmarshalling).Those classes contain the portlet class name, the portlet preferences and a lot of otherinformation as defined in the portlet API specification. The portlets Class object is first loadedusing the war class loader. Then, it is registered in the Pico container. Finally all the objectsin the container (portlets and validators) are instantiated. This part will be improved as soon as lazyinstantiation becomes possible with Pico.
Figure 8. The eXo Portlet Container class diagram
The portal also has to deal with the ExoPortletContainerFacade. In the service provider (spi) package,you can find the Input and the Output objects, used when the portal accesses the facade. Those classesare the argument objects used when the portal calls the processAction() and render() methods.Theportlet API specifications define two phases in the portlet object runtime: action and render.The ActionInput and the RenderInput are the processAction and the render method arguments,while the ActionOutputand the RenderOutput are the outputs, returned to the portal by the methods. When theInput objects are created, they are populated with data, such as the windowId to which the portletaccess is linked, the userId and the user attributes Map. (Note that the windowId is the association ofa Portletand a PortletPreferences object, as defined in the spec). The output objects,returned to the portal, contain all the information needed to render and save the state of the portlet.
Figure 9. The Input and Output objects class diagram
The portletAPIImp package contains the implementation of all the objects defined in the portlet APIspecification. Most of the objects are placed in a pool (we use the Jakarta common pool utility for that)as they have a request time lifecycle. This is the case for the PortletSessionImp, the ActionRequestImp,the ActionResponseImp, the RenderRequestImp, the RenderResponseImp and of all the other ServletRequest andServletResponse custom wrappers we use. The package also contains the PersistenceManager interfaceand its CMS implementation. This interface allows the portlet container to delegate the storage ofPortletPreferences objects (remember that each portlet has a PortletPreference object that is definedper user window id) and to get back to the stored info when the user portlet is used again. Note thatthe object caching has to be managed by the persistence engine as is the case in our CMSimplementation. Finally, the package contains the tag subpackage where all the required tags areimplemented.
public interface PersistenceManager {public void storePreferences(String userId, String windowId,PortletPreferencesImp prefs)throws java.io.IOException;public PortletWindowInternal getWindow(String userId, String windowId);}
Many required parts of the portlet API specification have been implemented using AOP and AspectJ.However, as portlets are hot deployed, the weaving of aspects has to be done at runtime.Therefore we use a custom class loader in order to load portlet classes, which allows us to useAspectJ and to add the byte code modified portlet classes to thePico container.
Figure 10. The Portlet Aspects

The monitor aspect is used to monitor the number of times the portlet is reached, so as to manage the memory and to decide which portlet to remove.
The exception handling aspect manages the UnavailableExceptions defined in the portlet API. These exceptions can contain a time period during which the portlet can not be called any more. If this time period is not due, the aspect will not call the next one.
The security aspect uses the incoming PortletRequest to compare the roles of the Principal, that is calling, to the roles required (and defined in the portlet.xml) in order to access the Portlet object. The main authentication is provided by the portal. The aspect only leverages the J2EE declarative security methods that can be accessed using the ServletRequest.
The cache aspect is rather self explanatory. It caches the rendering and the title of the portlet so that the portlet object is not reached each time. This content is unique per user and so is the cache.
The last aspect manages portlet filters. This feature is not part of the portlet API but it may be so in the next versions. As we thought it was a great functionality, we provided it. It works exactly in the same way as servlet filters.
Portal
Our portal is based on Java Server Faces(JSR-127), which is a new web framework paradigm. It provides areal MVC reference architecture allowing developers to deal with components and events on the web layeralmost in the same way as they would with rich Swing clients. The portal interacts with the container,described above, in order to get the portlet contents and to retrieve users‘ preferences from the CMS AOP.
JavaServer Faces allows you to build a tree of Java objects thatdescribes the components of a page. This tree is walked through severaltimes during the request lifecycle before the last phase - therendering phase - is accessed. We will not get into the details ofthese phases but we will describe some interesting features they offer.The tree components are associated with renderers that create theoutput mark-up language. These components can also create events to bedelegated to Action listener objects. For example, the UIPage componentcreates an event when the user clicks on a toolbar link. ThisActionEvent object is created when the decode() method of the componentrenderer is called. The UIPage that has been selected by the user isplaced in the event.
public void decode(FacesContext facesContext, UIComponent uiComponent)throws IOException {UIPage uiPage = (UIPage) uiComponent ;HttpServletRequest request = (HttpServletRequest)facesContext.getServletRequest();String portalAction = request.getParameter("portalAction");if (portalAction != null && "changePage".equals(portalAction)) {String pageId = request.getParameter("pageId") ;if (pageId.equals(uiPage.getId())) {ActionEvent event = new ActionEvent(uiComponent, portalAction);facesContext.addFacesEvent(event);}}}
In the ActionListener processAction() method, the event is processed. In the above example, the listenerwill go through all the children of UIPortalPages that are the "brothers" of the UIPage given with theevent. Only the page selected by the user will be marked as such. When the rendering phase occurs,only the selected page is rendered.
public void processAction(ActionEvent action)throws AbortProcessingException {UIPage uiPage = (UIPage)action.getComponent();UIPortalPages uiPortalPages = (UIPortalPages) uiPage.getParent() ;Iterator i = uiPortalPages.getChildren() ;while (i.hasNext()) {UIPage child = (UIPage) i.next() ;child.setSelectedPage(false) ;}uiPage.setSelectedPage(true) ;}
Figure 11. Components in a page

Our portal page includes several components that are used to build the JSF tree :
UIPortalPages : This is the root component. It references an aggregation of UIPortal objects.
UIPage : a page is what can be seen on the portal screen. The user can choose the page using the toolbar. Each page is composed of several main columns.
UIMainColumn :The user can - using the customized portlet - define the width of the column as well as the style and the Renderer to use.
UITab : To allow a high level of document sorting, each MainColumn can contain several Tabs, as this is the case in the News page of the online demo. Each tab can be split into several columns.
UIColumn : the user can also define the width of those second level columns. These columns contain the portlets.
UIPortlet : finally, the UIPortlet keeps the state and the mode info. This object can be seen as a proxy to the real javax.portlet.Portlet object. It interacts with the portlet container using the ExoPortletContainerFacade singleton. It builds the Input objects and gets the Output objects in return so as to update its state.
Figure 12. The JSF eXo tree components class diagram
The security model is based on J2EE declarative security. In the web.xml file, you define anexo-domain and the URL it should map to:
FORMexo-domain/login.jsp/login.jspuser authentication/faces/private/*POSTGETuserNONE
The /faces/private/* URL requires the user to be authenticated and authorised to be viewed (he needs the "user" role). If a request to the URL is made by a user whose security context (association of Principaland credentials objects) has not been created yet, then the login.jsp page is accessed. A form with thelogin and the password will have to be filled by the user. This information is then compared with thebackend system (databases, LDAP directory...). A logged-in user can tell which part of the JSF tree hewants to make public. If anyone uses public instead of private in the URL associated with a usersite, he will be allowed to access this public information (like an enhanced weblog).
Let‘s look at an example. When you access the site for the first time, the URL is:http://server:port/exo/faces/public/layout/blue-lagoon/portal.jsp. This simply means that you accessthe anonymous user public pages. If you have the correct password for the anonymous user, you willbe able to set the main site layout, style and portlets. While you are logged in as the anonymous userthe URL is: http://server:port/exo/faces/private/layout/blue-lagoon/portal.jsp. If you register a newuser, let‘s say toto, and you log in with this user, the URL ishttp://server:port/exo/faces/private/layout/blue-lagoon/portal.jsp again.This time, using the customizer‘s portlet, you can choose to let other users view some pages from your sitewith the public/private keywords in the GUI tool. Once you have saved this new configuration, other usersonly need to point to the URL http://server:port/exo/faces/public/layout/blue-lagoon/portal.jsp?user=tototo view your public pages. Finally, the admin user can choose any of those user public pages to be themain site. In other words, with one eXo platform, you can build many custom dynamic websites.This entire mechanism is based on servlet filters that we add using the"url-mapping" tag in the web.xml file of the exo.war archive.
The eXo portlet framework
The eXo portlet framework helps portlet developers to build portlet applications. It is a framework à la Strutsbut with a portlet specific design. It offers to portlet developers the possibility to manage all action mappingsof all portlet modes in a single XML file. The latter also includes exception handling and dynamic action classes.The framework is also a full IoC framework, which allows Action classes to use services that have not been createdby theclasses themselves. If you are familiar with struts and the Model View Controller (MVC) type 2, the learningcurve will be really small.
The best practices established for Servlet/JSP programming also applyto portlet development. The MVC model is still accurate, taking the portlet as the controller, some JavaBeansas the model and the jsp as the view. Struts is the best example of such an architecture in the web world.
Figure 13. The MVC paradigm

In the portlet scope, the portlet acts as the controller. Whether inside the portlet or using a helper,the controller creates the model object - JavaBeans - via access to the Enterprise Information System(an EJB layer, any database or ERP...). The portlet then dispatches the request to the correct view.The jsp page takes the previously created object and uses it to render the output mark-up language.The next section introduces our own MVC portlet framework that highly reduces portlet developmenttime. It is inspired from Struts, so any Struts developer should be familiar with it.
You map a Controller class to a portlet in the portlet.xml file using the exo.portal.portlet.ExoPortletFrameworkportlet.
Hello FrameworkHelloPortletFrameworkFrameworkexo.portal.portlet.ExoPortletFrameworkPortlet Controllercontroller-urlcontrollers.xmljsp files locationtemplate-location/WEB-INF/templates/html/[...]
In the controllers.xml file you bind incoming action parameters to ActionHandler classes. If the business logicfrom the class does not throw any exception, the request is redirected to the jsp defined in the controllers.xmlfile; otherwise, another error.jsp file is used. The DynamicAction class is provided to redirect the request to thejsp page, without doing anything in the ActionHandler class.
Hello Portlet FrameworkHello Portlet FrameworkShowHelloWorldHelloHelpModeHelloEditMode
As there are several modes that can be supported by a portlet (VIEW, HELP and EDIT), there are also severalblocks in the controller that define specific actions within each mode. Each mode controller defines a defaultaction that is used when no action parameter is provided (nothing has been added to the portlet request).This happens, for example, when the portlet is first executed. The action parameter dispatches the request toan action class. The latter must extend the ActionHandler class.
Here is an exmple of the code you can find in an ActionHandler class. As the ActionHandler is a componentof the IoC service container, it can use services without instantiating them itself; it only has to get them fromthe constructor as required by the Pico Container.
package framework ;import javax.portlet.ActionRequest ;import javax.portlet.PortletContext ;import exo.portal.portlet.actions.ActionHandler ;public class HelloAction extends ActionHandler {private DumbService dumbService;public HelloAction(DumbService service){this.dumbService = service;}public void init() throws Exception {}public void execute(PortletContext context, ActionRequest request)throws Exception {String name = request.getParameter("name");request.setAttribute("name", name) ;service.dumbMethod();}}
When a portlet with ActionHandlers or a service is redeployed, the whole new dependencies object is resolved.The portlet can then use - at runtime and without any changes in its code - this newly deployed service.
Figure 14. The JSF eXo portlet framework class diagram

The eXo portlets
Finally, we provide a bunch of portlets that can be classified in several categories :
Core portlets
Without those portlets, the portal would be useless. It includes all the administration portlets such asregistration, login/logout, monitors, the layout customization portlet andthe edit portlet (called FilePortlet) that allows identified users to create the content of the portletsusing a“What You See Is What You Get” editor (WYSIWYG). The created document is then savedin the CMS directory. In the enterprise distribution, the workflow is accessible through portlets. Allthose portlets have been built using the eXo portlet framework.
Technology wrappers portlets
One of the big advantages of the portlet API is that it allows you touse several technologies within the portlets even if the portal itselfis built upon some other technology (such as JSF for eXo). Thus, weprovide technology specific portlets like Velocity, Cocoon and JSF.There is also an IFrame portlet that allows you to include another webapplication in the portal, making it possible to use PHP, ASP or CGIapplications in portlets.
Basic JSR 168 portlets
These portlets, such as the Sun samples or the calendar, canbe added or removed simply from the eXo portal. As the API is a standard, the portlets market may growconsiderably. It may be possible to buy portlets to connect to Enterprise Resource Planning (ERP),Supply Chain Management (SCM) or CRM software, which would work in the same way as if the portletswere deployedon the Weblogic portal or the eXo portal. We will probably see many portlet applications in the coming years,both commercial and free ones.
Figure 15. A summary

Conclusion
We hope that you‘ve grasped the big picture of the eXo platform,which was built upon a service micro-kernel to be as "agile" aspossible. We encourage you to download the sources, play withthem and to join us; there is still much work to do in many areas.
We‘ve tried to introduce most of the aspects of the project‘sarchitecture, but some modules - like the enhanced communications toolsand the workflow integration - have been left for further articles andtutorials.
Resources
[1] UML is a graphical modelling language. More information can be found on theOMG site. We also recommand Allen Holub‘sUML documentation
download:http://sourceforge.net/project/showfiles.php?group_id=62218
project:http://www.exoportal.org/
sourceforge page:http://www.sourceforge.net/projects/exo
last discussion thread:/news/thread.tss?thread_id=21102
About the Authors
Benjamin Mestrallet is a French computer science engineer andhas a DEA in Management Science from the University of Paris IXDauphine. He is currently doing research on "Object and AspectModelisation of operational Business Processes". He founded the eXoproject in late 2002 and released the first source code in December2002.
Tuan Nguyen is a Java developer who graduated with a bachelor‘sdegree in 2000 from Concordia University, Montreal, Canada. From 2000to 2002 , he worked for Azerity Inc in Silicon Valley. In early 2003,he went back to Canada and worked as an independant consultant. Hejoined Exo Team in May 2003.
The eXo kernel (CMS, portlet container, portal and some coreportlets) is distributed under the GNU/GPL licence. The Portletframework as well as the Services container and some non-core portletsare distributed under the GNU/LGPL licence. Therefore, compagnies whowould like to bundle the eXo platform with their application musteither distribute their code under the GNU/GPL licence (copyleft) orcontact the eXo develoment team to create a custom licence. The eXodevelopment team also provides customized - business specific -portlets and business processes development, as well as consulting andsupport on the platform integration.