| /* |
| * Copyright (c) 2010-2013, 2015, 2016, 2019, 2020 Eike Stepper (Loehne, Germany) and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Eike Stepper - initial API and implementation |
| */ |
| package org.eclipse.emf.cdo.spi.common.branch; |
| |
| import org.eclipse.emf.cdo.common.branch.CDOBranch; |
| import org.eclipse.emf.cdo.common.branch.CDOBranchManager; |
| import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; |
| import org.eclipse.emf.cdo.common.branch.CDOBranchPointRange; |
| import org.eclipse.emf.cdo.common.branch.CDOBranchVersion; |
| import org.eclipse.emf.cdo.common.protocol.CDODataInput; |
| import org.eclipse.emf.cdo.common.protocol.CDODataOutput; |
| import org.eclipse.emf.cdo.common.util.CDOCommonUtil; |
| import org.eclipse.emf.cdo.internal.common.branch.CDOBranchManagerImpl; |
| import org.eclipse.emf.cdo.internal.common.branch.CDOBranchPointRangeImpl; |
| |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| /** |
| * If the meaning of this type isn't clear, there really should be more of a description here... |
| * |
| * @author Eike Stepper |
| * @since 3.0 |
| */ |
| public final class CDOBranchUtil |
| { |
| private static final char PATH_SEPARATOR_CHAR = CDOBranch.PATH_SEPARATOR.charAt(0); |
| |
| /** |
| * @since 4.6 |
| */ |
| public static final CDOBranchPoint AUTO_BRANCH_POINT = new AutoBranchPoint(); |
| |
| private CDOBranchUtil() |
| { |
| } |
| |
| public static InternalCDOBranchManager createBranchManager() |
| { |
| return new CDOBranchManagerImpl(); |
| } |
| |
| public static CDOBranchPointRange createRange(CDOBranchPoint startPoint, CDOBranchPoint endPoint) |
| { |
| return new CDOBranchPointRangeImpl(startPoint, endPoint); |
| } |
| |
| /** |
| * @since 4.6 |
| */ |
| public static void writeRange(CDODataOutput out, CDOBranchPointRange range) throws IOException |
| { |
| out.writeCDOBranchPoint(range.getStartPoint()); |
| out.writeCDOBranchPoint(range.getEndPoint()); |
| } |
| |
| /** |
| * @since 4.6 |
| */ |
| public static CDOBranchPointRange readRange(CDODataInput in) throws IOException |
| { |
| CDOBranchPoint startPoint = in.readCDOBranchPoint(); |
| CDOBranchPoint endPoint = in.readCDOBranchPoint(); |
| return createRange(startPoint, endPoint); |
| } |
| |
| /** |
| * @since 4.6 |
| */ |
| public static void writeRangeOrNull(CDODataOutput out, CDOBranchPointRange range) throws IOException |
| { |
| if (range != null) |
| { |
| out.writeBoolean(true); |
| writeRange(out, range); |
| } |
| else |
| { |
| out.writeBoolean(false); |
| } |
| } |
| |
| /** |
| * @since 4.6 |
| */ |
| public static CDOBranchPointRange readRangeOrNull(CDODataInput in) throws IOException |
| { |
| if (in.readBoolean()) |
| { |
| return readRange(in); |
| } |
| |
| return null; |
| } |
| |
| /** |
| * @since 4.6 |
| */ |
| public static void writeBranchPointOrNull(CDODataOutput out, CDOBranchPoint point) throws IOException |
| { |
| if (point != null) |
| { |
| out.writeBoolean(true); |
| out.writeCDOBranchPoint(point); |
| } |
| else |
| { |
| out.writeBoolean(false); |
| } |
| } |
| |
| /** |
| * @since 4.6 |
| */ |
| public static CDOBranchPoint readBranchPointOrNull(CDODataInput in) throws IOException |
| { |
| if (in.readBoolean()) |
| { |
| return in.readCDOBranchPoint(); |
| } |
| |
| return null; |
| } |
| |
| public static CDOBranchPoint copyBranchPoint(CDOBranchPoint source) |
| { |
| return source.getBranch().getPoint(source.getTimeStamp()); |
| } |
| |
| public static CDOBranchVersion copyBranchVersion(CDOBranchVersion source) |
| { |
| return source.getBranch().getVersion(source.getVersion()); |
| } |
| |
| /** |
| * @since 4.14 |
| */ |
| public static CDOBranch adjustBranch(CDOBranch branch, CDOBranchManager branchManager) |
| { |
| if (branch.getBranchManager() != branchManager) |
| { |
| branch = branchManager.getBranch(branch.getID()); |
| } |
| |
| return branch; |
| } |
| |
| /** |
| * @since 4.4 |
| */ |
| public static CDOBranchPoint adjustBranchPoint(CDOBranchPoint branchPoint, CDOBranchManager branchManager) |
| { |
| CDOBranch branch = branchPoint.getBranch(); |
| CDOBranch adjustedBranch = adjustBranch(branch, branchManager); |
| if (adjustedBranch != branch) |
| { |
| branchPoint = adjustedBranch.getPoint(branchPoint.getTimeStamp()); |
| } |
| |
| return branchPoint; |
| } |
| |
| /** |
| * @since 4.4 |
| */ |
| public static CDOBranchPoint normalizeBranchPoint(CDOBranchPoint branchPoint) |
| { |
| long timeStamp = branchPoint.getTimeStamp(); |
| if (timeStamp == CDOBranchPoint.UNSPECIFIED_DATE) |
| { |
| return branchPoint; |
| } |
| |
| CDOBranch branch = branchPoint.getBranch(); |
| return doNormalizeBranchPoint(branch, timeStamp); |
| } |
| |
| /** |
| * @since 4.2 |
| */ |
| public static CDOBranchPoint normalizeBranchPoint(CDOBranch branch, long timeStamp) |
| { |
| if (timeStamp == CDOBranchPoint.UNSPECIFIED_DATE) |
| { |
| return branch.getHead(); |
| } |
| |
| return doNormalizeBranchPoint(branch, timeStamp); |
| } |
| |
| private static CDOBranchPoint doNormalizeBranchPoint(CDOBranch branch, long timeStamp) |
| { |
| for (;;) |
| { |
| long baseTime = branch.getBase().getTimeStamp(); |
| if (timeStamp < baseTime) |
| { |
| branch = branch.getBase().getBranch(); |
| if (branch == null) |
| { |
| throw new IllegalArgumentException( |
| "Time " + CDOCommonUtil.formatTimeStamp(timeStamp) + " is before the repository creation time " + CDOCommonUtil.formatTimeStamp(baseTime)); |
| } |
| } |
| else |
| { |
| return branch.getPoint(timeStamp); |
| } |
| } |
| } |
| |
| public static boolean isContainedBy(CDOBranchPoint contained, CDOBranchPoint container) |
| { |
| CDOBranch containerBranch = container.getBranch(); |
| if (containerBranch == contained.getBranch()) |
| { |
| return CDOCommonUtil.compareTimeStamps(contained.getTimeStamp(), container.getTimeStamp()) <= 0; |
| } |
| |
| if (containerBranch == null) |
| { |
| return false; |
| } |
| |
| return isContainedBy(contained, containerBranch.getBase()); |
| } |
| |
| public static CDOBranchPoint getAncestor(CDOBranchPoint point1, CDOBranchPoint point2) |
| { |
| if (point1.getBranch() == null) |
| { |
| // Must be the main branch base |
| return point1; |
| } |
| |
| if (point2.getBranch() == null) |
| { |
| // Must be the main branch base |
| return point2; |
| } |
| |
| CDOBranchPoint[] path1 = getPath(point1); |
| CDOBranchPoint[] path2 = getPath(point2); |
| for (CDOBranchPoint pathPoint1 : path1) |
| { |
| for (CDOBranchPoint pathPoint2 : path2) |
| { |
| if (pathPoint1.getBranch() == pathPoint2.getBranch()) |
| { |
| if (CDOCommonUtil.compareTimeStamps(pathPoint1.getTimeStamp(), pathPoint2.getTimeStamp()) < 0) |
| { |
| return pathPoint1; |
| } |
| |
| return pathPoint2; |
| } |
| } |
| } |
| |
| // Can not happen because any two branches meet on the main branch |
| return null; |
| } |
| |
| public static CDOBranchPoint[] getPath(CDOBranchPoint point) |
| { |
| List<CDOBranchPoint> result = new ArrayList<>(); |
| getPath(point, result); |
| return result.toArray(new CDOBranchPoint[result.size()]); |
| } |
| |
| private static void getPath(CDOBranchPoint point, List<CDOBranchPoint> result) |
| { |
| CDOBranch branch = point.getBranch(); |
| if (branch != null) |
| { |
| result.add(point); |
| getPath(branch.getBase(), result); |
| } |
| } |
| |
| /** |
| * @since 4.12 |
| */ |
| public static String sanitizePathName(String pathName) |
| { |
| pathName = pathName.trim(); |
| int length = pathName.length(); |
| |
| int i = 0; |
| while (i < length && pathName.charAt(i) == PATH_SEPARATOR_CHAR) |
| { |
| ++i; |
| } |
| |
| return i == 0 ? pathName : pathName.substring(i); |
| } |
| |
| /** |
| * @author Eike Stepper |
| */ |
| private static final class AutoBranchPoint implements CDOBranchPoint |
| { |
| @Override |
| public long getTimeStamp() |
| { |
| return Long.MIN_VALUE; |
| } |
| |
| @Override |
| public CDOBranch getBranch() |
| { |
| return null; |
| } |
| |
| @Override |
| public String toString() |
| { |
| return "BranchPoint[AUTO]"; |
| } |
| } |
| } |