创建系统配置收集器插件
您需要创建一个新的插件,以与 Windchill 中的系统配置收集器 UI 配合使用,从而执行可用插件所不具备的某些功能。该插件可能会帮助您调试 Windchill 配置、安装和运行时问题。
背景
系统配置收集器是一个 Windchill UI 页面,当前以系统管理员 LDAP 组中的用户身份登录到 Windchill 时,可通过“站点” > “实用程序” > “系统配置收集器”的 UI 导航路径访问该页面。该 UI 页面提供了一些功能,系统管理员可以使用这些功能来收集和保存 Windchill 系统和配置信息,并将其同时发送到本地系统和远程系统,包括 PTC 技术支持。
用户可以通过系统配置收集器的指令一次尽可能多地收集有关 Windchill 系统的相应信息。收集到的信息为用户所用,用户更容易使用这些信息来诊断 Windchill 实例存在的任何潜在系统和/或配置问题。
在“系统配置收集器”页面上,系统管理员可以选择问题类别,例如“性能”和/或“运行时”相关问题。随后将执行多种相应的插件。通过展开 UI 上各个相应类别的根树节点,可以查看要执行的插件列表。每个插件都会收集关于当前 Windchill 系统和配置的离散集。例如,某些插件会收集 Windchill 方法服务器日志、xconf 特性文件、JMX Mbean 配置信息和数据库信息等。
这些插件是完成系统配置收集器类别任务的离散方法。这些插件可用于完成任何可通过 Java 实现的任务,包括执行 SQL 和 QML 脚本、Java 命令实用程序 (其中包括 main() 方法) 和 Windchill WinDU 任务。
这些插件由一组一种或多种类别的软件操作构成,以将特定功能添加到系统配置收集器中。系统配置收集器是使用插件体系结构设计的,因此所提供的功能可由 PTC R&D、PTC 全球服务、PTC 技术支持和 PTC 客户进行自定义。插件体系结构允许开发人员扩展新功能并将其添加到活动 Windchill 系统上的系统配置收集器中。因此,系统配置收集器在无需重新启动 Windchill 服务器的情况下即可识别新插件。插件体系结构可供立即使用已开发的插件。
正因这种插件体系结构的存在,以及可通过插件对其他 Java 系统、数据库、WinDU 任务、脚本等进行操作,系统配置收集器插件拥有了非常强大的功能。
插件也是 JMX Management Bean (MBean)。因此,可通过 JMX 控制台管理插件,例如 Windchill、JConsole 和 VisualVM 附带的插件。使用 MBean 接口,可以轻松管理和部署插件。
有关系统配置收集器及其使用方法的详细信息,请参阅系统配置收集器
有关 JMX MBean 的详细信息,请参阅 Windchill MBean
范围/适用性/假设
范围仅限于系统配置收集器 UI 页面和创建在该页面上运行的插件。
假设您在诊断 Windchill 系统时遇到问题,且当前插件不具备所需功能,无法帮助您诊断该问题。
假设您要扩展现有插件的功能。
预期结果
在 Windchill 中正确设计、创建和部署插件后,可立即将其与“系统配置收集器”页面配合使用。随后,该插件将执行可帮助您执行诊断的所有功能。
创建和部署插件后,刷新系统配置收集器 UI 将允许用户使用已部署的插件。在下面的屏幕截图中,该插件已添加至用户定义的 "Custom Plugins" 类别。该类别仅包含自定义创建的插件 "Tomcat Property Config File"。有关详细信息,请参阅“示例代码”一节。
现在,用户可以在其创建的任何类别中使用该插件,并相应地执行该插件。
另一种方式是通过 JMX 控制台使用自定义插件。在 Windchill 系统中创建和部署插件后,用户可以通过 JMX 控制台加载该插件,并执行该插件。该操作可实现的原因在于,每个插件也是 JMX MBean。
用户必须先在 CustomerSupport MBean 上运行 reloadPlugins() MBean 操作。请参阅下面的屏幕截图。该操作将强制插件体系结构重新加载所有 MBean,并找到先前已部署的自定义插件。
重新加载插件后,可在插件 MBean 列表中查看已创建的自定义插件。
在这种情况下,新加载的插件为 "TomcatConfigProperties" MBean。有关详细信息,请参阅“示例代码”一节。
现在,用户可以通过 JMX 控制台编辑此插件的属性,或运行此插件的操作 (执行插件)。此外,用户还可以将自定义插件添加到现有自定义类别中。有关使用 JMX MBean 的详细信息,请参阅相关文档。
有关 JMX MBean 的详细信息,请参阅 Windchill MBean
创建的插件将在系统配置收集器 UI 或 JMX 控制台中执行。
解决方案
使用系统配置收集器 UI 或 JMX 控制台设计、开发、部署和执行自定义插件。
必备知识
要应用此解决方案,需要了解以下内容:
使用 Java 进行基础开发 - 用于开发插件
Java Management Bean 知识 - 用于开发复杂插件
Java Jar 服务提供者知识 - 了解插件部署
解决方案元素
元素
类型
说明
PluginMBean
Java 类 - 接口
如前所述,每个插件都是 MBean,因此必须实现 PluginMBean 接口。此接口用于指定实现插件所需的合约,并确保其用作 MBean。可将此类扩展到新接口层次结构,以提供其他功能。
实现此类后,插件能够公开可通过 JMX 控制台执行的属性和操作。
此类包含用于实现 MBean 属性和操作的主 API。
AbstractPlugin
Java 类 - 抽象
一种抽象类,用于封装对插件实现 PluginMBean 接口的诸多复杂性。此类提供了方法的具体实现,可通过用于扩展此类的类的继承来使用。
此类为所有插件的基础父类,任何自定义插件都应直接或按层次结构扩展此类。
SelfAwareMBean
Java 类 - 抽象
每个插件都是一个 SelfAwareMBean,也就是说,每个插件都是一个标准 MBean (如前所述),它知道自己的 MBean ObjectName,从而可以在 MBean 注册表中保留其自身的单一注册。
所有自定义插件都应在插件构造函数中实现对 super() 的调用 (请参阅“示例代码”一节),以确保将每个插件都注册为 SelfAwareMBean。AbstractPlugin 基类实现了一种方法调用,用于将插件注册为 SelfAwareMBean。
通常,所有插件都应为 SelfAwareMBean,因为每个插件最终都应从扩展 SelfAwareMBean 的基类 AbstractPlugin 继承。
com.ptc.customersupport.plugins
Java 包
此 Java 包中包含所有 PTC 提供的插件实现。此包中包含抽象源文件,通过为大部分必需方法提供默认功能来简化众多插件的实现。
特别需要注意的是,此包中包含以下 Java 抽象类:
AbstractMultipleFilePlugin
AbstractQMLPlugin
AbstractReportingPlugin
AbstractSQLPlugin
AbstactWinDUPlugin
AbstractXconfPlugin
GatherFilePlugin
GatherFolderPlugin
GatherLogsPlugin
GatherEveryLogPlugin
这些插件的功能可通过 Java 继承直接使用,从而为常用的插件功能类型提供更简单的插件实现。
AbstractMultipleFilePlugin
Java 类 - 抽象
此类封装了插件在收集文件列表时所需的常用功能。
AbstractQMLPlugin
Java 类 - 抽象
此类封装了插件在执行 QML (查询标记语言) 文件/脚本时所需的常用功能。这些脚本通常包含 .qml 文件扩展名。
AbstractReportingPlugin
Java 类 - 抽象
此类封装了插件在对 Windchill Business Reporting 执行插件时所需的常用功能。
AbstractSQLPlugin
Java 类 - 抽象
此类封装了插件在执行 SQL (结构化查询语言) 文件/脚本时所需的常用功能。
AbstractWinDUPlugin
Java 类 - 抽象
此类封装了插件在执行 WinDU (Windchill 诊断实用程序) 任务时所需的常用功能。
AbstractXconfPlugin
Java 类 - 抽象
此类封装了插件在递归标识父 xconf 文件中引用的 xconf 文件时所需的常用功能。
GatherFilePlugin
Java 类 - 抽象
此类封装了插件在收集单个文件时所需的常用功能。
GatherFolderPlugin
Java 类 - 抽象
此类封装了插件在收集父目录和所有子目录时所需的常用功能。
GatherLogsPlugin
Java 类 - 抽象
此类封装了插件在收集日志文件目录时所需的常用功能。此类与类似的 GatherFolderPlugin 稍有不同,前者在文件的指定日期范围内运行,尤其是文件修改时间。
GatherEveryLogPlugin
Java 类 - 抽象
此类封装了插件在收集日志文件目录时所需的常用功能。此类与类似的 GatherLogsPlugin 稍有不同,前者会忽略文件的日期范围,尤其是文件修改时间。因此,此类会在每个日志文件上运行。
CollectorMBean
Java 类 - 接口
用于指定插件如何收集其目标数据的合约的 Java MBean 接口。此 MBean 不需要由插件直接实现,因为 AbstractPlugin 会注意实现细节。
Collector
Java 类
CollectorMBean 接口的具体实现类。这是所有插件实质上都依赖其进行文件收集的类。
collect(...)
Java 方法
这两个 collect(...) 方法是 PluginMBean 接口的一部分,必须由所有插件实现 (因为所有插件都必须实现 PluginMBean 接口)。
这些方法指定了与 Collector 类进行交互并最终执行插件工作所需的 API。
通常情况下,插件层次结构中的 AbstractPlugin 和其他抽象类 (请参阅上文) 提供了可供 collect(...) 方法依赖的默认实现。具体来说,AbstractPlugin.java 的 collectData(...) 方法通常可由 collect(...) 方法来简单调用。但是,用于处理特定需求的更高级插件则可能需要直接覆盖和实现这些方法。通常情况下,这类情况很少发生,仅当在后述情况下才会发生:插件不只是收集文件,而是需要运行某些 Java 进程或调用某些单独的操作来进行处理,以生成待收集文件。
com.ptc.customer
support.plugin.* 包中有些插件可以执行此操作,例如可对其进行检查,具体请参阅 MBeanDumpPlugin.java、WDSPlugin.java 和 AbstractWinduPlugin.java。
请注意,必须实现两种 collect(...) 方法,因为 PluginMBean 接口在指定用户可收集数据时实际上有两种方式。一个 API 需要 callNumber 参数,而另一个则需要 topicIdentifier 参数。这些参数中的每一个参数都用于区分信息的收集位置。
此方法需要特定的 Map 返回值。有关返回值和此方法的更多详细信息,请参阅“自定义点”一节中的“抽象化插件”。
collectData(...)
Java 方法
AbstractPlugin.java 的 collectData(...) 方法封装了实现 PluginMBean 接口的 collect(...) 方法的诸多复杂性。此方法将广播消息设置为将其封送到由插件确定的每个服务器。此方法还可以正确构建预期的返回 Map。由于此方法隐藏了直接使用收集框架的复杂性,因此通常可供 collect(...) 方法依赖。在大多数插件情况下,只需使用适当的参数值即可调用此方法。
此方法需要特定的 Map 返回值。有关返回值和此方法的更多详细信息,请参阅“自定义点”一节中的“抽象化插件”。
PluginType
Java 类
这是一个 Java 枚举类型类。每个插件在初始化其自身时都必须指定其中一种 PluginType 枚举类型,以便 Collector 类了解收集到的信息以何种方式处理以及放置在文件系统的何处。
PluginUtilities
Java 类
此 Java 类提供了实用程序方法,可用于创建不依赖 collect(...) 方法的默认行为的更高级插件。需要特别注意 getReturnMap(boolean, String, String) 方法,该方法可用于构建 collect(...) 方法所预期的 Map 返回值。这将有助于简化高级插件的实现,这些插件会通过特定行为实现 collect(...) 方法。
PluginPropertyUtils
Java 类
此 Java 类为特性信息提供实用程序方法,可用于创建更高级的插件。此类提供的方法可供用户获取 xconf 管理的特性值信息以及将已标记的 xconf 路径解析为完全限定的规范路径的方法。
*Resource
Java 类
应对每个插件字符串进行本地化,以便在不同的区域设置中进行查看。com.ptc.customersupport.mbeans.plugin* 包中包含资源类。这些资源 Java 类保留可本地化的字符串,以及可在 Java 源代码中使用的字符串。
插件可利用这些字符串或新的资源文件来提供本地化的字符串。
<文件_名>.jar
Java Jar 文件
这是标准的 Java .jar 文件,可随意命名。.jar 文件是在系统配置收集器中部署自定义插件以供使用的标准方法。
.jar 应包含插件的已编译 .class 文件和帮助程序 Java 类以及 PluginMBean 服务文件 (请参阅下文)。.jar 文件必须保留 .class 文件和服务文件的包的目录结构。
有关 Java Jar 文件规范的详细信息,请参阅“更多资源”一节。
com.ptc.customersupport.mbeans.PluginMBean
Java Jar 服务文件
这是 Java .jar 文件中包含的服务文件,系统配置收集器 Java 类加载程序可通过该文件了解是否已部署新的插件。文件结构是刚性的且必须保持不变,否则会导致 Java 类加载程序出现问题,插件无法加载或插件不可用。.jar 文件必须包含位于 META-INF\services 位置的 com.ptc.customersupport.mbeans.PluginMBean 文件。文件内容的类型必须如下:
<java 源包>.<插件类名称> (不带括号)。
有关 Java 服务提供者接口的详细信息,请参阅“更多资源”一节。
如上所述,插件包中包含 Java 继承的层次结构,插件开发人员可依赖该层次结构来创建插件。下面的 UML 图表显示了抽象类与 MBean 接口 API 之间的层次关系。
如上所述,所有插件都实现了 PluginMBean 接口并最终对 AbstractPlugin 类进行了扩展。自定义插件可以利用插件层次结构和任何抽象类提供的功能。
过程 - 创建自定义插件
最重要的是,对于完整的 CustomPlugin.java 类 (在以下各节中将其视为代码片段),请参阅“示例代码”一节。
首先必须完成四个不同的阶段,之后才能将插件与系统配置收集器或 JMX 控制台配合使用。
1. 设计插件。
2. 实现插件。
3. 编译插件。
4. 部署插件。
设计插件
为系统配置收集器设计插件时需考虑以下事项。
1. 强烈建议 (尽管不是必需) 插件类名称中包含单词 "Plugin"。将单词 "Plugin" 作为类名称的后缀可轻松识别其用途。插件源文件名称的格式应为 <ClassName>Plugin.java。出于实用性方面的考虑,<ClassName> 也应间接指出插件的用途。例如,PTC 提供了 SiteXConfPlugin 插件,该插件可用于收集 <Windchill>\site.xconf 文件。
2. 强烈建议插件开发人员为其插件保留合理的 Java 包结构。PTC 提供的插件通常会保留与其用途和 PluginType 相关的包结构 (有关 PluginType 类的详细信息,请参阅“解决方案”一节)。大部分 PTC 插件都可以在包 com.ptc.customersupport.mbeans.plugins 中找到。将自定义插件放置在此包中可以简化自定义插件的调试,同时便于识别插件部署后所在的位置。但是,这并非严格要求,包结构留给开发人员使用。
3. 所有插件都必须实现 PluginMBean 接口。实现此 PluginMBean 接口类后,插件能够公开可通过 JMX 控制台执行的属性和操作。此外,PluginMBean 类强制执行 API 合约,所有插件都必须遵循该合约,这对于基础收集框架而言至关重要 (请参阅“解决方案”一节中所述的 CollectorMBean 和 Collector 类)。
4. 所有插件都必须扩展 AbstractPlugin 类。AbstractPlugin 类封装了实现 PluginMBean 接口的诸多复杂性。此类为多种创建插件的常用方法提供了默认实现。当然,可以覆盖默认方法实现来提供不同的功能。
例如:
public class CustomPlugin extends AbstractPlugin
implements PluginMBean {}
此示例显示了实现 PluginMBean 接口并扩展 AbstractPlugin 类的 CustomPlugin 类。请注意,在此示例中,不会实现接口的必需方法,即 collect(...) 方法,且不会编译此简单类。有关使用 Windchill 封装的示例插件的完整示例插件实现,请参阅“示例代码”一节。
5. 所有插件对象构造函数都必须对其超类进行方法调用。这是为了确保所有插件均初始化为 SelfAwareMBean (有关 SelfAwareMBean 的详细信息,请参阅“解决方案”一节)。由于所有插件都必须通过插件层次结构扩展 AbstractPlugin 类,因此 AbstractPlugin 类将进行相应的方法调用,以将插件注册为 SelfAwareMBean。因此,插件开发人员只需确保其插件在构造过程中调用 super() 运算符,并且插件继承最终扩展 AbstractPlugin.java 即可,而不必考虑实际的插件 MBean 注册。
例如:
public CustomPlugin() throws NotCompliantMBeanException {
super(null);
// TODO Other initialization of this particular plugin
}
public CustomPlugin(final String displayName,
final String beanName, final String description,
final String pluginVersion)
throws NotCompliantMBeanException {
super(null, displayName, beanName, description, pluginVersion);
// TODO Other initialization of this particular plugin
}
实现这些构造函数是为了与 AbstractPlugin 的构造函数相匹配,并通过 super 运算符对 AbstractPlugin 进行调用。这会使 CustomPlugin 注册为 SelfAwarePlugin。
构造函数对 super 的调用采用类对象。如果已知具体类,则可以指定具体类,否则将使用 null。Java 将使用自省来确定类名称。例如,由于 CustomPlugin 实现了 PluginMBean,因此对 super 的调用可以是:
super(PluginMBean.class);
查找选项以依赖继承来设计更简洁的构造函数。
6. 由于实现了 PluginMBean 接口并对 AbstractPlugin 进行了扩展,因此插件必须实现两个 collect(...) 方法。这些方法实质上是组织工作并将其交付给 Collector 类和收集框架。
例如:
@Override
public Map<String, Object> collect(final long callNumber,
final long maxAgeInDays,final long minAgeInDays,
final String pathTimeStamp) {
// TODO Do actual collection work and return correct Map
return null;
}
@Override
public Map<String, Object> collect(String topicIdentifier,
final long maxAgeInDays, final long minAgeInDays,
final String pathTimeStamp) {
// TODO Do actual collection work and return correct Map
return null;
}
此处显示的 collect(...) 方法实现不会执行任何有用的操作,为了清楚起见,在此加以介绍。这些方法实现应执行插件收集需要完成的所有工作,并返回预期的正确 Map<String, Object> 值。
collect(...) 方法存在多个默认实现,可通过抽象类进行依赖。通常,插件只需要通过将 collect(...) 方法的参数传递给 collectData(...) 方法来调用 AbstractPlugin.java 的 collectData(...) 方法。collectData(...) 方法封装了直接在 collect(...) 方法中调用收集框架的复杂性。PluginMBean 接口 API 需要使用 collect(...) 方法,因为此方法具有一定的灵活性,而更高级的插件可能需要避免使用 collectData(...) 的默认行为,这样开发人员便可根据需要实现 collect(...) 方法。此外,抽象类还具有其他可依赖的方法。其中,许多方法的形式为 collectXYZ(...),可由特定插件的 collect(...) 方法实现进行调用。这些 collect (...) 方法封装了插件执行的抽象类型的工作的具体收集实现。例如,GatherFolderPlugin 类具有实现的 collect(...) 方法,以便将要收集的特定文件夹传递到收集框架,但前提是文件夹已在插件初始化中正确设置)。
collect(...) 方法必须返回 Map<String, Object>。插件框架使用此返回 Map 来了解用以执行插件的服务器以及插件的状况。此返回值实际上是 Map; Map<String, Map<String, String>> 内的 Map。外部 Map 包含服务器信息,而内部 Map 包含该服务器的插件执行状况。
如果定制器并不使用父 collectData(...) 或抽象类的其他 collect(...) 方法来依赖 collect(...) 方法的默认实现,需特别留意,确保返回 Map 已正确构建且包含有效值。
有关使用默认 collect(...) 实现的其他详细信息,以及有关方法返回 Map<String, Object> 值的详细信息,请参阅“自定义点”一节。
7. 最后需要考虑的是插件在实际工作中必须完成的工作以及完成此工作最合适的方法。这可以通过使多个类彼此协同工作来实现,也可以通过将所有执行封装在一个类中来实现。
此外,还有许多实用程序方法和抽象类 (如“解决方案”一节中所述) 可用于简化插件实现。但是,可根据插件需要完成的任务,将其设计为非常复杂的插件或非常简单的插件。
8. 总之,一个设计正确的插件至少具备以下特征:
实现 PluginMBean 接口。
直接扩展或通过继承扩展 AbstractPlugin 类。
2 个具有 super() 运算符调用 (最终导致 AbstractPlugin) 的构造函数。
2 个 collect(...) 方法 (如果不依赖于父 collect(...) 实现)。
实现插件
插件的实现是将执行插件实际工作的代码。主要步骤是确保正确初始化插件 (请参阅上述设计步骤) 并遵循所需接口。最后一步是为插件执行其工作提供必要的方法实现。
1. 插件初始化:
在插件构建期间,对象应初始化其 MBean 属性 (同样,所有插件均为 MBean)。使用设计阶段的示例时,可以对构造函数方法进行扩展:
public CustomPlugin() throws NotCompliantMBeanException {
super(null);
// super(PluginMBean.class);
initializeMBeanAttributes();
}
private void initializeMBeanAttributes() {
if (logger.isDebugEnabled()) {
logger.debug("Initializing " + CUSTOM_PLUGIN_NAME + " Plugin.");
}
// set the plugin display name
setDisplayName(CUSTOM_PLUGIN_NAME);
// set the plugin description
setDescription(CUSTOM_PLUGIN_DESCRIPTION);
// set the plugin MBean name
setMBeanName("TomcatConfigProperties");
// set the plugin enumerated type
setPluginType(PluginType.MISC);
// set the plugin version number
setPluginVersion("1.0");
// set whether the plugin relies on database
// administrator credentials
setDbCredentialsNeeded(false);
// set whether the plugin operates on each
// cluster node
setClusterAware(true);
// set whether the plugin relies on file
// date ranges for data collection
setDateRangeUsed(false);
// set whether the plugin should compress the
// output of its data collection
setCompressOutput(false);
}
在此,构造函数已扩展为包含用于初始化所有插件属性的私有方法,其中包含所显示的 MBean 值。
setMBeanName 参数的值应为具有正确格式的 MBean 对象名称。为避免发生潜在的 MBean 加载程序问题,建议不要在字符串名称中使用空格。有关 MBean 对象名称语法的完整详细信息,请参阅“更多资源”一节中的“相关网站”。
2. 插件 collect(...) 方法
大部分插件工作都包含在 collect(...) 方法中,实现细节留给插件开发人员进行实现。有关示例,请参阅“示例代码”一节。
在高级插件中,collect(...) 方法的工作量通常比较庞大,因此需要合理实现帮助程序 Java 类和私有帮助程序方法。这将使插件具有更多的离散方法,以便于维护。任何帮助程序方法的实现都完全取决于插件和开发人员的决定,因此实现也是特定的,并留给插件的特定实现器来执行。有关 collect(...) 方法的更多详细信息,请参阅“自定义点”一节。
3. 插件本地化:
由于 Windchill 为分布式应用程序,客户端可能位于不同的区域设置,因此强烈建议对插件中的所有外部化 Java 字符串进行本地化。
注解的字符串为插件名称和插件说明。用户可在系统配置收集器 UI 中看到这些值。
com.ptc.customersupport.plugins.* 包中包含多个 *Resource.java 文件,这些文件为多个插件所引用,因此在相同的包中都可以找到。这些 *Resource.java 文件包含在 MBean 插件初始化期间本地化和读取的 public String 参考值。
但是,本地化 Java 字符串并不总是可行的,也可能是不切实际的。如果值未本地化,则使用的值即输入并编译到类文件中的值;在上述情况下,值保留英语。
我们使用 CustomPlugin 中的示例,添加新的插件成员变量:
private static ResourceBundle RESOURCE =
ResourceBundle.getBundle(
CustomPluginResource.class.getName());
这将成为我们对本地化 Java 字符串所在位置的引用。随后,CustomPlugin 可以使用此引用来检索本地化值。重构的 setDisplayName(string) 和 setDescription(string) 方法变为:
// set the localized plugin display name
setDisplayName(MBeanUtilities.formatMessage(
RESOURCE.getString(
CustomPluginResource.CUSTOM_PLUGIN_NAME)));
// set the localized plugin description
setDescription(MBeanUtilities.formatMessage(
RESOURCE.getString(
CustomPluginResource.CUSTOM_PLUGIN_DESC)));
从已正确本地化的类文件中检索本地化的 String CUSTOM_PLUGIN_NAME CUSTOM_PLUGIN_DESC
注意:本地化的插件字符串基于服务器区域设置,因为在插件初始化期间会从服务器读取本地化的插件字符串。本地化的值在系统配置收集器 UI 中将根据服务器区域设置显示,而非根据客户端区域设置显示。
编译插件
实现所有插件文件后,必须将其编译为 .class 文件。使用运行 Windchill 的 Java jdk 版本,以确保正确的类文件兼容性。有关如何使用 javac 命令编译 Java 源文件的信息,请参阅“更多资源”一节中的“相关网站”。
部署插件
最后,必须捆绑插件封装的文件并将其部署到 Windchill。如“编译插件”一节所述,系统配置收集器使用 Java 类加载程序来加载所有自定义插件文件。为了使类加载程序能够识别插件,必须使用插件创建和部署服务文件 (有关此文件的信息,请参阅“解决方案元素”和“相关网站”)。
具有功能部署插件的步骤如下:
1. 封装文件。
2. 创建 Jar 文件。
3. 部署 Jar。
1. 在封装的源目录的根位置创建名为 "META-INF" 的目录。在该目录中,创建一个名为 "services" 的子目录。在服务目录中,创建一个名为 "com.ptc.customersupport.mbeans.PluginMBean" 的文本文件。这是一个服务文件,类加载程序通过该文件检查插件类文件。此文件必须包含要加载的所有插件,且必须遵循严格的语法格式。服务文件中每个插件条目的格式如下:
<java 源包>.<插件类名称> (不带括号)。
例如,返回到 CustomPlugin 示例,随即显示相应的服务文件,且其中仅包含如下一行:
com.ptc.customersupport.mbeans.plugins.CustomPlugin
以下是 CustomPlugin 源、类文件和服务文件的包结构示例。
注解项如下:
CustomPlugin 源的包结构 com\ptc\customersupport\mbeans\plugins 保持不变。
.class 文件位于 /plugins 目录中。或者,.java 源文件也可位于此目录中。
存在 META-INF/services 目录。
/services 目录包含 "com.ptc.customersupport.mbeans.PluginMBean" 文件,其中包含要加载的每个插件的条目。
2. 创建包结构和服务文件后,需要将这些文件捆绑到 Java 的 .jar 文件中。有关使用 Java jar 命令的完整详细信息,请参阅“相关网站”。
使用 Windchill shell,导航至根包位置并创建 .jar 文件。
返回到上面的示例,显示包结构并使用命令
jar cvfM CustomPlugin.jar ./com ./META-INF
生成 CustomPlugin.jar,其中包含 /com 和 /META-INF 目录的所有内容及其子目录。
3. 最后,需要将此 .jar 文件部署到系统配置收集器类加载程序位置。复制此文件并将其放置到 <Windchill>\utilities\SystemConfigurationCollector\plugins 目录中。
现在,可在“系统配置收集器”页面中使用插件。要执行此操作,只需刷新浏览器并将自定义插件添加到自定义类别中即可。有关创建自定义类别的详细信息,请参阅有关使用系统配置收集器的帮助信息。
有关系统配置收集器及其使用方法的详细信息,请参阅系统配置收集器
或者,由于所有插件都是 MBean,因此也可以部署插件以在 JMX 控制台中使用。使用 JMX 控制台导航至 CustomerSupport MBean 并运行 reloadPlugins() 操作。此操作强制插件 MBean 加载程序重新加载所有可用插件,包括部署位置的插件。下面的屏幕截图显示了用户正在调用 reloadPlugins CustomerSupport MBean 操作。
调用 reloadPlugins CustomerSupport MBean 操作后,自定义插件将在为其定义了插件的相应插件类型子目录下的 com.ptc/plugins MBean 节点中显示。
有关从 JMX 控制台重新加载插件的详细信息和图像,请参阅“预期结果”。
自定义点
扩展 PluginMBean 接口
插件不必直接实现 PluginMBean 接口。可通过具体插件实现来定义和实现用于扩展 PluginMBean 接口的新接口。但是,要继承 PluginMBean 接口,仍需要新的插件接口。
例如:
public interface XYZPluginMBean extends PluginMBean {}
在此,XYZPluginMBean 扩展 PluginMBean。随后,此接口可进一步定义要通过 MBean 操作公开的任何必需方法或属性。
于是,具体实现如下:
public class XYZPlugin extends AbstractPlugin implements XYZPluginMBean {}
抽象化插件
与“扩展 PluginMBean 接口”部分类似,开发人员可以依赖“解决方案元素”中详述的众多抽象类或由开发人员定义的任意抽象类,将插件 MBean 值初始化为默认值。如前所述,抽象类会封装插件创建的诸多复杂性。除了依赖抽象类进行插件初始化外,开发人员还可以依赖 collect(...) 方法的抽象实现。
AbstractPlugin.java API: public AbstractPlugin(final Class mbeanInterface) throws NotCompliantMBeanException
参数
默认值
可能的值
必需?
说明
mbeanInterface
Class
插件具体实现的类名称。
AbstractPlugin.java API: public AbstractPlugin(final Class mbeanInterface, final String displayName, final String mBeanName,
final String description, final String pluginVersion) throws NotCompliantMBeanException {
参数
默认值
可能的值
必需?
说明
mbeanInterface
Class
插件具体实现的类名称。
displayName
String
插件名称的 String 表示。
mBeanName
String
插件 MBean 名称的 String 表示。此值应符合正确的 Java MBean 对象名称。有关 MBean 对象名称,请参阅“相关网站”。
说明
String
插件说明的 String 表示。
pluginVersion
String
与此插件关联的版本号。
AbstractPlugin.java API: public abstract Map<String, Object> collect(long callNumber, long maxAgeInDays, long minAgeInDays, String pathTimeStamp);
开发人员需要实现此方法,因为此插件为 Abstract 插件。它由 UI 层调用为执行插件工作的入口点。
参数
默认值
可能的值
必需?
说明
callNumber
long
长整型值,与 PTC 技术支持呼叫号相关联。它用作收集插件数据的位置。该值不需要通过 collect(...) 方法实现进行修改。
maxAgeInDays
long
长整型值,是根据时间收集文件的开始时间值。该值不需要通过 collect(...) 方法实现进行修改。
minAgeInDays
long
长整型值,是根据时间收集文件的结束时间值。该值不需要通过 collect(...) 方法实现进行修改。
pathTimeStamp
String
目录时间戳的 String 表示,用作插件收集其数据的名称。该值不需要通过 collect(...) 方法实现进行修改。
开发人员通常可以将此方法参数传递给 AbstractPlugin.java 的 collectData(...) 方法。如前所述,collectData(...) 方法用于处理调用收集框架的复杂性。
开发人员可以采用不依赖 collectData(...) 或任何抽象类的父 collectXYZ(...) 方法实现的方式来实现收集方法。通常情况下,这属于异常。只有需要专门化工作的高级插件 (例如,运行 Java 进程来执行某些工作以构建要收集的文件),可能会避免仅调用父 collect(...) 方法实现。即使在这种情况下,在 Java 进程完成并生成其数据后,仍可依赖父类进行实际收集。MBeanDumpPlugin.java 和 WDSPlugin.java 是 PTC 提供的两个插件,可以执行除简单调用父收集方法以外的其他工作,因此,如果用户想要构建更为复杂的插件,则可以对其进行更详细的检查。
返回值
可能的值
必需?
说明
Map<String, Object>
类型为 <String, Object> 的 Map,其中 Object 的类型为 Map<String, String>
返回类型为包含内部 Map 的 Map。Map<String, Map<String, String>>。内部 Map<String, String> 为包含插件执行状况的 Map。外部 Map<String, Object> 为包含在其上执行插件的服务器的 Map。这样,插件框架便可为每个已执行的插件报告群集中的信息。
提供 collect(...) 方法的返回类型时务必谨慎小心。AbstractPlugin.java 的 collectData(...) 方法封装了创建有效返回类型 (插件框架将正确解释) 的所有复杂性。这也是建议在 collect(...) 方法实现中使用 collectData(...) 方法的原因。否则,将大幅增加实现 collect(...) 方法的复杂性。
外部 Map:Map <String, Object>
String 键必须为服务器进程 ID 和在其上执行插件的名称的主机名。例如,5524@DSTUSYNSKI03D。在所有 String 均有效的情况下,插件框架仍会向用户报告此数据,如果未正确构建,则将显示为无意义的数据。
Object 实际上是类型为 <String, String> 的内部 Map。
内部 Map:Map<String, String>
内部 Map 应具有四个键项,每个键项对应一个 String,即分别对应 "success"、"path"、"message" 和 "location"。
每一个键值都必须是与该键的相应值相对应的另一个 String。"success" 键值应为 true 或 false,其值表明收集框架是否成功收集插件数据。"path" 键值由收集框架生成,它表示规范路径中的最后一个目录,在该目录中,插件数据被收集到在其上执行插件的特定服务器中。"message" 键值是一个 String 消息,可能与收集框架生成的插件一起出现。这可能是有关插件失败原因的状况消息。如果未报告任何消息,则应使用 null 值。"location" 键值是一个 String,用于表示收集框架将插件数据收集到的位置的部分路径。
如果不依赖于 AbstractPlugin.java 或其他父抽象类的 collectData(...) 方法,则必须确保 collect(...) 方法的返回类型遵循此格式,以便插件框架对其进行正确处理。如果直接实现插件并构建返回 Map<String, Object>,则检查 MBeanDump.java 和 WDSPlugin.java 实现以获取更多详细信息。这两个类都不直接依赖于抽象类或收集框架,因此可在其 collect(...) 方法实现中构建正确的返回类型。
对于需要构建返回 Map 的高级插件,开发人员可以依赖 PluginUtilites.getReturnMap(...) 方法,本节将对此进行进一步讨论。
AbstractPlugin.java API: public abstract Map<String, Object> collect(String topicIdentifier, long maxAgeInDays, long minAgeInDays, String pathTimeStamp);
开发人员需要实现此方法,因为此插件为 Abstract 插件。它由 UI 层调用为执行插件工作的入口点。
参数
默认值
可能的值
必需?
说明
topicIdentifier
String
这是目录的 String 表示,用作将插件数据收集到的位置。该值不需要通过 collect(...) 方法实现进行修改。
maxAgeInDays
long
长整型值,是根据时间收集文件的开始时间值。该值不需要通过 collect(...) 方法实现进行修改。
minAgeInDays
long
长整型值,是根据时间收集文件的结束时间值。该值不需要通过 collect(...) 方法实现进行修改。
pathTimeStamp
String
目录时间戳的 String 表示,用作插件收集其数据的名称。该值不需要通过 collect(...) 方法实现进行修改。
有关此方法用法的详细信息,请参阅前述 collect(...) 方法。
AbstractPlugin.java API: public Map<String, Object> collectData(String srcPath, final long callNumber,
final long maxAgeInDays, final long minAgeInDays, String pathTimeStamp) {
参数
默认值
可能的值
必需?
说明
srcPath
String
这是从其收集插件源数据的位置的 String 表示。这通常是一个标记化的 Windchill 特性字符串。例如,WindchillLogsPlugin.java 会将 $(wt.logs.dir) 作为参数传递。此值也可以是要收集的数据的规范文件路径。但是,必须要注意,可能并非每个执行插件的服务器上都存在此文件路径。如果使用的是规范文件路径,则插件应仅在一个群集节点上执行,方法是在插件初始化期间将插件属性 isClusterAware 设置为 false。
callNumber
long
长整型值,与 PTC 技术支持呼叫号相关联。它用作收集插件数据的位置。
maxAgeInDays
long
长整型值,是根据时间收集文件的开始时间值。
minAgeInDays
long
长整型值,是根据时间收集文件的结束时间值。
pathTimeStamp
String
目录时间戳的 String 表示,用作插件收集其数据的名称。
此方法封装了直接使用收集框架收集插件数据的复杂性。尽管并非严格要求,但还是建议通过插件的 collect(...) 方法实现对其进行调用。通常,在 collect(...) 方法中调用此方法并返回其值是执行 collect(...) 方法实现所必需的操作。
此方法的返回值与上面所述的 collect(...) 方法的返回值相同。
AbstractPlugin.java API: public Map<String, Object> collectData(String srcPath, final String topicIdentifier,
final long maxAgeInDays, final long minAgeInDays, String pathTimeStamp) {
参数
默认值
可能的值
必需?
说明
srcPath
String
这是从其收集插件源数据的位置的 String 表示。这通常是一个标记化的 Windchill 特性字符串。例如,WindchillLogsPlugin.java 会将 $(wt.logs.dir) 作为参数传递。此值也可以是要收集的数据的规范文件路径。但是,必须要注意,可能并非每个执行插件的服务器上都存在此文件路径。如果使用的是规范文件路径,则插件应仅在一个群集节点上执行,方法是在插件初始化期间将插件属性 isClusterAware 设置为 false。
topicIdentifier
String
这是目录的 String 表示,用作将插件数据收集到的位置。
maxAgeInDays
long
长整型值,是根据时间收集文件的开始时间值。
minAgeInDays
long
长整型值,是根据时间收集文件的结束时间值。
pathTimeStamp
String
目录时间戳的 String 表示,用作插件收集其数据的名称。
有关此方法用法的详细信息,请参阅前述 collect(...) 方法。
PluginUtilities.java API: public static Map<String, Object>
getReturnMap(final boolean success, final String path, final String message,
final String location) {
参数
默认值
可能的值
必需?
说明
success
boolean
插件执行的成功值,位于插件框架状况的内部 Map 中。
path
String
路径目录值,是收集文件的父目录,位于插件框架状况的内部 Map 中。
message
String
消息,位于插件框架状况的内部 Map 中。
location
String
PluginType 目录的位置部分文件路径,位于插件框架状况的内部 Map 中。
此方法将构建用于 collect(...) 方法实现的返回值,但前提是要将正确的值通过其参数传递给此方法。此方法是一种实用程序方法,更便于 collect(...) 方法创建返回值。实质上,该方法封装了返回值的创建,使 collect(...) 方法的实现器无需创建外部和内部 Map。正如各个参数说明中所述,这些参数用于生成内部 Map,而方法实现用于处理生成的外部 Map<String, Object>。生成的返回值为 Map<String, Object>,其中 Object 的类型为 Map<String, String>,因此可作为 collect(...) 方法的返回类型。
虽然未对这些参数提出严格要求,但理应如此,否则方法的返回值 Map<String, Object> 将会不完整。内部 Map 不包含插件框架用于报告插件执行状况所需的正确数据。
请注意,仅当开发人员不依赖 AbstractPlugin.java 的 collectData(...) 实现或其他 Abstract collectXYZ(...) 方法实现时,此方法才可作为实用程序使用。
限制
系统配置收集器上使用的插件或用作 MBean 的插件具有十分强大的功能。它们可用于收集文件、目录和特性,执行 Java 类、WinDU 任务和脚本,以及收集数据库信息。目前,插件执行仅限于 SQL 和 QML 脚本、WinDU 任务及 Java 代码。
示例代码
CustomPlugin.java
package com.ptc.customersupport.mbeans.plugins;
import java.util.Map;
import java.util.ResourceBundle;
import javax.management.NotCompliantMBeanException;
import org.apache.logging log4j.Logger;
import wt.jmx.core.MBeanUtilities;
import wt.log4j.LogR;
import com.ptc.customersupport.mbeans.AbstractPlugin;
import com.ptc.customersupport.mbeans.PluginMBean;
import com.ptc.customersupport.mbeans.PluginType;
public class CustomPlugin extends AbstractPlugin implements PluginMBean {
private static ResourceBundle RESOURCE =
ResourceBundle.getBundle(CustomPluginResource.class.getName());

private static final Logger logger = LogR.getLoggerInternal(CustomPlugin.class.getName());

public CustomPlugin() throws NotCompliantMBeanException {
super(null);
// super(PluginMBean.class);
initializeMBeanAttributes();
}
public CustomPlugin(final String displayName,
final String beanName, final String description,
final String pluginVersion)
throws NotCompliantMBeanException {
// super(PluginMBean.class, displayName, beanName,
// description, pluginVersion);
super(null, displayName, beanName, description, pluginVersion);
}
@Override
public Map<String, Object> collect(final long callNumber,
final long maxAgeInDays,final long minAgeInDays,
final String pathTimeStamp) {
// TODO Do actual collection work and return correct Map
return null;
}
@Override
public Map<String, Object> collect(String topicIdentifier,
final long maxAgeInDays, final long minAgeInDays,
final String pathTimeStamp) {
// TODO Do actual collection work and return correct Map
return null;
}
private void initializeMBeanAttributes() {
if (logger.isDebugEnabled()) {
logger.debug("Initializing " +
MBeanUtilities.formatMessage(
RESOURCE.getString(
CustomPluginResource.
CUSTOM_PLUGIN_NAME))
+ " Plugin.");
}
// set the localized plugin display name
setDisplayName(MBeanUtilities.formatMessage(
RESOURCE.getString(
CustomPluginResource.CUSTOM_PLUGIN_NAME)));
// set the localized plugin description
setDescription(MBeanUtilities.formatMessage(
RESOURCE.getString(
CustomPluginResource.CUSTOM_PLUGIN_DESC)));
// set the plugin MBean name
setMBeanName("TomcatConfigProperties");
// set the plugin enumerated type
setPluginType(PluginType.MISC);
// set the plugin version number
setPluginVersion("1.0");
// set whether the plugin relies on database
// administrator credentials
setDbCredentialsNeeded(false);
// set whether the plugin operates on each
// cluster node
setClusterAware(true);
// set whether the plugin relies on file
// date ranges for collection
setDateRangeUsed(false);
// set whether the plugin should compress the
// output of its collected data
setCompressOutput(false);
}
}
CustomPluginResource.java
package com.ptc.customersupport.mbeans.plugins;
import wt.util.resource.RBEntry;
import wt.util.resource.RBUUID;
import wt.util.resource.WTListResourceBundle;
@RBUUID("com.ptc.customersupport.mbeans.plugins.CustomPluginResource")
public class CustomPluginResource extends WTListResourceBundle{
@RBEntry("My Custom Plugin")
public static final String CUSTOM_PLUGIN_NAME = "0";

@RBEntry("A plugin that does xyz.")
public static final String CUSTOM_PLUGIN_DESC = "1";
}
TomcatConfigPropertiesPlugin.java
下面是用于收集 installedProduct.location.Tomcat (此为 wt.property 值) 位置处的 config.properties 文件的示例代码。为简便起见,未本地化该插件。
package demo;
import java.util.Map;
import javax.management.NotCompliantMBeanException;
import org.apache.logging log4j.Logger;
import wt.log4j.LogR;
import com.ptc.customersupport.mbeans.PluginType;
import com.ptc.customersupport.mbeans.plugins.GatherFilePlugin;

/**
* A sample Plugin that gathers the Tomcat config.properties file.
* The location of this file is controlled by the location of
* Tomcat on an installed system. Generally, this location is
* <Windchill>/tomcat/config.properties. However, there exists a
* wt.property which points to where the tomcat instance is
* installed. This property is installed.Product.location.Tomcat,
* and it is used to build a tokenized path to the location of the
* config.properties file.
* <BR><BR>
* This class extends the
* {@link com.ptc.customersupport.mbeans.files.GatherFilePlugin
* GatherFilePlugin} which is used to provide functionality that is
* already implemented that this Plugin can rely upon for default
* behavior. Most plugins will be able to make use of existing
* Abstract plugin classes for much of their behavior and method
* implementations. See the
* {@link com.ptc.customersupport.mbeans.files.GatherFilePlugin
* GatherFilePlugin} for more infomration on the parent class of
* this Plugin and it's methods.
* <BR><BR>
*/
public class TomcatConfigPropertiesPlugin extends GatherFilePlugin {
/*
* Optionally provide some form of localization for plugin strings.
*
* In order to localize the values like name, description,
* and version, follow these steps:
*
* 1. Create a tomcatConfigPropertiesPluginResource.rbInfo
* file with the correct values.
*
* 2. Get an instance of a ResouceBundle like this: private static
* ResourceBundle RESOURCE =
* ResourceBundle.getBundle(
* tomcatConfigPropertiesPluginResource.class.getName());
*
* 3. Set the name (or other value) like this:
* setDisplayName(MBeanUtilities.formatMessage(
* RESOURCE.getString(
* tomcatConfigPropertiesPluginResource.
* PLUGIN_DISPLAY_NAME)));
*/

// Set member variables for ease of use.
private static final String TCP_PLUGIN_NAME =
"Tomcat Property Config File";
private static final String TCP_PLUGIN_DESCRIPTION =
"<tomcat_home>/config.properties file.";
/*
* Optionally, provide some logging capabilities. Doing so
* can facilitate easier Plugin debugging or provide
* status/information messages to the running servers.
*/
private static final Logger logger = LogR.getLoggerInternal(
TomcatConfigPropertiesPlugin.class.getName());
/**
* Default constructor that sets all the required values.
*/
public TomcatConfigPropertiesPlugin() throws
NotCompliantMBeanException {
/*
* The operator call to super() allows the
* TomcatConfigPropertiesPlugin to rely on the parent class for
* much of the Plugin initialization. This call will set
* default values which are later overridden as necessary. This
* also sets up and initializes this Plugin as a SelfAwareMBean
* as the inheritance hierarchy eventually reaches
* AbstractPlugin.
*/
super();
/*
* This method call is simply for convenience of setting
* all the Plugin values in one place that we are
* overriding the default values for which were set when
* super() was called.
*/
initializeMBeanAttributes();
}

/**
* Initializes all the Plugin values for this specific Plugin.
* Those values which were initially set by parent classes are
* overidden.
*/
private void initializeMBeanAttributes() {
// Log a debug message that the Plugin is being initialized.
if (logger.isDebugEnabled()) {
logger.debug("Initializing " + TCP_PLUGIN_NAME + "" +
" Plugin.");
}
/*
* Set the attribute values that are common to all Plugins,
* regardless of the PluginType.
*/
// The name that will be used for this Plugin.
setDisplayName(TCP_PLUGIN_NAME);
// The description that will be displayed for this Plugin.
setDescription(TCP_PLUGIN_DESCRIPTION);
// Set the MBean ObjectName.
setMBeanName("TomcatConfigProperties");
/*
* Set the PluginType value. This will control where the
* data is collected to in terms of directory structure.
*/
setPluginType(PluginType.PROPERTY);
// Set the Plugin version information.
setPluginVersion("1.0");

/*
* Set the file name that we want to collect. This value
* overrides the default value set by the parent. The
* GatherFilePluginMBean Interface of the parent class
* specifies this method must be implemented. Since we
* are extending the parent class and want to collect a
* specific file (not the default file the parent specifies)
* we override the value and set it to the location:
* $(installedProduct.location.Tomcat)$(dir.sep)
* config.properties
*
* This is a tokenized wt.property value. When the
* collection framework operates on this Plugin, these
* tokenized values are replaced by their canonicalized
* paths and a file path results. This is how the collection
* framework knows where to find files to collect. Ideally
* tokenized or property values should be used to create
* a path to the file. If hard-coded file paths are used
* the Plugin will not operate across a cluster correctly.
*/
setFileName("$(installedProduct.location.Tomcat)" +
"$(dir.sep)config.properties");
}

/**
* Override the collect methods as needed. Incidentally, this
* Plugin does not dictate the collect(...) methods be
* overridden. The implementation of this method is actually
* the same as the parent implementation. However, for clarity
* of the example the collect(...) methods are shown.
*/
@Override
public Map<String, Object> collect(final long callNumber,
final long maxAgeInDays, final long minAgeInDays,
final String pathTimeStamp) {
/*
* Here we call the collectData(...) method of AbstractPlugin
* which will handle the actual collecting of the file
* specified as the first parameter. Here the first parameter
* is returned by the getFileName() method of the parent
* class.
*
* The collectData method sets up and hides all the complexity
* of using the collection framework and allows a developer to
* avoid implementing a specific collect(...) implementation.
*
* However, there are instances when certain Plugins require
* specific collect(...) method behavior, these instances
* are usually reserved for very advanced Plugins.
*/
return collectData(getFileName(), callNumber, maxAgeInDays,
minAgeInDays, pathTimeStamp);
}
@Override
public Map<String, Object> collect(final String topicIdentifier,
final long maxAgeInDays, final long minAgeInDays,
final String pathTimeStamp) {
return collectData(getFileName(), topicIdentifier,
maxAgeInDays, minAgeInDays, pathTimeStamp);
}
}
Windchill 代码中的使用示例
com.ptc.customersupport.mbeans 包
此 Java 包中包含 AbstractPluginPluginMBean 接口。其中还包含可用于创建插件的其他实用程序类,例如 PluginType.javaPluginUtilities.java
com.ptc.customersupport.mbeans.plugin 包
此 Java 包中包含多个抽象类,可在 UML 图表中进行查看;有关详细信息,请参阅“解决方案元素”。此包中包含
com.ptc.customersupport.mbeans.plugin.logs 包
此 Java 包中包含 PluginType 日志的具体插件实现。这些插件通常负责收集日志文件。Log4jFilesPluginWindchillLogsPluginWDSLogsPlugin 示例在复杂性方面有所不同。
com.ptc.customersupport.mbeans.plugin.misc 包
此 Java 包中包含有关 PluginType 杂项的具体插件实现。这些插件通常负责收集杂项信息。UpgradeFolderPluginMigrationReportsFolderPluginWtSafeAreaFolderPlugin 示例在复杂性方面有所不同。
com.ptc.customersupport.mbeans.plugin.properties 包
此 Java 包中包含 PluginType 特性的具体插件实现。这些插件通常负责收集特性文件。DbPropertiesPluginDeclarationsXconfPluginIePropertiesPlugin 示例在复杂性方面有所不同。
com.ptc.customersupport.mbeans.plugin.third 包
此 Java 包中包含有关 PluginType 第三方的具体插件实现。这些插件通常负责收集第三方产品信息。ApacheConfFolderPluginApacheLogsPluginCogStartupXmlPlugin 示例在复杂性方面有所不同。
com.ptc.customersupport.mbeans.plugin.util 包
此 Java 包中包含有关 PluginType 实用程序的具体插件实现。这些插件通常负责收集实用程序信息。GatherInfoScriptPluginMBeanDumpPluginWDSMBeanDumpPlugin 示例在复杂性方面有所不同。
MBeanDumpPlugin.java 是一个复杂插件,此插件并不依赖于抽象类的 collect(...) 方法实现。可对此插件进行检查,以便更深入地了解如何创建实现 collect(...) 方法的复杂插件,以便这些插件不直接使用 collect(...) 方法的抽象类实现或收集框架。
随附的示例
PTC 提供封装的插件示例代码,该代码位于 <Windchill>\utilities\SystemConfigurationCollector\plugins\examples 目录中。此目录包含用于维护封装在示例子目录中的 com.ptc.customersupport.* 的封装示例。可对其进行检查,以了解如何在插件内部使用 SQL、QML、Java 命令等。
更多资源
相关的包/类 Javadoc
com.ptc.customersupport.mbeans* 包中包含 Java 插件接口、可提供通用功能的多个抽象插件以及具体插件实现。
相关 Windchill 文档
有关系统配置收集器及其使用方法的详细信息,请参阅系统配置收集器
相关网站
Java Jar 服务提供者规范:
Java Jar 文件规范:
Java MBean 对象名称:
Java 编译:
Java Jar 命令:
这对您有帮助吗?