function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
hiteshghiahiteshghia 

Create trigger code using php/java dynamically

I want to acceot some parameters like the object, on insert / on update etc and then I want to create a new trigger in my salesforce application, can someone please give me some pointers on how to start going about this? 

Thanks a lot in advance, any advice will be really helpful!

- Hitesh 

Best Answer chosen by Admin (Salesforce Developers) 
Pat PattersonPat Patterson

No - unfortunately the only supported calls for ApexTrigger are deploy(), retrieve(), describeMetadata() and listMetadata() - see http://www.salesforce.com/us/developer/docs/api_meta/Content/meta_triggers.htm

All Answers

hiteshghiahiteshghia

Anyone??

Pat PattersonPat Patterson

Hi Hiteshghia,

 

You would create the trigger source code, package it into a zip file, and use Metadata API deploy() to deploy it.

 

Cheers,

 

Pat

hiteshghiahiteshghia

Hi Pat, 

I did a lot of readin around the last couple of days and what I really want to do is use the Java for CRUD based development instead of working with files. So I followed all the steps mentioned here  :
http://www.salesforce.com/us/developer/docs/api_meta/index.htm, but all the imports containing '*_2006._04*'  are not present in the jars I generated and also I am not sure what Authendpoint to use. I am using wsc-20.jar. 

 

Is it possible to create trigger the way I mentioned above using these meta data api calls http://www.salesforce.com/us/developer/docs/api_meta/index.htm for triggers? If yes and if possible can you give me a samll sample code and answer the questions above. I cannot find any sample code related to triggers in the metadata API docs. Thanks a lot Pat!! 

Looking forward to your reply!

 

- Hitesh

Pat PattersonPat Patterson

Hi Hitesh,

 

Apex code and triggers don't support the CRUD calls - only deploy() and retrieve(). You should be able to follow the docs to create the zip file then deploy it. If I can, I'll create a sample and post it here.

 

Cheers,


Pat

hiteshghiahiteshghia

Thanks a lot Pat. So this is my actual use case :

I want to acceot certain parameters from the user via a web page or something, like  Object Name , On Insert / Update / Delete and then generate a Trigger based on the user input and then deploy that trigger into the application. 

The main question is, how do I create the trigger dynamically, can I use the metadata API to create a trigger just like the examples shown to create custom objects?

 

Also based on your advice I started playing with the File based approach to use retrieve and deploy, I am using the code mentioned here : http://www.salesforce.com/us/developer/docs/api_meta/Content/meta_quickstart.htm#title_java_sample_code_file_based

 

I use the correct username of my account and password+securityToken and the AuthEndPoint is : https://cs1-api.salesforce.com/services/Soap/c/20, but when I run the code I get this error, can you please help with that :


Enter username: hitesh.ghia@bunchball.com

Enter password: password+securitytoken

 

[LoginFault [ApiFault  exceptionCode='INVALID_LOGIN' exceptionMessage='Invalid username, password, security token; or user locked out.']]


at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)at java.lang.reflect.Constructor.newInstance(Unknown Source)at java.lang.Class.newInstance0(Unknown Source)at java.lang.Class.newInstance(Unknown Source)at com.sforce.ws.bind.TypeMapper.readSingle(TypeMapper.java:627)at com.sforce.ws.bind.TypeMapper.readObject(TypeMapper.java:504)at com.sforce.ws.transport.SoapConnection.parseDetail(SoapConnection.java:226)at com.sforce.ws.transport.SoapConnection.createException(SoapConnection.java:200)at com.sforce.ws.transport.SoapConnection.receive(SoapConnection.java:146)at com.sforce.ws.transport.SoapConnection.send(SoapConnection.java:98)at com.sforce.soap.enterprise.EnterpriseConnection.login(EnterpriseConnection.java:1)at com.sforce.soap.enterprise.EnterpriseConnection.<init>(EnterpriseConnection.java:1)at FileObject.login(FileObject.java:452)at FileObject.run(FileObject.java:88)at FileObject.main(FileObject.java:78) 

 

 

I really appreciate all your help. Thank you very much!!

 

- Hitesh

hiteshghiahiteshghia

Hi Pat, 

I read in one of the posts that I should use this 'https://na12-api.salesforce.com/services/Soap/c/20.0; as the AuthEndPoint, if I use that I get this error :
 

"com.sforce.ws.ConnectionException: Unexpected element. Parser was expecting element 'urn:enterprise.soap.sforce.com:orgAttachmentFileSizeLimit' but found 'urn:enterprise.soap.sforce.com:orgDefaultCurrencyIsoCode'at com.sforce.ws.bind.TypeMapper.verifyTag(TypeMapper.java:386)at com.sforce.ws.bind.TypeMapper.verifyElement(TypeMapper.java:415)at com.sforce.soap.enterprise.GetUserInfoResult.loadFields(GetUserInfoResult.java:1)at com.sforce.soap.enterprise.GetUserInfoResult.load(GetUserInfoResult.java:1)at com.sforce.ws.bind.TypeMapper.readSingle(TypeMapper.java:628)at com.sforce.ws.bind.TypeMapper.readObject(TypeMapper.java:504)at com.sforce.soap.enterprise.LoginResult.loadFields(LoginResult.java:1)at com.sforce.soap.enterprise.LoginResult.load(LoginResult.java:1)at com.sforce.ws.bind.TypeMapper.readSingle(TypeMapper.java:628)at com.sforce.ws.bind.TypeMapper.readObject(TypeMapper.java:504)at com.sforce.soap.enterprise.LoginResponse_element.loadFields(LoginResponse_element.java:1)at com.sforce.soap.enterprise.LoginResponse_element.load(LoginResponse_element.java:1)at com.sforce.ws.bind.TypeMapper.readSingle(TypeMapper.java:628)at com.sforce.ws.bind.TypeMapper.readObject(TypeMapper.java:504)at com.sforce.ws.transport.SoapConnection.bind(SoapConnection.java:170)at com.sforce.ws.transport.SoapConnection.receive(SoapConnection.java:144)at com.sforce.ws.transport.SoapConnection.send(SoapConnection.java:98)at com.sforce.soap.enterprise.EnterpriseConnection.login(EnterpriseConnection.java:1)at com.sforce.soap.enterprise.EnterpriseConnection.<init>(EnterpriseConnection.java:1)at FileObject.login(FileObject.java:452)at FileObject.run(FileObject.java:88)at FileObject.main(FileObject.java:78)"

 

Please help I am badly stuck and out of resource to read or idea???

 

Thanks a lot

- Hitesh

Pat PattersonPat Patterson

Can you post your source code?

hiteshghiahiteshghia

Hi Pat, 

 

I just figured out the above problems ( But I have more questions :) at the bottom of this page.), I was using the wrong version number, I had to use 'https://login.salesforce.com/services/Soap/c/23.0' as my AuthEndpoint and also for MetaData Connection I had to get the service Endpoint from login result after I create the enterprise connection like this :

 

LoginResult lr = connection.login(userId, passwd);     

ConnectorConfig metadataConfig = new ConnectorConfig();      metadataConfig.setSessionId(connection.getSessionHeader().getSessionId());      metadataConfig.setServiceEndpoint(lr.getMetadataServerUrl());     

metadataConnection = new MetadataConnection(metadataConfig); 

 

So now I have a working  model of the Retrieve and Deploy metadataApi. Now I have to figure out a way to create triggers on the go put them in the zip file and then deploy... Any advice on that Pat? A small sample, some starting statement ?

 

Thanks a lot Pat you have been really very helpful!

 

- Hitesh


 

Pat PattersonPat Patterson

Hi Hitesh,

 

Now you need to write the text for your trigger to a file, create a package.xml file according to the instructions at http://www.salesforce.com/us/developer/docs/api_meta/Content/file_based.htm#using_deploy_retrieve , zip it all up and pass that zip in the deploy().

 

So, let's say you have a trigger, HandleMyObjectUpdate:

 

trigger HandleMyObjectUpdate on MyObject__c (after update) {
    // Code to do something!
    System.debug('In HandleMyObjectUpdate');
}

You would create a temporary directory, create a triggers subdirectory, write the trigger code as text to a file called HandleMyObjectUpdate.trigger in the triggers subdirectory, write package.xml to the temporary directory:

 

<?xml version="1.0" encoding="UTF-8"?> 
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
    <types>
        <members>HandleMyObjectUpdate</members>
        <name>ApexTrigger</name>
    </types>
    <version>23.0</version>
</Package>

Then zip up the result so you have a zip file with contents:

 

package.xml
triggers/HandleMyObjectUpdate.trigger

Feed this zip file into the deploy() call and, fingers crossed, you should see a trigger in your org.

 

Cheers,

 

Pat

Pat PattersonPat Patterson

BTW - I would create the zip manually to begin with, get the deploy() working, then look at how to create a zip in Java - there seems to be plenty of sample code for that out there.

hiteshghiahiteshghia

Awesome, I ll try it out and let you know what happens :) .  So there is no way to create the trigger more gracefully like by using the ApexTrigger object and then setting its content , name, version etc and then covert that to a file , something on those lines as oppose to manually writing my Trigger text to a file, just  a thought.

 

So something like this

ApexTrigger trig = new ApexTrigger();

trig.setApiVersion(API_VERSION);

trig.setContent("some trigger code".getBytes());

ds.setFullName("TestTrigger.trigger");

 

and then make a trigger and its metadata xml out of this object ?

 

I am going try out the approach you suggested now, thanks a lot Pat.

 

- Hitesh

Pat PattersonPat Patterson

No - unfortunately the only supported calls for ApexTrigger are deploy(), retrieve(), describeMetadata() and listMetadata() - see http://www.salesforce.com/us/developer/docs/api_meta/Content/meta_triggers.htm

This was selected as the best answer
hiteshghiahiteshghia

Yes I went through the docs. The good news is everything worked retrieved , created my new trigger, zipped it up and then deployed and it all works like a charm! 

Thanks Pat!

 

So this was the ground work for the real thing we were trying to achieve. What we want to do is, once our application goes in the market, we want like a webpage within the application where a user can select object they want a trigger on, select the on update / up create / on delete and select a couple of internal parameters and once he hits save button I'll run this code which I just wrote to create the new trigger and then I will deploy it in the customers org. 
Now to do that the user of the application needs to give me an adminitrator username, password_securityToken of their org for me to be able to create a connection with them and deploy to it. But the road block is that why would the user give us their adminitrator account, so the question is, is there a way to leverage the session credentials the user is already logged in with, or do this with apex or some way in which I will not require the users username and password+securitytoken?

 

Does the question make sense? Let me know if I need to be more clear. Looking forward to your reply!

 

Thanks Pat !!

 

 

- Hitesh 

Pat PattersonPat Patterson

Hi Hitesh,

 

OAuth 2.0 will redirect the user to authenticate at salesforce.com and provide your app with a token that it can use to access APIs in the context of that user, so your app never needs to see the user's password - see this article for a detailed explanation of OAuth 2.0 on Force.com.

 

There are Java OAuth 2.0 libraries out there, or you can see sample Java code to do OAuth in this article. After the user has logged in and authorized your app to access their data, your app will receive a JSON (or XML) formatted structure containing an access token, instance URL etc:

 

{
	"id":"https://login.salesforce.com/id/00D50000000IZ3ZEAW/00550000001fg5OAAQ",
	"issued_at":"1296458209517",
	"refresh_token":"5Aep862eWO5D.7wJB...",
	"instance_url":"https://na1.salesforce.com",
	"signature":"0/1Ldval/TIP...",
	"access_token":"00D50000000IZ3Z!AQ0AQ..."
}

 

OAuth integrates well with the Force.com REST API, but, with a little work, you can also use it with the SOAP or Metadata API. The access token above is equivalent to the session ID in the SOAP and Metadata APIs, while the id property points to a service that will return information on the user and their environment, including the Metadata API. You can GET the id URL, passing the access token as an HTTP header:

 

Authorization: OAuth 00D50000000IZ3Z!AQ0AQDpEDKYsn7ioKug2aSmgCjgrPjG...

 

You will receive another JSON structure with the Metadata endpoint formatted thus:

 

https://na1.salesforce.com/services/Soap/m/{version}/00D50000000IZ3Z

 

You will need to substitute the actual API version you want to use in that string to make a real endpoint:

 

https://na1.salesforce.com/services/Soap/m/23.0/00D50000000IZ3Z

 

Now you can push that into the Metadata connection, like this:

 

ConnectorConfig metadataConfig = new ConnectorConfig();
        
metadataConfig.setSessionId(accessTokenFromOAuth);
metadataConfig.setServiceEndpoint(metadataEndpointFromIdentityService);
MetadataConnection metadataConnection = com.sforce.soap.metadata.Connector.newConnection(metadataConfig);

 

Now you can call the Metadata API as before.

 

Cheers,

 

Pat

hiteshghiahiteshghia

Interesting! I'll try it out and let you know how it goes :).

Once again thanks a lot Pat !!

 

- Hitesh

hiteshghiahiteshghia

It all worked!!

 

Thanks a lot.

- Hitesh

Pat PattersonPat Patterson

Awesome! Glad to hear it - thanks for reporting back :)

 

Cheers,

 

Pat

siddhraj atodariasiddhraj atodaria
Hi Patterson,
I want to create trigger using java/metadata.
I read the blogs and tried but got some error..

I use below code :
http://www.salesforce.com/us/developer/docs/api_meta/Content/meta_deploy.htm

with same  .trigger file and  package.xml file.. and with zip file to deploy() but got below error.

temp/Triggers/helloWorldAccountTrigger.trigger
temp/package.xml
temp.zip

i used this zip

helloWorldAccountTrigger.trigger :

trigger helloWorldAccountTrigger on Account (before insert) {

  Account[] accs = Trigger.new;

   MyHelloWorld.addHelloWorld(accs);
}


Status is: Failed
Final list of failures:
Exception in thread "main" java.lang.Exception: The files were not successfully deployed
temp/package.xml(HandleMyObjectUpdate):An object 'HandleMyObjectUpdate' of type ApexTrigger was named in package.xml, but was not found in zipped directory

at sample.DeploySample.deployZip(DeploySample.java:101)
at sample.DeploySample.main(DeploySample.java:46)
Java Result: 1

Please help me to resolve this error.
Akhilesh Dahat 11Akhilesh Dahat 11
Hello Pat,  
This Is the awesome toolkit for the PHP , but currently i am having the requirement for building the web app.So it can create the triggers and classes by php into salesforce. Can you please provide the appropriate guideline for this.This would be great if the toolkit is having such functionality.