侦听器 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
FileUploadListener (Codebeamer 9.5 及更高版本)
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
TrackerSynchronizationListener (Codebeamer 10.0 及更高版本)
trackerSynchronizationConfigured
trackerSynchronizationRemoved
trackerSynchronized
UserListener
userCreated
userUpdated
userDeleted
WorkflowListener
transitionTaken
要查看提供的实际事件信息,请参阅特定实体侦听器 接口 方法 (= 事件) 的文档。
侦听器
Codebeamer 事件 侦听器 是一个 Java ,用于实现一个或多个侦听器接口
同一事件 可以具有任意数量的侦听器,或者根本没有侦听器。
将按以下方式调用所有适当侦听器
按顺序 (按非定义顺序),
同步
在生命周期操作的事务处理 内。
因此
调用侦听器 期间的未捕获 异常 将导致事务 回滚,并且
低效的侦听器实施将降低触发生命周期操作的性能!
默认侦听器
Codebeamercom.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 {

}
除非要将默认侦听器 (请参阅上文) 替换为扩展/自定义版本,否则不能
从默认侦听器派生自定义侦听器
复用默认侦听器的 名称
重新使用默认侦听器的组件名称/ <bean id>
如果侦听器 需要访问其他 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.jarcb-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 (适用于共享字段/全局类型的实用工具)
Codebeamercom.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。
此设计决策旨在保证行为简单,但功能足够强大,适用于大多数实际应用。
这对您有帮助吗?