View Javadoc
1   /*
2    * Copyright (C) 2015, Google Inc. and others
3    *
4    * This program and the accompanying materials are made available under the
5    * terms of the Eclipse Distribution License v. 1.0 which is available at
6    * https://www.eclipse.org/org/documents/edl-v10.php.
7    *
8    * SPDX-License-Identifier: BSD-3-Clause
9    */
10  
11  package org.eclipse.jgit.transport;
12  
13  import java.io.IOException;
14  import java.io.PipedInputStream;
15  import java.io.PipedOutputStream;
16  import java.io.UncheckedIOException;
17  
18  import org.eclipse.jgit.errors.TransportException;
19  import org.eclipse.jgit.internal.JGitText;
20  import org.eclipse.jgit.lib.Repository;
21  import org.eclipse.jgit.transport.resolver.ReceivePackFactory;
22  import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
23  import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
24  
25  class InternalPushConnection<C> extends BasePackPushConnection {
26  	private Thread worker;
27  
28  	/**
29  	 * Constructor for InternalPushConnection.
30  	 *
31  	 * @param transport
32  	 *            a {@link org.eclipse.jgit.transport.PackTransport}
33  	 * @param receivePackFactory
34  	 *            a
35  	 *            {@link org.eclipse.jgit.transport.resolver.ReceivePackFactory}
36  	 * @param req
37  	 *            a request
38  	 * @param remote
39  	 *            the {@link org.eclipse.jgit.lib.Repository}
40  	 * @throws org.eclipse.jgit.errors.TransportException
41  	 *             if any.
42  	 */
43  	public InternalPushConnection(PackTransport transport,
44  			final ReceivePackFactory<C> receivePackFactory,
45  			final C req, final Repository remote) throws TransportException {
46  		super(transport);
47  
48  		final PipedInputStream in_r;
49  		final PipedOutputStream in_w;
50  
51  		final PipedInputStream out_r;
52  		final PipedOutputStream out_w;
53  		try {
54  			in_r = new PipedInputStream();
55  			in_w = new PipedOutputStream(in_r);
56  
57  			out_r = new PipedInputStream();
58  			out_w = new PipedOutputStream(out_r);
59  		} catch (IOException err) {
60  			remote.close();
61  			throw new TransportException(uri, JGitText.get().cannotConnectPipes, err);
62  		}
63  
64  		worker = new Thread("JGit-Receive-Pack") { //$NON-NLS-1$
65  			@Override
66  			public void run() {
67  				try {
68  					final ReceivePack rp = receivePackFactory.create(req, remote);
69  					rp.receive(out_r, in_w, System.err);
70  				} catch (ServiceNotEnabledException
71  						| ServiceNotAuthorizedException e) {
72  					// Ignored. Client cannot use this repository.
73  				} catch (IOException e) {
74  					// Since the InternalPushConnection is used in tests, we
75  					// want to avoid hiding exceptions because they can point to
76  					// programming errors on the server side. By rethrowing, the
77  					// default handler will dump it to stderr.
78  					throw new UncheckedIOException(e);
79  				} finally {
80  					try {
81  						out_r.close();
82  					} catch (IOException e2) {
83  						// Ignore close failure, we probably crashed above.
84  					}
85  
86  					try {
87  						in_w.close();
88  					} catch (IOException e2) {
89  						// Ignore close failure, we probably crashed above.
90  					}
91  
92  					remote.close();
93  				}
94  			}
95  		};
96  		worker.start();
97  
98  		init(in_r, out_w);
99  		readAdvertisedRefs();
100 	}
101 
102 	/** {@inheritDoc} */
103 	@Override
104 	public void close() {
105 		super.close();
106 
107 		if (worker != null) {
108 			try {
109 				worker.join();
110 			} catch (InterruptedException ie) {
111 				// Stop waiting and return anyway.
112 			} finally {
113 				worker = null;
114 			}
115 		}
116 	}
117 }