Регистрация  |  Вход

Обращение к внешнему серверу посредством триггера

trigger OpportunityRemoteUpdate on Opportunity (after insert, after update, after delete) {
HttpRequest req = new HttpRequest();
req.setEndpoint('http://dev.xxxxx.com/ntm/trunk/opportunity/remote/sf_query&token=xxxxx&act=update&id=006P0000004NPIA4');
req.setMethod('POST');

Http http = new Http();
HTTPResponse res = http.send(req);
System.debug(res.getBody());
}

При отработке тригера выдается ошибка
Error: Invalid Data.
Review all error messages below to correct your data.
Apex trigger OpportunityRemoteUpdate caused an unexpected exception, contact your administrator: OpportunityRemoteUpdate: execution of AfterUpdate caused by: System.CalloutException: Callout from triggers are currently not supported.: Trigger.OpportunityRemoteUpdate: line 7, column 1

В чем может быть проблема?

Snn
[code]trigger OpportunityRemoteUpdate on Opportunity (after insert, after update, after delete) {
     HttpRequest req = new HttpRequest();
     req.setEndpoint('http://dev.xxxxx.com/ntm/trunk/opportunity/remote/sf_query&token=xxxxx&act=update&id=006P0000004NPIA4');
     req.setMethod('POST');

     Http http = new Http();
     HTTPResponse res = http.send(req);
     System.debug(res.getBody());
}[/code]

При отработке тригера выдается ошибка 
Error: Invalid Data.
Review all error messages below to correct your data.
Apex trigger OpportunityRemoteUpdate caused an unexpected exception, contact your administrator: OpportunityRemoteUpdate: execution of AfterUpdate caused by: System.CalloutException: Callout from triggers are currently not supported.: Trigger.OpportunityRemoteUpdate: line 7, column 1

В чем может быть проблема?

Вот тут есть ответ на ваш вопрос.

http://boards.developerforce.com/t5/Apex-Code-Development/Callout-from-triggers-are-currently-not-supported/td-p/108871

Дело в том что в Salesforce есть такой нюанс - нельзя делать callout после DML операции. А триггер запускается в результате DML операции. Тут необходимо использовать @future метод. Но учтите, что это асинхронная операция и в debug log будет отображаться как отдельный процесс после основного.

Процетирую

You do need to use the @future annotation in an apex method that is stored in a separate class. Then call that class and method from within your trigger.

For example:

trigger justAnExample on Account (after update){

testCls.myMethod(); //call the static method, with the @future annotation
}


global testCls {

@future Public static void myMethod(callout=true){
System.debug('inside myMethod...');

//do your callout logic here...
System.debug('exiting myMethod...');

}
}

Вот тут есть ответ на ваш вопрос.

[url]http://boards.developerforce.com/t5/Apex-Code-Development/Callout-from-triggers-are-currently-not-supported/td-p/108871[/url]

Дело в том что в Salesforce есть такой нюанс - нельзя делать callout после DML операции.  А триггер запускается в результате DML операции. Тут необходимо использовать @future метод. Но учтите, что это асинхронная операция и в debug log будет отображаться как отдельный процесс после основного.

Процетирую 

You do need to use the @future annotation in an apex method that is stored in a separate class. Then call that class and method from within your trigger.
 
For example:
 
trigger justAnExample on Account (after update){

   testCls.myMethod(); //call the static method, with the @future annotation 
}

  
global testCls {
 
    @future Public static void myMethod(callout=true){
          System.debug('inside myMethod...');
         
          //do your callout logic here...
          System.debug('exiting myMethod...');
         
     }
}

Да действительно так работает!

Есть еще одна проблема - когда я хочу передать параметр trigger.newMap

trigger OpportunityRemoteUpdate on Opportunity (after insert, after update, after delete) {
Opportunity_TriggerHelper.updateOpportunity(trigger.newMap);
}

public with sharing class Opportunity_TriggerHelper {
@future (callout=true)
public static void updateOpportunity (Map<Id, Opportunity> newMap);
HttpRequest req = new HttpRequest();
req.setEndpoint('http://dev.xxxxx.com/ntm/trunk/opportunity/remote/sf_query&token=xxxxx&act=update&id=xxxxx');
req.setMethod('GET');

Http http = new Http();
HTTPResponse res = http.send(req);
System.debug(res.getBody());
}
}

то при сохранении класса получаю ошибку: Error: Compile Error: expecting a right parentheses, found 'http://dev.xxxxx.com/ntm/trunk/opportunity/remote/sf_query&token=xxxxx&act=update&id=xxxxx' at line 5 column 21

причем если передавать string в качестве параметра то все норм, например так:

trigger OpportunityRemoteUpdate on Opportunity (after insert, after update, after delete) {
String OpportunityId = 'xxxxx';
Opportunity_TriggerHelper.updateOpportunity(OpportunityId);
}

public with sharing class Opportunity_TriggerHelper {
@future (callout=true)
public static void updateOpportunity (String OpportunityId) {
HttpRequest req = new HttpRequest();
req.setEndpoint('http://dev.xxxxx.com/ntm/trunk/opportunity/remote/sf_query&token=xxxxx&act=update&id='+OpportunityId);
req.setMethod('GET');

Http http = new Http();
HTTPResponse res = http.send(req);
System.debug(res.getBody());
}
}

Snn
Да действительно так работает!

Есть еще одна проблема - когда я хочу передать параметр trigger.newMap

trigger OpportunityRemoteUpdate on Opportunity (after insert, after update, after delete) {
    Opportunity_TriggerHelper.updateOpportunity(trigger.newMap);
}

public with sharing class Opportunity_TriggerHelper {
    @future (callout=true)
    public static void updateOpportunity (Map<Id, Opportunity> newMap);
     HttpRequest req = new HttpRequest();
     req.setEndpoint('http://dev.xxxxx.com/ntm/trunk/opportunity/remote/sf_query&token=xxxxx&act=update&id=xxxxx');
     req.setMethod('GET');

     Http http = new Http();
     HTTPResponse res = http.send(req);
     System.debug(res.getBody());
    }
}

то при сохранении класса получаю ошибку: Error: Compile Error: expecting a right parentheses, found 'http://dev.xxxxx.com/ntm/trunk/opportunity/remote/sf_query&token=xxxxx&act=update&id=xxxxx' at line 5 column 21

причем если передавать string в качестве параметра то все норм, например так:

trigger OpportunityRemoteUpdate on Opportunity (after insert, after update, after delete) {
    String OpportunityId = 'xxxxx';
    Opportunity_TriggerHelper.updateOpportunity(OpportunityId);
}

public with sharing class Opportunity_TriggerHelper {
    @future (callout=true)
    public static void updateOpportunity (String OpportunityId) {
     HttpRequest req = new HttpRequest();
     req.setEndpoint('http://dev.xxxxx.com/ntm/trunk/opportunity/remote/sf_query&token=xxxxx&act=update&id='+OpportunityId);
     req.setMethod('GET');

     Http http = new Http();
     HTTPResponse res = http.send(req);
     System.debug(res.getBody());
    }
}

В первом куске кода:

public with sharing class Opportunity_TriggerHelper {
@future (callout=true)
public static void updateOpportunity (Map<Id, Opportunity> newMap);
HttpRequest req = new HttpRequest();
req.setEndpoint('http://dev.xxxxx.com/ntm/trunk/opportunity/remote/sf_query&token=xxxxx&act=update&id=xxxxx');
req.setMethod('GET');

Http http = new Http();
HTTPResponse res = http.send(req);
System.debug(res.getBody());
}
}

У тебя в строке public static void updateOpportunity (Map<Id, Opportunity> newMap); в конце стоит ; а должна стоять {

Следующий нюанс

Если ничего не поменялось в последнем релизе то во future нельзя передавать объекты. Только примитивные данные (Integer, String, ID) или списки этих примитивных данных типо List<Id>, Set<Id>

В твоем случае надо из триггера передавать Set<Id>

В первом куске кода:

[code]
public with sharing class Opportunity_TriggerHelper {
    @future (callout=true)
    public static void updateOpportunity (Map<Id, Opportunity> newMap);
         HttpRequest req = new HttpRequest();
         req.setEndpoint('http://dev.xxxxx.com/ntm/trunk/opportunity/remote/sf_query&token=xxxxx&act=update&id=xxxxx');
         req.setMethod('GET');

         Http http = new Http();
         HTTPResponse res = http.send(req);
         System.debug(res.getBody());
     }
}
[/code]

У тебя в строке public static void updateOpportunity (Map<Id, Opportunity> newMap); в конце стоит ; а должна стоять {

Следующий нюанс

Если ничего не поменялось в последнем релизе то во future нельзя передавать объекты. Только примитивные данные (Integer, String, ID) или списки этих примитивных данных типо List<Id>, Set<Id>

В твоем случае надо из триггера передавать Set<Id>

Твой @future метод должен так объявляться

@future (callout=true)
public static void updateOpportunity (Set<Id> opportunityIds){

}

Твой @future метод должен так объявляться

[code]
@future (callout=true)
public static void updateOpportunity (Set<Id> opportunityIds){

}
[/code]

Вот твой триггер, который передает во @future метод Set<Id> opportunity

trigger OpportunityRemoteUpdate on Opportunity (after insert, after update, after delete) {

Set<Id> opportunityIds = new Set<Id>();

if (Trigger.isInsert || Trigger.isUpdate) {
opportunityIds = Trigger.newMap.keySet();
}

if (Trigger.isDelete) {
opportunityIds = Trigger.oldMap.keySet();
}

Opportunity_TriggerHelper.updateOpportunity(opportunityIds);
}

Ну @future метод сам попробуй написать. Только учти, что тебе на вход будет приходить Set<Id> т.е. ты не знаешь будет 1 или N записей. Так что либо вставляй в запрос только первую opportunityIds[0] или пиши интеграцию, которая может принимать более 1 в одном запросе.

Вот твой триггер, который передает во @future метод Set<Id> opportunity

[code]
trigger OpportunityRemoteUpdate on Opportunity (after insert, after update, after delete) {
    
    Set<Id> opportunityIds = new Set<Id>();

    if (Trigger.isInsert || Trigger.isUpdate) {
        opportunityIds = Trigger.newMap.keySet();       
    }
    
    if (Trigger.isDelete) {
        opportunityIds = Trigger.oldMap.keySet();       
    }

    Opportunity_TriggerHelper.updateOpportunity(opportunityIds);
}
[/code]

Ну @future метод сам попробуй написать. Только учти, что тебе на вход будет приходить Set<Id> т.е. ты не знаешь будет 1 или N записей. Так что либо вставляй в запрос только первую opportunityIds[0] или пиши интеграцию, которая может принимать более 1 в одном запросе.

Осталась маленькая проблема

public static void updateOpportunity (String action, Set<Id> opportunityIds) {
String ids = String.join(opportunityIds, ',');
...

Error: Compile Error: Variable does not exist: String at line 5 column 22 (ругается на String.join)

Snn
Осталась маленькая проблема

    public static void updateOpportunity (String action, Set<Id> opportunityIds) {
        String ids = String.join(opportunityIds, ',');
        ...

Error: Compile Error: Variable does not exist: String at line 5 column 22 (ругается на String.join)

new List<Id>(your Set instance);

new List<Id>(your Set instance);