/** * Commit the passed in changed cube records identified by NCubeInfoDtos. * * @return array of NCubeInfoDtos that are to be committed. */ public static List<NCubeInfoDto> commitBranch( ApplicationID appId, Object[] infoDtos, String username) { validateAppId(appId); appId.validateBranchIsNotHead(); appId.validateStatusIsNotRelease(); ApplicationID headAppId = appId.asHead(); Map<String, NCubeInfoDto> headMap = new TreeMap<>(); Map<String, Object> options = new HashMap<>(); options.put(SEARCH_ACTIVE_RECORDS_ONLY, false); List<NCubeInfoDto> headInfo = search(headAppId, null, null, options); // build map of head objects for reference. for (NCubeInfoDto info : headInfo) { headMap.put(info.name, info); } List<NCubeInfoDto> dtosToUpdate = new ArrayList<>(infoDtos.length); List<NCubeInfoDto> dtosMerged = new ArrayList<>(); Map<String, Map> errors = new LinkedHashMap<>(); for (Object dto : infoDtos) { NCubeInfoDto branchCubeInfo = (NCubeInfoDto) dto; if (!branchCubeInfo.isChanged()) { continue; } if (branchCubeInfo.sha1 == null) { branchCubeInfo.sha1 = ""; } // All changes go through here. NCubeInfoDto headCubeInfo = headMap.get(branchCubeInfo.name); long infoRev = (long) Converter.convert(branchCubeInfo.revision, long.class); if (headCubeInfo == null) { // No matching head cube, CREATE case if (infoRev >= 0) { // Only create if the cube in the branch is active (revision number not // negative) dtosToUpdate.add(branchCubeInfo); } } else if (StringUtilities.equalsIgnoreCase( branchCubeInfo.headSha1, headCubeInfo .sha1)) { // HEAD cube has not changed (at least in terms of SHA-1 it could have it's // revision sign changed) if (StringUtilities.equalsIgnoreCase( branchCubeInfo.sha1, branchCubeInfo .headSha1)) { // Cubes are same, but active status could be opposite (delete or // restore case) long headRev = (long) Converter.convert(headCubeInfo.revision, long.class); if ((infoRev < 0) != (headRev < 0)) { dtosToUpdate.add(branchCubeInfo); } } else { // Regular update case (branch updated cube that was not touched in HEAD) dtosToUpdate.add(branchCubeInfo); } } else if (StringUtilities.equalsIgnoreCase( branchCubeInfo.sha1, headCubeInfo .sha1)) { // Branch headSha1 does not match HEAD sha1, but it's SHA-1 matches the HEAD // SHA-1. // This means that the branch cube and HEAD cube are identical, but the HEAD was // different when the branch was created. dtosToUpdate.add(branchCubeInfo); } else { String msg; if (branchCubeInfo.headSha1 == null) { msg = ". A cube with the same name was added to HEAD since your branch was created."; } else { msg = ". The cube changed since your last update branch."; } String message = "Conflict merging " + branchCubeInfo.name + msg; NCube mergedCube = checkForConflicts(appId, errors, message, branchCubeInfo, headCubeInfo, false); if (mergedCube != null) { NCubeInfoDto mergedDto = getPersister().commitMergedCubeToHead(appId, mergedCube, username); dtosMerged.add(mergedDto); } } } if (!errors.isEmpty()) { throw new BranchMergeException( errors.size() + " merge conflict(s) committing branch. Update your branch and retry commit.", errors); } List<NCubeInfoDto> committedCubes = new ArrayList<>(dtosToUpdate.size()); Object[] ids = new Object[dtosToUpdate.size()]; int i = 0; for (NCubeInfoDto dto : dtosToUpdate) { ids[i++] = dto.id; } committedCubes.addAll(getPersister().commitCubes(appId, ids, username)); committedCubes.addAll(dtosMerged); clearCache(appId); clearCache(headAppId); broadcast(appId); return committedCubes; }