[SalesForce] Using Meta data api in apex

i know if u have to create a field in apex then u have to call meta data api of salesforce.i found only this link for implementation https://github.com/financialforcedev/apex-mdapi is there any other good tutorial or resource for calling metadata api from apex ??

Best Answer

Apex Metadata API Introduction. The Salesforce Metadata API allows you to perform many org configuration and setup features programatically. Code examples given by Salesforce are in Java as the API is a SOAP API. In respect to the Apex library provided here, it wraps via the provided MetadataService.cls class the Salesforce SOAP version of the API to make it easier to access for Apex developers. Key terms, structures and operations exposed are still the same however, so reading the Salesforce documentation is still important. You should also review the readme and example class

Handling Asynchronous Aspects. The first challenging aspect is the fact that Salesforce provides this API as an asynchronous API. Which requires some additional coding approaches to handle its responses. Effectively polling for the result of the API calls. To make it easier the Apex library includes some examples for doing this in Batch Apex and using Visualforce's apex:actionPoller component.

Create Field Example. Here is an example of creating a CustomField using the create operation. First creating an instance of the service which exposes all the operations and configures the authentication, by passing on the users current Session ID. For more information on calling SOAP from Apex, see here.

MetadataService.MetadataPort service = new MetadataService.MetadataPort();
service.SessionHeader = new MetadataService.SessionHeader_element();
service.SessionHeader.sessionId = UserInfo.getSessionId();

MetadataService.CustomField customField = new MetadataService.CustomField();
customField.fullName = 'Test__c.TestField__c';
customField.label = 'Test Field';
customField.type_x = 'Text';
customField.length = 42;
MetadataService.AsyncResult[] results = 
    service.create(new List<MetadataService.Metadata> { customField });

The code then needs to inspect the contents of AsyncResult and be prepared to pass it back to the API to poll for the results periodically. If you study the create documentation you will see this summary...

enter image description here

You can call the checkStatus method from Apex, though you must wait for Salesforce to process the request, either via Batch Apex context or via Visualforce and its AJAX support.

MetadataService.AsyncResult[] results = 
    service.checkStatus(new List<String> { results[0].Id });    

Calling checkStatus from Visualforce

If you have an interactive tool your building, you can use Visualforce and use the apex:actionPoller to store the AsyncResult in your controller and write a controller method to call the checkStatus, which the action poller repeatedly calls until the AsyncResult indicates the request is completed by Salesforce.

public with sharing class MetadataController {

    public MetadataService.AsyncResult result {get;set;}

    public PageReference createField()
    {
        // .. as per above ...
        result = createService().create(new List<MetadataService.Metadata> { customField })[0];     
        displayStatus();
        return null;
    }

    public PageReference checkStatus()
    {
        // Check status of the request
        result = createService().checkStatus(new List<String> { result.Id })[0];
        displayStatus();        
        return null;    
    }

    private void displayStatus()
    {
        // Inspect the AsyncResult and display the result
        ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.Info, 
                result.done ? 'Request completed' : 'Request in progress...'));
        if(result.state == 'Error')
            ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.Error, result.message));
        if(result.done)
            result = null;
    }
}

This controllers page then looks like this...

<apex:page controller="MetadataController">
    <apex:form id="form">
        <apex:sectionHeader title="Metadata Demo"/>
        <apex:pageMessages />
        <apex:actionPoller action="{!checkStatus}" interval="5" rerender="form" rendered="{!NOT(ISNULL(Result))}"/>
        <apex:outputPanel rendered="{!ISNULL(Result)}">
            <apex:commandButton value="Create Field" action="{!createField}"/>
            <apex:commandButton value="Delete Field" action="{!deleteField}"/>
        </apex:outputPanel>
    </apex:form>
</apex:page>

enter image description here

enter image description here

enter image description here

Note: The demos for the retrieve and deploy operations have good example of this here and here. Even though they don't actually use the above CRUD operations of the Metadata API, polling for the AsyncResult is the same. Note that these two operations, retrieve and deploy are useful for deploying code or retrieving configuration. But do have the added complexity of handling zip file format, something the library also provides some components for.

Calling checkStatus from Batch Apex

This part of the Readme describes a helper class MetadataCreateJob.cls to do this in Batch Apex which actually handles both calling the create and checkStatus methods for you. Sending the final results to an Apex handler class, in this case a default email handler is provided, but you write your own.

// Pass the Metadata items to the job for processing, indicating any dependencies
MetadataCreateJob.run(
    new List<MetadataCreateJob.Item> { new MetadataCreateJob.Item(customField) },
    new MetadataCreateJob.EmailNotificationMetadataAsyncCallback());              

How do I know what org configuration can be access via the Salesforce Metadata API?

First review this topic from the Salesforce documentation...

Metadata components are not based on sObjects, like objects in the API. Instead, they are based on metadata types, such as ApexClass and CustomObject, which extend Metadata. A component is an instance of a metadata type. For example, CustomObject is a metadata type for custom objects, and the MyCustomObject__c component is an instance of a custom object.

In respect to the CRUD (Create, Update and Delete) operations of the API you can only pass metadata / component types that extend the class Metadata (or MetadataService.Metadata in the Apex API). As as described in the create operation documentation...

Adds one or more new metadata components to your organization’s data. This call can be used to create any of the objects that extend Metadata. For more details, see Metadata Components and Types.

If you review the MetadataService.CustomField class you can see it does just this...

public class CustomField extends Metadata {

When you review the individual topics for the metadata component types in the Salesforce documentation, pay attention to those that state that they extend the Metadata type.

enter image description here

NOTE: As per the last section of the Readme for the library, it has manually made this modification as the Salesforce WSDL to Apex code generator that initially generated the wrap did not do this. Most of the popular Metadata types have already had this treatment in the Apex API.

Related Topic