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.api;
44
45 import java.io.IOException;
46 import java.io.InputStream;
47 import java.io.PrintStream;
48 import java.text.MessageFormat;
49 import java.util.ArrayList;
50 import java.util.Collections;
51 import java.util.HashMap;
52 import java.util.LinkedList;
53 import java.util.List;
54
55 import org.eclipse.jgit.api.errors.AbortedByHookException;
56 import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;
57 import org.eclipse.jgit.api.errors.EmptyCommitException;
58 import org.eclipse.jgit.api.errors.GitAPIException;
59 import org.eclipse.jgit.api.errors.JGitInternalException;
60 import org.eclipse.jgit.api.errors.NoFilepatternException;
61 import org.eclipse.jgit.api.errors.NoHeadException;
62 import org.eclipse.jgit.api.errors.NoMessageException;
63 import org.eclipse.jgit.api.errors.UnmergedPathsException;
64 import org.eclipse.jgit.api.errors.UnsupportedSigningFormatException;
65 import org.eclipse.jgit.api.errors.WrongRepositoryStateException;
66 import org.eclipse.jgit.dircache.DirCache;
67 import org.eclipse.jgit.dircache.DirCacheBuildIterator;
68 import org.eclipse.jgit.dircache.DirCacheBuilder;
69 import org.eclipse.jgit.dircache.DirCacheEntry;
70 import org.eclipse.jgit.dircache.DirCacheIterator;
71 import org.eclipse.jgit.errors.UnmergedPathException;
72 import org.eclipse.jgit.hooks.CommitMsgHook;
73 import org.eclipse.jgit.hooks.Hooks;
74 import org.eclipse.jgit.hooks.PostCommitHook;
75 import org.eclipse.jgit.hooks.PreCommitHook;
76 import org.eclipse.jgit.internal.JGitText;
77 import org.eclipse.jgit.lib.CommitBuilder;
78 import org.eclipse.jgit.lib.Constants;
79 import org.eclipse.jgit.lib.FileMode;
80 import org.eclipse.jgit.lib.GpgConfig;
81 import org.eclipse.jgit.lib.GpgConfig.GpgFormat;
82 import org.eclipse.jgit.lib.GpgSigner;
83 import org.eclipse.jgit.lib.ObjectId;
84 import org.eclipse.jgit.lib.ObjectInserter;
85 import org.eclipse.jgit.lib.PersonIdent;
86 import org.eclipse.jgit.lib.Ref;
87 import org.eclipse.jgit.lib.RefUpdate;
88 import org.eclipse.jgit.lib.RefUpdate.Result;
89 import org.eclipse.jgit.lib.Repository;
90 import org.eclipse.jgit.lib.RepositoryState;
91 import org.eclipse.jgit.lib.internal.BouncyCastleGpgSigner;
92 import org.eclipse.jgit.revwalk.RevCommit;
93 import org.eclipse.jgit.revwalk.RevObject;
94 import org.eclipse.jgit.revwalk.RevTag;
95 import org.eclipse.jgit.revwalk.RevWalk;
96 import org.eclipse.jgit.transport.CredentialsProvider;
97 import org.eclipse.jgit.treewalk.CanonicalTreeParser;
98 import org.eclipse.jgit.treewalk.FileTreeIterator;
99 import org.eclipse.jgit.treewalk.TreeWalk;
100 import org.eclipse.jgit.treewalk.TreeWalk.OperationType;
101 import org.eclipse.jgit.util.ChangeIdUtil;
102
103
104
105
106
107
108
109
110
111
112 public class CommitCommand extends GitCommand<RevCommit> {
113 private PersonIdent author;
114
115 private PersonIdent committer;
116
117 private String message;
118
119 private boolean all;
120
121 private List<String> only = new ArrayList<>();
122
123 private boolean[] onlyProcessed;
124
125 private boolean amend;
126
127 private boolean insertChangeId;
128
129
130
131
132
133 private List<ObjectId> parents = new LinkedList<>();
134
135 private String reflogComment;
136
137 private boolean useDefaultReflogMessage = true;
138
139
140
141
142 private boolean noVerify;
143
144 private HashMap<String, PrintStream> hookOutRedirect = new HashMap<>(3);
145
146 private HashMap<String, PrintStream> hookErrRedirect = new HashMap<>(3);
147
148 private Boolean allowEmpty;
149
150 private Boolean signCommit;
151
152 private String signingKey;
153
154 private GpgSigner gpgSigner;
155
156 private CredentialsProvider credentialsProvider;
157
158
159
160
161
162
163
164 protected CommitCommand(Repository repo) {
165 super(repo);
166 this.credentialsProvider = CredentialsProvider.getDefault();
167 }
168
169
170
171
172
173
174
175
176
177 @Override
178 public RevCommit call() throws GitAPIException, NoHeadException,
179 NoMessageException, UnmergedPathsException,
180 ConcurrentRefUpdateException, WrongRepositoryStateException,
181 AbortedByHookException {
182 checkCallable();
183 Collections.sort(only);
184
185 try (RevWalkRevWalk.html#RevWalk">RevWalk rw = new RevWalk(repo)) {
186 RepositoryState state = repo.getRepositoryState();
187 if (!state.canCommit())
188 throw new WrongRepositoryStateException(MessageFormat.format(
189 JGitText.get().cannotCommitOnARepoWithState,
190 state.name()));
191
192 if (!noVerify) {
193 Hooks.preCommit(repo, hookOutRedirect.get(PreCommitHook.NAME),
194 hookErrRedirect.get(PreCommitHook.NAME))
195 .call();
196 }
197
198 processOptions(state, rw);
199
200 if (all && !repo.isBare()) {
201 try (Gitit.html#Git">Git git = new Git(repo)) {
202 git.add()
203 .addFilepattern(".")
204 .setUpdate(true).call();
205 } catch (NoFilepatternException e) {
206
207 throw new JGitInternalException(e.getMessage(), e);
208 }
209 }
210
211 Ref head = repo.exactRef(Constants.HEAD);
212 if (head == null)
213 throw new NoHeadException(
214 JGitText.get().commitOnRepoWithoutHEADCurrentlyNotSupported);
215
216
217 ObjectId headId = repo.resolve(Constants.HEAD + "^{commit}");
218 if (headId == null && amend)
219 throw new WrongRepositoryStateException(
220 JGitText.get().commitAmendOnInitialNotPossible);
221
222 if (headId != null)
223 if (amend) {
224 RevCommit previousCommit = rw.parseCommit(headId);
225 for (RevCommit p : previousCommit.getParents())
226 parents.add(p.getId());
227 if (author == null)
228 author = previousCommit.getAuthorIdent();
229 } else {
230 parents.add(0, headId);
231 }
232
233 if (!noVerify) {
234 message = Hooks
235 .commitMsg(repo,
236 hookOutRedirect.get(CommitMsgHook.NAME),
237 hookErrRedirect.get(CommitMsgHook.NAME))
238 .setCommitMessage(message).call();
239 }
240
241
242 DirCache index = repo.lockDirCache();
243 try (ObjectInserter odi = repo.newObjectInserter()) {
244 if (!only.isEmpty())
245 index = createTemporaryIndex(headId, index, rw);
246
247
248
249
250 ObjectId indexTreeId = index.writeTree(odi);
251
252 if (insertChangeId)
253 insertChangeId(indexTreeId);
254
255
256 if (headId != null && !allowEmpty.booleanValue()) {
257 RevCommit headCommit = rw.parseCommit(headId);
258 headCommit.getTree();
259 if (indexTreeId.equals(headCommit.getTree())) {
260 throw new EmptyCommitException(
261 JGitText.get().emptyCommit);
262 }
263 }
264
265
266 CommitBuilder commit = new CommitBuilder();
267 commit.setCommitter(committer);
268 commit.setAuthor(author);
269 commit.setMessage(message);
270
271 commit.setParentIds(parents);
272 commit.setTreeId(indexTreeId);
273
274 if (signCommit.booleanValue()) {
275 gpgSigner.sign(commit, signingKey, committer,
276 credentialsProvider);
277 }
278
279 ObjectId commitId = odi.insert(commit);
280 odi.flush();
281
282 RevCommit revCommit = rw.parseCommit(commitId);
283 RefUpdate ru = repo.updateRef(Constants.HEAD);
284 ru.setNewObjectId(commitId);
285 if (!useDefaultReflogMessage) {
286 ru.setRefLogMessage(reflogComment, false);
287 } else {
288 String prefix = amend ? "commit (amend): "
289 : parents.isEmpty() ? "commit (initial): "
290 : "commit: ";
291 ru.setRefLogMessage(prefix + revCommit.getShortMessage(),
292 false);
293 }
294 if (headId != null)
295 ru.setExpectedOldObjectId(headId);
296 else
297 ru.setExpectedOldObjectId(ObjectId.zeroId());
298 Result rc = ru.forceUpdate();
299 switch (rc) {
300 case NEW:
301 case FORCED:
302 case FAST_FORWARD: {
303 setCallable(false);
304 if (state == RepositoryState.MERGING_RESOLVED
305 || isMergeDuringRebase(state)) {
306
307
308 repo.writeMergeCommitMsg(null);
309 repo.writeMergeHeads(null);
310 } else if (state == RepositoryState.CHERRY_PICKING_RESOLVED) {
311 repo.writeMergeCommitMsg(null);
312 repo.writeCherryPickHead(null);
313 } else if (state == RepositoryState.REVERTING_RESOLVED) {
314 repo.writeMergeCommitMsg(null);
315 repo.writeRevertHead(null);
316 }
317 Hooks.postCommit(repo,
318 hookOutRedirect.get(PostCommitHook.NAME),
319 hookErrRedirect.get(PostCommitHook.NAME)).call();
320
321 return revCommit;
322 }
323 case REJECTED:
324 case LOCK_FAILURE:
325 throw new ConcurrentRefUpdateException(
326 JGitText.get().couldNotLockHEAD, ru.getRef(), rc);
327 default:
328 throw new JGitInternalException(MessageFormat.format(
329 JGitText.get().updatingRefFailed, Constants.HEAD,
330 commitId.toString(), rc));
331 }
332 } finally {
333 index.unlock();
334 }
335 } catch (UnmergedPathException e) {
336 throw new UnmergedPathsException(e);
337 } catch (IOException e) {
338 throw new JGitInternalException(
339 JGitText.get().exceptionCaughtDuringExecutionOfCommitCommand, e);
340 }
341 }
342
343 private void insertChangeId(ObjectId treeId) {
344 ObjectId firstParentId = null;
345 if (!parents.isEmpty())
346 firstParentId = parents.get(0);
347 ObjectId changeId = ChangeIdUtil.computeChangeId(treeId, firstParentId,
348 author, committer, message);
349 message = ChangeIdUtil.insertId(message, changeId);
350 if (changeId != null)
351 message = message.replaceAll("\nChange-Id: I"
352 + ObjectId.zeroId().getName() + "\n", "\nChange-Id: I"
353 + changeId.getName() + "\n");
354 }
355
356 private DirCacheircache/DirCache.html#DirCache">DirCache createTemporaryIndex(ObjectId headId, DirCache index,
357 RevWalk rw)
358 throws IOException {
359 ObjectInserter inserter = null;
360
361
362 DirCacheBuilder existingBuilder = index.builder();
363
364
365
366 DirCache inCoreIndex = DirCache.newInCore();
367 DirCacheBuilder tempBuilder = inCoreIndex.builder();
368
369 onlyProcessed = new boolean[only.size()];
370 boolean emptyCommit = true;
371
372 try (TreeWalklk.html#TreeWalk">TreeWalk treeWalk = new TreeWalk(repo)) {
373 treeWalk.setOperationType(OperationType.CHECKIN_OP);
374 int dcIdx = treeWalk
375 .addTree(new DirCacheBuildIterator(existingBuilder));
376 FileTreeIterator fti = new FileTreeIterator(repo);
377 fti.setDirCacheIterator(treeWalk, 0);
378 int fIdx = treeWalk.addTree(fti);
379 int hIdx = -1;
380 if (headId != null)
381 hIdx = treeWalk.addTree(rw.parseTree(headId));
382 treeWalk.setRecursive(true);
383
384 String lastAddedFile = null;
385 while (treeWalk.next()) {
386 String path = treeWalk.getPathString();
387
388 int pos = lookupOnly(path);
389
390 CanonicalTreeParser hTree = null;
391 if (hIdx != -1)
392 hTree = treeWalk.getTree(hIdx, CanonicalTreeParser.class);
393
394 DirCacheIterator dcTree = treeWalk.getTree(dcIdx,
395 DirCacheIterator.class);
396
397 if (pos >= 0) {
398
399
400 FileTreeIterator fTree = treeWalk.getTree(fIdx,
401 FileTreeIterator.class);
402
403
404 boolean tracked = dcTree != null || hTree != null;
405 if (!tracked)
406 continue;
407
408
409
410 if (path.equals(lastAddedFile))
411 continue;
412
413 lastAddedFile = path;
414
415 if (fTree != null) {
416
417
418 final DirCacheEntrytry.html#DirCacheEntry">DirCacheEntry dcEntry = new DirCacheEntry(path);
419 long entryLength = fTree.getEntryLength();
420 dcEntry.setLength(entryLength);
421 dcEntry.setLastModified(fTree.getEntryLastModifiedInstant());
422 dcEntry.setFileMode(fTree.getIndexFileMode(dcTree));
423
424 boolean objectExists = (dcTree != null
425 && fTree.idEqual(dcTree))
426 || (hTree != null && fTree.idEqual(hTree));
427 if (objectExists) {
428 dcEntry.setObjectId(fTree.getEntryObjectId());
429 } else {
430 if (FileMode.GITLINK.equals(dcEntry.getFileMode()))
431 dcEntry.setObjectId(fTree.getEntryObjectId());
432 else {
433
434 if (inserter == null)
435 inserter = repo.newObjectInserter();
436 long contentLength = fTree
437 .getEntryContentLength();
438 try (InputStream inputStream = fTree
439 .openEntryStream()) {
440 dcEntry.setObjectId(inserter.insert(
441 Constants.OBJ_BLOB, contentLength,
442 inputStream));
443 }
444 }
445 }
446
447
448 existingBuilder.add(dcEntry);
449
450 tempBuilder.add(dcEntry);
451
452 if (emptyCommit
453 && (hTree == null || !hTree.idEqual(fTree)
454 || hTree.getEntryRawMode() != fTree
455 .getEntryRawMode()))
456
457 emptyCommit = false;
458 } else {
459
460
461
462 if (emptyCommit && hTree != null)
463
464 emptyCommit = false;
465 }
466
467
468 onlyProcessed[pos] = true;
469 } else {
470
471 if (hTree != null) {
472
473
474 final DirCacheEntrytry.html#DirCacheEntry">DirCacheEntry dcEntry = new DirCacheEntry(path);
475 dcEntry.setObjectId(hTree.getEntryObjectId());
476 dcEntry.setFileMode(hTree.getEntryFileMode());
477
478
479 tempBuilder.add(dcEntry);
480 }
481
482
483 if (dcTree != null)
484 existingBuilder.add(dcTree.getDirCacheEntry());
485 }
486 }
487 }
488
489
490
491 for (int i = 0; i < onlyProcessed.length; i++)
492 if (!onlyProcessed[i])
493 throw new JGitInternalException(MessageFormat.format(
494 JGitText.get().entryNotFoundByPath, only.get(i)));
495
496
497 if (emptyCommit && !allowEmpty.booleanValue())
498
499
500 throw new JGitInternalException(JGitText.get().emptyCommit);
501
502
503 existingBuilder.commit();
504
505 tempBuilder.finish();
506 return inCoreIndex;
507 }
508
509
510
511
512
513
514
515
516
517
518
519
520
521 private int lookupOnly(String pathString) {
522 String p = pathString;
523 while (true) {
524 int position = Collections.binarySearch(only, p);
525 if (position >= 0)
526 return position;
527 int l = p.lastIndexOf("/");
528 if (l < 1)
529 break;
530 p = p.substring(0, l);
531 }
532 return -1;
533 }
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548 private void processOptions(RepositoryState state, RevWalk rw)
549 throws NoMessageException, UnsupportedSigningFormatException {
550 if (committer == null)
551 committer = new PersonIdent(repo);
552 if (author == null && !amend)
553 author = committer;
554 if (allowEmpty == null)
555
556
557
558
559 allowEmpty = (only.isEmpty()) ? Boolean.TRUE : Boolean.FALSE;
560
561
562 if (state == RepositoryState.MERGING_RESOLVED
563 || isMergeDuringRebase(state)) {
564 try {
565 parents = repo.readMergeHeads();
566 if (parents != null)
567 for (int i = 0; i < parents.size(); i++) {
568 RevObject ro = rw.parseAny(parents.get(i));
569 if (ro instanceof RevTag)
570 parents.set(i, rw.peel(ro));
571 }
572 } catch (IOException e) {
573 throw new JGitInternalException(MessageFormat.format(
574 JGitText.get().exceptionOccurredDuringReadingOfGIT_DIR,
575 Constants.MERGE_HEAD, e), e);
576 }
577 if (message == null) {
578 try {
579 message = repo.readMergeCommitMsg();
580 } catch (IOException e) {
581 throw new JGitInternalException(MessageFormat.format(
582 JGitText.get().exceptionOccurredDuringReadingOfGIT_DIR,
583 Constants.MERGE_MSG, e), e);
584 }
585 }
586 } else if (state == RepositoryState.SAFE && message == null) {
587 try {
588 message = repo.readSquashCommitMsg();
589 if (message != null)
590 repo.writeSquashCommitMsg(null );
591 } catch (IOException e) {
592 throw new JGitInternalException(MessageFormat.format(
593 JGitText.get().exceptionOccurredDuringReadingOfGIT_DIR,
594 Constants.MERGE_MSG, e), e);
595 }
596
597 }
598 if (message == null)
599
600
601 throw new NoMessageException(JGitText.get().commitMessageNotSpecified);
602
603 GpgConfig gpgConfig = new GpgConfig(repo.getConfig());
604 if (signCommit == null) {
605 signCommit = gpgConfig.isSignCommits() ? Boolean.TRUE
606 : Boolean.FALSE;
607 }
608 if (signingKey == null) {
609 signingKey = gpgConfig.getSigningKey();
610 }
611 if (gpgSigner == null) {
612 if (gpgConfig.getKeyFormat() != GpgFormat.OPENPGP) {
613 throw new UnsupportedSigningFormatException(
614 JGitText.get().onlyOpenPgpSupportedForSigning);
615 }
616 gpgSigner = GpgSigner.getDefault();
617 if (gpgSigner == null) {
618 gpgSigner = new BouncyCastleGpgSigner();
619 }
620 }
621 }
622
623 private boolean isMergeDuringRebase(RepositoryState state) {
624 if (state != RepositoryState.REBASING_INTERACTIVE
625 && state != RepositoryState.REBASING_MERGE)
626 return false;
627 try {
628 return repo.readMergeHeads() != null;
629 } catch (IOException e) {
630 throw new JGitInternalException(MessageFormat.format(
631 JGitText.get().exceptionOccurredDuringReadingOfGIT_DIR,
632 Constants.MERGE_HEAD, e), e);
633 }
634 }
635
636
637
638
639
640
641
642
643 public CommitCommand setMessage(String message) {
644 checkCallable();
645 this.message = message;
646 return this;
647 }
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668 public CommitCommand setAllowEmpty(boolean allowEmpty) {
669 this.allowEmpty = Boolean.valueOf(allowEmpty);
670 return this;
671 }
672
673
674
675
676
677
678 public String getMessage() {
679 return message;
680 }
681
682
683
684
685
686
687
688
689
690
691
692 public CommitCommand setCommitter(PersonIdent committer) {
693 checkCallable();
694 this.committer = committer;
695 return this;
696 }
697
698
699
700
701
702
703
704
705
706
707
708
709 public CommitCommand setCommitter(String name, String email) {
710 checkCallable();
711 return setCommitter(new PersonIdent(name, email));
712 }
713
714
715
716
717
718
719
720
721
722 public PersonIdent getCommitter() {
723 return committer;
724 }
725
726
727
728
729
730
731
732
733
734
735
736 public CommitCommand setAuthor(PersonIdent author) {
737 checkCallable();
738 this.author = author;
739 return this;
740 }
741
742
743
744
745
746
747
748
749
750
751
752
753 public CommitCommand setAuthor(String name, String email) {
754 checkCallable();
755 return setAuthor(new PersonIdent(name, email));
756 }
757
758
759
760
761
762
763
764
765
766 public PersonIdent getAuthor() {
767 return author;
768 }
769
770
771
772
773
774
775
776
777
778
779
780
781
782 public CommitCommand setAll(boolean all) {
783 checkCallable();
784 if (all && !only.isEmpty())
785 throw new JGitInternalException(MessageFormat.format(
786 JGitText.get().illegalCombinationOfArguments, "--all",
787 "--only"));
788 this.all = all;
789 return this;
790 }
791
792
793
794
795
796
797
798
799
800
801 public CommitCommand setAmend(boolean amend) {
802 checkCallable();
803 this.amend = amend;
804 return this;
805 }
806
807
808
809
810
811
812
813
814
815
816
817
818 public CommitCommand setOnly(String only) {
819 checkCallable();
820 if (all)
821 throw new JGitInternalException(MessageFormat.format(
822 JGitText.get().illegalCombinationOfArguments, "--only",
823 "--all"));
824 String o = only.endsWith("/") ? only.substring(0, only.length() - 1)
825 : only;
826
827 if (!this.only.contains(o))
828 this.only.add(o);
829 return this;
830 }
831
832
833
834
835
836
837
838
839
840
841
842 public CommitCommand setInsertChangeId(boolean insertChangeId) {
843 checkCallable();
844 this.insertChangeId = insertChangeId;
845 return this;
846 }
847
848
849
850
851
852
853
854
855
856 public CommitCommand setReflogComment(String reflogComment) {
857 this.reflogComment = reflogComment;
858 useDefaultReflogMessage = false;
859 return this;
860 }
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876 public CommitCommand setNoVerify(boolean noVerify) {
877 this.noVerify = noVerify;
878 return this;
879 }
880
881
882
883
884
885
886
887
888
889
890
891 public CommitCommand setHookOutputStream(PrintStream hookStdOut) {
892 setHookOutputStream(PreCommitHook.NAME, hookStdOut);
893 setHookOutputStream(CommitMsgHook.NAME, hookStdOut);
894 setHookOutputStream(PostCommitHook.NAME, hookStdOut);
895 return this;
896 }
897
898
899
900
901
902
903
904
905
906
907
908 public CommitCommand setHookErrorStream(PrintStream hookStdErr) {
909 setHookErrorStream(PreCommitHook.NAME, hookStdErr);
910 setHookErrorStream(CommitMsgHook.NAME, hookStdErr);
911 setHookErrorStream(PostCommitHook.NAME, hookStdErr);
912 return this;
913 }
914
915
916
917
918
919
920
921
922
923
924
925
926
927 public CommitCommand setHookOutputStream(String hookName,
928 PrintStream hookStdOut) {
929 if (!(PreCommitHook.NAME.equals(hookName)
930 || CommitMsgHook.NAME.equals(hookName)
931 || PostCommitHook.NAME.equals(hookName))) {
932 throw new IllegalArgumentException(
933 MessageFormat.format(JGitText.get().illegalHookName,
934 hookName));
935 }
936 hookOutRedirect.put(hookName, hookStdOut);
937 return this;
938 }
939
940
941
942
943
944
945
946
947
948
949
950
951
952 public CommitCommand setHookErrorStream(String hookName,
953 PrintStream hookStdErr) {
954 if (!(PreCommitHook.NAME.equals(hookName)
955 || CommitMsgHook.NAME.equals(hookName)
956 || PostCommitHook.NAME.equals(hookName))) {
957 throw new IllegalArgumentException(MessageFormat
958 .format(JGitText.get().illegalHookName, hookName));
959 }
960 hookErrRedirect.put(hookName, hookStdErr);
961 return this;
962 }
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980 public CommitCommand setSigningKey(String signingKey) {
981 checkCallable();
982 this.signingKey = signingKey;
983 return this;
984 }
985
986
987
988
989
990
991
992
993
994
995
996 public CommitCommand setSign(Boolean sign) {
997 checkCallable();
998 this.signCommit = sign;
999 return this;
1000 }
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010 public void setCredentialsProvider(
1011 CredentialsProvider credentialsProvider) {
1012 this.credentialsProvider = credentialsProvider;
1013 }
1014 }