It seems like an absolute age since i first blogged about the new features Salesforce have added to the Spring’14 version of the Metadata API. This weekend my development org was finally upgraded and I was able to continue the work to upgrade the Apex wrapper around this API. The work is now complete and is formally the hardest and most time consuming upgrade yet, ultimately though the most worthwhile in terms of the way the API can now be used in Apex, it really feels like it has now finally unlocked the keys to the kingdom for Apex developers!
The last blog presented an example of reading and updating a Layout. With this release I’ve now extended this to all Metadata types. The introduction of the real time variants of the CRUD operations is a significant step forward in the usability of this library, particularly if your want to update rather than just create things.
Prior to Spring’14 you had to jump through quite a few hoops to read metadata, involving zip file handling in JavaScript and AJAX or Batch Apex code for handling asynchronous responses, as described in this blog. The async API variants still exist and are still supported, so all your code that used them before still works. There is also some reasons to consider still to use them, which i’ll cover later. Lets get into some new examples, all of which are available in MetadataServiceExamples.cls
Creating a Button and adding it to a Layout
// Create Custom Button MetadataService.WebLink webLink = new MetadataService.WebLink(); webLink.fullName = 'Test__c.googleButton'; webLink.availability = 'online'; webLink.displayType = 'button'; webLink.encodingKey = 'UTF-8'; webLink.hasMenubar = false; webLink.hasScrollbars = true; webLink.hasToolbar = false; webLink.height = 600; webLink.isResizable = true; webLink.linkType = 'url'; webLink.masterLabel = 'google'; webLink.openType = 'newWindow'; webLink.position = 'none'; webLink.protected_x = false; webLink.showsLocation = false; webLink.showsStatus = false; webLink.url = 'http://www.google.com'; webLink.width = 600; handleSaveResults( service.createMetadata( new List<MetadataService.Metadata> { webLink })[0]); // Read the Layout MetadataService.Layout layout = (MetadataService.Layout) service.readMetadata('Layout', new String[] { 'Test__c-Test Layout' }).getRecords()[0]; // Add the Custom Button to the Layout if(layout.customButtons==null) layout.customButtons = new List<String>(); layout.customButtons.add('googleButton'); // Update the Layout handleSaveResults( service.updateMetadata( new MetadataService.Metadata[] { layout })[0]);
Add a new Picklist Value
// Read Custom Field MetadataService.CustomField customField = (MetadataService.CustomField) service.readMetadata('CustomField', new String[] { 'Lead.picklist__c' }).getRecords()[0]; // Add Picklist values MetadataService.PicklistValue two = new MetadataService.PicklistValue(); two.fullName= 'second'; two.default_x=false; MetadataService.PicklistValue three = new MetadataService.PicklistValue(); three.fullName= 'third'; three.default_x=false; customField.picklist.picklistValues.add(two); customField.picklist.picklistValues.add(three); // Update Custom Field handleSaveResults( service.updateMetadata( new MetadataService.Metadata[] { customField })[0]);
Copy Layout Sections between Layouts
// Read the source Layout MetadataService.Layout sourceLayout = (MetadataService.Layout) service.readMetadata('Layout', new String[] { 'Test__c-Test Template Layout' }).getRecords()[0]; // Read the target Layout MetadataService.Layout targetLayout = (MetadataService.Layout) service.readMetadata('Layout', new String[] { 'Test__c-Test Layout' }).getRecords()[0]; // Add section from source Layout to target Layout targetLayout.layoutSections.add( sourceLayout.layoutSections[0]); // Update target Layout handleSaveResults( service.updateMetadata( new MetadataService.Metadata[] { targetLayout })[0]);
More possibilities…
Salesforce are doing an amazing job with Metadata API coverage these days. If you can see it in the Setup menu, i’d say there is a good chance you can find it in the Metadata API list of support Metadata types. Here are a few interesting use cases that you might want to think about…
- Copy or merge tools. Ability to save admins potentially a significant number of clicks by writing tools to copy or merge Setup configuration.
- Setup Wizards. Scripting the creation more complex Setup config, such as Force.com sites or templating the growing set of org Settings.
- Field usage reporting. Read layouts, validation rules, workflows and search for field references.
- Writing your own Change Sets, You could write your own scripts to move specific metadata and/or sync things like picklists between orgs.
- Post install upgrades. Configuration UI to perform post install upgrades to none upgradable components, such as picklists and layouts in the subscriber org.
NOTE: One thing still not possible via the above CRUD methods is the creation of Apex Class or Apex Triggers, the only way (including the Tooling API) of doing this in a Production org, is still via the Metadata API deploy operation, thus the sample code for this in the library is still valid.
Upgrading to the new MetadataService.cls
For the first time since I’ve been refreshing the Apex wrapper MetadataService.cls, some of the metadata type classes and method signatures have changed. This is due to Salesforce changing the Metadata API of course, which they can do because they version at the end point, not at the WSDL level. I’m open to feedback on ways to avoid this in the future, such as the version on the end of the class, e.g. MetadataService30. The changes in this case which i have observed will effect require small changes to your use of the deploy method…
- MetadataService.checkDeployStatus now takes a boolean argument, called includeDetails, read more here,
- MetadataService.DeployResult class has a new details property replacing messages, read more here.
NOTE: The deploy example has been updated in the library with the above changes.
Scripting the Release Upgrade Process
I first described in my previous blog, that i have invested in developing a patcher script, a peace of Apex code i have written that parses the default Apex code output from the Generate Apex from WSDL button and automatically applies the usual changes i have been making manually to date to get things to work, plus some new changes to support the new readMetadata operation. I have included the patcher code in the library if you want to take a look at it and have updated the steps in the readme to create your own MetadataService.cls should you want to (in the event i don’t update it in the future for example). You do not need to worry about this if you plan to take the pre-patched MetadataService.cls from the repository, the above is really just an FYI.
Unsupported Metadata Types
The following Metadata types are not supported, as they utilise some specific features the above Patcher script does not support in relation to the use of shared Metadata type base classes. I’m confident these can be supported in the future and will like be working on these as part of the next release. I’ll be giving priority to those that have been the subject of recent questions , such as Flow and Sharing Rules.
- Flow
- Sharing Rules
- Role
- Custom Shortcut
- Email Folder
- Document Folder
Summary
Since its creation, i have been getting a steady flow of questions and requests for this library (evidence by the large examples class these days), so i can see there is demand for it in general, personally i’d still like to see it as a native library without the need to make the callouts. However until that time comes I’ll continue to support the community. Please do let me know what you’ve been getting up to with it and join in creating great community tools to help admins and developers be more productive!
