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