Mercurial > hg4j
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; + } + } +}