Oracle® Fusion Middleware Content Management SPI Development Guide for Oracle WebLogic Portal 10g Release 3 (10.3.4) Part Number E14231-02 |
|
|
View PDF |
This chapter provides information about creating an SPI implementation. It contains the following sections:
Section 4.2, "Primary Classes for a Basic SPI Implementation"
Section 4.3, "Repository Guidelines when Creating an SPI Implementation"
Section 4.6, "SPI Interface Result Collections, Sorting, and Filtering"
Section 4.8, "Connecting and Logging Into a Third-Party Repository"
When the VCR needs to access a specific repository from the set of application repository configurations, the VCR loads and creates an instance of the configured SPI implementation class, which implements the VCR SPI Repository interface. The VCR invokes methods on the repository implementation to obtain objects, such as a Ticket
, which implement other VCR SPI interfaces.
The VCR invokes methods on the Repository and Ticket implementations to query the SPI implementation for its capabilities. (Capabilities are what operations the implementation supports.) The VCR then invokes methods to retrieve the operation interfaces, such as NodeOpsV1, that the SPI exposes. Finally, the VCR invokes methods on the operation interfaces.
The two primary classes for an SPI implementation are:
Repository
Ticket
The Repository
class is instantiated directly by the VCR. This class provides anonymous repository access. For example, an SPI implementation can report its version and other basic information. Most importantly, this is the entry point for authenticating to an SPI implementation to obtain a Ticket. Only authenticated users can obtain a Ticket; the Ticket provides access to the important repository operations.
The Ticket
class provides authorized repository access, and provides access to the authorized operations interfaces such as NodeOpsV1
. Only authenticated users can obtain a Ticket
; the Ticket
provides access to the important repository operations. This class is instantiated by Repository.connect(...)
.
The Repository
can optionally expose additional authorized ticket operations interfaces, such as NodeOpsV1
, SearchOpsV1
, via its implementation of getAllInterfaces()
and getInterface()
.
The general flow at runtime is:
Connection process:
VCR instantiates Repository
class.
VCR configures Repository
object.
VCR queries Repository
object.
VCR invokes Repository.getAllInterfaces()
to retrieve all repository interfaces.
VCR invokes Repository.connect()
to obtain a Ticket
.
VCR invokes Ticket.getAllInterfaces()
to retrieve all ticket interfaces.
Call process:
VCR accesses the desired interface, such as NodeOps
.
VCR invokes method on the desired interface, such as NodeOpsV1.getNodeWithId( ID )
.
Use the following design guidelines when creating an SPI implementation:
Standalone – The SPI implementation should be standalone. The VCR calls into the SPI implementation. The SPI implementation should not call into the VCR federated interfaces, although it can use the VCR data objects.
Stateless – Generally, the SPI implementation should be stateless. All changes should be propagated to the external system immediately.
There are several reasons for this. Primarily, because in a cluster scenario or multiple enterprise applications on the same server, changes to external system data should be persisted immediately. This allows the data to appear "live" regardless from which server and enterprise application the data is accessed.
Object caching – The SPI implementation should not cache the data objects instances it returns (Nodes
, Properties
, Values
, ObjectClasses
, PropertyDefinitions
, and PropertyChoices
). The VCR and client code own these objects, which they can modify. For example, the VCR may change the node path before returning the node to the client.
A safe approach is to cache the objects, then return a clone of these objects, which the SPI implementation will not have references to.
Because the data object types are shared between the SPI implementation, VCR, and client code, not all methods on these data objects are appropriate for each type of caller. (See the Oracle Fusion Middleware Java API Reference for Oracle WebLogic Portal for clarification.) For example, new data objects, such as Properties
passed when creating a Node
from the VCR to the SPI implementation do not have UUID on the PropertyID
. This happens because the UUID is assigned by the SPI implementation and the new object has not yet been persisted by the SPI implementation. The UUID is present only for data objects retrieved or returned by the SPI.
VCR Repository interface – SPI implementations must implement the VCR Repository interface. Repositories are loaded dynamically by the VCR and require a public default constructor. When the VCR loads the SPI implementation, it calls the Repository.setName()
and Repository.setProperties()
methods before it calls the connect()
method.
Each Repository instance corresponds to a single repository configuration for a single enterprise application and for use by a single user. At runtime, the VCR can create many instances of Repositories for use by numerous current WebLogic Portal users. For this reason they should be relatively lightweight objects, as hundreds of these objects may exist.
In an enterprise application for a given SPI implementation, there may be multiple active repository configurations. For example, three repository configurations may exist for an application that the VCR is managing, and each repository will have its own configuration data and its own Repository instance that is created at runtime.
Exceptions – Anytime the SPI implementation is unable to perform an operation, it should throw a RepositoryException
. Several subclasses of RepositoryException
are defined, and these should be used when a good match exists. For example, if the SPI implementation does not support an operation, it should throw a UnsupportedRepositoryOperationException
.
Ticket re-use – The Ticket
object is cached and re-used by the VCR. Generally, it should be stateless for concurrency reasons. The VCR associates the Ticket
with a user on a HTTPSession
. If multiple requests on the same HTTPSession
arrive for the same repository, multiple operations on the same Ticket
object can be performed simultaneously. A stateless design will avoid issues in this situation.
Support for multiple repository instances of the SPI implementation – To work properly when multiple repositories of your SPI implementation are used simultaneously, be careful with static caches by ensuring that the data is tied to a specific repository name or instance. One option is to incorporate the repository name in the data key when caching data. Another option is to use named singletons to access cached data. By keeping the data segregated by repository name, the SPI implementation should work properly in this situation.
Performance – SPI caching is important; the SPI should generally cache data so it does not need to consult the external system frequently. The SPI can lazy-load several settings to boost performance, such as:
Node properties – If the Node is created with a null Property[]
, the properties are lazy-loaded.
Node objectClass –
If the Node is created with a null ObjectClass
, but the ObjectClassId
assigned via setObjectClassId
, the ObjectClass
is lazily-loaded.
Binary property values –
When the node's properties (and values) are loaded, the binary property inputstream
can be returned as null to boost performance.
To create a basic SPI implementation:
Create a Java class that implements the interface com.bea.content.spi.flexspi.Repository
.
This class is a required interface that must be implemented. It is included with WebLogic Portal.
Create a public default constructor.
Implement setProperties()
to store the repository configuration properties passed by the VCR. Store in a local variable.
Implement setName()
to store the repository configuration name passed by the VCR. Store in a local variable.
Implement getProperties()
and getName()
to read the local variables.
Implement getDescription()
to report the repository description data.
This is essentially a Properties
bucket, with some well-defined keys in SPIDescriptionKeys
. It includes the vendor, version, and so on.
Implement getRepositoryDefinedCapabilities()
to report which custom capabilities the SPI implementation supports.
For a basic SPI implementation, just return Collections.emptySet()
.
Implement getAllInterfaces()
to return all repository (not ticket
) operations interfaces.
These are optional interfaces, such as RepositoryConfigOpsV1
, that a Repository can implement.
For a bare-bones SPI implementation, just return an empty HashMap
.
Implement getInterface( String interfaceName )
to be consistent with getAllInterfaces()
.
For a bare-bones SPI implementation, just return null.
Implement getCapabilitySupport( Set<ICapabilityDefinition> )
to report which feature capabilities this SPI implementation supports.
It also report which method capabilities the repository supports across the optional repository operation interfaces.
Implement connect( Credentials )
and Connect( String username, String password )
to allow a caller to obtain a ticket.
connect( username, password )
is called if a username and password are available (generally from the repository configuration data.)
connect( credentials )
is called if no username/password are available. The credentials includes the caller's implicit identity.
For a basic SPI implementation, create and return a new Ticket
instance. More advanced implementations may authenticate the credentials, and only return a Ticket
instance if successful.
Implement any optional Repository
operation interfaces, such as RepositoryConfigOpsV1
.
For any repository operation interfaces returned by Repository.getAllInterfaces()
:
Implement the interface.
Any methods that are not implemented should throw an UnsupportedRepositoryOperationException
and the getCapabilitySupport()
method should not report this method as supported.
Modify Repository.getAllInterfaces()
and getInterface()
to return the interface implementation.
Modify Repository.getCapabilitySupport()
to report the status (supported or unsupported) of each method on the repository operation interface.
Create a Java class that implements the interface com.bea.content.spi.flexspi.Ticket
(supplied with WebLogic Portal)
Implement getAllInterfaces()
to return all ticket operations interfaces. These are optional interfaces, such as NodeOpsV1
, which a Ticket
can implement. For a basic SPI implementation, return an empty HashMap
.
Implement getInterface( String interfaceName )
to be consistent with getAllInterfaces()
. For a basic SPI implementation, just return null.
Implement getCapabilitySupport( Set<ICapabilityDefinition> )
to report which method capabilities this ticket supports across the optional ticket operation interfaces.
Implement any optional Ticket
operation interfaces, such as NodeOpsV1
.
For any ticket optional interfaces returned by Ticket.getAllInterfaces()
:
Implement the interface.
Any methods that are not implemented should throw an UnsupportedRepositoryOperationException
and the getCapabilitySupport()
method should not report this method as supported.
Modify Ticket.getAllInterfaces()
and getInterface()
to return the interface implementation.
Modify Ticket.getCapabilitySupport()
to report the status (supported or unsupported) of each method on the ticket operation interface.
Example 4-1shows a simple SPI Repository code example of a Repository with the following limitations:
It does not authenticate.
It does not support any feature capabilities.
It does not support any optional repository operation interfaces, such as RepositoryConfigOpsV1
, and therefore does not support any method capabilities.
It does not provide any repository defined capabilities.
Example 4-1 Basic SPI Implementation
import com.bea.content.spi.flexspi.Repository; import com.bea.content.spi.flexspi.Ticket; import com.bea.content.spi.flexspi.common.capability.ICapabilityDefinition; import com.bea.content.spi.flexspi.common.capability.CapabilityLevel; import com.bea.content.spi.flexspi.common.capability.FeatureCapabilityDefinition; import com.bea.content.spi.flexspi.common.ISPIMarker; import com.bea.content.spi.flexspi.common.SPIRepositoryInterfaces; import com.bea.content.spi.flexspi.common.SPIDescriptionKeys; import com.bea.content.capability.NodeFeatureCapability; import com.bea.content.*; import java.util.*; public class FlexRepositoryImpl implements Repository { // VCR configures these before connect() is called private String repositoryName; private Properties props; // the description key/values private Map<String, String> descMap = new HashMap<String, String>(); public FlexRepositoryImpl() { // SPI implementation MUST have a public default ctor //standard keys descMap.put(SPIDescriptionKeys.VENDOR_KEY, "Some third party vendor"); descMap.put(SPIDescriptionKeys. VERSION_KEY, "0.1.1"); descMap.put(SPIDescriptionKeys. DESCRIPTION_KEY, "Simple SPI"); //custom keys can also be added descMap.put("InternalVersion", "Build 31141"); } public Ticket connect(Credentials credentials) throws AuthenticationException, RepositoryException { // this SPI does not perform authentication return new FlexTicketImpl(this); } public Ticket connect(String username, String password) throws AuthenticationException, RepositoryException { // this SPI does not perform authentication return new FlexTicketImpl(this); } public String getName() { return repositoryName; } public void setName(String name) { repositoryName = name; } public Properties getProperties() { return props; } public void setProperties(Properties properties) { props = properties; } public Set<ICapabilityDefinition> getRepositoryDefinedCapabilities() { return Collections.emptySet(); } public Map<String, String> getDescription() { return descMap; } public Map<String, ISPIMarker> getAllInterfaces() { // no repository operation interfaces return new HashMap<String,ISPIMarker>(); } public ISPIMarker getInterface(String interfaceName) { // no repository operation interfaces return null; } public Map<ICapabilityDefinition, CapabilityLevel> getCapabilitySupport(Set<ICapabilityDefinition> capabilities) { HashMap<ICapabilityDefinition, CapabilityLevel> capMap =new HashMap<ICapabilityDefinition, CapabilityLevel>(); // start out with everything not supported; we will mark // individual feature capabilities as supported. for (ICapabilityDefinition capDef : capabilities) { capMap.put(capDef, CapabilityLevel.NotSupported); } // here we would override the unsupported value if we supported anything // but we don't… // everything unsupported return capMap; } }
Example 4-2 shows a simple SPI Ticket code example of a Ticket that does not support any optional ticket operation interfaces, such as NodeOpsV1
and SearchOpsV1
, and therefore does not support any method capabilities.
Example 4-2 Ticket Implementation Code Example
import com.bea.content.spi.flexspi.Ticket; import com.bea.content.spi.flexspi.Repository; import com.bea.content.spi.flexspi.common.ISPIMarker; import com.bea.content.spi.flexspi.common.SPITicketInterfaces; import com.bea.content.spi.flexspi.common.capability.ICapabilityDefinition; import com.bea.content.spi.flexspi.common.capability.CapabilityLevel; import com.bea.content.spi.flexspi.common.capability.MethodCapabilityDefinition; import java.util.*; public class FlexTicketImpl implements Ticket { Repository repository; // the repository this ticket was created from //1=flex interface name, 2=flex interface object private Map<String, ISPIMarker> advertisedInterfaces; public FlexTicketImpl(Repository repository) { this.repository = repository; advertisedInterfaces= new HashMap<String,ISPIMarker>(); // no interfaces yet } public Map<String, ISPIMarker> getAllInterfaces() { return advertisedInterfaces; } public ISPIMarker getInterface(String interfaceName) { return advertisedInterfaces.get(interfaceName); } public Map<ICapabilityDefinition, CapabilityLevel> getCapabilitySupport(Set<ICapabilityDefinition> capabilities) { // no interfaces, no methods, no capabilities; everything is unsupported HashMap<ICapabilityDefinition, CapabilityLevel> capMap =new HashMap<ICapabilityDefinition, CapabilityLevel>(); // start out with everything not supported; we will mark // individual feature capabilities as supported. for (ICapabilityDefinition capDef : capabilities) { capMap.put(capDef, CapabilityLevel.NotSupported); } // here we would override the unsupported value if we supported anything // but we don't… // everything unsupported return capMap; } }
You use optional SPI interfaces to expose nodes and types to the VCR. Generally, client code has certain assumptions about the capabilities of the repositories the code runs against, such as read-only access to nodes. As the VCR delegates to the repository, the client code presumes that certain VCR methods work properly.
The optional PSPI interfaces are:
Repository operation interfaces – The RepositoryConfigOpsV1
provides repository callbacks as repository configurations that are modified by VCR clients (generally, administrators). For example, createRepository(…)
, updateRepository(…)
, and removeRepository(…)
.
Ticket operation interfaces – The following interfaces provide CRUD operations:
Nodes – NodeOpsV1
.
Types – ObjectClassOpsV1
.
Operations for searching for nodes – SearchOpsV1
.
Workflows – WorkflowOpsV1
.
To expose an optional SPI interface such as NodeOpsV1
.
Create a class to implement the SPI interface.
For example MyNodeOps
implements NodeOpsV1
. Generally, you should make this a light-weight class, as many objects may be created.
Write implementations of the SPI interface methods.
Note:
Any methods that are not implemented should throw an UnsupportedRepositoryOperationException. Additionally, the Ticket.getCapabilitySupport() method should report this method as not supported.Modify Ticket.getAllInterfaces()
and getInterface()
to return the interface implementation.
To reduce object creation, create the interfaces when the ticket is created, hold onto them, and then return them in getAllInterfaces()
and getInterface()
. For example:
private Map<String,ISPIMarker> ifaces; public FlexTicketImpl( Repository repository ) { this.repository= repository; //init interfaces ifaces= new HashMap<String,ISPIMarker>(); ifaces.put(SPITicketInterfaces.NODE_OPS_V1, new MyNodeOps(…); . . . } public Map<String, ISPIMarker> getAllInterfaces() { return ifaces; } public ISPIMarker getInterface( String ifaceName ) { return ifaces.get( ifaceName ); }
Modify Ticket.getCapabilitySupport()
to report the status (supported or unsupported) of each method on all the ticket operation interfaces. For example:
public Map<ICapabilityDefinition, CapabilityLevel> getCapabilitySupport(Set<ICapabilityDefinition> capabilities) { Map<ICapabilityDefinition, CapabilityLevel> capMap =new HashMap<ICapabilityDefinition, CapabilityLevel>(); // start out with everything not supported; we will mark // individual feature capabilities as supported. for (ICapabilityDefinition capDef : capabilities) { capMap.put(capDef, CapabilityLevel.NotSupported); } // now override the unsupported values where it makes sense final String[] supportedNodeOpsMethodNames = new String[] { NodeOpsV1.MethodName.getNodeChildren.toString(), NodeOpsV1.MethodName.getNodeChildrenAsNodeIds.toString(), NodeOpsV1.MethodName.getNodesWithIds.toString(), NodeOpsV1.MethodName.getNodeWithId.toString(), NodeOpsV1.MethodName.getNodeWithPath.toString(), }; for (String methodName : supportedNodeOpsMethodNames) { ICapabilityDefinition capDef = new MethodCapabilityDefinition( SPITicketInterfaces.NODE_OPS, methodName ); if (capabilities.contains(capDef)) { capMap.put(capDef, CapabilityLevel.FullySupported); } } return capMap; }
Optionally, the SPI implementation can include the ability to sort and/or filter results. The collections of items returned by the SPI are returned in a QueryResult
object (including an ordered list of results) and a QueryCriteria
object that describes how the returned collection is sorted and filtered (if at all). For instance, a QueryResult<Node>
may contains a collection of nodes that are both sorted and filtered.
Many of the methods that return results collections take a QueryCriteria
parameter. This parameter allows the caller to indicate how results should be sorted or filtered or both (if possible). For example, the caller may request that the results be sorted by name. At present, the caller can specify only one sort criteria and one filter criteria.
The SortCriteria
contains a property (criteria) and an ascending or descending flag, such as name ascending
.
The FilterCriteria
contains a property (criteria), a FilterMethod
operand, such as unfiltered, equals, not equals, contains, not contains, begins with, ends with, greater than, and less than, and a value. For example, name contains 'foo'
.
The sort and filter criteria set of properties are related to the JavaBean properties on the data objects being used. For example, Node
contains a JavaBean property for name
because it has a getName()
method; for createdDate
because it has a getCreatedDate()
method; and so on.
Native sorting and filtering performs best. The VCR also supports mechanisms for sorting and filtering in-memory if the SPI implementation is unable to service a sort or filter request. Client code (and the VCR) can ask the SPI which properties it can natively sort and filter.
The SPI implementation reports its sorting and filtering capabilities (the properties it can sort and filter on) to the VCR for objects on an interface by implementing methods such as NodeOpsV1.getNativeSortableProperties()
and NodeOpsV1.getNativeFilterableProperties()
. For example, the SPI may report that it can sort nodes by name
and createDate
properties.
The sorting and filtering capability reporting is currently done at the interface granularity. In other words, a given interface such as NodeOpsV1
has a primary data object. The primary data object, a Node
for example, reports the capabilities for sorting and filtering across the results collection methods in the interface.
Tip:
If the SPI does not support native sorting or filtering, it should return an empty set, such as Collections.emptySet() rather than null.The SPI implementation may receive a QueryCriteria
parameter that requests sorting or filtering capabilities beyond what it can support. If this happens, the SPI implementation should not throw an exception. Instead the SPI implementation should do its best to report how the results are currently sorted and filtered. For example, the SPI implementation should create an unsorted and/or unfiltered QueryResult
to express what it was unable to sort and/or filter. If the SPI implementation can perform one of the requests, it should do so and report the results appropriately. For instance, if it can sort, the SPI implementation should report the results as sorted, but unfiltered.
If necessary the VCR may sort/filter the query results in memory to ensure the query results are sorted/filtered as the client requests.
Use the following objects for sorting and filtering:
QueryCriteria
– Some methods pass a QueryCriteria
object as a means for a caller to request sorting and filtering of results. These methods include SortCriteria
and FilterCriteria
objects. Currently, only a single SortCriteria
or FilterCriteria
can be specified; multi-criteria sorting or filtering is not supported.
SortCriteria
– Provides the ability for ascending or descending sorting on a specific property (criteria). A sortResults
flag indicates whether the results are sorted or unsorted. SortCriteria
also includes a property
that is one of the JavaBean properties on the data object.
FilterCriteria
– Provides the ability to filter on a specific property (criteria). A filterResults
flag indicates whether the results are filtered or unfiltered. FilterCriteria
includes a property
that is one of the JavaBean properties on the data object, and a filterMethod
that indicates the filter operation, such as begins with, contains, equals, greater than, unfiltered, and so on.
QueryResult
– Represents a set of results returned by the SPI implementation. QueryResult
also includes a QueryCriteria
object that describes how the results are sorted and filtered (or neither), plus an ordered list of the data objects.
This section describes the available options for configuring security with a third-party repository through the SPI.
Section 4.7.1, "Authorization and Identity Management Overview"
Section 4.7.5, "Identity Propagation with Native Security"
Note:
Techniques that use native security tend to offer the best performance (useNativeSecurity = true).The SPI security model lets you configure both authorization and identity management options. You can configure authorization to be managed by either WLP or the native (third-party) repository. With WLP-managed authorization, data is secured by WLP, and WLP content entitlements apply. With native authorization, data is secured through the third-party repository. WLP content entitlements do not apply.
When user identity is configured globally, all WLP application users who log in to the repository share the same user credentials and privileges. If the third-party repository supports the RepositoryMultipleUsers capability, it is possible on a per-WLP-user basis to log in to the third-party repository with "individual" credentials (typically called "mapped credentials").
Developers can use the SPI API to develop a login feature that allows portal users to log in with mapped credentials. For example, if a user logs in using his or her global identity, they might have read-only access to the repository. However, if they log in using their mapped identity, they could have read-write access. In addition, administrators using the Portal Administration Console can log in to a third-party repository with a mapped credential. For details, see "Logging Into a Third-Party Repository" in the Oracle Fusion Middleware Content Management SPI Development Guide for Oracle WebLogic Portal. Again, mapped credential identity management is only possible if the third-party repository supports it. To support this capability in a repository, the repository must indicate it supports the RepositoryMultipleUsers capability. When this is done, the VCR allows users to define personal mapped credentials for this repository, and supplies the credentials to the repository as appropriate with the Ticket.connect(...) methods.
Note:
Currently, Oracle WebCenter Content is the only repository that supports the RepositoryMultipleUsers capability.Some SPI implementations may not have a concept of authentication. If this is the case, the repository configuration contains no user or password credentials, and all VCR users in the same enterprise application have access to the repository. WebLogic Portal CM entitlements define the data each user is permitted to access. From an SPI implementation perspective, the Repository.connect()
methods should always create and return a Ticket
implementation object.
If WLP manages resource authorization, the data is secured through WebLogic Portal and WLP Content Entitlements will apply. Two options for identity management exist for WLP-secured resource management.
In the case of global user identity, all users in the application use the same credentials to connect to the third-party repository instance.
Configure this type of security with these settings in the META-INF/content-config.xml
file in the EAR Project, as described in the following table.
Field | Value |
---|---|
Username | The user name of a valid user of the repository. |
useNativeSecurity | false |
Mapped credential identity management is only available if the third-party repository supports it. Currently, only the Oracle WebCenter Content repository supports identity mapping. For information on the mapped identity option, see Section 4.7.1, "Authorization and Identity Management Overview."
If the third-party (native) respository manages resource authorization, the data is secured through the third-party repository and WLP Content Entitlements do not apply. Two options for identity management exist for natively-secured resource management.
All users in the application use the same credentials to connect to the third-party repository instance. Configure this type of security with these settings in the META-INF/content-config.xml
file in the EAR Project:
Field | Value |
---|---|
Username | The user name of a valid user of the repository. |
useNativeSecurity | true |
Mapped identity management is only available if the third-party repository supports it. Currently, on the Oracle WebCenter Content repository supports identity mapping. For information on the mapped identity option, see Section 4.7.1, "Authorization and Identity Management Overview."
With this option, WebLogic Portal and the third-party repository use the same security store, such as a shared LDAP store. Each WLP user sees in the application what they are permitted to see on the third-party repository side. Entitlements (WLP content security) are disabled.
Field | Value |
---|---|
Username | Do not set a value for this field. |
useNativeSecurity | true |
For detailed information on connecting to third-party repositories, see "Connecting to a Third-Party Repository" in the Oracle Fusion Middleware Content Management Guide for Oracle WebLogic Portal. For information on logging in to a third-party repository (including the procedure for logging in using either global or mapped user credentials), see "Logging Into a Third-Party Repository" in the Oracle Fusion Middleware Content Management Guide for Oracle WebLogic Portal.
The VCR manages repository-specific search caches of the form: searchCache.repository_name. These caches can be configured on a per-repository basis. For details, see the Oracle Fusion Middleware Cache Management Guide for Oracle WebLogic Portal.
SPI developers can exclude a repository from the VCR search cache. For example, you might do this if the repository can efficiently serve search results or live search results are required.. This feature is only available if the respository supports the feature capability named SearchFeatureCapability.RepositoryManagedSearchCache.