We have a method which will recursively create docbase folder, base on some parameters received as input.
This method runs well in mono-thread environment, but when coming to multi-thread - which is required accounting for the needed throughput, as our method checks the existence of the folder, then tries creating it we may get the following error:
Error: [DM_FOLDER_E_PATH_EXISTS]error: "Cannot save (or link) 'MYFOLDER' folder with path name '/Client Documents/2,013/11/MYPARENT/MYFOLDER' because one already exists."
Exception: DfException:: THREAD: pool-1-thread-5; MSG: [DM_FOLDER_E_PATH_EXISTS]
We thought about 2 ways out:
- synchronize the whole method, which is possible but implies a performance cost
- catch this exception when it occurs, parse the message for the key of this error and, if found, return the existing folder
I assume this kind of problem is frequent when working with business objects and service mode, so does anyone know of a better way to handle it?
Please find below the code of our method:
// DocumentFolder object is a bean which defines the Path, the acl name and the acl domain
public String getOrCreateFolder(DocumentFolder folderToCreate) throws DfException {
IDfSession session = null;
try {
session = dctmDataSource.getSession();
String path = folderToCreate.getPath();
IDfId folderId = session.getIdByQualification("dm_folder WHERE ANY r_folder_path = '" + path + "'");
if (!folderId.isNull()) {
LOG.debug("Documentum folder {} was found. ID is {}", path, folderId.toString());
return folderId.getId();
}
LOG.debug("Documentum folder {} was not found. Creating path recursively.", path);
// Create folder hierarchy
String parentFolderName = "";
StringBuilder pathBuilder = new StringBuilder();
boolean isCabinet = true;
if (path.startsWith("/") && path.length() > 1) {
path = path.substring(1);
}
String[] folderNames = path.split("/");
for (String folderName : folderNames) {
pathBuilder.append("/");
pathBuilder.append(folderName);
folderId = session.getIdByQualification("dm_folder WHERE ANY r_folder_path = '" + pathBuilder + "'");
if (folderId.isNull()) {
LOG.info("Folder {} does not exist. Creating it..", pathBuilder.toString());
IDfFolder folder = null;
if (isCabinet) {
// The root folder is a cabinet. Everything below is a
// folder.
folder = (IDfFolder) session.newObject("dm_cabinet");
} else {
folder = (IDfFolder) session.newObject("dm_folder");
folder.link(parentFolderName);
}
folder.setObjectName(folderName);
if (!StringUtils.isBlank(folderToCreate.getAclName())
&& !StringUtils.isBlank(folderToCreate.getAclDomain())) {
folder.setACLName(folderToCreate.getAclName());
folder.setACLDomain(folderToCreate.getAclDomain());
}
folder.save();
folderId = folder.getObjectId();
} else {
LOG.debug("Folder {} already exist. Skipping creation.", pathBuilder.toString());
}
parentFolderName = pathBuilder.toString();
isCabinet = false;
}
return folderId.getId();
} finally {
if (session != null) {
dctmDataSource.releaseSession(session);
}
}
}