{"thread":{"id":"18917","subject":"[JGIT PATCH (resending) 1/3] Changed Transport class hierarchy basing on underlying transport","startedAt":"2009-04-17T15:25:26Z","lastAt":"2009-04-17T15:25:26Z","messageCount":1,"participants":["Constantine Plotnikov"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"111496","messageId":"85647ef50904170825u1bee4d03sdf64e0134adbc4b8@mail.gmail.com","threadId":"18917","inReplyTo":null,"subject":"[JGIT PATCH (resending) 1/3] Changed Transport class hierarchy basing on underlying transport","fromName":"Constantine Plotnikov","fromEmail":"constantine.plotnikov@gmail.com","sentAt":"2009-04-17T15:25:26Z","receivedAt":"2009-04-17T15:25:26Z","isPatch":true,"sender":{"key":"constantine.plotnikov@gmail.com","avatar":null},"body":"Instead of WalkTransport and PackTransport the transports\nare now using SshTransport, TcpTransport, and HttpTransport,\nindicating the type of basic underlying protocol is dealt\nwith. This lays groundwork for supplying transport specific\nproperties in the future. The WalkTransport and PackTransport\nare now marker interfaces.\n\nSigned-off-by: Constantine Plotnikov <constantine.plotnikov@gmail.com>\n---\nResending the patch as is through git imap-send\n\n .../spearce/jgit/transport/BasePackConnection.java |    8 +-\n .../jgit/transport/BasePackFetchConnection.java    |    4 +-\n .../jgit/transport/BasePackPushConnection.java     |    4 +-\n .../jgit/transport/BundleFetchConnection.java      |  247 ++++++++++++++++++++\n .../org/spearce/jgit/transport/HttpTransport.java  |   62 +++++\n .../org/spearce/jgit/transport/PackTransport.java  |   12 +-\n .../org/spearce/jgit/transport/SshTransport.java   |   62 +++++\n .../org/spearce/jgit/transport/TcpTransport.java   |   62 +++++\n .../spearce/jgit/transport/TransportAmazonS3.java  |    2 +-\n .../spearce/jgit/transport/TransportBundle.java    |  227 +-----------------\n .../jgit/transport/TransportBundleFile.java        |   16 ++-\n .../jgit/transport/TransportBundleStream.java      |   11 +-\n .../spearce/jgit/transport/TransportGitAnon.java   |    2 +-\n .../spearce/jgit/transport/TransportGitSsh.java    |    2 +-\n .../org/spearce/jgit/transport/TransportHttp.java  |    9 +-\n .../org/spearce/jgit/transport/TransportLocal.java |    2 +-\n .../org/spearce/jgit/transport/TransportSftp.java  |    2 +-\n .../jgit/transport/WalkFetchConnection.java        |    3 +-\n .../spearce/jgit/transport/WalkPushConnection.java |    5 +-\n .../org/spearce/jgit/transport/WalkTransport.java  |   21 +--\n 20 files changed, 497 insertions(+), 266 deletions(-)\n create mode 100644\norg.spearce.jgit/src/org/spearce/jgit/transport/BundleFetchConnection.java\n create mode 100644\norg.spearce.jgit/src/org/spearce/jgit/transport/HttpTransport.java\n create mode 100644\norg.spearce.jgit/src/org/spearce/jgit/transport/SshTransport.java\n create mode 100644\norg.spearce.jgit/src/org/spearce/jgit/transport/TcpTransport.java\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackConnection.java\nb/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackConnection.java\nindex c9232ce..c6440c7 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackConnection.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackConnection.java\n@@ -73,7 +73,7 @@\n \tprotected final URIish uri;\n\n \t/** A transport connected to {@link #uri}. */\n-\tprotected final PackTransport transport;\n+\tprotected final Transport transport;\n\n \t/** Buffered input stream reading from the remote. */\n \tprotected InputStream in;\n@@ -97,9 +97,9 @@\n \tprotected final Set<ObjectId> additionalHaves = new HashSet<ObjectId>();\n\n \tBasePackConnection(final PackTransport packTransport) {\n-\t\tlocal = packTransport.local;\n-\t\turi = packTransport.uri;\n-\t\ttransport = packTransport;\n+\t\ttransport = (Transport)packTransport;\n+\t\tlocal = transport.local;\n+\t\turi = transport.uri;\n \t}\n\n \tprotected void init(final InputStream myIn, final OutputStream myOut) {\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackFetchConnection.java\nb/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackFetchConnection.java\nindex 19ac161..b75e0ef 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackFetchConnection.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackFetchConnection.java\n@@ -128,8 +128,8 @@\n\n \tBasePackFetchConnection(final PackTransport packTransport) {\n \t\tsuper(packTransport);\n-\t\tincludeTags = packTransport.getTagOpt() != TagOpt.NO_TAGS;\n-\t\tthinPack = packTransport.isFetchThin();\n+\t\tincludeTags = transport.getTagOpt() != TagOpt.NO_TAGS;\n+\t\tthinPack = transport.isFetchThin();\n\n \t\twalk = new RevWalk(local);\n \t\treachableCommits = new RevCommitList<RevCommit>();\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackPushConnection.java\nb/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackPushConnection.java\nindex dde1d26..07e8cb9 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackPushConnection.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackPushConnection.java\n@@ -88,8 +88,8 @@\n\n \tprivate boolean writePack;\n\n-\tBasePackPushConnection(final PackTransport transport) {\n-\t\tsuper(transport);\n+\tBasePackPushConnection(final PackTransport packTransport) {\n+\t\tsuper(packTransport);\n \t\tthinPack = transport.isPushThin();\n \t}\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/BundleFetchConnection.java\nb/org.spearce.jgit/src/org/spearce/jgit/transport/BundleFetchConnection.java\nnew file mode 100644\nindex 0000000..7ab6c6d\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/BundleFetchConnection.java\n@@ -0,0 +1,247 @@\n+/*\n+ * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>\n+ * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>\n+ * Copyright (C) 2008, Google Inc.\n+ *\n+ * All rights reserved.\n+ *\n+ * Redistribution and use in source and binary forms, with or\n+ * without modification, are permitted provided that the following\n+ * conditions are met:\n+ *\n+ * - Redistributions of source code must retain the above copyright\n+ *   notice, this list of conditions and the following disclaimer.\n+ *\n+ * - Redistributions in binary form must reproduce the above\n+ *   copyright notice, this list of conditions and the following\n+ *   disclaimer in the documentation and/or other materials provided\n+ *   with the distribution.\n+ *\n+ * - Neither the name of the Git Development Community nor the\n+ *   names of its contributors may be used to endorse or promote\n+ *   products derived from this software without specific prior\n+ *   written permission.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n+ * CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+package org.spearce.jgit.transport;\n+\n+import java.io.BufferedInputStream;\n+import java.io.IOException;\n+import java.io.InputStream;\n+import java.util.ArrayList;\n+import java.util.Collection;\n+import java.util.HashSet;\n+import java.util.LinkedHashMap;\n+import java.util.List;\n+import java.util.Set;\n+\n+import org.spearce.jgit.errors.MissingBundlePrerequisiteException;\n+import org.spearce.jgit.errors.MissingObjectException;\n+import org.spearce.jgit.errors.PackProtocolException;\n+import org.spearce.jgit.errors.TransportException;\n+import org.spearce.jgit.lib.Constants;\n+import org.spearce.jgit.lib.ObjectId;\n+import org.spearce.jgit.lib.ProgressMonitor;\n+import org.spearce.jgit.lib.Ref;\n+import org.spearce.jgit.revwalk.RevCommit;\n+import org.spearce.jgit.revwalk.RevFlag;\n+import org.spearce.jgit.revwalk.RevObject;\n+import org.spearce.jgit.revwalk.RevWalk;\n+import org.spearce.jgit.util.RawParseUtils;\n+\n+/**\n+ * Fetch connection for bundle based classes. It used by\n+ * instances of {@link TransportBundle}\n+ */\n+class BundleFetchConnection extends BaseFetchConnection {\n+\n+\tprivate final Transport transport;\n+\n+\tInputStream bin;\n+\n+\tfinal Set<ObjectId> prereqs = new HashSet<ObjectId>();\n+\n+\tBundleFetchConnection(Transport transportBundle, final InputStream\nsrc) throws TransportException {\n+\t\ttransport = transportBundle;\n+\t\tbin = new BufferedInputStream(src, IndexPack.BUFFER_SIZE);\n+\t\ttry {\n+\t\t\tswitch (readSignature()) {\n+\t\t\tcase 2:\n+\t\t\t\treadBundleV2();\n+\t\t\t\tbreak;\n+\t\t\tdefault:\n+\t\t\t\tthrow new TransportException(transport.uri, \"not a bundle\");\n+\t\t\t}\n+\t\t} catch (TransportException err) {\n+\t\t\tclose();\n+\t\t\tthrow err;\n+\t\t} catch (IOException err) {\n+\t\t\tclose();\n+\t\t\tthrow new TransportException(transport.uri, err.getMessage(), err);\n+\t\t} catch (RuntimeException err) {\n+\t\t\tclose();\n+\t\t\tthrow new TransportException(transport.uri, err.getMessage(), err);\n+\t\t}\n+\t}\n+\n+\tprivate int readSignature() throws IOException {\n+\t\tfinal String rev = readLine(new byte[1024]);\n+\t\tif (TransportBundle.V2_BUNDLE_SIGNATURE.equals(rev))\n+\t\t\treturn 2;\n+\t\tthrow new TransportException(transport.uri, \"not a bundle\");\n+\t}\n+\n+\tprivate void readBundleV2() throws IOException {\n+\t\tfinal byte[] hdrbuf = new byte[1024];\n+\t\tfinal LinkedHashMap<String, Ref> avail = new LinkedHashMap<String, Ref>();\n+\t\tfor (;;) {\n+\t\t\tString line = readLine(hdrbuf);\n+\t\t\tif (line.length() == 0)\n+\t\t\t\tbreak;\n+\n+\t\t\tif (line.charAt(0) == '-') {\n+\t\t\t\tprereqs.add(ObjectId.fromString(line.substring(1, 41)));\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\n+\t\t\tfinal String name = line.substring(41, line.length());\n+\t\t\tfinal ObjectId id = ObjectId.fromString(line.substring(0, 40));\n+\t\t\tfinal Ref prior = avail.put(name, new Ref(Ref.Storage.NETWORK,\n+\t\t\t\t\tname, id));\n+\t\t\tif (prior != null)\n+\t\t\t\tthrow duplicateAdvertisement(name);\n+\t\t}\n+\t\tavailable(avail);\n+\t}\n+\n+\tprivate PackProtocolException duplicateAdvertisement(final String name) {\n+\t\treturn new PackProtocolException(transport.uri,\n+\t\t\t\t\"duplicate advertisements of \" + name);\n+\t}\n+\n+\tprivate String readLine(final byte[] hdrbuf) throws IOException {\n+\t\tbin.mark(hdrbuf.length);\n+\t\tfinal int cnt = bin.read(hdrbuf);\n+\t\tint lf = 0;\n+\t\twhile (lf < cnt && hdrbuf[lf] != '\\n')\n+\t\t\tlf++;\n+\t\tbin.reset();\n+\t\tbin.skip(lf);\n+\t\tif (lf < cnt && hdrbuf[lf] == '\\n')\n+\t\t\tbin.skip(1);\n+\t\treturn RawParseUtils.decode(Constants.CHARSET, hdrbuf, 0, lf);\n+\t}\n+\n+\tpublic boolean didFetchTestConnectivity() {\n+\t\treturn false;\n+\t}\n+\n+\t@Override\n+\tprotected void doFetch(final ProgressMonitor monitor,\n+\t\t\tfinal Collection<Ref> want, final Set<ObjectId> have)\n+\t\t\tthrows TransportException {\n+\t\tverifyPrerequisites();\n+\t\ttry {\n+\t\t\tfinal IndexPack ip = newIndexPack();\n+\t\t\tip.index(monitor);\n+\t\t\tip.renameAndOpenPack();\n+\t\t} catch (IOException err) {\n+\t\t\tclose();\n+\t\t\tthrow new TransportException(transport.uri, err.getMessage(), err);\n+\t\t} catch (RuntimeException err) {\n+\t\t\tclose();\n+\t\t\tthrow new TransportException(transport.uri, err.getMessage(), err);\n+\t\t}\n+\t}\n+\n+\tprivate IndexPack newIndexPack() throws IOException {\n+\t\tfinal IndexPack ip = IndexPack.create(transport.local, bin);\n+\t\tip.setFixThin(true);\n+\t\tip.setObjectChecking(transport.isCheckFetchedObjects());\n+\t\treturn ip;\n+\t}\n+\n+\tprivate void verifyPrerequisites() throws TransportException {\n+\t\tif (prereqs.isEmpty())\n+\t\t\treturn;\n+\n+\t\tfinal RevWalk rw = new RevWalk(transport.local);\n+\t\tfinal RevFlag PREREQ = rw.newFlag(\"PREREQ\");\n+\t\tfinal RevFlag SEEN = rw.newFlag(\"SEEN\");\n+\n+\t\tfinal List<ObjectId> missing = new ArrayList<ObjectId>();\n+\t\tfinal List<RevObject> commits = new ArrayList<RevObject>();\n+\t\tfor (final ObjectId p : prereqs) {\n+\t\t\ttry {\n+\t\t\t\tfinal RevCommit c = rw.parseCommit(p);\n+\t\t\t\tif (!c.has(PREREQ)) {\n+\t\t\t\t\tc.add(PREREQ);\n+\t\t\t\t\tcommits.add(c);\n+\t\t\t\t}\n+\t\t\t} catch (MissingObjectException notFound) {\n+\t\t\t\tmissing.add(p);\n+\t\t\t} catch (IOException err) {\n+\t\t\t\tthrow new TransportException(transport.uri, \"Cannot read commit \"\n+\t\t\t\t\t\t+ p.name(), err);\n+\t\t\t}\n+\t\t}\n+\t\tif (!missing.isEmpty())\n+\t\t\tthrow new MissingBundlePrerequisiteException(transport.uri, missing);\n+\n+\t\tfor (final Ref r : transport.local.getAllRefs().values()) {\n+\t\t\ttry {\n+\t\t\t\trw.markStart(rw.parseCommit(r.getObjectId()));\n+\t\t\t} catch (IOException readError) {\n+\t\t\t\t// If we cannot read the value of the ref skip it.\n+\t\t\t}\n+\t\t}\n+\n+\t\tint remaining = commits.size();\n+\t\ttry {\n+\t\t\tRevCommit c;\n+\t\t\twhile ((c = rw.next()) != null) {\n+\t\t\t\tif (c.has(PREREQ)) {\n+\t\t\t\t\tc.add(SEEN);\n+\t\t\t\t\tif (--remaining == 0)\n+\t\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t} catch (IOException err) {\n+\t\t\tthrow new TransportException(transport.uri, \"Cannot read object\", err);\n+\t\t}\n+\n+\t\tif (remaining > 0) {\n+\t\t\tfor (final RevObject o : commits) {\n+\t\t\t\tif (!o.has(SEEN))\n+\t\t\t\t\tmissing.add(o);\n+\t\t\t}\n+\t\t\tthrow new MissingBundlePrerequisiteException(transport.uri, missing);\n+\t\t}\n+\t}\n+\n+\t@Override\n+\tpublic void close() {\n+\t\tif (bin != null) {\n+\t\t\ttry {\n+\t\t\t\tbin.close();\n+\t\t\t} catch (IOException ie) {\n+\t\t\t\t// Ignore close failures.\n+\t\t\t} finally {\n+\t\t\t\tbin = null;\n+\t\t\t}\n+\t\t}\n+\t}\n+}\n\\ No newline at end of file\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/HttpTransport.java\nb/org.spearce.jgit/src/org/spearce/jgit/transport/HttpTransport.java\nnew file mode 100644\nindex 0000000..5c60094\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/HttpTransport.java\n@@ -0,0 +1,62 @@\n+/*\n+ * Copyright (C) 2009, Shawn O. Pearce <spearce@spearce.org>\n+ * Copyright (C) 2009, JetBrains s.r.o.\n+ *\n+ * All rights reserved.\n+ *\n+ * Redistribution and use in source and binary forms, with or\n+ * without modification, are permitted provided that the following\n+ * conditions are met:\n+ *\n+ * - Redistributions of source code must retain the above copyright\n+ *   notice, this list of conditions and the following disclaimer.\n+ *\n+ * - Redistributions in binary form must reproduce the above\n+ *   copyright notice, this list of conditions and the following\n+ *   disclaimer in the documentation and/or other materials provided\n+ *   with the distribution.\n+ *\n+ * - Neither the name of the Git Development Community nor the\n+ *   names of its contributors may be used to endorse or promote\n+ *   products derived from this software without specific prior\n+ *   written permission.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n+ * CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+package org.spearce.jgit.transport;\n+\n+import org.spearce.jgit.lib.Repository;\n+\n+/**\n+ * The base class for transports that use HTTP as underlying\nprotocol. This class\n+ * allows customizing HTTP connection settings.\n+ */\n+public abstract class HttpTransport extends Transport {\n+\n+\t/**\n+\t * Create a new transport instance.\n+\t *\n+\t * @param local\n+\t *            the repository this instance will fetch into, or push out of.\n+\t *            This must be the repository passed to\n+\t *            {@link #open(Repository, URIish)}.\n+\t * @param uri\n+\t *            the URI used to access the remote repository. This must be the\n+\t *            URI passed to {@link #open(Repository, URIish)}.\n+\t */\n+\tpublic HttpTransport(Repository local, URIish uri) {\n+\t\tsuper(local, uri);\n+\t}\n+}\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/PackTransport.java\nb/org.spearce.jgit/src/org/spearce/jgit/transport/PackTransport.java\nindex 50708d3..522022e 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/PackTransport.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/PackTransport.java\n@@ -1,5 +1,6 @@\n /*\n  * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>\n+ * Copyright (C) 2009, JetBrains s.r.o.\n  *\n  * All rights reserved.\n  *\n@@ -34,13 +35,10 @@\n  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n  */\n-\n package org.spearce.jgit.transport;\n\n-import org.spearce.jgit.lib.Repository;\n-\n /**\n- * Canonical implementation of an object transport using Git pack transfers.\n+ * Marker interface an object transport using Git pack transfers.\n  * <p>\n  * Implementations of PackTransport setup connections and move objects back and\n  * forth by creating pack files on the source side and indexing them on the\n@@ -49,8 +47,6 @@\n  * @see BasePackFetchConnection\n  * @see BasePackPushConnection\n  */\n-abstract class PackTransport extends Transport {\n-\tPackTransport(final Repository local, final URIish u) {\n-\t\tsuper(local, u);\n-\t}\n+public interface PackTransport {\n+\t// no methods in marker interface\n }\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/SshTransport.java\nb/org.spearce.jgit/src/org/spearce/jgit/transport/SshTransport.java\nnew file mode 100644\nindex 0000000..4532590\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/SshTransport.java\n@@ -0,0 +1,62 @@\n+/*\n+ * Copyright (C) 2009, Shawn O. Pearce <spearce@spearce.org>\n+ * Copyright (C) 2009, JetBrains s.r.o.\n+ *\n+ * All rights reserved.\n+ *\n+ * Redistribution and use in source and binary forms, with or\n+ * without modification, are permitted provided that the following\n+ * conditions are met:\n+ *\n+ * - Redistributions of source code must retain the above copyright\n+ *   notice, this list of conditions and the following disclaimer.\n+ *\n+ * - Redistributions in binary form must reproduce the above\n+ *   copyright notice, this list of conditions and the following\n+ *   disclaimer in the documentation and/or other materials provided\n+ *   with the distribution.\n+ *\n+ * - Neither the name of the Git Development Community nor the\n+ *   names of its contributors may be used to endorse or promote\n+ *   products derived from this software without specific prior\n+ *   written permission.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n+ * CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+package org.spearce.jgit.transport;\n+\n+import org.spearce.jgit.lib.Repository;\n+\n+/**\n+ * The base class for transports that use SSH protocol. This class\n+ * allows customizing SSH connection settings.\n+ */\n+public abstract class SshTransport extends TcpTransport {\n+\n+\t/**\n+\t * Create a new transport instance.\n+\t *\n+\t * @param local\n+\t *            the repository this instance will fetch into, or push out of.\n+\t *            This must be the repository passed to\n+\t *            {@link #open(Repository, URIish)}.\n+\t * @param uri\n+\t *            the URI used to access the remote repository. This must be the\n+\t *            URI passed to {@link #open(Repository, URIish)}.\n+\t */\n+\tpublic SshTransport(Repository local, URIish uri) {\n+\t\tsuper(local, uri);\n+\t}\n+}\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TcpTransport.java\nb/org.spearce.jgit/src/org/spearce/jgit/transport/TcpTransport.java\nnew file mode 100644\nindex 0000000..82ef1cc\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TcpTransport.java\n@@ -0,0 +1,62 @@\n+/*\n+ * Copyright (C) 2009, Shawn O. Pearce <spearce@spearce.org>\n+ * Copyright (C) 2009, JetBrains s.r.o.\n+ *\n+ * All rights reserved.\n+ *\n+ * Redistribution and use in source and binary forms, with or\n+ * without modification, are permitted provided that the following\n+ * conditions are met:\n+ *\n+ * - Redistributions of source code must retain the above copyright\n+ *   notice, this list of conditions and the following disclaimer.\n+ *\n+ * - Redistributions in binary form must reproduce the above\n+ *   copyright notice, this list of conditions and the following\n+ *   disclaimer in the documentation and/or other materials provided\n+ *   with the distribution.\n+ *\n+ * - Neither the name of the Git Development Community nor the\n+ *   names of its contributors may be used to endorse or promote\n+ *   products derived from this software without specific prior\n+ *   written permission.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n+ * CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+package org.spearce.jgit.transport;\n+\n+import org.spearce.jgit.lib.Repository;\n+\n+/**\n+ * The base class for transports based on TCP sockets. This class\n+ * holds settings common for all TCP based transports.\n+ */\n+public abstract class TcpTransport extends Transport {\n+\n+\t/**\n+\t * Create a new transport instance.\n+\t *\n+\t * @param local\n+\t *            the repository this instance will fetch into, or push out of.\n+\t *            This must be the repository passed to\n+\t *            {@link #open(Repository, URIish)}.\n+\t * @param uri\n+\t *            the URI used to access the remote repository. This must be the\n+\t *            URI passed to {@link #open(Repository, URIish)}.\n+\t */\n+\tpublic TcpTransport(Repository local, URIish uri) {\n+\t\tsuper(local, uri);\n+\t}\n+}\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportAmazonS3.java\nb/org.spearce.jgit/src/org/spearce/jgit/transport/TransportAmazonS3.java\nindex a9fcdb9..f09060f 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportAmazonS3.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportAmazonS3.java\n@@ -85,7 +85,7 @@\n  * @see WalkFetchConnection\n  * @see WalkPushConnection\n  */\n-class TransportAmazonS3 extends WalkTransport {\n+public class TransportAmazonS3 extends HttpTransport implements WalkTransport {\n \tstatic final String S3_SCHEME = \"amazon-s3\";\n\n \tstatic boolean canHandle(final URIish uri) {\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundle.java\nb/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundle.java\nindex 1734d94..7dca433 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundle.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundle.java\n@@ -39,230 +39,17 @@\n\n package org.spearce.jgit.transport;\n\n-import java.io.BufferedInputStream;\n-import java.io.IOException;\n-import java.io.InputStream;\n-import java.util.ArrayList;\n-import java.util.Collection;\n-import java.util.HashSet;\n-import java.util.LinkedHashMap;\n-import java.util.List;\n-import java.util.Set;\n-\n-import org.spearce.jgit.errors.MissingBundlePrerequisiteException;\n-import org.spearce.jgit.errors.MissingObjectException;\n-import org.spearce.jgit.errors.NotSupportedException;\n-import org.spearce.jgit.errors.PackProtocolException;\n-import org.spearce.jgit.errors.TransportException;\n-import org.spearce.jgit.lib.Constants;\n-import org.spearce.jgit.lib.ObjectId;\n-import org.spearce.jgit.lib.ProgressMonitor;\n-import org.spearce.jgit.lib.Ref;\n-import org.spearce.jgit.lib.Repository;\n-import org.spearce.jgit.revwalk.RevCommit;\n-import org.spearce.jgit.revwalk.RevFlag;\n-import org.spearce.jgit.revwalk.RevObject;\n-import org.spearce.jgit.revwalk.RevWalk;\n-import org.spearce.jgit.util.RawParseUtils;\n-\n /**\n- * Supports fetching from a git bundle (sneaker-net object transport).\n+ * Marker interface for transports that supports fetching from a git bundle\n+ * (sneaker-net object transport).\n  * <p>\n  * Push support for a bundle is complex, as one does not have a peer to\n  * communicate with to decide what the peer already knows. So push is not\n  * supported by the bundle transport.\n  */\n-abstract class TransportBundle extends PackTransport {\n-\tstatic final String V2_BUNDLE_SIGNATURE = \"# v2 git bundle\";\n-\n-\tTransportBundle(final Repository local, final URIish uri) {\n-\t\tsuper(local, uri);\n-\t}\n-\n-\t@Override\n-\tpublic PushConnection openPush() throws NotSupportedException {\n-\t\tthrow new NotSupportedException(\n-\t\t\t\t\"Push is not supported for bundle transport\");\n-\t}\n-\n-\t@Override\n-\tpublic void close() {\n-\t\t// Resources must be established per-connection.\n-\t}\n-\n-\tclass BundleFetchConnection extends BaseFetchConnection {\n-\t\tInputStream bin;\n-\n-\t\tfinal Set<ObjectId> prereqs = new HashSet<ObjectId>();\n-\n-\t\tBundleFetchConnection(final InputStream src) throws TransportException {\n-\t\t\tbin = new BufferedInputStream(src, IndexPack.BUFFER_SIZE);\n-\t\t\ttry {\n-\t\t\t\tswitch (readSignature()) {\n-\t\t\t\tcase 2:\n-\t\t\t\t\treadBundleV2();\n-\t\t\t\t\tbreak;\n-\t\t\t\tdefault:\n-\t\t\t\t\tthrow new TransportException(uri, \"not a bundle\");\n-\t\t\t\t}\n-\t\t\t} catch (TransportException err) {\n-\t\t\t\tclose();\n-\t\t\t\tthrow err;\n-\t\t\t} catch (IOException err) {\n-\t\t\t\tclose();\n-\t\t\t\tthrow new TransportException(uri, err.getMessage(), err);\n-\t\t\t} catch (RuntimeException err) {\n-\t\t\t\tclose();\n-\t\t\t\tthrow new TransportException(uri, err.getMessage(), err);\n-\t\t\t}\n-\t\t}\n-\n-\t\tprivate int readSignature() throws IOException {\n-\t\t\tfinal String rev = readLine(new byte[1024]);\n-\t\t\tif (V2_BUNDLE_SIGNATURE.equals(rev))\n-\t\t\t\treturn 2;\n-\t\t\tthrow new TransportException(uri, \"not a bundle\");\n-\t\t}\n-\n-\t\tprivate void readBundleV2() throws IOException {\n-\t\t\tfinal byte[] hdrbuf = new byte[1024];\n-\t\t\tfinal LinkedHashMap<String, Ref> avail = new LinkedHashMap<String, Ref>();\n-\t\t\tfor (;;) {\n-\t\t\t\tString line = readLine(hdrbuf);\n-\t\t\t\tif (line.length() == 0)\n-\t\t\t\t\tbreak;\n-\n-\t\t\t\tif (line.charAt(0) == '-') {\n-\t\t\t\t\tprereqs.add(ObjectId.fromString(line.substring(1, 41)));\n-\t\t\t\t\tcontinue;\n-\t\t\t\t}\n-\n-\t\t\t\tfinal String name = line.substring(41, line.length());\n-\t\t\t\tfinal ObjectId id = ObjectId.fromString(line.substring(0, 40));\n-\t\t\t\tfinal Ref prior = avail.put(name, new Ref(Ref.Storage.NETWORK,\n-\t\t\t\t\t\tname, id));\n-\t\t\t\tif (prior != null)\n-\t\t\t\t\tthrow duplicateAdvertisement(name);\n-\t\t\t}\n-\t\t\tavailable(avail);\n-\t\t}\n-\n-\t\tprivate PackProtocolException duplicateAdvertisement(final String name) {\n-\t\t\treturn new PackProtocolException(uri,\n-\t\t\t\t\t\"duplicate advertisements of \" + name);\n-\t\t}\n-\n-\t\tprivate String readLine(final byte[] hdrbuf) throws IOException {\n-\t\t\tbin.mark(hdrbuf.length);\n-\t\t\tfinal int cnt = bin.read(hdrbuf);\n-\t\t\tint lf = 0;\n-\t\t\twhile (lf < cnt && hdrbuf[lf] != '\\n')\n-\t\t\t\tlf++;\n-\t\t\tbin.reset();\n-\t\t\tbin.skip(lf);\n-\t\t\tif (lf < cnt && hdrbuf[lf] == '\\n')\n-\t\t\t\tbin.skip(1);\n-\t\t\treturn RawParseUtils.decode(Constants.CHARSET, hdrbuf, 0, lf);\n-\t\t}\n-\n-\t\tpublic boolean didFetchTestConnectivity() {\n-\t\t\treturn false;\n-\t\t}\n-\n-\t\t@Override\n-\t\tprotected void doFetch(final ProgressMonitor monitor,\n-\t\t\t\tfinal Collection<Ref> want, final Set<ObjectId> have)\n-\t\t\t\tthrows TransportException {\n-\t\t\tverifyPrerequisites();\n-\t\t\ttry {\n-\t\t\t\tfinal IndexPack ip = newIndexPack();\n-\t\t\t\tip.index(monitor);\n-\t\t\t\tip.renameAndOpenPack();\n-\t\t\t} catch (IOException err) {\n-\t\t\t\tclose();\n-\t\t\t\tthrow new TransportException(uri, err.getMessage(), err);\n-\t\t\t} catch (RuntimeException err) {\n-\t\t\t\tclose();\n-\t\t\t\tthrow new TransportException(uri, err.getMessage(), err);\n-\t\t\t}\n-\t\t}\n-\n-\t\tprivate IndexPack newIndexPack() throws IOException {\n-\t\t\tfinal IndexPack ip = IndexPack.create(local, bin);\n-\t\t\tip.setFixThin(true);\n-\t\t\tip.setObjectChecking(TransportBundle.this.isCheckFetchedObjects());\n-\t\t\treturn ip;\n-\t\t}\n-\n-\t\tprivate void verifyPrerequisites() throws TransportException {\n-\t\t\tif (prereqs.isEmpty())\n-\t\t\t\treturn;\n-\n-\t\t\tfinal RevWalk rw = new RevWalk(local);\n-\t\t\tfinal RevFlag PREREQ = rw.newFlag(\"PREREQ\");\n-\t\t\tfinal RevFlag SEEN = rw.newFlag(\"SEEN\");\n-\n-\t\t\tfinal List<ObjectId> missing = new ArrayList<ObjectId>();\n-\t\t\tfinal List<RevObject> commits = new ArrayList<RevObject>();\n-\t\t\tfor (final ObjectId p : prereqs) {\n-\t\t\t\ttry {\n-\t\t\t\t\tfinal RevCommit c = rw.parseCommit(p);\n-\t\t\t\t\tif (!c.has(PREREQ)) {\n-\t\t\t\t\t\tc.add(PREREQ);\n-\t\t\t\t\t\tcommits.add(c);\n-\t\t\t\t\t}\n-\t\t\t\t} catch (MissingObjectException notFound) {\n-\t\t\t\t\tmissing.add(p);\n-\t\t\t\t} catch (IOException err) {\n-\t\t\t\t\tthrow new TransportException(uri, \"Cannot read commit \"\n-\t\t\t\t\t\t\t+ p.name(), err);\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tif (!missing.isEmpty())\n-\t\t\t\tthrow new MissingBundlePrerequisiteException(uri, missing);\n-\n-\t\t\tfor (final Ref r : local.getAllRefs().values()) {\n-\t\t\t\ttry {\n-\t\t\t\t\trw.markStart(rw.parseCommit(r.getObjectId()));\n-\t\t\t\t} catch (IOException readError) {\n-\t\t\t\t\t// If we cannot read the value of the ref skip it.\n-\t\t\t\t}\n-\t\t\t}\n-\n-\t\t\tint remaining = commits.size();\n-\t\t\ttry {\n-\t\t\t\tRevCommit c;\n-\t\t\t\twhile ((c = rw.next()) != null) {\n-\t\t\t\t\tif (c.has(PREREQ)) {\n-\t\t\t\t\t\tc.add(SEEN);\n-\t\t\t\t\t\tif (--remaining == 0)\n-\t\t\t\t\t\t\tbreak;\n-\t\t\t\t\t}\n-\t\t\t\t}\n-\t\t\t} catch (IOException err) {\n-\t\t\t\tthrow new TransportException(uri, \"Cannot read object\", err);\n-\t\t\t}\n-\n-\t\t\tif (remaining > 0) {\n-\t\t\t\tfor (final RevObject o : commits) {\n-\t\t\t\t\tif (!o.has(SEEN))\n-\t\t\t\t\t\tmissing.add(o);\n-\t\t\t\t}\n-\t\t\t\tthrow new MissingBundlePrerequisiteException(uri, missing);\n-\t\t\t}\n-\t\t}\n-\n-\t\t@Override\n-\t\tpublic void close() {\n-\t\t\tif (bin != null) {\n-\t\t\t\ttry {\n-\t\t\t\t\tbin.close();\n-\t\t\t\t} catch (IOException ie) {\n-\t\t\t\t\t// Ignore close failures.\n-\t\t\t\t} finally {\n-\t\t\t\t\tbin = null;\n-\t\t\t\t}\n-\t\t\t}\n-\t\t}\n-\t}\n+public interface TransportBundle extends PackTransport {\n+\t/**\n+\t * Bundle signature\n+\t */\n+\tpublic static final String V2_BUNDLE_SIGNATURE = \"# v2 git bundle\";\n }\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundleFile.java\nb/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundleFile.java\nindex c9ff1b2..91f076d 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundleFile.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundleFile.java\n@@ -47,7 +47,7 @@\n import org.spearce.jgit.lib.Repository;\n import org.spearce.jgit.util.FS;\n\n-class TransportBundleFile extends TransportBundle {\n+class TransportBundleFile extends Transport implements TransportBundle {\n \tstatic boolean canHandle(final URIish uri) {\n \t\tif (uri.getHost() != null || uri.getPort() > 0 || uri.getUser() != null\n \t\t\t\t|| uri.getPass() != null || uri.getPath() == null)\n@@ -77,6 +77,18 @@ public FetchConnection openFetch() throws\nNotSupportedException,\n \t\t} catch (FileNotFoundException err) {\n \t\t\tthrow new TransportException(uri, \"not found\");\n \t\t}\n-\t\treturn new BundleFetchConnection(src);\n+\t\treturn new BundleFetchConnection(this, src);\n \t}\n+\n+\t@Override\n+\tpublic PushConnection openPush() throws NotSupportedException {\n+\t\tthrow new NotSupportedException(\n+\t\t\t\t\"Push is not supported for bundle transport\");\n+\t}\n+\n+\t@Override\n+\tpublic void close() {\n+\t\t// Resources must be established per-connection.\n+\t}\n+\n }\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundleStream.java\nb/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundleStream.java\nindex 611ad3b..71c0723 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundleStream.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundleStream.java\n@@ -40,6 +40,7 @@\n import java.io.IOException;\n import java.io.InputStream;\n\n+import org.spearce.jgit.errors.NotSupportedException;\n import org.spearce.jgit.errors.TransportException;\n import org.spearce.jgit.lib.Repository;\n\n@@ -50,7 +51,7 @@\n  * transport to opening at most one FetchConnection before needing to recreate\n  * the transport instance.\n  */\n-public class TransportBundleStream extends TransportBundle {\n+public class TransportBundleStream extends Transport implements\nTransportBundle {\n \tprivate InputStream src;\n\n \t/**\n@@ -84,13 +85,19 @@ public FetchConnection openFetch() throws\nTransportException {\n \t\tif (src == null)\n \t\t\tthrow new TransportException(uri, \"Only one fetch supported\");\n \t\ttry {\n-\t\t\treturn new BundleFetchConnection(src);\n+\t\t\treturn new BundleFetchConnection(this, src);\n \t\t} finally {\n \t\t\tsrc = null;\n \t\t}\n \t}\n\n \t@Override\n+\tpublic PushConnection openPush() throws NotSupportedException {\n+\t\tthrow new NotSupportedException(\n+\t\t\t\t\"Push is not supported for bundle transport\");\n+\t}\n+\n+\t@Override\n \tpublic void close() {\n \t\tif (src != null) {\n \t\t\ttry {\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitAnon.java\nb/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitAnon.java\nindex a11f293..add7e2a 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitAnon.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitAnon.java\n@@ -55,7 +55,7 @@\n  * the IANA registered port 9418. It is a popular means for distributing open\n  * source projects, as there are no authentication or authorization overheads.\n  */\n-class TransportGitAnon extends PackTransport {\n+class TransportGitAnon extends TcpTransport implements PackTransport {\n \tstatic final int GIT_PORT = Daemon.DEFAULT_PORT;\n\n \tstatic boolean canHandle(final URIish uri) {\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java\nb/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java\nindex d4bf466..1f69ed7 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java\n@@ -64,7 +64,7 @@\n  * assumes there are Git specific smarts on the remote side to perform object\n  * enumeration, save file modification and hook execution.\n  */\n-class TransportGitSsh extends PackTransport {\n+public class TransportGitSsh extends SshTransport implements PackTransport {\n \tstatic boolean canHandle(final URIish uri) {\n \t\tif (!uri.isRemote())\n \t\t\treturn false;\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportHttp.java\nb/org.spearce.jgit/src/org/spearce/jgit/transport/TransportHttp.java\nindex fe4a437..da0dfd9 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportHttp.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportHttp.java\n@@ -69,7 +69,7 @@\n  *\n  * @see WalkFetchConnection\n  */\n-class TransportHttp extends WalkTransport {\n+public class TransportHttp extends HttpTransport implements WalkTransport {\n \tstatic boolean canHandle(final URIish uri) {\n \t\tif (!uri.isRemote())\n \t\t\treturn false;\n@@ -107,6 +107,13 @@ public FetchConnection openFetch() throws\nTransportException {\n \t}\n\n \t@Override\n+\tpublic PushConnection openPush() throws NotSupportedException,\n+\t\t\tTransportException {\n+\t\tfinal String s = getURI().getScheme();\n+\t\tthrow new NotSupportedException(\"Push not supported over \" + s + \".\");\n+\t}\n+\n+\t@Override\n \tpublic void close() {\n \t\t// No explicit connections are maintained.\n \t}\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java\nb/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java\nindex 17d95c2..d5a6c14 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java\n@@ -60,7 +60,7 @@\n  * {@link TransportGitSsh} implementation causes the remote side to run a C Git\n  * process.\n  */\n-class TransportLocal extends PackTransport {\n+class TransportLocal extends Transport implements PackTransport {\n \tprivate static final String PWD = \".\";\n\n \tstatic boolean canHandle(final URIish uri) {\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportSftp.java\nb/org.spearce.jgit/src/org/spearce/jgit/transport/TransportSftp.java\nindex d8b4ff7..50bd564 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportSftp.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportSftp.java\n@@ -87,7 +87,7 @@\n  *\n  * @see WalkFetchConnection\n  */\n-class TransportSftp extends WalkTransport {\n+public class TransportSftp extends SshTransport implements WalkTransport {\n \tstatic boolean canHandle(final URIish uri) {\n \t\treturn uri.isRemote() && \"sftp\".equals(uri.getScheme());\n \t}\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/WalkFetchConnection.java\nb/org.spearce.jgit/src/org/spearce/jgit/transport/WalkFetchConnection.java\nindex 93b5bd2..6912a1f 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/WalkFetchConnection.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/WalkFetchConnection.java\n@@ -167,7 +167,8 @@\n \t */\n \tprivate final HashMap<ObjectId, List<Throwable>> fetchErrors;\n\n-\tWalkFetchConnection(final WalkTransport wt, final\nWalkRemoteObjectDatabase w) {\n+\tWalkFetchConnection(final WalkTransport t, final WalkRemoteObjectDatabase w) {\n+\t\tTransport wt = (Transport)t;\n \t\tlocal = wt.local;\n \t\tobjCheck = wt.isCheckFetchedObjects() ? new ObjectChecker() : null;\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/WalkPushConnection.java\nb/org.spearce.jgit/src/org/spearce/jgit/transport/WalkPushConnection.java\nindex acdb5b8..b9b9ae1 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/WalkPushConnection.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/WalkPushConnection.java\n@@ -114,8 +114,9 @@\n\n \tWalkPushConnection(final WalkTransport walkTransport,\n \t\t\tfinal WalkRemoteObjectDatabase w) {\n-\t\tlocal = walkTransport.local;\n-\t\turi = walkTransport.getURI();\n+\t\tTransport t = (Transport)walkTransport;\n+\t\tlocal = t.local;\n+\t\turi = t.getURI();\n \t\tdest = w;\n \t}\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/WalkTransport.java\nb/org.spearce.jgit/src/org/spearce/jgit/transport/WalkTransport.java\nindex 87949a6..4d54e17 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/WalkTransport.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/WalkTransport.java\n@@ -1,5 +1,6 @@\n /*\n  * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>\n+ * Copyright (C) 2009, JetBrains s.r.o.\n  *\n  * All rights reserved.\n  *\n@@ -34,15 +35,10 @@\n  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n  */\n-\n package org.spearce.jgit.transport;\n\n-import org.spearce.jgit.errors.NotSupportedException;\n-import org.spearce.jgit.errors.TransportException;\n-import org.spearce.jgit.lib.Repository;\n-\n /**\n- * Canonical implementation of an object transport walking transport.\n+ * Marker interface for an object transport walking transport.\n  * <p>\n  * Implementations of WalkTransport transfer individual objects one at a time\n  * from the loose objects directory, or entire packs if the source\nside does not\n@@ -53,15 +49,6 @@\n  *\n  * @see WalkFetchConnection\n  */\n-abstract class WalkTransport extends Transport {\n-\tWalkTransport(final Repository local, final URIish u) {\n-\t\tsuper(local, u);\n-\t}\n-\n-\t@Override\n-\tpublic PushConnection openPush() throws NotSupportedException,\n-\t\t\tTransportException {\n-\t\tfinal String s = getURI().getScheme();\n-\t\tthrow new NotSupportedException(\"Push not supported over \" + s + \".\");\n-\t}\n+public interface WalkTransport {\n+\t// no methods in marker interface\n }\n-- \n1.6.0.2.1172.ga5ed0\n"}]}