103 * {@code Set} of most-trusted CAs. Each element of the
104 * set is a {@link TrustAnchor TrustAnchor}.
105 * <p>
106 * Note that the {@code Set} is copied to protect against
107 * subsequent modifications.
108 *
109 * @param trustAnchors a {@code Set} of {@code TrustAnchor}s
110 * @throws InvalidAlgorithmParameterException if the specified
111 * {@code Set} is empty {@code (trustAnchors.isEmpty() == true)}
112 * @throws NullPointerException if the specified {@code Set} is
113 * {@code null}
114 * @throws ClassCastException if any of the elements in the {@code Set}
115 * are not of type {@code java.security.cert.TrustAnchor}
116 */
117 public PKIXParameters(Set<TrustAnchor> trustAnchors)
118 throws InvalidAlgorithmParameterException
119 {
120 setTrustAnchors(trustAnchors);
121
122 this.unmodInitialPolicies = Collections.<String>emptySet();
123 this.certPathCheckers = new ArrayList<PKIXCertPathChecker>();
124 this.certStores = new ArrayList<CertStore>();
125 }
126
127 /**
128 * Creates an instance of {@code PKIXParameters} that
129 * populates the set of most-trusted CAs from the trusted
130 * certificate entries contained in the specified {@code KeyStore}.
131 * Only keystore entries that contain trusted {@code X509Certificates}
132 * are considered; all other certificate types are ignored.
133 *
134 * @param keystore a {@code KeyStore} from which the set of
135 * most-trusted CAs will be populated
136 * @throws KeyStoreException if the keystore has not been initialized
137 * @throws InvalidAlgorithmParameterException if the keystore does
138 * not contain at least one trusted certificate entry
139 * @throws NullPointerException if the keystore is {@code null}
140 */
141 public PKIXParameters(KeyStore keystore)
142 throws KeyStoreException, InvalidAlgorithmParameterException
143 {
144 if (keystore == null)
145 throw new NullPointerException("the keystore parameter must be " +
146 "non-null");
147 Set<TrustAnchor> hashSet = new HashSet<TrustAnchor>();
148 Enumeration<String> aliases = keystore.aliases();
149 while (aliases.hasMoreElements()) {
150 String alias = aliases.nextElement();
151 if (keystore.isCertificateEntry(alias)) {
152 Certificate cert = keystore.getCertificate(alias);
153 if (cert instanceof X509Certificate)
154 hashSet.add(new TrustAnchor((X509Certificate)cert, null));
155 }
156 }
157 setTrustAnchors(hashSet);
158 this.unmodInitialPolicies = Collections.<String>emptySet();
159 this.certPathCheckers = new ArrayList<PKIXCertPathChecker>();
160 this.certStores = new ArrayList<CertStore>();
161 }
162
163 /**
164 * Returns an immutable {@code Set} of the most-trusted
165 * CAs.
166 *
167 * @return an immutable {@code Set} of {@code TrustAnchor}s
168 * (never {@code null})
169 *
170 * @see #setTrustAnchors
171 */
172 public Set<TrustAnchor> getTrustAnchors() {
173 return this.unmodTrustAnchors;
174 }
175
176 /**
177 * Sets the {@code Set} of most-trusted CAs.
178 * <p>
179 * Note that the {@code Set} is copied to protect against
180 * subsequent modifications.
190 * @see #getTrustAnchors
191 */
192 public void setTrustAnchors(Set<TrustAnchor> trustAnchors)
193 throws InvalidAlgorithmParameterException
194 {
195 if (trustAnchors == null) {
196 throw new NullPointerException("the trustAnchors parameters must" +
197 " be non-null");
198 }
199 if (trustAnchors.isEmpty()) {
200 throw new InvalidAlgorithmParameterException("the trustAnchors " +
201 "parameter must be non-empty");
202 }
203 for (Iterator<TrustAnchor> i = trustAnchors.iterator(); i.hasNext(); ) {
204 if (!(i.next() instanceof TrustAnchor)) {
205 throw new ClassCastException("all elements of set must be "
206 + "of type java.security.cert.TrustAnchor");
207 }
208 }
209 this.unmodTrustAnchors = Collections.unmodifiableSet
210 (new HashSet<TrustAnchor>(trustAnchors));
211 }
212
213 /**
214 * Returns an immutable {@code Set} of initial
215 * policy identifiers (OID strings), indicating that any one of these
216 * policies would be acceptable to the certificate user for the purposes of
217 * certification path processing. The default return value is an empty
218 * {@code Set}, which is interpreted as meaning that any policy would
219 * be acceptable.
220 *
221 * @return an immutable {@code Set} of initial policy OIDs in
222 * {@code String} format, or an empty {@code Set} (implying any
223 * policy is acceptable). Never returns {@code null}.
224 *
225 * @see #setInitialPolicies
226 */
227 public Set<String> getInitialPolicies() {
228 return this.unmodInitialPolicies;
229 }
230
239 * <p>
240 * Note that the {@code Set} is copied to protect against
241 * subsequent modifications.
242 *
243 * @param initialPolicies a {@code Set} of initial policy
244 * OIDs in {@code String} format (or {@code null})
245 * @throws ClassCastException if any of the elements in the set are
246 * not of type {@code String}
247 *
248 * @see #getInitialPolicies
249 */
250 public void setInitialPolicies(Set<String> initialPolicies) {
251 if (initialPolicies != null) {
252 for (Iterator<String> i = initialPolicies.iterator();
253 i.hasNext();) {
254 if (!(i.next() instanceof String))
255 throw new ClassCastException("all elements of set must be "
256 + "of type java.lang.String");
257 }
258 this.unmodInitialPolicies =
259 Collections.unmodifiableSet(new HashSet<String>(initialPolicies));
260 } else
261 this.unmodInitialPolicies = Collections.<String>emptySet();
262 }
263
264 /**
265 * Sets the list of {@code CertStore}s to be used in finding
266 * certificates and CRLs. May be {@code null}, in which case
267 * no {@code CertStore}s will be used. The first
268 * {@code CertStore}s in the list may be preferred to those that
269 * appear later.
270 * <p>
271 * Note that the {@code List} is copied to protect against
272 * subsequent modifications.
273 *
274 * @param stores a {@code List} of {@code CertStore}s (or
275 * {@code null})
276 * @throws ClassCastException if any of the elements in the list are
277 * not of type {@code java.security.cert.CertStore}
278 *
279 * @see #getCertStores
280 */
281 public void setCertStores(List<CertStore> stores) {
282 if (stores == null) {
283 this.certStores = new ArrayList<CertStore>();
284 } else {
285 for (Iterator<CertStore> i = stores.iterator(); i.hasNext();) {
286 if (!(i.next() instanceof CertStore)) {
287 throw new ClassCastException("all elements of list must be "
288 + "of type java.security.cert.CertStore");
289 }
290 }
291 this.certStores = new ArrayList<CertStore>(stores);
292 }
293 }
294
295 /**
296 * Adds a {@code CertStore} to the end of the list of
297 * {@code CertStore}s used in finding certificates and CRLs.
298 *
299 * @param store the {@code CertStore} to add. If {@code null},
300 * the store is ignored (not added to list).
301 */
302 public void addCertStore(CertStore store) {
303 if (store != null) {
304 this.certStores.add(store);
305 }
306 }
307
308 /**
309 * Returns an immutable {@code List} of {@code CertStore}s that
310 * are used to find certificates and CRLs.
311 *
312 * @return an immutable {@code List} of {@code CertStore}s
313 * (may be empty, but never {@code null})
314 *
315 * @see #setCertStores
316 */
317 public List<CertStore> getCertStores() {
318 return Collections.unmodifiableList
319 (new ArrayList<CertStore>(this.certStores));
320 }
321
322 /**
323 * Sets the RevocationEnabled flag. If this flag is true, the default
324 * revocation checking mechanism of the underlying PKIX service provider
325 * will be used. If this flag is false, the default revocation checking
326 * mechanism will be disabled (not used).
327 * <p>
328 * When a {@code PKIXParameters} object is created, this flag is set
329 * to true. This setting reflects the most common strategy for checking
330 * revocation, since each service provider must support revocation
331 * checking to be PKIX compliant. Sophisticated applications should set
332 * this flag to false when it is not practical to use a PKIX service
333 * provider's default revocation checking mechanism or when an alternative
334 * revocation checking mechanism is to be substituted (by also calling the
335 * {@link #addCertPathChecker addCertPathChecker} or {@link
336 * #setCertPathCheckers setCertPathCheckers} methods).
337 *
338 * @param val the new value of the RevocationEnabled flag
339 */
527 * Regardless of whether these additional {@code PKIXCertPathChecker}s
528 * are set, a PKIX {@code CertPathValidator} or
529 * {@code CertPathBuilder} must perform all of the required PKIX
530 * checks on each certificate. The one exception to this rule is if the
531 * RevocationEnabled flag is set to false (see the {@link
532 * #setRevocationEnabled setRevocationEnabled} method).
533 * <p>
534 * Note that the {@code List} supplied here is copied and each
535 * {@code PKIXCertPathChecker} in the list is cloned to protect
536 * against subsequent modifications.
537 *
538 * @param checkers a {@code List} of {@code PKIXCertPathChecker}s.
539 * May be {@code null}, in which case no additional checkers will be
540 * used.
541 * @throws ClassCastException if any of the elements in the list
542 * are not of type {@code java.security.cert.PKIXCertPathChecker}
543 * @see #getCertPathCheckers
544 */
545 public void setCertPathCheckers(List<PKIXCertPathChecker> checkers) {
546 if (checkers != null) {
547 List<PKIXCertPathChecker> tmpList =
548 new ArrayList<PKIXCertPathChecker>();
549 for (PKIXCertPathChecker checker : checkers) {
550 tmpList.add((PKIXCertPathChecker)checker.clone());
551 }
552 this.certPathCheckers = tmpList;
553 } else {
554 this.certPathCheckers = new ArrayList<PKIXCertPathChecker>();
555 }
556 }
557
558 /**
559 * Returns the {@code List} of certification path checkers.
560 * The returned {@code List} is immutable, and each
561 * {@code PKIXCertPathChecker} in the {@code List} is cloned
562 * to protect against subsequent modifications.
563 *
564 * @return an immutable {@code List} of
565 * {@code PKIXCertPathChecker}s (may be empty, but not
566 * {@code null})
567 * @see #setCertPathCheckers
568 */
569 public List<PKIXCertPathChecker> getCertPathCheckers() {
570 List<PKIXCertPathChecker> tmpList = new ArrayList<PKIXCertPathChecker>();
571 for (PKIXCertPathChecker ck : certPathCheckers) {
572 tmpList.add((PKIXCertPathChecker)ck.clone());
573 }
574 return Collections.unmodifiableList(tmpList);
575 }
576
577 /**
578 * Adds a {@code PKIXCertPathChecker} to the list of certification
579 * path checkers. See the {@link #setCertPathCheckers setCertPathCheckers}
580 * method for more details.
581 * <p>
582 * Note that the {@code PKIXCertPathChecker} is cloned to protect
583 * against subsequent modifications.
584 *
585 * @param checker a {@code PKIXCertPathChecker} to add to the list of
586 * checks. If {@code null}, the checker is ignored (not added to list).
587 */
588 public void addCertPathChecker(PKIXCertPathChecker checker) {
589 if (checker != null) {
590 certPathCheckers.add((PKIXCertPathChecker)checker.clone());
650 */
651 public void setTargetCertConstraints(CertSelector selector) {
652 if (selector != null)
653 certSelector = (CertSelector) selector.clone();
654 else
655 certSelector = null;
656 }
657
658 /**
659 * Makes a copy of this {@code PKIXParameters} object. Changes
660 * to the copy will not affect the original and vice versa.
661 *
662 * @return a copy of this {@code PKIXParameters} object
663 */
664 public Object clone() {
665 try {
666 PKIXParameters copy = (PKIXParameters)super.clone();
667
668 // must clone these because addCertStore, et al. modify them
669 if (certStores != null) {
670 copy.certStores = new ArrayList<CertStore>(certStores);
671 }
672 if (certPathCheckers != null) {
673 copy.certPathCheckers =
674 new ArrayList<PKIXCertPathChecker>(certPathCheckers.size());
675 for (PKIXCertPathChecker checker : certPathCheckers) {
676 copy.certPathCheckers.add(
677 (PKIXCertPathChecker)checker.clone());
678 }
679 }
680
681 // other class fields are immutable to public, don't bother
682 // to clone the read-only fields.
683 return copy;
684 } catch (CloneNotSupportedException e) {
685 /* Cannot happen */
686 throw new InternalError(e.toString(), e);
687 }
688 }
689
690 /**
691 * Returns a formatted string describing the parameters.
692 *
693 * @return a formatted string describing the parameters.
694 */
|
103 * {@code Set} of most-trusted CAs. Each element of the
104 * set is a {@link TrustAnchor TrustAnchor}.
105 * <p>
106 * Note that the {@code Set} is copied to protect against
107 * subsequent modifications.
108 *
109 * @param trustAnchors a {@code Set} of {@code TrustAnchor}s
110 * @throws InvalidAlgorithmParameterException if the specified
111 * {@code Set} is empty {@code (trustAnchors.isEmpty() == true)}
112 * @throws NullPointerException if the specified {@code Set} is
113 * {@code null}
114 * @throws ClassCastException if any of the elements in the {@code Set}
115 * are not of type {@code java.security.cert.TrustAnchor}
116 */
117 public PKIXParameters(Set<TrustAnchor> trustAnchors)
118 throws InvalidAlgorithmParameterException
119 {
120 setTrustAnchors(trustAnchors);
121
122 this.unmodInitialPolicies = Collections.<String>emptySet();
123 this.certPathCheckers = new ArrayList<>();
124 this.certStores = new ArrayList<>();
125 }
126
127 /**
128 * Creates an instance of {@code PKIXParameters} that
129 * populates the set of most-trusted CAs from the trusted
130 * certificate entries contained in the specified {@code KeyStore}.
131 * Only keystore entries that contain trusted {@code X509Certificates}
132 * are considered; all other certificate types are ignored.
133 *
134 * @param keystore a {@code KeyStore} from which the set of
135 * most-trusted CAs will be populated
136 * @throws KeyStoreException if the keystore has not been initialized
137 * @throws InvalidAlgorithmParameterException if the keystore does
138 * not contain at least one trusted certificate entry
139 * @throws NullPointerException if the keystore is {@code null}
140 */
141 public PKIXParameters(KeyStore keystore)
142 throws KeyStoreException, InvalidAlgorithmParameterException
143 {
144 if (keystore == null)
145 throw new NullPointerException("the keystore parameter must be " +
146 "non-null");
147 Set<TrustAnchor> hashSet = new HashSet<>();
148 Enumeration<String> aliases = keystore.aliases();
149 while (aliases.hasMoreElements()) {
150 String alias = aliases.nextElement();
151 if (keystore.isCertificateEntry(alias)) {
152 Certificate cert = keystore.getCertificate(alias);
153 if (cert instanceof X509Certificate)
154 hashSet.add(new TrustAnchor((X509Certificate)cert, null));
155 }
156 }
157 setTrustAnchors(hashSet);
158 this.unmodInitialPolicies = Collections.<String>emptySet();
159 this.certPathCheckers = new ArrayList<>();
160 this.certStores = new ArrayList<>();
161 }
162
163 /**
164 * Returns an immutable {@code Set} of the most-trusted
165 * CAs.
166 *
167 * @return an immutable {@code Set} of {@code TrustAnchor}s
168 * (never {@code null})
169 *
170 * @see #setTrustAnchors
171 */
172 public Set<TrustAnchor> getTrustAnchors() {
173 return this.unmodTrustAnchors;
174 }
175
176 /**
177 * Sets the {@code Set} of most-trusted CAs.
178 * <p>
179 * Note that the {@code Set} is copied to protect against
180 * subsequent modifications.
190 * @see #getTrustAnchors
191 */
192 public void setTrustAnchors(Set<TrustAnchor> trustAnchors)
193 throws InvalidAlgorithmParameterException
194 {
195 if (trustAnchors == null) {
196 throw new NullPointerException("the trustAnchors parameters must" +
197 " be non-null");
198 }
199 if (trustAnchors.isEmpty()) {
200 throw new InvalidAlgorithmParameterException("the trustAnchors " +
201 "parameter must be non-empty");
202 }
203 for (Iterator<TrustAnchor> i = trustAnchors.iterator(); i.hasNext(); ) {
204 if (!(i.next() instanceof TrustAnchor)) {
205 throw new ClassCastException("all elements of set must be "
206 + "of type java.security.cert.TrustAnchor");
207 }
208 }
209 this.unmodTrustAnchors = Collections.unmodifiableSet
210 (new HashSet<>(trustAnchors));
211 }
212
213 /**
214 * Returns an immutable {@code Set} of initial
215 * policy identifiers (OID strings), indicating that any one of these
216 * policies would be acceptable to the certificate user for the purposes of
217 * certification path processing. The default return value is an empty
218 * {@code Set}, which is interpreted as meaning that any policy would
219 * be acceptable.
220 *
221 * @return an immutable {@code Set} of initial policy OIDs in
222 * {@code String} format, or an empty {@code Set} (implying any
223 * policy is acceptable). Never returns {@code null}.
224 *
225 * @see #setInitialPolicies
226 */
227 public Set<String> getInitialPolicies() {
228 return this.unmodInitialPolicies;
229 }
230
239 * <p>
240 * Note that the {@code Set} is copied to protect against
241 * subsequent modifications.
242 *
243 * @param initialPolicies a {@code Set} of initial policy
244 * OIDs in {@code String} format (or {@code null})
245 * @throws ClassCastException if any of the elements in the set are
246 * not of type {@code String}
247 *
248 * @see #getInitialPolicies
249 */
250 public void setInitialPolicies(Set<String> initialPolicies) {
251 if (initialPolicies != null) {
252 for (Iterator<String> i = initialPolicies.iterator();
253 i.hasNext();) {
254 if (!(i.next() instanceof String))
255 throw new ClassCastException("all elements of set must be "
256 + "of type java.lang.String");
257 }
258 this.unmodInitialPolicies =
259 Collections.unmodifiableSet(new HashSet<>(initialPolicies));
260 } else
261 this.unmodInitialPolicies = Collections.<String>emptySet();
262 }
263
264 /**
265 * Sets the list of {@code CertStore}s to be used in finding
266 * certificates and CRLs. May be {@code null}, in which case
267 * no {@code CertStore}s will be used. The first
268 * {@code CertStore}s in the list may be preferred to those that
269 * appear later.
270 * <p>
271 * Note that the {@code List} is copied to protect against
272 * subsequent modifications.
273 *
274 * @param stores a {@code List} of {@code CertStore}s (or
275 * {@code null})
276 * @throws ClassCastException if any of the elements in the list are
277 * not of type {@code java.security.cert.CertStore}
278 *
279 * @see #getCertStores
280 */
281 public void setCertStores(List<CertStore> stores) {
282 if (stores == null) {
283 this.certStores = new ArrayList<>();
284 } else {
285 for (Iterator<CertStore> i = stores.iterator(); i.hasNext();) {
286 if (!(i.next() instanceof CertStore)) {
287 throw new ClassCastException("all elements of list must be "
288 + "of type java.security.cert.CertStore");
289 }
290 }
291 this.certStores = new ArrayList<>(stores);
292 }
293 }
294
295 /**
296 * Adds a {@code CertStore} to the end of the list of
297 * {@code CertStore}s used in finding certificates and CRLs.
298 *
299 * @param store the {@code CertStore} to add. If {@code null},
300 * the store is ignored (not added to list).
301 */
302 public void addCertStore(CertStore store) {
303 if (store != null) {
304 this.certStores.add(store);
305 }
306 }
307
308 /**
309 * Returns an immutable {@code List} of {@code CertStore}s that
310 * are used to find certificates and CRLs.
311 *
312 * @return an immutable {@code List} of {@code CertStore}s
313 * (may be empty, but never {@code null})
314 *
315 * @see #setCertStores
316 */
317 public List<CertStore> getCertStores() {
318 return Collections.unmodifiableList
319 (new ArrayList<>(this.certStores));
320 }
321
322 /**
323 * Sets the RevocationEnabled flag. If this flag is true, the default
324 * revocation checking mechanism of the underlying PKIX service provider
325 * will be used. If this flag is false, the default revocation checking
326 * mechanism will be disabled (not used).
327 * <p>
328 * When a {@code PKIXParameters} object is created, this flag is set
329 * to true. This setting reflects the most common strategy for checking
330 * revocation, since each service provider must support revocation
331 * checking to be PKIX compliant. Sophisticated applications should set
332 * this flag to false when it is not practical to use a PKIX service
333 * provider's default revocation checking mechanism or when an alternative
334 * revocation checking mechanism is to be substituted (by also calling the
335 * {@link #addCertPathChecker addCertPathChecker} or {@link
336 * #setCertPathCheckers setCertPathCheckers} methods).
337 *
338 * @param val the new value of the RevocationEnabled flag
339 */
527 * Regardless of whether these additional {@code PKIXCertPathChecker}s
528 * are set, a PKIX {@code CertPathValidator} or
529 * {@code CertPathBuilder} must perform all of the required PKIX
530 * checks on each certificate. The one exception to this rule is if the
531 * RevocationEnabled flag is set to false (see the {@link
532 * #setRevocationEnabled setRevocationEnabled} method).
533 * <p>
534 * Note that the {@code List} supplied here is copied and each
535 * {@code PKIXCertPathChecker} in the list is cloned to protect
536 * against subsequent modifications.
537 *
538 * @param checkers a {@code List} of {@code PKIXCertPathChecker}s.
539 * May be {@code null}, in which case no additional checkers will be
540 * used.
541 * @throws ClassCastException if any of the elements in the list
542 * are not of type {@code java.security.cert.PKIXCertPathChecker}
543 * @see #getCertPathCheckers
544 */
545 public void setCertPathCheckers(List<PKIXCertPathChecker> checkers) {
546 if (checkers != null) {
547 List<PKIXCertPathChecker> tmpList = new ArrayList<>();
548 for (PKIXCertPathChecker checker : checkers) {
549 tmpList.add((PKIXCertPathChecker)checker.clone());
550 }
551 this.certPathCheckers = tmpList;
552 } else {
553 this.certPathCheckers = new ArrayList<>();
554 }
555 }
556
557 /**
558 * Returns the {@code List} of certification path checkers.
559 * The returned {@code List} is immutable, and each
560 * {@code PKIXCertPathChecker} in the {@code List} is cloned
561 * to protect against subsequent modifications.
562 *
563 * @return an immutable {@code List} of
564 * {@code PKIXCertPathChecker}s (may be empty, but not
565 * {@code null})
566 * @see #setCertPathCheckers
567 */
568 public List<PKIXCertPathChecker> getCertPathCheckers() {
569 List<PKIXCertPathChecker> tmpList = new ArrayList<>();
570 for (PKIXCertPathChecker ck : certPathCheckers) {
571 tmpList.add((PKIXCertPathChecker)ck.clone());
572 }
573 return Collections.unmodifiableList(tmpList);
574 }
575
576 /**
577 * Adds a {@code PKIXCertPathChecker} to the list of certification
578 * path checkers. See the {@link #setCertPathCheckers setCertPathCheckers}
579 * method for more details.
580 * <p>
581 * Note that the {@code PKIXCertPathChecker} is cloned to protect
582 * against subsequent modifications.
583 *
584 * @param checker a {@code PKIXCertPathChecker} to add to the list of
585 * checks. If {@code null}, the checker is ignored (not added to list).
586 */
587 public void addCertPathChecker(PKIXCertPathChecker checker) {
588 if (checker != null) {
589 certPathCheckers.add((PKIXCertPathChecker)checker.clone());
649 */
650 public void setTargetCertConstraints(CertSelector selector) {
651 if (selector != null)
652 certSelector = (CertSelector) selector.clone();
653 else
654 certSelector = null;
655 }
656
657 /**
658 * Makes a copy of this {@code PKIXParameters} object. Changes
659 * to the copy will not affect the original and vice versa.
660 *
661 * @return a copy of this {@code PKIXParameters} object
662 */
663 public Object clone() {
664 try {
665 PKIXParameters copy = (PKIXParameters)super.clone();
666
667 // must clone these because addCertStore, et al. modify them
668 if (certStores != null) {
669 copy.certStores = new ArrayList<>(certStores);
670 }
671 if (certPathCheckers != null) {
672 copy.certPathCheckers =
673 new ArrayList<>(certPathCheckers.size());
674 for (PKIXCertPathChecker checker : certPathCheckers) {
675 copy.certPathCheckers.add(
676 (PKIXCertPathChecker)checker.clone());
677 }
678 }
679
680 // other class fields are immutable to public, don't bother
681 // to clone the read-only fields.
682 return copy;
683 } catch (CloneNotSupportedException e) {
684 /* Cannot happen */
685 throw new InternalError(e.toString(), e);
686 }
687 }
688
689 /**
690 * Returns a formatted string describing the parameters.
691 *
692 * @return a formatted string describing the parameters.
693 */
|