Add Dynamic Application Factory

This enabled realtime dependency injection for the fflib application.
By default the configuration comes from the Custom Metadata object fflib_AppBinding__mdt, but can be fully customised and extended.

Initial stuff
This commit is contained in:
Wim Velzeboer
2021-07-02 13:57:11 +01:00
parent 46276b564f
commit 039e82d73c
73 changed files with 3418 additions and 4 deletions
@@ -150,7 +150,7 @@ public virtual class fflib_ClassicDomainFactory
* avoids the need to stub the mock to return its ObjectType
* @param mockDomain The instance of the Domain mock
*/
public virtual void setMock(Type domainType, fflib_IDomain mockDomain)
public virtual void setMock(Object domainType, fflib_IDomain mockDomain)
{
mockDomainByObject.put(domainType, mockDomain);
}
@@ -0,0 +1,131 @@
/**
* File Name: fflib_AppBinding
* Description: Definition for an Application Binding
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public virtual class fflib_AppBinding
implements fflib_IAppBinding, Comparable
{
protected Object bindingObject { get; set; }
protected Decimal bindingSequence { get; set; }
protected fflib_AppBindingType bindingType { get; set; }
protected System.Type implementationType { get; set; }
protected System.Type interfaceType { get; set; }
protected String namespacePrefix { get; set; }
protected fflib_SharingMode sharingMode { get; set; }
public Integer compareTo(Object compareTo)
{
fflib_IAppBinding compareToEmp = (fflib_IAppBinding) compareTo;
if (getSequence() == compareToEmp.getSequence()) return 0;
if (getSequence() > compareToEmp.getSequence()) return 1;
return -1;
}
public Object getBindingObject()
{
return this.bindingObject;
}
public virtual fflib_AppBindingType getBindingType()
{
return this.bindingType;
}
public virtual System.Type getImplementationType()
{
return this.implementationType;
}
public Type getInterfaceType()
{
return this.interfaceType;
}
public String getNamespacePrefix()
{
return this.namespacePrefix;
}
public Decimal getSequence()
{
return this.bindingSequence;
}
public fflib_SharingMode getSharingMode()
{
return this.sharingMode;
}
public virtual Object newImplInstance()
{
return implementationType.newInstance();
}
public virtual fflib_IAppBinding setBindingObject(Object bindingObject)
{
this.bindingObject = bindingObject;
return this;
}
public virtual fflib_IAppBinding setBindingType(fflib_AppBindingType bindingType)
{
this.bindingType = bindingType;
return this;
}
public virtual fflib_IAppBinding setNamespacePrefix(String namespacePrefix)
{
this.namespacePrefix = namespacePrefix;
return this;
}
public virtual fflib_IAppBinding setImplementationType(System.Type implementationType)
{
this.implementationType = implementationType;
return this;
}
public virtual fflib_IAppBinding setInterfaceType(Type interfaceType)
{
this.interfaceType = interfaceType;
return this;
}
public virtual fflib_IAppBinding setSequence(Decimal sequence)
{
this.bindingSequence = sequence;
return this;
}
public virtual fflib_IAppBinding setSharingMode(fflib_SharingMode sharingMode)
{
this.sharingMode = sharingMode;
return this;
}
}
@@ -0,0 +1,139 @@
/**
* File Name: fflib_AppBindingMetaDataModule
* Description: An application module responsible for loading the application bindings
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public with sharing class fflib_AppBindingMetaDataModule
extends fflib_AppBindingModule
{
public override void init()
{
this.bindings = new List<fflib_IAppBinding>();
for (fflib_AppBinding__mdt binding : fflib_AppBindingsSelector.newInstance().selectAll())
{
addBinding(
new fflib_AppBinding()
.setBindingObject(getBindingObject(binding))
.setBindingType(getBindingType(binding))
.setImplementationType(getSystemType(binding, fflib_AppBinding__mdt.ImplementationType__c))
.setInterfaceType(getSystemType(binding, fflib_AppBinding__mdt.InterfaceType__c))
.setNamespacePrefix(binding.NamespacePrefix)
.setSequence(binding.BindingSequence__c)
.setSharingMode(getSharingModeFromString(binding.SharingMode__c))
);
}
}
private Object getBindingObject(fflib_AppBinding__mdt binding)
{
if (String.isBlank(binding.BindingObject__c) && String.isBlank(binding.BindingObjectAlternate__c)) return null;
String bindingObjectApiName = String.isNotBlank(binding.BindingObject__c)
? binding.BindingObject__r.QualifiedApiName.toLowerCase().trim()
: binding.BindingObjectAlternate__c.toLowerCase().trim();
// Assume its an SObjectType
List<Schema.DescribeSObjectResult> schemaDescribes = Schema.describeSObjects(new List<String> {bindingObjectApiName});
if (schemaDescribes.size() == 1)
{
return schemaDescribes.get(0).getSObjectType();
}
else
{
// check if its an Object (class)
Type objectType = System.Type.forName(bindingObjectApiName);
if (objectType == null)
throw new DeveloperException('Failed to find (S)Object ' + bindingObjectApiName + ' referenced by binding ' + binding.DeveloperName);
return objectType;
}
}
private fflib_AppBindingType getBindingType(fflib_AppBinding__mdt binding)
{
Map<String, fflib_AppBindingType> bindingTypeByStrings = new Map<String, fflib_AppBindingType>();
for (fflib_AppBindingType enumValue : fflib_AppBindingType.values())
{
bindingTypeByStrings.put(String.valueOf(enumValue).toUpperCase(), enumValue);
}
if (bindingTypeByStrings.containsKey(binding.Type__c.toUpperCase()) == false)
throw new DeveloperException(
String.format(
'Unable to identify binding type {0} referenced by binding {1}',
new List<String>{ binding.Type__c, binding.DeveloperName}
)
);
return bindingTypeByStrings.get(binding.Type__c.toUpperCase());
}
private fflib_SharingMode getSharingModeFromString(String sharingMode)
{
switch on sharingMode.toUpperCase()
{
when 'WITH SHARING'
{
return fflib_SharingMode.WithSharing;
}
when 'WITHOUT SHARING'
{
return fflib_SharingMode.WithoutSharing;
}
when 'INHERITED SHARING'
{
return fflib_SharingMode.WithoutSharing;
}
when 'NONE'
{
return null;
}
}
return null;
}
private Type getSystemType(fflib_AppBinding__mdt binding, Schema.SObjectField sObjectField)
{
String systemTypeName = String.valueOf(binding.get(sObjectField));
if (null == systemTypeName) return null;
Type systemType = System.Type.forName(systemTypeName);
if (null == systemType)
throw new DeveloperException(
String.format(
'Unable to find {0} referenced by binding {1} for {2}',
new List<String>{ systemTypeName, binding.DeveloperName, sObjectField.getDescribe().getName()}
)
);
return systemType;
}
public class DeveloperException extends Exception
{
}
}
@@ -0,0 +1,71 @@
/**
* File Name: fflib_AppBindingModule
* Description: An application module is responsible for loading the application bindings
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public virtual class fflib_AppBindingModule
implements fflib_IAppBindingModule
{
protected List<fflib_IAppBinding> bindings;
public fflib_AppBindingModule(){ }
public fflib_AppBindingModule(List<fflib_IAppBinding> bindings)
{
this.bindings = bindings;
}
public virtual void addBinding(fflib_IAppBinding binding)
{
if (null == this.bindings) this.bindings = new List<fflib_IAppBinding>();
this.bindings.add(binding);
}
public virtual void addBindings(List<fflib_IAppBinding> bindings)
{
if (null == this.bindings)
{
this.bindings = bindings;
}
else
{
this.bindings.addAll(bindings);
}
}
public List<fflib_IAppBinding> getBindings()
{
return this.bindings;
}
public virtual void init()
{
if (null == this.bindings) this.bindings = new List<fflib_IAppBinding>();
}
}
@@ -0,0 +1,318 @@
/**
* File Name: fflib_AppBindingResolver
* Description: Resolver for returning the requested binding(s)
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public virtual class fflib_AppBindingResolver
implements fflib_IAppBindingResolver
{
// allow for dependency injection inside the resolver
protected InternalBindings internalBindings
{
get
{
if (null == internalBindings)
{
internalBindings = new InternalBindings();
}
return internalBindings;
}
private set;
}
protected fflib_IAppBinding bindingToResolve
{
get
{
if (bindingToResolve == null)
{
bindingToResolve = internalBindings.newAppBinding();
}
return bindingToResolve;
}
private set;
}
protected fflib_IAppBindings bindings;
private List<fflib_IAppBindingModule> modules;
public static fflib_IAppBindingResolver newInstance()
{
return new fflib_AppBindingResolver();
}
/**
* Constructors
*/
public fflib_AppBindingResolver()
{
}
/**
* Providing routes to the AppBindingResolver constructor provides dependency injection inside the resolver
*
* @param routes The routes
*/
public fflib_AppBindingResolver(fflib_IAppBindingRouter routes)
{
this(routes.getRoutes());
}
public fflib_AppBindingResolver(Map<System.Type, System.Type> internalBindings)
{
this.internalBindings = new InternalBindings(internalBindings);
}
public fflib_IAppBindingResolver addModule(fflib_IAppBindingModule bindingModule)
{
if (null == this.modules) this.modules = new List<fflib_IAppBindingModule>();
this.modules.add(bindingModule);
return this;
}
public fflib_IAppBindingResolver byObject(Object bindingObject)
{
this.bindingToResolve.setBindingObject(bindingObject);
return this;
}
public fflib_IAppBindingResolver bySequence(Integer sequence)
{
this.bindingToResolve.setSequence(sequence);
return this;
}
public fflib_IAppBindingResolver byType(fflib_AppBindingType bindingType)
{
this.bindingToResolve.setBindingType(bindingType);
return this;
}
public fflib_IAppBindingResolver byInterfaceType(Type interfaceType)
{
this.bindingToResolve.setInterfaceType(interfaceType);
return this;
}
public fflib_IAppBindingResolver bySharingMode(fflib_SharingMode sharingMode)
{
this.bindingToResolve.setSharingMode(sharingMode);
return this;
}
public fflib_IAppBindingResolver byNamespacePrefix(String namespacePrefix)
{
this.bindingToResolve.setNamespacePrefix(namespacePrefix);
return this;
}
/**
* Handles lazy loading of modules, if no custom module is configured (via addModule) the default module is returned
*
* @return Returns the configured modules
*/
public List<fflib_IAppBindingModule> getModules()
{
if (null == this.modules)
{
// Lazy load the default Binding module is none other is set.
modules = new List<fflib_IAppBindingModule>
{
internalBindings.newAppBindingModule()
};
}
return modules;
}
public List<fflib_IAppBinding> resolve()
{
if (!hasBindingsLoaded()) loadBindings();
fflib_IAppBindings resolvedBindings =
this.bindings
.selectByNamespacePrefix(bindingToResolve.getNamespacePrefix())
.selectByType(bindingToResolve.getBindingType())
.selectByInterfaceType(bindingToResolve.getInterfaceType())
.selectByObject(bindingToResolve.getBindingObject())
.selectBySharingMode(bindingToResolve.getSharingMode())
.selectBySequence(bindingToResolve.getSequence());
this.bindingToResolve = internalBindings.newAppBinding();
return resolvedBindings.getBindings();
}
protected Boolean hasBindingsLoaded()
{
return (this.bindings != null);
}
/**
* Prepares a domain to store the bindings,
* retrieves the bindings from the modules
* and stores the bindings in this.bindings
*/
protected virtual void loadBindings()
{
this.bindings = internalBindings.newAppBindings();
List<fflib_IAppBindingModule> modules = getModules();
List<fflib_IAppBinding> appBindings = loadModules(modules);
this.bindings.addBindings(
appBindings
);
}
/**
* Initialises all the modules and retrieves their binding.
* Any child modules in all nested will also be initialised and processed
*
* @param modules The modules to load their binding
*
* @return Returns the bindings configured in the given modules
*/
protected virtual List<fflib_IAppBinding> loadModules(List<fflib_IAppBindingModule> modules)
{
List<fflib_IAppBinding> result = new List<fflib_IAppBinding>();
for (fflib_IAppBindingModule module : getModules())
{
module.init();
List<fflib_IAppBinding> bindings = module.getBindings();
List<fflib_IAppBindingModule> subModules = getModulesFromBindings(bindings);
if (subModules.isEmpty() == false)
{
result.addAll(
loadModules(subModules)
);
}
result.addAll(bindings);
}
return result;
}
/**
* Retrieves the bindings of the type module from the given list and returns their instance
*
* @param bindings The bindings to filter
*
* @return Returns the instances of Module bindings
*/
private List<fflib_IAppBindingModule> getModulesFromBindings(List<fflib_IAppBinding> bindings)
{
List<fflib_IAppBindingModule> result = new List<fflib_IAppBindingModule>();
for (fflib_IAppBinding binding : bindings)
{
if (binding.getBindingType() != fflib_AppBindingType.Module) continue;
Object instance = binding.newImplInstance();
if (!(instance instanceof fflib_IAppBindingModule))
throw new DeveloperException(
'Binding module should be an instance of fflib_IAppBindingModule, instead found: '
+ binding.getImplementationType().getName()
);
result.add(
(fflib_IAppBindingModule) instance
);
}
return result;
}
public class InternalBindings
{
private Map<System.Type, System.Type> bindings;
public InternalBindings()
{
}
public InternalBindings(Map<System.Type, System.Type> internalBindings)
{
this.bindings = internalBindings;
}
public fflib_IAppBinding newAppBinding()
{
System.Type interfaceType = fflib_IAppBinding.class;
if (hasInternalBinding(interfaceType))
{
Object instance = getInternalBinding(interfaceType);
if (!(instance instanceof fflib_IAppBinding))
throw new DeveloperException('Invalid internal binding for fflib_IAppBinding');
return (fflib_IAppBinding) instance;
}
return new fflib_AppBinding();
}
public fflib_IAppBindings newAppBindings()
{
System.Type interfaceType = fflib_IAppBindings.class;
if (hasInternalBinding(interfaceType))
{
Object instance = getInternalBinding(interfaceType);
if (!(instance instanceof fflib_IAppBinding))
throw new DeveloperException('Invalid internal binding for fflib_IAppBindings');
return (fflib_IAppBindings) instance;
}
return new fflib_AppBindings();
}
private Boolean hasInternalBinding(System.Type interfaceType)
{
return this.bindings != null && this.bindings.containsKey(interfaceType);
}
private Object getInternalBinding(System.Type interfaceType)
{
return this.bindings.get(interfaceType).newInstance();
}
private fflib_IAppBindingModule newAppBindingModule()
{
System.Type interfaceType = fflib_IAppBindingModule.class;
if (hasInternalBinding(interfaceType))
{
Object instance = getInternalBinding(interfaceType);
if (!(instance instanceof fflib_IAppBindingModule))
throw new DeveloperException('Invalid internal binding for fflib_IAppBindingModule');
return (fflib_IAppBindingModule) instance;
}
return new fflib_AppBindingMetaDataModule();
}
}
public class DeveloperException extends Exception {}
}
@@ -0,0 +1,34 @@
/**
* File Name: fflib_AppBindingType
* Description: Enum for Binding Types
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public enum fflib_AppBindingType
{
Domain, Service, Selector, Controller, Module, Misc
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>51.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,178 @@
/**
* File Name: fflib_AppBindings
* Description: Domain class for fflib_AppBinding objects
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public virtual class fflib_AppBindings
implements fflib_IAppBindings
{
protected List<fflib_IAppBinding> bindings;
public fflib_AppBindings() { }
public fflib_AppBindings(List<fflib_IAppBinding> bindings)
{
this.bindings = bindings;
}
public void addBinding(fflib_IAppBinding binding)
{
if (null == this.bindings)
{
this.bindings = new List<fflib_IAppBinding>{ binding };
}
{
this.bindings.add(binding);
}
}
public void addBindings(List<fflib_IAppBinding> bindings)
{
if (null == this.bindings)
{
this.bindings = bindings;
}
else
{
this.bindings.addAll(bindings);
}
}
public fflib_IAppBindings selectByObject(Object bindingObject)
{
if (null == bindingObject) return this;
List<fflib_IAppBinding> result = new List<fflib_IAppBinding>();
for (fflib_IAppBinding binding : bindings)
{
if (binding.getBindingObject() != bindingObject) continue;
result.add(binding);
}
return new fflib_AppBindings(result);
}
public fflib_IAppBindings selectBySequence(Decimal sequence)
{
bindings.sort();
if (null == sequence) return this;
List<fflib_IAppBinding> result = new List<fflib_IAppBinding>();
for (fflib_IAppBinding binding : bindings)
{
if (binding.getSequence() != sequence) continue;
result.add(binding);
}
return new fflib_AppBindings(result);
}
public fflib_IAppBindings selectByType(fflib_AppBindingType bindingType)
{
if (null == bindingType) return this;
List<fflib_IAppBinding> result = new List<fflib_IAppBinding>();
for (fflib_IAppBinding binding : bindings)
{
if (binding.getBindingType() != bindingType) continue;
result.add(binding);
}
return new fflib_AppBindings(result);
}
public fflib_IAppBindings selectByInterfaceType(Type interfaceType)
{
if (null == interfaceType) return this;
List<fflib_IAppBinding> result = new List<fflib_IAppBinding>();
for (fflib_IAppBinding binding : bindings)
{
if (binding.getInterfaceType() != interfaceType) continue;
result.add(binding);
}
return new fflib_AppBindings(result);
}
public fflib_IAppBindings selectBySharingMode(fflib_SharingMode sharingMode)
{
if (null == sharingMode) return this;
List<fflib_IAppBinding> result = new List<fflib_IAppBinding>();
for (fflib_IAppBinding binding : bindings)
{
if (binding.getSharingMode() != sharingMode) continue;
result.add(binding);
}
return new fflib_AppBindings(result);
}
public fflib_IAppBindings selectByNamespacePrefix(String namespacePrefix)
{
if (null == namespacePrefix) return this;
List<fflib_IAppBinding> result = new List<fflib_IAppBinding>();
for (fflib_IAppBinding binding : bindings)
{
if (binding.getNamespacePrefix() != namespacePrefix) continue;
result.add(binding);
}
return new fflib_AppBindings(result);
}
public List<fflib_IAppBinding> getBindings()
{
return this.bindings;
}
public List<System.Type> getImplementations()
{
List<System.Type> result = new List<System.Type>();
for (fflib_IAppBinding binding : bindings)
{
result.add(
binding.getImplementationType()
);
}
return result;
}
public List<Object> getObjects()
{
return getBindings();
}
public Object getType()
{
return fflib_IAppBinding.class;
}
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>51.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,93 @@
/**
* File Name: fflib_AppBindingsSelector
* Description: Selector for fflib_AppBinding__mdt records
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public virtual without sharing class fflib_AppBindingsSelector extends fflib_SObjectSelector
{
// Used for mocking
@TestVisible
private static System.Type SELECTOR_IMPL_TYPE = fflib_AppBindingsSelector.class;
public List<Schema.SObjectField> getSObjectFieldList()
{
return new List<Schema.SObjectField>
{
fflib_AppBinding__mdt.Id,
fflib_AppBinding__mdt.BindingObject__c,
fflib_AppBinding__mdt.BindingObjectAlternate__c,
fflib_AppBinding__mdt.BindingSequence__c,
fflib_AppBinding__mdt.DeveloperName,
fflib_AppBinding__mdt.NamespacePrefix,
fflib_AppBinding__mdt.ImplementationType__c,
fflib_AppBinding__mdt.InterfaceType__c,
fflib_AppBinding__mdt.SharingMode__c,
fflib_AppBinding__mdt.Type__c
};
}
public static fflib_AppBindingsSelector newInstance()
{
return (fflib_AppBindingsSelector) SELECTOR_IMPL_TYPE.newInstance();
}
public Schema.SObjectType getSObjectType()
{
return fflib_AppBinding__mdt.SObjectType;
}
public virtual List<fflib_AppBinding__mdt> selectAll()
{
/**
Todo - Waiting to uncomment the following section
until fflib-apex-common fixes the getFieldPath issue
Currently failing on the BindingObject__r field,
thinking its not a relationship field
Error on line 119, column 1: fflib_QueryFactory.NonReferenceFieldException:
fflib_AppBinding__mdt.BindingObject__r is not a lookup or master-detail
field but is used in a cross-object query field.
return (List<fflib_AppBinding__mdt>) Database.query(
newQueryFactory()
.selectField('BindingObject__r.QualifiedApiName')
.toSOQL());
*/
return (List<fflib_AppBinding__mdt>) Database.query(
String.format(
'SELECT {0} FROM {1}',
new List<String>
{
getFieldListString() + ', BindingObject__r.QualifiedApiName',
getSObjectType().getDescribe().getName()
}
)
);
}
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>51.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,56 @@
/**
* File Name: fflib_DynamicAppFactory
* Description: Abstract class with common functionality for Dynamic Bindings
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public abstract class fflib_DynamicAppFactory
{
protected fflib_SharingMode sharingMode;
protected fflib_IAppBindingResolver resolver;
protected Map<System.Type, System.Type> routes;
protected Map<Object, Object> mockImplByObjectType = new Map<Object, Object>();
protected void setMock(Object objectType, Object mock)
{
this.mockImplByObjectType.put(
objectType,
mock
);
}
protected Object getMock(Object objectType)
{
return this.mockImplByObjectType.get(objectType);
}
protected Boolean hasMock(Object objectType)
{
return this.mockImplByObjectType.containsKey(objectType);
}
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>51.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,123 @@
/**
* File Name: fflib_DynamicDomainFactory
* Description:
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public virtual class fflib_DynamicDomainFactory
extends fflib_DynamicAppFactory
implements fflib_IDomainFactory
{
public static final fflib_AppBindingType DOMAIN = fflib_AppBindingType.Domain;
protected Map<Object, fflib_IDomain> mockDomainByObjectType = new Map<Object, fflib_IDomain>();
protected fflib_ISelectorFactory selectorFactory;
public fflib_DynamicDomainFactory(fflib_IAppBindingResolver resolver, fflib_ISelectorFactory selectorFactory)
{
this.resolver = resolver;
this.selectorFactory = selectorFactory;
}
public fflib_IDomain newInstance(Set<Id> recordIds)
{
return newInstance(this.selectorFactory.selectById(recordIds));
}
public fflib_IDomain newInstance(Set<Id> recordIds, SObjectType sObjectType)
{
return newInstance(this.selectorFactory.selectById(recordIds, sObjectType));
}
public fflib_IDomain newInstance(List<SObject> records)
{
SObjectType sObjectType = records.getSObjectType();
if (sObjectType == null)
throw new DeveloperException('Could not determine the SObjectType of the provided records');
return newInstance(
(List<Object>) records,
(Object) sObjectType
);
}
public fflib_IDomain newInstance(List<Object> objects, Object objectType)
{
if (hasMock(objectType)) return (fflib_IDomain) getMock(objectType);
List<fflib_IAppBinding> bindings = resolver.byObject(objectType)
.byType(DOMAIN)
.resolve();
if (bindings.isEmpty())
throw new DeveloperException('Unable to find domain binding ' + objectType);
System.Type domainImplementationType = bindings.get(0).getImplementationType();
Object instance = domainImplementationType.newInstance();
if (!(instance instanceof fflib_IDomainConstructor))
throw new DeveloperException(
String.format(
'Domain implementation {0} should be an instance of fflib_IDomainConstructor',
new List<String> { domainImplementationType.getName() }
)
);
return ((fflib_IDomainConstructor) domainImplementationType.newInstance())
.construct(objects);
}
public fflib_IDomain newInstance(List<SObject> records, SObjectType domainSObjectType)
{
return newInstance((List<Object>) records, (Object) domainSObjectType);
}
public void setMock(fflib_ISObjectDomain mockDomain)
{
super.setMock(mockDomain.getType(), mockDomain);
}
public void setMock(Schema.SObjectType sObjectType, fflib_ISObjectDomain mockDomain)
{
super.setMock(sObjectType, mockDomain);
}
public void setMock(fflib_IDomain mockDomain)
{
super.setMock(mockDomain.getType(), mockDomain);
}
public void setMock(Object domainType, fflib_IDomain mockDomain)
{
super.setMock(domainType, mockDomain);
}
public class DeveloperException extends Exception {}
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>51.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,137 @@
/**
* File Name: fflib_DynamicSelectorFactory
* Description:
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public virtual class fflib_DynamicSelectorFactory
extends fflib_DynamicAppFactory
implements fflib_ISelectorFactory
{
public static final fflib_AppBindingType SELECTOR_BINDING_TYPE = fflib_AppBindingType.Selector;
protected Map<Object, Object> mockSelectorImplByObjectType = new Map<Object, Object>();
public fflib_DynamicSelectorFactory(fflib_IAppBindingResolver resolver)
{
this.resolver = resolver;
}
public fflib_ISObjectSelector newInstance(SObjectType sObjectType)
{
if (hasMock(sObjectType)) return (fflib_ISObjectSelector) getMock(sObjectType);
List<fflib_IAppBinding> bindings = resolver
.byType(SELECTOR_BINDING_TYPE)
.byObject(sObjectType)
.bySharingMode(sharingMode)
.resolve();
if (bindings.isEmpty())
throw new DeveloperException(
String.format(
'Unable to find selector binding {0} with sharing more {0}',
new List<String>
{
sObjectType.getDescribe().getName(),
sharingMode.name()
}
)
);
return (fflib_ISObjectSelector) bindings.get(0).newImplInstance();
}
public List<SObject> selectById(Set<Id> recordIds)
{
if (null == recordIds || recordIds.size() == 0)
throw new fflib_Application.DeveloperException('Invalid record Id\'s set');
return selectById(recordIds, new List<Id>(recordIds)[0].getSObjectType());
}
public List<SObject> selectById(Set<Id> recordIds, SObjectType sObjectType)
{
if (null == recordIds || recordIds.size() == 0)
throw new fflib_Application.DeveloperException('Invalid record Id\'s set');
return newInstance(sObjectType)
.selectSObjectsById(recordIds);
}
public List<SObject> selectByRelationship(List<SObject> relatedRecords, SObjectField relationshipField)
{
Set<Id> relatedIds =
new RelatedRecordsDomain(relatedRecords)
.getRelatedIds(relationshipField);
if (relatedIds.isEmpty()) return new List<SObject>();
return selectById(relatedIds);
}
public void replaceWith(SObjectType sObjectType, Type replacementImplType)
{
resolver.byType(fflib_AppBindingType.Selector)
.byObject(sObjectType)
.bySharingMode(this.sharingMode)
.resolve()
.get(0)
.setImplementationType(replacementImplType);
}
public void setMock(fflib_ISObjectSelector selectorInstance)
{
setMock(selectorInstance.sObjectType(), selectorInstance);
}
public void setMock(SObjectType sObjectType, fflib_ISObjectSelector selectorInstance)
{
super.setMock(sObjectType, selectorInstance);
}
public fflib_DynamicSelectorFactory setSharingMode(fflib_SharingMode sharingMode)
{
this.sharingMode = sharingMode;
return this;
}
private class RelatedRecordsDomain extends SObjects
{
public RelatedRecordsDomain(List<SObject> records)
{
super(records);
}
public Set<Id> getRelatedIds(Schema.SObjectField relationshipField)
{
return getIdFieldValues(relationshipField).getIds();
}
}
public class DeveloperException extends Exception {}
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>51.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,91 @@
/**
* File Name: fflib_DynamicServiceFactory
* Description: Service Factory to return service class instances in a dynamic way
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public virtual class fflib_DynamicServiceFactory
extends fflib_DynamicAppFactory
implements fflib_IServiceFactory
{
public static final fflib_AppBindingType SERVICE_BINDING_TYPE = fflib_AppBindingType.Service;
protected Map<System.Type, Object> mockServiceImplByObjectType = new Map<System.Type, Object>();
public fflib_DynamicServiceFactory(fflib_IAppBindingResolver resolver)
{
this.resolver = resolver;
}
public Object newInstance(Type serviceInterfaceType)
{
if (hasMock(serviceInterfaceType)) return getMock(serviceInterfaceType);
List<fflib_IAppBinding> bindings = resolver
.byType(SERVICE_BINDING_TYPE)
.byInterfaceType(serviceInterfaceType)
.bySharingMode(sharingMode)
.resolve();
if (bindings.isEmpty())
throw new DeveloperException(
String.format(
'Unable to find service binding {0} with sharing more {0}',
new List<String>
{
serviceInterfaceType.getName(),
sharingMode.name()
}
)
);
return bindings.get(0).newImplInstance();
}
public void replaceWith(Type serviceInterfaceType, Type replacementImplType)
{
resolver.byType(SERVICE_BINDING_TYPE)
.byInterfaceType(serviceInterfaceType)
.bySharingMode(sharingMode)
.resolve()
.get(0) // TODO - validate that there are any resolved bindings
.setImplementationType(replacementImplType);
}
public void setMock(Type serviceInterfaceType, Object serviceImpl)
{
super.setMock(serviceInterfaceType, serviceImpl);
}
public fflib_DynamicServiceFactory setSharingMode(fflib_SharingMode sharingMode)
{
this.sharingMode = sharingMode;
return this;
}
public class DeveloperException extends Exception {}
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>51.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,34 @@
/**
* File Name: fflib_SharingMode
* Description: Enum with the Application Binding Sharing Modes
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public enum fflib_SharingMode
{
WithSharing, WithoutSharing, InheritedSharing, None
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>51.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,50 @@
/**
* File Name: fflib_IAppBinding
* Description: Interface for Application Binding Data Object
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public interface fflib_IAppBinding
{
Object getBindingObject();
fflib_AppBindingType getBindingType();
System.Type getImplementationType();
System.Type getInterfaceType();
String getNamespacePrefix();
Decimal getSequence();
fflib_SharingMode getSharingMode();
Object newImplInstance();
fflib_IAppBinding setBindingObject(Object bindingObject);
fflib_IAppBinding setBindingType(fflib_AppBindingType bindingType);
fflib_IAppBinding setNamespacePrefix(String namespacePrefix);
fflib_IAppBinding setImplementationType(System.Type implementationType);
fflib_IAppBinding setInterfaceType(System.Type interfaceType);
fflib_IAppBinding setSequence(Decimal sequence);
fflib_IAppBinding setSharingMode(fflib_SharingMode sharingMode);
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>51.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,37 @@
/**
* File Name: fflib_IAppBindingModule
* Description: Interface for the Application Module
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public interface fflib_IAppBindingModule
{
void init();
void addBinding(fflib_IAppBinding binding);
void addBindings(List<fflib_IAppBinding> bindings);
List<fflib_IAppBinding> getBindings();
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>51.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,41 @@
/**
* File Name: fflib_IAppBindingResolver
* Description:
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public interface fflib_IAppBindingResolver
{
fflib_IAppBindingResolver addModule(fflib_IAppBindingModule bindingModule);
fflib_IAppBindingResolver byObject(Object bindingObject);
fflib_IAppBindingResolver bySequence(Integer sequence);
fflib_IAppBindingResolver byType(fflib_AppBindingType bindingType);
fflib_IAppBindingResolver byInterfaceType(System.Type interfaceType);
fflib_IAppBindingResolver bySharingMode(fflib_SharingMode sharingMode);
fflib_IAppBindingResolver byNamespacePrefix(String namespacePrefix);
List<fflib_IAppBinding> resolve();
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>51.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,34 @@
/**
* File Name: fflib_IAppBindingRouter
* Description:
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public interface fflib_IAppBindingRouter
{
Map<System.Type, System.Type> getRoutes();
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>51.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,46 @@
/**
* File Name: fflib_IAppBindings
* Description: Domain class interface signatures for fflib_AppBindings
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public interface fflib_IAppBindings
extends fflib_IDomain
{
void addBinding(fflib_IAppBinding binding);
void addBindings(List<fflib_IAppBinding> bindings);
fflib_IAppBindings selectByObject(Object bindingObject);
fflib_IAppBindings selectBySequence(Decimal sequence);
fflib_IAppBindings selectByType(fflib_AppBindingType bindingType);
fflib_IAppBindings selectByInterfaceType(System.Type interfaceType);
fflib_IAppBindings selectBySharingMode(fflib_SharingMode sharingMode);
fflib_IAppBindings selectByNamespacePrefix(String namespacePrefix);
List<fflib_IAppBinding> getBindings();
List<System.Type> getImplementations();
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>51.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,109 @@
<?xml version="1.0" encoding="UTF-8"?>
<Layout xmlns="http://soap.sforce.com/2006/04/metadata">
<layoutSections>
<customLabel>false</customLabel>
<detailHeading>false</detailHeading>
<editHeading>true</editHeading>
<label>Information</label>
<layoutColumns>
<layoutItems>
<behavior>Required</behavior>
<field>MasterLabel</field>
</layoutItems>
<layoutItems>
<behavior>Required</behavior>
<field>DeveloperName</field>
</layoutItems>
<layoutItems>
<behavior>Required</behavior>
<field>Type__c</field>
</layoutItems>
</layoutColumns>
<layoutColumns>
<layoutItems>
<behavior>Edit</behavior>
<field>IsProtected</field>
</layoutItems>
<layoutItems>
<behavior>Required</behavior>
<field>NamespacePrefix</field>
</layoutItems>
</layoutColumns>
<style>TwoColumnsTopToBottom</style>
</layoutSections>
<layoutSections>
<customLabel>true</customLabel>
<detailHeading>true</detailHeading>
<editHeading>true</editHeading>
<label>Binding</label>
<layoutColumns>
<layoutItems>
<behavior>Edit</behavior>
<field>BindingObject__c</field>
</layoutItems>
<layoutItems>
<behavior>Edit</behavior>
<field>BindingObjectAlternate__c</field>
</layoutItems>
<layoutItems>
<behavior>Edit</behavior>
<field>BindingSequence__c</field>
</layoutItems>
</layoutColumns>
<layoutColumns>
<layoutItems>
<behavior>Edit</behavior>
<field>InterfaceType__c</field>
</layoutItems>
<layoutItems>
<behavior>Required</behavior>
<field>ImplementationType__c</field>
</layoutItems>
<layoutItems>
<behavior>Required</behavior>
<field>SharingMode__c</field>
</layoutItems>
</layoutColumns>
<style>TwoColumnsLeftToRight</style>
</layoutSections>
<layoutSections>
<customLabel>false</customLabel>
<detailHeading>false</detailHeading>
<editHeading>true</editHeading>
<label>System Information</label>
<layoutColumns>
<layoutItems>
<behavior>Readonly</behavior>
<field>CreatedById</field>
</layoutItems>
</layoutColumns>
<layoutColumns>
<layoutItems>
<behavior>Readonly</behavior>
<field>LastModifiedById</field>
</layoutItems>
</layoutColumns>
<style>TwoColumnsTopToBottom</style>
</layoutSections>
<layoutSections>
<customLabel>true</customLabel>
<detailHeading>true</detailHeading>
<editHeading>false</editHeading>
<label>Custom Links</label>
<layoutColumns/>
<layoutColumns/>
<layoutColumns/>
<style>CustomLinks</style>
</layoutSections>
<showEmailCheckbox>false</showEmailCheckbox>
<showHighlightsPanel>false</showHighlightsPanel>
<showInteractionLogPanel>false</showInteractionLogPanel>
<showRunAssignmentRulesCheckbox>false</showRunAssignmentRulesCheckbox>
<showSubmitAndAttachButton>false</showSubmitAndAttachButton>
<summaryLayout>
<masterLabel>00h55000002F8hB</masterLabel>
<sizeX>4</sizeX>
<sizeY>0</sizeY>
<summaryLayoutStyle>Default</summaryLayoutStyle>
</summaryLayout>
</Layout>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
<label>Application Binding</label>
<pluralLabel>Application Bindings</pluralLabel>
<visibility>Public</visibility>
</CustomObject>
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>BindingObjectAlternate__c</fullName>
<description>Use this field to specify the SObject API name to bind to when the &quot;Binding Object&quot; field does not list that particular SObject. Only specify the &quot;Binding Object&quot; field or this one; not both.</description>
<externalId>false</externalId>
<fieldManageability>SubscriberControlled</fieldManageability>
<inlineHelpText>Use this field to specify the SObject API name to bind to when the &quot;Binding Object&quot; field does not list that particular SObject. Only specify the &quot;Binding Object&quot; field or this one; not both.</inlineHelpText>
<label>Binding Object Alternate</label>
<length>255</length>
<required>false</required>
<type>Text</type>
<unique>false</unique>
</CustomField>
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>BindingObject__c</fullName>
<externalId>false</externalId>
<fieldManageability>SubscriberControlled</fieldManageability>
<label>Binding Object</label>
<referenceTo>EntityDefinition</referenceTo>
<relationshipLabel>Bindings</relationshipLabel>
<relationshipName>Bindings</relationshipName>
<required>false</required>
<type>MetadataRelationship</type>
<unique>false</unique>
</CustomField>
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>BindingSequence__c</fullName>
<externalId>false</externalId>
<fieldManageability>SubscriberControlled</fieldManageability>
<label>Binding Sequence</label>
<precision>18</precision>
<required>false</required>
<scale>0</scale>
<type>Number</type>
<unique>false</unique>
</CustomField>
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>ImplementationType__c</fullName>
<externalId>false</externalId>
<fieldManageability>SubscriberControlled</fieldManageability>
<label>Implementation Type</label>
<length>255</length>
<required>true</required>
<type>Text</type>
<unique>false</unique>
</CustomField>
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>InterfaceType__c</fullName>
<externalId>false</externalId>
<fieldManageability>SubscriberControlled</fieldManageability>
<label>Interface Type</label>
<length>255</length>
<required>false</required>
<type>Text</type>
<unique>false</unique>
</CustomField>
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>SharingMode__c</fullName>
<defaultValue>&quot;With Sharing&quot;</defaultValue>
<externalId>false</externalId>
<fieldManageability>DeveloperControlled</fieldManageability>
<label>Sharing mode</label>
<required>true</required>
<type>Picklist</type>
<valueSet>
<restricted>true</restricted>
<valueSetDefinition>
<sorted>false</sorted>
<value>
<fullName>With Sharing</fullName>
<default>true</default>
<label>With Sharing</label>
</value>
<value>
<fullName>Without Sharing</fullName>
<default>false</default>
<label>Without Sharing</label>
</value>
<value>
<fullName>Inherited Sharing</fullName>
<default>false</default>
<label>Inherited Sharing</label>
</value>
<value>
<fullName>None</fullName>
<default>false</default>
<label>None</label>
</value>
</valueSetDefinition>
</valueSet>
</CustomField>
@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>Type__c</fullName>
<externalId>false</externalId>
<fieldManageability>DeveloperControlled</fieldManageability>
<inlineHelpText>Type of binding or Logical layers of functionality</inlineHelpText>
<label>Binding Type</label>
<required>true</required>
<type>Picklist</type>
<valueSet>
<restricted>true</restricted>
<valueSetDefinition>
<sorted>false</sorted>
<value>
<fullName>Domain</fullName>
<default>true</default>
<label>Domain</label>
</value>
<value>
<fullName>Service</fullName>
<default>false</default>
<label>Service</label>
</value>
<value>
<fullName>Selector</fullName>
<default>false</default>
<label>Selector</label>
</value>
<value>
<fullName>Controller</fullName>
<default>false</default>
<label>Controller</label>
</value>
<value>
<fullName>Module</fullName>
<default>false</default>
<label>Module</label>
</value>
<value>
<fullName>EventListener</fullName>
<default>false</default>
<label>Event Listener</label>
</value>
<value>
<fullName>Miscellaneous</fullName>
<default>false</default>
<label>Miscellaneous</label>
</value>
</valueSetDefinition>
</valueSet>
</CustomField>
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<ListView xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>All</fullName>
<columns>MasterLabel</columns>
<columns>BindingObject__c</columns>
<columns>BindingObjectAlternate__c</columns>
<columns>BindingSequence__c</columns>
<columns>InterfaceType__c</columns>
<columns>ImplementationType__c</columns>
<filterScope>Everything</filterScope>
<label>All</label>
</ListView>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<ValidationRule xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>BindObj_Or_BindObjAlt</fullName>
<active>true</active>
<description>This validation rule ensures that only the &quot;Binding Object&quot; or the &quot;Binding Object Alternate&quot; field is specified and not both.</description>
<errorConditionFormula>NOT( ISBLANK( BindingObject__c ) ) &amp;&amp; NOT( ISBLANK( BindingObjectAlternate__c ) )</errorConditionFormula>
<errorMessage>Only specify the &quot;Binding Object&quot; field or the &quot;Binding Object Alternate&quot; field; not both.</errorMessage>
</ValidationRule>
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<ValidationRule xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>Require_Interface_Type_For_Services</fullName>
<active>true</active>
<description>An Interface Type is required for Service class Bindings</description>
<errorConditionFormula>AND(ISPICKVAL(Type__c,&quot;Service&quot;), ISBLANK( InterfaceType__c ) )</errorConditionFormula>
<errorDisplayField>ImplementationType__c</errorDisplayField>
<errorMessage>An Interface Type is required for Service class Bindings</errorMessage>
</ValidationRule>
@@ -42,7 +42,7 @@ public interface fflib_IDomainFactory
**/
fflib_IDomain newInstance(Set<Id> recordIds);
fflib_IDomain newInstance(Set<Id> recordIds, Schema.SObjectType objectType);
fflib_IDomain newInstance(Set<Id> recordIds, Schema.SObjectType sObjectType);
/**
* Dynamically constructs an instance of the Domain class for the given records
@@ -95,5 +95,5 @@ public interface fflib_IDomainFactory
* avoids the need to stub the mock to return its ObjectType
* @param mockDomain The instance of the Domain mock
*/
void setMock(Type domainType, fflib_IDomain mockDomain);
void setMock(Object domainType, fflib_IDomain mockDomain);
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>51.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>51.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>51.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>51.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,147 @@
/**
* File Name: fflib_DynamicDomainFactoryTest
* Description:
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@IsTest(IsParallel=true)
public class fflib_DynamicDomainFactoryTest
{
private static final fflib_IAppBindingResolver bindingResolver =
new fflib_AppBindingResolver();
private static final fflib_IDomainFactory Domain =
new fflib_DynamicDomainFactory(
bindingResolver,
fflib_DynamicSelectorFactoryTest.Selector);
private static final SObjectType ACCOUNT_OBJECT_TYPE = Schema.Account.SObjectType;
@IsTest
static void itShouldReturnDomain()
{
// Mock the App Bindings selector
fflib_AppBindingsSelector.SELECTOR_IMPL_TYPE = AppBindingsSelectorMock.class;
final List<Account> records = generateAccountRecords();
System.Test.startTest();
Object instance = Domain.newInstance(records);
System.Test.stopTest();
System.assert(instance instanceof fflib_SObjects);
}
@IsTest
static void itShouldReturnDomainById()
{
// Mock the App Bindings selector
fflib_AppBindingsSelector.SELECTOR_IMPL_TYPE = AppBindingsSelectorMock.class;
final List<Account> records = generateAccountRecords();
final Set<Id> ids = new fflib_SObjects(records).getRecordIds();
fflib_ApexMocks mocks = new fflib_ApexMocks();
fflib_ISObjectSelector selectorMock = (fflib_ISObjectSelector) mocks.mock(fflib_ISObjectSelector.class);
mocks.startStubbing();
mocks.when(selectorMock.selectSObjectsById(ids)).thenReturn(records);
mocks.stopStubbing();
fflib_DynamicSelectorFactoryTest.Selector.setMock(ACCOUNT_OBJECT_TYPE, selectorMock);
System.Test.startTest();
Object instance = Domain.newInstance(ids);
System.Test.stopTest();
System.assert(instance instanceof fflib_SObjects);
System.assertEquals(records, ((fflib_SObjects) instance).getRecords());
}
@IsTest
static void itShouldReturnTheMockDomain()
{
// Mock the App Bindings selector
fflib_AppBindingsSelector.SELECTOR_IMPL_TYPE = AppBindingsSelectorMock.class;
final List<Account> records = generateAccountRecords();
final Set<Id> ids = new fflib_SObjects(records).getRecordIds();
fflib_ApexMocks mocks = new fflib_ApexMocks();
fflib_SObjects domainMock = (fflib_SObjects) mocks.mock(fflib_SObjects.class);
mocks.startStubbing();
mocks.when(domainMock.getType()).thenReturn(ACCOUNT_OBJECT_TYPE);
mocks.when(domainMock.getRecords()).thenReturn(new List<Account>());
mocks.stopStubbing();
System.Test.startTest();
fflib_SObjects instanceA = (fflib_SObjects) Domain.newInstance(records);
Domain.setMock(domainMock);
fflib_SObjects instanceB = (fflib_SObjects) Domain.newInstance(records, ACCOUNT_OBJECT_TYPE);
System.Test.stopTest();
System.assertEquals(records, instanceA.getRecords());
System.assert(instanceB.getRecords().isEmpty());
}
private static List<Account> generateAccountRecords()
{
List<Account> records = new List<Account>
{
new Account(Id = fflib_IDGenerator.generate(ACCOUNT_OBJECT_TYPE)),
new Account(Id = fflib_IDGenerator.generate(ACCOUNT_OBJECT_TYPE)),
new Account(Id = fflib_IDGenerator.generate(ACCOUNT_OBJECT_TYPE))
};
return records;
}
public class MyDomainConstructor implements fflib_IDomainConstructor
{
public fflib_IDomain construct(List<Object> objects)
{
return new fflib_SObjects((List<SObject>) objects);
}
}
private class AppBindingsSelectorMock extends fflib_AppBindingsSelector
{
public override List<fflib_AppBinding__mdt> selectAll()
{
return new List<fflib_AppBinding__mdt>
{
new fflib_AppBinding__mdt(
Type__c = 'Domain',
BindingObject__c = '',
BindingObjectAlternate__c = ACCOUNT_OBJECT_TYPE.getDescribe().getName(),
ImplementationType__c = MyDomainConstructor.class.getName(),
SharingMode__c = 'None'
)
};
}
}
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>51.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,156 @@
/**
* File Name: fflib_DynamicSelectorFactoryTest
* Description:
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@IsTest(IsParallel=true)
public class fflib_DynamicSelectorFactoryTest
{
private static fflib_IAppBindingResolver bindingResolver =
new fflib_AppBindingResolver();
@TestVisible
private static final fflib_ISelectorFactory Selector =
new fflib_DynamicSelectorFactory(bindingResolver)
.setSharingMode(fflib_SharingMode.WithSharing);
private static final Type MY_SELECTOR_TYPE = fflib_DynamicSelectorFactoryTest.MySelector.class;
@IsTest
static void itShouldReturnTheSelectorByBindingObject()
{
// Mock the App Bindings selector
fflib_AppBindingsSelector.SELECTOR_IMPL_TYPE = AppBindingsSelectorMock.class;
System.Test.startTest();
Object instance = Selector.newInstance(Schema.Account.SObjectType);
System.Test.stopTest();
System.assert(instance instanceof fflib_DynamicSelectorFactoryTest.MySelector);
}
@IsTest
static void itShouldReturnTheAlternativeSelector()
{
// Mock the App Bindings selector
fflib_AppBindingsSelector.SELECTOR_IMPL_TYPE = AppBindingsSelectorMock.class;
System.Test.startTest();
Object instanceA = Selector.newInstance(Schema.Account.SObjectType);
Selector.replaceWith(Schema.Account.SObjectType, MyMockSelector.class);
Object instanceB = Selector.newInstance(Schema.Account.SObjectType);
System.Test.stopTest();
System.assert(instanceA instanceof fflib_DynamicSelectorFactoryTest.MySelector);
System.assert(instanceB instanceof fflib_DynamicSelectorFactoryTest.MyMockSelector);
}
@IsTest
static void itShouldReturnTheRecordsById()
{
Id id = fflib_IDGenerator.generate(Schema.Account.SObjectType);
Set<Id> ids = new Set<Id>{ id };
final List<Account> records = new List<Account>{ new Account(Name='Test') };
fflib_ApexMocks mocks = new fflib_ApexMocks();
fflib_ISObjectSelector selectorMock = (fflib_ISObjectSelector) mocks.mock(fflib_ISObjectSelector.class);
mocks.startStubbing();
mocks.when(selectorMock.selectSObjectsById(ids)).thenReturn(records);
mocks.stopStubbing();
Selector.setMock(Schema.Account.SObjectType, selectorMock);
System.Test.startTest();
List<SObject> result = Selector.selectById(ids);
System.Test.stopTest();
System.assert(result == records);
((fflib_ISObjectSelector) mocks.verify(selectorMock)).selectSObjectsById(ids);
}
@IsTest
static void itShouldReturnTheRecordsByRelatedId()
{
Id id = fflib_IDGenerator.generate(Schema.Account.SObjectType);
Set<Id> ids = new Set<Id>{ id };
final List<Account> accounts = new List<Account>{ new Account(Id = id, Name='Test') };
final List<Contact> contacts = new List<Contact> { new Contact(AccountId = id)};
fflib_ApexMocks mocks = new fflib_ApexMocks();
fflib_ISObjectSelector selectorMock = (fflib_ISObjectSelector) mocks.mock(fflib_ISObjectSelector.class);
mocks.startStubbing();
mocks.when(selectorMock.sObjectType()).thenReturn(Schema.Account.SObjectType);
mocks.when(selectorMock.selectSObjectsById(ids)).thenReturn(accounts);
mocks.stopStubbing();
Selector.setMock(selectorMock);
System.Test.startTest();
List<SObject> result = Selector.selectByRelationship(contacts, Schema.Contact.AccountId);
System.Test.stopTest();
System.assert(result == accounts);
((fflib_ISObjectSelector) mocks.verify(selectorMock)).selectSObjectsById(ids);
}
public interface IMySelector extends fflib_ISObjectSelector {}
private abstract class MySelectorAbstract extends fflib_SObjectSelector implements IMySelector
{
public List<Schema.SObjectField> getSObjectFieldList()
{
return new List<Schema.SObjectField>{ Account.Id, Account.Name };
}
public SObjectType getSObjectType()
{
return Schema.Account.SObjectType;
}
}
public class MySelector extends MySelectorAbstract {}
public class MyMockSelector extends MySelectorAbstract {}
private class AppBindingsSelectorMock extends fflib_AppBindingsSelector
{
public override List<fflib_AppBinding__mdt> selectAll()
{
return new List<fflib_AppBinding__mdt>
{
new fflib_AppBinding__mdt(
Type__c = 'Selector',
BindingObject__c = '',
BindingObjectAlternate__c = Schema.Account.SObjectType.getDescribe().getName(),
ImplementationType__c = MY_SELECTOR_TYPE.getName(),
SharingMode__c = 'With Sharing'
)
};
}
}
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>51.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,188 @@
/**
* File Name: fflib_DynamicServiceFactoryTest
* Description:
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@IsTest(IsParallel=true)
public class fflib_DynamicServiceFactoryTest
{
private static final Type MY_SERVICE_INTERFACE_TYPE = fflib_DynamicServiceFactoryTest.IMyService.class;
private static final Type MY_SERVICE_TYPE = fflib_DynamicServiceFactoryTest.MyService.class;
private static final Type MY_ALT_SERVICE_TYPE = fflib_DynamicServiceFactoryTest.MyALtService.class;
@IsTest
static void itShouldReturnTheCorrectInstance()
{
fflib_AppBindingModule module = new fflib_AppBindingModule();
module.addBinding(createBindingForMyService());
bindingResolver.addModule(module);
System.Test.startTest();
Object instance = Service.newInstance(MY_SERVICE_TYPE);
System.Test.stopTest();
System.assert(instance instanceof fflib_DynamicServiceFactoryTest.MyService);
}
@IsTest
static void itShouldReturnTheAlternativeInstance()
{
fflib_AppBindingModule module = new fflib_AppBindingModule();
module.addBinding(createBindingForMyService());
bindingResolver.addModule(module);
Service.replaceWith(MyService.class, MyAltService.class);
System.Test.startTest();
Object instance = Service.newInstance(MY_SERVICE_TYPE);
System.Test.stopTest();
System.assert(instance instanceof fflib_DynamicServiceFactoryTest.MyAltService);
}
@IsTest
static void itShouldReturnTheMockInstance()
{
fflib_AppBindingModule module = new fflib_AppBindingModule();
module.addBinding(createBindingForMyService());
bindingResolver.addModule(module);
IMyService mock = new MyAltService();
Service.setMock(MyService.class, mock);
System.Test.startTest();
Object instance = Service.newInstance(MY_SERVICE_TYPE);
System.Test.stopTest();
System.assert(instance instanceof fflib_DynamicServiceFactoryTest.MyAltService);
}
@IsTest
static void itShouldReturnTheFirstBindingInstance()
{
fflib_AppBindingsSelector.SELECTOR_IMPL_TYPE = AppBindingsSelectorMock.class;
System.Test.startTest();
Object instance = Service.newInstance(MY_SERVICE_INTERFACE_TYPE);
System.Test.stopTest();
System.assert(instance instanceof fflib_DynamicServiceFactoryTest.MyService);
}
@IsTest
static void itShouldReturnTheSecondBindingInstance()
{
fflib_AppBindingsSelector.SELECTOR_IMPL_TYPE = reverseAppBindingsSelectorMock.class;
System.Test.startTest();
Object instance = Service.newInstance(MY_SERVICE_INTERFACE_TYPE);
System.Test.stopTest();
System.assert(instance instanceof fflib_DynamicServiceFactoryTest.MyAltService);
}
private static fflib_AppBinding createBindingForMyService()
{
fflib_AppBinding result = new fflib_AppBinding();
result.setBindingType(fflib_AppBindingType.Service);
result.setInterfaceType(MY_SERVICE_TYPE);
result.setImplementationType(MY_SERVICE_TYPE);
result.setSharingMode(fflib_SharingMode.WithSharing);
result.setSequence(2);
return result;
}
private static fflib_AppBinding createBindingForMyAltService()
{
fflib_AppBinding result = createBindingForMyService();
result.setImplementationType(MyAltService.class);
result.setSequence(1);
return result;
}
private static fflib_IAppBindingResolver bindingResolver =
new fflib_AppBindingResolver();
private static final fflib_IServiceFactory Service =
new fflib_DynamicServiceFactory(bindingResolver)
.setSharingMode(fflib_SharingMode.WithSharing);
public interface IMyService {}
public class MyService implements IMyService { }
public class MyAltService implements IMyService { }
private class AppBindingsSelectorMock extends fflib_AppBindingsSelector
{
public override List<fflib_AppBinding__mdt> selectAll()
{
return new List<fflib_AppBinding__mdt>
{
new fflib_AppBinding__mdt(
Type__c = 'Service',
InterfaceType__c = MY_SERVICE_INTERFACE_TYPE.getName(),
ImplementationType__c = MY_SERVICE_TYPE.getName(),
SharingMode__c = 'With Sharing',
BindingSequence__c = 1
),
new fflib_AppBinding__mdt(
Type__c = 'Service',
InterfaceType__c = MY_SERVICE_INTERFACE_TYPE.getName(),
ImplementationType__c = MY_ALT_SERVICE_TYPE.getName(),
SharingMode__c = 'With Sharing',
BindingSequence__c = 2
)
};
}
}
private class reverseAppBindingsSelectorMock extends fflib_AppBindingsSelector
{
public override List<fflib_AppBinding__mdt> selectAll()
{
return new List<fflib_AppBinding__mdt>
{
new fflib_AppBinding__mdt(
Type__c = 'Service',
InterfaceType__c = MY_SERVICE_INTERFACE_TYPE.getName(),
ImplementationType__c = MY_SERVICE_TYPE.getName(),
SharingMode__c = 'With Sharing',
BindingSequence__c = 2
),
new fflib_AppBinding__mdt(
Type__c = 'Service',
InterfaceType__c = MY_SERVICE_INTERFACE_TYPE.getName(),
ImplementationType__c = MY_ALT_SERVICE_TYPE.getName(),
SharingMode__c = 'With Sharing',
BindingSequence__c = 1
)
};
}
}
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>51.0</apiVersion>
<status>Active</status>
</ApexClass>