tikhomirov@170: /* tikhomirov@170: * Copyright (c) 2011 TMate Software Ltd tikhomirov@170: * tikhomirov@170: * This program is free software; you can redistribute it and/or modify tikhomirov@170: * it under the terms of the GNU General Public License as published by tikhomirov@170: * the Free Software Foundation; version 2 of the License. tikhomirov@170: * tikhomirov@170: * This program is distributed in the hope that it will be useful, tikhomirov@170: * but WITHOUT ANY WARRANTY; without even the implied warranty of tikhomirov@170: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the tikhomirov@170: * GNU General Public License for more details. tikhomirov@170: * tikhomirov@170: * For information on how to redistribute this software under tikhomirov@170: * the terms of a license other than GNU General Public License tikhomirov@170: * contact TMate Software at support@hg4j.com tikhomirov@170: */ tikhomirov@170: package org.tmatesoft.hg.repo; tikhomirov@170: tikhomirov@170: import java.io.File; tikhomirov@176: import java.io.IOException; tikhomirov@176: import java.io.InputStream; tikhomirov@176: import java.io.StreamTokenizer; tikhomirov@176: import java.net.MalformedURLException; tikhomirov@171: import java.net.URL; tikhomirov@176: import java.net.URLConnection; tikhomirov@176: import java.security.cert.CertificateException; tikhomirov@176: import java.security.cert.X509Certificate; tikhomirov@176: import java.util.Collection; tikhomirov@171: import java.util.Collections; tikhomirov@176: import java.util.LinkedHashMap; tikhomirov@176: import java.util.LinkedList; tikhomirov@170: import java.util.List; tikhomirov@176: import java.util.Map; tikhomirov@176: import java.util.prefs.BackingStoreException; tikhomirov@176: import java.util.prefs.Preferences; tikhomirov@176: tikhomirov@176: import javax.net.ssl.HttpsURLConnection; tikhomirov@176: import javax.net.ssl.SSLContext; tikhomirov@176: import javax.net.ssl.TrustManager; tikhomirov@176: import javax.net.ssl.X509TrustManager; tikhomirov@170: tikhomirov@170: import org.tmatesoft.hg.core.HgException; tikhomirov@170: import org.tmatesoft.hg.core.Nodeid; tikhomirov@170: tikhomirov@170: /** tikhomirov@170: * WORK IN PROGRESS, DO NOT USE tikhomirov@170: * tikhomirov@170: * @see http://mercurial.selenic.com/wiki/WireProtocol tikhomirov@170: * tikhomirov@170: * @author Artem Tikhomirov tikhomirov@170: * @author TMate Software Ltd. tikhomirov@170: */ tikhomirov@170: public class HgRemoteRepository { tikhomirov@171: tikhomirov@176: private final URL url; tikhomirov@176: private final SSLContext sslContext; tikhomirov@176: private final String authInfo; tikhomirov@176: tikhomirov@176: HgRemoteRepository(URL url) throws HgException { tikhomirov@176: if (url == null) { tikhomirov@176: throw new IllegalArgumentException(); tikhomirov@176: } tikhomirov@176: this.url = url; tikhomirov@176: if ("https".equals(url.getProtocol())) { tikhomirov@176: try { tikhomirov@176: sslContext = SSLContext.getInstance("SSL"); tikhomirov@176: class TrustEveryone implements X509TrustManager { tikhomirov@176: public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { tikhomirov@176: System.out.println("checkClientTrusted " + authType); tikhomirov@176: } tikhomirov@176: public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { tikhomirov@176: System.out.println("checkServerTrusted" + authType); tikhomirov@176: } tikhomirov@176: public X509Certificate[] getAcceptedIssuers() { tikhomirov@176: return new X509Certificate[0]; tikhomirov@176: } tikhomirov@176: }; tikhomirov@176: sslContext.init(null, new TrustManager[] { new TrustEveryone() }, null); tikhomirov@176: } catch (Exception ex) { tikhomirov@176: throw new HgException(ex); tikhomirov@176: } tikhomirov@176: } else { tikhomirov@176: sslContext = null; tikhomirov@176: } tikhomirov@176: if (url.getUserInfo() != null) { tikhomirov@176: String ai = null; tikhomirov@176: try { tikhomirov@176: // Hack to get Base64-encoded credentials tikhomirov@176: Preferences tempNode = Preferences.userRoot().node("xxx"); tikhomirov@176: tempNode.putByteArray("xxx", url.getUserInfo().getBytes()); tikhomirov@176: ai = tempNode.get("xxx", null); tikhomirov@176: tempNode.removeNode(); tikhomirov@176: } catch (BackingStoreException ex) { tikhomirov@176: ex.printStackTrace(); tikhomirov@176: // IGNORE tikhomirov@176: } tikhomirov@176: authInfo = ai; tikhomirov@176: } else { tikhomirov@176: authInfo = null; tikhomirov@176: } tikhomirov@171: } tikhomirov@171: tikhomirov@171: public List heads() { tikhomirov@172: return Collections.singletonList(Nodeid.fromAscii("71ddbf8603e8e09d54ac9c5fe4bb5ae824589f1d")); tikhomirov@172: // return Collections.emptyList(); tikhomirov@171: } tikhomirov@171: tikhomirov@176: public List between(Nodeid tip, Nodeid base) throws HgException { tikhomirov@176: try { tikhomirov@176: LinkedList rv = new LinkedList(); tikhomirov@176: URL u = new URL(url, url.getPath() + "?cmd=between&pairs=" + tip.toString() + '-' + base.toString()); tikhomirov@176: URLConnection c = setupConnection(u.openConnection()); tikhomirov@176: c.connect(); tikhomirov@176: System.out.println("Query:" + u.getQuery()); tikhomirov@176: System.out.println("Response headers:"); tikhomirov@176: final Map> headerFields = c.getHeaderFields(); tikhomirov@176: for (String s : headerFields.keySet()) { tikhomirov@176: System.out.printf("%s: %s\n", s, c.getHeaderField(s)); tikhomirov@176: } tikhomirov@176: InputStream is = c.getInputStream(); tikhomirov@176: StreamTokenizer st = new StreamTokenizer(is); tikhomirov@176: st.ordinaryChars('0', '9'); tikhomirov@176: st.wordChars('0', '9'); tikhomirov@176: while (st.nextToken() != StreamTokenizer.TT_EOF) { tikhomirov@176: System.out.println(st.sval); tikhomirov@176: Nodeid nid = Nodeid.fromAscii(st.sval); tikhomirov@176: rv.addLast(nid); tikhomirov@176: } tikhomirov@176: is.close(); tikhomirov@176: return rv; tikhomirov@176: } catch (MalformedURLException ex) { tikhomirov@176: throw new HgException(ex); tikhomirov@176: } catch (IOException ex) { tikhomirov@176: throw new HgException(ex); tikhomirov@176: } tikhomirov@176: } tikhomirov@176: tikhomirov@176: /** tikhomirov@176: * @param ranges tikhomirov@176: * @return map, where keys are input instances, values are corresponding server reply tikhomirov@176: * @throws HgException tikhomirov@176: */ tikhomirov@176: public Map> between(Collection ranges) throws HgException { tikhomirov@176: // if fact, shall do other way round, this method shall send tikhomirov@176: LinkedHashMap> rv = new LinkedHashMap>(ranges.size() * 4 / 3); tikhomirov@176: for (Range r : ranges) { tikhomirov@176: List between = between(r.end, r.start); tikhomirov@176: rv.put(r, between); tikhomirov@176: } tikhomirov@176: return rv; tikhomirov@171: } tikhomirov@171: tikhomirov@171: public List branches(List nodes) { tikhomirov@171: return Collections.emptyList(); tikhomirov@171: } tikhomirov@170: tikhomirov@170: // WireProtocol wiki: roots = a list of the latest nodes on every service side changeset branch that both the client and server know about. tikhomirov@170: public HgBundle getChanges(List roots) throws HgException { tikhomirov@170: return new HgLookup().loadBundle(new File("/temp/hg/hg-bundle-000000000000-gz.tmp")); tikhomirov@170: } tikhomirov@176: tikhomirov@176: private URLConnection setupConnection(URLConnection urlConnection) { tikhomirov@176: urlConnection.addRequestProperty("User-Agent", "hg4j/0.5.0"); tikhomirov@176: urlConnection.addRequestProperty("Accept", "application/mercurial-0.1"); tikhomirov@176: if (authInfo != null) { tikhomirov@176: urlConnection.addRequestProperty("Authorization", "Basic " + authInfo); tikhomirov@176: } tikhomirov@176: if (sslContext != null) { tikhomirov@176: ((HttpsURLConnection) urlConnection).setSSLSocketFactory(sslContext.getSocketFactory()); tikhomirov@176: } tikhomirov@176: return urlConnection; tikhomirov@176: } tikhomirov@171: tikhomirov@176: public static final class Range { tikhomirov@176: /** tikhomirov@176: * Root of the range, earlier revision tikhomirov@176: */ tikhomirov@176: public final Nodeid start; tikhomirov@176: /** tikhomirov@176: * Head of the range, later revision. tikhomirov@176: */ tikhomirov@176: public final Nodeid end; tikhomirov@176: tikhomirov@176: /** tikhomirov@176: * @param from - root/base revision tikhomirov@176: * @param to - head/tip revision tikhomirov@176: */ tikhomirov@176: public Range(Nodeid from, Nodeid to) { tikhomirov@176: start = from; tikhomirov@176: end = to; tikhomirov@176: } tikhomirov@176: } tikhomirov@171: public static final class RemoteBranch { tikhomirov@171: public final Nodeid head, root, p1, p2; tikhomirov@171: tikhomirov@171: public RemoteBranch(Nodeid h, Nodeid r, Nodeid parent1, Nodeid parent2) { tikhomirov@171: head = h; tikhomirov@171: root = r; tikhomirov@171: p1 = parent1; tikhomirov@171: p2 = parent2; tikhomirov@171: } tikhomirov@171: tikhomirov@171: @Override tikhomirov@171: public boolean equals(Object obj) { tikhomirov@171: if (this == obj) { tikhomirov@171: return true; tikhomirov@171: } tikhomirov@171: if (false == obj instanceof RemoteBranch) { tikhomirov@171: return false; tikhomirov@171: } tikhomirov@171: RemoteBranch o = (RemoteBranch) obj; tikhomirov@171: return head.equals(o.head) && root.equals(o.root) && (p1 == null && o.p1 == null || p1.equals(o.p1)) && (p2 == null && o.p2 == null || p2.equals(o.p2)); tikhomirov@171: } tikhomirov@171: } tikhomirov@170: }