Advanced Customization > Services and Infrastructure Customization > System Configuration Collector Plugin > Creating a System Configuration Collector Plugin > Procedures – Creating a Custom Plugin > Designing the Plugin
  
Designing the Plugin
There are numerous considerations to take into account when designing a plugin for the System Configuration Collector.
1. It is highly recommended, although not required, that a plugin class name include the word “Plugin”. Including the word “Plugin” as a suffix of the class name easily identifies its purpose. The plugin source file name should be of the form <ClassName>Plugin.java. For practicality, the <ClassName> should allude to the plugins purpose as well. For example, PTC provides a SiteXConfPlugin that collects the <Windchill>/site.xconf file.
2. It is highly recommend that a plugin developer maintain a reasonable Java package structure for their plugins. The PTC provided plugins generally maintain package structures relevant to their purpose and PluginType (see Solution for more information on the PluginType class). Many of the PTC plugins can be found in the package com.ptc.customersupport.mbeans.plugins. Placing custom plugins in this package may allow for easier debugging of custom plugins as well as identifying their locations after deployment. However, this is not a strict requirement and the package structure is left to the developer.
3. All plugins must implement the PluginMBean interface. Implementing the PluginMBean interface class allows a plugin to expose attributes and operations that be executed from a JMX console. In addition, the PluginMBean class enforces an API contract that all plugins must adhere to which is vitally important to the underlying collection framework (see the CollectorMBean and Collector class as noted in Solution).
4. All plugins must extend the AbstractPlugin class. The AbstractPlugin wraps much of the complexity of implementing the PluginMBean interface. It provides default implementations for many methods that are common to creating a plugin. Certainly, the default method implementations can be overridden to provide varying functionality.
For example:
public class CustomPlugin extends AbstractPlugin
implements PluginMBean {}
This example shows a CustomPlugin class that implements the PluginMBean interface and extends the AbstractPlugin class. Note that in this example the required methods of the interface, namely the collect(…) methods, are not implemented and this simple class would not compile. See Sample Code for a complete sample plugin implementation for sample plugins packaged with Windchill.
5. All plugin object constructors must make a method call to its super class. This is to ensure that all plugins initialize as SelfAwareMBeans (see Solution details regarding SelfAwareMBean). Since all plugins must extend the AbstractPlugin class through the plugin hierarchy, the AbstractPlugin class will make the appropriate method calls to register a plugin as a SelfAwareMBean. Therefore, a plugin developer does not need to concern themselves with the actual plugin MBean registration other than ensuring their plugin calls the super() operator during construction and that the plugin inheritance eventually extends AbstractPlugin.java.
For example:
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
}
These constructors are implemented to match the constructors of AbstractPlugin and make calls to AbstractPlugin through the super operator. This causes the CustomPlugin to be registered as a SelfAwarePlugin.
The constructors call to super takes a Class object. If the concrete class is known it can be specified, otherwise null can be used. Java will use Introspection to determine the Class name. For example, since the CustomPlugin implements the PluginMBean the call to super could alternatively be:
super(PluginMBean.class);
See for options to rely on inheritance to design more succinct constructors.
6. Due to implementing the PluginMBean interface and extending AbstractPlugin, a plugin must implement the two collect(…) methods. These are methods that essentially organize and hand-off work to the Collector class and collection framework.
For example:
@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;
}
The collect(…) method implementations shown here do not do anything useful and are merely presented here for clarity. They should do whatever work the plugin collection needs to accomplish and return the correct Map<String, Object> value that is expected.
There are numerous default implementations of the collect(…) methods that can be relied upon through the Abstract classes. Often, a plugin simply needs to call the collectData(…) method of AbstractPlugin.java passing through the parameters of the collect(…) method to the collectData(…) method. The collectData(…) method wraps the complexity of calling the collection framework directly in the collect(…) methods. The collect(…) methods are required by the PluginMBean interface API since the flexibility is necessary to allow a developer to implement the collect(…) methods as necessary since very advanced plugins might desire to avoid using the default behavior of collectData(…). Additionally, the Abstract classes have additional methods that can be relied upon. Many of these methods are of the form collectXYZ(…) that can be called by the collect(…) method implementations of specific plugins. These collect (…) methods wrap the specific collect implementations for the Abstract type of work the plugin does. For example, the GatherFolderPlugin.java class has collect(…) methods that are implemented such that it passes along the specific folder to be collected to the collection framework, provided that folder was correctly set in the plugin initialization.
The collect(…) methods must return a Map<String, Object>. This return Map is what is used by the plugin framework to understand on what server a plugin was executed and the plugins status. This return value is actually a Map inside of a Map; Map<String, Map<String, String>>. The outer Map contains the server information while the inner Map contains the plugin execution status for that server.
If a customizer does not rely on the default implementations of collect(…) methods either through using the parent collectData(…) or other collect(…) methods of Abstract classes one must take extreme care to ensure that the return Map is correctly built and contains valid values.
See Customization Points for additional detail on using default collect(…) implementations as well as greater detail regarding the methods return Map<String, Object> value.
7. The last consideration is what your plugin must do for actual work, and the most appropriate means to accomplish this. This can be accomplished by making numerous classes to work in conjunction with each other or wrapping all execution in one class.
Additionally, there are numerous utility methods and abstract classes, as discussed in Solutionwhich can simplify plugin implementation. However, plugins can be designed to be very complex or very simple depending on the task the plugin is supposed to accomplish.
8. In summary, a properly designed plugin is required to have at least these characteristics:
Implement the PluginMBean interface.
Extend the AbstractPlugin class, either directly or through inheritance.
2 constructors with super() operator calls which eventually lead to AbstractPlugin.
2 collect(…) methods (if not relying on parent collect(…) implementations).