comparison src/org/tmatesoft/hg/repo/HgRemoteRepository.java @ 215:41a778e3fd31

Issue 5: Facilities for progress and cancellation. More specific exceptions. Exceptions from callbacks as RuntimeException
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Tue, 17 May 2011 00:56:54 +0200
parents 6a2481866491
children 9fb50c04f03c
comparison
equal deleted inserted replaced
214:4252faa556cd 215:41a778e3fd31
46 import javax.net.ssl.TrustManager; 46 import javax.net.ssl.TrustManager;
47 import javax.net.ssl.X509TrustManager; 47 import javax.net.ssl.X509TrustManager;
48 48
49 import org.tmatesoft.hg.core.HgBadArgumentException; 49 import org.tmatesoft.hg.core.HgBadArgumentException;
50 import org.tmatesoft.hg.core.HgBadStateException; 50 import org.tmatesoft.hg.core.HgBadStateException;
51 import org.tmatesoft.hg.core.HgException; 51 import org.tmatesoft.hg.core.HgRemoteConnectionException;
52 import org.tmatesoft.hg.core.Nodeid; 52 import org.tmatesoft.hg.core.Nodeid;
53 53
54 /** 54 /**
55 * WORK IN PROGRESS, DO NOT USE 55 * WORK IN PROGRESS, DO NOT USE
56 * 56 *
113 } else { 113 } else {
114 authInfo = null; 114 authInfo = null;
115 } 115 }
116 } 116 }
117 117
118 public boolean isInvalid() throws HgException { 118 public boolean isInvalid() throws HgRemoteConnectionException {
119 // say hello to server, check response 119 // say hello to server, check response
120 if (Boolean.FALSE.booleanValue()) { 120 if (Boolean.FALSE.booleanValue()) {
121 throw HgRepository.notImplemented(); 121 throw HgRepository.notImplemented();
122 } 122 }
123 return false; // FIXME 123 return false; // FIXME
135 } else { 135 } else {
136 return String.format("%s://%s%s", url.getProtocol(), url.getHost(), url.getPath()); 136 return String.format("%s://%s%s", url.getProtocol(), url.getHost(), url.getPath());
137 } 137 }
138 } 138 }
139 139
140 public List<Nodeid> heads() throws HgException { 140 public List<Nodeid> heads() throws HgRemoteConnectionException {
141 try { 141 try {
142 URL u = new URL(url, url.getPath() + "?cmd=heads"); 142 URL u = new URL(url, url.getPath() + "?cmd=heads");
143 HttpURLConnection c = setupConnection(u.openConnection()); 143 HttpURLConnection c = setupConnection(u.openConnection());
144 c.connect(); 144 c.connect();
145 if (debug) { 145 if (debug) {
154 while (st.nextToken() != StreamTokenizer.TT_EOF) { 154 while (st.nextToken() != StreamTokenizer.TT_EOF) {
155 parseResult.add(Nodeid.fromAscii(st.sval)); 155 parseResult.add(Nodeid.fromAscii(st.sval));
156 } 156 }
157 return parseResult; 157 return parseResult;
158 } catch (MalformedURLException ex) { 158 } catch (MalformedURLException ex) {
159 throw new HgException(ex); 159 throw new HgRemoteConnectionException("Bad URL", ex).setRemoteCommand("heads").setServerInfo(getLocation());
160 } catch (IOException ex) { 160 } catch (IOException ex) {
161 throw new HgException(ex); 161 throw new HgRemoteConnectionException("Communication failure", ex).setRemoteCommand("heads").setServerInfo(getLocation());
162 } 162 }
163 } 163 }
164 164
165 public List<Nodeid> between(Nodeid tip, Nodeid base) throws HgException { 165 public List<Nodeid> between(Nodeid tip, Nodeid base) throws HgRemoteConnectionException {
166 Range r = new Range(base, tip); 166 Range r = new Range(base, tip);
167 // XXX shall handle errors like no range key in the returned map, not sure how. 167 // XXX shall handle errors like no range key in the returned map, not sure how.
168 return between(Collections.singletonList(r)).get(r); 168 return between(Collections.singletonList(r)).get(r);
169 } 169 }
170 170
171 /** 171 /**
172 * @param ranges 172 * @param ranges
173 * @return map, where keys are input instances, values are corresponding server reply 173 * @return map, where keys are input instances, values are corresponding server reply
174 * @throws HgException 174 * @throws HgRemoteConnectionException
175 */ 175 */
176 public Map<Range, List<Nodeid>> between(Collection<Range> ranges) throws HgException { 176 public Map<Range, List<Nodeid>> between(Collection<Range> ranges) throws HgRemoteConnectionException {
177 if (ranges.isEmpty()) { 177 if (ranges.isEmpty()) {
178 return Collections.emptyMap(); 178 return Collections.emptyMap();
179 } 179 }
180 // if fact, shall do other way round, this method shall send 180 // if fact, shall do other way round, this method shall send
181 LinkedHashMap<Range, List<Nodeid>> rv = new LinkedHashMap<HgRemoteRepository.Range, List<Nodeid>>(ranges.size() * 4 / 3); 181 LinkedHashMap<Range, List<Nodeid>> rv = new LinkedHashMap<HgRemoteRepository.Range, List<Nodeid>>(ranges.size() * 4 / 3);
255 } 255 }
256 } 256 }
257 is.close(); 257 is.close();
258 return rv; 258 return rv;
259 } catch (MalformedURLException ex) { 259 } catch (MalformedURLException ex) {
260 throw new HgException(ex); 260 throw new HgRemoteConnectionException("Bad URL", ex).setRemoteCommand("between").setServerInfo(getLocation());
261 } catch (IOException ex) { 261 } catch (IOException ex) {
262 throw new HgException(ex); 262 throw new HgRemoteConnectionException("Communication failure", ex).setRemoteCommand("between").setServerInfo(getLocation());
263 } 263 }
264 } 264 }
265 265
266 public List<RemoteBranch> branches(List<Nodeid> nodes) throws HgException { 266 public List<RemoteBranch> branches(List<Nodeid> nodes) throws HgRemoteConnectionException {
267 StringBuilder sb = new StringBuilder(20 + nodes.size() * 41); 267 StringBuilder sb = new StringBuilder(20 + nodes.size() * 41);
268 sb.append("nodes="); 268 sb.append("nodes=");
269 for (Nodeid n : nodes) { 269 for (Nodeid n : nodes) {
270 sb.append(n.toString()); 270 sb.append(n.toString());
271 sb.append('+'); 271 sb.append('+');
289 ArrayList<Nodeid> parseResult = new ArrayList<Nodeid>(nodes.size() * 4); 289 ArrayList<Nodeid> parseResult = new ArrayList<Nodeid>(nodes.size() * 4);
290 while (st.nextToken() != StreamTokenizer.TT_EOF) { 290 while (st.nextToken() != StreamTokenizer.TT_EOF) {
291 parseResult.add(Nodeid.fromAscii(st.sval)); 291 parseResult.add(Nodeid.fromAscii(st.sval));
292 } 292 }
293 if (parseResult.size() != nodes.size() * 4) { 293 if (parseResult.size() != nodes.size() * 4) {
294 throw new HgException(String.format("Bad number of nodeids in result (shall be factor 4), expected %d, got %d", nodes.size()*4, parseResult.size())); 294 throw new HgRemoteConnectionException(String.format("Bad number of nodeids in result (shall be factor 4), expected %d, got %d", nodes.size()*4, parseResult.size()));
295 } 295 }
296 ArrayList<RemoteBranch> rv = new ArrayList<RemoteBranch>(nodes.size()); 296 ArrayList<RemoteBranch> rv = new ArrayList<RemoteBranch>(nodes.size());
297 for (int i = 0; i < nodes.size(); i++) { 297 for (int i = 0; i < nodes.size(); i++) {
298 RemoteBranch rb = new RemoteBranch(parseResult.get(i*4), parseResult.get(i*4 + 1), parseResult.get(i*4 + 2), parseResult.get(i*4 + 3)); 298 RemoteBranch rb = new RemoteBranch(parseResult.get(i*4), parseResult.get(i*4 + 1), parseResult.get(i*4 + 2), parseResult.get(i*4 + 3));
299 rv.add(rb); 299 rv.add(rb);
300 } 300 }
301 return rv; 301 return rv;
302 } catch (MalformedURLException ex) { 302 } catch (MalformedURLException ex) {
303 throw new HgException(ex); 303 throw new HgRemoteConnectionException("Bad URL", ex).setRemoteCommand("branches").setServerInfo(getLocation());
304 } catch (IOException ex) { 304 } catch (IOException ex) {
305 throw new HgException(ex); 305 throw new HgRemoteConnectionException("Communication failure", ex).setRemoteCommand("branches").setServerInfo(getLocation());
306 } 306 }
307 } 307 }
308 308
309 /* 309 /*
310 * XXX need to describe behavior when roots arg is empty; our RepositoryComparator code currently returns empty lists when 310 * XXX need to describe behavior when roots arg is empty; our RepositoryComparator code currently returns empty lists when
320 * 320 *
321 * according to latter, bundleformat data is sent through zlib 321 * according to latter, bundleformat data is sent through zlib
322 * (there's no header like HG10?? with the server output, though, 322 * (there's no header like HG10?? with the server output, though,
323 * as one may expect according to http://mercurial.selenic.com/wiki/BundleFormat) 323 * as one may expect according to http://mercurial.selenic.com/wiki/BundleFormat)
324 */ 324 */
325 public HgBundle getChanges(List<Nodeid> roots) throws HgException { 325 public HgBundle getChanges(List<Nodeid> roots) throws HgRemoteConnectionException {
326 List<Nodeid> _roots = roots.isEmpty() ? Collections.singletonList(Nodeid.NULL) : roots; 326 List<Nodeid> _roots = roots.isEmpty() ? Collections.singletonList(Nodeid.NULL) : roots;
327 StringBuilder sb = new StringBuilder(20 + _roots.size() * 41); 327 StringBuilder sb = new StringBuilder(20 + _roots.size() * 41);
328 sb.append("roots="); 328 sb.append("roots=");
329 for (Nodeid n : _roots) { 329 for (Nodeid n : _roots) {
330 sb.append(n.toString()); 330 sb.append(n.toString());
344 File tf = writeBundle(c.getInputStream(), false, "HG10GZ" /*didn't see any other that zip*/); 344 File tf = writeBundle(c.getInputStream(), false, "HG10GZ" /*didn't see any other that zip*/);
345 if (debug) { 345 if (debug) {
346 System.out.printf("Wrote bundle %s for roots %s\n", tf, sb); 346 System.out.printf("Wrote bundle %s for roots %s\n", tf, sb);
347 } 347 }
348 return getLookupHelper().loadBundle(tf); 348 return getLookupHelper().loadBundle(tf);
349 } catch (MalformedURLException ex) { 349 } catch (MalformedURLException ex) { // XXX in fact, this exception might be better to be re-thrown as RuntimeEx,
350 throw new HgException(ex); 350 // as there's little user can do about this issue (URLs are constructed by our code)
351 throw new HgRemoteConnectionException("Bad URL", ex).setRemoteCommand("changegroup").setServerInfo(getLocation());
351 } catch (IOException ex) { 352 } catch (IOException ex) {
352 throw new HgException(ex); 353 throw new HgRemoteConnectionException("Communication failure", ex).setRemoteCommand("changegroup").setServerInfo(getLocation());
353 } 354 }
354 } 355 }
355 356
356 @Override 357 @Override
357 public String toString() { 358 public String toString() {