SailPoint connectors are continuously being upgraded with new features and security fixes. Changes to libraries and code are inevitable. The connector-classloader and library isolation projects are a step towards fixing the problems of customization that can happen during upgrades.
The following connector-classloader features help reduce the customization failures during upgrades:
Class loading is driven by the sequence of paths/locations or jars available in the classpath. On the request to load the class, the classloader traverses the classpath items one by one to search the class. It returns the class from the first occurrence and stops searching.
The following is the typical classpath for the connector-classloader. This gives you an idea of how, and from where, the classes for connectors are loaded. It also provides insight into the priority for classpath.
<!-- IdentityIQ filePathPrefix = Directory Path including /WEB-INF -->
<entry key="connector-classpath">
<value>
<List>
<String>\lib-connectors\JDBCCustom\commons-codec-1.9.jar</String> <!-- path of single jar -->
<String>\lib-connectors\ JDBCCustom \</String> <!-- path of folder, all jars under the folder will be added to classpath -->
</List>
</value>
</entry>
ConnectorFactory.getConnector(application, instance)
Before starting, ensure that all third-party libraries used:
Never add the following libraries explicitly to the classpath of any application, as they can cause class loading or conflict errors (these libraries are infrastructure libraries provided OOTB and are shared across IdentityIQ):
To enable third-party libraries, complete the following:
<!-- IIQ filePathPrefix = Directory Path including /WEB-INF -->
<entry key="connector-classpath">
<value>
<List>
<String>\lib-connectors\JDBCCustom\commons-codec-1.9.jar</String> <!-- path of single jar -->
<String>\lib-connectors\ JDBCCustom\</String> <!-- path of folder, all jars under the folder will be added to classpath -->
</List>
</value>
</entry>
Sometimes libraries have a conflict with the system-classloader, as the same library gets loaded by both the customization and the system-classloader. This can cause some problems. For example you could see the following: java.lang.LinkageError: loader constraint violation:, ClassCastException, or cannot be cast to: For reference, see https://sailpoint.atlassian.net/browse/CONJUBILEE-1467.
To solve these issues, you can delegate the classloading for the specific libraries, jar, or classes to the system-classloader by using the following configuration:
<entry key="load-by-sysclassloader">
<value>
<List>
<String>velocity.jar</String>
<String>org.apache.velocity</String> <!-- package to delegate, Connector Classloader will delegate all the classes under this package to sysclassloader to load –->
<String>org.apache.bsf.engines.jacl.BSFCommand.class</String> <!-- Class to delegate, Connector Classloader will delegate the specified classes to sysclassloader to load -->
</List>
</value>
</entry>
The correct way to instantiate a connector in your implementation-specific code is:
Connector connector = ConnectorFactory.getConnector(application, null);
As mentioned in the seconf bullet of the high-level understanding of the design, the connector-classloader is associated with the connector only when you instantiate with ConnectorFactory. Otherwise, it leads to exceptions of ClassNotFoundException or NoClassDefFoundError.
If you are using any of the concrete methods from the connector as a utility or for some other purpose, SailPoint recommends using the concrete methods as connectors are continuously being upgraded. It is inevitable that a few methods or classes will be moved, updated, or dropped during this process. So, you should not use any connector methods other than the connector interface contract. As seen in the following example:
Connector connector = ConnectorFactory.getConnector(application, null);
connector.provision(provisioningPlan);
connector.getObject("group", identity, options);
For more information on custom connector development, see the following guides: