diff src/org/tmatesoft/hg/internal/remote/RemoteConnectorDescriptor.java @ 698:822f3a83ff57

in, out and clone tests pass for ssh repositories. Infrastructure to decouple HgRemoteRepository from specific Connector implementation
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Tue, 06 Aug 2013 21:18:33 +0200
parents
children a483b2b68a2e
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/tmatesoft/hg/internal/remote/RemoteConnectorDescriptor.java	Tue Aug 06 21:18:33 2013 +0200
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2013 TMate Software Ltd
+ *  
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * For information on how to redistribute this software under
+ * the terms of a license other than GNU General Public License
+ * contact TMate Software at support@hg4j.com
+ */
+package org.tmatesoft.hg.internal.remote;
+
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.tmatesoft.hg.core.HgBadArgumentException;
+import org.tmatesoft.hg.core.SessionContext;
+import org.tmatesoft.hg.repo.HgLookup.Authenticator;
+import org.tmatesoft.hg.repo.HgLookup.RemoteDescriptor;
+import org.tmatesoft.hg.repo.HgRemoteRepository;
+import org.tmatesoft.hg.util.Pair;
+
+/**
+ * Connector-aware descriptor of remote repository, i.e. descriptor that uses 
+ * {@link Connector Connectors} to connect to a remote repository.
+ * 
+ * <p>Candidate to become public API, with createConnector() method, so that {@link HgRemoteRepository} 
+ * may accept instances of that interfact directly
+ * 
+ * 
+ * @author Artem Tikhomirov
+ * @author TMate Software Ltd.
+ */
+public class RemoteConnectorDescriptor implements RemoteDescriptor {
+	
+	private Map<String, Pair<ClassLoader, String>> connFactory;
+	private final URI uri;
+
+	public RemoteConnectorDescriptor(Map<String,Pair<ClassLoader, String>> scheme2connectorMap, URI uriRemote) {
+		this(uriRemote);
+		connFactory = scheme2connectorMap;
+	}
+	
+	protected RemoteConnectorDescriptor(URI uriRemote) {
+		uri = uriRemote;
+	}
+
+	public URI getURI() {
+		return uri;
+	}
+
+	public Authenticator getAuth() {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	public Connector createConnector() throws HgBadArgumentException {
+		Pair<ClassLoader, String> connectorToBe = connFactory.get(uri.getScheme());
+		if (connectorToBe == null || connectorToBe.second() == null) {
+			throw new HgBadArgumentException(String.format("Can't instantiate connector for scheme '%s'", uri.getScheme()), null);
+		}
+		try {
+			Class<?> connClass = connectorToBe.first().loadClass(connectorToBe.second());
+			if (!Connector.class.isAssignableFrom(connClass)) {
+				throw new HgBadArgumentException(String.format("Connector %s for scheme '%s' is not a subclass of %s", connectorToBe.second(), uri.getScheme(), Connector.class.getName()), null);
+			}
+			final Object connector = connClass.newInstance();
+			return Connector.class.cast(connector);
+		} catch (ClassNotFoundException ex) {
+			throw new HgBadArgumentException(String.format("Can't instantiate connector %s for scheme '%s'", connectorToBe.second(), uri.getScheme()), ex);
+		} catch (InstantiationException ex) {
+			throw new HgBadArgumentException(String.format("Can't instantiate connector %s for scheme '%s'", connectorToBe.second(), uri.getScheme()), ex);
+		} catch (IllegalAccessException ex) {
+			throw new HgBadArgumentException(String.format("Can't instantiate connector %s for scheme '%s'", connectorToBe.second(), uri.getScheme()), ex);
+		}
+	}
+
+	// I don't see a reason to expose provider of RemoteDescriptors yet
+	// although it might not be the best idea for session context to serve as provider intermediate
+	public static class Provider {
+		private final Map<String, Pair<ClassLoader, String>> knownConnectors = new HashMap<String, Pair<ClassLoader, String>>(5);
+		
+		{
+			final ClassLoader cl = Provider.class.getClassLoader();
+			knownConnectors.put("http", new Pair<ClassLoader, String>(cl, HttpConnector.class.getName()));
+			knownConnectors.put("https", new Pair<ClassLoader, String>(cl, HttpConnector.class.getName()));
+			 // FIXME replace SshConnector.class with fqn string to avoid dependency from the trilead library in runtime
+			knownConnectors.put("ssh", new Pair<ClassLoader, String>(cl, SshConnector.class.getName()));
+		}
+
+		public RemoteDescriptor get(SessionContext ctx, URI uri) {
+			if (knownConnectors.containsKey(uri.getScheme())) {
+				return new RemoteConnectorDescriptor(knownConnectors, uri);
+			}
+			return null;
+		}
+	}
+}