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
stepbstepb 

Detecting if Chatter is enabled and developing apps with optional Chatter functionality?

Hello, I am developing an application in which I would like to integrate Chatter as an enhancement-- i.e., Chatter would enhance this application's experience, but it isn't required for the main features of this application. Ideally, when an organization does not have Chatter enabled, I would like this application to degrade gracefully and simply not display any of its Chatter features.

 

I've integrated Chatter into this application using Apex components and classes (from Chatter Combo Pack as a starting point), and it works great when Chatter is enabled. If I disable Chatter in my developer organization, then I receive SalesForce errors which make the application completely unusable. For instance: Dependent class is invalid and needs recompilation: chatterFeed: line 275, column 19: sObject type 'UserFeed' is not supported. Sometimes I get SalesForce.com internal errors instead.

 

If Chatter is disabled, then I also have issues editing and saving classes which have Chatter-related features with errors such as: Save error: Dependent class is invalid and needs recompilation: chatterfeeditem: line 3, column 13: Invalid type: FeedPost

 

So my question is, what is the best way to detect if Chatter is enabled for an organization and if it's enabled for an object in that organization? Do I need to describe sObject for every type of Chatter-related object which is used (EntitySubscription, UserFeed, FeedPost, etc.)? Or is there some preferred way to do what I'm describing?

Best Answer chosen by Admin (Salesforce Developers) 
bob17bob17

Here is a code snippet I wrote to test if I could build a managed package that was chatter enabled without requiring chatter be enabled to be installed.  You have to use dynamic SOQL / DML but it is possible.

 

 

Schema.DescribeSObjectResult r = Opportunity.sObjectType.getDescribe();		
if(r.IsFeedEnabled())
{
     SObjectType token = Schema.getGlobalDescribe().get('FeedPost');
     SObject objPost = token.newSObject();
     objPost.put('ParentId', m_oppty.Id); // m_oppty is an instance of an Opportunity object
     objPost.put('Body', 'your chatter post text here');
     insert objPost;	
}

 

 

All Answers

d3developerd3developer

I'm guessing you can just look for the UserFeed and if it doesn't exist Chatter isn't enabled. If you need help I can probably scrape together some sample code.

stepbstepb

I am finding that if I use any object introduced with Chatter, it will not be recognized if Chatter is disabled in the organization which I am trying to save to. (I've only tried with my dev account, but I would assume that it cannot be deployed to production organizations which do not have Chatter enabled either.)  The behavior that occurs is that the Chatter object such UserFeed is treated as an Apex parse error or syntax error.

 

For instance, if I had the following pseudocode:

 

if (isChatterEnabled) {

UserFeed uf = [SELECT query would go here];

}

 

and isChatterEnabled was false, I believe it would still fail to work when the organization had Chatter disabled because it would not understand the "UserFeed" token.

 

It's as if when Chatter is disabled, it acts as if those Chatter objects (UserFeed, EntitySubscription, FeedPost, etc.) do not exist, rather than changing the permissions on them.

 

If you have the time, some sample code would be great, because I am at a loss as to how this can be done. Thanks!

bob17bob17

Here is a code snippet I wrote to test if I could build a managed package that was chatter enabled without requiring chatter be enabled to be installed.  You have to use dynamic SOQL / DML but it is possible.

 

 

Schema.DescribeSObjectResult r = Opportunity.sObjectType.getDescribe();		
if(r.IsFeedEnabled())
{
     SObjectType token = Schema.getGlobalDescribe().get('FeedPost');
     SObject objPost = token.newSObject();
     objPost.put('ParentId', m_oppty.Id); // m_oppty is an instance of an Opportunity object
     objPost.put('Body', 'your chatter post text here');
     insert objPost;	
}

 

 

This was selected as the best answer
d3developerd3developer

bob17,

 

I don't quite follow. Is the test just the isFeedEnabled() method call or does it throw an error otherwise when you attempt to insert the FeedPost?

bob17bob17

d3developer,

 

The test was to build a managed package that would install into an org that does not have Chatter enabled.  The code inside the if condition is an example of creating an entiry post (in this case an opportunity post) using only dynamic DML.  Using only dynamic references the package install process does not know that chatter objects are referenced and will allow the package to install into an org that does not have Chatter enabled.  If a static reference was used such as:

 

FeedPost opptyPost = new FeedPost();

 

the manage package would not be permitted to install into an org that did not have Chatter enabled.

 

The isFeedEnabled method is used to prevent the run time code from executing the attempt to insert a FeedPost which would throw an error if Chatter was not enabled.

 

Hope that answers your question,

 

bob

d3developerd3developer

Makes perfect sense now thanks.

d3developerd3developer

To answer the original poster, I think you'd want something like this:

 

 

Boolean chatterEnabled = false;
	
try
{
     SObjectType token = Schema.getGlobalDescribe().get('FeedPost');
     SObject objPost = token.newSObject();
     objPost.put('ParentId', UserInfo.getUserId()); 
     objPost.put('Body', 'test post');
     insert objPost;
     delete objPost;
     chatterEnabled = true;	

}
catch (Exception e) {
   //
}

 

 

Haven't tested it, but that should also deploy anywhere and correctly set ChatterEnabled whenever Chatter is or is not enabled. 

 

bob17bob17

If checking for the activation state of Chatter is all that is needed, simply use the IsFeedEnabled() method on the object describe result.   This method is new so you have to make sure you class is set to user version 19.0 of the API.

d3developerd3developer

But that's going Object by object instead of attempting to find out if Chatter is enabled for the org and not for any specific object. Also, the User object does not allow toggling of feed tracking, which is why I'm focusing on that one -- since UserStatus updates are always enabled whenever Chatter is enabled (I believe). 

 

Now that I'm thinking about that, potentially what I wrote above could be shortened to running IsFeedEnabled() on the User object. 

bob17bob17

Great point, I had foggotten that you can turn on Chatter support on an object by object basis. 

stepbstepb

This is fantastic. Thanks. I'd like to avoid dynamic SOQL if possible, but I can give this a try if there's no better way at the moment.

 

Thinking along the same lines, one other way that this can be done is to use the Ajax toolkit, I think.

stepbstepb

I had a chance to try this, and while it seems to making progress, there are still problems. The Apex portion works great and it will now save and even go through a test case without failure (althought the % of tested code is much lower now, of course.) In order to make the classes work though, all references to feed objects such as FeedPost and UserFeed had to be changed to generic SObjects. This causes a problem with components/pages which reference these objects because seem to no longer be able to use the object.property syntax on objects that have been changed to the SObject type.

 

This is the save error which now occurs on one of our VisualForce pages which is a result of trying to access the fieldname property on what used to be a FeedTrackedChange object.

 

 

Save error: Unknown property 'SObject.fieldname'

 Does anyone have any ideas for this?

 

bob17bob17

Stepb,

 

When getting a value from an SObject you can't reference a field that is specific to a concrete object.  To get the value from the SObject you need to use the get() method.  For example:

 

String sTheValue = theSObject.get('fieldname');

 

  

stepbstepb

Yes -- but how do I do this in a VisualForce component or page?

 

Edit: Unless, do you mean that I should convert all such fields to a string and use that string value before referencing them in the page?

d3developerd3developer

This may be painful but your best option probably is to create an encasing Wrapper object to hold the values you want to display.

 

Here are two Chatter related examples from my code:

 

http://snipplr.com/view.php?id=38881

 

http://snipplr.com/view.php?id=38882

 

They would need to be rewritten slightly to refer to generic SObjects.

 

stepbstepb

Great, that worked. Thank you both so much for your help!

d3developerd3developer

My pleasure. If you don't mind sharing the code for your Chatter discovery and wrapper object I'd add it to my code snippet library. I'd imagine it will be useful to someone else at some point.