You are on page 1of 7

Using Apex Managed Sharing to Create Custom Record Sharing Logic - developer.force.

com
http://w iki.developerforce.com/index.php/Using_Apex_Managed_Sharing_to_Create_Custom_Record_Sharing_Logic August 27, 2011

Abstract
Force.com allows developers and administrators to control access to data at many different levels. You can control access at the object-level, the record-level and even at the field-level. This article will focus on methods for controlling access to data at the record-level. In the vast majority of cases, the appropriate Force.com sharing settings can be defined declaratively by simply pointing and clicking. In some cases, developers may need the ability to define even more sophisticated sharing settings, and this is where Apex Managed Sharing comes in. Apex Managed Sharing allows you to use Apex Code to build sophisticated and dynamic sharing settings that arent otherwise possible. For example, a developer can use Apex Managed Sharing to write a trigger that will automatically share a custom object record with a user that has been specified in a lookup field. You can also use Apex Managed Sharing to write custom Visualforce controllers that implement your sharing logic After an introduction to sharing, this article looks at the components of Apex Managed Sharing and how you can use Apex Managed Sharing in your own applications. It also provides sample code for the trigger described above. If you need an introduction to these topics, see An Introduction to the Force.com Database and An Overview of Force.com Security.

Understanding Sharing
Organization Wide Defaults are the least granular level of sharing. Organization Wide Defaults allow an administrator to specify a users default access level to an object. From most restrictive to least restrictive, the available default settings are: "Private", "Public Read Only" and "Public Read/Write". All record-level sharing settings, including the ones created by Apex Managed Sharing, are exceptions to these Organization Wide Default sharing settings. Record-level sharing settings can only be used to grant more permissive access to records. Record-level sharing settings cannot be used to restrict access to records. This also means that sharing settings can only be implemented for objects whose object-level sharing defaults are restricted i.e. either Public Read Only or Private. It is not necessary to grant additional permissions on objects that have a default sharing access of Public Read/Write because users already have read/write default access. The declarative sharing settings that the Force.com platform provides are very easy to configure and are very powerful, so before writing any Apex Managed Sharing code, you should verify that the declarative sharing settings will not meet your requirements. Here's a look at the types of sharing settings available to you.

Force.com Managed Sharing


Force.com Managed Sharing involves sharing access granted by Force.com through record ownership, the role hierarchy, and sharing rules: Record Ownership: Each record is owned by a user. The record owner is automatically granted Full Access, allowing them to view, edit, transfer, share, and delete the record. Role Hierarchy: The role hierarchy enables users above another user in the hierarchy to have the same level of access to records owned by or shared with users below them.

Sharing Rules: Sharing rules are defined by administrators. They automatically grant users within a given group/role access to records owned by a specific group of users.

User Managed Sharing, also known as Manual Sharing


User managed sharing allows the record owner, or any user with Full Access to a record, to share the record with another user/group of users. This is generally done by an end-user, for a single record. User managed sharing is removed when the record owner changes or when the access granted in the sharing does not grant additional access beyond the object's organization-wide sharing default access level.

Apex Managed Sharing


Apex managed sharing provides developers with the ability to support an applications particular sharing requirements programmatically via Apex code. The sample use case for Apex managed sharing that we will explore in this article is an "after insert" trigger that grants 'edit' access on a private record to a user specified in a lookup field on that record. Another example use case would be a trigger that shares a record with a group of users once the record meets certain criteria - you could automatically grant 'read' access on a record to a team once the record reaches a certain stage or currency amount. You're not limited to writing triggers though-you can also use Apex managed sharing in custom Visualforce controllers for example. There are many other use cases that Apex managed sharing supports as well. Do keep in mind that Apex managed sharing is currently only available for custom objects. Now let's dive in and learn how records are shared on the platform.

Important Objects Related to Apex Managed Sharing


Sharing is a fairly sophisticated topic, so some explanation of the underlying mechanisms may be helpful.

Sharing Table
All objects that have a default sharing setting of the either "Private" or "Public Read Only" also have a related "Share" object that is similar to an access control list (ACL) found in other platforms. All share objects for custom objects are named as MyCustomObject__Share, where MyCustomObject__c is the name of the related custom object. A share object includes records supporting all three types of sharing: Force.com managed sharing, user managed sharing, and Apex managed sharing. A custom objects share object allows four pieces of information to be defined: The record being shared. The User or Group with whom the object is being shared. The permission level being granted to the User or Group. The reason why the User or Group has been granted sharing access. This information corresponds with the following fields in a share object:

ParentId The Id of the record being shared. This field cannot be updated. UserOrGroupId The Id of the User to whom you are granting access. May also be a Public Group Id, Role Id, or Territory Id. This field cannot be updated. AccessLevel The level of access that the specified User or Group has been granted. Valid values for Apex managed sharing are: Edit, Read. This field must be set to an access level that is higher than the organizations default access level for the parent object. For more information, see Access Levels. The reason why the user or group is being granted access. The reason determines the type of sharing, which in turn controls who can alter the sharing record. This field cannot be updated.

RowCause (aka Sharing Reasons)

Apex Sharing Reasons


Apex code can create records in share tables with either a custom RowCause or with a RowCause that is set as "Manual". A "Manual" RowCause means that the share record will be treated as if it was created by User managed sharing. True Apex managed sharing is when a record in a share table has a custom RowCause, which is known as an Apex sharing reason. Apex sharing reasons are a way for a developer to track why they shared a record with a user or group of users. Using multiple Apex sharing reasons simplifies the coding required to make updates and deletions of sharing records. They also enable developers to share with the same user or group multiple times using different reasons. Each Apex sharing reason has a label and a name. The "label" value is displayed in the "Reason" column when viewing the sharing for a record in the user interface. This allows users and administrators to understand the source of the sharing. The "name" value is used when referencing the reason in the API and Apex. An example sharing Reason Label might be, "My Sharing Reason". The corresponding Reason Name would be, "My_Sharing_Reason__c". This Apex sharing reason would be referenced in Apex as follows: Schema.MyCustomObject__Share.rowCause.My_Sharing_Reason__c

Reasons to Implement Apex Managed Sharing


Building sophisticated and dynamic sharing settings isnt the only reason to use Apex managed sharing. You may also find advantage in the fact that share records created by Apex managed sharing behave differently than the other forms of record-level sharing: Sharing records created by Apex managed sharing are maintained across record owner changes. The only users that can add, edit or delete sharing records created by Apex managed sharing are users with the "Modify All Data" permission. A record can be shared multiple times with a user or group using different Apex sharing reasons.

Apex Managed Sharing


Now that weve discussed sharing in depth, lets take a look at a sample use case and how it might be solved with Apex managed sharing.

Example Use Case


The simple use case that we will use to explain the utility of Apex managed sharing is: "Automatically share a record to a User based on a User-lookup field." For example, imagine that weve just built a recruiting application for our company. In our application, we have a "Job" custom object: In this

example, the Organization Wide Default Sharing Setting for our Job object is set to "Private". This means that when a recruiter at our company creates a new Job record, only the recruiter will have access to that record the hiring manager for the Job wont be able to edit or even view the record that corresponds with her job opening! As we can see if we click on the Job records "Sharing" button, only the recruiter that created the Job record has access to it:

Clearly the hiring manager should have access to her job record as well. This is the perfect use case for Apex managed sharing. To get started, we'll create an Apex sharing reason. Then, we'll write an Apex trigger that will automatically create the appropriate Job_Share record every time a new Job record is created.

Example Apex Sharing Reason


Before we can start writing any Apex managed sharing code, we must create an Apex sharing

reason. To do that: Click Setup | Create | Objects. Select the custom object. (In this case, the "Job" custom object.) Click New in the Apex Sharing Reasons related list. (If you don't see this related list, Apex managed sharing has not been configured for your Org - please contact your support representative.) Enter a label for the Apex sharing reason. Enter a name for the Apex sharing reason. Click Save. The end result will look like this:

Using the naming scheme explained previously, this Apex Sharing Reason will be called Hiring_Manager_Access__c. Let's now look at the code which uses this.

Example Code:
Our Apex Trigger will look like this:
trigger Hiring_Manager_Job_Share on Job__c (after insert) { // We only execute the trigger after a Job record has been inserted // because we need the Id of the Job record to already exist. if(trigger.isInsert){ // Job_Share is the "Share" table that was created when the // Organization Wide Default sharing setting was set to "Private". // Allocate storage for a list of Job__Share records. List<Job__Share> jobShares = new List<Job__Share>();

// For each of the Job records being inserted, do the following: for(Job__c job : trigger.new){ // Create a new Job__Share record to be inserted in to the Job_Share table. Job__Share hiringManagerShare = new Job__Share(); // Populate the Job__Share record with the ID of the record to be shared. hiringManagerShare.ParentId = job.Id; // Then, set the ID of user or group being granted access. In this case, // were setting the Id of the Hiring Manager that was specified by // the Recruiter in the Hiring_Manager__c lookup field on the Job record. // (See Image 1 to review the Job object's schema.) hiringManagerShare.UserOrGroupId = job.Hiring_Manager__c; // Specify that the Hiring Manager should have edit access for // this particular Job record. hiringManagerShare.AccessLevel = 'edit'; // Specify that the reason the Hiring Manager can edit the record is // because hes the Hiring Manager. // (Hiring_Manager_Access__c is the Apex Sharing Reason that we defined earlier.) hiringManagerShare.RowCause = Schema.Job__Share.RowCause.Hiring_Manager_Access__c; // Add the new Share record to the list of new Share records. jobShares.add(hiringManagerShare); } // Insert all of the newly created Share records and capture save result Database.SaveResult[] jobShareInsertResult = Database.insert(jobShares,false); // Error handling code omitted for readability. } }

We've just written a properly "bulkified" trigger that for each new Job record: Creates a Job_Share record. Assigns the Id of the Job record to the Job_Share record's ParentId field. Assigns the User Id of the Hiring Manager to the Job_Share record's UserOrGroupId field. Specifies that the Job_Share's AccessLevel field have a value of 'edit'. Assigns the Hiring_Manager_Access__c Apex Sharing Reason to the JobShare's RowCause field. Inserts the Job_Share record in to the Job_Share table. Now, the next time that a recruiter creates a new Job record, the Hiring Manager will automatically be given access to the record with a custom Sharing Reason of Hiring Manager: That's it!

Summary
This article describes Apex managed sharing, a technique that allows you to use Apex Code to build sophisticated and dynamic sharing settings for records on Force.com. After creating the Sharing Reasons, it's simply a matter of coding the creation of the share record. Besides the straightforward example shown in this article, there are any number of other use cases that Apex managed sharing can support as well - it gives you full control over the record sharing. You should be able to use this code as a starting point and modify it to implement your own custom sharing logic.

References
The following Help topics provide additional context. Search for them in the "Help" module in your Developer Edition environment. Sharing Considerations Managing the Sharing Settings Creating Apex Sharing Reasons The Force.com Platform Developer Guide contains a section that discusses Apex Managed Sharing. The Force.com Apex Code Developer's Guide describes how to share a record programmatically, as we have done here.

About the Author


Jesse Lorenz is a Technical Evangelist at salesforce.com, helping independent software vendors, product teams and other partners to architect and build innovative applications on Force.com.

You might also like