Monday, September 13, 2010

Deleting chatter feeds and comments

Recently I was working on some chatter stuff where i come across the requirement of deleting some chatter feeds (FeedPost) and comments(FeedComment). I try to delete these by making a direct query to the FeedPost and FeedComment object having the ids which i want to delete. But here comes the limitation.

Given post focus on deleting the feeds and comments, while taking these limitation in consideration.

Deleting FeedPost: FeedPost represents the following types of changes in a NewsFeed, UserProfileFeed, or record feed, such as AccountFeed: status updates, text posts, link posts, and content posts.

Limitation: One can't directly query for a FeedPost. FeedPosts are always associated with a feed item, so you can query for them through the feeds.

The following example returns all feed items for a given account, ordered by date descending:

SELECT Id, Type, FeedPost.Body FROM AccountFeed WHERE ParentId = AccountId ORDER BY CreatedDate DESC


So to delete FeedPosts we need to first query for it using its associated feed item and FeedPostsId as shown in the example below. Deleting the feed item will delete all the associated feeds.


List accountFeeds = [Select ParentId, Id, FeedPost.ParentId, FeedPostId From UserFeed where ParentId=: userid and FeedPostId=:chatterParentFeedId];
if(accountFeeds != null) {
delete accountFeeds;
}



Note: NewsFeed does not support delete call. It represents a Chatter feed on a user's home tab. A Chatter feed shows recent changes to records that the user is following.

Deleting FeedComment: A FeedComment is a child object of an associated UserProfileFeed, NewsFeed, or object feed, such as AccountFeed.

Limitation: One can't query FeedComment records directly. They can only be queried via the parent NewsFeed, UserProfileFeed, or entity feed, such as AccountFeed.

The following query returns information, including child FeedComment records:


SELECT ID, CreatedDate, CreatedById, CreatedBy.FirstName, CreatedBy.LastName, ParentId, Parent.Name,
(SELECT CommentBody, FeedItemId FROM FeedComments ORDER BY ID DESC)
FROM NewsFeed
ORDER BY CreatedDate DESC, ID DESC
LIMIT 20


So if we want to delete the comments associated with feed items, one need to query the feed item such as AccountFeed, NewsFeed etc along with FeedComments (filtered using comment id if available to get specific FeedComment record). The below example queries NewsFeed object along with the FeedComment object using the chatterNewsFeedId and chatterCommentId to get specific FeedComment object record to delete.


NewsFeed newFeed = [SELECT Id, (SELECT Id, CommentBody, CreatedDate, CreatedById, CreatedBy.FirstName, CreatedBy.LastName FROM FeedComments where id=:chatterCommentId) FROM NewsFeed where id=:chatterNewsFeedId];
if(newFeed != null) {
List comments = newFeed.FeedComments;
if(comments != null && comments.size() > 0) {
delete comments;
Apexpages.addMessage(new Apexpages.Message(Apexpages.severity.INFO, 'deleted successfully'));
}
}


Similarly one can query for the FeedComment objects using different feed items such AccountFeed, ContactFeed, UserProfileFeed etc. as per the requirement.

Saturday, July 24, 2010

Chatter messenger todo notes

Chatter messenger apps was developed as part of chatter challenge. Its code is available at code share.

Here are some todo's which i am planing as part of its enhancement. It will be a road map for the developers who are interested in doing a open source contribution to this app.

TODO's List:
  1. Support for multiple chats with separate 'chat history' section.(Currently it support only one chat or chat history section (latest requested chat) at a time.)
  2. Giving different sharing options:
  • Sharing to the chatter wall (Currently available).
  • Creating a Case record and sharing chat history as part case comments with some user defined case subject and description.
Any other idea’s from yours side will be greatly appreciated.

For more details related chatter messenger, please follow these pointers:

Monday, July 19, 2010

View State and Associated best practices


Few days back i gone through a very interesting article on view state. I putting some its contents as part of this post. This post will be really very help full for the developers who are new to salesforce and looking for good development practices.

The salesforce Summer '10 release introduced a very good feature which will really make the life of a visualforce developer easier. Especially for those who are working on creating some big pages having lots of fields, components and action buttons and facing the challenge of improving the performance of the page. Each visualforce page that contains a form component also contain a encrypted form field that encapsulates the state of the page know as view state. This view is automatically created and holds the state of the page.

This post is to give a brief overview to view state and the best practices for optimizing the view state in order to improve the page performance.

View state Overview:
While working on a page we are either submitting or retrieving the data to or from the server. The page is initially retrieved with a GET request and form submissions happen via POST requests. From users perspective all this is a state full interaction since the page state is changing based on its previous state. But as we know HTTP is a stateless protocol, which means that the initial GET and the subsequent POSTs requests are treated as independent requests for the page. As a result, some other mechanism is needed to persist state information across HTTP requests.

Here come the role of view state mechanism. In view state mechanism page state is persist as a hidden form field that is automatically created in the form when the page gets generated. View state capture the complete state page. The view state is summited back with other form data, which gives the server enough information to recreate the page state to which new changes can be applied.

Note: View state data is encrypted and cannot be viewed with tools like Firebug.

Getting the View State Inspector:
The Summer '10 release includes a pilot of a tool called the View State Inspector, which lets you view the contents of the view state.This information can help you in optimizing the view state size. This feature needs to be enabled by support - please file a support ticket to get it enabled for your organization. Once enabled, it shows up as a tab in development mode.
 
Image showing view state tab:
ViewState

Best practice for optimizing the view state:
As view state is associated with each page page and it has to be transferred back and forth between the browser and Force.com, there could be a potential performance impact in terms of increased page load times when the view state becomes large. So here are some best practices with can help one optimize the view state size.
  • Minimize number of form on a page: Assume a page contains two forms - form 1 and form 2. Irrespective of which form the user submits and causes a post back, the view state for the page needs to get transferred. To support this, each form on your page will have its own copy of view state. If the associated view state is large, instead of having multiple forms on a page, have a single form and use <apex:actionRegion> to submit portions of the form. This will ensure that only a single copy of the view state is associated with that page. You can find additional details on component here.

// Using two forms
<apex:page controller="MyController">

<apex:form>
<apex:commandButton action="{!saveAccount}"
value="Update Account"/>
<!--Account attributes available for editing -->

</apex:form>

<apex:form>
<apex:commandButton action="{!saveContacts}"
value="Update Contacts"/>
<!--Contact attributes available for editing -->
</apex:form>

</apex:page>
This can be combined into a single form by leveraging the <apex:actionRegion> component.
// Combining into single form and leveraging <apex:actionRegion>
<apex:page controller="MyController">
<apex:form>
<apex:commandButton action="{!saveAccount}"
value="Update Account"/>
<!--Account attributes available for editing -->

<apex:actionRegion>
<apex:commandButton action="{!saveContacts}"
value="Update Contacts"/>
<!--Contact attributes available for editing -->
</apex:actionRegion>

</apex:form>
</apex:page>


  • Declare variable as transient: An instance variable declared as transient is not saved and is not transmitted as part of the view state. If a certain field is needed only for the duration of the page request and does not need to be part of the view state, declare it as transient.

<apex:page controller="ExampleController">
The Current Time is : {!currentDateTime} <br/>
<apex:form>
<apex:commandLink value="refresh"/>
</apex:form>
</apex:page>

public class ExampleController {
transient DateTime currentDateTime;
public String getCurrentDateTime() {
if (currentDateTime == null) currentDateTime = System.now();
return '' + currentDateTime;
}
}


  • Recreate state versus storing it in view state: View state should ideally contain only work in progress data e.g. current object being edited, multi-page wizard data etc. If you can reconstruct the data during postback, via a SOQL query or a web services call, do that instead of storing it in controller data members.
  • Use custom objects or custom settings to store large quantities of read only data: Let us say that your controller needs to call a web service and parse a large response object. Storing it in view state may increase the page size. Marking it as transient would incur the cost of an additional web service call and parsing it again. In such cases, you could store the parsed response in a custom object and just use the stored record id to get to the parsed response. Custom settings provide another mechanism to cache data needed by your controller. Accessing custom settings is faster than access to custom objects since custom settings are part of your application's cache and does not require a database query to retrieve the data.
  • Refine your SOQL to only retrieve the data needed by the page: Only retrieve (and store) the fields you need and also filter the data to only retrieve data needed by the page.
  • Refactor your pages to make its view stateless: Instead of using apex:commandLink or apex:commandButton components (which needs to be inside a apex:form component) to invoke an action, use an apex:outputLink or other non action method instead and implement the action through an apex:page action attribute - where it makes sense.
  • Consider doing your own state management in certain case: In certain cases you may want to bypass the view state mechanism offered by Visualforce and do your own state management. In such cases, use a HTML FORM instead of apex:form. This technique is useful for dealing with Visualforce pages that may have to be served to mobile devices where the view state may be too large for the embedded browsers.

Summery:
Proper management of view state will really make the job of developer easier. One can control the view state and optimize its size by paying attention to transient variables, the number of forms on a page, using custom settings to store data and so on.

Wednesday, June 30, 2010

Chatter Messenger on salesforce IdeaExchange

Today i was looking for some chatter messenger related content on salesforce community. I was really very happy to find some good entry there.

There is a entry on ideaExchange for the instant messenger in chatter. There is really a group of peoples who are interested in having some native messenger with in SFDC org.

The other entry was posted on Force.com Discussion Boards

'Chatter Messenger' is available to all who are interested in having a native SFDC messenger with in there org. It is open for your open contribution and support.

I am really looking forward for some open contributions.

Tuesday, June 29, 2010

My CDC Code Share entries

Finally Both my CDC entries Chatter Notifier and Chatter Messenger are now available on salesforce code share One can browse through the code and even contribute if he/she really interested to do show.

One can have look and feel of these apps by installing to there salesforce org. Both are available will install link available on code share home page.

Note: Salesforce org should be chatter enable to allow successful installing of these apps.

Please feel free to contact me in case of any problem related to these apps.

Monday, June 28, 2010

My chatter development challenge entries

I recently participated in salesforce chatter developer challenge (CDC). I submitted two my app for the challenge as 'Chatter Notifier' and 'Chatter Messenger'.

Details of both as follows:

Chatter messenger:

Chatter messenger allow peoples in an organization to chat with each other. They can have one to one communication using chatter messenger without need of any external messenger from within there salesforce org. Finally they have the option of sharing their chat to their chatter wall with a single click ‘share’.

All peoples in an organization are available as chatter messenger contacts. One can select any contact to chat with. If he is online, he can reply you back. If he is offline, he will receive you message when he gets online to chatter messenger app.

Selecting the Chatter Messenger tab login’s that user to chatter messenger app. Your will be then show as online to other Chatter Messenger user’s. One can change their status to either ‘OffLine?’, ‘Do Not Disturb’ or ‘Invisible’ as required by the user.

If a user (contact) is idle for more than 30 minutes, he will logout and his status will be set as offline. He can again get online by changing his status as ‘Online’.

Chatter messenger provide a real time chatting experience like any other messenger. This can help peoples who want to have one to one discussion with each other while working with in the salesforce org. Later one if they feel to share their discussion they can share their chat or discussion on chatter wall.

Chatter Messenger Detail View:





Code for chatter messenger is available on google code.
Chatter Messenger youtube video

Chatter Notifier:

Chatter notifier notifies once's followers with birthday or anniversary dates. Followers can help that person in celebrate by posting a message on his wall or sending him a gift.

One can control his birthday or anniversary notifications to his followers by using the “Notification” setting tab. If a user has disabled/Unchecked his birthday/anniversary notification, his birthday/anniversary will not be notified to his followers.




Code for chatter notifier is available on google code.

Chatter Notifier youtube video

Other Related Links:

Thursday, October 18, 2007

Investigating CacheFullException for Entity

Why does the problem occur?
A CacheFullException will be thrown when no more beans can be inserted into the cache. This is because the cache is full with beans which are currently participating in a transaction, or the instances cannot be removed from cache because of other reasons. If any bean in the cache can be found that is not active in a transaction, it will be replaced by the current one. The index for the beans in cache is (primary key, transaction).

CacheFullException - for Entity Beans
There are different reasons that can lead to a CacheFullException for Entity beans:

1. The property is set too small to hold all the number of beans that are simultaneously active.
Note that for WLS 6.1, after upgrading to a service pack equal or higher than SP4, this can be an issue, as the setting has not been considered before for Database concurrency.

2.The implementation of the primary key class is incorrect. The related methods equals() and hashcode() need to return unique values for each and every possible primary key value. If this is not the case, there may be instances in the cache that are not reused and not removed from the cache even though they are no longer participating in a transaction. This means the cache may contain instances of entity beans that are not active in a transaction, but cannot be removed, as the index into the cache is not working because of the primary key (PK) class that is improperly implemented.

Note: It is good practice to ensure that all PK classes have been implemented correctly in your code. See sample below where a small coding error caused a problem:

public boolean equals(Object o){
if (o instanceof AbcPK) {
AbcPK otherKey = (AbcPK)o;
return (companyId.equals(otherKey.string1)&& string1.equals(otherKey.companyId));
} else
return false;
}

The code is comparing the wrong fields as follows:

companyId.equals(otherKey.string1)

should be:

companyId.equals(otherKey.companyId)

and

string1.equals(otherKey.companyId)

should be:

string1.equals(otherKey.string1)

3. If the property is set to true, an EJB instance is created and put into the cache for every value that is returned from a finder method.The cache needs to be sized large enough to hold all those EJBs simultaneously, as the finder runs in one transaction. Alternatively, set to false so that EJBs are instantiated only if needed.
4. For WebLogic Server version 6.1, please ensure that the property is set, because otherwise the beans in the cache may not be re-used.
For versions greater or equal than WLS 7.0 SP5 or 8.1 SP3, the property can be used to specify the maximum length of time an entity bean stays in the cache before it is removed. This helps to free memory used by the cache in peak times.
5. For EJBs that use container managed relationships, relationship-caching can be turned on in order to improve performance. Please check the related tag in the weblogic-cmp-rdbms-jar.xml Deployment Descriptor to find out if you use this feature. The settings need to consider the possible sizes of result sets for relationships. This may be relatively large compared to the number of parent beans used.