View Javadoc
1   /*
2    * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
3    * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
4    * Copyright (C) 2009, Google Inc.
5    * Copyright (C) 2010, Chris Aniszczyk <caniszczyk@gmail.com>
6    * and other copyright owners as documented in the project's IP log.
7    *
8    * This program and the accompanying materials are made available
9    * under the terms of the Eclipse Distribution License v1.0 which
10   * accompanies this distribution, is reproduced below, and is
11   * available at http://www.eclipse.org/org/documents/edl-v10.php
12   *
13   * All rights reserved.
14   *
15   * Redistribution and use in source and binary forms, with or
16   * without modification, are permitted provided that the following
17   * conditions are met:
18   *
19   * - Redistributions of source code must retain the above copyright
20   *   notice, this list of conditions and the following disclaimer.
21   *
22   * - Redistributions in binary form must reproduce the above
23   *   copyright notice, this list of conditions and the following
24   *   disclaimer in the documentation and/or other materials provided
25   *   with the distribution.
26   *
27   * - Neither the name of the Eclipse Foundation, Inc. nor the
28   *   names of its contributors may be used to endorse or promote
29   *   products derived from this software without specific prior
30   *   written permission.
31   *
32   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
33   * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
34   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
37   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
39   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
40   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
41   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
42   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
43   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
44   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45   */
46  
47  package org.eclipse.jgit.lib;
48  
49  import java.io.ByteArrayInputStream;
50  import java.io.EOFException;
51  import java.io.IOException;
52  import java.io.InputStream;
53  
54  import org.eclipse.jgit.internal.JGitText;
55  import org.eclipse.jgit.transport.PackParser;
56  import org.eclipse.jgit.util.sha1.SHA1;
57  
58  /**
59   * Inserts objects into an existing {@code ObjectDatabase}.
60   * <p>
61   * An inserter is not thread-safe. Individual threads should each obtain their
62   * own unique inserter instance, or must arrange for locking at a higher level
63   * to ensure the inserter is in use by no more than one thread at a time.
64   * <p>
65   * Objects written by an inserter may not be immediately visible for reading
66   * after the insert method completes. Callers must invoke either
67   * {@link #close()} or {@link #flush()} prior to updating references or
68   * otherwise making the returned ObjectIds visible to other code.
69   */
70  public abstract class ObjectInserter implements AutoCloseable {
71  	/** An inserter that can be used for formatting and id generation only. */
72  	public static class Formatter extends ObjectInserter {
73  		@Override
74  		public ObjectId insert(int objectType, long length, InputStream in)
75  				throws IOException {
76  			throw new UnsupportedOperationException();
77  		}
78  
79  		@Override
80  		public PackParser newPackParser(InputStream in) throws IOException {
81  			throw new UnsupportedOperationException();
82  		}
83  
84  		@Override
85  		public ObjectReader newReader() {
86  			throw new UnsupportedOperationException();
87  		}
88  
89  		@Override
90  		public void flush() throws IOException {
91  			// Do nothing.
92  		}
93  
94  		@Override
95  		public void close() {
96  			// Do nothing.
97  		}
98  	}
99  
100 	/** Wraps a delegate ObjectInserter. */
101 	public static abstract class Filter extends ObjectInserter {
102 		/** @return delegate ObjectInserter to handle all processing. */
103 		protected abstract ObjectInserter delegate();
104 
105 		@Override
106 		protected byte[] buffer() {
107 			return delegate().buffer();
108 		}
109 
110 		@Override
111 		public ObjectId idFor(int type, byte[] data) {
112 			return delegate().idFor(type, data);
113 		}
114 
115 		@Override
116 		public ObjectId idFor(int type, byte[] data, int off, int len) {
117 			return delegate().idFor(type, data, off, len);
118 		}
119 
120 		@Override
121 		public ObjectId idFor(int objectType, long length, InputStream in)
122 				throws IOException {
123 			return delegate().idFor(objectType, length, in);
124 		}
125 
126 		@Override
127 		public ObjectId idFor(TreeFormatter formatter) {
128 			return delegate().idFor(formatter);
129 		}
130 
131 		@Override
132 		public ObjectId insert(int type, byte[] data) throws IOException {
133 			return delegate().insert(type, data);
134 		}
135 
136 		@Override
137 		public ObjectId insert(int type, byte[] data, int off, int len)
138 				throws IOException {
139 			return delegate().insert(type, data, off, len);
140 		}
141 
142 		@Override
143 		public ObjectId insert(int objectType, long length, InputStream in)
144 				throws IOException {
145 			return delegate().insert(objectType, length, in);
146 		}
147 
148 		@Override
149 		public PackParser newPackParser(InputStream in) throws IOException {
150 			return delegate().newPackParser(in);
151 		}
152 
153 		@Override
154 		public ObjectReader newReader() {
155 			final ObjectReader dr = delegate().newReader();
156 			return new ObjectReader.Filter() {
157 				@Override
158 				protected ObjectReader delegate() {
159 					return dr;
160 				}
161 
162 				@Override
163 				public ObjectInserter getCreatedFromInserter() {
164 					return ObjectInserter.Filter.this;
165 				}
166 			};
167 		}
168 
169 		@Override
170 		public void flush() throws IOException {
171 			delegate().flush();
172 		}
173 
174 		@Override
175 		public void close() {
176 			delegate().close();
177 		}
178 	}
179 
180 	private final SHA1 hasher = SHA1.newInstance();
181 
182 	/** Temporary working buffer for streaming data through. */
183 	private byte[] tempBuffer;
184 
185 	/** Create a new inserter for a database. */
186 	protected ObjectInserter() {
187 	}
188 
189 	/**
190 	 * Obtain a temporary buffer for use by the ObjectInserter or its subclass.
191 	 * <p>
192 	 * This buffer is supplied by the ObjectInserter base class to itself and
193 	 * its subclasses for the purposes of pulling data from a supplied
194 	 * InputStream, passing it through a Deflater, or formatting the canonical
195 	 * format of a small object like a small tree or commit.
196 	 * <p>
197 	 * <strong>This buffer IS NOT for translation such as auto-CRLF or content
198 	 * filtering and must not be used for such purposes.</strong>
199 	 * <p>
200 	 * The returned buffer is small, around a few KiBs, and the size may change
201 	 * between versions of JGit. Callers using this buffer must always check the
202 	 * length of the returned array to ascertain how much space was provided.
203 	 * <p>
204 	 * There is a single buffer for each ObjectInserter, repeated calls to this
205 	 * method will (usually) always return the same buffer. If the caller needs
206 	 * more than one buffer, or needs a buffer of a larger size, it must manage
207 	 * that buffer on its own.
208 	 * <p>
209 	 * The buffer is usually on first demand for a buffer.
210 	 *
211 	 * @return a temporary byte array for use by the caller.
212 	 */
213 	protected byte[] buffer() {
214 		byte[] b = tempBuffer;
215 		if (b == null)
216 			tempBuffer = b = new byte[8192];
217 		return b;
218 	}
219 
220 	/**
221 	 * @return digest to help compute an ObjectId
222 	 * @since 4.7
223 	 */
224 	protected SHA1 digest() {
225 		return hasher.reset();
226 	}
227 
228 	/**
229 	 * Compute the name of an object, without inserting it.
230 	 *
231 	 * @param type
232 	 *            type code of the object to store.
233 	 * @param data
234 	 *            complete content of the object.
235 	 * @return the name of the object.
236 	 */
237 	public ObjectId idFor(int type, byte[] data) {
238 		return idFor(type, data, 0, data.length);
239 	}
240 
241 	/**
242 	 * Compute the name of an object, without inserting it.
243 	 *
244 	 * @param type
245 	 *            type code of the object to store.
246 	 * @param data
247 	 *            complete content of the object.
248 	 * @param off
249 	 *            first position within {@code data}.
250 	 * @param len
251 	 *            number of bytes to copy from {@code data}.
252 	 * @return the name of the object.
253 	 */
254 	public ObjectId idFor(int type, byte[] data, int off, int len) {
255 		SHA1 md = SHA1.newInstance();
256 		md.update(Constants.encodedTypeString(type));
257 		md.update((byte) ' ');
258 		md.update(Constants.encodeASCII(len));
259 		md.update((byte) 0);
260 		md.update(data, off, len);
261 		return md.toObjectId();
262 	}
263 
264 	/**
265 	 * Compute the name of an object, without inserting it.
266 	 *
267 	 * @param objectType
268 	 *            type code of the object to store.
269 	 * @param length
270 	 *            number of bytes to scan from {@code in}.
271 	 * @param in
272 	 *            stream providing the object content. The caller is responsible
273 	 *            for closing the stream.
274 	 * @return the name of the object.
275 	 * @throws IOException
276 	 *             the source stream could not be read.
277 	 */
278 	public ObjectId idFor(int objectType, long length, InputStream in)
279 			throws IOException {
280 		SHA1 md = SHA1.newInstance();
281 		md.update(Constants.encodedTypeString(objectType));
282 		md.update((byte) ' ');
283 		md.update(Constants.encodeASCII(length));
284 		md.update((byte) 0);
285 		byte[] buf = buffer();
286 		while (length > 0) {
287 			int n = in.read(buf, 0, (int) Math.min(length, buf.length));
288 			if (n < 0)
289 				throw new EOFException(JGitText.get().unexpectedEndOfInput);
290 			md.update(buf, 0, n);
291 			length -= n;
292 		}
293 		return md.toObjectId();
294 	}
295 
296 	/**
297 	 * Compute the ObjectId for the given tree without inserting it.
298 	 *
299 	 * @param formatter
300 	 * @return the computed ObjectId
301 	 */
302 	public ObjectId idFor(TreeFormatter formatter) {
303 		return formatter.computeId(this);
304 	}
305 
306 	/**
307 	 * Insert a single tree into the store, returning its unique name.
308 	 *
309 	 * @param formatter
310 	 *            the formatter containing the proposed tree's data.
311 	 * @return the name of the tree object.
312 	 * @throws IOException
313 	 *             the object could not be stored.
314 	 */
315 	public final ObjectId insert(TreeFormatter formatter) throws IOException {
316 		// Delegate to the formatter, as then it can pass the raw internal
317 		// buffer back to this inserter, avoiding unnecessary data copying.
318 		//
319 		return formatter.insertTo(this);
320 	}
321 
322 	/**
323 	 * Insert a single commit into the store, returning its unique name.
324 	 *
325 	 * @param builder
326 	 *            the builder containing the proposed commit's data.
327 	 * @return the name of the commit object.
328 	 * @throws IOException
329 	 *             the object could not be stored.
330 	 */
331 	public final ObjectId insert(CommitBuilder builder) throws IOException {
332 		return insert(Constants.OBJ_COMMIT, builder.build());
333 	}
334 
335 	/**
336 	 * Insert a single annotated tag into the store, returning its unique name.
337 	 *
338 	 * @param builder
339 	 *            the builder containing the proposed tag's data.
340 	 * @return the name of the tag object.
341 	 * @throws IOException
342 	 *             the object could not be stored.
343 	 */
344 	public final ObjectId insert(TagBuilder builder) throws IOException {
345 		return insert(Constants.OBJ_TAG, builder.build());
346 	}
347 
348 	/**
349 	 * Insert a single object into the store, returning its unique name.
350 	 *
351 	 * @param type
352 	 *            type code of the object to store.
353 	 * @param data
354 	 *            complete content of the object.
355 	 * @return the name of the object.
356 	 * @throws IOException
357 	 *             the object could not be stored.
358 	 */
359 	public ObjectId insert(final int type, final byte[] data)
360 			throws IOException {
361 		return insert(type, data, 0, data.length);
362 	}
363 
364 	/**
365 	 * Insert a single object into the store, returning its unique name.
366 	 *
367 	 * @param type
368 	 *            type code of the object to store.
369 	 * @param data
370 	 *            complete content of the object.
371 	 * @param off
372 	 *            first position within {@code data}.
373 	 * @param len
374 	 *            number of bytes to copy from {@code data}.
375 	 * @return the name of the object.
376 	 * @throws IOException
377 	 *             the object could not be stored.
378 	 */
379 	public ObjectId insert(int type, byte[] data, int off, int len)
380 			throws IOException {
381 		return insert(type, len, new ByteArrayInputStream(data, off, len));
382 	}
383 
384 	/**
385 	 * Insert a single object into the store, returning its unique name.
386 	 *
387 	 * @param objectType
388 	 *            type code of the object to store.
389 	 * @param length
390 	 *            number of bytes to copy from {@code in}.
391 	 * @param in
392 	 *            stream providing the object content. The caller is responsible
393 	 *            for closing the stream.
394 	 * @return the name of the object.
395 	 * @throws IOException
396 	 *             the object could not be stored, or the source stream could
397 	 *             not be read.
398 	 */
399 	public abstract ObjectId insert(int objectType, long length, InputStream in)
400 			throws IOException;
401 
402 	/**
403 	 * Initialize a parser to read from a pack formatted stream.
404 	 *
405 	 * @param in
406 	 *            the input stream. The stream is not closed by the parser, and
407 	 *            must instead be closed by the caller once parsing is complete.
408 	 * @return the pack parser.
409 	 * @throws IOException
410 	 *             the parser instance, which can be configured and then used to
411 	 *             parse objects into the ObjectDatabase.
412 	 */
413 	public abstract PackParser newPackParser(InputStream in) throws IOException;
414 
415 	/**
416 	 * Open a reader for objects that may have been written by this inserter.
417 	 * <p>
418 	 * The returned reader allows the calling thread to read back recently
419 	 * inserted objects without first calling {@code flush()} to make them
420 	 * visible to the repository. The returned reader should only be used from
421 	 * the same thread as the inserter. Objects written by this inserter may not
422 	 * be visible to {@code this.newReader().newReader()}.
423 	 * <p>
424 	 * The returned reader should return this inserter instance from {@link
425 	 * ObjectReader#getCreatedFromInserter()}.
426 	 * <p>
427 	 * Behavior is undefined if an insert method is called on the inserter in the
428 	 * middle of reading from an {@link ObjectStream} opened from this reader. For
429 	 * example, reading the remainder of the object may fail, or newly written
430 	 * data may even be corrupted. Interleaving whole object reads (including
431 	 * streaming reads) with inserts is fine, just not interleaving streaming
432 	 * <em>partial</em> object reads with inserts.
433 	 *
434 	 * @since 3.5
435 	 * @return reader for any object, including an object recently inserted by
436 	 *         this inserter since the last flush.
437 	 */
438 	public abstract ObjectReader newReader();
439 
440 	/**
441 	 * Make all inserted objects visible.
442 	 * <p>
443 	 * The flush may take some period of time to make the objects available to
444 	 * other threads.
445 	 *
446 	 * @throws IOException
447 	 *             the flush could not be completed; objects inserted thus far
448 	 *             are in an indeterminate state.
449 	 */
450 	public abstract void flush() throws IOException;
451 
452 	/**
453 	 * Release any resources used by this inserter.
454 	 * <p>
455 	 * An inserter that has been released can be used again, but may need to be
456 	 * released after the subsequent usage.
457 	 *
458 	 * @since 4.0
459 	 */
460 	@Override
461 	public abstract void close();
462 }