Communication between Managed Packages

Have you ever wondered, whether it is possible to synchronously communicate between different managed packages in Salesforce? We have! As we have built many managed packages, we thought it would be useful to create a connection between these packages. They would highly benefit from receiving/sending data from/to other packages. Of course, you could create a base package and store all shared data in there, but then the base package would become too large and blow up eventually.

We managed to create an architecture that let’s us have a whole suite of managed packages that be installed in any order and use data of each other, however do not crash, when a required package is not installed. It is therefore fully extendible and every package is independent. Following a diagram of the architecture:

This looks pretty big at first, however after an initial setup it is easy to add new packages. First we need a Base Package that contains a Factory class. This class is responsible for creating instances of the needed classes in different packages. In this example we have three packages: Package A, Package B and Package C. The Base Package must be installed in every Package org, because a direct reference to its classes and interfaces is made. Let’s say the class Sample Class in Package A wants to know if a certain UVW is active in Package B. Then the class can instantiate PackageBProvider through the Factory:

// Alternatively you could throw your own PackageNotFoundException here

System.debug('Package B is not installed');

}

}

Type.forName(namespace, classname) let’s you create a new dynamic type and newInstance() a new instance of the type. After casting it to IPackageBProvider, SampleClass knows which methods are provided. If you need to pass complex parameters or get complex return values, you can create a new container class (such as XYZ) in the Base Package.

Of course it would be possible to run dynamic SOQL queries instead of providing an interface:

Dynamic SOQL instead of an interface

Java

1

2

3

4

5

6

7

List<SObject>listOfTestObjects=

Database.query('SELECT Id, Name, package_b_namespace__TestField__c '+

'FROM package_b_namespace__TestObject__c '+

'WHERE package_b_namespace__TestField__c = True');

System.debug(‘Object‘+listOfTestObjects[0].get(‘Name’)+‘:’+

listOfTestObjects[0].get('package_b_namespace__TestField__c’));

The approach is too error prone however. Whenever there is a change in the data model, the other package developer need to be informed about it. By abstracting it with an interface, they do not need to care about the change.

There is only a single downside to the architecture. It is not possible to change global interfaces after they have been uploaded in a managed package. This means whenever there is a change in the provider interfaces, the following tasks are required:

A new interface is created

The old interface is declared as obsolete

The new version of Base Package must be installed in Package A, B, C

We decided though that this is not a blocker for us. Instead it gives us really nice versioning of the interfaces.