杂项提示、技巧和要避免的事项
本部分包含以下主题:
• 使用访问权限
• 经验法则:每个操作/属性/组件一个验证器
• 不要扩展 WTReferences
• 处理 Null 值
• 使用 @Override 注释
• UIValidationCriteria.toString()
使用访问权限
提供了一个 UIValidationCriteria 属性,用于存储由某一验证器或筛选器检索的访问权限,以供后续验证器或筛选器使用。例如,假设 actionA、actionB 和 actionC 都在同一操作模型中,且都需要知道用户在当前容器中是否具有修改权限。如果先调用 actionA 的验证器或筛选器,则可以查询 AccessControlManager 以获取权限,然后将其存储在 UIValidationCriteria 中,从而使得 actionB 和 actionC 的验证器或筛选器无需再次执行相同查询。
通常,如果需要检查验证器或筛选器中的访问权限,则应执行以下操作:
• 通过调用新的 UIValidationCriteria.getCachedAccessPermissions() 方法来检查权限是否已存储在 UIValidationCriteria 中。
• 如果 getCachedAccessPermissions() 返回一个非 null 值,则可以使用这些权限进行验证检查
• 如果 getCachedAccessPermissions() 返回 null 值,则可以查询 AccessControlManager 以获取所需的权限,然后通过调用 setCachedAccessPermissions() 方法将其存储在 UIValidationCriteria 中,以供后续验证器使用。
UIValidationCriteira 中 cachedAccessPermissions 属性旨在存储 AccessControlManager.getPermissions() 的结果。
也就是说,您应按如下所示编写验证器或筛选器代码:
// check to see if the access permissions have already been
calculated...
WTKeyedHashMap accessPermissions =
criteria.getCachedAccessPermissions();
// if the access permissions have not been calculated yet, get the
permissions and cache them for other
// validators to use
if (accessPermissions == null){
accessPermissions = AccessControlManager.getPermissions(...);
criteria.setCachedAccessPermissions(accessPermissions);
}
有关访问权限的其他说明:
• wt.access.AccessControlManager 在单个和多个对象变型中提供了以下 API:
◦ hasAccess - 如果承担者具有给定访问权限,则返回 true,否则返回 false。
◦ checkAccess - 如果承担者没有给定的访问权限,则会抛出 NotAuthorizedException 并激发用于审计目的的事件。
◦ getPermissions - 返回授予承担者的权限集 (AccessPermissionSet)
• 使用 hasAccess 或 getPermissions 评估用户权限并继续 (例如,UI 操作验证代码根据用户权限禁用操作)
• 检查用户是否具有访问权限的一种方法是使用任一 hasAccess API。另一种方法是让需要检查一个或多个对象权限的任何人调用这两个 getPermissions API 之一,并将结果存储在 UIValidationCriteria 中,以供也需要检查相同对象权限的其他验证器使用 (假设对象的域、类型与状态以及当前承担者保持相同),而不是通过调用 hasAccess 来评估访问权限的方式进行每项权限检查。即使结果未存储,getPermissions API 对任何需要检查多个权限的验证器也会很有用。AccessPermissionSet 是一个集合,提供了一个方法来检查指定权限是否在该集中:
boolean includes(AccessPermission permission)
// Returns true if permissions in this set include rights for
the specified permission.
• 不应使用 checkAccess API 来查看用户是否具有指定权限,除非目的是将异常传播至最终用户。如果捕获 NotAuthorizedException,而未因为缺少访问权限导致用户操作失败,则应禁用异常审计。有关详细信息,请参阅 Javadoc。
经验法则:每个操作/属性/组件一个验证器
不要陷入为多个不相关操作注册一个验证器的陷阱。结果会产生大量 if/else 分支和一些非常大的方法。这会使维护变得困难,且更容易引入回归。
通常,只有当这些组件共享完全相同的验证逻辑,或者您拥有一个 either/or 情景时,才会为多个操作/组件使用一个验证器。所谓 either-or 情景是指:在给定操作菜单中应该出现 actionA 或 actionB,但二者从不同时出现。对于所有其他情况,最好为每个操作/组件注册一个验证器。
不要扩展 WTReferences
您可能会尝试按如下所示编写验证代码。请勿如此编写代码。
@Override
public UIValidationResultSet performFullPreValidation
(UIValidationKey validationKey,
UIValidationCriteria validationCriteria, Locale locale)
throws WTException
{
Persistable contextObject =
validationCriteria.getContextObject().getObject();
WTContainer container =
validationCriteria.getParentContainer().getReferencedContainer();
if (!contextObject instanceof WTPart){
...
}
if (!container instanceof PDMLinkProduct){
...
}
}
以上代码会将保存在 UIValidationCriteria 中的 WTReferences 扩展为 Persistables,操作成本相对较高。在某些情况下,可能必须扩展这些对象,但也有很多情况可避免扩展此类对象。如果您实际上只需要知道上下文对象或父项容器是否为某个类的实例,则可以改为使用 isAssignableFrom() 方法,如下所示:
@Override
public UIValidationResultSet performFullPreValidation
(UIValidationKey validationKey,
UIValidationCriteria validationCriteria, Locale locale)
throws WTException
{
WTReference contextObjectRef =
validationCriteria.getContextObject();
WTContainerRef containerRef =
validationCriteria.getParentContainer();
if
(!WTPart.class.isAssignableFrom(contextObjectRef.getReferencedClas
s())){
...
}
if (!PDMLinkProduct.class.isAssignableFrom(containerRef.getReferenced
Class())){
...
}
}
处理 Null 值
在某些情况下,您可能要为产品中特定页面上的特定操作编写验证器或筛选器,在这种情况下,您需要使用来自 UIValidationCriteria 的属性之一执行业务逻辑。例如,假设您正在处理信息页面上的第 3 级表格,并且希望在使用“通用部件”的信息页面时,该表的工具栏不显示操作。因此,您可以执行以下操作 (不要复制此代码,但可作为示例进行参考...):
if
(((WTPart)validationCriteria.getContextObject().getObject()).getGe
nericType()
.equals(GenericType.GENERIC)){
...
对于仅测试部件详细信息页面上的操作的测试实例,此代码可能会运行良好。但是,如果该操作也出现在主页上某个表的工具栏中或者出现在产品列表页面上,会怎么样?那么,上述代码将从这些页面中抛出 NullPointerException,因为 validationCriteria.getContextObject() 将 (正确地) 返回 null 值。
您可以执行一些操作来避免这种情况。首先,可以检查并确保从 UIValidationCriteria 获取的值不为空。如果值为空,则记录警告,并调用 super.[无论实现何种方法](key, criteria, locale);.
另外,可在执行比较时对 "expected" 值使用 .equals 操作。例如:
if
(ComponentType.WIZARD.equals(validationCriteria.getComponentType()
)
而不是
if
(validationCriteria.getComponentType().equals(ComponentType.WIZARD
))
通常,在您的用例中,仅因为 null 值而不允许继续验证,并不意味着它应该在每个用例中都是一个 showstopper。
使用 @Override 注释
强烈建议您在覆盖预设交付的类的方法时使用覆盖注释。
UIValidationCriteria.toString()
UIValidationCriteria,为提供其内容相关信息,不会覆盖 toString()。可使用以下方法进行日志记录。
public String toString_heavy(Logger logger, Level level)
如果记录器的级别与所提供的级别相匹配,则该方法将返回信息。由于该方法会进行一些高成本计算,因此建议合理使用。