Implementing a custom Documentum job method requires writing some non trivial DFC code. Below you'll find a sample using an abstract class which can be extended and re-used for any implementation of a job method.
Connection/helping methods are encapsulated into the AbstractJobMethod abstract class, so you can write custom classes that extend it. The only method to be implemented is execute(), where you have an active session (handled by the abstract class) and can perform the required actions against the repository.
The abstract class uses the CustomJobArguments, which is an extension of standard DfStandardJobArguments, providing some additional methods to access the passed job arguments.
Check How to create a custom job in Documentum for details on creation of custom job and method.
public class SomeCustomMethod extends AbstractJobMethod {
public int execute() throws Exception {
DfLogger.debug(this, "Started custom method implementation with user: " + session.getLoginUserName(), null, null);
// custom method logic goes here
return 0;
}
}
////
public abstract class AbstractJobMethod implements IDfMethod, IDfModule {
// for BOF 1.0 the class must implement only the IDfMethod interface, the jar is deployed on JMS
// for BOF 2.0 it implements also IDfModule because it will be deployed into the repository and will run as a BOF module
protected CustomJobArguments jobArguments;
protected IDfTime startDate;
protected IReportWriter reportWriter;
protected IDfSession session;
protected IDfSessionManager sessionManager;
protected IDfClientX clientx;
protected IDfClient client;
public int execute(Map args, PrintWriter writer) throws Exception {
setup(args, writer);
try {
int retCode = execute();
printJobStatusReport(retCode);
return retCode;
} catch (Exception e) {
DfLogger.error(this, "", null, e);
reportWriter.emitLine("Error encountered: " + e.getMessage());
reportWriter.closeOut(false);
throw e;
} finally {
if (reportWriter != null)
reportWriter.close();
if (session != null)
sessionManager.release(session);
}
}
// the only method to be implemented in concrete subclasses
public abstract int execute() throws Exception;
public void setup(Map args, PrintWriter writer) throws DfMethodArgumentException, DfException, Exception {
startDate = new DfTime();
jobArguments = new CustomJobArguments(new DfMethodArgumentManager(args));
setupMethodFactory(writer);
String username = jobArguments.getUserName();
String password = jobArguments.getString("password");
String domain = jobArguments.getString("domain");
String docbase = jobArguments.getDocbaseName();
setupSessionManager(username, password, domain, docbase);
}
private void setupSessionManager(String username, String password, String domain, String docbase) throws DfServiceException, DfException {
DfLogger.debug(this, String.format("setupSessionManager-> username[%s] password[%s] domain[%s] docbase[%s]", username, password, domain, docbase), null, null);
clientx = new DfClientX();
client = clientx.getLocalClient();
sessionManager = client.newSessionManager();
IDfLoginInfo loginInfoObj = clientx.getLoginInfo();
loginInfoObj.setUser(username);
if (password != null && !password.equals(""))
loginInfoObj.setPassword(password);
loginInfoObj.setPassword(password);
loginInfoObj.setDomain(domain);
sessionManager.setIdentity(docbase, loginInfoObj);
session = sessionManager.getSession(docbase);
}
private void setupMethodFactory(PrintWriter writer) throws Exception {
try {
IDfId jobId = jobArguments.getJobId();
ReportFactory reportfactory = new ReportFactory();
if (writer != null) {
DfLogger.debug(this, "uso reportFactory", null, null);
reportWriter = reportfactory.getReport(jobArguments.getDocbaseName(), jobArguments.getUserName(), "", jobArguments.getMethodTraceLevel(), jobId, writer);
} else {
DfLogger.warn(this, "writer == null, uso SimpleReportWriter", null, null);
reportWriter = new SimpleReportWriter();
}
} catch (Exception e) {
DfLogger.error(this, "Failed to create report writer. Error: " + e.getMessage(), null, e);
throw e;
}
}
private void printJobStatusReport(int retCode) throws Exception {
reportWriter.emitLineToReport("Return Code-> " + retCode);
String jobStatus = null;
IDfTime end_date = new DfTime();
long min_duration = Utility.timeDiff(startDate, end_date) / 60L;
if (retCode == 0)
jobStatus = "Custom Job completed at " + end_date.asString("yyyy/mm/dd hh:mi:ss") + ". Total duration: " + min_duration + " minutes.";
else if (retCode > 0)
jobStatus = "Custom job completed with Warnings at " + end_date.asString("yyyy/mm/dd hh:mi:ss") + ". Total duration: " + min_duration + " minutes.";
else
jobStatus = "Custom job completed with Errors at " + end_date.asString("yyyy/mm/dd hh:mi:ss") + ". Total duration: " + min_duration + " minutes. Check job report for details.";
updateJobStatus(jobStatus, jobArguments.getJobId());
reportWriter.closeOut(retCode >= 0);
}
public void updateJobStatus(String sJobStatus, IDfId jobId) throws Exception {
if (session == null) {
DfLogger.error(this, "setJobStatus: (session==null)", null, null);
throw new NullPointerException("setJobStatus: (session==null)");
}
try {
IDfPersistentObject job = session.getObject(jobId);
if (job == null)
throw new DfException("Failed to retrieve dm_job object from id '" + jobId.getId() + "'.");
job.setString("a_current_status", sJobStatus);
job.save();
} catch (Exception e) {
throw e;
}
}
}
////
public class CustomJobArguments extends DfStandardJobArguments {
protected IDfMethodArgumentManager methodArgumentManager;
public CustomJobArguments(IDfMethodArgumentManager manager) throws DfMethodArgumentException {
super(manager);
methodArgumentManager=manager;
}
public String getString(String paramName) throws DfMethodArgumentException {
return methodArgumentManager.getString(paramName);
}
public int getInt(String paramName) throws DfMethodArgumentException {
return methodArgumentManager.getInt(paramName).intValue();
}
}
Connection/helping methods are encapsulated into the AbstractJobMethod abstract class, so you can write custom classes that extend it. The only method to be implemented is execute(), where you have an active session (handled by the abstract class) and can perform the required actions against the repository.
The abstract class uses the CustomJobArguments, which is an extension of standard DfStandardJobArguments, providing some additional methods to access the passed job arguments.
Check How to create a custom job in Documentum for details on creation of custom job and method.
public class SomeCustomMethod extends AbstractJobMethod {
public int execute() throws Exception {
DfLogger.debug(this, "Started custom method implementation with user: " + session.getLoginUserName(), null, null);
// custom method logic goes here
return 0;
}
}
////
public abstract class AbstractJobMethod implements IDfMethod, IDfModule {
// for BOF 1.0 the class must implement only the IDfMethod interface, the jar is deployed on JMS
// for BOF 2.0 it implements also IDfModule because it will be deployed into the repository and will run as a BOF module
protected CustomJobArguments jobArguments;
protected IDfTime startDate;
protected IReportWriter reportWriter;
protected IDfSession session;
protected IDfSessionManager sessionManager;
protected IDfClientX clientx;
protected IDfClient client;
public int execute(Map args, PrintWriter writer) throws Exception {
setup(args, writer);
try {
int retCode = execute();
printJobStatusReport(retCode);
return retCode;
} catch (Exception e) {
DfLogger.error(this, "", null, e);
reportWriter.emitLine("Error encountered: " + e.getMessage());
reportWriter.closeOut(false);
throw e;
} finally {
if (reportWriter != null)
reportWriter.close();
if (session != null)
sessionManager.release(session);
}
}
// the only method to be implemented in concrete subclasses
public abstract int execute() throws Exception;
public void setup(Map args, PrintWriter writer) throws DfMethodArgumentException, DfException, Exception {
startDate = new DfTime();
jobArguments = new CustomJobArguments(new DfMethodArgumentManager(args));
setupMethodFactory(writer);
String username = jobArguments.getUserName();
String password = jobArguments.getString("password");
String domain = jobArguments.getString("domain");
String docbase = jobArguments.getDocbaseName();
setupSessionManager(username, password, domain, docbase);
}
private void setupSessionManager(String username, String password, String domain, String docbase) throws DfServiceException, DfException {
DfLogger.debug(this, String.format("setupSessionManager-> username[%s] password[%s] domain[%s] docbase[%s]", username, password, domain, docbase), null, null);
clientx = new DfClientX();
client = clientx.getLocalClient();
sessionManager = client.newSessionManager();
IDfLoginInfo loginInfoObj = clientx.getLoginInfo();
loginInfoObj.setUser(username);
if (password != null && !password.equals(""))
loginInfoObj.setPassword(password);
loginInfoObj.setPassword(password);
loginInfoObj.setDomain(domain);
sessionManager.setIdentity(docbase, loginInfoObj);
session = sessionManager.getSession(docbase);
}
private void setupMethodFactory(PrintWriter writer) throws Exception {
try {
IDfId jobId = jobArguments.getJobId();
ReportFactory reportfactory = new ReportFactory();
if (writer != null) {
DfLogger.debug(this, "uso reportFactory", null, null);
reportWriter = reportfactory.getReport(jobArguments.getDocbaseName(), jobArguments.getUserName(), "", jobArguments.getMethodTraceLevel(), jobId, writer);
} else {
DfLogger.warn(this, "writer == null, uso SimpleReportWriter", null, null);
reportWriter = new SimpleReportWriter();
}
} catch (Exception e) {
DfLogger.error(this, "Failed to create report writer. Error: " + e.getMessage(), null, e);
throw e;
}
}
private void printJobStatusReport(int retCode) throws Exception {
reportWriter.emitLineToReport("Return Code-> " + retCode);
String jobStatus = null;
IDfTime end_date = new DfTime();
long min_duration = Utility.timeDiff(startDate, end_date) / 60L;
if (retCode == 0)
jobStatus = "Custom Job completed at " + end_date.asString("yyyy/mm/dd hh:mi:ss") + ". Total duration: " + min_duration + " minutes.";
else if (retCode > 0)
jobStatus = "Custom job completed with Warnings at " + end_date.asString("yyyy/mm/dd hh:mi:ss") + ". Total duration: " + min_duration + " minutes.";
else
jobStatus = "Custom job completed with Errors at " + end_date.asString("yyyy/mm/dd hh:mi:ss") + ". Total duration: " + min_duration + " minutes. Check job report for details.";
updateJobStatus(jobStatus, jobArguments.getJobId());
reportWriter.closeOut(retCode >= 0);
}
public void updateJobStatus(String sJobStatus, IDfId jobId) throws Exception {
if (session == null) {
DfLogger.error(this, "setJobStatus: (session==null)", null, null);
throw new NullPointerException("setJobStatus: (session==null)");
}
try {
IDfPersistentObject job = session.getObject(jobId);
if (job == null)
throw new DfException("Failed to retrieve dm_job object from id '" + jobId.getId() + "'.");
job.setString("a_current_status", sJobStatus);
job.save();
} catch (Exception e) {
throw e;
}
}
}
////
public class CustomJobArguments extends DfStandardJobArguments {
protected IDfMethodArgumentManager methodArgumentManager;
public CustomJobArguments(IDfMethodArgumentManager manager) throws DfMethodArgumentException {
super(manager);
methodArgumentManager=manager;
}
public String getString(String paramName) throws DfMethodArgumentException {
return methodArgumentManager.getString(paramName);
}
public int getInt(String paramName) throws DfMethodArgumentException {
return methodArgumentManager.getInt(paramName).intValue();
}
}
Thanks for this post and its been very helpful. Could you also post SimpleReportWriter and Utility class code as its been referenced in your code ?
ReplyDelete