侦听器 API
本部分介绍侦听器 API。
|
|
此功能只能与 PTC 专业服务配合使用。要加入早期发布社区,请联系 PTC 销售团队。
|
Codebeamer 侦听器 API
Codebeamer 服务器内部提供了一种机制,用于将实体生命周期
事件分派给注册的
侦听器。
事件
用于传送
事件的协议通过实体特定
Java 接口进行定义,其中每种类型的
事件均表示为一种
方法。
例如用于传送项目生命周期事件的接口如下:
• 创建新项目。
• 更新或移除现有项目。
public interface ProjectListener extends EventListener {
/**
* This method gets called when a new project is created.
* The {@link BaseEvent#getSource()} is the newly created project
* @throws VetoException if the listener wishes the change to be rolled back.
*/
default void projectCreated(BaseEvent<ProjectDto,Void,Void event) throws VetoException {}
/**
* This method gets called when a project is updated.
* The {@link BaseEvent#getSource()} is the new/updated project state
* The {@link BaseEvent#getSecondarySource()} is the old project state before the update
* @param event contains the "new" state as "source" and the "old" state as "secondarySource", so you have access to both.
* @throws VetoException if the listener wishes the change to be rolled back.
*/
default void projectUpdated(BaseEvent<ProjectDto,ProjectDto,Void event) throws VetoException {}
/**
* This method gets called when a project is deleted.
* The {@link BaseEvent#getSource()} is the deleted project
* @throws VetoException if the listener wishes the change to be rolled back.
*/
default void projectDeleted(BaseEvent<ProjectDto,Void,Void event) throws VetoException {}
/**
* This method gets called when the daily project statistics are built (typically daily once a night).
* The {@link BaseEvent#getSource()} is the project the statistics of which is to be built
* The {@link BaseEvent#getSecondarySource()} is the statistics anchor date.
* The {@link BaseEvent#getData()} are the {@link DailyProjectStatsDto}, but only in the post event notification.
* @throws VetoException if the listener wishes not to build statistics or this project.
* @since CB-6.0
*/
default void projectDailyStatistics(BaseEvent<ProjectDto,Date,DailyProjectStatsDto event) throws VetoException {}
/**
* This method gets called when a user requested to join a project.
* The {@link BaseEvent#getSource()} is the project where the {@link BaseEvent#getUser()} wants to join
* The {@link BaseEvent#getSecondarySource()} is the comment of the user for the join request
* @param event
* @throws VetoException
*/
default void userJoinRequested (BaseEvent<ProjectDto,String,Void event) throws VetoException {}
/**
* This method gets called when a project join request was accepted.
* The {@link BaseEvent#getSource()} is the project where the join was accepted by the {@link BaseEvent#getUser()}
* The {@link BaseEvent#getSecondarySource()} is the comment of the user who accepted the join
* The {@link BaseEvent#getData()} is the user whose join request was accepted.
* @param event
* @throws VetoException
*/
default void userJoinAccepted (BaseEvent<ProjectDto,String,UserDto event) throws VetoException {}
/**
* This method gets called when a project join request was rejected
* The {@link BaseEvent#getSource()} is the project where the join was rejected by the {@link BaseEvent#getUser()}
* The {@link BaseEvent#getSecondarySource()} is the comment of the user who rejected the join
* The {@link BaseEvent#getData()} is the user whose join request was rejected.
* @param event
* @throws VetoException
*/
default void userJoinRejected (BaseEvent<ProjectDto,String,UserDto event) throws VetoException {}
}
有关
事件
的信息将作为
方法
参数传递,通常以具有实体和事件特定信息的
通用
BaseEvent 对象形式传递:
• request
触发事件的
HTTP
Servlet 请求。
• user
发出请求的 Codebeamer 用户。
• source
事件涉及的实体:
• secondarySource
此事件涉及的第二个可选实体
• data
任何可选附加事件特定数据
• preEvent
这是执行基本实际生命周期操作之前的通知 (true) 还是成功执行生命周期操作之后的通知 (false)
如未另行声明,任何实体生命周期
事件
都会传送
两次:
• 在执行实际生命周期操作之前 (preEvent == true):
在此阶段中,可写入作为
source 传递的实体对象 (例如,
ProjectDto),从而支持
侦听器
执行以下操作:
◦ 验证甚至修改实体对象
◦ 通过抛出 VetoException 以及一些说明消息,拒绝预期的生命周期操作。
• 在成功执行实际生命周期操作之后 (preEvent == false):
请知悉,如果生命周期操作执行被拒绝 (请参阅上文) 或失败,则不会发布通知!
通常会使用此阶段在外部发布事件,例如,通过向注册的订阅者发送相应的通知电子邮件 (请参阅下面的默认侦听器):
◦ 无法再修改实体对象!
◦ 将忽略在此阶段中抛出的 VetoException!
发生的所有
事件
传送
• 在生命周期操作的
事务
中进行,
因此,
侦听器
通知过程中的
运行时
异常
将导致
事务
回滚
!
列表
以下是包
com.intland.codebeamer.event 中按字母顺序排列的所有
Codebeamer 侦听器
接口
列表,包括其传送的
事件
:
• ArtifactListener
◦ artifactCreated
◦ artifactUpdated
◦ artifactDeleted
◦ artifactOpened
• AssociationListener
◦ associationCreated
◦ associationUpdated
◦ associationDeleted
◦ fileUploaded
• ProjectListener
◦ projectCreated
◦ projectUpdated
◦ projectDeleted
◦ projectDailyStatistics
◦ userJoinRequested
◦ userJoinAccepted
◦ userJoinRejected
• RoleListener
◦ roleCreated
◦ roleUpdated
◦ roleDeleted
• ScmListener
◦ repositoryCreated
◦ repositoryUpdated
◦ repositoryDeleted
◦ repositorySynchronized
◦ changeSetCommitted
• TrackerItemListener
◦ trackerItemCreated
◦ trackerItemUpdated
◦ trackerItemRemoved
◦ trackerItemDeleted
◦ trackerItemEscalated
◦ attachmentAdded
◦ attachmentUpdated
◦ attachmentRemoved
• TrackerListener
◦ trackerCreated
◦ trackerUpdated
◦ trackerDeleted
◦ trackerSynchronizationConfigured
◦ trackerSynchronizationRemoved
◦ trackerSynchronized
• UserListener
◦ userCreated
◦ userUpdated
◦ userDeleted
• WorkflowListener
◦ transitionTaken
要查看提供的实际事件信息,请参阅特定实体
侦听器
接口
方法
(=
事件
) 的文档。
侦听器
同一
事件
可以具有任意数量的
侦听器
,或者根本没有侦听器。
将按以下方式调用所有适当
侦听器
• 按顺序 (按非定义顺序),
因此
• 低效的侦听器实施将降低触发生命周期操作的性能!
默认侦听器
Codebeamer 在
com.intland.codebeamer.event.impl 包中包含一组默认
侦听器
。
这些默认侦听器负责将特定事件的通知电子邮件发送给专用受众:
• <bean id="defaultUserListener" class="com.intland.codebeamer.event.impl.DefaultUserListener" />
◦ userCreated
▪ user_created_notification_email_[subject|body].vm
◦ userUpdated
▪ user_activated_confirmation_email_[subject|body].vm
• <bean id="defaultProjectListener" class="com.intland.codebeamer.event.impl.DefaultProjectListener" />
◦ projectCreated
▪ project_created_notification_email_[subject|body].vm
◦ userJoinRequested
▪ project_join_requested_notification_email_[subject|body].vm
◦ userJoinAccepted
▪ project_join_accepted_notification_email_[subject|body].vm
◦ userJoinRejected
▪ project_join_rejected_notification_email_[subject|body].vm
• <bean id="defaultArtifactListener" class="com.intland.codebeamer.event.impl.DefaultArtifactListener" />
◦ artifactCreated
▪ [artifact|wikipage][_comment]_created_notification_email_[subject|body].vm
◦ artifactUpdated
▪ [artifact|wikipage][_comment]_updated_notification_email_[subject|body].vm
◦ artifactDeleted
▪ [artifact|wikipage][_comment]_deleted_notification_email_[subject|body].vm
◦ artifactOpened
▪ [artifact|wikipage]_opened_notification_email_[subject|body].vm
• <bean id="defaultAssociationListener" class="com.intland.codebeamer.event.impl.DefaultAssociationListener" />
◦ associationCreated
▪ tracker_item_association_created_notification_email_[subject|body].vm
• <bean id="defaultScmListener" class="com.intland.codebeamer.event.impl.DefaultScmListener"/>
◦ changeSetCommitted
▪ scc_modification_committed_notification_email_[subject|body].vm
◦ repositorySynchronized
▪ scm_checkout_finished_email_[subject|body].vm
• <bean id="defaultTrackerItemListener" class="com.intland.codebeamer.event.impl.DefaultTrackerItemListener"/>
◦ trackerItemCreated
▪ [tracker_item|pull_request]_created_notification_email_[subject|body].vm
◦ trackerItemUpdated
▪ [tracker_item|pull_request]_updated_notification_email_[subject|body].vm
◦ trackerItemEscalated
▪ tracker_item_escalated_notification_email_[subject|body].vm
◦ attachmentAdded
▪ tracker_item_[attachment|comment]_created_notification_email_[subject|body].vm
适用于电子邮件主题和正文的
Velocity 模板
位于:
~/CB-../tomcat/webapps/cb/config/templates/email。
要替换默认侦听器,必须将扩展/自定义版本的
<bean> 配置
添加至
~/CB-../tomcat/webapps/cb/WEB-INF/classes/my-ApplicationContext.xml。
自定义侦听器
自定义
侦听器
类
的
包
应为
com.intland.codebeamer.event.impl 的子包。
可使用任何包名称,但如果使用
com.intland.codebeamer 的子包,则可以在
Codebeamer 启动期间通过
组件
扫描自动检测和部署
侦听器
。
例如示例 ProjectListener 实施如下:
package com.intland.codebeamer.event.impl.sample;
import org.springframework.stereotype.Component;
import com.intland.codebeamer.event.ProjectListener;
@Component("exampleProjectListener")
public class ExampleProjectListener implements ProjectListener {
}
除非要将默认侦听器 (请参阅上文) 替换为扩展/自定义版本,否则不能
• 从默认侦听器派生自定义侦听器
• 复用默认侦听器的
类
名称
如果
侦听器
类
需要访问其他
Codebeamer API
,则只需声明适当的
@Autowired
变量,例如
package com.intland.codebeamer.event.impl.sample;
import org.springframework.stereotype.Component;
import com.intland.codebeamer.event.ProjectListener;
import com.intland.codebeamer.manager.ProjectManager;
@Component("exampleProjectListener")
public class ExampleProjectListener implements ProjectListener {
@Autowired
private ProjectManager projectManager;
...
}
虽然此实施已编译,但它仍然无用,因为它尚未解决任何
事件
。
为此,我们必须
改写
相应的
方法
,例如
package com.intland.codebeamer.event.impl.sample;
import org.springframework.stereotype.Component;
import com.intland.codebeamer.event.BaseEvent;
import com.intland.codebeamer.event.ProjectListener;
import com.intland.codebeamer.event.util.VetoException;
import com.intland.codebeamer.persistence.dto.ProjectDto;
@Component("exampleProjectListener")
public class ExampleProjectListener implements ProjectListener {
@Override
public void projectCreated(BaseEvent<ProjectDto, Void, Void> event) throws VetoException {
ProjectDto project = event.getSource();
if (event.isPreEvent() && project.getCategoryReference() == null) {
throw new VetoException("Each project must have a category!");
}
}
}
在 Codebeamer 10.1 及更高版本中,只需为要解决的
事件
改写
方法。默认将忽略其他事件。
ProjectListener 的另一个示例是
将用户作为项目管理员添加至每个新建的项目。
下面是
FileUploadListener 的示例。
Java IDE
在
Java 中开发自定义
侦听器类时,需使用受支持的 Java 版本或更新的标准版 (SE)
Java Development Kit (JDK) 以及下列框架/库:
框架/库 | 组件 | 版本 |
|---|
| | 3.4 |
| spring-core | 5.1.x |
| spring-context | 5.1.x |
| spring-beans | 5.1.x |
| spring-tx | 5.1.x |
| mybatis-spring | 2.0.x |
还需要 Codebeamer 10.0 或更新版本安装的目录 ~/CB-../tomcat/webapps/cb/WEB-INF/lib 中的 cb.jar 和 cb-common.jar,以部署侦听器。
部署
要部署自定义
侦听器
类
,必须编译 Java 代码,并将生成的
*.class 文件上传到
Codebeamer 服务器上
~/CB-.../tomcat/webapps/cb/WEB-INF/classes/... 下的相应子目录,其中子目录等同于扩展的包名称。
如果存在多个自定义侦听器,则可以选择将所有自定义类打包到一个 Java 存档 (*.jar) 中,并将该存档放入 ~/CB-.../tomcat/webapps/cb/WEB-INF/lib。
对于不在
com.intland.codebeamer 下或未注释为
@Component
的
侦听器
类
,还
必须 在以下位置额外提供
<bean> 配置
:
~/CB-../tomcat/webapps/cb/WEB-INF/classes/my-ApplicationContext.xml
最后,必须重新启动 Codebeamer 才能加载新部署的侦听器。
| • 已部署 侦听器 在 Codebeamer 服务器 JVM 中运行,并可以不受限制地访问 所有内部功能和数据。 ◦ 因此,只需部署自定义侦听器,您了解这些侦听器的确切作用并且已知其经过仔细测试。 |
实用工具
GlobalTypeFacade (适用于共享字段/全局类型的实用工具)
Codebeamer 的 com.intland.codebeamer.facade 包中存在适用于全局类型 (共享字段) 的实用工具类 GlobalTypeFacade,该类具有以下方法:
• Map<String, Integer> getGlobalTypeNameToFieldIdMap(Integer trackerId) - 按跟踪器的全局类型名称获取跟踪器字段 ID 的映射。
• Optional<Object> getGlobalTypeValue(String globalTypeNameOrId, TrackerItemDto item, TrackerItemDto originalItem) throws GlobalTypeNotFoundException - 获取项中的全局类型值。
originalItem 可选参数用于检查当前项是否与原始 (持续) 项 (包含所有引用) 相同。如果不相同,则会从缓存中重新加载该项。
• Optional<TrackerLayoutLabelDto> getFieldByGlobalTypeNameOrId(String globalTypeNameOrId, Integer trackerId) - 按全局类型名称或 ID 获取跟踪器字段。
• Optional<GlobalTypeDto> findGlobalTypeById(UserDto user, Integer id) - 按 ID 查找全局类型。
• Optional<GlobalTypeDto> findGlobalTypeByName(UserDto user, String globalTypeName) - 按名称查找全局类型。
常见问题解答
• 在对我而言无关紧要但强制实现的事件处理器中,我需要执行哪些操作?
您只能将这些方法正文留空,这根本不会造成任何负面影响。
• 我是否可以安全地改写 Codebeamer 随附的默认侦听器?
不可以。Codebeamer 积极依靠利用自有侦听器来实现若干机制。禁用默认侦听器可能会导致未定义行为和数据失效。
• 是否定义了侦听器的调用顺序?
否,绝对无法保证其接收通知的顺序。这一点不可靠。
• 如果侦听器否决了某项操作,其他侦听器是否会收到有关此情况的任何通知?
否。如果侦听器通常以 A、B、C、D 顺序通知,但 B 否决了该操作,则:
• A 不会知道 B 否决了该操作。
• 根本不会调用 C 和 D。
此设计决策旨在保证行为简单,但功能足够强大,适用于大多数实际应用。