Cloud computing

When you want to create a button for an object you can override a standard or create a custom one. On the page for this you choose ‘Visualforce Page’ as content source. One thing you’ll discover is that there are no choices if there are also no Visualforce pages with a standard controller to the object of the button.

In this case I have created a Visualforce page with a standard controller to object ‘CObject_1__c’ and that is why this page is a choice in the content picklist. The following would be the first row of the VF page  in this case:

<apex:page standardcontroller=”CObject_1__c”>

 

Share and Enjoy:

  • Print
  • Digg
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Yahoo! Buzz
  • Twitter
  • Google Bookmarks
  • email
  • Google Buzz
  • RSS
  • Slashdot
  • Technorati
  • Add to favorites
  • DZone
  • LinkedIn
  • MySpace
  • Tumblr

Be the first to comment

Today I attended the webinar Winter ’12 release preview to learn about what’s coming in Salesforce winter ’12 release. It was quite a few interesting things that I’m looking forward to trying out.

A very small but wished-for adjustment is to being able to make Setup the default landing page when logging into Salesforce.

Go to your user record:

Select the checkbox ‘Make Setup My Default Landing Page’:

When logging into Salesforce the Setup will open up straight away which is rather convenient if you are a developer or administrator. Notice the the Setup home page also has changed quite a bit:

Share and Enjoy:

  • Print
  • Digg
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Yahoo! Buzz
  • Twitter
  • Google Bookmarks
  • email
  • Google Buzz
  • RSS
  • Slashdot
  • Technorati
  • Add to favorites
  • DZone
  • LinkedIn
  • MySpace
  • Tumblr

Be the first to comment

We use Salesforce together with BigMachines as our CRM-system and product configurator. This means very briefly that when our business are creating agreements they enter BigMachines from a Salesforce opportunity.

This procedure stopped working as it used to after this weekend’s upgrade to the Winter ’12 release of Salesforce sandboxes.

We get several errors. One of them is:

Invalid Session ID found in SessionHeader: Illegal Session

Another one that pops up sometimes is:

Stack Overflow

Another strange error that only my user seems to be affected by is a complaint about an integration and a SF field that most certainly works.

We don’t know how to handle this and both Salesforce and BigMachines are now involved in finding the issue. I have found similar threads on the Salesforce developer forums from 2008 after the upgrade to Winter ’08 but no obvious solution. See the Google results.

The problem is very annoying of course since I am having problems to actually work. And furthermore this really needs to be fixed by October 14th when production is being upgraded.

Anyone who got ideas are very welcome to post them here. When the problem is solved and if we get an explanation I will post it here as well.

Share and Enjoy:

  • Print
  • Digg
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Yahoo! Buzz
  • Twitter
  • Google Bookmarks
  • email
  • Google Buzz
  • RSS
  • Slashdot
  • Technorati
  • Add to favorites
  • DZone
  • LinkedIn
  • MySpace
  • Tumblr

1 comment

The ModSecurity module on the Apache server (BigMachines web server) is mandated for all upgrades starting with BigMachines version 11.

After upgrading to version 11 we suddenly got “The webpage can not be found” on several places. This turned out to be because the ModSecurity don’t permit double pipes (||) which we were using as delimiters. The reason for this is that it could be misused for a SQL injection attack and that’s why the server in these cases blocks the whole output.

The solution is simple. Search for double pipes everywhere and replace them with another delimiter or in another way depending on how you use them.

Here is some information I received when this was discovered about ModSecurity in BigMachines on how to find the problem and how to correct it:

ModSecurity is an integrated module with Apache, the BigMachines web server. It is used to prevent attacks and malicious code, and it provides a great extra layer of security for the BigMachines platform. Being integrated with Apache, the security rules apply to all traffic through the web server. You can find more information at http://www.modsecurity.org.

If you get an HTTP 400 error or an HTTP 501, it is very likely that you have run into a ModSecurity violation.

Investigation tip: To help identify if a string is causing a modsecurity fault, type it into the global search results box and hit search. If your string is the culprit, you will get the error there.

This is generally how the error will look:

Bad Request
Your browser sent a request that this server could not understand.
​ ​*This is the HTTP 400 Error

Method Not Implemented
POST to /admin/scripts/search_script.jsp not supported.
​*This is the HTTP 501 Error

Common ModSecurity Violations

Use of character string “||”
(“||” like SQL injection attack)
Causes an HTTP 400 Error ​You may not pass a double pipe through the server. This includes outputs from rules such as string delimiters, sending or receiving information from anyplace such as the resources server, and even end user inputs such as Configuration and Commerce fields. The double pipe is dangerous enough that it is tightly blocked by ModSecurity, and care needs to be taken that it is simply not used. When troubleshooting this ModSecurity violation, you will not be able to do a ‘Global Search on BML’, because even passing it into this field causes an HTML 400 error. You will need to do a bulk download of the different BML areas and search for the double pipe using an external program. You also need to check your CSS, JavaScript, and any other fancy workarounds that you may have come up with.
*NOTE: the ModSecurity rule is looking for [%]7C [%]7C (where %7C is the hex for a pipe), keep this in mind when searching.

Use of character string “|nc “, “|ps “, “|id ” or others
(“|” followed by certain linux commands and a blank)
Causes an HTTP 501 Error ​The same restrictions as the above “double pipe” rule apply to the “|nc” rule.
The “nc” pattern matches a linux command, so ModSecurity perceives it as a system attack and will try to block it. As with the double pipe rule, the way to fix this is to replace it, and you will not be able to search for it using Global Search on BML.

Use of character string “%00″
Causes an HTTP 400 Error ​Same restrictions as double-pipe. “%00″ is a null byte, with which attackers can make part of the system think a string is over, and thus quit analyzing for security. Customer data could start with 00, so you should not use anything ending in % as a delimiter.

Share and Enjoy:

  • Print
  • Digg
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Yahoo! Buzz
  • Twitter
  • Google Bookmarks
  • email
  • Google Buzz
  • RSS
  • Slashdot
  • Technorati
  • Add to favorites
  • DZone
  • LinkedIn
  • MySpace
  • Tumblr

Be the first to comment

Calling a web service by pressing a button

by Niklas Waller on September 1, 2011

in Cloud computing,Salesforce

If you want to run some code when pressing a button in Salesforce you could do it in the button itself, for example like this:

{!REQUIRESCRIPT("/soap/ajax/22.0/connection.js")}
{!REQUIRESCRIPT("/soap/ajax/22.0/apex.js" )}
var connection = sforce.connection;
var callOff = new sforce.SObject("Opportunity");
callOff.AccountId = "{!Opportunity.AccountId__c}";
callOff.Main_Opp__c = "{!Opportunity.Id}";
callOff.RecordTypeId = "01460000000JngT"
callOff.Name = "Opp Name";
callOff.StageName = 'Identified';
callOff.CloseDate = new Date();
result = sforce.connection.create([callOff]);
alert(result );

This is a good solution if you don’t need much code.
If the code is more complex however, it is a good option to call an apex class. This can be done from a button like this:

{!REQUIRESCRIPT("/soap/ajax/22.0/connection.js")}
{!REQUIRESCRIPT("/soap/ajax/22.0/apex.js")}
var result = sforce.apex.execute("ApexClassToDoSomeLogic","nameOfAMethod",{oppId:"{!Opportunity.Id}"});

The code to run is defined within the Apex class ‘ApexClassToDoSomeLogic’. The idea in this case is to create a new record of an object and return its id and return back. In this way pressing the button will be a re-direct to a new page:

global with sharing class ApexClassToDoSomeLogic { 

webService static String nameOfAMethod(Id oppId) {
Opportunity main = [select AccountId,Name,CloseDate from Opportunity where Id =: oppId];
Opportunity callOff = new Opportunity();    

ID callOffId = null;
// Get the id of a recordtype with a specific name
ID recordTypeId = [select id from RecordType where SObjectType = 'Opportunity' and Name = 'Call-off Opportunity'].Id;    

// Set values of new opportunity record
callOff.RecordTypeId = recordTypeId;
callOff.Main_Opportunity__c = oppId;
callOff.Standard_Opportunity_Type__c = 'Call-off';
callOff.AccountId = main.AccountId;
callOff.OwnerId = UserInfo.getUserId();
callOff.StageName = 'Identified';
callOff.CloseDate = main.CloseDate + 45;
callOff.Type = 'New'; 

/* Insert the new call-off opportunity */
Database.SaveResult oppResult;
try {
oppResult = Database.insert(callOff, false);
callOffId = oppResult.getId();
} catch (System.QueryException e) {
return 'An error occured querying for the call-off opportunity record: ' + e.getMessage();
}                

if (!oppResult.isSuccess()) {
return 'Insert failed: ' + oppResult.getErrors();
}    

/* Cast the ID to a string since that's what expected to return */
return (String)callOffId;
}

Share and Enjoy:

  • Print
  • Digg
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Yahoo! Buzz
  • Twitter
  • Google Bookmarks
  • email
  • Google Buzz
  • RSS
  • Slashdot
  • Technorati
  • Add to favorites
  • DZone
  • LinkedIn
  • MySpace
  • Tumblr

Be the first to comment

For a specific purpose I need to create a query that an external part should run against our Salesforce organization. Normally this is not a problem. However, this specific query should group on a specific field which causes errors.

The problem is that the enterprise WSDL was imported into our integration portal more than two years ago. The WSDL was using API version 14. Many integrations have been setup on the same adapter and this means that it is not an easy thing to just import a new WSDL file on a new API version as this would require extensive regression testing and possible extra development. So why is this a problem? Well, this is because aggregate functions like group by, sum, max, avg, count didn’t exist to be used in SOQL queries until API version 18.

So the grouping operation is not advanced in any way. You know that if you have been using SQL, the problem is that it is not an option. The options that we have defined are:

  • Update the current adapter with a new WSDL file (not an option right now as it requires to much work)
  • Create separate web services (not an option since it would not be a clean solution to have some methods this way and some the other way and also more difficult to maintain because of this)
  • Do some logic in the integration portal. For example a Java function (not an option at this time due to existing rule sets and possibly also difficult to make work since records are read in batches)
  • Create a new adapter with a new WSDL file on the latest API version that can handle aggregate functions. This is the one we will go for.
Ok, so I know what we need to do. Now I just want to test some queries to make sure these works before the integration portal team starts to work. I found myself in some troubles here too.
I tested 6 different tools, only three worked with an API version 18 or later – meaning that they can’t use aggregate functions. I am most disappointed in Apex Explorer which should really be the updated one.
  • Apex Explorer. Don’t work. Either you get the error message “Query failed: MALFORMED_QUERY: Aggregate query not allowed with this API version” or the result set is empty.
  • Data Loader. It works, but this is not a test tool and is not as easy to work with.
  • AJAX Tools on AppExchange. Don’t work for aggregate functions.
  • SOQL Query Tool. Don’t work for aggregate functions.
  • SoqlXplorer. Works, but only for Mac.
  • Schema Explorer in Eclipse for Force.IDE. Works fine!

Share and Enjoy:

  • Print
  • Digg
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Yahoo! Buzz
  • Twitter
  • Google Bookmarks
  • email
  • Google Buzz
  • RSS
  • Slashdot
  • Technorati
  • Add to favorites
  • DZone
  • LinkedIn
  • MySpace
  • Tumblr

Be the first to comment

Three weeks ago I got certified as a Salesforce.com Certified Force.com Developer and a few weeks before that I got certified as a BigMachines Admin Certified – Yellow belt.

Force.com Salesforce Certified Developer BigMachines Admin Training - Yellow belt

Next step for me would be to take the admin certifications on the Salesforce side since I think I already know them pretty well and after that, if time and planning allows, I guess the Advanced Developer certification would be the obvious choice.

On the BigMachines side, the Blue belt exam is the next step and that probably require more knowledge and hands-on training regarding the Document Engine, the new functionality of version 11 and overall more detailed knowledge.

Share and Enjoy:

  • Print
  • Digg
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Yahoo! Buzz
  • Twitter
  • Google Bookmarks
  • email
  • Google Buzz
  • RSS
  • Slashdot
  • Technorati
  • Add to favorites
  • DZone
  • LinkedIn
  • MySpace
  • Tumblr

Be the first to comment

The other week I was going to deploy some changes to production in BigMachines. BigMachines is roughly speaking our product configurator used to configure products and to create agreements.

Everything worked well in TEST. This time, I was forced to deploy manually which is always a risk since it then depends so much more on the person behind the buttons. Although I can make many things automatic by downloading existing rules from TEST and updating (overwriting) them in PROD for example, there are still many places where things can be forgotten and go wrong.

When I thought that everything had been deployed correctly I was doing a test and noticed with panic increasing deep inside that it didn’t work. Float attributes that were supposed to be forced set were now editable requiring input. The intended idea is that a recommendation sets many of these float attributes to a specific value determined by logic and data tables. Now no value was set and they were not forced, meaning that error messages were displayed not allowing to proceed with the configuration either.

I was lucky and found the error after just a few minutes. It is not very logic to me why it happened but perhaps it can help someone else. I had created an attribute (not being used in this recommendation rule but another one) that I had forgotten to include in the configuration flow. So if this happens to you, start by checking that all attributes used in some way also are in the configuration flow.

Share and Enjoy:

  • Print
  • Digg
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Yahoo! Buzz
  • Twitter
  • Google Bookmarks
  • email
  • Google Buzz
  • RSS
  • Slashdot
  • Technorati
  • Add to favorites
  • DZone
  • LinkedIn
  • MySpace
  • Tumblr

Be the first to comment

When I develop web service providers in Salesforce, I often create mock objects. The reason for this is when I need to return a defined set of fields as a list for many records. The set of fields might be only a subset from an object (standard or custom) or a mix of fields for several objects. Since it is not possible to return maps (sets of key-value pair) from a web service (since there are no such equivalent in SOAP) I have come to the conclusion that this is the best way.

A simple example on how to demonstrate how this works would be a web service that has one method with the task to return records for the Opportunity object between a start date and an end date as the arguments to the method. The caller of the web service are only interested in 5 fields of the opportunity however and not all. Returning a list of opportunity records would be easy but not relevant and would be to send a lot of data not needed for the caller or maybe also not allowed for the caller to see. Creating 5 methods would be just stupid.
The web service would provide a WSDL-file to the caller that wouldn’t have to be changed either even though a field need to be added or removed in the future since the return value would be the same anyhow.

This is what it would look like:

global with sharing class GetOpportunityInfo {

// Define mock object
global class MockOpportunity {
	webservice ID OpportunityId;
	webservice ID AccountId;
	webservice ID AccountOwner;
	webservice String OpportunityName;
	webservice String StageName;
}

/**
 * getOpportunityInfoFields - Webservice method used to get opportunity information
 *
 * @param 'startDate' Date used as part of the filter criteria. Compare with lastModified date.
 * @param 'endDate' Date used as part of the filter criteria. Compare with lastModified date.
 * @return List of MockOpportunity objects
 */
webservice static List<mockOpportunity> getOpportunityInfoFields(Datetime startDate,Datetime endDate) {	

List<Opportunity> opps = [select Id,AccountId,Account.OwnerId,Name,StageName from Opportunity where LastModifiedDate > :startDate and LastModifiedDate < :endDate];		

// Create Mock Opportunity list
List<mockOpportunity> mockOpportunities = new List<mockOpportunity>();

// Loop through list of opportunities matching the criteria
for (Opportunity opp : opps) {
	// Create instance of MockOpportunity object
	MockOpportunity mOpportunity = new MockOpportunity();

	// Set fields of mock object from current opportunity in loop
	mOpportunity.OpportunityId = opp.Id;
	mOpportunity.AccountId = opp.AccountId;
	mOpportunity.AccountOwner = opp.Account.OwnerId;
	mOpportunity.OpportunityName = opp.Name;
	mOpportunity.StageName = opp.StageName;

	// Add mock agreement to mock agreement list
	mockOpportunities.add(mOpportunity);

	// Kill object reference
	mOpportunity = null;
}				

return mockOpportunities;
}

I don’t know if this is the common way of work or not or if anyone have other or better solutions. Anyway, I hope this can bring joy to anyone. Let me know if you got use of it!

Share and Enjoy:

  • Print
  • Digg
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Yahoo! Buzz
  • Twitter
  • Google Bookmarks
  • email
  • Google Buzz
  • RSS
  • Slashdot
  • Technorati
  • Add to favorites
  • DZone
  • LinkedIn
  • MySpace
  • Tumblr

1 comment

How to query deleted records with SOQL

by Niklas Waller on April 21, 2011

in Cloud computing,Salesforce

I have recently created a webservice provider in Salesforce (Apex class) which will be queried for modified data by another system. The other system wants updates of a predefined set of fields for several objects that have been modified. The requirements are also to get notified of whether the modification is an insert, an update or a deletion.

The webservice queries data from the system with a SOQL query. A SOQL query by default only queries records that are not deleted or archived.

select Id,Name,Stage,IsDeleted from Opportunity

Therefore the above SOQL query returns only records where IsDeleted is false. To get deleted records as well all you have to do is add ‘ALL ROWS’ at the end of the query. Like this:

select Id,Name,Stage,IsDeleted from Opportunity ALL ROWS

To return the type of modification that has been done, this logic can be added.

String retVal;

if (opp.IsDeleted == true) {
retVal = 'Deleted';
} else if (opp.CreatedDate == opp.LastModifiedDate) {
retVal = 'Inserted';
} else {
retVal = 'Updated';
}

Share and Enjoy:

  • Print
  • Digg
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Yahoo! Buzz
  • Twitter
  • Google Bookmarks
  • email
  • Google Buzz
  • RSS
  • Slashdot
  • Technorati
  • Add to favorites
  • DZone
  • LinkedIn
  • MySpace
  • Tumblr

3 comments