TIS Plugin Creator
This skill helps you create a well-structured TIS (Data Integration Service) plugin that conforms to all TIS plugin specifications.
What This Skill Does
When invoked, this skill will:
- Analyze the user-provided context to understand the plugin's functionality
- Design the plugin structure with appropriate properties (general or aggregated)
- Generate the complete plugin implementation including:
- Main plugin class implementing
Describable
- Inner
Descriptor class with @TISExtension
- Properties with proper
@FormField annotations
- Property validation methods
- Corresponding
.json property descriptor file
- Optional
.md help documentation
TIS Plugin Specifications
Core Requirements
Every TIS plugin MUST satisfy:
Implement Describable Interface
- Plugin class must implement
com.qlangtech.tis.extension.Describable (directly or via parent)
Inner Descriptor Class
- Must have a
public inner class extending com.qlangtech.tis.extension.Descriptor
- Annotated with
@TISExtension from com.qlangtech.tis.extension.TISExtension
Property Requirements
- All properties must be
public
- Must be annotated with
@FormField
Property Descriptor Files
- A
.json file in the same package under resources/ directory
- Optional
.md file for rich markdown help content
Property Types
General Properties
Basic Java types:
Boolean / boolean
Integer / int
String
Long / long
java.util.Date
com.qlangtech.tis.plugin.MemorySize
- Duration types
Aggregated Properties
Properties that are themselves Describable plugins, providing polymorphic capability. Example: ClusterType in TISFlinkCDCStreamFactory.
IMPORTANT: Each concrete implementation class of an aggregated property is a full plugin and MUST have:
- Its own Java class with
@FormField properties
- Its own
@TISExtension Descriptor
- Descriptor MUST implement
DescriptorUseableShortComment interface (from tis-plugin/src/main/java/com/qlangtech/tis/extension/DescriptorUseableShortComment.java)
- Implement
shortComment() method returning a brief Chinese description of the plugin's function
- Requirements for shortComment():
- Use Chinese language (中文)
- Maximum 10 characters (10个字以内)
- NO punctuation marks (no periods, commas, etc.)
- Will be displayed in the frontend UI to help users understand the plugin at a glance
- Example: "Hadoop文件系统管理" or "Hive元数据存储"
- Its own
.json descriptor file in resources (same package path)
- Optional
.md help file if properties are complex
Parent Class Requirements for Aggregated Properties:
- If an aggregated property type (e.g.,
IcebergCatalog) will have multiple concrete implementations, the parent abstract class MUST define a BasicDescriptor:
- Must be a protected abstract static inner class
- Must extend
Descriptor<ParentClassName>
- All concrete implementation classes' Descriptors MUST extend this
BasicDescriptor
- Example structure in parent class:
public abstract class IcebergCatalog implements Describable<IcebergCatalog> {
// properties...
protected abstract static class BasicDescriptor extends Descriptor<IcebergCatalog> {
// common descriptor logic for all implementations
}
}
- Example in implementation class:
public class HadoopCatalog extends IcebergCatalog {
// properties...
@TISExtension()
public static class DefaultDescriptor extends BasicDescriptor
implements DescriptorUseableShortComment {
@Override
public String shortComment() {
return "基于HDFS文件系统";
}
@Override
public String getDisplayName() {
return "Hadoop Catalog";
}
}
}
Example: If DataxIcebergWriter has an aggregated property IcebergCatalog catalog, and HadoopCatalog extends IcebergCatalog, then you need:
IcebergCatalog.java (abstract parent with protected abstract static BasicDescriptor inner class)
HadoopCatalog.java (with its own @FormField properties, Descriptor extends BasicDescriptor)
HadoopCatalog.json (describing HadoopCatalog's own properties)
- Descriptor implements
DescriptorUseableShortComment with shortComment() returning Chinese text (≤10 chars, no punctuation)
- Optional
HadoopCatalog.md (if properties are complex)
@FormField Annotation Attributes
- identity: Unique identifier for the plugin instance (acts as primary key)
- ordinal: Display order in UI form (lower = higher priority, semantically related fields should be adjacent)
- advance: Mark as advanced setting (must have default value, can be hidden)
- validate: Frontend validation rules (see Validator options below)
- type: Field type (see FormFieldType options below)
Validator Options
Reference: tis-plugin/src/main/java/com/qlangtech/tis/plugin/annotation/Validator.java
require: Required field
user_name: Username format (letters, numbers, underscore, dot, dash)
email: Email format
forbid_start_with_number: Cannot start with number
identity: Primary key format
integer: Integer format
host: Internet domain with optional port (e.g., 192.168.28.200:7070)
hostWithoutPort: Domain without port
url: URL starting with http/https
db_col_name: Database column name format
relative_path: File system relative path
absolute_path: Unix absolute path
none_blank: Non-empty content
FormFieldType Options
Reference: tis-plugin/src/main/java/com/qlangtech/tis/plugin/annotation/FormFieldType.java
MULTI_SELECTABLE: Multi-select, property type List<IdentityName> or List<String>
INPUTTEXT: Single-line text input, property type String
SELECTABLE: Single-select dropdown (register options via registerSelectOptions() in Descriptor)
PASSWORD: Password input
FILE: File upload (only one per form, plugin must implement ITmpFileStore)
TEXTAREA: Multi-line text input (for SQL scripts, XML, etc.)
DATE: Date picker
JDBCColumn: JDBC column type
INT_NUMBER: Integer number input
ENUM: Enumeration selection
DateTime: Date-time (UTC, property type long or java.util.Date)
DECIMAL_NUMBER: Decimal number
DURATION_OF_SECOND: Duration in seconds
DURATION_OF_MINUTE: Duration in minutes
DURATION_OF_HOUR: Duration in hours
MEMORY_SIZE_OF_BYTE: Memory size in bytes
MEMORY_SIZE_OF_KIBI: Memory size in KB
MEMORY_SIZE_OF_MEGA: Memory size in MB
Validation Logic
Single Property Validation
Add a method in Descriptor with pattern validate{PropertyName}:
public boolean validateAge(IFieldErrorHandler msgHandler, Context context, String fieldName, String value) {
int age = Integer.parseInt(value);
if (age < MIN_AGE) {
msgHandler.addFieldError(context, fieldName, "Cannot be less than: " + MIN_AGE);
return false;
}
if (age > MAX_AGE) {
msgHandler.addFieldError(context, fieldName, "Cannot be greater than: " + MAX_AGE);
return false;
}
return true;
}
Multi-Property Joint Validation
Override validateAll in Descriptor:
@Override
protected boolean validateAll(IControlMsgHandler msgHandler, Context context, PostFormVals postFormVals) {
// Perform joint validation
if (!validateUserCredentials(postFormVals.newInstance())) {
msgHandler.addErrorMessage(context, "Validation failed");
return false;
}
return true;
}
Reference Implementations
Excellent examples in the codebase:
tis-plugin/src/main/java/com/qlangtech/tis/config/authtoken/impl/DefaultHiveUserToken.java
tis-plugin/src/main/java/com/qlangtech/tis/manage/common/UserProfile.java
tis-plugin/src/main/java/com/qlangtech/tis/plugin/alert/impl/LoginPlugin.java (multi-property validation)
Instructions for Claude
When the user invokes /create-plugin, follow this workflow:
Step 1: Analyze Context
- Ask the user to provide context about the plugin they want to create (or the user may provide it directly)
- Analyze the context to determine:
- Plugin's purpose and functionality
- What properties are needed (general vs aggregated)
- Parent class to extend (if any)
- Validation rules required
Step 2: Design Plugin Structure
- Determine property organization:
- Which properties should be general types?
- Which properties should be aggregated (polymorphic)?
- For each aggregated property:
- Will it have multiple concrete implementations?
- If yes, the parent abstract class MUST define a
BasicDescriptor inner class
- List all planned implementation classes
- Group semantically related properties via ordinal ordering
- Plan validation logic:
- Which properties need business logic validation?
- Are there any multi-property joint validations?
Step 3: Confirm Design with User
Before implementation, present:
- Plugin class name and package
- List of properties with types, FormFieldType, and validators
- Any aggregated properties and their subtypes (each subtype will be a separate plugin with its own files)
- For each aggregated property subtype, list:
- Subtype class name and parent class
- Its own properties with types and validators
- Files to be generated (Java + JSON + optional MD)
- Validation methods to be implemented
- Wait for user approval
Step 4: Implement Plugin
Generate these files in the correct structure:
Plugin Java Class
- Package declaration
- Imports
- Plugin class implementing
Describable<PluginClassName>
- Public properties with
@FormField annotations
- Business logic methods
- Inner
Descriptor class with:
@TISExtension annotation
getDisplayName() override
validate* methods for property validation
validateAll() if needed for joint validation
registerSelectOptions() if using SELECTABLE fields
Property Descriptor JSON (PluginClassName.json)
- CRITICAL: Correct JSON Format
{
"propertyName1": {
"label": "Display Label",
"placeholder": "Input placeholder text",
"help": "Short one-sentence help text",
"dftVal": "default value"
},
"propertyName2": {
"label": "Another Property",
"help": "Brief description"
}
}
- WRONG Format (DO NOT USE):
{
"formFields": [
{"key": "propertyName1", "label": "...", "help": "..."}
]
}
- In
src/main/resources/{package_path}/
- Direct object-to-object mapping (propertyName → property descriptor)
- Each property descriptor contains:
label: Display label (required)
placeholder: Input placeholder (optional, applicable for text inputs)
help: Brief one-sentence help text (optional, for simple properties)
dftVal: Default value (optional, for optional fields)
Optional Markdown Help (PluginClassName.md)
- Create ONLY for properties that need detailed multi-line explanation
- Help Information Distribution Rule:
- Simple properties (username, password, port, simple flags): Only define
help in JSON file with one sentence
- Complex properties (catalog types, file formats, configuration objects, properties needing examples): Define detailed help in
.md file with ## propertyName headers
- DO NOT duplicate: If a property has detailed help in
.md file, keep JSON help brief or omit it
- Decision criteria for .md file:
- Property requires multiple sentences to explain
- Property needs code examples or configuration samples
- Property has multiple options that need detailed comparison
- Property involves technical concepts requiring elaboration
- Use
## propertyName headers for each complex property that needs detailed documentation
For Aggregated Properties: Parent Abstract Class
- IMPORTANT: If the plugin has aggregated properties with multiple implementations, first create or verify the parent abstract class:
Parent Abstract Class (e.g., IcebergCatalog.java)
- Implements
Describable<ParentClassName>
- Has
@FormField properties that are common to all implementations
- MUST define a
BasicDescriptor inner class:
- Declared as
protected abstract static class BasicDescriptor extends Descriptor<ParentClassName>
- Contains common descriptor logic for all implementations
- May implement common validation methods
- Example:
public abstract class IcebergCatalog implements Describable<IcebergCatalog> {
@FormField(ordinal = 1, validate = {Validator.require})
public String catalogName;
@FormField(ordinal = 2)
public String databaseName;
// abstract methods...
protected abstract static class BasicDescriptor extends Descriptor<IcebergCatalog> {
// common descriptor logic
@Override
protected boolean verify(IFieldErrorHandler msgHandler, Context context, PostFormVals postFormVals) {
return super.verify(msgHandler, context, postFormVals);
}
}
}
For Each Aggregated Property Implementation Class
- IMPORTANT: If the plugin has aggregated properties (polymorphic plugin properties), EACH concrete implementation class is a separate plugin and needs:
Example: Main plugin DataxIcebergWriter has property IcebergCatalog catalog, and you're creating HadoopCatalog extends IcebergCatalog:
a. Implementation Java Class (HadoopCatalog.java)
- Extends the abstract parent class (e.g.,
IcebergCatalog)
- Has its own
@FormField properties (in addition to inherited ones)
- Has its own
@TISExtension Descriptor that:
- MUST extend parent's BasicDescriptor
- MUST implement
DescriptorUseableShortComment interface
- MUST override
shortComment() method with these requirements:
- Return Chinese text (中文) describing the plugin function
- Maximum 10 characters (10个字以内)
- NO punctuation marks (不要标点符号)
- Be concise and clear
- Example for HadoopCatalog:
return "基于HDFS文件系统";
- Example for HiveMetastoreCatalog:
return "使用Hive元数据";
- Override
getDisplayName() if needed
- Same structure as main plugin
b. Implementation JSON Descriptor (HadoopCatalog.json)
- In
src/main/resources/{package_path}/ (same package as HadoopCatalog.java)
- Describes only HadoopCatalog's own properties (not inherited ones)
- Same format rules as main plugin JSON
- Example:
{
"warehouse": {
"label": "Warehouse Path",
"help": "HDFS or local filesystem path"
},
"hadoopConfDir": {
"label": "Hadoop Config Directory",
"help": "Path to Hadoop configuration directory"
}
}
c. Optional Implementation MD (HadoopCatalog.md)
- Create if HadoopCatalog has complex properties
- Same rules as main plugin MD file
d. Repeat for ALL implementation classes
- If there's also
HiveMetastoreCatalog, create its Java + JSON + optional MD
- If there's
GlueCatalog, create its Java + JSON + optional MD
- Each implementation is a complete plugin with full file set
Step 5: Verify Implementation
- Check all requirements are satisfied:
- Implements
Describable
- Has
@TISExtension inner Descriptor
- All properties are public with
@FormField
- Ordinal values are properly sequenced
- Validation rules are appropriate
- JSON descriptor format is correct (object-to-object, NOT formFields array)
- All properties in JSON file exist as public fields in Java class
- Help information distribution is correct:
- Simple properties: only
help in JSON (one sentence)
- Complex properties: detailed help in
.md file, brief or no help in JSON
- No duplicate help content between JSON and .md files
- For aggregated properties:
- Parent abstract class requirements:
- Has a
protected abstract static class BasicDescriptor extends Descriptor<ParentClass>
- BasicDescriptor is properly defined in the parent class
- Each implementation class has its complete file set:
- Java class exists with @TISExtension Descriptor
- Descriptor extends parent's BasicDescriptor
- Descriptor implements
DescriptorUseableShortComment interface
shortComment() method implemented correctly:
- Returns Chinese text (中文)
- Length ≤ 10 characters
- No punctuation marks
- Clearly describes the plugin's function
- JSON descriptor exists in correct resources path
- JSON describes only the implementation's own properties (not inherited ones)
- Optional MD file if implementation has complex properties
- Suggest any improvements
Step 6: Provide Usage Instructions
- Explain where the plugin files were created
- How to build and test the plugin
- How to register the plugin in TIS (if special steps needed)
Important Considerations
JSON Format (CRITICAL): The property descriptor JSON file MUST use object-to-object format, NOT array format.
- ✅ Correct:
{"propertyName": {"label": "...", "help": "..."}}
- ❌ Wrong:
{"formFields": [{"key": "propertyName", ...}]}
- Wrong format will cause TIS backend to fail loading the plugin
Help Information Distribution: Avoid duplicating help content between JSON and .md files.
- Simple properties (username, password, port, boolean flags): Use only JSON
help field with one concise sentence
- Complex properties (catalog types, configuration objects, properties with multiple options): Use .md file with detailed explanation, keep JSON
help brief or omit it
- Rule of thumb: If explanation fits in one sentence, use JSON only. If it needs examples, bullet points, or multiple paragraphs, use .md file
- Let the AI judge the complexity: analyze each property's nature and decide the appropriate help placement
Ordinal Sequencing: Assign ordinal values carefully. Related properties (like username/password) should have consecutive ordinals to appear together in the UI.
Default Values: Advanced properties (with advance = true) MUST have sensible default values.
Validation: Always implement business logic validation for properties that need it. Don't rely solely on frontend validation.
Parent Classes: Check if there's an appropriate parent class to extend (like AlertChannel for alert plugins) to inherit common functionality.
Package Organization: Place the plugin in the appropriate package that reflects its functionality (e.g., alert plugins in *.plugin.alert.impl.*).
Example Interaction
User: /create-plugin
I want to create an email alert channel plugin for TIS. It should support:
- SMTP host and port
- Authentication (username/password)
- SSL support
- Sender email address
1---2name: create-plugin3description: Create a TIS plugin conforming to TIS plugin specifications4---56# TIS Plugin Creator78This skill helps you create a well-structured TIS (Data Integration Service) plugin that conforms to all TIS plugin specifications.910## What This Skill Does1112When invoked, this skill will:131. Analyze the user-provided context to understand the plugin's functionality142. Design the plugin structure with appropriate properties (general or aggregated)153. Generate the complete plugin implementation including:16 - Main plugin class implementing `Describable`17 - Inner `Descriptor` class with `@TISExtension`18 - Properties with proper `@FormField` annotations19 - Property validation methods20 - Corresponding `.json` property descriptor file21 - Optional `.md` help documentation2223## TIS Plugin Specifications2425### Core Requirements2627Every TIS plugin MUST satisfy:28291. **Implement Describable Interface**30 - Plugin class must implement `com.qlangtech.tis.extension.Describable` (directly or via parent)31322. **Inner Descriptor Class**33 - Must have a `public` inner class extending `com.qlangtech.tis.extension.Descriptor`34 - Annotated with `@TISExtension` from `com.qlangtech.tis.extension.TISExtension`35363. **Property Requirements**37 - All properties must be `public`38 - Must be annotated with `@FormField`39404. **Property Descriptor Files**41 - A `.json` file in the same package under `resources/` directory42 - Optional `.md` file for rich markdown help content4344### Property Types4546#### General Properties47Basic Java types:48- `Boolean` / `boolean`49- `Integer` / `int`50- `String`51- `Long` / `long`52- `java.util.Date`53- `com.qlangtech.tis.plugin.MemorySize`54- Duration types5556#### Aggregated Properties57Properties that are themselves `Describable` plugins, providing polymorphic capability. Example: `ClusterType` in `TISFlinkCDCStreamFactory`.5859**IMPORTANT**: Each concrete implementation class of an aggregated property is a full plugin and MUST have:60- Its own Java class with `@FormField` properties61- Its own `@TISExtension` Descriptor62- **Descriptor MUST implement `DescriptorUseableShortComment` interface** (from `tis-plugin/src/main/java/com/qlangtech/tis/extension/DescriptorUseableShortComment.java`)63 - Implement `shortComment()` method returning a **brief Chinese description** of the plugin's function64 - **Requirements for shortComment()**:65 - Use Chinese language (中文)66 - **Maximum 10 characters** (10个字以内)67 - **NO punctuation marks** (no periods, commas, etc.)68 - Will be displayed in the frontend UI to help users understand the plugin at a glance69 - Example: "Hadoop文件系统管理" or "Hive元数据存储"70- Its own `.json` descriptor file in resources (same package path)71- Optional `.md` help file if properties are complex7273**Parent Class Requirements for Aggregated Properties**:74- If an aggregated property type (e.g., `IcebergCatalog`) will have multiple concrete implementations, the **parent abstract class MUST define a `BasicDescriptor`**:75 - Must be a **protected abstract static** inner class76 - Must extend `Descriptor<ParentClassName>`77 - All concrete implementation classes' Descriptors MUST extend this `BasicDescriptor`78 - Example structure in parent class:79 ```java80 public abstract class IcebergCatalog implements Describable<IcebergCatalog> {81 // properties...82 83 protected abstract static class BasicDescriptor extends Descriptor<IcebergCatalog> {84 // common descriptor logic for all implementations85 }86 }87 ```88 - Example in implementation class:89 ```java90 public class HadoopCatalog extends IcebergCatalog {91 // properties...92 93 @TISExtension()94 public static class DefaultDescriptor extends BasicDescriptor 95 implements DescriptorUseableShortComment {96 @Override97 public String shortComment() {98 return "基于HDFS文件系统";99 }100 101 @Override102 public String getDisplayName() {103 return "Hadoop Catalog";104 }105 }106 }107 ```108109Example: If `DataxIcebergWriter` has an aggregated property `IcebergCatalog catalog`, and `HadoopCatalog` extends `IcebergCatalog`, then you need:110- `IcebergCatalog.java` (abstract parent with protected abstract static BasicDescriptor inner class)111- `HadoopCatalog.java` (with its own @FormField properties, Descriptor extends BasicDescriptor)112- `HadoopCatalog.json` (describing HadoopCatalog's own properties)113- Descriptor implements `DescriptorUseableShortComment` with `shortComment()` returning Chinese text (≤10 chars, no punctuation)114- Optional `HadoopCatalog.md` (if properties are complex)115116### @FormField Annotation Attributes117118- **identity**: Unique identifier for the plugin instance (acts as primary key)119- **ordinal**: Display order in UI form (lower = higher priority, semantically related fields should be adjacent)120- **advance**: Mark as advanced setting (must have default value, can be hidden)121- **validate**: Frontend validation rules (see Validator options below)122- **type**: Field type (see FormFieldType options below)123124### Validator Options125126Reference: `tis-plugin/src/main/java/com/qlangtech/tis/plugin/annotation/Validator.java`127128- `require`: Required field129- `user_name`: Username format (letters, numbers, underscore, dot, dash)130- `email`: Email format131- `forbid_start_with_number`: Cannot start with number132- `identity`: Primary key format133- `integer`: Integer format134- `host`: Internet domain with optional port (e.g., `192.168.28.200:7070`)135- `hostWithoutPort`: Domain without port136- `url`: URL starting with http/https137- `db_col_name`: Database column name format138- `relative_path`: File system relative path139- `absolute_path`: Unix absolute path140- `none_blank`: Non-empty content141142### FormFieldType Options143144Reference: `tis-plugin/src/main/java/com/qlangtech/tis/plugin/annotation/FormFieldType.java`145146- `MULTI_SELECTABLE`: Multi-select, property type `List<IdentityName>` or `List<String>`147- `INPUTTEXT`: Single-line text input, property type `String`148- `SELECTABLE`: Single-select dropdown (register options via `registerSelectOptions()` in Descriptor)149- `PASSWORD`: Password input150- `FILE`: File upload (only one per form, plugin must implement `ITmpFileStore`)151- `TEXTAREA`: Multi-line text input (for SQL scripts, XML, etc.)152- `DATE`: Date picker153- `JDBCColumn`: JDBC column type154- `INT_NUMBER`: Integer number input155- `ENUM`: Enumeration selection156- `DateTime`: Date-time (UTC, property type `long` or `java.util.Date`)157- `DECIMAL_NUMBER`: Decimal number158- `DURATION_OF_SECOND`: Duration in seconds159- `DURATION_OF_MINUTE`: Duration in minutes160- `DURATION_OF_HOUR`: Duration in hours161- `MEMORY_SIZE_OF_BYTE`: Memory size in bytes162- `MEMORY_SIZE_OF_KIBI`: Memory size in KB163- `MEMORY_SIZE_OF_MEGA`: Memory size in MB164165### Validation Logic166167#### Single Property Validation168169Add a method in Descriptor with pattern `validate{PropertyName}`:170171```java172public boolean validateAge(IFieldErrorHandler msgHandler, Context context, String fieldName, String value) {173 int age = Integer.parseInt(value);174 if (age < MIN_AGE) {175 msgHandler.addFieldError(context, fieldName, "Cannot be less than: " + MIN_AGE);176 return false;177 }178 if (age > MAX_AGE) {179 msgHandler.addFieldError(context, fieldName, "Cannot be greater than: " + MAX_AGE);180 return false;181 }182 return true;183}184```185186#### Multi-Property Joint Validation187188Override `validateAll` in Descriptor:189190```java191@Override192protected boolean validateAll(IControlMsgHandler msgHandler, Context context, PostFormVals postFormVals) {193 // Perform joint validation194 if (!validateUserCredentials(postFormVals.newInstance())) {195 msgHandler.addErrorMessage(context, "Validation failed");196 return false;197 }198 return true;199}200```201202## Reference Implementations203204Excellent examples in the codebase:2051. `tis-plugin/src/main/java/com/qlangtech/tis/config/authtoken/impl/DefaultHiveUserToken.java`2062. `tis-plugin/src/main/java/com/qlangtech/tis/manage/common/UserProfile.java`2073. `tis-plugin/src/main/java/com/qlangtech/tis/plugin/alert/impl/LoginPlugin.java` (multi-property validation)208209## Instructions for Claude210211When the user invokes `/create-plugin`, follow this workflow:212213### Step 1: Analyze Context214- Ask the user to provide context about the plugin they want to create (or the user may provide it directly)215- Analyze the context to determine:216 - Plugin's purpose and functionality217 - What properties are needed (general vs aggregated)218 - Parent class to extend (if any)219 - Validation rules required220221### Step 2: Design Plugin Structure222- Determine property organization:223 - Which properties should be general types?224 - Which properties should be aggregated (polymorphic)?225 - **For each aggregated property**:226 - Will it have multiple concrete implementations?227 - If yes, the parent abstract class MUST define a `BasicDescriptor` inner class228 - List all planned implementation classes229 - Group semantically related properties via ordinal ordering230- Plan validation logic:231 - Which properties need business logic validation?232 - Are there any multi-property joint validations?233234### Step 3: Confirm Design with User235Before implementation, present:236- Plugin class name and package237- List of properties with types, FormFieldType, and validators238- **Any aggregated properties and their subtypes** (each subtype will be a separate plugin with its own files)239- For each aggregated property subtype, list:240 - Subtype class name and parent class241 - Its own properties with types and validators242 - Files to be generated (Java + JSON + optional MD)243- Validation methods to be implemented244- Wait for user approval245246### Step 4: Implement Plugin247Generate these files in the correct structure:2482491. **Plugin Java Class**250 - Package declaration251 - Imports252 - Plugin class implementing `Describable<PluginClassName>`253 - Public properties with `@FormField` annotations254 - Business logic methods255 - Inner `Descriptor` class with:256 - `@TISExtension` annotation257 - `getDisplayName()` override258 - `validate*` methods for property validation259 - `validateAll()` if needed for joint validation260 - `registerSelectOptions()` if using SELECTABLE fields2612622. **Property Descriptor JSON** (`PluginClassName.json`)263 - **CRITICAL: Correct JSON Format**264 ```json265 {266 "propertyName1": {267 "label": "Display Label",268 "placeholder": "Input placeholder text",269 "help": "Short one-sentence help text",270 "dftVal": "default value"271 },272 "propertyName2": {273 "label": "Another Property",274 "help": "Brief description"275 }276 }277 ```278 - **WRONG Format** (DO NOT USE):279 ```json280 {281 "formFields": [282 {"key": "propertyName1", "label": "...", "help": "..."}283 ]284 }285 ```286 - In `src/main/resources/{package_path}/`287 - Direct object-to-object mapping (propertyName → property descriptor)288 - Each property descriptor contains:289 - `label`: Display label (required)290 - `placeholder`: Input placeholder (optional, applicable for text inputs)291 - `help`: Brief one-sentence help text (optional, for simple properties)292 - `dftVal`: Default value (optional, for optional fields)2932943. **Optional Markdown Help** (`PluginClassName.md`)295 - **Create ONLY for properties that need detailed multi-line explanation**296 - **Help Information Distribution Rule**:297 - **Simple properties** (username, password, port, simple flags): Only define `help` in JSON file with one sentence298 - **Complex properties** (catalog types, file formats, configuration objects, properties needing examples): Define detailed help in `.md` file with `## propertyName` headers299 - **DO NOT duplicate**: If a property has detailed help in `.md` file, keep JSON `help` brief or omit it300 - **Decision criteria for .md file**:301 - Property requires multiple sentences to explain302 - Property needs code examples or configuration samples303 - Property has multiple options that need detailed comparison304 - Property involves technical concepts requiring elaboration305 - Use `## propertyName` headers for each complex property that needs detailed documentation3063074. **For Aggregated Properties: Parent Abstract Class**308 - **IMPORTANT**: If the plugin has aggregated properties with multiple implementations, first create or verify the parent abstract class:309 310 **Parent Abstract Class** (e.g., `IcebergCatalog.java`)311 - Implements `Describable<ParentClassName>`312 - Has `@FormField` properties that are common to all implementations313 - **MUST define a `BasicDescriptor` inner class**:314 - Declared as `protected abstract static class BasicDescriptor extends Descriptor<ParentClassName>`315 - Contains common descriptor logic for all implementations316 - May implement common validation methods317 - Example:318 ```java319 public abstract class IcebergCatalog implements Describable<IcebergCatalog> {320 @FormField(ordinal = 1, validate = {Validator.require})321 public String catalogName;322 323 @FormField(ordinal = 2)324 public String databaseName;325 326 // abstract methods...327 328 protected abstract static class BasicDescriptor extends Descriptor<IcebergCatalog> {329 // common descriptor logic330 @Override331 protected boolean verify(IFieldErrorHandler msgHandler, Context context, PostFormVals postFormVals) {332 return super.verify(msgHandler, context, postFormVals);333 }334 }335 }336 ```3373385. **For Each Aggregated Property Implementation Class**339 - **IMPORTANT**: If the plugin has aggregated properties (polymorphic plugin properties), EACH concrete implementation class is a separate plugin and needs:340 341 **Example**: Main plugin `DataxIcebergWriter` has property `IcebergCatalog catalog`, and you're creating `HadoopCatalog extends IcebergCatalog`:342 343 a. **Implementation Java Class** (`HadoopCatalog.java`)344 - Extends the abstract parent class (e.g., `IcebergCatalog`)345 - Has its own `@FormField` properties (in addition to inherited ones)346 - Has its own `@TISExtension` Descriptor that:347 - **MUST extend parent's BasicDescriptor**348 - **MUST implement `DescriptorUseableShortComment` interface**349 - **MUST override `shortComment()` method** with these requirements:350 - Return Chinese text (中文) describing the plugin function351 - **Maximum 10 characters** (10个字以内)352 - **NO punctuation marks** (不要标点符号)353 - Be concise and clear354 - Example for HadoopCatalog: `return "基于HDFS文件系统";`355 - Example for HiveMetastoreCatalog: `return "使用Hive元数据";`356 - Override `getDisplayName()` if needed357 - Same structure as main plugin358 359 b. **Implementation JSON Descriptor** (`HadoopCatalog.json`)360 - In `src/main/resources/{package_path}/` (same package as HadoopCatalog.java)361 - Describes **only HadoopCatalog's own properties** (not inherited ones)362 - Same format rules as main plugin JSON363 - Example:364 ```json365 {366 "warehouse": {367 "label": "Warehouse Path",368 "help": "HDFS or local filesystem path"369 },370 "hadoopConfDir": {371 "label": "Hadoop Config Directory",372 "help": "Path to Hadoop configuration directory"373 }374 }375 ```376 377 c. **Optional Implementation MD** (`HadoopCatalog.md`)378 - Create if HadoopCatalog has complex properties379 - Same rules as main plugin MD file380 381 d. **Repeat for ALL implementation classes**382 - If there's also `HiveMetastoreCatalog`, create its Java + JSON + optional MD383 - If there's `GlueCatalog`, create its Java + JSON + optional MD384 - Each implementation is a complete plugin with full file set385386### Step 5: Verify Implementation387- Check all requirements are satisfied:388 - Implements `Describable`389 - Has `@TISExtension` inner Descriptor390 - All properties are public with `@FormField`391 - Ordinal values are properly sequenced392 - Validation rules are appropriate393 - **JSON descriptor format is correct** (object-to-object, NOT formFields array)394 - **All properties in JSON file** exist as public fields in Java class395 - **Help information distribution is correct**:396 - Simple properties: only `help` in JSON (one sentence)397 - Complex properties: detailed help in `.md` file, brief or no `help` in JSON398 - No duplicate help content between JSON and .md files399 - **For aggregated properties**: 400 - **Parent abstract class requirements**:401 - Has a `protected abstract static class BasicDescriptor extends Descriptor<ParentClass>`402 - BasicDescriptor is properly defined in the parent class403 - **Each implementation class has its complete file set**:404 - Java class exists with @TISExtension Descriptor405 - **Descriptor extends parent's BasicDescriptor**406 - **Descriptor implements `DescriptorUseableShortComment` interface**407 - **`shortComment()` method implemented correctly**:408 - Returns Chinese text (中文)409 - Length ≤ 10 characters410 - No punctuation marks411 - Clearly describes the plugin's function412 - JSON descriptor exists in correct resources path413 - JSON describes only the implementation's own properties (not inherited ones)414 - Optional MD file if implementation has complex properties415- Suggest any improvements416417### Step 6: Provide Usage Instructions418- Explain where the plugin files were created419- How to build and test the plugin420- How to register the plugin in TIS (if special steps needed)421422## Important Considerations4234241. **JSON Format (CRITICAL)**: The property descriptor JSON file MUST use object-to-object format, NOT array format.425 - ✅ Correct: `{"propertyName": {"label": "...", "help": "..."}}`426 - ❌ Wrong: `{"formFields": [{"key": "propertyName", ...}]}`427 - Wrong format will cause TIS backend to fail loading the plugin4284292. **Help Information Distribution**: Avoid duplicating help content between JSON and .md files.430 - **Simple properties** (username, password, port, boolean flags): Use only JSON `help` field with one concise sentence431 - **Complex properties** (catalog types, configuration objects, properties with multiple options): Use .md file with detailed explanation, keep JSON `help` brief or omit it432 - **Rule of thumb**: If explanation fits in one sentence, use JSON only. If it needs examples, bullet points, or multiple paragraphs, use .md file433 - Let the AI judge the complexity: analyze each property's nature and decide the appropriate help placement4344353. **Ordinal Sequencing**: Assign ordinal values carefully. Related properties (like username/password) should have consecutive ordinals to appear together in the UI.4364374. **Default Values**: Advanced properties (with `advance = true`) MUST have sensible default values.4384395. **Validation**: Always implement business logic validation for properties that need it. Don't rely solely on frontend validation.4404416. **Parent Classes**: Check if there's an appropriate parent class to extend (like `AlertChannel` for alert plugins) to inherit common functionality.4424437. **Package Organization**: Place the plugin in the appropriate package that reflects its functionality (e.g., alert plugins in `*.plugin.alert.impl.*`).444445## Example Interaction446447```448User: /create-plugin449450I want to create an email alert channel plugin for TIS. It should support:451- SMTP host and port452- Authentication (username/password) 453- SSL support454- Sender email address