Thursday, September 18, 2008

Facets FAQ : Supporting modular runtimes

This is the first entry in a series of posts where I will answer some frequently asked questions about the Faceted Project Framework in Eclipse.

Question: Some application servers such as WebLogic and JBoss are modular in nature. Various components of the server can be selectively present or absent. Further, even if the component is present, a particular configuration of the server might turn that component on or off. So say I have a portal server component and a corresponding facet for enabling tooling related to that portal component. I want the portal facet to only be available for selection if the targeted runtime includes the portal component. How do I set that up?

Answer: Faceted Project Framework models runtimes as made up of one or more runtime components. When you create a facet, you get to declare which runtime components it is supported on. In addition to what's specified explicitly, the facet will have implicit constraints on runtimes based on the dependencies that it declares on other facets.

Let's take the portal example described in the question. A Java application server will typically be modeled as composed of at least two runtime components. One will represent the JRE that the server is running on. The other will represent the base application server with all of its core capabilities. In the portal example, we will want to add a third runtime component to the mix to represent the portal module. Once we do that, we can easily map the portal facet to the portal component and facet will only be shown to the user if the runtime component is present in the runtime.

The following little snippet declares a portal runtime component and maps portal facet (assumed to be already declared) to it.

<extension point="org.eclipse.wst.common.project.facet.core.runtimes">
  <runtime-component-type id="sample-portal-component"/>
  <runtime-component-version type="sample-portal-component" version="1.0"/>
  <supported>
    <runtime-component id="sample-portal-component" version="1.0"/>
    <facet id="sample-portal-facet" version="1.0"/>
  </supported>
</extension>

So how do I add runtime components to my runtime? In WTP there is a bridge that translates runtimes defined using WTP Server Tools API to API that's understood by Faceted Project Framework. The default behavior of the bridge is to create two-component runtimes as described in the previous paragraph, but there is an extension point that lets you add a component provider that will be called when bridge is converting the runtime. Here is how you add declare a component provider:

<extension point="org.eclipse.jst.server.core.internalRuntimeComponentProviders">
  <runtimeComponentProvider
    id="[extension-id]"
    class="[provider-class-name]"
    runtimeTypeIds="[server-tools-runtime-id]"/>
</extension>

Once invoked, the component provider can examine various aspects of the runtime (such as state on disk at the location pointed to by the runtime or settings in the workspace). It can then construct and return the appropriate runtime components that will be merged with components created by the bridge to create a fully-specified runtime definition. Here is a sketch of how such component provider might look like:

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.wst.common.project.facet.core.runtime.IRuntimeComponent;
import org.eclipse.wst.common.project.facet.core.runtime.IRuntimeComponentType;
import org.eclipse.wst.common.project.facet.core.runtime.IRuntimeComponentVersion;
import org.eclipse.wst.common.project.facet.core.runtime.RuntimeManager;
import org.eclipse.wst.server.core.IRuntime;
import org.eclipse.wst.server.core.internal.facets.RuntimeFacetComponentProviderDelegate;

public final class SampleRuntimeComponentProvider extends RuntimeFacetComponentProviderDelegate
{
    private static final IRuntimeComponentType PORTAL_TYPE 
        = RuntimeManager.getRuntimeComponentType( "sample.portal.component" );
    
    private static final IRuntimeComponentVersion PORTAL_VERSION_1 
        = PORTAL_TYPE.getVersion( "1.0" );
    
    public List<IRuntimeComponent> getRuntimeComponents( final IRuntime runtime )
    {
        final File location = runtime.getLocation().toFile();
        final List<IRuntimeComponent> components = new ArrayList<IRuntimeComponent>();
        
        if( isPortalPresent( location ) )
        {
            final IRuntimeComponent portalComponent
                = RuntimeManager.createRuntimeComponent( PORTAL_VERSION_1, null );
            
            components.add( portalComponent );
        }
    }
    
    private static boolean isPortalPresent( final File location )
    {
        return false;  // TODO: Implement the check for portal.
    }
}

5 comments:

Max said...

Great info Konstatin.

The only grudge I have with this is that if I start using this for i.e. JBoss runtimes then other server adapters will not return our runtime component even though our Portal facet can be used with them.

Is there a way to handle this scenario besides letting the portal facet be installable on all (but then runtime components becomes irelevant again ;(

Konstantin Komissarchik said...

So, do you want to be able to add portal module detection logic to other runtimes or are you saying that some runtimes are able to support your portal facet without an extra module on the server side?

Max said...

Yes, some facets can be used on servers without having something installed in the server. Then the runtime jars would just be deployed with the web app.

I guess what I need to do is let the facet check if a certain runtime component is available; if yes it will do the project setup in one way (i.e. not add classpath entries), if not it would do a setup where jars needed to be added to the project.

Makes sense?

nitha said...

Hi,

I have a question regarding facet constraints, am hoping you will be able to help me.

I have a facet A, which needs to be displayed when the constraint is either jst.web or jst.utility. The scenario is facet A should be able to be added to a Web Project or Utiltiy Project.

I tried the or tag [Expr] or tag , but that did not work

Wanted to post the extension segment, but it doesn't allow me to use the tags in comments...


Thanks in advance,
nitha

Vas said...

Hello Konstantin,

Currently i am working on Facet project and trying to develop a mobile facet application that will add a menu option to the project(navigator -> project rootnode) that installs the facet.

I was searching info on net and also on your blog, but could not find a solution. Also i noticed the JPA Facet adding a menu option called "JPA Tools" to the project navigator menu on installation. But not sure how it is done exactly. I have attached an image which shows the menu item added on JPA installation.

Could you please help me with some hints on this!!