Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3

This document outlines the work that is underway to extend the Eclipse Web Tools Platform so that it can offer support for JBI components.   In order to understand a little about the process we'll walk through the steps involved in added adding a new module type,   creating a server definition and then ultimately adding the a new project type and deployables.

Its It is a work in progress,   but hopefully by seeing the process of adding the extension we help feed innovation around WTP and JBI.

OK.. Lets start at the begining, we will basically create three plug-in projects,   these will be for the server definition,   the UI components of JBI and the JBI core components (which will cover creating deployables).

We will start in the UI project,   and do our first big step: we will declare a new type of module.   In our case this will be a jst.jbi.component (though obviously we could create a new module type for other things ie a BPEL module).

...

Also note that we provide a template, this can be used in the wizard to show the default facets, in our case we wanted only that the java facet be there.

Before diving into the Java code for these classes there are two more extension point that we want to add first:

Code Block
xml
xml

<extension point="org.eclipse.ui.newWizards">
		<category name="%jbi.category"
			id="org.eclipse.jst.jbi.ui">
		</category>
		<wizard name="%jbi.component.project.name" icon="/icons/jbi-component.gif"
			category="org.eclipse.jst.jbi.ui"
			class="org.eclipse.jst.jbi.ui.project.facet.JbiProjectWizard"
			project="true"
			finalPerspective="org.eclipse.jdt.internal.ui.JavaHierarchyPerspectiveFactory"
			id="org.eclipse.jst.jbi.ui.project.facet.JbiProjectWizard">
			<description>%jbi.component.project.description</description>
		</wizard>
	</extension>

	<extension point="org.eclipse.wst.common.project.facet.ui.wizard">
		<wizard-pages facet="jst.jbi.component" version="1.0">
			<install>
				<page
					class="org.eclipse.jst.jbi.ui.project.facet.JbiFacetInstallPage" />
			</install>
		</wizard-pages>
	</extension>

These are used to first define our new JBI project wizard and then to define the install page for our JBI facet, since we are leveraging the WST/JST we will be able to re-use much of their infrastructure to get us a little closer.

OK... lets get started with the new project wizard, we can re-use much of the JEE stuff that those busy people on WTP have done (thanks!!). For our new project wizard we can extend NewProjectDataModelFacetWizard.

Code Block
java
java

public class JbiProjectWizard extends NewProjectDataModelFacetWizard {

	public JbiProjectWizard(IDataModel model) {
		super(model);
		setWindowTitle(JBIUIMessages.KEY_1);
	}

	public JbiProjectWizard() {
		super();
		setWindowTitle(JBIUIMessages.KEY_1);
	}

	protected IDataModel createDataModel() {
		return DataModelFactory
				.createDataModel(new JbiFacetProjectCreationDataModelProvider());
	}

	protected IFacetedProjectTemplate getTemplate() {
		return ProjectFacetsManager.getTemplate("template.jst.jbi.component"); //$NON-NLS-1$
	}

	protected IWizardPage createFirstPage() {
		return new JbiProjectFirstPage(model, "first.page"); //$NON-NLS-1$
	}

	protected ImageDescriptor getDefaultPageImageDescriptor() {
		final Bundle bundle = Platform.getBundle(Activator.PLUGIN_ID); //$NON-NLS-1$
		final URL url = bundle.getEntry("icons/jbi-component.gif"); //$NON-NLS-1$
		return ImageDescriptor.createFromURL(url);
	}

}

In the example new project wixard we see the use of an IDataModel, basically this is a holder for the parameters that we want to gather during the set-up of the project. Our implementation re-uses much of the WTP facet stuff by extending FacetProjectCreationDataModelProvider.

Code Block
java
java

public class JbiFacetProjectCreationDataModelProvider extends
		FacetProjectCreationDataModelProvider {

	public void init() {
		super.init();
		FacetDataModelMap map = (FacetDataModelMap) getProperty(FACET_DM_MAP);
		IDataModel javaFacet = DataModelFactory
				.createDataModel(new JavaFacetInstallDataModelProvider());
		map.add(javaFacet);
		IDataModel jbiFacet = DataModelFactory
				.createDataModel(new JbiFacetInstallDataModelProvider());
		map.add(jbiFacet);
		javaFacet
				.setProperty(
						IJavaFacetInstallDataModelProperties.SOURCE_FOLDER_NAME,
						jbiFacet
								.getStringProperty(IJbiFacetInstallDataModelProperties.JAVA_SOURCE_FOLDER));
	}
}

Note that we use the provide to get the facet data model map which we can use to all add the new Java data model provider and our JbiFacet install data model provider. These act to provide information about the parameters that you need to gather. A quick look at the JbiFacetInstallDataModelProvider gives you the idea.

Code Block
java
java

public class JbiFacetInstallDataModelProvider extends
		J2EEModuleFacetInstallDataModelProvider {

	private static final String JBI_V1_0 = "1.0";

	private static final String JBI_PROJECT_FACET = "jst.jbi.component";

	public static final IProjectFacetVersion JBI_10 = ProjectFacetsManager
			.getProjectFacet(JBI_PROJECT_FACET).getVersion(JBI_V1_0); //$NON-NLS-1$

	public Set getPropertyNames() {
		Set names = super.getPropertyNames();
		names.add(CONFIG_FOLDER);
		names.add(IJbiFacetInstallDataModelProperties.JAVA_SOURCE_FOLDER);
		return names;
	}

	public Object getDefaultProperty(String propertyName) {
		if (propertyName.equals(FACET_ID)) {
			return JBI_PROJECT_FACET;
		} else if (propertyName.equals(CONFIG_FOLDER)) {
			return "src/main/resources";
		} else if (propertyName
				.equals(IJbiFacetInstallDataModelProperties.JAVA_SOURCE_FOLDER)) {
			return "src/main/java";
		}
		return super.getDefaultProperty(propertyName);
	}

	protected int convertFacetVersionToJ2EEVersion(IProjectFacetVersion version) {
		return J2EEVersionConstants.J2EE_1_4_ID;
	}

	public boolean isPropertyEnabled(String propertyName) {
		return super.isPropertyEnabled(propertyName);
	}

	public boolean propertySet(String propertyName, Object propertyValue) {
		boolean status = false;
		status = super.propertySet(propertyName, propertyValue);
		return status;
	}

	public IStatus validate(String propertyName) {
		return OK_STATUS;
	}

}

The wizard code is simply to build a module, however since the facet we are adding has a runtime available you suddenly get the runtimes available in the wizard. Also remember the install delegate we had at the begining, well we have use that to determine whether a runtime was assigned and reference it if it was.

Code Block
java
java

public class JbiFacetInstallDelegate extends J2EEFacetInstallDelegate implements
		IDelegate {

	public void execute(IProject project, IProjectFacetVersion fv,
			Object config, IProgressMonitor monitor) throws CoreException {
		if (monitor != null) {
			monitor.beginTask("Installing JBI facet", 1);
		}

		try {
			IDataModel model = (IDataModel) config;

			final IJavaProject jproj = JavaCore.create(project);

			// Add WTP natures.
			WtpUtils.addNatures(project);

			// Setup the flexible project structure.
			final IVirtualComponent c = ComponentCore.createComponent(project);
			c.create(0, null);
			c.setMetaProperty("java-output-path", "/build/classes/");

			final IVirtualFolder jbiRoot = c.getRootFolder();

			// Create directory structure
			String srcFolder = null;
			srcFolder = model
					.getStringProperty(IJbiFacetInstallDataModelProperties.JAVA_SOURCE_FOLDER);
			jbiRoot.createLink(new Path("/" + srcFolder), 0, null);
			String resourcesFolder = model
					.getStringProperty(IJbiFacetInstallDataModelProperties.CONFIG_FOLDER);
			jbiRoot.createLink(new Path("/" + resourcesFolder), 0, null);

			// Look ma a runtime!!!!
			IRuntime runtime = (IRuntime) model
					.getProperty(IJbiFacetInstallDataModelProperties.FACET_RUNTIME);
			....
			if (monitor != null) {
				monitor.worked(1);
			}
		}

		finally {
			if (monitor != null) {
				monitor.done();
			}
		}

	}
}

As you can imagine this means that information from your runtime can be used to set up special stuff in the project, such as adding the runtime's project classpath to the project. OK... lets see all that in action

So now we have a server/runtime that we have added, a type of module and a new project and facet that allows a project to be associated with that facet and thus the runtime/server. OK, the final bit we need to think about is how do we make it so that we can add a project to the server (not just associate it with the runtime and publish the project to that server). Now this is still in development, but I'll put up what we have right now so you get the flavour of it all (smile)

You need to implement three extension points, these basically tell WTP that your project can create a deployable artifact that it is based on a project and that it is associated with the jst.jbi.component module type.

Code Block
xml
xml

<extension point="org.eclipse.wst.server.core.moduleFactories">
		<moduleFactory projects="true"
			class="org.eclipse.jst.jbi.internal.deployables.JBIComponentDeployableFactory"
			id="org.eclipse.jst.jbi.deployables.component">
			<moduleType versions="1.0" types="jst.jbi.component"/>
		</moduleFactory>
	</extension>

	<extension
		point="org.eclipse.wst.server.core.moduleArtifactAdapters">
		<moduleArtifactAdapter
			id="org.eclipse.jst.jbi.component"
			class="org.eclipse.jst.jbt.internal.deployables.JBIComponentDeployableObjectAdapter">
			<enablement>
				<with variable="selection">
					<adapt type="org.eclipse.core.resources.IProject" />
				</with>
			</enablement>
		</moduleArtifactAdapter>
	</extension>

	<extension point="org.eclipse.core.runtime.adapters">
		<factory
			class="org.eclipse.jst.jbi.internal.deployables.JBIComponentDeployableObjectAdapter"
			adaptableType="org.eclipse.core.resources.IProject">
			<adapter
				type="org.eclipse.jst.jbi.internal.deployables.IJBIComponentArtifact" />
		</factory>
	</extension>

Lets start by looking at the JBIComponentDeployableFactory, its job is to determine if a project can be deployed, and to create a module delegate that will actually perform the preparation, remember it is actually the server that does the publishing, our JBIComponentDeployable is passed to the publishing part of the server definition (in our case the generic ant task) to publish to the server.

Code Block
java
java

public class JBIComponentDeployable extends ComponentDeployable {

	public JBIComponentDeployable(IProject project, IVirtualComponent component) {
		super(project);
	}

	public String getContextRoot() {
		Properties props = component.getMetaProperties();
		if (props.containsKey("context-root")) //$NON-NLS-1$
			return props.getProperty("context-root"); //$NON-NLS-1$
		return component.getName();
	}

	public String getURI(IModule module) {
		IVirtualComponent comp = ComponentCore.createComponent(module
				.getProject());
		String aURI = null;
		if (comp != null) {
			if (!comp.isBinary()
					&& isProjectOfType(module.getProject(), "jst.jbi.component")) {
				IVirtualReference ref = component.getReference(comp.getName());
				aURI = ref.getRuntimePath().append(
						comp.getName() + "-installer.jar").toString(); //$NON-NLS-1$
			}
		}

		if (aURI != null && aURI.length() > 1 && aURI.startsWith("/")) //$NON-NLS-1$
			aURI = aURI.substring(1);
		return aURI;
	}

	public String getVersion() {
		IFacetedProject facetedProject = null;
		try {
			facetedProject = ProjectFacetsManager
					.create(component.getProject());
			if (facetedProject != null
					&& ProjectFacetsManager.isProjectFacetDefined("jst.jbi.component")) {
				IProjectFacet projectFacet = ProjectFacetsManager
						.getProjectFacet("jst.jbi.component");
				return facetedProject.getInstalledVersion(projectFacet)
						.getVersionString();
			}
		} catch (Exception e) {
			// Ignore
		}
		return "1.0"; //$NON-NLS-1$
	}
}

Note that this document will continue to discuss how the IProject is converted through the adaptable pattern into a JbiComponent in the next few days. In the meantime I'll leave you with a little demonstration of how a deployable projects looks.