这个文章基本是"Building Project Facets"的中文版
在WTP中创建Dynamic Web Project工程的时候提供了Project Facets的功能,它让用户在创建web项目的时候,可以像搭积木一下给我们创建的project添加各种功能模块,下面我们通过一个例子来讲解一下WTP中的Project Facets的用法
通常我们给创建的工程可能添加以下元素:资源文件, Builder, Nature标识等, 我们知道Eclipse本身提供了一个Nature的功能,但是Facets跟Nature是有区别的, 给工程添加Nature是用来给Eclipse底层的工具使用的,而Facets是用来给最终用户使用的, 通常Facets提供的模块都是自描述的,这样可以保证用户在使用的时候,避免添加不必要的Facet模块, 而且对于我们开发者而言也避免了在新建向导中插入新的wizard page以及避免通过右键菜单来给工程添加或者去掉某模块,从而大大简化了开发人员的工作量, 因此Facets对用户和开发者来说都是一个不错的选择
下面我们结合一个名为FormGen的实例来介绍, FormGen用来在我们创建的web工程中,加入一些我们自己的jar包以及修改web.xml文件
废话少说,先在插件工程中添加org.eclipse.wst.common.project.facet.core.facets 扩展点, 当然这里需要在依赖中加入org.eclipse.wst.common.project.facet.core引用,该扩展点包罗万象,这里我们遵循循序渐进的原则,从最最简单的内容开始:
xml 代码
- <extension point="org.eclipse.wst.common.project.facet.core.facets">
-
- <project-facet id="{string}"> (0 or more)
- <label>{string}label>
- <description>{string}description> (optional)
- project-facet>
-
- <project-facet-version facet="{string}" version="{string}"/> (0 or more)
-
- extension>
这里加入了两个节点:project-facet是我们要加入的facet, project-facet-version用来制定我们的facet版本, 每一个facet至少需要给它指定一个版本,否则不可用, 后面大家就会知道,实际上我们大部分工作都集中在project-facet-version中配置, 配置后的代码如下:
xml 代码
- <extension point="org.eclipse.wst.common.project.facet.core.facets">
-
- <project-facet id="formgen.core">
- <label>FormGen Corelabel>
- <description>
- Enables generation of HTML forms based on XML definition files.
- description>
- project-facet>
-
- <project-facet-version facet="formgen.core" version="1.0"/>
-
- <project-facet id="formgen.ext">
- <label>FormGen Extensionslabel>
- <description>
- Enables additional FormGen widgets.
- description>
- project-facet>
-
- <project-facet-version facet="formgen.ext" version="1.0"/>
-
- extension>
设置好后运行我们的插件项目,创建一个Dynamic Web Project, 在向导中第一个页面的Target Runtime设置为none,继续进入到下一个页面,这时在下面的列表中就会出现我们添加的两个facet
接下来的工作就是给facet指定约束
由于我们的FormGen是基于Servlet的,因此它应该适用于所有的Java EE项目.下面我们通过增加约束让FormGen facet也能在EJB项目向导中使用.
下面是我们将要用到的扩展节点的相关说明:
xml 代码
- <extension point="org.eclipse.wst.common.project.facet.core.facets">
- <project-facet-version>
- <constraint> (optional)
- [expr]
- constraint>
- project-facet-version>
- extension>
-
- [expr] =
- <requires facet="{string}" version="{version.expr}" soft="{boolean}"/> or
- <conflicts facet="{string}" version="{version.expr}"/> or
- <conflicts group="{string}"/> or
- <and>
- [expr] (1 or more)
- and> or
- <or>
- [expr] (1 or more)
- or>
约束由树状结构的表达式组成, 它包括4个部分,这里我们分别来加以说明:
requires:是用的最多的部分,它表示当前的facet还需要依赖的其他facet, 如果对所依赖的facet没有版本要求,那么不用设置version属性, version可以设置为表达式, soft属性用来创建一种特定类型的依赖,即如果依赖facet不存在,那么当前facet将不会在选项列表中出现,其本facet必须在引用facet之后被安装
conflicts:冲突约束用来制定如果在同一个工程中已经存在了这里指定的facet,那么当前声明的facet将不可用,它用两种形式:可以指定单个冲突或组(group)冲突的facet.对于组冲突,这里需要解释一下, 组冲突用来指定当前的facet与没有在facet列表中列出的某一类facet有冲突,比如说, WTP自己的moudule facet都属于moudules组, 而这些facet在定义的时候,都将组冲突设置为modules, 这样就可以保证两个module不会同时安装在同一个工程中
要让一个facet属于某个组,需要这样定义扩展点:
- <extension point="org.eclipse.wst.common.project.facet.core.facets">
- <project-facet-version>
- <group-member id="{string}"/> (0 or more)
- project-facet-version>
- extension>
and & or 是用来做逻辑判断的,写程序的都知道,这里不做介绍
下面是我们的FormGen的facet定义,为了让我们创建的项目是一个Java EE项目,这里我们设置FormGen Core依赖jst.web facet. FormGen Ext facet需要建立在 FormGen Core的基础上
xml 代码
- <extension point="org.eclipse.wst.common.project.facet.core.facets">
-
- <project-facet-version id="formgen.core" version="1.0">
- <constraint>
- <requires facet="jst.web" version="2.2,2.3,2.4"/>
- constraint>
- project-facet>
-
- <project-facet-version id="formgen.ext" version="1.0">
- <constraint>
- <requires facet="formgen.core" version="1.0"/>
- constraint>
- project-facet>
-
- extension>
实现Action
经过了上面的设置之后,运行插件,在新建工程向导里面选择FormGen Core会出现错误提示信息,这是因为我们还没有实现对应的Action,这里所说的Action是指facet所要执行的操作,这里有三种类型的action:INSTALL, UNINSTALL, and VERSION_CHANGE,下面的工作就是实现FormGen Core的action
下面是action对应的扩展点设置格式:
xml 代码
- <extension point="org.eclipse.wst.common.project.facet.core.facets">
- <action id="{string}" facet="{string}" version="{version.expr}" type="INSTALL|UNINSTALL|VERSION_CHANGE">
- <delegate class="{class:org.eclipse.wst.common.project.facet.core.IDelegate}"/>
- <property name="{string}" value="{string}"/> (0 or more)
- action>
- extension>
下面我们对上述设置进行一下说明:
version属性可以是单个值也可以是表达式,如果action使用所有的facet,那么不设置
id属性可选,如果不制定,系统将以"[facet-id]#[version-expression]#[action-type](#[prop-name]=[prop-value])*"格式创建一个, 为了可读性,最好自己制定id
在action内部还可以在project-facet-version元素内部中使用,如果是这样的话,那么facet和version属性将被忽略,如果同一个action delegate实现被多个facet 版本使用,那么最好在外面单独设置一个action节点,这样系统会进行优化
对于VERSION_CHANGE类型的Action而言, 那么制定了version信息之后,其行为将会收到一些限制, 我们只需要在action下的property中制定from.versions属性即可,其值可以是单个,也可以是表达式
我们的FormGen Core的action要做两件事:(1)copy formgen-core.jar 到项目的WEB-INF/lib 目录下;(2)将FormGen servlet添加到web.xml中.而FormGen Ext会将copy formgen-ext.jar 到WEB-INF/lib 目录下
xml 代码
- <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>
java 代码
- 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();
- }
- }
- }
-
java 代码
- 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();
- }
-
- }
- }
-
xml 代码
- <extension point="org.eclipse.wst.common.project.facet.core.facets">
- <category id="{string}">
- <label>{string}label>
- <description>{string}description> (optional)
- category>
- <project-facet>
- <category>{string}category> (optional)
- project-facet>
- extension>
设置如下:
xml 代码
- <extension point="org.eclipse.wst.common.project.facet.core.facets">
-
- <category id="formgen.category">
- <label>FormGenlabel>
- <description>Enables generation of HTML forms based on XML definition files.description>
- category>
-
- <project-facet id="formgen.core">
- <category>formgen.categorycategory>
- project-facet>
-
- <project-facet id="formgen.ext">
- <category>formgen.categorycategory>
- project-facet>
-
- extension>
效果如图