use of com.unboundid.util.Nullable in project ldapsdk by pingidentity.
the class Task method parseDate.
/**
* Parses the provided set of values for the associated task property as a
* {@code Date}.
*
* @param p The task property with which the values are
* associated.
* @param values The provided values for the task property.
* @param defaultValue The default value to use if the provided object array
* is empty.
*
* @return The parsed {@code Date} value.
*
* @throws TaskException If there is a problem with the provided values.
*/
@Nullable()
protected static Date parseDate(@NotNull final TaskProperty p, @NotNull final List<Object> values, @Nullable final Date defaultValue) throws TaskException {
// be a problem.
if (values.isEmpty()) {
if (p.isRequired()) {
throw new TaskException(ERR_TASK_REQUIRED_PROPERTY_WITHOUT_VALUES.get(p.getDisplayName()));
} else {
return defaultValue;
}
}
// If there were multiple values, then that's always an error.
if (values.size() > 1) {
throw new TaskException(ERR_TASK_PROPERTY_NOT_MULTIVALUED.get(p.getDisplayName()));
}
// Make sure that the value can be interpreted as a Date.
final Date dateValue;
final Object o = values.get(0);
if (o instanceof Date) {
dateValue = (Date) o;
} else if (o instanceof String) {
try {
dateValue = StaticUtils.decodeGeneralizedTime((String) o);
} catch (final ParseException pe) {
throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_DATE.get(p.getDisplayName()), pe);
}
} else {
throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_DATE.get(p.getDisplayName()));
}
// If the task property has a set of allowed values, then make sure that the
// provided value is acceptable.
final Object[] allowedValues = p.getAllowedValues();
if (allowedValues != null) {
boolean found = false;
for (final Object allowedValue : allowedValues) {
if (dateValue.equals(allowedValue)) {
found = true;
break;
}
}
if (!found) {
throw new TaskException(ERR_TASK_PROPERTY_VALUE_NOT_ALLOWED.get(p.getDisplayName(), dateValue.toString()));
}
}
return dateValue;
}
use of com.unboundid.util.Nullable in project ldapsdk by pingidentity.
the class ManageCertificates method getIssuerCertificate.
/**
* Attempts to retrieve the issuer certificate for the provided certificate
* from the given keystore.
*
* @param certificate The certificate for which to retrieve the issuer
* certificate.
* @param keystore The keystore in which to look for the issuer
* certificate.
*
* @return The issuer certificate for the provided certificate, or
* {@code null} if the issuer certificate could not be retrieved.
*
* @throws Exception If a problem is encountered while trying to retrieve
* the issuer certificate.
*/
@Nullable()
private static X509Certificate getIssuerCertificate(@NotNull final X509Certificate certificate, @NotNull final KeyStore keystore) throws Exception {
final Enumeration<String> aliases = keystore.aliases();
while (aliases.hasMoreElements()) {
final String alias = aliases.nextElement();
Certificate[] certs = null;
if (hasCertificateAlias(keystore, alias)) {
final Certificate c = keystore.getCertificate(alias);
if (c == null) {
continue;
}
certs = new Certificate[] { c };
} else if (hasKeyAlias(keystore, alias)) {
certs = keystore.getCertificateChain(alias);
}
if (certs != null) {
for (final Certificate c : certs) {
final X509Certificate xc = new X509Certificate(c.getEncoded());
if (xc.isIssuerFor(certificate)) {
return xc;
}
}
}
}
return null;
}
use of com.unboundid.util.Nullable in project ldapsdk by pingidentity.
the class ManageCertificates method getPrivateKeyPassword.
/**
* Retrieves the password needed to access the private key.
*
* @param keystore The keystore that contains the target private
* key. This must not be {@code null}.
* @param alias The alias of the target private key. This must
* not be {@code null}.
* @param prefix The prefix string to use for the arguments. This
* may be {@code null} if no prefix is needed.
* @param keystorePassword The keystore password to use if no specific
* private key password was provided.
*
* @return The password needed to access the private key, or the provided
* keystore password if no arguments were provided to specify a
* different private key password.
*
* @throws LDAPException If a problem is encountered while trying to get the
* private key password.
*/
@Nullable()
private char[] getPrivateKeyPassword(@NotNull final KeyStore keystore, @NotNull final String alias, @Nullable final String prefix, @Nullable final char[] keystorePassword) throws LDAPException {
final String prefixDash;
if (prefix == null) {
prefixDash = "";
} else {
prefixDash = prefix + '-';
}
final StringArgument privateKeyPasswordArgument = subCommandParser.getStringArgument(prefixDash + "private-key-password");
if ((privateKeyPasswordArgument != null) && privateKeyPasswordArgument.isPresent()) {
final char[] pkPasswordChars = privateKeyPasswordArgument.getValue().toCharArray();
if ((pkPasswordChars.length < 6) && (!(hasCertificateAlias(keystore, alias) || hasKeyAlias(keystore, alias)))) {
throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_GET_PK_PW_TOO_SHORT.get());
}
return pkPasswordChars;
}
final FileArgument privateKeyPasswordFileArgument = subCommandParser.getFileArgument(prefixDash + "private-key-password-file");
if ((privateKeyPasswordFileArgument != null) && privateKeyPasswordFileArgument.isPresent()) {
final File f = privateKeyPasswordFileArgument.getValue();
try {
final char[] passwordChars = getPasswordFileReader().readPassword(f);
if (passwordChars.length < 6) {
throw new LDAPException(ResultCode.PARAM_ERROR, ERR_MANAGE_CERTS_GET_PK_PW_EMPTY_FILE.get(f.getAbsolutePath()));
}
return passwordChars;
} catch (final LDAPException e) {
Debug.debugException(e);
throw e;
} catch (final Exception e) {
Debug.debugException(e);
throw new LDAPException(ResultCode.LOCAL_ERROR, ERR_MANAGE_CERTS_GET_PK_PW_ERROR_READING_FILE.get(f.getAbsolutePath(), StaticUtils.getExceptionMessage(e)), e);
}
}
final BooleanArgument promptArgument = subCommandParser.getBooleanArgument("prompt-for-" + prefixDash + "private-key-password");
if ((promptArgument != null) && promptArgument.isPresent()) {
out();
try {
if ((hasKeyAlias(keystore, alias) || hasCertificateAlias(keystore, alias)) && (!"new".equals(prefix)) && (!"destination".equals(prefix))) {
// This means that the private key already exists, so we just need to
// prompt once.
final String prompt;
if ("current".equals(prefix)) {
prompt = INFO_MANAGE_CERTS_GET_PK_PW_CURRENT_PROMPT.get(alias);
} else {
prompt = INFO_MANAGE_CERTS_GET_PK_PW_EXISTING_PROMPT.get(alias);
}
return promptForPassword(prompt, false);
} else {
// prompt twice.
while (true) {
final String prompt;
if ("new".equals(prefix)) {
prompt = INFO_MANAGE_CERTS_GET_PK_PW_NEW_PROMPT.get();
} else {
prompt = INFO_MANAGE_CERTS_GET_PK_PW_NEW_PROMPT_1.get(alias);
}
final char[] pwChars = promptForPassword(prompt, false);
if (pwChars.length < 6) {
wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GET_PK_PW_TOO_SHORT.get());
err();
continue;
}
final char[] confirmChars = promptForPassword(INFO_MANAGE_CERTS_GET_PK_PW_NEW_PROMPT_2.get(), true);
if (Arrays.equals(pwChars, confirmChars)) {
Arrays.fill(confirmChars, '\u0000');
return pwChars;
} else {
wrapErr(0, WRAP_COLUMN, ERR_MANAGE_CERTS_GET_PK_PW_PROMPT_MISMATCH.get());
err();
}
}
}
} catch (final LDAPException le) {
Debug.debugException(le);
throw le;
} catch (final Exception e) {
Debug.debugException(e);
throw new LDAPException(ResultCode.LOCAL_ERROR, ERR_MANAGE_CERTS_GET_PK_PW_PROMPT_ERROR.get(alias, StaticUtils.getExceptionMessage(e)), e);
}
}
return keystorePassword;
}
use of com.unboundid.util.Nullable in project ldapsdk by pingidentity.
the class APITestCase method testNullability.
/**
* Ensures that all non-primitive fields, constructor and method parameters,
* and method return values are marked with either the {@code NotNull} or
* {@code Nullable} annotation types.
*
* @param c The class to be examined.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test(dataProvider = "sdkClasses")
public void testNullability(final Class<?> c) throws Exception {
// codebase, then it won't be annotated.
if (c.isSynthetic()) {
return;
}
// annotated.
if (c.isEnum() && c.getName().endsWith("Messages")) {
try {
c.getDeclaredField("defaultText");
return;
} catch (final Exception e) {
// Ignore this.
}
}
// If the class is the dynamically generated Version file, then ignore it.
if (c.equals(Version.class)) {
return;
}
final List<String> errors = new ArrayList<>();
// Make sure that all fields are annotated properly.
for (final Field field : c.getDeclaredFields()) {
// If the field is dynamically generated, then it won't be annotated.
if (field.isSynthetic()) {
continue;
}
// Ignore enum constants.
if (field.isEnumConstant()) {
continue;
}
final Annotation notNullAnnotation = field.getAnnotation(NotNull.class);
final Annotation nullableAnnotation = field.getAnnotation(Nullable.class);
if (field.getType().isPrimitive()) {
if (notNullAnnotation != null) {
errors.add("Primitive field '" + field.getName() + "' is marked @NotNull.");
}
if (nullableAnnotation != null) {
errors.add("Primitive field '" + field.getName() + "' is marked @Nullable.");
}
} else {
if (notNullAnnotation != null) {
if (nullableAnnotation != null) {
errors.add("Field '" + field.getName() + "' is marked with both @NotNull and @Nullable.");
}
} else if (nullableAnnotation == null) {
errors.add("Non-primitive field '" + field.getName() + "' is not marked with either @NotNull or @Nullable.");
}
}
}
// validation entirely for enums.
if (!c.isEnum()) {
for (final Constructor<?> constructor : c.getDeclaredConstructors()) {
// annotated.
if (constructor.isSynthetic()) {
continue;
}
final Class<?>[] parameterTypes = constructor.getParameterTypes();
final Annotation[][] parameterAnnotations = constructor.getParameterAnnotations();
if (parameterTypes.length != parameterAnnotations.length) {
// local classes. In that case, we can't check it.
continue;
}
for (int i = 0; i < parameterTypes.length; i++) {
boolean isNotNull = false;
boolean isNullable = false;
for (final Annotation a : parameterAnnotations[i]) {
if (a.annotationType().equals(NotNull.class)) {
isNotNull = true;
} else if (a.annotationType().equals(Nullable.class)) {
isNullable = true;
}
}
if (parameterTypes[i].isPrimitive()) {
if (isNotNull) {
errors.add("Constructor " + constructor + " parameter " + i + " is primitive but is marked @NotNull.");
}
if (isNullable) {
errors.add("Constructor " + constructor + " parameter " + i + " is primitive but is marked @Nullable.");
}
} else {
if (isNotNull) {
if (isNullable) {
errors.add("Constructor " + constructor + " parameter " + i + " is marked both @NotNull and @Nullable.");
}
} else if (!isNullable) {
// exist in the codebase, they won't be annotated.
if (c.isEnum() && (parameterTypes.length == 2) && (parameterTypes[0].equals(String.class) && parameterTypes[1].equals(Integer.TYPE))) {
continue;
}
errors.add("Constructor " + constructor + " parameter " + i + " is not primitive but is not marked @NotNull or " + "@Nullable.");
}
}
}
}
}
// properly.
for (final Method method : c.getDeclaredMethods()) {
// values() methods that are generated by the compiler.
if (c.isEnum()) {
if (method.getName().equals("valueOf") && (method.getParameterTypes().length == 1) && (method.getParameterTypes()[0].equals(String.class))) {
continue;
}
if (method.getName().equals("values") && (method.getParameterTypes().length == 0)) {
continue;
}
}
// annotated.
if (method.isSynthetic()) {
continue;
}
// Check the method return type.
final Class<?> returnType = method.getReturnType();
final Annotation notNullReturnTypeAnnotation = method.getAnnotation(NotNull.class);
final Annotation nullableReturnTypeAnnotation = method.getAnnotation(Nullable.class);
if (returnType.equals(Void.TYPE)) {
if (notNullReturnTypeAnnotation != null) {
errors.add("Method " + method + " has a void return type but is " + "marked @NotNull.");
}
if (nullableReturnTypeAnnotation != null) {
errors.add("Method " + method + " has a void return type but is " + "marked @Nullable.");
}
} else if (returnType.isPrimitive()) {
if (notNullReturnTypeAnnotation != null) {
errors.add("Method " + method + " has a primitive return type but " + "is marked @NotNull.");
}
if (nullableReturnTypeAnnotation != null) {
errors.add("Method " + method + " has a primitive return type but " + "is marked @Nullable.");
}
} else if (notNullReturnTypeAnnotation == null) {
if (nullableReturnTypeAnnotation == null) {
errors.add("Method " + method + " has a non-primitive return " + "type but is not marked @NotNull or @Nullable.");
}
} else if (nullableReturnTypeAnnotation != null) {
errors.add("Method " + method + " is declared both @NotNull and " + "@Nullable.");
}
// Check the method parameters.
final Class<?>[] parameterTypes = method.getParameterTypes();
final Annotation[][] parameterAnnotations = method.getParameterAnnotations();
if (parameterTypes.length != parameterAnnotations.length) {
// local classes. In that case, we can't check it.
continue;
}
for (int i = 0; i < parameterTypes.length; i++) {
boolean isNotNull = false;
boolean isNullable = false;
for (final Annotation a : parameterAnnotations[i]) {
if (a.annotationType().equals(NotNull.class)) {
isNotNull = true;
} else if (a.annotationType().equals(Nullable.class)) {
isNullable = true;
}
}
if (parameterTypes[i].isPrimitive()) {
if (isNotNull) {
errors.add("Method " + method + " parameter " + i + " is primitive but is marked @NotNull.");
}
if (isNullable) {
errors.add("Method " + method + " parameter " + i + " is primitive but is marked @Nullable.");
}
} else {
if (isNotNull) {
if (isNullable) {
errors.add("Method " + method + " parameter " + i + " is marked both @NotNull and @Nullable.");
}
} else if (!isNullable) {
// exist in the codebase, they won't be annotated.
if (c.isEnum() && (parameterTypes.length == 2) && (parameterTypes[0].equals(String.class) && parameterTypes[1].equals(Integer.TYPE))) {
continue;
}
errors.add("Method " + method + " parameter " + i + " is not primitive but is not marked @NotNull or " + "@Nullable.");
}
}
}
}
if (!errors.isEmpty()) {
fail("Found nullability errors in class " + c.getName() + ": " + StaticUtils.concatenateStrings(null, StaticUtils.EOL, null, null, null, errors));
}
}
use of com.unboundid.util.Nullable in project ldapsdk by pingidentity.
the class LDIFModify method updateEntry.
/**
* Updates the provided entry with any appropriate changes.
*
* @param entry
* The entry to be processed. It must not be {@code null}.
* @param addAndSubsequentChangeRecords
* A map that will be updated with add change records for a given
* entry, along with any subsequent change records that apply to
* the entry after it has been added. It must not be
* {@code null}, must be empty, and must be updatable.
* @param deletedEntryDNs
* A map that will be updated with the DNs of any entries that
* are targeted by delete modifications and that have not been
* previously added or renamed. It must not be {@code null},
* must be empty, and must be updatable.
* @param modifyChangeRecords
* A map that will be updated with any modify change records
* that target an entry that has not been targeted by any other
* type of change. It must not be {@code null}, must be empty,
* and must be updatable.
* @param modifyDNAndSubsequentChangeRecords
* A map that will be updated with any change records for modify
* DN operations that target a given entry, and any subsequent
* operations that target the entry with its new DN. It must not
* be {@code null}, must be empty, and must be updatable.
* @param comment
* A buffer that should be updated with any comment to be
* included in the output, even if the entry is not altered. It
* must not be {@code null}, but it should be empty.
* @param resultCode
* A reference to the final result code that should be used for
* the tool. This may be updated if an error occurred during
* processing and no value is already set. It must not be
* {@code null}, but is allowed to have no value assigned.
* @param entriesUpdated
* A counter that should be incremented if any changes are
* applied (including deleting the entry). It should not be
* updated if none of the changes are applicable to the provided
* entry. It must not be {@code null}.
*
* @return The provided entry if none of the changes are applicable, an
* updated entry if changes are applied, or {@code null} if the entry
* should be deleted and therefore omitted from the target LDIF file.
*/
@Nullable()
private Entry updateEntry(@NotNull final Entry entry, @NotNull final Map<DN, List<LDIFChangeRecord>> addAndSubsequentChangeRecords, @NotNull final Map<DN, Boolean> deletedEntryDNs, @NotNull final Map<DN, List<LDIFModifyChangeRecord>> modifyChangeRecords, @NotNull final Map<DN, ObjectPair<DN, List<LDIFChangeRecord>>> modifyDNAndSubsequentChangeRecords, @NotNull final StringBuilder comment, @NotNull final AtomicReference<ResultCode> resultCode, @NotNull final AtomicLong entriesUpdated) {
// Get the parsed DN for the entry. If that fails, then we'll just return
// the provided entry along with a comment explaining that its DN could not
// be parsed.
final DN entryDN;
try {
entryDN = entry.getParsedDN();
} catch (final LDAPException e) {
Debug.debugException(e);
resultCode.compareAndSet(null, e.getResultCode());
appendComment(comment, ERR_LDIFMODIFY_CANNOT_PARSE_ENTRY_DN.get(e.getMessage()), true);
return entry;
}
// the entry as deleted and return null.
if (deletedEntryDNs.containsKey(entryDN)) {
deletedEntryDNs.put(entryDN, Boolean.TRUE);
createChangeRecordComment(comment, INFO_LDIFMODIFY_APPLIED_DELETE.get(), entry, false);
entriesUpdated.incrementAndGet();
return null;
}
// See if there is a delete change record for one of the entry's superiors.
// If so, then mark the entry as deleted and return null.
DN parentDN = entryDN.getParent();
while (parentDN != null) {
if (deletedEntryDNs.containsKey(parentDN)) {
createChangeRecordComment(comment, INFO_LDIFMODIFY_APPLIED_DELETE_OF_ANCESTOR.get(parentDN.toString()), entry, false);
entriesUpdated.incrementAndGet();
return null;
}
parentDN = parentDN.getParent();
}
// See if there are any modify change records that target the entry. If so,
// then apply those modifications.
Entry updatedEntry = entry;
final AtomicBoolean isUpdated = new AtomicBoolean(false);
final List<String> errors = new ArrayList<>();
final List<LDIFModifyChangeRecord> modRecords = modifyChangeRecords.remove(entryDN);
if (modRecords != null) {
for (final LDIFModifyChangeRecord r : modRecords) {
updatedEntry = applyModification(updatedEntry, r, isUpdated, resultCode, comment);
}
}
// See if the entry was targeted by a modify DN operation. If so, then
// rename the entry and see if there are any follow-on modifications.
final ObjectPair<DN, List<LDIFChangeRecord>> modDNRecords = modifyDNAndSubsequentChangeRecords.remove(entryDN);
if (modDNRecords != null) {
for (final LDIFChangeRecord r : modDNRecords.getSecond()) {
if (r instanceof LDIFModifyDNChangeRecord) {
final LDIFModifyDNChangeRecord modDNChangeRecord = (LDIFModifyDNChangeRecord) r;
updatedEntry = applyModifyDN(updatedEntry, entryDN, modDNRecords.getFirst(), modDNChangeRecord.deleteOldRDN());
createChangeRecordComment(comment, INFO_LDIFMODIFY_APPLIED_MODIFY_DN.get(), r, false);
isUpdated.set(true);
} else {
updatedEntry = applyModification(updatedEntry, (LDIFModifyChangeRecord) r, isUpdated, resultCode, comment);
}
}
}
// See if there is an add change record that targets the same entry. If so,
// then the add won't be processed but maybe subsequent changes will be.
final List<LDIFChangeRecord> addAndMods = addAndSubsequentChangeRecords.remove(entryDN);
if (addAndMods != null) {
for (final LDIFChangeRecord r : addAndMods) {
if (r instanceof LDIFAddChangeRecord) {
resultCode.compareAndSet(null, ResultCode.ENTRY_ALREADY_EXISTS);
createChangeRecordComment(comment, ERR_LDIFMODIFY_NOT_ADDING_EXISTING_ENTRY.get(), r, true);
} else {
updatedEntry = applyModification(updatedEntry, (LDIFModifyChangeRecord) r, isUpdated, resultCode, comment);
}
}
}
if (isUpdated.get()) {
entriesUpdated.incrementAndGet();
} else {
if (comment.length() > 0) {
appendComment(comment, StaticUtils.EOL, false);
appendComment(comment, StaticUtils.EOL, false);
}
appendComment(comment, INFO_LDIFMODIFY_ENTRY_NOT_UPDATED.get(), false);
}
return updatedEntry;
}
Aggregations