Facet扩展点及其使用心得
本次Facet扩展点的学习参照文章“Extending WTP Using Project Facets”。
Facet项目框架提供了一个功能强大扩展WTP的机制,用户可以在创建web项目时添加各种功能模块。当一个Facet添加到项目中后,它可以执行任何必要的操作如:拷贝resources,安装builders,添加natures等,同时Facet也可以用作用户界面元素可用的标志。
自己的理解就是:可以省略开发人员人工的引入jar包,配置xml等操作,通过添加facet直接完成以上工作。
以下以文章中所给实例starter为起点进行学习使用(starter和solution可在文章链接中下载)。
1.添加facet扩展点,配置xml文件
Facet扩展点为org.eclipse.wst.common.project.facet.core.facets
,在插件项目的
plugin.xml
文件中添加此扩展点,并进行配置,如表
1
所示。
<?xml version="1.0" encoding="UTF-8"?> <?eclipse version="3.0"?> <plugin> <extension point="org.eclipse.wst.common.project.facet.core.facets">
<category id="formgen.category"> <label>FormGen</label> <description>Enables generation of HTML forms based on XML definition files.</description> </category>
<project-facet id="formgen.core"> <category>formgen.category</category> <label>FormGen Core</label> <description> Enables generation of HTML forms based on XML definition files. </description> </project-facet>
<project-facet-version facet="formgen.core" version="1.0"> <constraint> <requires facet="jst.web" version="2.2,2.3,2.4"/> </constraint> </project-facet-version>
<project-facet id="formgen.ext"> <category>formgen.category</category> <label>FormGen Extensions</label> <description> Enables additional FormGen widgets. </description> </project-facet>
<project-facet-version facet="formgen.ext" version="1.0"> <constraint> <requires facet="formgen.core" version="1.0"/> </constraint> </project-facet-version> </extension> </plugin> |
表1:plugin.xml文件
***在xml中主要有两个元素,<project-facet>用于声明facet本身,<project-facet-version >声明版本信息。
***再其中,category表示所创建facet所属的类别。
***在project-facet节点下:label内容表示facet显示名称、description内容表示注释。
***在project-facet-version节点下:constraint表示当前facet的约束,在constraint下:requires表示当前facet依赖于其他facet,且可以通过version属性设置所依赖facet的版本要求,也通过soft属性设置在依赖facet不存在时不显示当前facet;另外可以用conflicts指定与当前facet相冲突的facet,conflicts中同样要设置facet、version属性。
完成扩展点的基本设置后,还可以通过其他扩展点对category、facet进行添加图标等操作。如表2所示。
<extension point="org.eclipse.wst.common.project.facet.ui.images"> <image facet="formgen.core" path="icons/formgen-core.gif"/> <image facet="formgen.ext" path="icons/formgen-ext.gif"/> <image category="formgen.category" path="icons/formgen-cat.gif"/> </extension> |
表2:为facet添加图标
通过org.eclipse.wst.common.project.facet.ui.images扩展点添加图标。
运行结果如下图:
错误信息的显示表示对应facet的action没有实现。有三种类型的action:INSTALL
, UNINSTALL
, and VERSION_CHANGE
。此处为
Formgen facet
实现
INSTALL action
。在
xml
中继续添加如下
action
标签的代码。
<extension point="org.eclipse.wst.common.project.facet.core.facets">
<project-facet-version facet="formgen.core" version="1.0"> <action type="INSTALL"> <delegate class="com.formgen.eclipse.FormGenCoreFacetInstallDelegate"/> </action> </project-facet-version>
<project-facet-version facet="formgen.ext" version="1.0"> <action type="INSTALL"> <delegate class="com.formgen.eclipse.FormGenExtFacetInstallDelegate"/> </action> </project-facet-version>
</extension> |
2.facet行为的实现类的创建
Formgen.core facet应该做的事情是:1.将formgen.jar拷贝到WEB-INF/lib目录下。2.在web.xml中添加FormGen servlet的代码。
Formgen-ext.jar应该做的事情是:将formgen-ext.jar拷贝到WEB-INF/lib目录下。
两个java类应该实现的接口是Idelete,详情如下:
package org.eclipse.wst.common.project.facet.core; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; /** * This interface is implemented in order to provide logic associated with * a particular event in project facet's life cycle, such as install or * uninstall. */ public interface IDelegate { /** * The method that's called to execute the delegate. * * @param project the workspace project * @param fv the project facet version that this delegate is handling; this * is useful when sharing the delegate among several versions of the same * project facet or even different project facets * @param config the configuration object, or * should be used * @param monitor the progress monitor * @throws CoreException if the delegate fails for any reason */ void execute( IProject project, IProjectFacetVersion fv, Object config, IProgressMonitor monitor ) throws CoreException; } |
连个类的具体代码如下
package com.formgen.eclipse; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.wst.common.project.facet.core.IDelegate; import org.eclipse.wst.common.project.facet.core.IProjectFacetVersion; public final class FormGenCoreFacetInstallDelegate implements IDelegate { public void execute( final IProject pj, final IProjectFacetVersion fv, final Object config, final IProgressMonitor monitor ) throws CoreException { monitor.beginTask( "", 2 ); try { final IFolder webInfLib = Utils.getWebInfLibDir( pj ); Utils.copyFromPlugin( new Path( "libs/formgen-core.jar" ), webInfLib.getFile( "formgen-core.jar" ) ); monitor.worked( 1 ); Utils.registerFormGenServlet( pj ); monitor.worked( 1 ); } finally { monitor.done(); } } } |
package com.formgen.eclipse; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.wst.common.project.facet.core.IDelegate; import org.eclipse.wst.common.project.facet.core.IProjectFacetVersion; public final class FormGenExtFacetInstallDelegate implements IDelegate { public void execute( final IProject pj, final IProjectFacetVersion fv, final Object config, final IProgressMonitor monitor ) throws CoreException { monitor.beginTask( "", 1 ); try { final IFolder webInfLib = Utils.getWebInfLibDir( pj ); Utils.copyFromPlugin( new Path( "libs/formgen-ext.jar" ), webInfLib.getFile( "formgen-ext.jar" ) ); monitor.worked( 1 ); } finally { monitor.done(); } } } |
完成以上操作试运行得结果如下图:
3.facet行为更深一步的学习:添加向导页
有的时候选中了特定的facet后,可能facet需要收集用户的一些信息来配置具体的情况,实现方法是再添加一个向导页。
此处我们对action重新配置,并添加wizardPages扩展点。具体xml配置如下:
<extension point="org.eclipse.wst.common.project.facet.core.facets"> <project-facet-version facet="formgen.core" version="1.0"> <action type="INSTALL" id="formgen.core.install"> <config-factory class="com.formgen.eclipse.FormGenCoreFacetInstallConfig$Factory"/> </action> </project-facet-version> </extension> <extension point="org.eclipse.wst.common.project.facet.ui.wizardPages"> <wizard-pages action="formgen.core.install"> <page class="com.formgen.eclipse.FormGenCoreFacetInstallPage"/> </wizard-pages> </extension> |
此处要实现的两个接口如下:
package org.eclipse.wst.common.project.facet.core; import org.eclipse.core.runtime.CoreException; /** * This interface is implemented in order to provide a method for creating * a config object that will be used for parameterizing the facet action * delegate. */ public interface IActionConfigFactory { /** * Creates a new facet action configuration object. The new configuration * object should ideally be populated with reasonable defaults. * * @return a new facet action configuration object * @throws CoreException if failed while creating the configuration object */ Object create() throws CoreException; } |
package org.eclipse.wst.common.project.facet.ui; import org.eclipse.jface.wizard.IWizardPage; /** * This interface is implemented by the wizard pages associated with project * facet actions. */ public interface IFacetWizardPage extends IWizardPage { /** * The framework will call this method in order to provide the wizard * context to the wizard page. The wizard context can be used to find out * about other actions being configured by the wizard. * * @param context the wizard context */ void setWizardContext( IWizardContext context ); /** * The framework will call this method in order to provide the action config * object that the wizard page should save user selection into. The * populated config object will then be passed to the action delegate. * * @param config the action config object */ void setConfig( Object config ); /** * This method is called after the user has pressed the * button. It allows the wizard page to transfer user selection into the * config object. Alternative, instead of using this method, the wizard * page could update the model on the fly as the user is making changes. */ void transferStateToConfig(); } |
下边是两个类的具体实现代码:
package com.formgen.eclipse; import org.eclipse.wst.common.project.facet.core.IActionConfigFactory; public final class FormGenCoreFacetInstallConfig { private String urlPattern = "*.form"; public String getUrlPattern() { return this.urlPattern; } public void setUrlPattern( final String urlPattern ) { this.urlPattern = urlPattern; } public static final class Factory implements IActionConfigFactory { public Object create() { return new FormGenCoreFacetInstallConfig(); } } } |
package com.formgen.eclipse; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; import org.eclipse.wst.common.project.facet.ui.AbstractFacetWizardPage; public final class FormGenCoreFacetInstallPage extends AbstractFacetWizardPage { private FormGenCoreFacetInstallConfig config; private Text urlPatternTextField; public FormGenCoreFacetInstallPage() { super( "formgen.core.facet.install.page" ); setTitle( "FormGen Core" ); setDescription( "Configure the FormGen servlet." ); } public void createControl( final Composite parent ) { final Composite composite = new Composite( parent, SWT.NONE ); composite.setLayout( new GridLayout( 1, false ) ); final Label label = new Label( composite, SWT.NONE ); label.setLayoutData( gdhfill() ); label.setText( "URL Pattern:" ); this.urlPatternTextField = new Text( composite, SWT.BORDER ); this.urlPatternTextField.setLayoutData( gdhfill() ); this.urlPatternTextField.setText( this.config.getUrlPattern() ); setControl( composite ); } public void setConfig( final Object config ) { this.config = (FormGenCoreFacetInstallConfig) config; } public void transferStateToConfig() { this.config.setUrlPattern( this.urlPatternTextField.getText() ); } private static GridData gdhfill() { return new GridData( GridData.FILL_HORIZONTAL ); } } |
同时要修改FormGenCoreFacetInstallDelegate类:如下
package com.formgen.eclipse; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.wst.common.project.facet.core.IDelegate; import org.eclipse.wst.common.project.facet.core.IProjectFacetVersion; public final class FormGenCoreFacetInstallDelegate implements IDelegate { public void execute( final IProject pj, final IProjectFacetVersion fv, final Object config, final IProgressMonitor monitor ) throws CoreException { monitor.beginTask( "", 2 ); try { final FormGenCoreFacetInstallConfig cfg = (FormGenCoreFacetInstallConfig) config; final IFolder webInfLib = Utils.getWebInfLibDir( pj ); Utils.copyFromPlugin( new Path( "libs/formgen-core.jar" ), webInfLib.getFile( "formgen-core.jar" ) ); monitor.worked( 1 ); Utils.registerFormGenServlet( pj, cfg.getUrlPattern() ); monitor.worked( 1 ); } finally { monitor.done(); } } } |
完成以上操作后,多出来的一个wizard page如下:
4.facet行为更深一步的学习:定义预设
如果有多个facet,对于用户来说一个个的进行选择可能会很麻烦,一个好的方法是实现一个Preset,帮助用户免去挨个选择facet的烦恼。
下面根据前面的实现,为FormGen实现一个Preset。Xml中实现如下扩展点:
<extension point="org.eclipse.wst.common.project.facet.core.facets"> <preset id="formgen.preset"> <label>FormGen Web Project</label> <description>Creates a web project with FormGen functionality.</description> <facet id="jst.java" version="5.0"/> <facet id="jst.web" version="2.2"/> <facet id="formgen.core" version="1.0"/> <facet id="formgen.ext" version="1.0"/> </preset> </extension> |
运行结果如下图:
此外,还可以通过扩展点指定facet的运行环境,添加形式如下:
<extension point="org.eclipse.wst.common.project.facet.core.runtimes"> <supported> (0 or more) <runtime-component any="{boolean}"/> (optional) <runtime-component id="{string}"/ version="{version.expr}"/> (0 or more) <facet id="{string}"/ version="{version.expr}"/> (1 or more) </supported> </extension> |
以下是实际添加的两个例子,一个是在任意环境下,另一个是在Tomcat下,具体配置代码如下:
<extension point="org.eclipse.wst.common.project.facet.core.runtimes"> <supported> <runtime-component any="true"/> <facet id="formgen.core"/> <facet id="formgen.ext"/> </supported> </extension> |
<extension point="org.eclipse.wst.common.project.facet.core.runtimes"> <supported> <runtime-component id="org.eclipse.jst.server.tomcat" version="[5.0"/> <facet id="formgen.core"/> <facet id="formgen.ext"/> </supported> </extension> |