|
| 1 | +# Extension Points |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +Extension Points in ServiceNow provide a powerful mechanism for creating extensible, plugin-based architectures. They allow you to define interfaces that can be implemented by multiple extensions, enabling dynamic behavior selection at runtime without modifying core code. |
| 6 | + |
| 7 | +## What are Extension Points? |
| 8 | + |
| 9 | +Extension Points follow the interface-implementation pattern where: |
| 10 | +- **Extension Point (Interface)**: Defines a contract with methods that implementations must provide |
| 11 | +- **Extensions (Implementations)**: Concrete classes that implement the interface methods |
| 12 | +- **Consumer**: Code that discovers and invokes extensions dynamically using `GlideScriptedExtensionPoint` |
| 13 | + |
| 14 | +This pattern is ideal for: |
| 15 | +- Creating pluggable notification systems |
| 16 | +- Building extensible validation frameworks |
| 17 | +- Implementing strategy patterns |
| 18 | +- Supporting multi-tenant customizations |
| 19 | +- Enabling third-party integrations |
| 20 | + |
| 21 | +## Files in this Directory |
| 22 | + |
| 23 | +### 1. CustomNotificationHandlerInterfaceExtension.js |
| 24 | +Defines the base interface (Extension Point) for notification handlers. |
| 25 | + |
| 26 | +**Key Methods:** |
| 27 | +- `initialize(record, config)`: Constructor for setting up the handler |
| 28 | +- `process()`: Must be implemented - processes the notification |
| 29 | +- `shouldNotify()`: Must be implemented - validates if notification should be sent |
| 30 | +- `handles(notificationSystem)`: Determines if this implementation applies to a specific system |
| 31 | + |
| 32 | +### 2. CustomNotificationHandlerInterfaceImplementation.js |
| 33 | +Concrete implementation of the notification handler interface for email notifications. |
| 34 | + |
| 35 | +**Features:** |
| 36 | +- Email notification processing using `GlideEmailOutbound` |
| 37 | +- Priority-based notification criteria |
| 38 | +- Template-based subject and body generation |
| 39 | +- Error handling and logging |
| 40 | +- Configurable recipients and templates |
| 41 | + |
| 42 | +### 3. ExtensionPointCallingExample.js |
| 43 | +Demonstrates how to discover and invoke extension point implementations dynamically. |
| 44 | + |
| 45 | +**Pattern:** |
| 46 | +```javascript |
| 47 | +var eps = new GlideScriptedExtensionPoint().getExtensions("scope.InterfaceName"); |
| 48 | +for (var i = 0; i < eps.length; i++) { |
| 49 | + if (eps[i].handles("criteria")) { |
| 50 | + eps[i].process(); |
| 51 | + } |
| 52 | +} |
| 53 | +``` |
| 54 | + |
| 55 | +## How to Use Extension Points |
| 56 | + |
| 57 | +### Step 1: Create the Extension Point (Interface) |
| 58 | + |
| 59 | +Create a Script Include with the interface definition: |
| 60 | + |
| 61 | +```javascript |
| 62 | +var CustomNotificationHandlerInterface = Class.create(); |
| 63 | +CustomNotificationHandlerInterface.prototype = { |
| 64 | + initialize: function(record, config) { |
| 65 | + this.record = record; |
| 66 | + this.config = config || {}; |
| 67 | + }, |
| 68 | + |
| 69 | + process: function() { |
| 70 | + throw new Error('process() must be implemented by extension'); |
| 71 | + }, |
| 72 | + |
| 73 | + shouldNotify: function() { |
| 74 | + throw new Error('shouldNotify() must be implemented by extension'); |
| 75 | + }, |
| 76 | + |
| 77 | + handles: function(notificationSystem) { |
| 78 | + return notificationSystem == "DEFAULT"; |
| 79 | + }, |
| 80 | + |
| 81 | + type: 'CustomNotificationHandlerInterface' |
| 82 | +}; |
| 83 | +``` |
| 84 | + |
| 85 | +**Important Configuration:** |
| 86 | +- Set **API Name** to match the type (e.g., `CustomNotificationHandlerInterface`) |
| 87 | +- Check **Client callable** if needed from client-side |
| 88 | +- Set appropriate **Application** scope |
| 89 | + |
| 90 | +### Step 2: Create Extension Point Record |
| 91 | + |
| 92 | +1. Navigate to **System Definition > Extension Points** |
| 93 | +2. Create a new Extension Point record: |
| 94 | + - **Name**: Descriptive name (e.g., "Custom Notification Handler Interface") |
| 95 | + - **API name**: Full scoped name (e.g., `x_snc_extension_p_0.CustomNotificationHandlerInterface`) |
| 96 | + - **Example implementation**: Reference your interface Script Include |
| 97 | + |
| 98 | +### Step 3: Create Implementations (Extensions) |
| 99 | + |
| 100 | +Create Script Includes that extend the interface: |
| 101 | + |
| 102 | +```javascript |
| 103 | +var EmailNotificationHandler = Class.create(); |
| 104 | +EmailNotificationHandler.prototype = Object.extendsObject(CustomNotificationHandlerInterface, { |
| 105 | + |
| 106 | + process: function() { |
| 107 | + // Implementation-specific logic |
| 108 | + var email = new GlideEmailOutbound(); |
| 109 | + email.setSubject(this._buildSubject()); |
| 110 | + email.setBody(this._buildBody()); |
| 111 | + email.send(); |
| 112 | + |
| 113 | + return { success: true, message: 'Email sent' }; |
| 114 | + }, |
| 115 | + |
| 116 | + shouldNotify: function() { |
| 117 | + // Custom validation logic |
| 118 | + return this.record.getValue('priority') <= 3; |
| 119 | + }, |
| 120 | + |
| 121 | + handles: function(notificationSystem) { |
| 122 | + return notificationSystem == "Email"; |
| 123 | + }, |
| 124 | + |
| 125 | + type: 'EmailNotificationHandler' |
| 126 | +}); |
| 127 | +``` |
| 128 | + |
| 129 | +### Step 4: Register Extensions |
| 130 | + |
| 131 | +1. Navigate to **System Definition > Extensions** |
| 132 | +2. Create Extension records for each implementation: |
| 133 | + - **Extension point**: Select your Extension Point |
| 134 | + - **Name**: Implementation name |
| 135 | + - **Implementation**: Reference your implementation Script Include |
| 136 | + |
| 137 | +### Step 5: Invoke Extensions Dynamically |
| 138 | + |
| 139 | +Use `GlideScriptedExtensionPoint` to discover and execute extensions: |
| 140 | + |
| 141 | +```javascript |
| 142 | +// Get all extensions for the interface |
| 143 | +var eps = new GlideScriptedExtensionPoint().getExtensions("x_snc_extension_p_0.CustomNotificationHandlerInterface"); |
| 144 | + |
| 145 | +// Iterate and invoke matching extensions |
| 146 | +for (var i = 0; i < eps.length; i++) { |
| 147 | + gs.info("Checking extension: " + eps[i].type); |
| 148 | + |
| 149 | + if (eps[i].handles("Email")) { |
| 150 | + var result = eps[i].process(); |
| 151 | + gs.info("Result: " + JSON.stringify(result)); |
| 152 | + } |
| 153 | +} |
| 154 | +``` |
| 155 | + |
| 156 | +## Best Practices |
| 157 | + |
| 158 | +### 1. Interface Design |
| 159 | +- Define clear contracts with well-documented methods |
| 160 | +- Use JSDoc comments for all interface methods |
| 161 | +- Throw errors for unimplemented required methods |
| 162 | +- Provide sensible defaults in the base interface |
| 163 | + |
| 164 | +### 2. Implementation Guidelines |
| 165 | +- Always implement all required interface methods |
| 166 | +- Use the `handles()` method to control when implementation applies |
| 167 | +- Include comprehensive error handling |
| 168 | +- Return consistent result objects |
| 169 | +- Log important operations for debugging |
| 170 | + |
| 171 | +### 3. Naming Conventions |
| 172 | +- Use descriptive names for Extension Points |
| 173 | +- Follow ServiceNow naming standards |
| 174 | +- Include scope prefix in API names |
| 175 | +- Use consistent naming across interface and implementations |
| 176 | + |
| 177 | +### 4. Performance Considerations |
| 178 | +- Cache extension instances when possible |
| 179 | +- Avoid heavy processing in `handles()` method |
| 180 | +- Use early returns to skip unnecessary processing |
| 181 | +- Consider lazy initialization for expensive resources |
| 182 | + |
| 183 | +### 5. Testing |
| 184 | +- Test each implementation independently |
| 185 | +- Verify `handles()` logic with various inputs |
| 186 | +- Test error handling and edge cases |
| 187 | +- Validate behavior when no extensions match |
| 188 | + |
| 189 | +## Common Use Cases |
| 190 | + |
| 191 | +### 1. Multi-Channel Notifications |
| 192 | +Create extensions for Email, SMS, Slack, Teams, etc., all implementing a common notification interface. |
| 193 | + |
| 194 | +### 2. Validation Frameworks |
| 195 | +Build extensible validation systems where different validators can be plugged in based on record type or business rules. |
| 196 | + |
| 197 | +### 3. Data Transformation |
| 198 | +Implement multiple transformation strategies that can be selected dynamically based on data source or format. |
| 199 | + |
| 200 | +### 4. Integration Adapters |
| 201 | +Create adapters for different external systems, all conforming to a common integration interface. |
| 202 | + |
| 203 | +### 5. Approval Workflows |
| 204 | +Build flexible approval mechanisms where different approval strategies can be applied based on conditions. |
| 205 | + |
| 206 | +## Troubleshooting |
| 207 | + |
| 208 | +### Extensions Not Found |
| 209 | +- Verify Extension Point API name matches exactly |
| 210 | +- Check that Extension records are active |
| 211 | +- Ensure Script Includes are in the correct application scope |
| 212 | +- Verify no typos in scope prefix |
| 213 | + |
| 214 | +### Methods Not Executing |
| 215 | +- Confirm `handles()` method returns true for your criteria |
| 216 | +- Check for errors in implementation code |
| 217 | +- Verify Script Include is set to correct type |
| 218 | +- Review logs for error messages |
| 219 | + |
| 220 | +### Performance Issues |
| 221 | +- Reduce number of extensions if possible |
| 222 | +- Optimize `handles()` method logic |
| 223 | +- Consider caching extension instances |
| 224 | +- Profile code to identify bottlenecks |
| 225 | + |
| 226 | +## Additional Resources |
| 227 | + |
| 228 | +- [ServiceNow Extension Points Documentation](https://docs.servicenow.com) |
| 229 | +- [GlideScriptedExtensionPoint API Reference](https://developer.servicenow.com/dev.do#!/reference/api/latest/server/no-namespace/c_GlideScriptedExtensionPointScopedAPI) |
| 230 | +- [Script Includes Best Practices](https://developer.servicenow.com/dev.do#!/learn/learning-plans/tokyo/new_to_servicenow/app_store_learnv2_scripting_tokyo_script_includes) |
| 231 | + |
| 232 | +## Example Scenarios |
| 233 | + |
| 234 | +### Scenario 1: Priority-Based Email Notifications |
| 235 | +Use the provided implementation to send email notifications only for high-priority incidents (priority 1-3). |
| 236 | + |
| 237 | +### Scenario 2: Multi-System Notification Router |
| 238 | +Create multiple implementations (Email, SMS, Slack) and route notifications based on user preferences or incident severity. |
| 239 | + |
| 240 | +### Scenario 3: Custom Business Logic |
| 241 | +Extend the interface to add custom validation rules, approval logic, or data transformation specific to your organization. |
| 242 | + |
| 243 | +## Contributing |
| 244 | + |
| 245 | +When adding new Extension Point examples: |
| 246 | +1. Include both interface and at least one implementation |
| 247 | +2. Provide clear documentation in code comments |
| 248 | +3. Add usage examples |
| 249 | +4. Include screenshots of configuration if helpful |
| 250 | +5. Follow the repository's code quality standards |
0 commit comments