Using the same instance of ServiceClientFactory to remotely invoke the services exposed by the LiveCycle container can lead to exception related to assertion expiry
To handle the timeout use the ThrowHandler mechanism provided by the ServiceClientFactory framework
LiveCycle provides a client sdk for java based client to invoke its services remotely. An invocation involves
For more details refer to Invoking LiveCycle ES Using the Java API. A ServiceClientFactory instance once created is valid for a ceratin period of time which is by default 120 min. if the same instance is used to invoke beyond this period then it would lead to an exception stating that the session has expired
[com.adobe.idp.um.api.impl.AuthenticationManagerImpl] errorCode:16421 errorCodeHEX:0x4025 message:Could not validate SAML Token --- Assertion has expired and hence not valid for user [administrator@DefaultDom]. Its valid till time [Thu Oct 22 17:07:53 IST 2009] was found to be before the current time [Thu Oct 22 17:58:18 IST 2009]
This is not an issue if the ServiceClientFactory instance is used for short duration. However if you are going to perform a long running task like converting large number of documents to pdf , applying policies to them etc then it would be an issue.
Before fixing the issue some info on what is session expiry. When you use a ServiceClientFactory instance to invoke the service following flow happens
This whole flow is done to ensure that user's credentials are not sent for each remote call thus improving the security. For more information on Context refer to User Identity in LiveCycle.
To fix this issue you would have to re authenticate to LiveCycle
and get the
Context reissued. the best way to do that is to make
use of the
ThrowHandler
provided by the ServiceClientFactory framework
/**
* This ThrowHandler caches the user credentials and uses them
to refresh the Context in the
* ServiceClientFactory upon expiry.
*/
private static class SimpleTimeoutThrowHandler implements
ThrowHandler {
private String username;
private String password;
public SimpleTimeoutThrowHandler(String username, String
password) {
this.username = username;
this.password = password;
}
public boolean handleThrowable(Throwable t, ServiceClient
sc,
ServiceClientFactory scf, MessageDispatcher md,
InvocationRequest ir, int numTries) throws
DSCException {
if(timeoutError(t)){
//The call to AuthenticationManager do not require
authentication so the default properties
//are sufficient
AuthenticationManager am =
new
AuthenticationManagerServiceClient(ServiceClientFactory.createInstance(getDefaultProperties()));
AuthResult ar = null;
try {
ar =
am.authenticate(username,password.getBytes());
} catch (UMException e) {
throw new IllegalStateException(e);
}
Context ctx = new Context();
ctx.initPrincipal(ar);
//Refresh the ServiceClientFactory instance with
the new context
scf.setContext(ctx);
logger.info("Refreshed the context associated with
ServiceCLientFactory");
//Now tell SCF to try the invocation again
return true;
}
//Check so that we do not wrap the exception again
if(t instanceof DSCException)
throw (DSCException)t;
if(t instanceof RuntimeException)
throw (RuntimeException)t;
// how is it possible to get this far?
throw new IllegalStateException(t);
}
private boolean timeoutError(Throwable t) {
if(!(t.getCause() instanceof UMException)){
return false;
}
UMException ue = (UMException) t.getCause();
//Check that UMException is due to the
assertion/context expiry
if(UMConstants.ErrorCodes.E_TOKEN_INVALID ==
ue.getErrCode()){
return true;
}
return false;
}
}
This ThrowHandler would be invoked by the ServiceClientFactory upon receiving any exception. The handler would then determine if its a timeout related exception and then would refresh the Context associated with the factory instance and tells it to retry the invocation
ServiceClientFactory.installThrowHandler(new SimpleTimeoutThrowHandler(username, password));
Note: The handler should be registered only once in the application
Following sample would try to apply policies on all the files present in a directory
Properties p = getDefaultProperties();
p.setProperty(DSC_CREDENTIAL_USERNAME, username);
p.setProperty(DSC_CREDENTIAL_PASSWORD, password);
ServiceClientFactory scf =
ServiceClientFactory.createInstance(p);
//Now do some long running operation
String inputDirName ="path-to-input-dir";
String outDirName = "path-to-out-dir";
String policyName = "the-policy-name";
File inDir = new File(inputDirName);
File outDir = new File(outDirName);
RightsManagementClient rmClient = new
RightsManagementClient(scf);
DocumentManager docManager = rmClient.getDocumentManager();
//Iterate over all the pdf in the inDir and apply the
policies. If this takes a
for(File pdfFile : inDir.listFiles()){
Document inDoc = new Document(pdfFile, false);
Document securedDoc = docManager.applyPolicy(inDoc,
pdfFile.getName(), null, policyName, null, null);
securedDoc.copyToFile(new
File(outDir,pdfFile.getName()));
}
Now the invocation would complete even if it takes a long time. if any session expiry occurs then our ThrowHandler would take care of that
+