1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43 package org.eclipse.jgit.internal.transport.sshd;
44
45 import static java.text.MessageFormat.format;
46
47 import java.io.IOException;
48 import java.nio.file.Path;
49 import java.security.GeneralSecurityException;
50 import java.security.KeyPair;
51 import java.util.ArrayList;
52 import java.util.Collection;
53 import java.util.Collections;
54 import java.util.Iterator;
55 import java.util.List;
56 import java.util.NoSuchElementException;
57 import java.util.concurrent.CancellationException;
58
59 import org.eclipse.jgit.transport.sshd.KeyCache;
60
61
62
63
64
65 public class CachingKeyPairProvider extends EncryptedFileKeyPairProvider {
66
67 private final KeyCache cache;
68
69
70
71
72
73
74
75
76
77
78
79 public CachingKeyPairProvider(List<Path> paths, KeyCache cache) {
80 super(paths);
81 this.cache = cache;
82 }
83
84 @Override
85 protected Iterable<KeyPair> loadKeys(Collection<? extends Path> resources) {
86 if (resources.isEmpty()) {
87 return Collections.emptyList();
88 }
89 return () -> new CancellingKeyPairIterator(resources);
90 }
91
92 @Override
93 protected KeyPair doLoadKey(Path resource)
94 throws IOException, GeneralSecurityException {
95
96
97
98 String resourceId = resource.toString();
99 if (cache == null) {
100 return doLoadKey(resourceId, resource, getPasswordFinder());
101 }
102 Throwable t[] = { null };
103 KeyPair key = cache.get(resource, p -> {
104 try {
105 return doLoadKey(resourceId, p, getPasswordFinder());
106 } catch (IOException | GeneralSecurityException e) {
107 t[0] = e;
108 return null;
109 }
110 });
111 if (t[0] != null) {
112 if (t[0] instanceof CancellationException) {
113 throw (CancellationException) t[0];
114 }
115 throw new IOException(
116 format(SshdText.get().keyLoadFailed, resource), t[0]);
117 }
118 return key;
119 }
120
121 private class CancellingKeyPairIterator implements Iterator<KeyPair> {
122
123 private final Iterator<Path> paths;
124
125 private KeyPair nextItem;
126
127 private boolean nextSet;
128
129 public CancellingKeyPairIterator(Collection<? extends Path> resources) {
130 List<Path> copy = new ArrayList<>(resources.size());
131 copy.addAll(resources);
132 paths = copy.iterator();
133 }
134
135 @Override
136 public boolean hasNext() {
137 if (nextSet) {
138 return nextItem != null;
139 }
140 nextSet = true;
141 while (nextItem == null && paths.hasNext()) {
142 try {
143 nextItem = doLoadKey(paths.next());
144 } catch (CancellationException cancelled) {
145 throw cancelled;
146 } catch (Exception other) {
147 log.warn(other.toString());
148 }
149 }
150 return nextItem != null;
151 }
152
153 @Override
154 public KeyPair next() {
155 if (!nextSet && !hasNext()) {
156 throw new NoSuchElementException();
157 }
158 KeyPair result = nextItem;
159 nextItem = null;
160 nextSet = false;
161 if (result == null) {
162 throw new NoSuchElementException();
163 }
164 return result;
165 }
166
167 }
168 }