Use 3 different types of LargeObjectException for the 3 major ways that we can fail to load an object. For each of these use a unique string translation which describes the root cause better than just the ObjectId.name() does. Change-Id: I810c98d5691b74af9fc6cbd46fc9879e35a7bdca Signed-off-by: Shawn O. Pearce <spearce@spearce.org>tags/v0.9.1
@@ -47,9 +47,11 @@ import java.io.ByteArrayInputStream; | |||
import java.io.ByteArrayOutputStream; | |||
import java.io.IOException; | |||
import java.security.MessageDigest; | |||
import java.text.MessageFormat; | |||
import java.util.Arrays; | |||
import java.util.zip.Deflater; | |||
import org.eclipse.jgit.JGitText; | |||
import org.eclipse.jgit.errors.LargeObjectException; | |||
import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase; | |||
import org.eclipse.jgit.junit.TestRepository; | |||
@@ -133,7 +135,9 @@ public class PackFileTest extends LocalDiskRepositoryTestCase { | |||
ol.getCachedBytes(); | |||
fail("Should have thrown LargeObjectException"); | |||
} catch (LargeObjectException tooBig) { | |||
assertEquals(id.name(), tooBig.getMessage()); | |||
assertEquals(MessageFormat.format( | |||
JGitText.get().largeObjectException, id.name()), tooBig | |||
.getMessage()); | |||
} | |||
ObjectStream in = ol.openStream(); | |||
@@ -257,7 +261,9 @@ public class PackFileTest extends LocalDiskRepositoryTestCase { | |||
ol.getCachedBytes(); | |||
fail("Should have thrown LargeObjectException"); | |||
} catch (LargeObjectException tooBig) { | |||
assertEquals(id3.name(), tooBig.getMessage()); | |||
assertEquals(MessageFormat.format( | |||
JGitText.get().largeObjectException, id3.name()), tooBig | |||
.getMessage()); | |||
} | |||
ObjectStream in = ol.openStream(); | |||
@@ -313,7 +319,9 @@ public class PackFileTest extends LocalDiskRepositoryTestCase { | |||
ol.getCachedBytes(); | |||
fail("Should have thrown LargeObjectException"); | |||
} catch (LargeObjectException tooBig) { | |||
assertEquals(id3.name(), tooBig.getMessage()); | |||
assertEquals(MessageFormat.format( | |||
JGitText.get().largeObjectException, id3.name()), tooBig | |||
.getMessage()); | |||
} | |||
ObjectStream in = ol.openStream(); |
@@ -135,7 +135,9 @@ public class UnpackedObjectTest extends LocalDiskRepositoryTestCase { | |||
ol.getCachedBytes(); | |||
fail("Should have thrown LargeObjectException"); | |||
} catch (LargeObjectException tooBig) { | |||
assertEquals(id.name(), tooBig.getMessage()); | |||
assertEquals(MessageFormat.format( | |||
JGitText.get().largeObjectException, id.name()), tooBig | |||
.getMessage()); | |||
} | |||
ObjectStream in = ol.openStream(); | |||
@@ -416,7 +418,9 @@ public class UnpackedObjectTest extends LocalDiskRepositoryTestCase { | |||
ol.getCachedBytes(); | |||
fail("Should have thrown LargeObjectException"); | |||
} catch (LargeObjectException tooBig) { | |||
assertEquals(id.name(), tooBig.getMessage()); | |||
assertEquals(MessageFormat.format( | |||
JGitText.get().largeObjectException, id.name()), tooBig | |||
.getMessage()); | |||
} | |||
ObjectStream in = ol.openStream(); |
@@ -216,6 +216,10 @@ invalidWildcards=Invalid wildcards {0} | |||
invalidWindowSize=Invalid window size | |||
isAStaticFlagAndHasNorevWalkInstance={0} is a static flag and has no RevWalk instance | |||
kNotInRange=k {0} not in {1} - {2} | |||
largeObjectException={0} exceeds size limit | |||
largeObjectOutOfMemory=Out of memory loading {0} | |||
largeObjectExceedsByteArray=Object {0} exceeds 2 GiB byte array limit | |||
largeObjectExceedsLimit=Object {0} exceeds {1} limit, actual size is {2} | |||
lengthExceedsMaximumArraySize=Length exceeds maximum array size | |||
listingAlternates=Listing alternates | |||
localObjectsIncomplete=Local objects incomplete. | |||
@@ -374,6 +378,7 @@ unexpectedReportLine=unexpected report line: {0} | |||
unknownDIRCVersion=Unknown DIRC version {0} | |||
unknownHost=unknown host | |||
unknownIndexVersionOrCorruptIndex=Unknown index version (or corrupt index): {0} | |||
unknownObject=unknown object | |||
unknownObjectType=Unknown object type {0}. | |||
unknownRepositoryFormat2=Unknown repository format "{0}"; expected "0". | |||
unknownRepositoryFormat=Unknown repository format |
@@ -276,6 +276,10 @@ public class JGitText extends TranslationBundle { | |||
/***/ public String invalidWindowSize; | |||
/***/ public String isAStaticFlagAndHasNorevWalkInstance; | |||
/***/ public String kNotInRange; | |||
/***/ public String largeObjectException; | |||
/***/ public String largeObjectOutOfMemory; | |||
/***/ public String largeObjectExceedsByteArray; | |||
/***/ public String largeObjectExceedsLimit; | |||
/***/ public String lengthExceedsMaximumArraySize; | |||
/***/ public String listingAlternates; | |||
/***/ public String localObjectsIncomplete; | |||
@@ -433,6 +437,7 @@ public class JGitText extends TranslationBundle { | |||
/***/ public String unknownDIRCVersion; | |||
/***/ public String unknownHost; | |||
/***/ public String unknownIndexVersionOrCorruptIndex; | |||
/***/ public String unknownObject; | |||
/***/ public String unknownObjectType; | |||
/***/ public String unknownRepositoryFormat2; | |||
/***/ public String unknownRepositoryFormat; |
@@ -43,6 +43,9 @@ | |||
package org.eclipse.jgit.errors; | |||
import java.text.MessageFormat; | |||
import org.eclipse.jgit.JGitText; | |||
import org.eclipse.jgit.lib.AnyObjectId; | |||
import org.eclipse.jgit.lib.ObjectId; | |||
@@ -73,6 +76,13 @@ public class LargeObjectException extends RuntimeException { | |||
return objectId; | |||
} | |||
/** @return either the hex encoded name of the object, or 'unknown object'. */ | |||
protected String getObjectName() { | |||
if (getObjectId() != null) | |||
return getObjectId().name(); | |||
return JGitText.get().unknownObject; | |||
} | |||
/** | |||
* Set the identity of the object, if its not already set. | |||
* | |||
@@ -86,6 +96,68 @@ public class LargeObjectException extends RuntimeException { | |||
@Override | |||
public String getMessage() { | |||
return objectId != null ? objectId.name() : getClass().getSimpleName(); | |||
return MessageFormat.format(JGitText.get().largeObjectException, | |||
getObjectName()); | |||
} | |||
/** An error caused by the JVM being out of heap space. */ | |||
public static class OutOfMemory extends LargeObjectException { | |||
private static final long serialVersionUID = 1L; | |||
/** | |||
* Construct a wrapper around the original OutOfMemoryError. | |||
* | |||
* @param cause | |||
* the original root cause. | |||
*/ | |||
public OutOfMemory(OutOfMemoryError cause) { | |||
initCause(cause); | |||
} | |||
@Override | |||
public String getMessage() { | |||
return MessageFormat.format(JGitText.get().largeObjectOutOfMemory, | |||
getObjectName()); | |||
} | |||
} | |||
/** Object size exceeds JVM limit of 2 GiB per byte array. */ | |||
public static class ExceedsByteArrayLimit extends LargeObjectException { | |||
private static final long serialVersionUID = 1L; | |||
@Override | |||
public String getMessage() { | |||
return MessageFormat | |||
.format(JGitText.get().largeObjectExceedsByteArray, | |||
getObjectName()); | |||
} | |||
} | |||
/** Object size exceeds the caller's upper limit. */ | |||
public static class ExceedsLimit extends LargeObjectException { | |||
private static final long serialVersionUID = 1L; | |||
private final long limit; | |||
private final long size; | |||
/** | |||
* Construct an exception for a particular size being exceeded. | |||
* | |||
* @param limit | |||
* the limit the caller imposed on the object. | |||
* @param size | |||
* the actual size of the object. | |||
*/ | |||
public ExceedsLimit(long limit, long size) { | |||
this.limit = limit; | |||
this.size = size; | |||
} | |||
@Override | |||
public String getMessage() { | |||
return MessageFormat.format(JGitText.get().largeObjectExceedsLimit, | |||
getObjectName(), limit, size); | |||
} | |||
} | |||
} |
@@ -139,7 +139,7 @@ public abstract class ObjectLoader { | |||
try { | |||
return cloneArray(cached); | |||
} catch (OutOfMemoryError tooBig) { | |||
throw new LargeObjectException(); | |||
throw new LargeObjectException.OutOfMemory(tooBig); | |||
} | |||
} | |||
@@ -195,14 +195,17 @@ public abstract class ObjectLoader { | |||
ObjectStream in = openStream(); | |||
try { | |||
long sz = in.getSize(); | |||
if (sizeLimit < sz || Integer.MAX_VALUE < sz) | |||
throw new LargeObjectException(); | |||
if (sizeLimit < sz) | |||
throw new LargeObjectException.ExceedsLimit(sizeLimit, sz); | |||
if (Integer.MAX_VALUE < sz) | |||
throw new LargeObjectException.ExceedsByteArrayLimit(); | |||
byte[] buf; | |||
try { | |||
buf = new byte[(int) sz]; | |||
} catch (OutOfMemoryError notEnoughHeap) { | |||
throw new LargeObjectException(); | |||
throw new LargeObjectException.OutOfMemory(notEnoughHeap); | |||
} | |||
IO.readFully(in, buf, 0, buf.length); |
@@ -157,7 +157,9 @@ class LargePackedDeltaObject extends ObjectLoader { | |||
try { | |||
throw new LargeObjectException(getObjectId()); | |||
} catch (IOException cannotObtainId) { | |||
throw new LargeObjectException(); | |||
LargeObjectException err = new LargeObjectException(); | |||
err.initCause(cannotObtainId); | |||
throw err; | |||
} | |||
} | |||
@@ -97,7 +97,9 @@ class LargePackedWholeObject extends ObjectLoader { | |||
try { | |||
throw new LargeObjectException(getObjectId()); | |||
} catch (IOException cannotObtainId) { | |||
throw new LargeObjectException(); | |||
LargeObjectException err = new LargeObjectException(); | |||
err.initCause(cannotObtainId); | |||
throw err; | |||
} | |||
} | |||
@@ -125,8 +125,12 @@ public class UnpackedObject { | |||
if (hdr[p.value++] != 0) | |||
throw new CorruptObjectException(id, | |||
JGitText.get().corruptObjectGarbageAfterSize); | |||
if (path == null && Integer.MAX_VALUE < size) | |||
throw new LargeObjectException(id.copy()); | |||
if (path == null && Integer.MAX_VALUE < size) { | |||
LargeObjectException.ExceedsByteArrayLimit e; | |||
e = new LargeObjectException.ExceedsByteArrayLimit(); | |||
e.setObjectId(id); | |||
throw e; | |||
} | |||
if (size < wc.getStreamFileThreshold() || path == null) { | |||
byte[] data = new byte[(int) size]; | |||
int n = avail - p.value; | |||
@@ -163,8 +167,12 @@ public class UnpackedObject { | |||
JGitText.get().corruptObjectInvalidType); | |||
} | |||
if (path == null && Integer.MAX_VALUE < size) | |||
throw new LargeObjectException(id.copy()); | |||
if (path == null && Integer.MAX_VALUE < size) { | |||
LargeObjectException.ExceedsByteArrayLimit e; | |||
e = new LargeObjectException.ExceedsByteArrayLimit(); | |||
e.setObjectId(id); | |||
throw e; | |||
} | |||
if (size < wc.getStreamFileThreshold() || path == null) { | |||
in.reset(); | |||
IO.skipFully(in, p); |
@@ -424,8 +424,9 @@ class DeltaWindow { | |||
try { | |||
idx = new DeltaIndex(buffer(ent)); | |||
} catch (OutOfMemoryError noMemory) { | |||
LargeObjectException e = new LargeObjectException(ent.object); | |||
e.initCause(noMemory); | |||
LargeObjectException.OutOfMemory e; | |||
e = new LargeObjectException.OutOfMemory(noMemory); | |||
e.setObjectId(ent.object); | |||
throw e; | |||
} | |||
if (0 < maxMemory) |