132 files modified
5 files added
| | |
| | | * |
| | | * Copyright 2008 Sun Microsystems, Inc. |
| | | * Portions Copyright 2015-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.forgerock.opendj.config.client; |
| | | |
| | |
| | | * @return Returns the first exception that caused this exception. |
| | | */ |
| | | @Override |
| | | public PropertyException getCause() { |
| | | public synchronized PropertyException getCause() { |
| | | return causes.iterator().next(); |
| | | } |
| | | |
| | |
| | | * |
| | | * Copyright 2008 Sun Microsystems, Inc. |
| | | * Portions Copyright 2013-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.forgerock.opendj.config.dsconfig; |
| | | |
| | |
| | | if (major == version.major) { |
| | | if (minor == version.minor) { |
| | | if (point == version.point) { |
| | | if (rev == version.rev) { |
| | | return 0; |
| | | } else if (rev.compareTo(version.rev) < 0) { |
| | | return -1; |
| | | } |
| | | // Compares the revisions as strings: they are VCS revisions, not numbers. |
| | | return Integer.signum(rev.compareTo(version.rev)); |
| | | } else if (point < version.point) { |
| | | return -1; |
| | | } |
| New file |
| | |
| | | /* |
| | | * The contents of this file are subject to the terms of the Common Development and |
| | | * Distribution License (the License). You may not use this file except in compliance with the |
| | | * License. |
| | | * |
| | | * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the |
| | | * specific language governing permission and limitations under the License. |
| | | * |
| | | * When distributing Covered Software, include this CDDL Header Notice in each file and include |
| | | * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL |
| | | * Header, with the fields enclosed by brackets [] replaced by your own identifying |
| | | * information: "Portions copyright [year] [name of copyright owner]". |
| | | * |
| | | * Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.forgerock.opendj.config.dsconfig; |
| | | |
| | | import org.forgerock.testng.ForgeRockTestCase; |
| | | import org.testng.Assert; |
| | | import org.testng.annotations.Test; |
| | | |
| | | @Test(groups = { "precommit", "config" }) |
| | | public class BuildVersionTest extends ForgeRockTestCase { |
| | | |
| | | @Test |
| | | public void testEqualRevisionsCompareEqual() { |
| | | // Two distinct String instances holding the same revision: the revisions must be compared |
| | | // by value, not by reference. |
| | | final String rev = "abcdef"; |
| | | final String sameRev = new StringBuilder(rev).toString(); |
| | | Assert.assertEquals(new BuildVersion(4, 0, 0, rev).compareTo(new BuildVersion(4, 0, 0, sameRev)), 0); |
| | | } |
| | | |
| | | @Test |
| | | public void testRevisionsOrderVersionsWhichAreOtherwiseEqual() { |
| | | Assert.assertEquals(new BuildVersion(4, 0, 0, "aaa").compareTo(new BuildVersion(4, 0, 0, "bbb")), -1); |
| | | Assert.assertEquals(new BuildVersion(4, 0, 0, "bbb").compareTo(new BuildVersion(4, 0, 0, "aaa")), 1); |
| | | } |
| | | |
| | | @Test |
| | | public void testVersionNumbersTakePrecedenceOverRevisions() { |
| | | Assert.assertEquals(new BuildVersion(3, 9, 9, "zzz").compareTo(new BuildVersion(4, 0, 0, "aaa")), -1); |
| | | Assert.assertEquals(new BuildVersion(4, 1, 0, "aaa").compareTo(new BuildVersion(4, 0, 9, "zzz")), 1); |
| | | Assert.assertEquals(new BuildVersion(4, 0, 1, "aaa").compareTo(new BuildVersion(4, 0, 0, "zzz")), 1); |
| | | } |
| | | } |
| | |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2011-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | |
| | | package com.forgerock.opendj.util; |
| | |
| | | this.isKeyChar = true; |
| | | this.isCompatKeyChar = true; |
| | | this.decimalValue = -1; |
| | | if (c >= 'a' && c <= 'f') { |
| | | if (c <= 'f') { |
| | | this.isHexChar = true; |
| | | this.hexValue = c - 87; |
| | | } else { |
| | |
| | | this.isKeyChar = true; |
| | | this.isCompatKeyChar = true; |
| | | this.decimalValue = -1; |
| | | if (c >= 'A' && c <= 'F') { |
| | | if (c <= 'F') { |
| | | this.isHexChar = true; |
| | | this.hexValue = c - 55; |
| | | } else { |
| | |
| | | * |
| | | * Copyright 2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2015 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package com.forgerock.opendj.util; |
| | | |
| | |
| | | if (canMapToSpace(buffer, trim)) { |
| | | buffer.append(SPACE_CHAR); |
| | | } |
| | | } else if ((b >= '\u0000' && b <= '\u0008') || (b >= '\u000E' && b <= '\u001F') |
| | | } else if (b <= '\u0008' || (b >= '\u000E' && b <= '\u001F') |
| | | || b == '\u007F') { |
| | | // These characters are mapped to nothing and hence not |
| | | // copied over.. |
| | |
| | | builder.append(StaticUtils.byteToLowerHex(b)); |
| | | } |
| | | } else { |
| | | // NUL needs no test here: it is already handled by the c < ' ' branch above. |
| | | if ((c == ' ' && si == length - 1) |
| | | || (c == '"' || c == '+' || c == ',' || c == ';' || c == '<' |
| | | || c == '>' || c == '\\' || c == '\u0000' || c == '=')) { |
| | | || c == '>' || c == '\\' || c == '=')) { |
| | | builder.append('\\'); |
| | | } |
| | | builder.append(c); |
| | |
| | | * information: "Portions Copyright [year] [name of copyright owner]". |
| | | * |
| | | * Copyright 2013-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | |
| | | package org.forgerock.opendj.ldap; |
| | |
| | | * requested by the user. |
| | | */ |
| | | return new Iterable<Attribute>() { |
| | | private boolean hasNextMustIterate = true; |
| | | private final Iterator<Attribute> iterator = entry.getAllAttributes().iterator(); |
| | | private Attribute next = null; |
| | | |
| | | @Override |
| | | public Iterator<Attribute> iterator() { |
| | | /* |
| | | * The iteration state belongs to the iterator, not to this Iterable: |
| | | * keeping it here is what allows the Iterable to be iterated more than |
| | | * once, including by the toString() below. |
| | | */ |
| | | return new Iterator<Attribute>() { |
| | | private boolean hasNextMustIterate = true; |
| | | private final Iterator<Attribute> iterator = |
| | | entry.getAllAttributes().iterator(); |
| | | private Attribute next; |
| | | |
| | | @Override |
| | | public boolean hasNext() { |
| | | if (hasNextMustIterate) { |
| | |
| | | |
| | | @Override |
| | | public int compareTo(final GeneralizedTime o) { |
| | | final Long timeMS1 = getTimeInMillis(); |
| | | final Long timeMS2 = o.getTimeInMillis(); |
| | | return timeMS1.compareTo(timeMS2); |
| | | final long timeMS1 = getTimeInMillis(); |
| | | final long timeMS2 = o.getTimeInMillis(); |
| | | return Long.compare(timeMS1, timeMS2); |
| | | } |
| | | |
| | | @Override |
| | |
| | | * information: "Portions Copyright [year] [name of copyright owner]". |
| | | * |
| | | * Portions copyright 2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | /* |
| | | * Licensed to the Apache Software Foundation (ASF) under one or more |
| | |
| | | if (!inet6Address.endsWith(octet)) { |
| | | return false; |
| | | } |
| | | if (index > octets.length - 1 || index > 6) { // CHECKSTYLE IGNORE MagicNumber |
| | | if (index > 6) { // CHECKSTYLE IGNORE MagicNumber |
| | | // IPV4 occupies last two octets |
| | | return false; |
| | | } |
| | |
| | | // nested element. |
| | | reader.readStartSequence(); |
| | | final int warningChoiceValue = (0x7F & reader.peekType()); |
| | | if (warningChoiceValue < 0 |
| | | || warningChoiceValue >= PasswordPolicyWarningType.values().length) { |
| | | if (warningChoiceValue >= PasswordPolicyWarningType.values().length) { |
| | | final LocalizableMessage message = |
| | | ERR_PWPOLICYRES_INVALID_WARNING_TYPE.get(byteToHex(reader |
| | | .peekType())); |
| | |
| | | * information: "Portions Copyright [year] [name of copyright owner]". |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | * Portions copyright 2011-2016 ForgeRock AS. |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | |
| | | if (builder.structuralObjectClassOID == null || builder.structuralObjectClassOID.isEmpty()) { |
| | | throw new IllegalArgumentException("A structural class OID must be specified."); |
| | | } |
| | | if (builder.requiredAttributes == null || builder.requiredAttributes.isEmpty()) { |
| | | if (builder.requiredAttributes.isEmpty()) { |
| | | throw new IllegalArgumentException("Required attribute must be specified."); |
| | | } |
| | | |
| | |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2011-2016 ForgeRock AS. |
| | | * Portions Copyright 2024 3A Systems, LLC. |
| | | * Portions Copyright 2024-2026 3A Systems, LLC. |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | | |
| | |
| | | && (c = reader.read()) != ' ' |
| | | && c != ')' |
| | | && (c != '\'' || !enclosingQuote)) { |
| | | if (length == 0 && !isAlpha(c)) { |
| | | throw DecodeException.error( |
| | | ERR_ATTR_SYNTAX_ILLEGAL_CHAR_IN_STRING_OID1.get(c, reader.pos() - 1)); |
| | | } |
| | | |
| | | // The first character was already required to be alphabetic by the enclosing |
| | | // test, so only the key-character check is needed here. |
| | | if (!isKeyChar(c, allowCompatChars)) { |
| | | throw DecodeException.error( |
| | | ERR_ATTR_SYNTAX_ILLEGAL_CHAR_IN_STRING_OID1.get(c, reader.pos() - 1)); |
| | |
| | | } |
| | | length++; |
| | | } |
| | | |
| | | if (length == 0) { |
| | | throw DecodeException.error( |
| | | ERR_ATTR_SYNTAX_OID_NO_VALUE1.get(reader.pos() - 1)); |
| | | } |
| | | } else if (isAlpha(c)) { |
| | | // This must be an attribute description. In this case, we will |
| | | // only accept alphabetic characters, numeric digits, and the hyphen. |
| | |
| | | && c != ')' |
| | | && c != '{' |
| | | && (c != '\'' || !enclosingQuote)) { |
| | | if (length == 0 && !isAlpha(c)) { |
| | | throw DecodeException.error( |
| | | ERR_ATTR_SYNTAX_ILLEGAL_CHAR_IN_STRING_OID1.get(c, reader.pos() - 1)); |
| | | } |
| | | |
| | | // The first character was already required to be alphabetic by the enclosing |
| | | // test, so only the key-character check is needed here. |
| | | if (!isKeyChar(c, allowCompatChars)) { |
| | | throw DecodeException.error( |
| | | ERR_ATTR_SYNTAX_ILLEGAL_CHAR_IN_STRING_OID1.get(c, reader.pos() - 1)); |
| | |
| | | * information: "Portions Copyright [year] [name of copyright owner]". |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | * Portions copyright 2012-2016 ForgeRock AS. |
| | | */ |
| | | package org.forgerock.opendj.ldap.schema; |
| | |
| | | case '3': |
| | | case '4': |
| | | case '5': |
| | | // There must be at least two more characters, and the next one |
| | | // must be a digit between 0 and 9. |
| | | if (length < 11) { |
| | | final LocalizableMessage message = |
| | | ERR_ATTR_SYNTAX_UTC_TIME_INVALID_CHAR.get(valueString, String.valueOf(m1), |
| | | 8); |
| | | invalidReason.append(message); |
| | | return false; |
| | | } |
| | | |
| | | // A length below 11 was already rejected at the top of this method, so the next |
| | | // character is present and must be a digit between 0 and 9. |
| | | switch (valueString.charAt(9)) { |
| | | case '0': |
| | | case '1': |
| | |
| | | * |
| | | * Copyright 2006-2009 Sun Microsystems, Inc. |
| | | * Portions Copyright 2013-2015 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.forgerock.opendj.ldif; |
| | | |
| | |
| | | } |
| | | |
| | | private void initialize(String[] arguments, int lineNumber) throws DecodeException { |
| | | if (arguments.length < 0 || arguments.length > 2) { |
| | | if (arguments.length > 2) { |
| | | throw DecodeException.fatalError(ERR_ENTRY_GENERATOR_TAG_INVALID_ARGUMENT_RANGE_COUNT.get( |
| | | getName(), lineNumber, 0, 2, arguments.length)); |
| | | } |
| | |
| | | * information: "Portions copyright [year] [name of copyright owner]". |
| | | * |
| | | * Copyright 2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.forgerock.opendj.security; |
| | | |
| | |
| | | } |
| | | |
| | | private static ConnectionFactory newLDIFConnectionFactory(final File ldifFile) throws IOException { |
| | | try (LDIFEntryReader reader = new LDIFEntryReader(new FileReader(ldifFile)).setSchema(SCHEMA)) { |
| | | try (FileReader ldifFileReader = new FileReader(ldifFile); |
| | | LDIFEntryReader reader = new LDIFEntryReader(ldifFileReader).setSchema(SCHEMA)) { |
| | | final MemoryBackend backend = new MemoryBackend(SCHEMA, reader).enableVirtualAttributes(true); |
| | | return newInternalConnectionFactory(new WriteLDIFOnUpdateRequestHandler(backend, ldifFile)); |
| | | } |
| New file |
| | |
| | | /* |
| | | * The contents of this file are subject to the terms of the Common Development and |
| | | * Distribution License (the License). You may not use this file except in compliance with the |
| | | * License. |
| | | * |
| | | * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the |
| | | * specific language governing permission and limitations under the License. |
| | | * |
| | | * When distributing Covered Software, include this CDDL Header Notice in each file and include |
| | | * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL |
| | | * Header, with the fields enclosed by brackets [] replaced by your own identifying |
| | | * information: "Portions copyright [year] [name of copyright owner]". |
| | | * |
| | | * Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.forgerock.opendj.ldap; |
| | | |
| | | import static org.fest.assertions.Assertions.assertThat; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | | import org.testng.annotations.Test; |
| | | |
| | | /** |
| | | * Test {@code AttributeFilter}. |
| | | */ |
| | | @SuppressWarnings("javadoc") |
| | | public final class AttributeFilterTestCase extends SdkTestCase { |
| | | |
| | | @Test |
| | | public void testFilteredViewCanBeIteratedMoreThanOnce() { |
| | | final Iterable<Attribute> attributes = filteredView().getAllAttributes(); |
| | | |
| | | final List<String> firstPass = namesOf(attributes); |
| | | assertThat(firstPass).isNotEmpty(); |
| | | assertThat(namesOf(attributes)).isEqualTo(firstPass); |
| | | } |
| | | |
| | | @Test |
| | | public void testFilteredViewCanBeIteratedAfterToString() { |
| | | final Iterable<Attribute> attributes = filteredView().getAllAttributes(); |
| | | |
| | | final List<String> expected = namesOf(attributes); |
| | | attributes.toString(); |
| | | assertThat(namesOf(attributes)).isEqualTo(expected); |
| | | } |
| | | |
| | | private Entry filteredView() { |
| | | final Entry entry = |
| | | new LinkedHashMapEntry("dn: cn=test", "objectClass: top", "objectClass: person", |
| | | "cn: test", "sn: user"); |
| | | return new AttributeFilter().filteredViewOf(entry); |
| | | } |
| | | |
| | | private List<String> namesOf(final Iterable<Attribute> attributes) { |
| | | final List<String> names = new ArrayList<>(); |
| | | for (final Attribute attribute : attributes) { |
| | | names.add(attribute.getAttributeDescriptionAsString()); |
| | | } |
| | | return names; |
| | | } |
| | | } |
| | |
| | | * information: "Portions Copyright [year] [name of copyright owner]". |
| | | * |
| | | * Copyright 2015-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.forgerock.opendj.maven.doc; |
| | | |
| | |
| | | */ |
| | | private void copyResources() throws IOException { |
| | | for (String file : resourceFiles) { |
| | | InputStream original = this.getClass().getResourceAsStream("/config-ref/" + file); |
| | | InputStream original = GenerateConfigurationReferenceMojo.class.getResourceAsStream("/config-ref/" + file); |
| | | File copy = new File(outputDirectory, file); |
| | | copyInputStreamToFile(original, copy); |
| | | } |
| | |
| | | * information: "Portions Copyright [year] [name of copyright owner]". |
| | | * |
| | | * Copyright 2015-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.forgerock.opendj.maven.doc; |
| | | |
| | |
| | | */ |
| | | private Map<String, String> getAciDescriptions() throws IOException { |
| | | final Map<String, String> descriptions = new HashMap<>(); |
| | | BufferedReader reader = new BufferedReader(new FileReader(configDotLdif)); |
| | | String line; |
| | | while ((line = reader.readLine()) != null) { |
| | | if (line.startsWith("# @aci ")) { |
| | | String[] split = line.replace("# @aci ", "").split(":", 2); |
| | | descriptions.put(split[0], split[1]); |
| | | try (FileReader fileReader = new FileReader(configDotLdif); |
| | | BufferedReader reader = new BufferedReader(fileReader)) { |
| | | String line; |
| | | while ((line = reader.readLine()) != null) { |
| | | if (line.startsWith("# @aci ")) { |
| | | String[] split = line.replace("# @aci ", "").split(":", 2); |
| | | descriptions.put(split[0], split[1]); |
| | | } |
| | | } |
| | | } |
| | | return descriptions; |
| | |
| | | * @throws IOException Failed to read the LDIF. |
| | | */ |
| | | private void readAcis(Map<String, String> descriptions) throws IOException { |
| | | LDIFEntryReader reader = new LDIFEntryReader(new FileInputStream(configDotLdif)); |
| | | reader.setIncludeBranch(DN.valueOf("cn=Access Control Handler,cn=config")); |
| | | try (FileInputStream configStream = new FileInputStream(configDotLdif); |
| | | LDIFEntryReader reader = new LDIFEntryReader(configStream)) { |
| | | reader.setIncludeBranch(DN.valueOf("cn=Access Control Handler,cn=config")); |
| | | |
| | | while (reader.hasNext()) { |
| | | Entry entry = reader.readEntry(); |
| | | for (String attribute : entry.parseAttribute("ds-cfg-global-aci").asSetOfString()) { |
| | | Aci aci = new Aci(); |
| | | aci.name = getName(attribute); |
| | | if (descriptions != null) { |
| | | aci.description = descriptions.get(aci.name); |
| | | while (reader.hasNext()) { |
| | | Entry entry = reader.readEntry(); |
| | | for (String attribute : entry.parseAttribute("ds-cfg-global-aci").asSetOfString()) { |
| | | Aci aci = new Aci(); |
| | | aci.name = getName(attribute); |
| | | if (descriptions != null) { |
| | | aci.description = descriptions.get(aci.name); |
| | | } |
| | | aci.definition = AsciidocConverterUtils.escapeVerticalLine(attribute); |
| | | allGlobalAcis.add(aci); |
| | | } |
| | | aci.definition = AsciidocConverterUtils.escapeVerticalLine(attribute); |
| | | allGlobalAcis.add(aci); |
| | | } |
| | | } |
| | | } |
| | |
| | | * information: "Portions Copyright [year] [name of copyright owner]". |
| | | * |
| | | * Copyright 2015-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.forgerock.opendj.maven.doc; |
| | | |
| | |
| | | * @throws IOException Failed to make the copy. |
| | | */ |
| | | static void copyFile(File original, File copy) throws IOException { |
| | | copyInputStreamToFile(new FileInputStream(original), copy); |
| | | try (InputStream input = new FileInputStream(original)) { |
| | | copyInputStreamToFile(input, copy); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Copies the content of the original input stream to the copy. |
| | | * <p> |
| | | * The original input stream is closed on return, whether the copy succeeded or not. |
| | | * @param original The original input stream. |
| | | * @param copy The copy. |
| | | * @throws IOException Failed to make the copy. |
| | |
| | | if (original == null) { |
| | | throw new IOException("Could not read input to copy."); |
| | | } |
| | | createFile(copy); |
| | | try (OutputStream outputStream = new FileOutputStream(copy)) { |
| | | int bytesRead; |
| | | byte[] buffer = new byte[4096]; |
| | | while ((bytesRead = original.read(buffer)) > 0) { |
| | | outputStream.write(buffer, 0, bytesRead); |
| | | try { |
| | | createFile(copy); |
| | | try (OutputStream outputStream = new FileOutputStream(copy)) { |
| | | int bytesRead; |
| | | byte[] buffer = new byte[4096]; |
| | | while ((bytesRead = original.read(buffer)) > 0) { |
| | | outputStream.write(buffer, 0, bytesRead); |
| | | } |
| | | } |
| | | } finally { |
| | | closeSilently(original); |
| | |
| | | // assign the DSMLv2 schema for validation |
| | | if(schema==null) |
| | | { |
| | | URL url = getClass().getResource("/resources/DSMLv2.xsd"); |
| | | URL url = DSMLServlet.class.getResource("/resources/DSMLv2.xsd"); |
| | | if ( url != null ) { |
| | | SchemaFactory sf = SchemaFactory.newInstance(W3C_XML_SCHEMA_NS_URI); |
| | | schema = sf.newSchema(url); |
| | |
| | | * Header, with the fields enclosed by brackets [] replaced by your own identifying |
| | | * information: "Portions Copyright [year] [name of copyright owner]". |
| | | * |
| | | * Copyright 2024 3A Systems LLC. |
| | | * Copyright 2024-2026 3A Systems LLC. |
| | | */ |
| | | |
| | | package org.openidentityplatform.opendj.embedded; |
| | |
| | | public class Config { |
| | | |
| | | private final String CONFIG_PREFIX = Config.class.getPackage().getName(); |
| | | private int port = Integer.parseInt(System.getProperty(CONFIG_PREFIX + ".port", "1389")); |
| | | private int port = intProperty(CONFIG_PREFIX + ".port", "1389"); |
| | | |
| | | private int adminPort = Integer.parseInt(System.getProperty(CONFIG_PREFIX + ".admin_port", "4444")); |
| | | private int adminPort = intProperty(CONFIG_PREFIX + ".admin_port", "4444"); |
| | | |
| | | private String adminPassword = System.getProperty(CONFIG_PREFIX + ".password", "passw0rd"); |
| | | |
| | |
| | | |
| | | private String backendType = System.getProperty(CONFIG_PREFIX + ".backend", "je"); |
| | | |
| | | private int jmxPort = Integer.parseInt(System.getProperty(CONFIG_PREFIX + ".jmx_port", "1689")); |
| | | private int jmxPort = intProperty(CONFIG_PREFIX + ".jmx_port", "1689"); |
| | | |
| | | private String ldifSchema = System.getProperty(CONFIG_PREFIX + ".ldif.schema"); |
| | | |
| | |
| | | |
| | | private Set<String> skipSet = new HashSet<>(Arrays.asList(System.getProperty(CONFIG_PREFIX + ".skip", ",ou=sample-skip-group,").toLowerCase().split(";"))); |
| | | |
| | | private long deleteTimeout = timeoutProperty(CONFIG_PREFIX + ".delete_timeout", "10000"); |
| | | |
| | | /** |
| | | * Returns the value of a system property holding a number. |
| | | * <p> |
| | | * These fields are initialized when the instance is created, so an unhandled |
| | | * {@link NumberFormatException} would surface from the constructor of |
| | | * {@link EmbeddedOpenDJ} saying only which string was rejected, without naming the |
| | | * property that carried it. |
| | | * |
| | | * @param name |
| | | * the name of the system property |
| | | * @param defaultValue |
| | | * the value used when the property is not set |
| | | * @return the value of the property, or {@code defaultValue} when it is not set |
| | | * @throws IllegalArgumentException |
| | | * If the value of the property is not a number. |
| | | */ |
| | | private static int intProperty(String name, String defaultValue) { |
| | | final String value = System.getProperty(name, defaultValue); |
| | | try { |
| | | return Integer.parseInt(value); |
| | | } catch (NumberFormatException e) { |
| | | throw invalidProperty(name, value, e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Returns the value of a system property holding a duration in milliseconds. |
| | | * |
| | | * @param name |
| | | * the name of the system property |
| | | * @param defaultValue |
| | | * the value used when the property is not set |
| | | * @return the value of the property, or {@code defaultValue} when it is not set |
| | | * @throws IllegalArgumentException |
| | | * If the value of the property is not a number, or is negative. |
| | | */ |
| | | private static long timeoutProperty(String name, String defaultValue) { |
| | | final String value = System.getProperty(name, defaultValue); |
| | | final long timeout; |
| | | try { |
| | | timeout = Long.parseLong(value); |
| | | } catch (NumberFormatException e) { |
| | | throw invalidProperty(name, value, e); |
| | | } |
| | | if (timeout < 0) { |
| | | throw new IllegalArgumentException("Invalid value \"" + value + "\" for the system property " |
| | | + name + ": a timeout in milliseconds cannot be negative"); |
| | | } |
| | | return timeout; |
| | | } |
| | | |
| | | private static IllegalArgumentException invalidProperty(String name, String value, NumberFormatException cause) { |
| | | return new IllegalArgumentException("Invalid value \"" + value + "\" for the system property " |
| | | + name + ": expected a number", cause); |
| | | } |
| | | |
| | | public int getPort() { |
| | | return port; |
| | | } |
| | |
| | | this.skipSet = skipSet; |
| | | } |
| | | |
| | | /** |
| | | * Returns how long {@link EmbeddedOpenDJ#close()} retries the deletion of the temporary |
| | | * directory of the instance, in milliseconds. |
| | | * <p> |
| | | * The deletion has to be retried because a file cannot be deleted on Windows while a |
| | | * handle to it is still open, and the server threads release their handles shortly after |
| | | * the server has been stopped. Whatever is still locked when this expires is scheduled for |
| | | * deletion on JVM exit. Set it to {@code 0} to delete once and never wait. |
| | | * |
| | | * @return the deletion timeout in milliseconds |
| | | */ |
| | | public long getDeleteTimeout() { |
| | | return deleteTimeout; |
| | | } |
| | | |
| | | /** |
| | | * Sets how long {@link EmbeddedOpenDJ#close()} retries the deletion of the temporary |
| | | * directory of the instance. |
| | | * |
| | | * @param deleteTimeout |
| | | * the deletion timeout in milliseconds, {@code 0} to delete once and never wait |
| | | * @throws IllegalArgumentException |
| | | * If the timeout is negative. |
| | | */ |
| | | public void setDeleteTimeout(long deleteTimeout) { |
| | | if (deleteTimeout < 0) { |
| | | throw new IllegalArgumentException("The delete timeout cannot be negative, but was " + deleteTimeout); |
| | | } |
| | | this.deleteTimeout = deleteTimeout; |
| | | } |
| | | |
| | | @Override |
| | | public String toString() { |
| | | return "Config {" + |
| | |
| | | ", ldifSchema='" + ldifSchema + '\'' + |
| | | ", file='" + file + '\'' + |
| | | ", skipSet=" + skipSet + |
| | | ", deleteTimeout=" + deleteTimeout + |
| | | '}'; |
| | | } |
| | | } |
| | |
| | | import java.util.ArrayList; |
| | | import java.util.Collections; |
| | | import java.util.List; |
| | | import java.util.concurrent.TimeUnit; |
| | | import java.util.function.Predicate; |
| | | |
| | | public class EmbeddedOpenDJ implements Runnable, Closeable { |
| | | private static final String JAR_SCHEMA_DIRECTORY = "opendj/config/schema/"; |
| | | |
| | | private static final String ARCHIVE_NAME = "opendj.zip"; |
| | | |
| | | /** |
| | | * How long the deletion of the instance directory is retried when there is no point in |
| | | * waiting for the full {@link Config#getDeleteTimeout() configured timeout}: from the |
| | | * shutdown hook, where a longer wait only makes Control-C look hung, and from the |
| | | * constructor, where an initialization failure has to be reported promptly. What is still |
| | | * locked when this expires is deleted on JVM exit anyway. |
| | | */ |
| | | private static final long SHORT_DELETE_TIMEOUT_MS = 1_000L; |
| | | |
| | | private static final long INITIAL_DELETE_RETRY_DELAY_MS = 50L; |
| | | |
| | | private static final long MAX_DELETE_RETRY_DELAY_MS = 500L; |
| | | |
| | | /** Upper bound on the number of leftover paths reported when the deletion fails. */ |
| | | private static final int MAX_REPORTED_REMAINING_PATHS = 20; |
| | | |
| | | final static Logger logger = LoggerFactory.getLogger(EmbeddedOpenDJ.class.getName()); |
| | | final EmbeddedDirectoryServer server; |
| | | |
| | |
| | | |
| | | private final File instanceDirectory; |
| | | private final File rootDirectory; |
| | | private final Thread shutdownHook; |
| | | |
| | | /** Written under {@code this}, read without locking so that a running {@link #close()} blocks nothing. */ |
| | | private volatile boolean closed; |
| | | |
| | | public EmbeddedOpenDJ() { |
| | | this(new Config()); |
| | |
| | | // deleted on close(). |
| | | instanceDirectory = Files.createTempDirectory("opendj").toFile(); |
| | | File rootDirectory = new File(instanceDirectory, "opendj"); |
| | | rootDirectory.mkdir(); |
| | | if (!rootDirectory.mkdir()) { |
| | | // the parent has just been created, so this only fails on a real filesystem error |
| | | throw new IOException("Cannot create the server root directory " + rootDirectory); |
| | | } |
| | | logger.info("OpenDJ server root: {}", rootDirectory); |
| | | |
| | | File configDirectory = new File(rootDirectory, "config"); |
| | |
| | | System.out, |
| | | System.err); |
| | | |
| | | copyFilesFromJar(Collections.singletonList("opendj.zip"),"embedded-opendj/",rootDirectory); |
| | | server.extractArchiveForSetup(new File(rootDirectory,"opendj.zip")); |
| | | copyFilesFromJar(Collections.singletonList(ARCHIVE_NAME),"embedded-opendj/",rootDirectory); |
| | | final File archive = new File(rootDirectory, ARCHIVE_NAME); |
| | | server.extractArchiveForSetup(archive); |
| | | // The archive is only needed for the extraction above. Keeping it would leave a |
| | | // full copy of the distribution in the temporary directory and one more file to |
| | | // delete on close(). |
| | | if (!archive.delete()) { |
| | | logger.warn("Cannot delete {} after extracting it", archive); |
| | | } |
| | | |
| | | server.setup( |
| | | SetupParameters.setupParams() |
| | |
| | | this.rootDirectory = rootDirectory; |
| | | }catch (Exception e) { |
| | | logger.error("Error initializing OpenDJ"); |
| | | FileUtils.deleteQuietly(instanceDirectory); |
| | | deleteInstanceDirectory(instanceDirectory, shortDeleteTimeout(config)); |
| | | throw new RuntimeException(e); |
| | | } |
| | | Runtime.getRuntime().addShutdownHook(new Thread(this::close)); |
| | | shutdownHook = new Thread(this::close, "EmbeddedOpenDJ shutdown hook"); |
| | | Runtime.getRuntime().addShutdownHook(shutdownHook); |
| | | } |
| | | |
| | | /** |
| | | * Returns the server root directory of this embedded instance. |
| | | * |
| | | * @return the server root directory |
| | | * @throws IllegalStateException |
| | | * If this instance has been closed, and the directory therefore deleted. |
| | | */ |
| | | public File getServerRootDirectory() { |
| | | checkNotClosed(); |
| | | return rootDirectory; |
| | | } |
| | | |
| | | @Override |
| | | public void run() { |
| | | checkNotClosed(); |
| | | try { |
| | | final DN baseDN = DN.valueOf(config.getBaseDN()); |
| | | try { |
| | | ManagementContext config = server.getConfiguration(); |
| | | BackendCfgClient userRoot = config.getRootConfiguration().getBackend("userRoot"); |
| | | try (ManagementContext managementContext = server.getConfiguration()) { |
| | | BackendCfgClient userRoot = managementContext.getRootConfiguration().getBackend("userRoot"); |
| | | userRoot.setBaseDN((Collections.singletonList(baseDN))); |
| | | userRoot.setEnabled(true); |
| | | userRoot.commit(); |
| | | config.close(); |
| | | } catch (Exception e) { |
| | | throw new RuntimeException(e); |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Stops this instance, if it is still running, and deletes its temporary directory. |
| | | * <p> |
| | | * This method is idempotent: it is also registered as a JVM shutdown hook. |
| | | * <p> |
| | | * When the server cannot be stopped, this instance stays open and keeps its shutdown hook |
| | | * registered, so that a later call - or the hook at JVM exit - retries the stop. |
| | | */ |
| | | @Override |
| | | public void close() { |
| | | public synchronized void close() { |
| | | if (closed) { |
| | | return; |
| | | } |
| | | final boolean fromShutdownHook = Thread.currentThread() == shutdownHook; |
| | | if (server.isRunning()) { |
| | | try { |
| | | logger.info("Shutting down OpenDJ ..."); |
| | | server.stop(this.getClass().getName(), LocalizableMessage.raw("Stopped after receiving Control-C")); |
| | | }catch (Throwable e) { |
| | | logger.error("Error stopping OpenDJ", e); |
| | | if (!fromShutdownHook) { |
| | | // The server is still running: deleting its directory now would destroy a |
| | | // live installation. Leave this instance open, with its shutdown hook still |
| | | // registered, so that the stop can be retried. |
| | | return; |
| | | } |
| | | // The JVM is going down and there will be no later attempt, so the temporary |
| | | // directory is removed even though the server has not stopped cleanly. |
| | | } |
| | | } |
| | | // close() is also registered as a shutdown hook, so deletion must stay idempotent |
| | | FileUtils.deleteQuietly(instanceDirectory); |
| | | closed = true; |
| | | unregisterShutdownHook(); |
| | | deleteInstanceDirectory(instanceDirectory, |
| | | fromShutdownHook ? shortDeleteTimeout(config) : config.getDeleteTimeout()); |
| | | } |
| | | |
| | | private void checkNotClosed() { |
| | | if (closed) { |
| | | throw new IllegalStateException("this embedded OpenDJ instance is closed"); |
| | | } |
| | | } |
| | | |
| | | private static long shortDeleteTimeout(Config config) { |
| | | return Math.min(config.getDeleteTimeout(), SHORT_DELETE_TIMEOUT_MS); |
| | | } |
| | | |
| | | private void unregisterShutdownHook() { |
| | | try { |
| | | Runtime.getRuntime().removeShutdownHook(shutdownHook); |
| | | } catch (IllegalStateException e) { |
| | | // close() was reached from the shutdown hook itself: nothing to unregister |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Deletes the temporary directory of an instance, retrying for a bounded period and |
| | | * falling back to a deletion on JVM exit. |
| | | * <p> |
| | | * Deleting once is not enough. On Windows a file cannot be deleted while a handle to it |
| | | * is still open, and {@code server.stop()} does not wait for the server threads to |
| | | * terminate: an embedded server runs them as daemon threads, which the shutdown monitor |
| | | * of the directory server ignores. Some handles are therefore released shortly after |
| | | * {@code stop()} has returned, and a single best-effort deletion loses that race and |
| | | * silently leaks the whole directory, backend data included. Retrying is a way to wait |
| | | * for those handles to be released - a single attempt already removes everything that is |
| | | * not in use at that moment. |
| | | * |
| | | * @param directory |
| | | * the directory to delete, may be {@code null} when the instance failed to |
| | | * initialize before creating it |
| | | * @param timeoutMs |
| | | * how long the deletion is retried, in milliseconds |
| | | */ |
| | | static void deleteInstanceDirectory(File directory, long timeoutMs) { |
| | | deleteInstanceDirectory(directory, timeoutMs, FileUtils::deleteQuietly); |
| | | } |
| | | |
| | | /** |
| | | * Implements {@link #deleteInstanceDirectory(File, long)} with an injectable deletion, so |
| | | * that tests can drive the retries without depending on a genuinely undeletable file. |
| | | * |
| | | * @param deleteAttempt |
| | | * performs one deletion attempt and reports whether the directory is gone |
| | | */ |
| | | static void deleteInstanceDirectory(File directory, long timeoutMs, Predicate<File> deleteAttempt) { |
| | | if (directory == null || !directory.exists()) { |
| | | return; |
| | | } |
| | | final long deadline = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(timeoutMs); |
| | | long retryDelay = INITIAL_DELETE_RETRY_DELAY_MS; |
| | | while (true) { |
| | | // The second test covers a directory removed by someone else in the meantime: |
| | | // deleteQuietly() reports a failure for a directory that is already gone. |
| | | if (deleteAttempt.test(directory) || !directory.exists()) { |
| | | return; |
| | | } |
| | | if (System.nanoTime() >= deadline) { |
| | | logger.warn("Cannot delete {} within {} ms, some files are still in use. " |
| | | + "They are now scheduled for deletion on JVM exit:{}", |
| | | directory, timeoutMs, remainingPaths(directory)); |
| | | break; |
| | | } |
| | | try { |
| | | Thread.sleep(retryDelay); |
| | | } catch (InterruptedException e) { |
| | | Thread.currentThread().interrupt(); |
| | | logger.warn("Interrupted while deleting {}. What is left is now scheduled " |
| | | + "for deletion on JVM exit:{}", directory, remainingPaths(directory)); |
| | | break; |
| | | } |
| | | retryDelay = Math.min(retryDelay * 2, MAX_DELETE_RETRY_DELAY_MS); |
| | | } |
| | | deleteTreeOnExit(directory); |
| | | } |
| | | |
| | | /** |
| | | * Describes what is left in the given directory: one path per line, at most |
| | | * {@link #MAX_REPORTED_REMAINING_PATHS} of them, followed by the number of paths left out. |
| | | */ |
| | | static String remainingPaths(File directory) { |
| | | final List<String> reported = new ArrayList<>(); |
| | | final int total = collectRemainingPaths(directory, reported); |
| | | final StringBuilder description = new StringBuilder(); |
| | | for (String path : reported) { |
| | | description.append("\n ").append(path); |
| | | } |
| | | if (total > reported.size()) { |
| | | description.append("\n ... and ").append(total - reported.size()).append(" more"); |
| | | } |
| | | return description.toString(); |
| | | } |
| | | |
| | | /** |
| | | * Adds at most {@link #MAX_REPORTED_REMAINING_PATHS} paths of the given tree to |
| | | * {@code reported} and returns how many paths it holds in total. |
| | | */ |
| | | private static int collectRemainingPaths(File file, List<String> reported) { |
| | | final File[] children = file.listFiles(); |
| | | if (children == null || children.length == 0) { |
| | | if (reported.size() < MAX_REPORTED_REMAINING_PATHS) { |
| | | reported.add(file.getPath()); |
| | | } |
| | | return 1; |
| | | } |
| | | int total = 0; |
| | | for (File child : children) { |
| | | total += collectRemainingPaths(child, reported); |
| | | } |
| | | return total; |
| | | } |
| | | |
| | | private static void deleteTreeOnExit(File file) { |
| | | // File.deleteOnExit() deletes in reverse order of registration, so a directory has to |
| | | // be registered before its content for the content to be removed first. |
| | | file.deleteOnExit(); |
| | | final File[] children = file.listFiles(); |
| | | if (children != null) { |
| | | for (File child : children) { |
| | | deleteTreeOnExit(child); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private void copyFilesFromJar(List<String> jarFiles, String jarDirectory, File outputDirectory) throws IOException{ |
| | |
| | | final String resourcePath = !jarFile.contains("/") |
| | | ? "/"+jarDirectory + jarFile |
| | | : jarFile; |
| | | InputStream in = new File(jarFile).exists() |
| | | try (InputStream in = new File(jarFile).exists() |
| | | ? Files.newInputStream(new File(jarFile).toPath()) |
| | | : MemoryBackend.class.getResourceAsStream(resourcePath); |
| | | if (in == null) { |
| | | throw new IOException("cannot find " + resourcePath); |
| | | : MemoryBackend.class.getResourceAsStream(resourcePath)) { |
| | | if (in == null) { |
| | | throw new IOException("cannot find " + resourcePath); |
| | | } |
| | | FileUtils.copyInputStreamToFile(in, outputFile); |
| | | } |
| | | FileUtils.copyInputStreamToFile(in, outputFile); |
| | | in.close(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Imports the LDIF read from the given stream. |
| | | * <p> |
| | | * The stream is closed by this method, whether the import succeeds or not. |
| | | * |
| | | * @param inputStream |
| | | * the LDIF to import |
| | | * @throws IllegalStateException |
| | | * If this instance has been closed. |
| | | */ |
| | | public void importData(InputStream inputStream) throws EmbeddedDirectoryServerException, IOException { |
| | | checkNotClosed(); |
| | | logger.info("start import ldif from stream"); |
| | | |
| | | EntryReader reader; |
| | | try { |
| | | BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); |
| | | reader = new LDIFEntryReader(bufferedReader); |
| | | } catch (Exception e) { |
| | | logger.error("import ldif : {}", e, e); |
| | | throw e; |
| | | } |
| | | org.forgerock.opendj.ldap.Entry entryBefore; |
| | | final Connection connection = server.getInternalConnection(); |
| | | long recordCount = 0; |
| | | while (reader.hasNext() && (entryBefore = reader.readEntry()) != null) { |
| | | recordCount++; |
| | | try { |
| | | connection.add(entryBefore); |
| | | logger.info("import ldif : {}",entryBefore.getName()); |
| | | }catch (LdapException e) { |
| | | logger.error("import ldif : {} {}",entryBefore.getName(),e.toString()); |
| | | try (EntryReader reader = new LDIFEntryReader(new BufferedReader(new InputStreamReader(inputStream))); |
| | | Connection connection = server.getInternalConnection()) { |
| | | while (reader.hasNext() && (entryBefore = reader.readEntry()) != null) { |
| | | recordCount++; |
| | | try { |
| | | connection.add(entryBefore); |
| | | logger.info("import ldif : {}",entryBefore.getName()); |
| | | }catch (LdapException e) { |
| | | logger.error("import ldif : {} {}",entryBefore.getName(),e.toString()); |
| | | } |
| | | } |
| | | } |
| | | if(recordCount == 0) { |
| | | logger.error("no records were imported, check file contents and permissions"); |
| | | throw new RuntimeException("no records were imported"); |
| | | } |
| | | reader.close(); |
| | | connection.close(); |
| | | } |
| | | |
| | | /** |
| | | * Writes the entries below the given base DN to the given stream, as LDIF. |
| | | * <p> |
| | | * The stream is flushed and closed by this method, whether the export succeeds or not. |
| | | * |
| | | * @param baseDN |
| | | * the base DN of the subtree to export |
| | | * @param out |
| | | * where the LDIF is written |
| | | * @throws IllegalStateException |
| | | * If this instance has been closed. |
| | | */ |
| | | public void getData(String baseDN, OutputStream out) throws IOException, EmbeddedDirectoryServerException { |
| | | LDIFEntryWriter ldifWriter = new LDIFEntryWriter(out); |
| | | final Connection connection = server.getInternalConnection(); |
| | | |
| | | ConnectionEntryReader reader = connection.search(baseDN, SearchScope.WHOLE_SUBTREE, "(objectClass=*)"); |
| | | while(reader.hasNext()) { |
| | | if (!reader.isReference()) { |
| | | SearchResultEntry se = reader.readEntry(); |
| | | if (!skipEntry(se)) { |
| | | ldifWriter.writeEntry(se); |
| | | logger.info("export {}", se.toString()); |
| | | checkNotClosed(); |
| | | // resources are closed in reverse order, so the writer is flushed and closed last |
| | | try (LDIFEntryWriter ldifWriter = new LDIFEntryWriter(out); |
| | | Connection connection = server.getInternalConnection(); |
| | | ConnectionEntryReader reader = |
| | | connection.search(baseDN, SearchScope.WHOLE_SUBTREE, "(objectClass=*)")) { |
| | | while (reader.hasNext()) { |
| | | if (!reader.isReference()) { |
| | | SearchResultEntry se = reader.readEntry(); |
| | | if (!skipEntry(se)) { |
| | | ldifWriter.writeEntry(se); |
| | | logger.info("export {}", se.toString()); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | reader.close(); |
| | | ldifWriter.close(); |
| | | connection.close(); |
| | | } |
| | | |
| | | private boolean skipEntry(SearchResultEntry se) { |
| New file |
| | |
| | | /* |
| | | * The contents of this file are subject to the terms of the Common Development and |
| | | * Distribution License (the License). You may not use this file except in compliance with the |
| | | * License. |
| | | * |
| | | * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the |
| | | * specific language governing permission and limitations under the License. |
| | | * |
| | | * When distributing Covered Software, include this CDDL Header Notice in each file and include |
| | | * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL |
| | | * Header, with the fields enclosed by brackets [] replaced by your own identifying |
| | | * information: "Portions Copyright [year] [name of copyright owner]". |
| | | * |
| | | * Copyright 2026 3A Systems LLC. |
| | | */ |
| | | |
| | | package org.openidentityplatform.opendj.embedded; |
| | | |
| | | import org.testng.annotations.AfterMethod; |
| | | import org.testng.annotations.DataProvider; |
| | | import org.testng.annotations.Test; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | | import static org.testng.Assert.assertEquals; |
| | | import static org.testng.Assert.assertTrue; |
| | | import static org.testng.Assert.fail; |
| | | |
| | | /** |
| | | * Tests how the numeric configuration properties are read: they are parsed while the instance |
| | | * is being created, so a value that cannot be parsed has to name the property that carried it |
| | | * instead of surfacing as a bare {@link NumberFormatException} from a constructor. |
| | | */ |
| | | public class ConfigTest { |
| | | |
| | | private static final String PREFIX = Config.class.getPackage().getName(); |
| | | |
| | | private final List<String> propertiesSet = new ArrayList<>(); |
| | | |
| | | @AfterMethod |
| | | public void clearProperties() { |
| | | for (String name : propertiesSet) { |
| | | System.clearProperty(name); |
| | | } |
| | | propertiesSet.clear(); |
| | | } |
| | | |
| | | @DataProvider |
| | | public Object[][] numericProperties() { |
| | | return new Object[][] { { ".port" }, { ".admin_port" }, { ".jmx_port" }, { ".delete_timeout" } }; |
| | | } |
| | | |
| | | @Test |
| | | public void readsTheDefaultsWhenNoPropertyIsSet() { |
| | | final Config config = new Config(); |
| | | |
| | | assertEquals(config.getPort(), 1389); |
| | | assertEquals(config.getAdminPort(), 4444); |
| | | assertEquals(config.getJmxPort(), 1689); |
| | | assertEquals(config.getDeleteTimeout(), 10_000L); |
| | | } |
| | | |
| | | @Test |
| | | public void readsTheNumbersFromTheSystemProperties() { |
| | | setProperty(".port", "11389"); |
| | | setProperty(".admin_port", "14444"); |
| | | setProperty(".jmx_port", "11689"); |
| | | setProperty(".delete_timeout", "0"); |
| | | |
| | | final Config config = new Config(); |
| | | |
| | | assertEquals(config.getPort(), 11389); |
| | | assertEquals(config.getAdminPort(), 14444); |
| | | assertEquals(config.getJmxPort(), 11689); |
| | | assertEquals(config.getDeleteTimeout(), 0L); |
| | | } |
| | | |
| | | @Test(dataProvider = "numericProperties") |
| | | public void namesThePropertyWhoseValueIsNotANumber(String property) { |
| | | setProperty(property, "not a number"); |
| | | |
| | | try { |
| | | new Config(); |
| | | fail("a value that is not a number should have been rejected"); |
| | | } catch (IllegalArgumentException e) { |
| | | assertTrue(e.getMessage().contains(PREFIX + property), e.getMessage()); |
| | | assertTrue(e.getMessage().contains("not a number"), e.getMessage()); |
| | | assertTrue(e.getCause() instanceof NumberFormatException, "unexpected cause: " + e.getCause()); |
| | | } |
| | | } |
| | | |
| | | @Test |
| | | public void rejectsANegativeDeleteTimeoutProperty() { |
| | | setProperty(".delete_timeout", "-1"); |
| | | |
| | | try { |
| | | new Config(); |
| | | fail("a negative timeout should have been rejected"); |
| | | } catch (IllegalArgumentException e) { |
| | | assertTrue(e.getMessage().contains(PREFIX + ".delete_timeout"), e.getMessage()); |
| | | assertTrue(e.getMessage().contains("negative"), e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | @Test |
| | | public void rejectsANegativeDeleteTimeout() { |
| | | final Config config = new Config(); |
| | | |
| | | try { |
| | | config.setDeleteTimeout(-1); |
| | | fail("a negative timeout should have been rejected"); |
| | | } catch (IllegalArgumentException e) { |
| | | assertTrue(e.getMessage().contains("-1"), e.getMessage()); |
| | | } |
| | | assertEquals(config.getDeleteTimeout(), 10_000L, "the timeout has been changed"); |
| | | } |
| | | |
| | | private void setProperty(String property, String value) { |
| | | final String name = PREFIX + property; |
| | | System.setProperty(name, value); |
| | | propertiesSet.add(name); |
| | | } |
| | | } |
| New file |
| | |
| | | /* |
| | | * The contents of this file are subject to the terms of the Common Development and |
| | | * Distribution License (the License). You may not use this file except in compliance with the |
| | | * License. |
| | | * |
| | | * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the |
| | | * specific language governing permission and limitations under the License. |
| | | * |
| | | * When distributing Covered Software, include this CDDL Header Notice in each file and include |
| | | * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL |
| | | * Header, with the fields enclosed by brackets [] replaced by your own identifying |
| | | * information: "Portions Copyright [year] [name of copyright owner]". |
| | | * |
| | | * Copyright 2026 3A Systems LLC. |
| | | */ |
| | | |
| | | package org.openidentityplatform.opendj.embedded; |
| | | |
| | | import org.apache.commons.io.FileUtils; |
| | | import org.testng.annotations.AfterMethod; |
| | | import org.testng.annotations.Test; |
| | | |
| | | import java.io.File; |
| | | import java.io.IOException; |
| | | import java.nio.file.Files; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | import java.util.concurrent.TimeUnit; |
| | | import java.util.concurrent.atomic.AtomicInteger; |
| | | |
| | | import static org.testng.Assert.assertEquals; |
| | | import static org.testng.Assert.assertFalse; |
| | | import static org.testng.Assert.assertTrue; |
| | | |
| | | /** |
| | | * Tests the deletion of the temporary directory of an embedded instance, which has to survive |
| | | * the files that the server threads are still holding when {@code stop()} returns. |
| | | * <p> |
| | | * The deletion itself is injected, so that the retries can be driven without depending on a |
| | | * genuinely undeletable file, which no platform offers in a portable way. |
| | | */ |
| | | public class EmbeddedOpenDJCleanupTest { |
| | | |
| | | private final List<File> temporaryDirectories = new ArrayList<>(); |
| | | |
| | | @AfterMethod |
| | | public void deleteTemporaryDirectories() { |
| | | for (File directory : temporaryDirectories) { |
| | | FileUtils.deleteQuietly(directory); |
| | | } |
| | | temporaryDirectories.clear(); |
| | | } |
| | | |
| | | @Test |
| | | public void deletesTheWholeTree() throws Exception { |
| | | final File directory = createTree(3); |
| | | |
| | | EmbeddedOpenDJ.deleteInstanceDirectory(directory, 0); |
| | | |
| | | assertFalse(directory.exists(), directory + " has not been deleted"); |
| | | } |
| | | |
| | | @Test |
| | | public void ignoresADirectoryThatDoesNotExist() throws Exception { |
| | | final File directory = createTree(0); |
| | | assertTrue(FileUtils.deleteQuietly(directory)); |
| | | |
| | | //neither of these must throw |
| | | EmbeddedOpenDJ.deleteInstanceDirectory(directory, 10_000); |
| | | EmbeddedOpenDJ.deleteInstanceDirectory(null, 10_000); |
| | | } |
| | | |
| | | @Test |
| | | public void stopsRetryingAsSoonAsTheDeletionSucceeds() throws Exception { |
| | | final File directory = createTree(1); |
| | | final AtomicInteger attempts = new AtomicInteger(); |
| | | |
| | | final long elapsedMs = timed(() -> |
| | | EmbeddedOpenDJ.deleteInstanceDirectory(directory, 10_000, file -> attempts.incrementAndGet() >= 3)); |
| | | |
| | | assertEquals(attempts.get(), 3, "the deletion should have been retried until it succeeded"); |
| | | assertTrue(elapsedMs < 10_000, "it waited " + elapsedMs + " ms instead of returning on success"); |
| | | } |
| | | |
| | | @Test |
| | | public void triesOnlyOnceWithoutATimeout() throws Exception { |
| | | final File directory = createTree(1); |
| | | final AtomicInteger attempts = new AtomicInteger(); |
| | | |
| | | EmbeddedOpenDJ.deleteInstanceDirectory(directory, 0, file -> { |
| | | attempts.incrementAndGet(); |
| | | return false; |
| | | }); |
| | | |
| | | assertEquals(attempts.get(), 1, "a zero timeout must not retry"); |
| | | assertTrue(directory.exists(), "the injected deletion did not delete anything"); |
| | | } |
| | | |
| | | @Test |
| | | public void givesUpWhenTheTimeoutExpires() throws Exception { |
| | | final File directory = createTree(1); |
| | | final AtomicInteger attempts = new AtomicInteger(); |
| | | final long timeoutMs = 300; |
| | | |
| | | final long elapsedMs = timed(() -> EmbeddedOpenDJ.deleteInstanceDirectory(directory, timeoutMs, file -> { |
| | | attempts.incrementAndGet(); |
| | | return false; |
| | | })); |
| | | |
| | | assertTrue(attempts.get() > 1, "the deletion should have been retried, attempts: " + attempts.get()); |
| | | assertTrue(elapsedMs >= timeoutMs, "it gave up after " + elapsedMs + " ms, before the timeout"); |
| | | assertTrue(elapsedMs < TimeUnit.SECONDS.toMillis(30), "it did not give up, " + elapsedMs + " ms elapsed"); |
| | | //the leftovers are registered for deletion on JVM exit, so this must return normally |
| | | assertTrue(directory.exists()); |
| | | } |
| | | |
| | | @Test |
| | | public void givesUpWhenTheThreadIsInterrupted() throws Exception { |
| | | final File directory = createTree(1); |
| | | final AtomicInteger attempts = new AtomicInteger(); |
| | | |
| | | final long elapsedMs; |
| | | Thread.currentThread().interrupt(); |
| | | try { |
| | | elapsedMs = timed(() -> EmbeddedOpenDJ.deleteInstanceDirectory(directory, 60_000, file -> { |
| | | attempts.incrementAndGet(); |
| | | return false; |
| | | })); |
| | | assertTrue(Thread.currentThread().isInterrupted(), "the interrupted status has been swallowed"); |
| | | } finally { |
| | | Thread.interrupted(); |
| | | } |
| | | |
| | | assertEquals(attempts.get(), 1, "an interrupted deletion must not be retried"); |
| | | assertTrue(elapsedMs < TimeUnit.SECONDS.toMillis(30), "it kept retrying for " + elapsedMs + " ms"); |
| | | } |
| | | |
| | | @Test |
| | | public void reportsTheRemainingPathsAndHowManyAreLeftOut() throws Exception { |
| | | final File directory = createTree(25); |
| | | |
| | | final String remaining = EmbeddedOpenDJ.remainingPaths(directory); |
| | | |
| | | final String[] lines = remaining.split("\n"); |
| | | //one empty leading token before the first line separator, 20 paths and the summary |
| | | assertEquals(lines.length, 22, "unexpected report: " + remaining); |
| | | for (int i = 1; i < lines.length - 1; i++) { |
| | | assertTrue(lines[i].startsWith(" " + directory.getPath()), "unexpected line: " + lines[i]); |
| | | } |
| | | assertTrue(remaining.endsWith("... and 5 more"), remaining); |
| | | } |
| | | |
| | | @Test |
| | | public void reportsAllTheRemainingPathsWhenThereAreFewOfThem() throws Exception { |
| | | final File directory = createTree(2); |
| | | |
| | | final String remaining = EmbeddedOpenDJ.remainingPaths(directory); |
| | | |
| | | assertEquals(remaining.split("\n").length, 3, "unexpected report: " + remaining); |
| | | assertFalse(remaining.contains("more"), remaining); |
| | | } |
| | | |
| | | /** Creates a temporary directory holding the given number of files, one of them nested. */ |
| | | private File createTree(int fileCount) throws IOException { |
| | | final File directory = Files.createTempDirectory("opendj-cleanup-test").toFile(); |
| | | temporaryDirectories.add(directory); |
| | | final File subDirectory = new File(directory, "nested"); |
| | | assertTrue(subDirectory.mkdir()); |
| | | for (int i = 0; i < fileCount; i++) { |
| | | final File parent = i == 0 ? subDirectory : directory; |
| | | Files.write(new File(parent, "file" + i + ".txt").toPath(), new byte[] { 'x' }); |
| | | } |
| | | return directory; |
| | | } |
| | | |
| | | private static long timed(Runnable runnable) { |
| | | final long start = System.nanoTime(); |
| | | runnable.run(); |
| | | return TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start); |
| | | } |
| | | } |
| | |
| | | import org.forgerock.opendj.ldif.ConnectionEntryReader; |
| | | import org.testng.annotations.Test; |
| | | |
| | | import java.io.ByteArrayInputStream; |
| | | import java.io.ByteArrayOutputStream; |
| | | import java.io.File; |
| | | import java.io.IOException; |
| | | import java.io.InputStream; |
| | | import java.net.URI; |
| | | import java.nio.charset.StandardCharsets; |
| | | import java.nio.file.Files; |
| | | import java.nio.file.Path; |
| | | import java.nio.file.Paths; |
| | | import java.util.stream.Stream; |
| | | |
| | | import static org.testng.Assert.assertEquals; |
| | | import static org.testng.Assert.assertFalse; |
| | | import static org.testng.Assert.assertThrows; |
| | | import static org.testng.Assert.assertTrue; |
| | | |
| | | public class EmbeddedOpenDJTest { |
| | |
| | | |
| | | //start embedded OpenDJ server |
| | | EmbeddedOpenDJ embeddedOpenDJ = new EmbeddedOpenDJ(config); |
| | | embeddedOpenDJ.run(); |
| | | assertTrue(embeddedOpenDJ.isRunning()); |
| | | |
| | | File serverRoot = embeddedOpenDJ.getServerRootDirectory(); |
| | | assertTrue(serverRoot.isDirectory()); |
| | | try { |
| | | embeddedOpenDJ.run(); |
| | | assertTrue(embeddedOpenDJ.isRunning()); |
| | | assertTrue(serverRoot.isDirectory()); |
| | | |
| | | //import ldif data from an input stream |
| | | URI resUri = getClass().getClassLoader().getResource("opendj/data.ldif").toURI(); |
| | | byte[] bytes = Files.readAllBytes(Paths.get(resUri)); |
| | | String newBytes = new String(bytes); |
| | | InputStream is = new ByteArrayInputStream(newBytes.getBytes(StandardCharsets.UTF_8)); |
| | | embeddedOpenDJ.importData(is); |
| | | //import ldif data from an input stream |
| | | URI resUri = getClass().getClassLoader().getResource("opendj/data.ldif").toURI(); |
| | | try (InputStream is = Files.newInputStream(Paths.get(resUri))) { |
| | | embeddedOpenDJ.importData(is); |
| | | } |
| | | |
| | | //export OpenDJ data |
| | | ByteArrayOutputStream bos = new ByteArrayOutputStream(); |
| | | embeddedOpenDJ.getData("dc=openidentityplatform,dc=org", bos); |
| | | String imported = bos.toString(); |
| | | assertTrue(imported.contains("dn: uid=jdoe,ou=people,dc=openidentityplatform,dc=org")); |
| | | //export OpenDJ data |
| | | ByteArrayOutputStream bos = new ByteArrayOutputStream(); |
| | | embeddedOpenDJ.getData(config.getBaseDN(), bos); |
| | | //getData() writes LDIF in the platform default charset, so it has to be read back |
| | | //in the same one: LDIFEntryWriter(OutputStream) wraps it in a plain OutputStreamWriter |
| | | String imported = bos.toString(); |
| | | assertTrue(imported.contains("dn: uid=jdoe,ou=people," + config.getBaseDN())); |
| | | |
| | | //test search in the imported data |
| | | try(LDAPConnectionFactory factory = new LDAPConnectionFactory("localhost", 1389); |
| | | Connection connection = factory.getConnection()) { |
| | | BindResult result = connection.bind("cn=Directory Manager", "passw0rd".toCharArray()); |
| | | assertTrue(result.isSuccess()); |
| | | //test search in the imported data |
| | | try (LDAPConnectionFactory factory = new LDAPConnectionFactory("localhost", config.getPort()); |
| | | Connection connection = factory.getConnection()) { |
| | | BindResult result = connection.bind("cn=Directory Manager", config.getAdminPassword().toCharArray()); |
| | | assertTrue(result.isSuccess()); |
| | | |
| | | SearchRequest request = Requests.newSearchRequest("dc=openidentityplatform,dc=org", |
| | | SearchScope.WHOLE_SUBTREE, "(uid=jdoe)", "uid"); |
| | | ConnectionEntryReader reader = connection.search(request); |
| | | SearchResultEntry entry = reader.readEntry(); |
| | | entry.getAllAttributes(); |
| | | SearchRequest request = Requests.newSearchRequest(config.getBaseDN(), |
| | | SearchScope.WHOLE_SUBTREE, "(uid=jdoe)", "uid"); |
| | | try (ConnectionEntryReader reader = connection.search(request)) { |
| | | SearchResultEntry entry = reader.readEntry(); |
| | | assertEquals(entry.getName().toString(), "uid=jdoe,ou=people," + config.getBaseDN()); |
| | | assertEquals(entry.parseAttribute("uid").asString(), "jdoe"); |
| | | assertFalse(reader.hasNext(), "the search returned more than one entry"); |
| | | } |
| | | } |
| | | } finally { |
| | | //stop OpenDJ |
| | | embeddedOpenDJ.close(); |
| | | } |
| | | |
| | | //stop OpenDJ |
| | | embeddedOpenDJ.close(); |
| | | assertFalse(embeddedOpenDJ.isRunning()); |
| | | |
| | | //the per-instance temporary directory is deleted on close |
| | | assertFalse(serverRoot.exists()); |
| | | assertFalse(serverRoot.getParentFile().exists()); |
| | | assertFalse(serverRoot.exists(), leftovers(serverRoot)); |
| | | assertFalse(serverRoot.getParentFile().exists(), leftovers(serverRoot.getParentFile())); |
| | | |
| | | //a closed instance cannot be used any more: its directory is gone |
| | | assertThrows(IllegalStateException.class, embeddedOpenDJ::run); |
| | | assertThrows(IllegalStateException.class, embeddedOpenDJ::getServerRootDirectory); |
| | | assertThrows(IllegalStateException.class, () -> embeddedOpenDJ.getData(config.getBaseDN(), new ByteArrayOutputStream())); |
| | | |
| | | //close() is idempotent, it is also registered as a shutdown hook |
| | | embeddedOpenDJ.close(); |
| | | } |
| | | |
| | | /** Describes what is left in the given directory, to make an assertion failure diagnosable. */ |
| | | private static String leftovers(File directory) { |
| | | if (!directory.exists()) { |
| | | return ""; |
| | | } |
| | | final StringBuilder message = new StringBuilder(directory + " still exists and contains:"); |
| | | try (Stream<Path> paths = Files.walk(directory.toPath())) { |
| | | paths.forEach(path -> message.append("\n ").append(path)); |
| | | } catch (IOException e) { |
| | | message.append(" <cannot be listed: ").append(e).append('>'); |
| | | } |
| | | return message.toString(); |
| | | } |
| | | } |
| | |
| | | * information: "Portions Copyright [year] [name of copyright owner]". |
| | | * |
| | | * Copyright 2015 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | |
| | | package org.forgerock.opendj.examples; |
| | |
| | | final String userName = args[2]; |
| | | final char[] password = args[3].toCharArray(); |
| | | |
| | | // Create the LDIF reader using either the named file, if provided, or stdin. |
| | | InputStream ldif; |
| | | // Read the LDIF from either the named file, if provided, or stdin. Only a file is closed |
| | | // here; stdin belongs to the caller. |
| | | final String[] ldifLines; |
| | | if (args.length > 4) { |
| | | try { |
| | | ldif = new FileInputStream(args[4]); |
| | | try (InputStream ldif = new FileInputStream(args[4])) { |
| | | ldifLines = getInputLines(ldif); |
| | | } catch (final FileNotFoundException e) { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue()); |
| | | return; |
| | | } catch (final IOException e) { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue()); |
| | | return; |
| | | } |
| | | } else { |
| | | ldif = System.in; |
| | | ldifLines = getInputLines(System.in); |
| | | } |
| | | final String[] ldifLines = getInputLines(ldif); |
| | | |
| | | // Connect to the server, bind, and request the modifications. |
| | | new LDAPConnectionFactory(hostName, port) |
| | |
| | | * |
| | | * Copyright 2009-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2011-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | |
| | | package org.forgerock.opendj.examples; |
| | |
| | | |
| | | // Create the memory backend. |
| | | final MemoryBackend backend; |
| | | try { |
| | | backend = new MemoryBackend(new LDIFEntryReader(new FileInputStream(ldifFileName))); |
| | | try (FileInputStream ldifStream = new FileInputStream(ldifFileName); |
| | | LDIFEntryReader ldifReader = new LDIFEntryReader(ldifStream)) { |
| | | backend = new MemoryBackend(ldifReader); |
| | | } catch (final IOException e) { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue()); |
| | |
| | | * |
| | | * Copyright 2006-2009 Sun Microsystems, Inc. |
| | | * Portions Copyright 2014-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | |
| | | package com.forgerock.opendj.ldap.tools; |
| | |
| | | import java.io.InputStream; |
| | | import java.io.InputStreamReader; |
| | | import java.io.PrintStream; |
| | | import java.io.Reader; |
| | | import java.io.UnsupportedEncodingException; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | |
| | | dataToDecode = encodedDataArg.getValue(); |
| | | } else { |
| | | final boolean readFromFile = encodedDataFilePathArg.isPresent(); |
| | | Reader source = null; |
| | | BufferedReader reader = null; |
| | | final String encodedDataFilePath = encodedDataFilePathArg.getValue(); |
| | | try { |
| | | reader = new BufferedReader(readFromFile ? new FileReader(encodedDataFilePath) |
| | | : new InputStreamReader(System.in)); |
| | | // Only a file is closed below; System.in belongs to the caller. |
| | | source = readFromFile ? new FileReader(encodedDataFilePath) |
| | | : new InputStreamReader(System.in); |
| | | reader = new BufferedReader(source); |
| | | final StringBuilder buffer = new StringBuilder(); |
| | | String line; |
| | | while ((line = reader.readLine()) != null) { |
| | |
| | | ERR_BASE64_CANNOT_READ_ENCODED_DATA.get(getExceptionMessage(e))); |
| | | } finally { |
| | | if (readFromFile) { |
| | | closeSilently(reader); |
| | | closeSilently(reader, source); |
| | | } |
| | | } |
| | | } |
| | |
| | | * information: "Portions Copyright [year] [name of copyright owner]". |
| | | * |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | * Portions copyright 2014-2016 ForgeRock AS. |
| | | * Portions copyright 2022-2024 3A Systems,LLC. |
| | | */ |
| | |
| | | case CHANGE_AFTER_RESET: |
| | | app.println(INFO_BIND_MUST_CHANGE_PASSWORD.get()); |
| | | break; |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | } |
| | | |
| | |
| | | } else if (!isXMLPackageDirectoryValid()) { |
| | | throw new MojoExecutionException("The XML definition directory \"" |
| | | + getXMLPackageDirectory() + "\" does not exist."); |
| | | } else if (getClass().getResource(getStylesheetDirectory()) == null) { |
| | | } else if (GenerateConfigMojo.class.getResource(getStylesheetDirectory()) == null) { |
| | | throw new MojoExecutionException("The XSLT stylesheet directory \"" |
| | | + getStylesheetDirectory() + "\" does not exist."); |
| | | } |
| | |
| | | private Templates loadStylesheet(final String stylesheet) |
| | | throws TransformerConfigurationException { |
| | | final Source xslt = |
| | | new StreamSource(getClass().getResourceAsStream( |
| | | new StreamSource(GenerateConfigMojo.class.getResourceAsStream( |
| | | getStylesheetDirectory() + "/" + stylesheet)); |
| | | return stylesheetFactory.newTemplates(xslt); |
| | | } |
| | |
| | | * |
| | | * Copyright 2015-2016 ForgeRock AS. |
| | | * Portions Copyright 2017 Rosie Applications, Inc. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.forgerock.opendj.rest2ldap; |
| | | |
| | |
| | | public Rest2LdapHttpApplication() { |
| | | try { |
| | | // The null check is required for unit test mocks because the resource does not exist. |
| | | final URL configUrl = getClass().getResource("/config.json"); |
| | | final URL configUrl = Rest2LdapHttpApplication.class.getResource("/config.json"); |
| | | this.configDirectory = configUrl != null ? new File(configUrl.toURI()).getParentFile() : null; |
| | | } catch (final URISyntaxException e) { |
| | | throw new IllegalStateException(""+getClass().getResource("/config.json"),e); |
| | | throw new IllegalStateException("" + Rest2LdapHttpApplication.class.getResource("/config.json"), e); |
| | | } |
| | | this.schema = Schema.getDefaultSchema(); |
| | | } |
| | |
| | | * information: "Portions copyright [year] [name of copyright owner]". |
| | | * |
| | | * Copyright 2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.forgerock.opendj.rest2ldap.schema; |
| | | |
| | |
| | | if (value == null) { |
| | | return createNullIndexKey(builder); |
| | | } else if (value instanceof Number) { |
| | | final Double doubleValue = ((Number) value).doubleValue(); |
| | | final double doubleValue = ((Number) value).doubleValue(); |
| | | return createNumberIndexKey(builder, BigDecimal.valueOf(doubleValue)); |
| | | } else if (value instanceof Boolean) { |
| | | final Boolean booleanValue = (Boolean) value; |
| | |
| | | #!/usr/bin/env ruby |
| | | # |
| | | # Portions Copyright 2026 3A Systems, LLC. |
| | | # |
| | | |
| | | require 'fileutils' |
| | | |
| | |
| | | (0..replacements.size-1).step(2).each { |index| |
| | | pattern, replace = replacements[index], replacements[index+1] |
| | | replace = replace.gsub('{CLASSNAME}', classname(file)) |
| | | is_replaced = true |
| | | #while is_replaced |
| | | #puts "pattern: " + pattern.to_s |
| | | is_replaced = contents.gsub!(pattern, replace) |
| | |
| | | * |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2011-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.forgerock.opendj.reactive; |
| | | |
| | |
| | | */ |
| | | private final Object waitListen = new Object(); |
| | | |
| | | /** |
| | | * Condition predicate for {@link #waitListen}: set once the handler thread has attempted to open the listen socket |
| | | * (successfully or not). Guarded by the {@link #waitListen} monitor; protects the start method against spurious |
| | | * wakeups. |
| | | */ |
| | | private boolean listenAttempted; |
| | | |
| | | /** The friendly name of this connection handler. */ |
| | | private String friendlyName; |
| | | |
| | |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | * <p> |
| | | * Deliberately left unsynchronized, unlike the overridden {@link Thread#start()}: the state this method touches is |
| | | * guarded by the {@link #waitListen} monitor, and holding the thread's own monitor across {@code waitListen.wait()} |
| | | * would block {@link Thread#join()}. |
| | | */ |
| | | @Override |
| | | public void start() { |
| | | // The Directory Server start process should only return when the connection handler port is fully opened |
| | | // and working. The start method therefore needs to wait for the created thread. |
| | | synchronized (waitListen) { |
| | | super.start(); |
| | | |
| | | final long deadlineNanos = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(LISTEN_TIMEOUT_MS); |
| | | try { |
| | | while (!listenAttempted) { |
| | | final long remainingMs = TimeUnit.NANOSECONDS.toMillis(deadlineNanos - System.nanoTime()); |
| | | if (remainingMs <= 0) { |
| | | logger.error(ERR_CONNHANDLER_TIMEOUT_WAITING_FOR_LISTENER, handlerName, |
| | | TimeUnit.MILLISECONDS.toSeconds(LISTEN_TIMEOUT_MS)); |
| | | break; |
| | | } |
| | | waitListen.wait(remainingMs); |
| | | } |
| | | } catch (InterruptedException e) { |
| | | // If something interrupted the start its probably better to return ASAP. |
| | | Thread.currentThread().interrupt(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Operates in a loop, accepting new connections and ensuring that requests on those connections are handled |
| | | * properly. |
| | | */ |
| | |
| | | // so notify here to allow the server startup to complete. |
| | | synchronized (waitListen) { |
| | | starting = false; |
| | | waitListen.notify(); |
| | | listenAttempted = true; |
| | | waitListen.notifyAll(); |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | try { |
| | | // At this point, the connection Handler either started correctly or failed |
| | | // to start but the start process should be notified and resume its work in any cases. |
| | | synchronized (waitListen) { |
| | | waitListen.notify(); |
| | | } |
| | | |
| | | // If we have gotten here, then we are about to start listening |
| | | // for the first time since startup or since we were previously disabled. |
| | | startListener(); |
| | |
| | | } else { |
| | | lastIterationFailed = true; |
| | | } |
| | | } finally { |
| | | // At this point, the connection handler either started listening or failed to do so, |
| | | // but the start process should be notified and resume its work in any cases. |
| | | synchronized (waitListen) { |
| | | listenAttempted = true; |
| | | waitListen.notifyAll(); |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | connectionPool = cpool; |
| | | connectionPool.addReferralAuthenticationListener(this); |
| | | |
| | | refreshQueue = new NodeSearcherQueue("New red", 2); |
| | | refreshQueue = new NodeSearcherQueue("New red", 2).start(); |
| | | |
| | | // NUMSUBORDINATE HACK |
| | | // Create an empty hacker to avoid null value test. |
| | |
| | | errorType = ERROR_SEARCHING_CHILDREN; |
| | | break; |
| | | |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | errorException = error.getException(); |
| | | errorArg = error.getArg(); |
| | |
| | | private final List<AbstractNodeTask> waitingQueue = new ArrayList<>(); |
| | | private final Map<BasicNode, AbstractNodeTask> workingList = new HashMap<>(); |
| | | private final ThreadGroup threadGroup; |
| | | private final List<Thread> threads = new ArrayList<>(); |
| | | |
| | | |
| | | /** |
| | |
| | | for (int i = 0; i < threadCount; i++) { |
| | | Thread t = new Thread(threadGroup, this, name + "[" + i + "]"); |
| | | t.setPriority(Thread.MIN_PRIORITY); |
| | | threads.add(t); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Starts the threads consuming this queue. |
| | | * <p> |
| | | * The threads are not started by the constructor so that {@code this} is not published to them |
| | | * before construction has completed. |
| | | * |
| | | * @return this queue |
| | | */ |
| | | public NodeSearcherQueue start() { |
| | | for (Thread t : threads) { |
| | | t.start(); |
| | | } |
| | | return this; |
| | | } |
| | | |
| | | /** |
| | |
| | | throw new IllegalArgumentException("null argument"); |
| | | } |
| | | waitingQueue.add(nodeTask); |
| | | notify(); |
| | | notifyAll(); |
| | | // System.out.println("Queued " + nodeTask + " in " + _name); |
| | | } |
| | | |
| | |
| | | if (task != null) { |
| | | task.cancel(); |
| | | } |
| | | notify(); |
| | | notifyAll(); |
| | | } |
| | | |
| | | /** |
| | |
| | | throw new IllegalArgumentException("null argument"); |
| | | } |
| | | workingList.remove(task.getNode()); |
| | | notify(); |
| | | notifyAll(); |
| | | // System.out.println("Flushed " + task + " from " + _name); |
| | | } |
| | | |
| | |
| | | * |
| | | * Copyright 2008-2009 Sun Microsystems, Inc. |
| | | * Portions Copyright 2011-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.guitools.controlpanel.task; |
| | | |
| | |
| | | case DELETE: |
| | | sb.append("delete: ").append(attrDesc).append("<br>"); |
| | | break; |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | |
| | | for (ByteString value : attr) |
| | |
| | | * |
| | | * Copyright 2008-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2011-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | |
| | | package org.opends.guitools.controlpanel.ui; |
| | |
| | | } |
| | | synchronized (entryReaderThread) |
| | | { |
| | | entryReaderThread.notify(); |
| | | entryReaderThread.notifyAll(); |
| | | } |
| | | } |
| | | |
| | |
| | | * |
| | | * Copyright 2008-2009 Sun Microsystems, Inc. |
| | | * Portions Copyright 2014-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.guitools.controlpanel.ui; |
| | | |
| | |
| | | } |
| | | if (visible && lastComponentWithFocus != null && lastComponentWithFocus.isVisible()) |
| | | { |
| | | if (lastComponentWithFocus == null) |
| | | { |
| | | lastComponentWithFocus = panel.getPreferredFocusComponent(); |
| | | } |
| | | lastComponentWithFocus.requestFocusInWindow(); |
| | | } |
| | | updateDefaultButton(panel); |
| | |
| | | * |
| | | * Copyright 2008-2009 Sun Microsystems, Inc. |
| | | * Portions Copyright 2014-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.guitools.controlpanel.ui; |
| | | |
| | |
| | | case SUBSTRING: |
| | | substring.setSelected(true); |
| | | break; |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | } |
| | | |
| | |
| | | * |
| | | * Copyright 2008-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2013-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.guitools.controlpanel.ui; |
| | | |
| | |
| | | args.add("--recurringTask"); |
| | | args.add(schedule.getCronValue()); |
| | | break; |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | return args; |
| | | } |
| | |
| | | * |
| | | * Copyright 2008 Sun Microsystems, Inc. |
| | | * Portions Copyright 2014-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.guitools.controlpanel.ui.components; |
| | | |
| | |
| | | } |
| | | |
| | | @Override |
| | | public void addMouseListener(MouseListener mouseListener) |
| | | public synchronized void addMouseListener(MouseListener mouseListener) |
| | | { |
| | | super.addMouseListener(mouseListener); |
| | | if (mouseListeners == null) |
| | |
| | | } |
| | | |
| | | @Override |
| | | public void removeMouseListener(MouseListener mouseListener) |
| | | public synchronized void removeMouseListener(MouseListener mouseListener) |
| | | { |
| | | super.removeMouseListener(mouseListener); |
| | | mouseListeners.remove(mouseListener); |
| | |
| | | * |
| | | * Copyright 2008 Sun Microsystems, Inc. |
| | | * Portions Copyright 2015-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | |
| | | package org.opends.guitools.controlpanel.ui.components; |
| | |
| | | } |
| | | |
| | | @Override |
| | | public void addActionListener(ActionListener listener) |
| | | public synchronized void addActionListener(ActionListener listener) |
| | | { |
| | | listeners.add(listener); |
| | | } |
| | | |
| | | @Override |
| | | public void removeActionListener(ActionListener listener) |
| | | public synchronized void removeActionListener(ActionListener listener) |
| | | { |
| | | listeners.remove(listener); |
| | | } |
| | |
| | | { |
| | | return NO_VALUE_SET.toString(); |
| | | } |
| | | Long l = Long.parseLong(monitoringValue); |
| | | long l = Long.parseLong(monitoringValue); |
| | | Date date = new Date(l); |
| | | return ConfigFromConnection.newDateFormatter().format(date); |
| | | } |
| | |
| | | } |
| | | else if (attr.isValueInBytes()) |
| | | { |
| | | Long l = Long.parseLong(monitoringValue); |
| | | long l = Long.parseLong(monitoringValue); |
| | | long mb = l / (1024 * 1024); |
| | | long kbs = (l - mb * 1024 * 1024) / 1024; |
| | | return INFO_CTRL_PANEL_MEMORY_VALUE.get(mb, kbs).toString(); |
| | |
| | | * |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2014-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.guitools.uninstaller; |
| | | |
| | |
| | | stopProcessing = true; |
| | | } |
| | | } |
| | | break; |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | exceptionMsgs.add(getMessage(e)); |
| | | } |
| | |
| | | * |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2011-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.quicksetup; |
| | | |
| | |
| | | ProcessBuilder pb = new ProcessBuilder(args); |
| | | InputStream is = null; |
| | | OutputStream out = null; |
| | | BufferedReader reader = null; |
| | | final boolean[] done = {false}; |
| | | try { |
| | | Map<String, String> env = pb.environment(); |
| | |
| | | }); |
| | | t.start(); |
| | | } |
| | | BufferedReader reader = new BufferedReader(new InputStreamReader(is)); |
| | | reader = new BufferedReader(new InputStreamReader(is)); |
| | | String line = reader.readLine(); |
| | | bi.values.put(NAME, line); |
| | | StringBuilder sb = new StringBuilder(); |
| | |
| | | |
| | | } finally { |
| | | done[0] = true; |
| | | StaticUtils.close(is, out); |
| | | StaticUtils.close(reader, is, out); |
| | | } |
| | | |
| | | // Make sure we got values for important properties that are used |
| | |
| | | * |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2011-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.quicksetup.installer; |
| | | |
| | |
| | | case IMPORT_AUTOMATICALLY_GENERATED_DATA: |
| | | steps.add(InstallProgressStep.IMPORTING_AUTOMATICALLY_GENERATED); |
| | | break; |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | } |
| | | |
| | |
| | | int cumulatedTime = 0; |
| | | for (InstallProgressStep s : steps) |
| | | { |
| | | Integer statusTime = s.getRelativeDuration(); |
| | | int statusTime = s.getRelativeDuration(); |
| | | hmRatio.put(s, (100 * cumulatedTime) / totalTime); |
| | | cumulatedTime += statusTime; |
| | | } |
| | |
| | | return new ProgressPanel(this); |
| | | case FINISHED: |
| | | return new FinishedPanel(this); |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | } |
| | | return null; |
| | |
| | | { |
| | | throw new ApplicationException(ReturnCode.APPLICATION_ERROR, pnfe.getMessageObject(), null); |
| | | } |
| | | StaticUtils.sleep((5 - nTries) * 3000); |
| | | StaticUtils.sleep((5 - nTries) * 3000L); |
| | | } |
| | | nTries--; |
| | | } |
| | |
| | | import java.io.FileReader; |
| | | import java.io.FileWriter; |
| | | import java.io.IOException; |
| | | import java.io.InputStreamReader; |
| | | import java.nio.file.Files; |
| | | import java.util.ArrayList; |
| | | import java.util.Arrays; |
| | |
| | | try |
| | | { |
| | | process = processBuilder.start(); |
| | | final BufferedReader err = new BufferedReader(new InputStreamReader(process.getErrorStream())); |
| | | new OutputReader(err) |
| | | new OutputReader(process.getErrorStream()) |
| | | { |
| | | @Override |
| | | public void processLine(final String line) |
| | |
| | | application.notifyListeners(LocalizableMessage.raw(line)); |
| | | application.notifyListeners(application.getLineBreak()); |
| | | } |
| | | }; |
| | | }.start(); |
| | | |
| | | final BufferedReader out = new BufferedReader(new InputStreamReader(process.getInputStream())); |
| | | new OutputReader(out) |
| | | new OutputReader(process.getInputStream()) |
| | | { |
| | | @Override |
| | | public void processLine(final String line) |
| | |
| | | application.notifyListeners(LocalizableMessage.raw(line)); |
| | | application.notifyListeners(application.getLineBreak()); |
| | | } |
| | | }; |
| | | }.start(); |
| | | |
| | | return process.waitFor(); |
| | | } |
| | |
| | | { |
| | | if (process != null) |
| | | { |
| | | closeProcessStream(process.getErrorStream(), "error"); |
| | | closeProcessStream(process.getOutputStream(), "output"); |
| | | // The error and output streams of the process are owned by the readers started above, |
| | | // which close them once drained. Only the stream writing to the standard input of the |
| | | // process, which is never used here, is left to close. |
| | | closeProcessStream(process.getOutputStream(), "input"); |
| | | } |
| | | } |
| | | } |
| | |
| | | * |
| | | * Copyright 2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2013-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.quicksetup.installer.ui; |
| | | |
| | |
| | | get(); |
| | | } |
| | | break; |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | } |
| | | else if (repl.getType() == DataReplicationOptions.Type.IN_EXISTING_TOPOLOGY) |
| | |
| | | * |
| | | * Copyright 2008 Sun Microsystems, Inc. |
| | | * Portions Copyright 2014-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | |
| | | package org.opends.quicksetup.util; |
| | | |
| | | import java.io.BufferedReader; |
| | | import java.io.InputStream; |
| | | import java.io.InputStreamReader; |
| | | |
| | | import org.forgerock.i18n.LocalizableMessage; |
| | | import org.forgerock.i18n.slf4j.LocalizedLogger; |
| | |
| | | */ |
| | | public abstract void processLine(String line); |
| | | |
| | | private final Thread thread; |
| | | |
| | | /** |
| | | * The protected constructor. |
| | | * <p> |
| | | * The stream is consumed until end of stream and then closed by this reader's thread, which is |
| | | * only launched by {@link #start()}. Wrapping the stream is done by that thread as well, so that |
| | | * this reader is the sole owner of every resource built on top of the stream. |
| | | * |
| | | * @param reader the BufferedReader of the stop process. |
| | | * @param stream the output stream of the process to read. |
| | | */ |
| | | public OutputReader(final BufferedReader reader) { |
| | | Thread t = new Thread(new Runnable() { |
| | | public OutputReader(final InputStream stream) { |
| | | thread = new Thread(new Runnable() { |
| | | @Override |
| | | public void run() { |
| | | try { |
| | | try (BufferedReader in = new BufferedReader(new InputStreamReader(stream))) { |
| | | String line; |
| | | while (null != (line = reader.readLine())) { |
| | | while (null != (line = in.readLine())) { |
| | | processLine(line); |
| | | } |
| | | } catch (Throwable t) { |
| | |
| | | } |
| | | } |
| | | }); |
| | | t.start(); |
| | | } |
| | | |
| | | /** |
| | | * Starts consuming the reader in a background thread. |
| | | * <p> |
| | | * The thread is not started by the constructor so that {@code this} does not escape before |
| | | * construction of the subclass has completed. |
| | | * |
| | | * @return this reader |
| | | */ |
| | | public OutputReader start() { |
| | | thread.start(); |
| | | return this; |
| | | } |
| | | } |
| | |
| | | |
| | | import java.io.BufferedReader; |
| | | import java.io.IOException; |
| | | import java.io.InputStream; |
| | | import java.io.InputStreamReader; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | |
| | | logger.info(LocalizableMessage.raw("Launching stop command, argList: "+argList)); |
| | | Process process = pb.start(); |
| | | |
| | | BufferedReader err = |
| | | new BufferedReader( |
| | | new InputStreamReader(process.getErrorStream())); |
| | | BufferedReader out = |
| | | new BufferedReader( |
| | | new InputStreamReader(process.getInputStream())); |
| | | |
| | | /* Create these objects to resend the stop process output to the details area. */ |
| | | new StopReader(err, true); |
| | | new StopReader(out, false); |
| | | new StopReader(process.getErrorStream(), true); |
| | | new StopReader(process.getInputStream(), false); |
| | | |
| | | int returnValue = process.waitFor(); |
| | | |
| | |
| | | String startedId = getStartedId(); |
| | | Process process = pb.start(); |
| | | |
| | | BufferedReader err = new BufferedReader(new InputStreamReader(process.getErrorStream())); |
| | | BufferedReader out = new BufferedReader(new InputStreamReader(process.getInputStream())); |
| | | |
| | | StartReader errReader = new StartReader(err, startedId, true); |
| | | StartReader outputReader = new StartReader(out, startedId, false); |
| | | StartReader errReader = new StartReader(process.getErrorStream(), startedId, true); |
| | | StartReader outputReader = new StartReader(process.getInputStream(), startedId, false); |
| | | |
| | | int returnValue = process.waitFor(); |
| | | |
| | |
| | | /** |
| | | * The protected constructor. |
| | | * |
| | | * @param reader the BufferedReader of the stop process. |
| | | * @param isError a boolean indicating whether the BufferedReader |
| | | * @param stream the stream of the stop process to read. |
| | | * @param isError a boolean indicating whether the stream |
| | | * corresponds to the standard error or to the standard output. |
| | | */ |
| | | public StopReader(final BufferedReader reader, |
| | | final boolean isError) { |
| | | public StopReader(final InputStream stream, final boolean isError) { |
| | | final LocalizableMessage errorTag = |
| | | isError ? |
| | | INFO_ERROR_READING_ERROROUTPUT.get() : |
| | |
| | | Thread t = new Thread(new Runnable() { |
| | | @Override |
| | | public void run() { |
| | | try { |
| | | String line = reader.readLine(); |
| | | // The reader is owned by this thread, which closes it once the stream is drained. |
| | | try (BufferedReader in = new BufferedReader(new InputStreamReader(stream))) { |
| | | String line = in.readLine(); |
| | | while (line != null) { |
| | | if (application != null) { |
| | | LocalizableMessageBuilder buf = new LocalizableMessageBuilder(); |
| | |
| | | isFirstLine = false; |
| | | } |
| | | logger.info(LocalizableMessage.raw("server: " + line)); |
| | | line = reader.readLine(); |
| | | line = in.readLine(); |
| | | } |
| | | } catch (Throwable t) { |
| | | if (application != null) { |
| | |
| | | |
| | | /** |
| | | * The protected constructor. |
| | | * @param reader the BufferedReader of the start process. |
| | | * @param stream the stream of the start process to read. |
| | | * @param startedId the message ID that this class can use to know whether |
| | | * the start is over or not. |
| | | * @param isError a boolean indicating whether the BufferedReader |
| | | * @param isError a boolean indicating whether the stream |
| | | * corresponds to the standard error or to the standard output. |
| | | */ |
| | | public StartReader(final BufferedReader reader, final String startedId, |
| | | public StartReader(final InputStream stream, final String startedId, |
| | | final boolean isError) |
| | | { |
| | | final LocalizableMessage errorTag = |
| | |
| | | @Override |
| | | public void run() |
| | | { |
| | | try |
| | | // The reader is owned by this thread, which closes it once the stream is drained. |
| | | try (BufferedReader in = new BufferedReader(new InputStreamReader(stream))) |
| | | { |
| | | String line = reader.readLine(); |
| | | String line = in.readLine(); |
| | | while (line != null) |
| | | { |
| | | if (application != null) { |
| | |
| | | isFinished = true; |
| | | startedIdFound = true; |
| | | } |
| | | line = reader.readLine(); |
| | | line = in.readLine(); |
| | | } |
| | | } catch (Throwable t) |
| | | { |
| | |
| | | final Process process = pb.start(); |
| | | logger.info(LocalizableMessage.raw("launching " + args + " with env: " + env)); |
| | | InputStream is = process.getInputStream(); |
| | | BufferedReader reader = new BufferedReader(new InputStreamReader(is)); |
| | | String line; |
| | | boolean errorDetected = false; |
| | | while (null != (line = reader.readLine())) |
| | | try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) |
| | | { |
| | | logger.info(LocalizableMessage.raw("The output: " + line)); |
| | | if (line.contains("ERROR: The detected Java version")) |
| | | String line; |
| | | while (null != (line = reader.readLine())) |
| | | { |
| | | if (isWindows()) |
| | | logger.info(LocalizableMessage.raw("The output: " + line)); |
| | | if (line.contains("ERROR: The detected Java version")) |
| | | { |
| | | // If we are running windows, the process get blocked waiting for |
| | | // user input. Just wait for a certain time to print the output |
| | | // in the logger and then kill the process. |
| | | Thread t = new Thread(new Runnable() |
| | | if (isWindows()) |
| | | { |
| | | @Override |
| | | public void run() |
| | | // If we are running windows, the process get blocked waiting for |
| | | // user input. Just wait for a certain time to print the output |
| | | // in the logger and then kill the process. |
| | | Thread t = new Thread(new Runnable() |
| | | { |
| | | try |
| | | @Override |
| | | public void run() |
| | | { |
| | | Thread.sleep(3000); |
| | | // To see if the process is over, call the exitValue method. |
| | | // If it is not over, a IllegalThreadStateException. |
| | | process.exitValue(); |
| | | try |
| | | { |
| | | Thread.sleep(3000); |
| | | // To see if the process is over, call the exitValue method. |
| | | // If it is not over, a IllegalThreadStateException. |
| | | process.exitValue(); |
| | | } |
| | | catch (Throwable t) |
| | | { |
| | | process.destroy(); |
| | | } |
| | | } |
| | | catch (Throwable t) |
| | | { |
| | | process.destroy(); |
| | | } |
| | | } |
| | | }); |
| | | t.start(); |
| | | }); |
| | | t.start(); |
| | | } |
| | | errorDetected = true; |
| | | } |
| | | errorDetected = true; |
| | | } |
| | | } |
| | | process.waitFor(); |
| | |
| | | Application app) |
| | | throws FileNotFoundException, IllegalArgumentException |
| | | { |
| | | this(new FileInputStream(zipFile), |
| | | // The name is validated before the stream is opened, otherwise the stream would leak when the |
| | | // validation fails. |
| | | this(openZipFile(zipFile), |
| | | minRatio, |
| | | maxRatio, |
| | | numberZipEntries, |
| | | zipFile.getName(), |
| | | app); |
| | | } |
| | | |
| | | private static FileInputStream openZipFile(File zipFile) throws FileNotFoundException |
| | | { |
| | | if (!zipFile.getName().endsWith(".zip")) { |
| | | throw new IllegalArgumentException("File must have extension .zip"); |
| | | } |
| | | return new FileInputStream(zipFile); |
| | | } |
| | | |
| | | /** |
| | |
| | | * |
| | | * Copyright 2006-2009 Sun Microsystems, Inc. |
| | | * Portions Copyright 2012-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.api; |
| | | |
| | |
| | | import java.util.Collection; |
| | | import java.util.Collections; |
| | | import java.util.List; |
| | | import java.util.concurrent.TimeUnit; |
| | | |
| | | import org.forgerock.i18n.LocalizableMessage; |
| | | import org.forgerock.opendj.server.config.server.ConnectionHandlerCfg; |
| | |
| | | |
| | | private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); |
| | | |
| | | /** |
| | | * Maximum time a {@code start()} implementation waits for its handler thread |
| | | * to attempt to open the listen socket. The wait is bounded so that a handler |
| | | * thread dying before it reaches the listen code cannot hang the whole server |
| | | * startup. |
| | | * <p> |
| | | * {@code DirectoryServer.startConnectionHandlers()} starts the handlers one |
| | | * after another, so the worst case for a start is this value multiplied by |
| | | * the number of configured handlers. It is therefore kept far below the |
| | | * {@code start-ds} timeout ({@code DirectoryServer.DEFAULT_TIMEOUT}, 200 |
| | | * seconds), which is generous for a {@code bind()}. |
| | | */ |
| | | protected static final long LISTEN_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(15); |
| | | |
| | | /** The monitor associated with this connection handler. */ |
| | | private ConnectionHandlerMonitor monitor; |
| | | |
| | |
| | | * Portions Copyright 2011-2016 ForgeRock AS. |
| | | * Portions Copyright 2013 Manuel Gaupp |
| | | * Portions Copyright 2024 3A Systems, LLC. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.authorization.dseecompat; |
| | | |
| | |
| | | } |
| | | } |
| | | break; |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | /* |
| | | * Check if the modification type has an "aci" attribute type. |
| | |
| | | throw new AciException( |
| | | WARN_ACI_SYNTAX_INVALID_BIND_RULE_KEYWORD_OPERATOR_COMBO.get(keyword, op)); |
| | | } |
| | | break; |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | } |
| | | |
| | |
| | | * should be appended. |
| | | */ |
| | | public final void toString(StringBuilder buffer) { |
| | | if (this.keywordRuleMap != null) { |
| | | for (KeywordBindRule rule : this.keywordRuleMap.values()) { |
| | | rule.toString(buffer); |
| | | buffer.append(";"); |
| | | } |
| | | for (KeywordBindRule rule : this.keywordRuleMap.values()) { |
| | | rule.toString(buffer); |
| | | buffer.append(";"); |
| | | } |
| | | } |
| | | } |
| | |
| | | * |
| | | * Copyright 2008 Sun Microsystems, Inc. |
| | | * Portions Copyright 2011-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.authorization.dseecompat; |
| | | |
| | |
| | | //a message if it is seen in the expression. |
| | | throw new AciException(WARN_ACI_SYNTAX_ROLEDN_NOT_SUPPORTED.get(expression)); |
| | | } |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | return new UserAttr(vals[0], vals[1], userAttrType, type); |
| | | } |
| | |
| | | * |
| | | * Copyright 2007-2008 Sun Microsystems, Inc. |
| | | * Portions Copyright 2011-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.backends; |
| | | |
| | |
| | | |
| | | try |
| | | { |
| | | if (entryMap != null) |
| | | { |
| | | return entryMap.size(); |
| | | } |
| | | |
| | | return -1; |
| | | return entryMap.size(); |
| | | } |
| | | finally |
| | | { |
| | |
| | | * |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2012-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.backends.pluggable; |
| | | |
| | |
| | | update(txn, entryDN, toStrings(a)); |
| | | } |
| | | break; |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | } |
| | | } |
| | |
| | | * |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2012-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.backends.pluggable; |
| | | |
| | |
| | | { |
| | | return Entry.decode(reader, compressedSchema); |
| | | } |
| | | InputStream is = reader.asInputStream(); |
| | | if ((format & ENCRYPT_ENTRY) == ENCRYPT_ENTRY) |
| | | try (InputStream entryStream = newEntryInputStream(reader, format)) |
| | | { |
| | | is = getCryptoManager().getCipherInputStream(is); |
| | | } |
| | | if ((format & COMPRESS_ENTRY) == COMPRESS_ENTRY) |
| | | { |
| | | is = new InflaterInputStream(is); |
| | | } |
| | | byte[] data = new byte[encodedEntryLen]; |
| | | int readBytes; |
| | | int position = 0; |
| | | int leftToRead = encodedEntryLen; |
| | | // CipherInputStream does not read more than block size... |
| | | do |
| | | { |
| | | if ((readBytes = is.read(data, position, leftToRead)) == -1 ) |
| | | byte[] data = new byte[encodedEntryLen]; |
| | | int readBytes; |
| | | int position = 0; |
| | | int leftToRead = encodedEntryLen; |
| | | // CipherInputStream does not read more than block size... |
| | | do |
| | | { |
| | | throw DecodeException.error(ERR_CANNOT_DECODE_ENTRY.get()); |
| | | } |
| | | position += readBytes; |
| | | leftToRead -= readBytes; |
| | | } while (leftToRead > 0 && readBytes > 0); |
| | | return Entry.decode(ByteString.wrap(data).asReader(), compressedSchema); |
| | | if ((readBytes = entryStream.read(data, position, leftToRead)) == -1 ) |
| | | { |
| | | throw DecodeException.error(ERR_CANNOT_DECODE_ENTRY.get()); |
| | | } |
| | | position += readBytes; |
| | | leftToRead -= readBytes; |
| | | } while (leftToRead > 0 && readBytes > 0); |
| | | return Entry.decode(ByteString.wrap(data).asReader(), compressedSchema); |
| | | } |
| | | } |
| | | catch (CryptoManagerException cme) |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Returns the stream to read the encoded entry from, decorated as mandated by the format. |
| | | * <p> |
| | | * The returned stream owns the streams it wraps, so closing it closes the whole chain. |
| | | * |
| | | * @param reader the reader positioned at the start of the encoded entry. |
| | | * @param format the format byte of the encoded entry. |
| | | * @return the stream to read the encoded entry from. |
| | | * @throws CryptoManagerException If the cipher input stream cannot be created. |
| | | */ |
| | | private static InputStream newEntryInputStream(ByteSequenceReader reader, int format) |
| | | throws CryptoManagerException |
| | | { |
| | | InputStream is = reader.asInputStream(); |
| | | if ((format & ENCRYPT_ENTRY) == ENCRYPT_ENTRY) |
| | | { |
| | | is = getCryptoManager().getCipherInputStream(is); |
| | | } |
| | | if ((format & COMPRESS_ENTRY) == COMPRESS_ENTRY) |
| | | { |
| | | is = new InflaterInputStream(is); |
| | | } |
| | | return is; |
| | | } |
| | | |
| | | private ByteString encode(Entry entry, DataConfig dataConfig) throws DirectoryException |
| | | { |
| | | encodeVolatile(entry, dataConfig); |
| | |
| | | * |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2011-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.backends.pluggable; |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | nextEntryID = new AtomicLong(highestID.longValue() + 1); |
| | | // highestID is null when there was no base DN to open, in which case numbering starts at 1. |
| | | nextEntryID = new AtomicLong(highestID != null ? highestID.longValue() + 1 : 1); |
| | | } |
| | | |
| | | /** |
| | |
| | | * |
| | | * Copyright 2006-2009 Sun Microsystems, Inc. |
| | | * Portions Copyright 2011-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.backends.task; |
| | | |
| | |
| | | searchScheduledTasks = true; |
| | | searchRecurringTasks = true; |
| | | break; |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | } |
| | | else if (baseDN.equals(scheduledTaskParentDN)) |
| | |
| | | case SUBORDINATES: |
| | | searchScheduledTasks = true; |
| | | break; |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | } |
| | | else if (baseDN.equals(recurringTaskParentDN)) |
| | |
| | | case SUBORDINATES: |
| | | searchRecurringTasks = true; |
| | | break; |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | } |
| | | else |
| | |
| | | * |
| | | * Copyright 2006-2009 Sun Microsystems, Inc. |
| | | * Portions Copyright 2013-2014 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.backends.task; |
| | | |
| | |
| | | |
| | | synchronized (notifyLock) |
| | | { |
| | | notifyLock.notify(); |
| | | notifyLock.notifyAll(); |
| | | } |
| | | } |
| | | |
| | |
| | | * information: "Portions Copyright [year] [name of copyright owner]". |
| | | * |
| | | * Copyright 2014-2016 ForgeRock AS. |
| | | * Portions Copyright 2025 3A Systems,LLC |
| | | * Portions Copyright 2025-2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.config; |
| | | |
| | |
| | | { |
| | | byte[] buffer = new byte[8192]; |
| | | try(FileInputStream inputStream = new FileInputStream(configFile); |
| | | GZIPOutputStream outputStream = new GZIPOutputStream(new FileOutputStream(archiveFile))) |
| | | FileOutputStream archiveStream = new FileOutputStream(archiveFile); |
| | | GZIPOutputStream outputStream = new GZIPOutputStream(archiveStream)) |
| | | { |
| | | int bytesRead = inputStream.read(buffer); |
| | | while (bytesRead > 0) |
| | |
| | | * |
| | | * Copyright 2007-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2013-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.core; |
| | | |
| | |
| | | { |
| | | bindDN = actualRootDN; |
| | | } |
| | | break; |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | |
| | | workflowExecuted = execute(this, bindDN); |
| | |
| | | } |
| | | break; |
| | | |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | // Modify may or may not be allowed, but we'll leave that |
| | | // determination up to the modify operation itself. |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | } |
| | | } |
| | |
| | | * information: "Portions Copyright [year] [name of copyright owner]". |
| | | * |
| | | * Copyright 2015 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.core; |
| | | |
| | |
| | | */ |
| | | public long memPercentToBytes(int percent) |
| | | { |
| | | return (reservableMemory * percent / 100) * ONE_MEGABYTE; |
| | | return ((long) reservableMemory * percent / 100) * ONE_MEGABYTE; |
| | | } |
| | | |
| | | /** |
| | |
| | | * |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2011-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.core; |
| | | |
| | |
| | | private DN newDN; |
| | | |
| | | /** |
| | | * Indicates whether the new entry DN has already been computed. The computation does not always |
| | | * yield a DN, and its failure is recorded on the operation, so it must not be repeated. |
| | | */ |
| | | private boolean newDNComputed; |
| | | |
| | | /** |
| | | * Creates a new modify DN operation with the provided information. |
| | | * |
| | | * @param clientConnection The client connection with which this operation |
| | |
| | | this.rawEntryDN = rawEntryDN; |
| | | |
| | | entryDN = null; |
| | | // The new DN is derived from the entry DN, so a failed computation must be allowed to run |
| | | // again. Any DN already computed is left in place, as it was before this flag existed. |
| | | newDNComputed = false; |
| | | } |
| | | |
| | | @Override |
| | |
| | | |
| | | newRDN = null; |
| | | newDN = null; |
| | | newDNComputed = false; |
| | | } |
| | | |
| | | @Override |
| | |
| | | |
| | | newSuperior = null; |
| | | newDN = null; |
| | | newDNComputed = false; |
| | | } |
| | | |
| | | @Override |
| | |
| | | @Override |
| | | public DN getNewDN() |
| | | { |
| | | if (newDN == null) |
| | | if (newDN == null && !newDNComputed) |
| | | { |
| | | newDNComputed = true; |
| | | |
| | | // Construct the new DN to use for the entry. |
| | | DN parentDN = null; |
| | | DN parentDN; |
| | | if (getNewSuperior() == null) |
| | | { |
| | | if (getEntryDN() != null) |
| | | if (getEntryDN() == null) |
| | | { |
| | | parentDN = DirectoryServer.getInstance().getServerContext().getBackendConfigManager() |
| | | .getParentDNInSuffix(entryDN); |
| | | // The raw DN could not be parsed and INVALID_DN_SYNTAX has already been recorded for it, |
| | | // so leave that diagnosis in place rather than replacing it with a less precise one. |
| | | return null; |
| | | } |
| | | parentDN = DirectoryServer.getInstance().getServerContext().getBackendConfigManager() |
| | | .getParentDNInSuffix(entryDN); |
| | | } |
| | | else |
| | | { |
| | |
| | | { |
| | | setResultCode(ResultCode.UNWILLING_TO_PERFORM); |
| | | appendErrorMessage(ERR_MODDN_NO_PARENT.get(entryDN)); |
| | | if (parentDN == null) |
| | | { |
| | | // Without a parent there is no new DN to build; the error set above is the outcome. |
| | | return null; |
| | | } |
| | | } |
| | | newDN = parentDN.child(getNewRDN()); |
| | | } |
| | |
| | | } |
| | | |
| | | @Override |
| | | public void abort(CancelRequest cancelRequest) |
| | | public synchronized void abort(CancelRequest cancelRequest) |
| | | { |
| | | if(cancelResult == null && this.cancelRequest == null) |
| | | { |
| | |
| | | } |
| | | } |
| | | break; |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | |
| | | return false; |
| | |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2009 Parametric Technology Corporation (PTC) |
| | | * Portions Copyright 2011-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.crypto; |
| | | |
| | |
| | | |
| | | // Requested encryption cipher validation. |
| | | String requestedCipherTransformation = cfg.getCipherTransformation(); |
| | | Integer requestedCipherTransformationKeyLengthBits = cfg.getCipherKeyLength(); |
| | | int requestedCipherTransformationKeyLengthBits = cfg.getCipherKeyLength(); |
| | | if (! requestedCipherTransformation.equals( |
| | | this.preferredCipherTransformation) || |
| | | requestedCipherTransformationKeyLengthBits != |
| | |
| | | |
| | | // Requested MAC algorithm validation. |
| | | String requestedMACAlgorithm = cfg.getMacAlgorithm(); |
| | | Integer requestedMACAlgorithmKeyLengthBits = cfg.getMacKeyLength(); |
| | | int requestedMACAlgorithmKeyLengthBits = cfg.getMacKeyLength(); |
| | | if (!requestedMACAlgorithm.equals(this.preferredMACAlgorithm) || |
| | | requestedMACAlgorithmKeyLengthBits != |
| | | this.preferredMACAlgorithmKeyLengthBits) |
| | |
| | | * |
| | | * Copyright 2008-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2014-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.extensions; |
| | | |
| | |
| | | public MemberList getMembers() |
| | | throws DirectoryException |
| | | { |
| | | return new DynamicGroupMemberList(groupEntryDN, memberURLs); |
| | | return new DynamicGroupMemberList(groupEntryDN, memberURLs).start(); |
| | | } |
| | | |
| | | @Override |
| | |
| | | { |
| | | if (baseDN == null && filter == null) |
| | | { |
| | | return new DynamicGroupMemberList(groupEntryDN, memberURLs); |
| | | return new DynamicGroupMemberList(groupEntryDN, memberURLs).start(); |
| | | } |
| | | else |
| | | { |
| | | return new DynamicGroupMemberList(groupEntryDN, memberURLs, baseDN, scope, |
| | | filter); |
| | | filter).start(); |
| | | } |
| | | } |
| | | |
| | |
| | | * |
| | | * Copyright 2008 Sun Microsystems, Inc. |
| | | * Portions Copyright 2014-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.extensions; |
| | | |
| | |
| | | */ |
| | | private final LinkedBlockingQueue<Object> resultQueue; |
| | | |
| | | /** The background thread which performs the internal searches. */ |
| | | private final DynamicGroupSearchThread searchThread; |
| | | |
| | | /** The search filter to use when filtering the set of group members. */ |
| | | private final SearchFilter filter; |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | DynamicGroupSearchThread searchThread = |
| | | searchThread = |
| | | new DynamicGroupSearchThread(this, baseDNArray, filterArray, urlArray); |
| | | } |
| | | |
| | | /** |
| | | * Starts the background searches which populate this member list. |
| | | * <p> |
| | | * The searches are not started by the constructor so that {@code this} is not published to the |
| | | * search thread before construction has completed. |
| | | * |
| | | * @return this member list |
| | | */ |
| | | DynamicGroupMemberList start() |
| | | { |
| | | searchThread.start(); |
| | | return this; |
| | | } |
| | | |
| | | /** |
| | |
| | | * |
| | | * Copyright 2006-2008 Sun Microsystems, Inc. |
| | | * Portions Copyright 2014-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.extensions; |
| | | |
| | |
| | | // Cache misses is required to get cache tries and hit ratio. |
| | | if (cacheMisses != null) |
| | | { |
| | | Long cacheTries = cacheHits + cacheMisses; |
| | | long cacheTries = cacheHits + cacheMisses; |
| | | attrs.add("entryCacheTries", cacheTries); |
| | | |
| | | Double hitRatioRaw = cacheTries > 0 ? cacheHits.doubleValue() |
| | | / cacheTries.doubleValue() : cacheHits.doubleValue() / 1; |
| | | double hitRatioRaw = cacheTries > 0 ? cacheHits.doubleValue() |
| | | / cacheTries : cacheHits.doubleValue(); |
| | | Double hitRatio = hitRatioRaw * 100D; |
| | | attrs.add("entryCacheHitRatio", hitRatio); |
| | | } |
| | |
| | | * |
| | | * Copyright 2008-2009 Sun Microsystems, Inc. |
| | | * Portions Copyright 2012-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.extensions; |
| | | |
| | |
| | | } |
| | | } |
| | | break; |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | } |
| | | } |
| | |
| | | * |
| | | * Copyright 2006-2009 Sun Microsystems, Inc. |
| | | * Portions Copyright 2013-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.extensions; |
| | | |
| | |
| | | return; |
| | | } |
| | | } |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | |
| | | |
| | |
| | | * |
| | | * Copyright 2008-2009 Sun Microsystems, Inc. |
| | | * Portions Copyright 2011-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.extensions; |
| | | |
| | |
| | | } |
| | | } |
| | | break; |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | |
| | | return null; |
| | |
| | | /** The number of bytes of random data to use as the salt when generating the hashes. */ |
| | | private static final int NUM_SALT_BYTES = 8; |
| | | |
| | | /** |
| | | * Source of randomness for the offline encoding, which has no access to the server's |
| | | * crypto manager. A single instance is shared because {@code SecureRandom} is thread-safe |
| | | * and reseeding it for every password would weaken it. |
| | | */ |
| | | private static final SecureRandom OFFLINE_RANDOM = new SecureRandom(); |
| | | |
| | | /** The number of bytes SHA algorithm produces. */ |
| | | private static final int SHA1_LENGTH = 20; |
| | | |
| | |
| | | throws DirectoryException |
| | | { |
| | | byte[] saltBytes = new byte[NUM_SALT_BYTES]; |
| | | new SecureRandom().nextBytes(saltBytes); |
| | | OFFLINE_RANDOM.nextBytes(saltBytes); |
| | | |
| | | byte[] passwordPlusSalt = new byte[passwordBytes.length + NUM_SALT_BYTES]; |
| | | System.arraycopy(passwordBytes, 0, passwordPlusSalt, 0, |
| | |
| | | /** The number of bytes of random data to use as the salt when generating the hashes. */ |
| | | private static final int NUM_SALT_BYTES = 8; |
| | | |
| | | /** |
| | | * Source of randomness for the offline encoding, which has no access to the server's |
| | | * crypto manager. A single instance is shared because {@code SecureRandom} is thread-safe |
| | | * and reseeding it for every password would weaken it. |
| | | */ |
| | | private static final SecureRandom OFFLINE_RANDOM = new SecureRandom(); |
| | | |
| | | /** The size of the digest in bytes. */ |
| | | private static final int SHA512_LENGTH = 512 / 8; |
| | | |
| | |
| | | throws DirectoryException |
| | | { |
| | | byte[] saltBytes = new byte[NUM_SALT_BYTES]; |
| | | new SecureRandom().nextBytes(saltBytes); |
| | | OFFLINE_RANDOM.nextBytes(saltBytes); |
| | | |
| | | byte[] passwordPlusSalt = new byte[passwordBytes.length + NUM_SALT_BYTES]; |
| | | System.arraycopy(passwordBytes, 0, passwordPlusSalt, 0, |
| | |
| | | * |
| | | * Copyright 2008-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2011-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.extensions; |
| | | |
| | |
| | | } |
| | | } |
| | | break; |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | } |
| | | } |
| | |
| | | |
| | | private String name; |
| | | private AtomicBoolean stopRequested; |
| | | private WriterThread writerThread; |
| | | private final WriterThread writerThread; |
| | | |
| | | private boolean autoFlush; |
| | | |
| | |
| | | |
| | | this.queue = new LinkedBlockingQueue<>(capacity); |
| | | this.capacity = capacity; |
| | | this.writerThread = null; |
| | | this.stopRequested = new AtomicBoolean(false); |
| | | |
| | | writerThread = new WriterThread(); |
| | | writerThread.start(); |
| | | |
| | | DirectoryServer.registerShutdownListener(this); |
| | | } |
| | | |
| | | /** |
| | | * Starts the background thread which publishes the queued log records. |
| | | * <p> |
| | | * The thread is not started by the constructor so that {@code this} is not published to it before |
| | | * construction has completed. |
| | | * |
| | | * @return this writer |
| | | */ |
| | | AsynchronousTextWriter start() |
| | | { |
| | | writerThread.start(); |
| | | return this; |
| | | } |
| | | |
| | | /** |
| | | * The publisher thread is responsible for emptying the queue of log records |
| | | * waiting to published. |
| | | */ |
| | |
| | | stopRequested.set(true); |
| | | |
| | | // Wait for publisher thread to terminate |
| | | while (writerThread != null && writerThread.isAlive()) { |
| | | while (writerThread.isAlive()) { |
| | | try { |
| | | // Interrupt the thread if its blocking |
| | | writerThread.interrupt(); |
| | |
| | | throws IOException, AuditException, ConfigException |
| | | { |
| | | final JsonValue jsonConfig; |
| | | try (InputStream input = getClass().getResourceAsStream(AUDIT_SERVICE_JSON_CONFIGURATION_FILE)) |
| | | try (InputStream input = CommonAudit.class.getResourceAsStream(AUDIT_SERVICE_JSON_CONFIGURATION_FILE)) |
| | | { |
| | | jsonConfig = AuditJsonConfig.getJson(input); |
| | | } |
| | |
| | | * information: "Portions Copyright [year] [name of copyright owner]". |
| | | * |
| | | * Copyright 2015-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.loggers; |
| | | |
| | |
| | | |
| | | private Pair<Long,TimeUnit> getExecutionTime(final Operation operation) |
| | | { |
| | | Long etime = operation.getProcessingNanoTime(); |
| | | long etime = operation.getProcessingNanoTime(); |
| | | // if not configured for nanos, use millis |
| | | return etime <= -1 ? |
| | | Pair.of(operation.getProcessingTime(), TimeUnit.MILLISECONDS) : |
| | |
| | | * information: "Portions Copyright [year] [name of copyright owner]". |
| | | * |
| | | * Copyright 2014-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.loggers; |
| | | |
| | |
| | | @Override |
| | | public void publish(LogRecord record) |
| | | { |
| | | if (getFormatter() == null) |
| | | // These calls resolve to Handler's own formatter, not to the enclosing |
| | | // JDKLogging.getFormatter(); qualify them so that is unambiguous. |
| | | if (super.getFormatter() == null) |
| | | { |
| | | setFormatter(new SimpleFormatter()); |
| | | super.setFormatter(new SimpleFormatter()); |
| | | } |
| | | |
| | | try |
| | | { |
| | | String message = getFormatter().format(record); |
| | | String message = super.getFormatter().format(record); |
| | | if (record.getLevel().intValue() >= Level.WARNING.intValue()) |
| | | { |
| | | err.write(message.getBytes()); |
| | |
| | | * |
| | | * Copyright 2006-2008 Sun Microsystems, Inc. |
| | | * Portions Copyright 2014-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.loggers; |
| | | |
| | |
| | | this.stopRequested = false; |
| | | |
| | | rotaterThread = new RotaterThread(this); |
| | | rotaterThread.start(); |
| | | |
| | | DirectoryServer.registerShutdownListener(this); |
| | | } |
| | | |
| | | /** |
| | | * Starts the background thread which rotates and retains the log files. |
| | | * <p> |
| | | * The thread is not started by the constructor so that {@code this} is not published to it before |
| | | * construction has completed. |
| | | * |
| | | * @return this writer |
| | | */ |
| | | MultifileTextWriter start() |
| | | { |
| | | rotaterThread.start(); |
| | | return this; |
| | | } |
| | | |
| | | /** |
| | | * Construct a PrintWriter for a file. |
| | | * @param file - the file to open for writing |
| | | * @param filePermissions - the file permissions to set on the file. |
| | |
| | | * |
| | | * Copyright 2006-2009 Sun Microsystems, Inc. |
| | | * Portions Copyright 2011-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.loggers; |
| | | |
| | |
| | | theWriter.addRetentionPolicy(DirectoryServer.getRetentionPolicy(dn)); |
| | | } |
| | | |
| | | // Rotation only starts once the policies above are registered. |
| | | theWriter.start(); |
| | | |
| | | if (cfg.isAsynchronous()) |
| | | { |
| | | this.writer = newAsyncWriter(theWriter, cfg); |
| | |
| | | private AsynchronousTextWriter newAsyncWriter(MultifileTextWriter mfWriter, FileBasedAccessLogPublisherCfg config) |
| | | { |
| | | String name = "Asynchronous Text Writer for " + config.dn(); |
| | | return new AsynchronousTextWriter(name, config.getQueueSize(), config.isAutoFlush(), mfWriter); |
| | | return new AsynchronousTextWriter(name, config.getQueueSize(), config.isAutoFlush(), mfWriter).start(); |
| | | } |
| | | |
| | | @Override |
| | |
| | | * |
| | | * Copyright 2006-2008 Sun Microsystems, Inc. |
| | | * Portions Copyright 2011-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.loggers; |
| | | |
| | |
| | | writer.addRetentionPolicy(DirectoryServer.getRetentionPolicy(dn)); |
| | | } |
| | | |
| | | // Rotation only starts once the policies above are registered. |
| | | writer.start(); |
| | | |
| | | if (cfg.isAsynchronous()) |
| | | { |
| | | this.writer = newAsyncWriter(writer, cfg); |
| | |
| | | private AsynchronousTextWriter newAsyncWriter(MultifileTextWriter writer, FileBasedAuditLogPublisherCfg cfg) |
| | | { |
| | | String name = "Asynchronous Text Writer for " + cfg.dn(); |
| | | return new AsynchronousTextWriter(name, cfg.getQueueSize(), cfg.isAutoFlush(), writer); |
| | | return new AsynchronousTextWriter(name, cfg.getQueueSize(), cfg.isAutoFlush(), writer).start(); |
| | | } |
| | | |
| | | @Override |
| | |
| | | * |
| | | * Copyright 2006-2009 Sun Microsystems, Inc. |
| | | * Portions Copyright 2013-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.loggers; |
| | | |
| | |
| | | writer.addRetentionPolicy(DirectoryServer.getRetentionPolicy(dn)); |
| | | } |
| | | |
| | | // Rotation only starts once the policies above are registered. |
| | | writer.start(); |
| | | |
| | | if(config.isAsynchronous()) |
| | | { |
| | | this.writer = newAsyncWriter(writer, config); |
| | |
| | | private AsynchronousTextWriter newAsyncWriter(MultifileTextWriter writer, FileBasedDebugLogPublisherCfg config) |
| | | { |
| | | String name = "Asynchronous Text Writer for " + config.dn(); |
| | | return new AsynchronousTextWriter(name, config.getQueueSize(), config.isAutoFlush(), writer); |
| | | return new AsynchronousTextWriter(name, config.getQueueSize(), config.isAutoFlush(), writer).start(); |
| | | } |
| | | |
| | | private void configure(MultifileTextWriter mfWriter, FileBasedDebugLogPublisherCfg config) throws DirectoryException |
| | |
| | | * |
| | | * Copyright 2006-2009 Sun Microsystems, Inc. |
| | | * Portions Copyright 2012-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.loggers; |
| | | |
| | |
| | | writer.addRetentionPolicy(DirectoryServer.getRetentionPolicy(dn)); |
| | | } |
| | | |
| | | // Rotation only starts once the policies above are registered. |
| | | writer.start(); |
| | | |
| | | if(config.isAsynchronous()) |
| | | { |
| | | this.writer = newAsyncWriter(writer, config); |
| | |
| | | private AsynchronousTextWriter newAsyncWriter(MultifileTextWriter mfWriter, FileBasedErrorLogPublisherCfg config) |
| | | { |
| | | String name = "Asynchronous Text Writer for " + config.dn(); |
| | | return new AsynchronousTextWriter(name, config.getQueueSize(), config.isAutoFlush(), mfWriter); |
| | | return new AsynchronousTextWriter(name, config.getQueueSize(), config.isAutoFlush(), mfWriter).start(); |
| | | } |
| | | |
| | | private void setDefaultSeverities(Set<ErrorLogPublisherCfgDefn.DefaultSeverity> defSevs) |
| | |
| | | * information: "Portions Copyright [year] [name of copyright owner]". |
| | | * |
| | | * Copyright 2013-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.loggers; |
| | | |
| | |
| | | private AsynchronousTextWriter newAsyncWriter(MultifileTextWriter mfWriter, FileBasedHTTPAccessLogPublisherCfg config) |
| | | { |
| | | String name = "Asynchronous Text Writer for " + config.dn(); |
| | | return new AsynchronousTextWriter(name, config.getQueueSize(), config.isAutoFlush(), mfWriter); |
| | | return new AsynchronousTextWriter(name, config.getQueueSize(), config.isAutoFlush(), mfWriter).start(); |
| | | } |
| | | |
| | | private LocalizableMessage setLogFormatFields(String logFormat) |
| | |
| | | theWriter.addRetentionPolicy(DirectoryServer.getRetentionPolicy(dn)); |
| | | } |
| | | |
| | | // Rotation only starts once the policies above are registered. |
| | | theWriter.start(); |
| | | |
| | | if (cfg.isAsynchronous()) |
| | | { |
| | | this.writer = newAsyncWriter(theWriter, cfg); |
| | |
| | | * |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2011-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.plugins; |
| | | |
| | |
| | | case USER_PASSWORD: |
| | | userPWTypes.add(t); |
| | | break; |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | } |
| | | |
| | |
| | | * |
| | | * Copyright 2006-2008 Sun Microsystems, Inc. |
| | | * Portions Copyright 2012-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.plugins.profiler; |
| | | |
| | |
| | | */ |
| | | public void processDataFile(String filename) throws IOException |
| | | { |
| | | // Try to open the file for reading. |
| | | ASN1Reader reader = ASN1.getReader(new FileInputStream(filename)); |
| | | |
| | | |
| | | try |
| | | // Both resources are declared here so that the file stream is closed as well if the reader |
| | | // cannot be created around it. |
| | | try (FileInputStream fileStream = new FileInputStream(filename); |
| | | ASN1Reader reader = ASN1.getReader(fileStream)) |
| | | { |
| | | // The first element in the file must be a sequence with the header |
| | | // information. |
| | |
| | | existingFrame.recurseSubFrames(stack, pos-1, count, stacksByMethod); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | close(reader); |
| | | } |
| | | } |
| | | |
| | | |
| | |
| | | * |
| | | * Copyright 2006-2008 Sun Microsystems, Inc. |
| | | * Portions Copyright 2014-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.plugins.profiler; |
| | | import static org.opends.messages.PluginMessages.*; |
| | |
| | | } |
| | | } |
| | | break; |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | |
| | | return ccr; |
| | |
| | | * information: "Portions Copyright [year] [name of copyright owner]". |
| | | * |
| | | * Copyright 2013-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.protocols.http; |
| | | |
| | |
| | | */ |
| | | private final Object waitListen = new Object(); |
| | | |
| | | /** |
| | | * Condition predicate for {@link #waitListen}: set once the handler thread |
| | | * has attempted to start the embedded HTTP server (successfully or not). |
| | | * Guarded by the {@link #waitListen} monitor; protects the start method |
| | | * against spurious wakeups. |
| | | */ |
| | | private boolean listenAttempted; |
| | | |
| | | /** The friendly name of this connection handler. */ |
| | | private String friendlyName; |
| | | |
| | |
| | | return httpServer != null; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | * <p> |
| | | * Deliberately left unsynchronized, unlike the overridden {@link Thread#start()}: |
| | | * the state this method touches is guarded by the {@link #waitListen} monitor, and |
| | | * holding the thread's own monitor across {@code waitListen.wait()} would block |
| | | * {@link Thread#join()}. |
| | | */ |
| | | @Override |
| | | public void start() |
| | | { |
| | |
| | | { |
| | | super.start(); |
| | | |
| | | final long deadlineNanos = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(LISTEN_TIMEOUT_MS); |
| | | try |
| | | { |
| | | waitListen.wait(); |
| | | while (!listenAttempted) |
| | | { |
| | | final long remainingMs = TimeUnit.NANOSECONDS.toMillis(deadlineNanos - System.nanoTime()); |
| | | if (remainingMs <= 0) |
| | | { |
| | | logger.error(ERR_CONNHANDLER_TIMEOUT_WAITING_FOR_LISTENER, handlerName, |
| | | TimeUnit.MILLISECONDS.toSeconds(LISTEN_TIMEOUT_MS)); |
| | | break; |
| | | } |
| | | waitListen.wait(remainingMs); |
| | | } |
| | | } |
| | | catch (InterruptedException e) |
| | | { |
| | | // If something interrupted the start its probably better to return ASAP |
| | | Thread.currentThread().interrupt(); |
| | | } |
| | | } |
| | | } |
| | |
| | | synchronized (waitListen) |
| | | { |
| | | starting = false; |
| | | waitListen.notify(); |
| | | listenAttempted = true; |
| | | waitListen.notifyAll(); |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | try |
| | | { |
| | | // At this point, the connection Handler either started correctly or failed |
| | | // to start but the start process should be notified and resume its work in any cases. |
| | | synchronized (waitListen) |
| | | { |
| | | waitListen.notify(); |
| | | } |
| | | |
| | | // If we have gotten here, then we are about to start listening |
| | | // for the first time since startup or since we were previously disabled. |
| | | // Start the embedded HTTP server |
| | |
| | | lastIterationFailed = true; |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | // At this point, the connection handler either started correctly or failed to start |
| | | // but the start process should be notified and resume its work in any cases. |
| | | synchronized (waitListen) |
| | | { |
| | | listenAttempted = true; |
| | | waitListen.notifyAll(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // Initiate shutdown |
| | |
| | | { |
| | | starting = false; |
| | | listenAttempted = true; |
| | | waitListen.notify(); |
| | | waitListen.notifyAll(); |
| | | } |
| | | } |
| | | |
| | |
| | | synchronized (waitListen) |
| | | { |
| | | listenAttempted = true; |
| | | waitListen.notify(); |
| | | waitListen.notifyAll(); |
| | | } |
| | | |
| | | // If none of the listeners were created successfully, then |
| | |
| | | * information: "Portions Copyright [year] [name of copyright owner]". |
| | | * |
| | | * Copyright 2008 Sun Microsystems, Inc. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.replication.common; |
| | | |
| | |
| | | case DEGRADED_STATUS: |
| | | case BAD_GEN_ID_STATUS: |
| | | return true; |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | |
| | | return false; |
| | |
| | | * |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2011-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.replication.plugin; |
| | | |
| | |
| | | case INCREMENT: |
| | | /* FIXME : we should update CSN */ |
| | | break; |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | } |
| | | |
| | |
| | | * |
| | | * Copyright 2008-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2011-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.replication.plugin; |
| | | |
| | |
| | | case INCREMENT: |
| | | /* FIXME : we should update CSN */ |
| | | break; |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | } |
| | | |
| | |
| | | case INCREMENT: |
| | | /* FIXME : we should update CSN */ |
| | | break; |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | return conflict; |
| | | } |
| | |
| | | * |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2011-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.replication.plugin; |
| | | |
| | |
| | | flushThread.initiateShutdown(); |
| | | synchronized (flushThread) |
| | | { |
| | | flushThread.notify(); |
| | | flushThread.notifyAll(); |
| | | } |
| | | } |
| | | |
| | |
| | | * |
| | | * Copyright 2008 Sun Microsystems, Inc. |
| | | * Portions Copyright 2014-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.replication.plugin; |
| | | |
| | |
| | | ReplicationSynchronizationProviderCfg configuration, |
| | | DSRSShutdownSync dsrsShutdownSync) throws ConfigException |
| | | { |
| | | configuration.addReplicationServerAddListener(this); |
| | | configuration.addReplicationServerDeleteListener(this); |
| | | |
| | | this.dsrsShutdownSync = dsrsShutdownSync; |
| | | if (configuration.hasReplicationServer()) |
| | | { |
| | | final ReplicationServerCfg cfg = configuration.getReplicationServer(); |
| | | // Registered only once the replication server exists: the listeners are held by the |
| | | // server wide configuration repository and keyed by DN, so a listener registered by |
| | | // a listener which is then discarded would be leaked until the server is restarted. |
| | | replicationServer = new ReplicationServer(cfg, dsrsShutdownSync); |
| | | } |
| | | |
| | | try |
| | | { |
| | | configuration.addReplicationServerAddListener(this); |
| | | configuration.addReplicationServerDeleteListener(this); |
| | | } |
| | | catch (ConfigException e) |
| | | { |
| | | // This listener is not returned to MultimasterReplication, which is what stops the |
| | | // replication server: nothing would ever shut down the one just created. |
| | | shutdown(); |
| | | throw e; |
| | | } |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | |
| | | } |
| | | catch (ConfigException e) |
| | | { |
| | | // we should never get to this point because the configEntry has |
| | | // already been validated in configAddisAcceptable |
| | | // The configEntry has already been validated in configAddisAcceptable, but the |
| | | // listen port may have been taken since then: report why the creation failed. The |
| | | // message is logged by the configuration handler, which reports the result. |
| | | ccr.setResultCode(ResultCode.CONSTRAINT_VIOLATION); |
| | | ccr.addMessage(e.getMessageObject()); |
| | | } |
| | | return ccr; |
| | | } |
| | |
| | | */ |
| | | if (msgQueue.isEmpty()) |
| | | { |
| | | msgQueue.notify(); |
| | | msgQueue.notifyAll(); |
| | | } |
| | | |
| | | msgQueue.add(update); |
| | |
| | | synchronized (msgQueue) |
| | | { |
| | | msgQueue.clear(); |
| | | msgQueue.notify(); |
| | | msgQueue.notifyAll(); |
| | | } |
| | | |
| | |
| | | import java.util.Set; |
| | | import java.util.concurrent.CopyOnWriteArraySet; |
| | | import java.util.concurrent.atomic.AtomicBoolean; |
| | | import java.util.concurrent.atomic.AtomicInteger; |
| | | |
| | | import org.forgerock.i18n.LocalizableMessage; |
| | | import org.forgerock.i18n.LocalizableMessageBuilder; |
| | | import org.forgerock.i18n.slf4j.LocalizedLogger; |
| | | import org.forgerock.opendj.config.server.ConfigChangeResult; |
| | | import org.forgerock.opendj.config.server.ConfigException; |
| | |
| | | { |
| | | private String serverURL; |
| | | |
| | | private ServerSocket listenSocket; |
| | | /** |
| | | * Number of attempts to bind the listen port before giving up. The port may be held for a |
| | | * short while by a socket which is being closed, so a few retries make the start-up |
| | | * resilient to such transient conditions. |
| | | */ |
| | | private static final int LISTEN_BIND_ATTEMPTS = 5; |
| | | /** Delay between two attempts to bind the listen port. */ |
| | | private static final long LISTEN_BIND_RETRY_DELAY_MS = 200; |
| | | /** Timeout of the diagnostic probe performed when the listen port cannot be bound. */ |
| | | private static final int LISTEN_PORT_PROBE_TIMEOUT_MS = 200; |
| | | |
| | | private volatile ServerSocket listenSocket; |
| | | private Thread listenThread; |
| | | private Thread connectThread; |
| | | |
| | |
| | | /** The backend that allow to search the changes (external changelog). */ |
| | | private ChangelogBackend changelogBackend; |
| | | |
| | | /** |
| | | * Whether this instance registered the virtual attribute rules of the external changelog. |
| | | * They are registered globally, by attribute name, so an instance which did not register |
| | | * them must not deregister them: it would strip them from the instance which did. |
| | | */ |
| | | private boolean externalChangelogRegistered; |
| | | |
| | | private final AtomicBoolean shutdown = new AtomicBoolean(); |
| | | private boolean stopListen; |
| | | /** Written by the thread applying a configuration change, read by the listen thread. */ |
| | | private volatile boolean stopListen; |
| | | private final ReplSessionSecurity replSessionSecurity; |
| | | |
| | | private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); |
| | |
| | | */ |
| | | private static final Set<Integer> localPorts = new CopyOnWriteArraySet<>(); |
| | | |
| | | /** |
| | | * Number of attempts to bind a listen port which failed in this VM. |
| | | * <p> |
| | | * This is required for unit testing: it lets a test which holds a listen port release it |
| | | * as soon as a replication server has actually failed to bind it, instead of after a |
| | | * delay which would make the test vacuous when it is too long, and flaky when it is too |
| | | * short. |
| | | */ |
| | | static final AtomicInteger listenPortBindFailures = new AtomicInteger(); |
| | | |
| | | /** Monitors for synchronizing domain creation with the connect thread. */ |
| | | private final Object domainTicketLock = new Object(); |
| | | private final Object connectThreadLock = new Object(); |
| | |
| | | this.dsrsShutdownSync = dsrsShutdownSync; |
| | | this.domainPredicate = predicate; |
| | | |
| | | enableExternalChangeLog(); |
| | | ServerContext serverContext = DirectoryServer.getInstance().getServerContext(); |
| | | cryptoSuite = serverContext.getCryptoManager(). |
| | | newCryptoSuite(cfg.getCipherTransformation(), cfg.getCipherKeyLength(), cfg.isConfidentialityEnabled()); |
| | | try |
| | | { |
| | | enableExternalChangeLog(); |
| | | ServerContext serverContext = DirectoryServer.getInstance().getServerContext(); |
| | | cryptoSuite = serverContext.getCryptoManager(). |
| | | newCryptoSuite(cfg.getCipherTransformation(), cfg.getCipherKeyLength(), cfg.isConfidentialityEnabled()); |
| | | |
| | | this.changelogDB = new FileChangelogDB(this, config.getReplicationDBDirectory(), cryptoSuite); |
| | | this.changelogDB = new FileChangelogDB(this, config.getReplicationDBDirectory(), cryptoSuite); |
| | | |
| | | replSessionSecurity = new ReplSessionSecurity(); |
| | | initialize(); |
| | | replSessionSecurity = new ReplSessionSecurity(); |
| | | initialize(); |
| | | } |
| | | catch (ConfigException e) |
| | | { |
| | | // This instance is never returned to the caller, so nothing will ever shut it down: |
| | | // release what the initialization managed to acquire before failing. |
| | | abortInitialization(); |
| | | throw e; |
| | | } |
| | | cfg.addChangeListener(this); |
| | | |
| | | localPorts.add(getReplicationPort()); |
| | |
| | | return true; |
| | | } |
| | | |
| | | /** Initialization function for the replicationServer. */ |
| | | private void initialize() |
| | | /** |
| | | * Initialization function for the replicationServer. |
| | | * |
| | | * @throws ConfigException |
| | | * when the replication server cannot be started, in particular when its listen |
| | | * port cannot be bound. |
| | | */ |
| | | private void initialize() throws ConfigException |
| | | { |
| | | shutdown.set(false); |
| | | |
| | |
| | | this.changelogDB.initializeDB(); |
| | | |
| | | setServerURL(); |
| | | listenSocket = new ServerSocket(); |
| | | listenSocket.bind(new InetSocketAddress(getReplicationPort())); |
| | | // Assigned before the threads are created, so that a failure below still releases it. |
| | | listenSocket = bindListenPort(getReplicationPort()); |
| | | |
| | | // creates working threads: we must first connect, then start to listen. |
| | | if (logger.isTraceEnabled()) |
| | |
| | | logger.trace("RS " + getMonitorInstanceName() + " creates listen thread"); |
| | | } |
| | | |
| | | listenThread = new ReplicationServerListenThread(this); |
| | | listenThread.start(); |
| | | startListenThread(listenSocket); |
| | | |
| | | if (logger.isTraceEnabled()) |
| | | { |
| | |
| | | } |
| | | } catch (UnknownHostException e) |
| | | { |
| | | logger.error(ERR_UNKNOWN_HOSTNAME); |
| | | // Not logged here: the caller reports the ConfigException, logging it once. |
| | | logger.traceException(e); |
| | | throw new ConfigException(ERR_UNKNOWN_HOSTNAME.get(), e); |
| | | } catch (IOException e) |
| | | { |
| | | logger.error(ERR_COULD_NOT_BIND_CHANGELOG, getReplicationPort(), e.getMessage()); |
| | | // A replication server whose listen port is not bound is dead: every consumer would |
| | | // otherwise only learn about it as a "connection refused" somewhere else. |
| | | logger.traceException(e); |
| | | throw new ConfigException(bindFailureMessage(getReplicationPort(), e), e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Binds the given port, retrying a few times when it is momentarily unavailable. |
| | | * |
| | | * @param port |
| | | * the port to bind |
| | | * @return the bound listen socket |
| | | * @throws IOException |
| | | * if the port could not be bound within {@link #LISTEN_BIND_ATTEMPTS} attempts |
| | | */ |
| | | private ServerSocket bindListenPort(int port) throws IOException |
| | | { |
| | | for (int attempt = 1; ; attempt++) |
| | | { |
| | | final ServerSocket socket = new ServerSocket(); |
| | | try |
| | | { |
| | | socket.bind(new InetSocketAddress(port)); |
| | | if (attempt > 1) |
| | | { |
| | | logger.info(NOTE_BOUND_CHANGELOG_AFTER_RETRY, port, attempt); |
| | | } |
| | | return socket; |
| | | } |
| | | catch (IOException e) |
| | | { |
| | | close(socket); |
| | | listenPortBindFailures.incrementAndGet(); |
| | | if (attempt >= LISTEN_BIND_ATTEMPTS) |
| | | { |
| | | throw e; |
| | | } |
| | | // The port is probed only when giving up: probing it on every attempt would cost a |
| | | // connection to whoever holds it, and delay the next attempt for nothing. |
| | | logger.warn(WARN_RETRYING_BIND_CHANGELOG, port, getExceptionMessage(e), LISTEN_BIND_RETRY_DELAY_MS); |
| | | try |
| | | { |
| | | Thread.sleep(LISTEN_BIND_RETRY_DELAY_MS); |
| | | } |
| | | catch (InterruptedException e2) |
| | | { |
| | | Thread.currentThread().interrupt(); |
| | | throw e; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Stops the listen thread and releases the listen port. |
| | | * |
| | | * @throws InterruptedException |
| | | * if this thread is interrupted while waiting for the listen thread to stop |
| | | */ |
| | | private void stopListenThread() throws InterruptedException |
| | | { |
| | | stopListen = true; |
| | | close(listenSocket); |
| | | if (listenThread != null) |
| | | { |
| | | listenThread.join(); |
| | | listenThread = null; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Starts a listen thread on the provided listen socket. |
| | | * <p> |
| | | * {@code stopListen} is only cleared here, i.e. once the listen port is bound, so a |
| | | * failure to bind leaves this replication server consistently stopped rather than with a |
| | | * listen thread which would spin on a closed socket. |
| | | * |
| | | * @param boundListenSocket |
| | | * the bound socket the listen thread will accept connections on |
| | | */ |
| | | private void startListenThread(ServerSocket boundListenSocket) |
| | | { |
| | | listenSocket = boundListenSocket; |
| | | stopListen = false; |
| | | listenThread = new ReplicationServerListenThread(this); |
| | | listenThread.start(); |
| | | } |
| | | |
| | | /** |
| | | * Switches the listen port to the one of the provided configuration. |
| | | * <p> |
| | | * The new port is bound while the current one is still open and serving, so a failure |
| | | * leaves this replication server listening on its current port, with its current |
| | | * configuration: there is nothing to roll back, and no window during which this |
| | | * replication server advertises a port that nothing listens to. |
| | | * |
| | | * @param newConfig |
| | | * the configuration being applied, whose listen port differs from the current one |
| | | * @param ccr |
| | | * the result of the configuration change, to which a failure is added |
| | | * @return {@code true} when this replication server listens on the new port, in which |
| | | * case {@code newConfig} has become its configuration |
| | | */ |
| | | private boolean switchListenPort(ReplicationServerCfg newConfig, ConfigChangeResult ccr) |
| | | { |
| | | final ReplicationServerCfg previousConfig = this.config; |
| | | final String previousServerURL = serverURL; |
| | | final int newPort = newConfig.getReplicationPort(); |
| | | ServerSocket newListenSocket = null; |
| | | try |
| | | { |
| | | // The current listen socket is still open and serving while the new port is bound. |
| | | newListenSocket = bindListenPort(newPort); |
| | | |
| | | this.config = newConfig; |
| | | setServerURL(); |
| | | |
| | | stopListenThread(); |
| | | startListenThread(newListenSocket); |
| | | newListenSocket = null; |
| | | |
| | | localPorts.remove(previousConfig.getReplicationPort()); |
| | | localPorts.add(newPort); |
| | | return true; |
| | | } |
| | | catch (UnknownHostException e) |
| | | { |
| | | logger.traceException(e); |
| | | ccr.setResultCode(ResultCode.OPERATIONS_ERROR); |
| | | ccr.addMessage(ERR_UNKNOWN_HOSTNAME.get()); |
| | | } |
| | | catch (IOException e) |
| | | { |
| | | // The new port could not be bound, the current listen socket was left untouched. |
| | | logger.traceException(e); |
| | | ccr.setResultCode(ResultCode.OPERATIONS_ERROR); |
| | | ccr.addMessage(bindFailureMessage(newPort, e)); |
| | | } |
| | | catch (InterruptedException e) |
| | | { |
| | | // The previous listen thread may still be running, so do not hand it a new socket: |
| | | // stopListen is still set, which makes that thread stop as soon as it wakes up. |
| | | Thread.currentThread().interrupt(); |
| | | logger.traceException(e); |
| | | ccr.setResultCode(ResultCode.OPERATIONS_ERROR); |
| | | ccr.addMessage(ERR_COULD_NOT_STOP_LISTEN_THREAD.get(getExceptionMessage(e))); |
| | | } |
| | | // The failure is reported through the ConfigChangeResult, which the configuration |
| | | // handler logs: nothing of the new configuration was applied. |
| | | this.config = previousConfig; |
| | | serverURL = previousServerURL; |
| | | close(newListenSocket); |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * Returns the message of a failed bind of the listen port, i.e. the error itself plus a |
| | | * best effort diagnostic of what holds the port. |
| | | * |
| | | * @param port |
| | | * the port which could not be bound |
| | | * @param cause |
| | | * the error returned by the failed bind |
| | | * @return the message describing the failure |
| | | */ |
| | | private static LocalizableMessage bindFailureMessage(int port, IOException cause) |
| | | { |
| | | return new LocalizableMessageBuilder(ERR_COULD_NOT_BIND_CHANGELOG.get(port, getExceptionMessage(cause))) |
| | | .append(" ").append(describeListenPortHolder(port)).toMessage(); |
| | | } |
| | | |
| | | /** |
| | | * Returns a best effort diagnostic of what holds the given port. |
| | | * <p> |
| | | * The port is probed over the loopback interface only, so the diagnostic reports what was |
| | | * observed there and nothing more: a socket bound to another address holds the port |
| | | * without ever accepting a loopback connection, and cannot be told apart from a socket |
| | | * which does not accept connections at all, e.g. a client socket which was given that |
| | | * port as its local port. |
| | | * |
| | | * @param port |
| | | * the port which could not be bound |
| | | * @return the message describing what was observed on the loopback interface |
| | | */ |
| | | private static LocalizableMessage describeListenPortHolder(int port) |
| | | { |
| | | final String probedAddress = InetAddress.getLoopbackAddress().getHostAddress() + ":" + port; |
| | | try (Socket probe = new Socket()) |
| | | { |
| | | // Without SO_REUSEADDR a probe which self-connects would, once closed, hold the port |
| | | // in TIME_WAIT and defeat the very bind it is diagnosing. |
| | | probe.setReuseAddress(true); |
| | | probe.connect(new InetSocketAddress(InetAddress.getLoopbackAddress(), port), LISTEN_PORT_PROBE_TIMEOUT_MS); |
| | | if (isSelfConnection(probe)) |
| | | { |
| | | // The kernel can only give the probed port to the probe as its local port while |
| | | // that port is free: whoever held it released it in the meantime. |
| | | return ERR_COULD_NOT_BIND_CHANGELOG_PORT_FREE.get(probedAddress); |
| | | } |
| | | return ERR_COULD_NOT_BIND_CHANGELOG_LISTENING.get(probedAddress); |
| | | } |
| | | catch (IOException e) |
| | | { |
| | | logger.traceException(e); |
| | | return ERR_COULD_NOT_BIND_CHANGELOG_NOT_ACCEPTING.get(probedAddress); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Releases what the initialization acquired before it failed. |
| | | * <p> |
| | | * It runs on a partially constructed instance, so every field it uses may still be |
| | | * unassigned. |
| | | */ |
| | | private void abortInitialization() |
| | | { |
| | | shutdown.set(true); |
| | | if (connectThread != null) |
| | | { |
| | | connectThread.interrupt(); |
| | | } |
| | | close(listenSocket); |
| | | if (listenThread != null) |
| | | { |
| | | listenThread.interrupt(); |
| | | } |
| | | shutdownExternalChangelog(); |
| | | if (this.changelogDB != null) |
| | | { |
| | | try |
| | | { |
| | | this.changelogDB.shutdownDB(); |
| | | } |
| | | catch (ChangelogException ignored) |
| | | { |
| | | logger.traceException(ignored); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Indicates whether this replication server has bound its listen port, i.e. whether it |
| | | * can accept connections from directory servers and from other replication servers. |
| | | * |
| | | * @return {@code true} if this replication server is listening |
| | | */ |
| | | public boolean isListening() |
| | | { |
| | | final ServerSocket socket = listenSocket; |
| | | return socket != null && socket.isBound() && !socket.isClosed(); |
| | | } |
| | | |
| | | /** |
| | | * Enable the external changelog if it is not already enabled. |
| | | * <p> |
| | | * The external changelog is provided by the changelog backend. |
| | |
| | | getExceptionMessage(e))); |
| | | } |
| | | |
| | | // Set before the rules are registered, so that a partial registration is released |
| | | // too: this instance is then the one which registered whatever is registered. |
| | | externalChangelogRegistered = true; |
| | | registerVirtualAttributeRules(); |
| | | } |
| | | catch (Exception e) |
| | |
| | | changelogBackend.finalizeBackend(); |
| | | changelogBackend = null; |
| | | } |
| | | deregisterVirtualAttributeRules(); |
| | | if (externalChangelogRegistered) |
| | | { |
| | | // Virtual attribute rules are registered globally, by attribute name: deregistering |
| | | // rules which this instance did not register would strip them from the instance |
| | | // which did, e.g. when this one took the early return of enableExternalChangeLog(). |
| | | externalChangelogRegistered = false; |
| | | deregisterVirtualAttributeRules(); |
| | | } |
| | | } |
| | | |
| | | private List<VirtualAttributeRule> getVirtualAttributesRules() throws DirectoryException |
| | |
| | | { |
| | | ReplicationServerDomain domain = baseDNs.get(baseDN); |
| | | if (domain == null && create) { |
| | | domain = new ReplicationServerDomain(baseDN, this); |
| | | domain = new ReplicationServerDomain(baseDN, this).start(); |
| | | baseDNs.put(baseDN, domain); |
| | | } |
| | | return domain; |
| | |
| | | } |
| | | |
| | | // Wake up connect thread. |
| | | connectThreadLock.notify(); |
| | | connectThreadLock.notifyAll(); |
| | | } |
| | | |
| | | // Wait until the connect thread has processed next connect phase. |
| | |
| | | { |
| | | int port = configuration.getReplicationPort(); |
| | | |
| | | try |
| | | try (ServerSocket tmpSocket = new ServerSocket()) |
| | | { |
| | | ServerSocket tmpSocket = new ServerSocket(); |
| | | tmpSocket.bind(new InetSocketAddress(port)); |
| | | tmpSocket.close(); |
| | | return true; |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | LocalizableMessage message = ERR_COULD_NOT_BIND_CHANGELOG.get(port, e.getMessage()); |
| | | unacceptableReasons.add(message); |
| | | unacceptableReasons.add(ERR_COULD_NOT_BIND_CHANGELOG.get(port, getExceptionMessage(e))); |
| | | return false; |
| | | } |
| | | } |
| | |
| | | { |
| | | final ConfigChangeResult ccr = new ConfigChangeResult(); |
| | | |
| | | final Set<HostPort> oldRSAddresses = getConfiguredRSAddresses(); |
| | | final ReplicationServerCfg oldConfig = this.config; |
| | | |
| | | // Changing the listen port requires to stop the listen thread and restart it. It is |
| | | // done first, and the new port is bound before the current one is released, so that a |
| | | // change which cannot be applied leaves this replication server as it was, instead of |
| | | // half configured and, worse, without any listener. |
| | | if (configuration.getReplicationPort() != oldConfig.getReplicationPort() |
| | | && !switchListenPort(configuration, ccr)) |
| | | { |
| | | return ccr; |
| | | } |
| | | |
| | | // Some of those properties change don't need specific code. |
| | | // They will be applied for next connections. Some others have immediate effect |
| | | final Set<HostPort> oldRSAddresses = getConfiguredRSAddresses(); |
| | | |
| | | final ReplicationServerCfg oldConfig = this.config; |
| | | this.config = configuration; |
| | | |
| | | disconnectRemovedReplicationServers(oldRSAddresses); |
| | |
| | | cryptoSuite.newParameters(config.getCipherTransformation(), config.getCipherKeyLength(), |
| | | config.isConfidentialityEnabled()); |
| | | |
| | | // changing the listen port requires to stop the listen thread |
| | | // and restart it. |
| | | if (getReplicationPort() != oldConfig.getReplicationPort()) |
| | | { |
| | | stopListen = true; |
| | | try |
| | | { |
| | | close(listenSocket); |
| | | if (listenThread != null) |
| | | { |
| | | listenThread.join(); |
| | | } |
| | | stopListen = false; |
| | | |
| | | setServerURL(); |
| | | listenSocket = new ServerSocket(); |
| | | listenSocket.bind(new InetSocketAddress(getReplicationPort())); |
| | | |
| | | listenThread = new ReplicationServerListenThread(this); |
| | | listenThread.start(); |
| | | } |
| | | catch (IOException e) |
| | | { |
| | | logger.traceException(e); |
| | | logger.error(ERR_COULD_NOT_CLOSE_THE_SOCKET, e); |
| | | } |
| | | catch (InterruptedException e) |
| | | { |
| | | logger.traceException(e); |
| | | logger.error(ERR_COULD_NOT_STOP_LISTEN_THREAD, e); |
| | | } |
| | | } |
| | | |
| | | // Update period value for monitoring publishers |
| | | if (oldConfig.getMonitoringPeriod() != config.getMonitoringPeriod()) |
| | | { |
| | |
| | | public boolean isConfigurationChangeAcceptable( |
| | | ReplicationServerCfg configuration, List<LocalizableMessage> unacceptableReasons) |
| | | { |
| | | return true; |
| | | if (configuration.getReplicationPort() == getReplicationPort()) |
| | | { |
| | | return true; |
| | | } |
| | | // The change is persisted before it is applied, so rejecting a port which cannot be |
| | | // bound is the only way to keep the configuration and the listen port in sync. |
| | | return isConfigurationAcceptable(configuration, unacceptableReasons); |
| | | } |
| | | |
| | | /** |
| | |
| | | this.domainDB = |
| | | localReplicationServer.getChangelogDB().getReplicationDomainDB(); |
| | | this.statusAnalyzer = new StatusAnalyzer(this); |
| | | this.statusAnalyzer.start(); |
| | | DirectoryServer.registerMonitorProvider(this); |
| | | } |
| | | |
| | | /** |
| | | * Starts the status analyzer of this domain. |
| | | * <p> |
| | | * The analyzer is not started by the constructor so that {@code this} is not published to its |
| | | * thread before construction has completed. |
| | | * |
| | | * @return this domain |
| | | */ |
| | | ReplicationServerDomain start() |
| | | { |
| | | statusAnalyzer.start(); |
| | | return this; |
| | | } |
| | | |
| | | /** |
| | | * Add an update that has been received to the list of |
| | | * updates that must be forwarded to all other servers. |
| | | * |
| | |
| | | final Random random = new Random(); |
| | | final int randomTime = random.nextInt(6); // Random from 0 to 5 |
| | | // Wait at least 3 seconds + (0 to 5 seconds) |
| | | final long timeout = 3000 + randomTime * 1000; |
| | | final long timeout = 3000 + randomTime * 1000L; |
| | | final boolean lockAcquired = replicationServerDomain.tryLock(timeout); |
| | | if (!lockAcquired) |
| | | { |
| | |
| | | * information: "Portions Copyright [year] [name of copyright owner]". |
| | | * |
| | | * Copyright 2013-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.replication.server.changelog.file; |
| | | |
| | |
| | | { |
| | | synchronized (this) |
| | | { |
| | | notify(); |
| | | notifyAll(); |
| | | } |
| | | } |
| | | } |
| | |
| | | super.initiateShutdown(); |
| | | synchronized (this) |
| | | { |
| | | notify(); |
| | | notifyAll(); |
| | | } |
| | | } |
| | | |
| | |
| | | // wait until clear() has been done by thread, always waking it up |
| | | synchronized (this) |
| | | { |
| | | notify(); |
| | | notifyAll(); |
| | | } |
| | | // ensures thread wait that this thread's state is cleaned up |
| | | Thread.yield(); |
| | |
| | | final ChangelogDBPurger currentPurger = cnPurger.get(); |
| | | synchronized (currentPurger) |
| | | { |
| | | currentPurger.notify(); |
| | | currentPurger.notifyAll(); |
| | | } |
| | | } |
| | | } |
| | |
| | | super.initiateShutdown(); |
| | | synchronized (this) |
| | | { |
| | | notify(); // wake up the purger thread for faster shutdown |
| | | notifyAll(); // wake up the purger thread for faster shutdown |
| | | } |
| | | } |
| | | } |
| | |
| | | * information: "Portions Copyright [year] [name of copyright owner]". |
| | | * |
| | | * Copyright 2014-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.replication.server.changelog.file; |
| | | |
| | |
| | | if (isWriteEnabled) |
| | | { |
| | | ensureLogFileIsValid(parser); |
| | | writer = BlockLogWriter.newWriter(new LogWriter(logfile), parser); |
| | | initializeNewestRecord(); |
| | | final LogWriter logWriter = new LogWriter(logfile); |
| | | try |
| | | { |
| | | writer = BlockLogWriter.newWriter(logWriter, parser); |
| | | initializeNewestRecord(); |
| | | } |
| | | catch (ChangelogException | RuntimeException e) |
| | | { |
| | | // The writer is not reachable from a half-constructed log file, so close it here. |
| | | StaticUtils.close(logWriter); |
| | | throw e; |
| | | } |
| | | } |
| | | else |
| | | { |
| | |
| | | final ConnectedRS rs = connectedRS.get(); |
| | | if (rs.isConnected()) |
| | | { |
| | | connectPhaseLock.notify(); |
| | | connectPhaseLock.notifyAll(); |
| | | |
| | | final long rsGenId = rs.rsInfo.getGenerationId(); |
| | | final int rsServerId = rs.rsInfo.getServerId(); |
| | |
| | | if (!connectionError) |
| | | { |
| | | connectionError = true; |
| | | connectPhaseLock.notify(); |
| | | connectPhaseLock.notifyAll(); |
| | | |
| | | if (!rsInfos.isEmpty()) |
| | | { |
| | |
| | | { |
| | | if (foundBestRS()) |
| | | { |
| | | final Integer bestRSServerId = getBestRS().getServerId(); |
| | | final int bestRSServerId = getBestRS().getServerId(); |
| | | if (rsEvals.get(bestRSServerId) == null) |
| | | { |
| | | final LocalizableMessage eval = NOTE_BEST_RS.get(bestRSServerId, localServerId); |
| | |
| | | synchronized (monitorResponse) |
| | | { |
| | | monitorResponse.set(true); |
| | | monitorResponse.notify(); |
| | | monitorResponse.notifyAll(); |
| | | } |
| | | |
| | | // Update the replication servers ServerStates with new received info |
| | |
| | | { |
| | | synchronized (update) |
| | | { |
| | | update.notify(); |
| | | update.notifyAll(); |
| | | } |
| | | |
| | | // Analyze status of embedded in the ack to see if everything went well |
| | |
| | | * Copyright 2006-2009 Sun Microsystems, Inc. |
| | | * Portions Copyright 2009 D. J. Hagberg, Millibits Consulting, Inc. |
| | | * Portions Copyright 2012-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.schema; |
| | | |
| | |
| | | ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); |
| | | } |
| | | |
| | | Double fractionValue = Double.parseDouble(fractionBuffer.toString()); |
| | | double fractionValue = Double.parseDouble(fractionBuffer.toString()); |
| | | long additionalMilliseconds = Math.round(fractionValue * multiplier); |
| | | |
| | | try |
| | |
| | | * |
| | | * Copyright 2006-2009 Sun Microsystems, Inc. |
| | | * Portions Copyright 2013-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.tasks; |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | if (backend == null) |
| | | { |
| | | // Unreachable as long as the checks above hold: a null backend ID implies at least one |
| | | // include branch, and every include branch either resolves to a backend or is rejected. |
| | | // The guard mirrors the one in runTask() and keeps the dereference below safe. |
| | | LocalizableMessage message = ERR_LDIFIMPORT_NO_BACKENDS_FOR_ID.get(); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message); |
| | | } |
| | | |
| | | // Make sure the selected backend will handle all the include branches |
| | | defaultIncludeBranches = new ArrayList<>(backend.getBaseDNs()); |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | if (backend == null) |
| | | { |
| | | // Unlike initializeTask(), this method does not reject an include branch which resolves to no |
| | | // backend, so none of them having resolved leaves nothing to import into. The message of the |
| | | // backend ID case is reused here rather than adding a new one for a malformed task. |
| | | logger.error(ERR_LDIFIMPORT_NO_BACKENDS_FOR_ID); |
| | | return TaskState.STOPPED_BY_ERROR; |
| | | } |
| | | |
| | | // Find backends with subordinate base DNs that should be excluded from the import. |
| | | defaultIncludeBranches = new HashSet<>(backend.getBaseDNs()); |
| | | for (Backend<?> subBackend : getServerContext().getBackendConfigManager().getSubordinateBackends(backend)) |
| | |
| | | * |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2013-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.tasks; |
| | | |
| | |
| | | private String domainString; |
| | | private int source; |
| | | private LDAPReplicationDomain domain; |
| | | private TaskState initState; |
| | | /** |
| | | * The monitor used to signal the completion of the import to {@link #runTask()}. |
| | | * <p> |
| | | * A dedicated lock is required because {@link #initState} is reassigned: synchronizing on the |
| | | * state itself would lock the monitor of an enum constant which is both shared JVM wide and |
| | | * different for the waiting and the notifying thread. |
| | | */ |
| | | private final Object initStateLock = new Object(); |
| | | private volatile TaskState initState; |
| | | |
| | | /** The total number of entries expected to be processed when this import will end successfully. */ |
| | | private long total; |
| | |
| | | // launch the import |
| | | domain.initializeFromRemote(source, this); |
| | | |
| | | synchronized(initState) |
| | | synchronized (initStateLock) |
| | | { |
| | | // Waiting for the end of the job |
| | | while (initState == TaskState.RUNNING) |
| | | { |
| | | initState.wait(1000); |
| | | initStateLock.wait(1000); |
| | | replaceAttributeValue(ATTR_TASK_INITIALIZE_LEFT, String.valueOf(left)); |
| | | replaceAttributeValue(ATTR_TASK_INITIALIZE_DONE, String.valueOf(total-left)); |
| | | } |
| | |
| | | finally |
| | | { |
| | | // Wake up runTask method waiting for completion |
| | | synchronized (initState) |
| | | synchronized (initStateLock) |
| | | { |
| | | initState.notify(); |
| | | initStateLock.notifyAll(); |
| | | } |
| | | } |
| | | } |
| | |
| | | * |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2013-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.tasks; |
| | | |
| | |
| | | @Override |
| | | protected TaskState runTask() |
| | | { |
| | | Boolean purgeCompletedInTime = false; |
| | | boolean purgeCompletedInTime = false; |
| | | logger.trace("PurgeConflictsHistoricalTask is starting on domain: %s max duration (sec): %d", |
| | | domain.getBaseDN(), purgeTaskMaxDurationInSec); |
| | | try |
| | | { |
| | | replaceAttributeValue(ATTR_TASK_CONFLICTS_HIST_PURGE_COMPLETED_IN_TIME, purgeCompletedInTime.toString()); |
| | | replaceAttributeValue(ATTR_TASK_CONFLICTS_HIST_PURGE_COMPLETED_IN_TIME, |
| | | String.valueOf(purgeCompletedInTime)); |
| | | |
| | | // launch the task |
| | | domain.purgeConflictsHistorical(this, TimeThread.getTime() + purgeTaskMaxDurationInSec*1000); |
| | | domain.purgeConflictsHistorical(this, TimeThread.getTime() + purgeTaskMaxDurationInSec * 1000L); |
| | | |
| | | purgeCompletedInTime = true; |
| | | replaceAttributeValue(ATTR_TASK_CONFLICTS_HIST_PURGE_COMPLETED_IN_TIME, purgeCompletedInTime.toString()); |
| | | replaceAttributeValue(ATTR_TASK_CONFLICTS_HIST_PURGE_COMPLETED_IN_TIME, |
| | | String.valueOf(purgeCompletedInTime)); |
| | | |
| | | initState = TaskState.COMPLETED_SUCCESSFULLY; |
| | | } |
| | |
| | | * |
| | | * Copyright 2008-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2011-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.tools; |
| | | |
| | |
| | | { |
| | | String serviceName = null; |
| | | Process p = Runtime.getRuntime().exec(cmd); |
| | | BufferedReader stdout = new BufferedReader(new InputStreamReader(p.getInputStream())); |
| | | boolean processDone = false; |
| | | String s; |
| | | while (!processDone) |
| | | try (BufferedReader stdout = new BufferedReader(new InputStreamReader(p.getInputStream()))) |
| | | { |
| | | try |
| | | boolean processDone = false; |
| | | String s; |
| | | while (!processDone) |
| | | { |
| | | p.exitValue(); |
| | | processDone = true; |
| | | } |
| | | catch (Throwable t) |
| | | { |
| | | } |
| | | while ((s = stdout.readLine()) != null) |
| | | { |
| | | serviceName = s; |
| | | if (serviceName.trim().length() == 0) |
| | | try |
| | | { |
| | | serviceName = null; |
| | | p.exitValue(); |
| | | processDone = true; |
| | | } |
| | | catch (Throwable t) |
| | | { |
| | | } |
| | | while ((s = stdout.readLine()) != null) |
| | | { |
| | | serviceName = s; |
| | | if (serviceName.trim().length() == 0) |
| | | { |
| | | serviceName = null; |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | { |
| | | int resultCode = -1; |
| | | Process process = new ProcessBuilder(cmd).start(); |
| | | BufferedReader stdout = new BufferedReader(new InputStreamReader(process.getInputStream())); |
| | | |
| | | boolean processDone = false; |
| | | String s; |
| | | while (!processDone) |
| | | try (BufferedReader stdout = new BufferedReader(new InputStreamReader(process.getInputStream()))) |
| | | { |
| | | try |
| | | boolean processDone = false; |
| | | String s; |
| | | while (!processDone) |
| | | { |
| | | resultCode = process.exitValue(); |
| | | processDone = true; |
| | | } |
| | | catch (Throwable t) |
| | | { |
| | | } |
| | | while ((s = stdout.readLine()) != null) |
| | | { |
| | | if (s.trim().length() != 0) |
| | | try |
| | | { |
| | | serviceName = s; |
| | | resultCode = process.exitValue(); |
| | | processDone = true; |
| | | } |
| | | catch (Throwable t) |
| | | { |
| | | } |
| | | while ((s = stdout.readLine()) != null) |
| | | { |
| | | if (s.trim().length() != 0) |
| | | { |
| | | serviceName = s; |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | case CHANGE_AFTER_RESET: |
| | | out.println(INFO_BIND_MUST_CHANGE_PASSWORD.get()); |
| | | break; |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | } |
| | | |
| | |
| | | ERR_REPLICATION_INITIALIZING_TRIES_COMPLETED.get( |
| | | pnfe.getMessageObject()), INITIALIZING_TRIES_COMPLETED, pnfe); |
| | | } |
| | | sleepCatchInterrupt((5 - nTries) * 3000); |
| | | sleepCatchInterrupt((5 - nTries) * 3000L); |
| | | } |
| | | catch (ApplicationException ae) |
| | | { |
| | |
| | | ERR_REPLICATION_INITIALIZING_TRIES_COMPLETED.get( |
| | | pnfe.getMessageObject()), INITIALIZING_TRIES_COMPLETED, pnfe); |
| | | } |
| | | sleepCatchInterrupt((5 - nTries) * 3000); |
| | | sleepCatchInterrupt((5 - nTries) * 3000L); |
| | | } |
| | | catch (ClientException ae) |
| | | { |
| | |
| | | * |
| | | * Copyright 2006-2009 Sun Microsystems, Inc. |
| | | * Portions Copyright 2015-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.tools.makeldif; |
| | | |
| | |
| | | /** The queue used to hold generated entries until they can be read. */ |
| | | private LinkedBlockingQueue<TemplateEntry> entryQueue; |
| | | |
| | | /** The background thread used to actually generate the entries. */ |
| | | private final MakeLDIFInputStreamThread generatorThread; |
| | | |
| | | /** |
| | | * Creates a new MakeLDIF input stream that will generate entries based on the |
| | | * provided template file. |
| | | * |
| | | * @param templateFile The template file to use to generate the entries. |
| | | */ |
| | | public MakeLDIFInputStream(TemplateFile templateFile) |
| | | private MakeLDIFInputStream(TemplateFile templateFile) |
| | | { |
| | | allGenerated = false; |
| | | closed = false; |
| | |
| | | } |
| | | |
| | | /* The background thread being used to actually generate the entries. */ |
| | | new MakeLDIFInputStreamThread(this, templateFile).start(); |
| | | generatorThread = new MakeLDIFInputStreamThread(this, templateFile); |
| | | } |
| | | |
| | | /** |
| | | * Creates a new MakeLDIF input stream based on the provided template file and starts generating |
| | | * entries in the background. |
| | | * <p> |
| | | * The generator thread is started here rather than by the constructor so that {@code this} is not |
| | | * published to it before construction has completed. |
| | | * |
| | | * @param templateFile The template file to use to generate the entries. |
| | | * |
| | | * @return A new input stream which has started generating entries. |
| | | */ |
| | | public static MakeLDIFInputStream newStartedInputStream(TemplateFile templateFile) |
| | | { |
| | | MakeLDIFInputStream inputStream = new MakeLDIFInputStream(templateFile); |
| | | inputStream.generatorThread.start(); |
| | | return inputStream; |
| | | } |
| | | |
| | | |
| | |
| | | import org.opends.server.types.InitializationException; |
| | | import org.opends.server.types.NullOutputStream; |
| | | import org.opends.server.util.BuildVersion; |
| | | import org.opends.server.util.StaticUtils; |
| | | import org.opends.server.util.cli.LDAPConnectionConsoleInteraction; |
| | | |
| | | import com.forgerock.opendj.cli.ArgumentException; |
| | |
| | | writeStatus(controlInfo.getServerDescriptor()); |
| | | int period = argParser.getRefreshPeriod(); |
| | | boolean first = true; |
| | | while (period > 0) |
| | | // A positive refresh period means refreshing until the command is interrupted. |
| | | while (period > 0 && !Thread.currentThread().isInterrupted()) |
| | | { |
| | | long timeToSleep = period * 1000; |
| | | long timeToSleep = period * 1000L; |
| | | if (!first) |
| | | { |
| | | long t1 = System.currentTimeMillis(); |
| | |
| | | |
| | | if (timeToSleep > 0) |
| | | { |
| | | StaticUtils.sleep(timeToSleep); |
| | | try |
| | | { |
| | | // Not StaticUtils.sleep(): it discards the interruption, which would leave this loop |
| | | // running with no way for the caller to stop it. |
| | | Thread.sleep(timeToSleep); |
| | | } |
| | | catch (InterruptedException e) |
| | | { |
| | | Thread.currentThread().interrupt(); |
| | | break; |
| | | } |
| | | } |
| | | println(); |
| | | println(LocalizableMessage.raw(" ---------------------")); |
| | |
| | | // Interact with the user though the console to get |
| | | // LDAP connection information |
| | | final String hostName = getHostNameForLdapUrl(ci.getHostName()); |
| | | final Integer portNumber = ci.getPortNumber(); |
| | | final int portNumber = ci.getPortNumber(); |
| | | final DN bindDN = ci.getBindDN(); |
| | | final String bindPassword = ci.getBindPassword(); |
| | | TrustManager trustManager = ci.getTrustManager(); |
| | |
| | | * information: "Portions Copyright [year] [name of copyright owner]". |
| | | * |
| | | * Portions Copyright 2013-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.tools.upgrade; |
| | | |
| | |
| | | import org.forgerock.opendj.ldif.LDIFEntryReader; |
| | | import org.forgerock.opendj.ldif.LDIFEntryWriter; |
| | | import org.forgerock.util.Reject; |
| | | import org.forgerock.util.Utils; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.opends.server.util.ChangeOperationType; |
| | | import org.opends.server.util.SchemaUtils; |
| | |
| | | { |
| | | final Schema schema = getUpgradeSchema(); |
| | | final File configFile = new File(configDirectory, CURRENT_CONFIG_FILE_NAME); |
| | | final LDIFEntryReader entryReader = new LDIFEntryReader(new FileInputStream(configFile)).setSchema(schema); |
| | | return LDIF.search(entryReader, searchRequest, schema); |
| | | final FileInputStream configStream = new FileInputStream(configFile); |
| | | try |
| | | { |
| | | // Ownership of the stream passes to the returned reader, which the caller must close. |
| | | final LDIFEntryReader entryReader = new LDIFEntryReader(configStream).setSchema(schema); |
| | | return LDIF.search(entryReader, searchRequest, schema); |
| | | } |
| | | catch (RuntimeException e) |
| | | { |
| | | Utils.closeSilently(configStream); |
| | | throw e; |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | |
| | | int changeCount = 0; |
| | | final Schema schema = getUpgradeSchema(); |
| | | try (LDIFEntryReader entryReader = new LDIFEntryReader(new FileInputStream(configFile)).setSchema(schema); |
| | | LDIFEntryWriter writer = new LDIFEntryWriter(new FileOutputStream(copyConfig))) |
| | | try (FileInputStream configStream = new FileInputStream(configFile); |
| | | LDIFEntryReader entryReader = new LDIFEntryReader(configStream).setSchema(schema); |
| | | FileOutputStream copyStream = new FileOutputStream(copyConfig); |
| | | LDIFEntryWriter writer = new LDIFEntryWriter(copyStream)) |
| | | { |
| | | writer.setWrapColumn(80); |
| | | |
| | |
| | | ldifDNs.add(DN.valueOf(removeDnPrefix(dnLine))); |
| | | } |
| | | break; |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | } |
| | | |
| | |
| | | * |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2011-2016 ForgeRock AS. |
| | | * Portions Copyright 2023-2024 3A Systems, LLC. |
| | | * Portions Copyright 2023-2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.types; |
| | | |
| | |
| | | { |
| | | // The first byte must be the entry version. If it's not one |
| | | // we recognize, then that's an error. |
| | | Byte version = entryBuffer.readByte(); |
| | | byte version = entryBuffer.readByte(); |
| | | if (version != 0x03 && version != 0x02 && version != 0x01) |
| | | { |
| | | LocalizableMessage message = ERR_ENTRY_DECODE_UNRECOGNIZED_VERSION.get( |
| | |
| | | case SUBORDINATES: |
| | | buffer.append("subordinate"); |
| | | break; |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | |
| | | buffer.append("?"); |
| | |
| | | * |
| | | * Copyright 2006-2009 Sun Microsystems, Inc. |
| | | * Portions Copyright 2012-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.types; |
| | | |
| | |
| | | */ |
| | | public LDIFImportConfig(TemplateFile templateFile) |
| | | { |
| | | this(new MakeLDIFInputStream(templateFile)); |
| | | this(MakeLDIFInputStream.newStartedInputStream(templateFile)); |
| | | } |
| | | |
| | | |
| | |
| | | |
| | | if (isCompressed) |
| | | { |
| | | inputStream = new GZIPInputStream(inputStream); |
| | | inputStream = wrapWithGzip(inputStream); |
| | | } |
| | | |
| | | reader = new BufferedReader(new InputStreamReader(inputStream), |
| | |
| | | return reader; |
| | | } |
| | | |
| | | /** |
| | | * Wraps the provided stream for decompression, closing it if the wrapping fails so that the |
| | | * underlying file descriptor is not leaked. |
| | | */ |
| | | private static InputStream wrapWithGzip(final InputStream inputStream) throws IOException |
| | | { |
| | | try |
| | | { |
| | | return new GZIPInputStream(inputStream); |
| | | } |
| | | catch (IOException | RuntimeException e) |
| | | { |
| | | StaticUtils.close(inputStream); |
| | | throw e; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | |
| | | |
| | | if (isCompressed) |
| | | { |
| | | inputStream = new GZIPInputStream(inputStream); |
| | | inputStream = wrapWithGzip(inputStream); |
| | | } |
| | | |
| | | reader = new BufferedReader(new InputStreamReader(inputStream), bufferSize); |
| | |
| | | * |
| | | * Copyright 2006-2009 Sun Microsystems, Inc. |
| | | * Portions Copyright 2014-2015 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.types; |
| | | |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void mark(int i) { |
| | | public synchronized void mark(int i) { |
| | | parentStream.mark(i); |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void reset() throws IOException { |
| | | public synchronized void reset() throws IOException { |
| | | parentStream.reset(); |
| | | } |
| | | |
| | |
| | | * information: "Portions Copyright [year] [name of copyright owner]". |
| | | * |
| | | * Copyright 2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.util; |
| | | |
| | |
| | | @Override |
| | | public boolean cancel(boolean mayInterruptIfRunning) |
| | | { |
| | | return schedulerFuture.cancel(mayInterruptIfRunning) |
| | | | (executorFuture != null && executorFuture.cancel(mayInterruptIfRunning)); |
| | | // Both futures must be cancelled, so neither call may be short circuited. |
| | | final boolean schedulerCancelled = schedulerFuture.cancel(mayInterruptIfRunning); |
| | | final boolean executorCancelled = |
| | | executorFuture != null && executorFuture.cancel(mayInterruptIfRunning); |
| | | return schedulerCancelled || executorCancelled; |
| | | } |
| | | |
| | | @Override |
| | |
| | | @Override |
| | | public boolean awaitTermination(final long timeout, final TimeUnit unit) throws InterruptedException |
| | | { |
| | | return cronScheduler.awaitTermination(timeout, unit) & cronExecutorService.awaitTermination(timeout, unit); |
| | | // Both services must be awaited, so neither call may be short circuited. |
| | | final boolean schedulerTerminated = cronScheduler.awaitTermination(timeout, unit); |
| | | final boolean executorTerminated = cronExecutorService.awaitTermination(timeout, unit); |
| | | return schedulerTerminated && executorTerminated; |
| | | } |
| | | |
| | | @Override |
| | |
| | | int firstByte = 0xFF & a[i]; |
| | | int secondByte = 0xFF & a2[i]; |
| | | if (firstByte != secondByte) { |
| | | if (firstByte < secondByte) { |
| | | return -1; |
| | | } else if (firstByte > secondByte) { |
| | | return 1; |
| | | } |
| | | return firstByte < secondByte ? -1 : 1; |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | return successful & file.delete(); |
| | | // The delete must be attempted even when a child could not be removed, so it is |
| | | // evaluated into a local before being combined with the running result. |
| | | final boolean deleted = file.delete(); |
| | | return successful && deleted; |
| | | } |
| | | return false; |
| | | } |
| | |
| | | * Copyright 2008-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2011-2016 ForgeRock AS. |
| | | * Portions Copyright 2024-2025 3A Systems,LLC. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.workflowelement.localbackend; |
| | | |
| | |
| | | ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); |
| | | case WARN: |
| | | logger.error(message); |
| | | break; |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | } |
| | | } |
| | |
| | | * |
| | | * Copyright 2008-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2011-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | * Portions copyright 2024-2025 3A Systems,LLC. |
| | | */ |
| | | package org.opends.server.workflowelement.localbackend; |
| | |
| | | case INCREMENT: |
| | | newEntry.incrementAttribute(a); |
| | | break; |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | } |
| | | |
| | |
| | | * Copyright 2008-2011 Sun Microsystems, Inc. |
| | | * Portions Copyright 2011-2016 ForgeRock AS. |
| | | * Portions Copyright 2024-2025 3A Systems,LLC. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.workflowelement.localbackend; |
| | | |
| | |
| | | case INCREMENT: |
| | | processIncrementModification(attr); |
| | | break; |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | } |
| | | |
| | |
| | | logger.error(msg); |
| | | invalidReason = new LocalizableMessageBuilder(); |
| | | break; |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | } |
| | | } |
| | |
| | | * |
| | | * Copyright 2008-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2011-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.workflowelement.localbackend; |
| | | |
| | |
| | | { |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, errorMsg.get(entryDN)); |
| | | } |
| | | break; |
| | | default: |
| | | // No action needed for the remaining values. |
| | | break; |
| | | } |
| | | } |
| | | |
| | |
| | | use request controls |
| | | ERR_CONNHANDLER_CANNOT_BIND_432=The %s connection handler \ |
| | | defined in configuration entry %s was unable to bind to %s:%d: %s |
| | | ERR_CONNHANDLER_TIMEOUT_WAITING_FOR_LISTENER_1540=The %s did not attempt to \ |
| | | open its listen port within %d seconds. The Directory Server will stop \ |
| | | waiting for it and continue, but that connection handler may never accept \ |
| | | connections |
| | | ERR_JMX_SEARCH_INSUFFICIENT_PRIVILEGES_438=You do not have sufficient \ |
| | | privileges to perform search operations through JMX |
| | | ERR_JMX_INSUFFICIENT_PRIVILEGES_439=You do not have sufficient \ |
| | |
| | | # |
| | | # Copyright 2006-2010 Sun Microsystems, Inc. |
| | | # Portions Copyright 2011-2016 ForgeRock AS. |
| | | # Portions Copyright 2026 3A Systems, LLC. |
| | | |
| | | # This file contains the primary Directory Server configuration. It must not |
| | | # be directly edited while the server is online. The server configuration |
| | |
| | | in domain "%s" from this directory server DS(%d): the remote directory server DS(%d) is unknown |
| | | ERR_REPLICATION_UNEXPECTED_MESSAGE_300=New replication connection from %s started with unexpected message %s and is \ |
| | | being closed |
| | | WARN_RETRYING_BIND_CHANGELOG_301=Replication Server could not bind to the listen port : %d. \ |
| | | Error : %s. Retrying in %d ms |
| | | NOTE_BOUND_CHANGELOG_AFTER_RETRY_302=Replication Server bound to the listen port : %d \ |
| | | at attempt %d |
| | | ERR_COULD_NOT_BIND_CHANGELOG_LISTENING_303=Another socket is listening on %s |
| | | ERR_COULD_NOT_BIND_CHANGELOG_NOT_ACCEPTING_304=Nothing accepted a connection on %s : the port is held \ |
| | | either by a socket bound to another address, or by a socket which does not accept connections |
| | | ERR_COULD_NOT_BIND_CHANGELOG_PORT_FREE_305=Nothing holds %s anymore : the port was released after the \ |
| | | last attempt to bind it |
| | |
| | | this.mib, this.server, this.applIndex); |
| | | |
| | | // if the entry already exists nothing to do |
| | | if ((this.dsTableEntries.containsKey(entry.getObjectName())) || |
| | | (entry == null)) { |
| | | if (this.dsTableEntries.containsKey(entry.getObjectName())) { |
| | | return true; |
| | | } |
| | | |
| | |
| | | this.applIndex, this.applIfOpsIndex); |
| | | |
| | | // If the entry already exists then nothing to do |
| | | if ((this.dsApplIfOpsTableEntries.containsKey(entry.getObjectName())) || |
| | | (entry == null)) { |
| | | if (this.dsApplIfOpsTableEntries.containsKey(entry.getObjectName())) { |
| | | return true; |
| | | } |
| | | // Add the entry in the Table |
| | |
| | | import java.lang.management.ThreadInfo; |
| | | import java.lang.management.ThreadMXBean; |
| | | import java.net.BindException; |
| | | import java.net.ConnectException; |
| | | import java.net.InetSocketAddress; |
| | | import java.net.ServerSocket; |
| | | import java.net.Socket; |
| | |
| | | } |
| | | |
| | | /** |
| | | * Asserts that the given local port accepts connections right now, without any retry loop. |
| | | * <p> |
| | | * Intended for connection handler tests: a handler start method must not return before its listen |
| | | * port is open. When the port is closed this method tells the two possible causes apart, because a |
| | | * plain connection failure cannot distinguish them: the handler may never have managed to bind at |
| | | * all, or its start method may have returned too early. |
| | | * |
| | | * @param port |
| | | * the port the connection handler under test is supposed to be listening on |
| | | * @throws IOException |
| | | * if the connection fails for a reason other than the port being closed |
| | | */ |
| | | public static void assertPortIsAcceptingConnections(int port) throws IOException |
| | | { |
| | | try |
| | | { |
| | | connectTo(port); |
| | | } |
| | | catch (ConnectException e) |
| | | { |
| | | // Give the handler thread the extra time it should not have needed. If the port opens now, the |
| | | // handler can bind and the start method simply returned too early, which is the regression this |
| | | // check is about. If it never opens, the test failed for an unrelated reason. |
| | | assertTrue(waitForPortToOpen(port), "the connection handler never opened port " + port); |
| | | fail("the connection handler start method returned before port " + port + " was open"); |
| | | } |
| | | } |
| | | |
| | | private static void connectTo(int port) throws IOException |
| | | { |
| | | try (Socket socket = new Socket()) |
| | | { |
| | | socket.connect(new InetSocketAddress("127.0.0.1", port), 1000); |
| | | } |
| | | } |
| | | |
| | | private static boolean waitForPortToOpen(int port) |
| | | { |
| | | final long deadline = System.currentTimeMillis() + 10000; |
| | | do |
| | | { |
| | | try |
| | | { |
| | | connectTo(port); |
| | | return true; |
| | | } |
| | | catch (IOException ignored) |
| | | { |
| | | sleep(100); |
| | | } |
| | | } |
| | | while (System.currentTimeMillis() < deadline); |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * Finds a free server socket port on the local host. |
| | | * |
| | | * @return The free port. |
| | |
| | | * |
| | | * Copyright 2006-2008 Sun Microsystems, Inc. |
| | | * Portions Copyright 2014-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.backends.jeb; |
| | | |
| | |
| | | ArrayList<LocalizableMessage> warnings = new ArrayList<>(); |
| | | templateFile.parse(template, warnings); |
| | | MakeLDIFInputStream ldifEntryStream = |
| | | new MakeLDIFInputStream(templateFile); |
| | | MakeLDIFInputStream.newStartedInputStream(templateFile); |
| | | LDIFReader reader = |
| | | new LDIFReader(new LDIFImportConfig(ldifEntryStream)); |
| | | for(int i =0; i<numEntries;i++) { |
| New file |
| | |
| | | /* |
| | | * The contents of this file are subject to the terms of the Common Development and |
| | | * Distribution License (the License). You may not use this file except in compliance with the |
| | | * License. |
| | | * |
| | | * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the |
| | | * specific language governing permission and limitations under the License. |
| | | * |
| | | * When distributing Covered Software, include this CDDL Header Notice in each file and include |
| | | * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL |
| | | * Header, with the fields enclosed by brackets [] replaced by your own identifying |
| | | * information: "Portions copyright [year] [name of copyright owner]". |
| | | * |
| | | * Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.protocols.http; |
| | | |
| | | import static org.testng.Assert.*; |
| | | |
| | | import org.forgerock.i18n.LocalizableMessage; |
| | | import org.forgerock.opendj.server.config.meta.HTTPConnectionHandlerCfgDefn; |
| | | import org.forgerock.opendj.server.config.server.HTTPConnectionHandlerCfg; |
| | | import org.opends.server.DirectoryServerTestCase; |
| | | import org.opends.server.TestCaseUtils; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.opends.server.extensions.InitializationUtils; |
| | | import org.opends.server.types.Entry; |
| | | import org.testng.annotations.BeforeClass; |
| | | import org.testng.annotations.Test; |
| | | |
| | | @SuppressWarnings("javadoc") |
| | | @Test(groups = { "precommit", "http" }, sequential = true) |
| | | public class HTTPConnectionHandlerTestCase extends DirectoryServerTestCase |
| | | { |
| | | private static final LocalizableMessage STOP_REASON = LocalizableMessage.raw("Don't need a reason."); |
| | | |
| | | @BeforeClass |
| | | public void setUp() throws Exception |
| | | { |
| | | // This test suite depends on having the schema available, so we'll start the server. |
| | | TestCaseUtils.startServer(); |
| | | } |
| | | |
| | | /** |
| | | * The start method must not return before the handler thread has attempted to start the embedded |
| | | * HTTP server, otherwise a client connecting right after the handler has been enabled through |
| | | * dsconfig can be refused. |
| | | * |
| | | * @throws Exception |
| | | * if the handler cannot be instantiated or started. |
| | | */ |
| | | @Test |
| | | public void testStartWaitsForListenPort() throws Exception |
| | | { |
| | | final int listenPort = TestCaseUtils.findFreePort(); |
| | | Entry handlerEntry = TestCaseUtils.makeEntry( |
| | | "dn: cn=HTTP Connection Handler,cn=Connection Handlers,cn=config", |
| | | "objectClass: top", |
| | | "objectClass: ds-cfg-connection-handler", |
| | | "objectClass: ds-cfg-http-connection-handler", |
| | | "cn: HTTP Connection Handler", |
| | | "ds-cfg-java-class: org.opends.server.protocols.http.HTTPConnectionHandler", |
| | | "ds-cfg-enabled: true", |
| | | "ds-cfg-listen-address: 127.0.0.1", |
| | | "ds-cfg-listen-port: " + listenPort, |
| | | "ds-cfg-accept-backlog: 128", |
| | | "ds-cfg-keep-stats: false", |
| | | "ds-cfg-use-tcp-keep-alive: true", |
| | | "ds-cfg-use-tcp-no-delay: true", |
| | | "ds-cfg-allow-tcp-reuse-address: true", |
| | | "ds-cfg-max-request-size: 5 megabytes", |
| | | "ds-cfg-buffer-size: 4096 bytes", |
| | | "ds-cfg-max-blocked-write-time-limit: 2 minutes", |
| | | "ds-cfg-use-ssl: false", |
| | | "ds-cfg-ssl-client-auth-policy: optional", |
| | | "ds-cfg-ssl-cert-nickname: server-cert"); |
| | | HTTPConnectionHandlerCfg config = |
| | | InitializationUtils.getConfiguration(HTTPConnectionHandlerCfgDefn.getInstance(), handlerEntry); |
| | | |
| | | HTTPConnectionHandler handler = new HTTPConnectionHandler(); |
| | | handler.initializeConnectionHandler(DirectoryServer.getInstance().getServerContext(), config); |
| | | try |
| | | { |
| | | handler.start(); |
| | | |
| | | // No retry loop here on purpose: once start() has returned, the port must already be open. |
| | | TestCaseUtils.assertPortIsAcceptingConnections(listenPort); |
| | | } |
| | | finally |
| | | { |
| | | handler.processServerShutdown(STOP_REASON); |
| | | handler.finalizeConnectionHandler(STOP_REASON); |
| | | handler.join(10000); |
| | | assertFalse(handler.isAlive(), "the connection handler thread is still running"); |
| | | } |
| | | } |
| | | } |
| | |
| | | * |
| | | * Copyright 2006-2009 Sun Microsystems, Inc. |
| | | * Portions Copyright 2012-2016 ForgeRock AS. |
| | | * Portions Copyright 2025 3A Systems, LLC. |
| | | * Portions Copyright 2025-2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.protocols.ldap; |
| | | |
| | |
| | | } |
| | | |
| | | /** |
| | | * The start method must not return before the handler thread has attempted to |
| | | * open the listen port, otherwise a client connecting right after the server |
| | | * startup can be refused. |
| | | * |
| | | * @throws Exception if the handler cannot be instantiated or started. |
| | | */ |
| | | @Test |
| | | public void testStartWaitsForListenPort() throws Exception { |
| | | Entry handlerEntry = TestCaseUtils.makeEntry( |
| | | "dn: cn=LDAP Connection Handler,cn=Connection Handlers,cn=config", |
| | | "objectClass: top", |
| | | "objectClass: ds-cfg-connection-handler", |
| | | "objectClass: ds-cfg-ldap-connection-handler", |
| | | "cn: LDAP Connection Handler", |
| | | "ds-cfg-java-class: org.forgerock.opendj.reactive.LDAPConnectionHandler2", |
| | | "ds-cfg-enabled: true", |
| | | "ds-cfg-listen-address: 127.0.0.1", |
| | | "ds-cfg-accept-backlog: 128", |
| | | "ds-cfg-allow-ldap-v2: false", |
| | | "ds-cfg-keep-stats: false", |
| | | "ds-cfg-use-tcp-keep-alive: true", |
| | | "ds-cfg-use-tcp-no-delay: true", |
| | | "ds-cfg-allow-tcp-reuse-address: true", |
| | | "ds-cfg-send-rejection-notice: true", |
| | | "ds-cfg-max-request-size: 5 megabytes", |
| | | "ds-cfg-num-request-handlers: 2", |
| | | "ds-cfg-allow-start-tls: false", |
| | | "ds-cfg-use-ssl: false", |
| | | "ds-cfg-ssl-client-auth-policy: optional", |
| | | "ds-cfg-ssl-cert-nickname: server-cert", |
| | | "ds-cfg-key-manager-provider: cn=JKS,cn=Key Manager Providers,cn=config", |
| | | "ds-cfg-trust-manager-provider: cn=JKS,cn=Trust Manager Providers,cn=config"); |
| | | LDAPConnectionHandler2 handler = getLDAPHandlerInstance(handlerEntry); |
| | | int listenPort = handler.getListeners().iterator().next().getPort(); |
| | | try |
| | | { |
| | | handler.start(); |
| | | |
| | | // No retry loop here on purpose: once start() has returned, the port must already be open. |
| | | TestCaseUtils.assertPortIsAcceptingConnections(listenPort); |
| | | } |
| | | finally |
| | | { |
| | | handler.processServerShutdown(reasonMsg); |
| | | handler.finalizeConnectionHandler(reasonMsg); |
| | | handler.join(10000); |
| | | assertFalse(handler.isAlive(), "the connection handler thread is still running"); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Start a handler an then give its hasAcceptableConfiguration a Entry with |
| | | * numerous invalid cases and single-valued attrs with duplicate values. |
| | | * |
| | |
| | | * |
| | | * Copyright 2006-2009 Sun Microsystems, Inc. |
| | | * Portions Copyright 2013-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.replication.server; |
| | | |
| | | import static org.opends.server.TestCaseUtils.*; |
| | | import static org.opends.server.util.StaticUtils.*; |
| | | import static org.testng.Assert.*; |
| | | |
| | | import java.net.ServerSocket; |
| | | import java.util.ArrayList; |
| | | import java.util.Arrays; |
| | | import java.util.Collection; |
| | | import java.util.Collections; |
| | | import java.util.List; |
| | | |
| | | import org.forgerock.i18n.LocalizableMessage; |
| | | import org.forgerock.opendj.config.server.ConfigChangeResult; |
| | | import org.forgerock.opendj.config.server.ConfigException; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | | import org.opends.server.TestCaseUtils; |
| | | import org.opends.server.backends.ChangelogBackend; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.opends.server.replication.ReplicationTestCase; |
| | | import org.opends.server.replication.service.ReplicationBroker; |
| | | import org.opends.server.types.VirtualAttributeRule; |
| | | import org.forgerock.opendj.ldap.DN; |
| | | import org.testng.annotations.Test; |
| | | |
| | |
| | | // instantiate a Replication server using the first port number. |
| | | ReplServerFakeConfiguration conf = new ReplServerFakeConfiguration(ports[0], null, 0, 1, 0, 0, null); |
| | | replicationServer = new ReplicationServer(conf); |
| | | assertTrue(replicationServer.isListening(), "the replication server should listen on port " + ports[0]); |
| | | |
| | | // Most of the configuration change are trivial to apply. |
| | | // The interesting change is the change of the replication server port. |
| | |
| | | // check that the sendWindow is not null to make sure that the |
| | | // broker did connect successfully. |
| | | assertTrue(broker.getCurrentSendWindow() != 0); |
| | | assertTrue(replicationServer.isListening(), "the replication server should listen on port " + ports[1]); |
| | | } |
| | | finally |
| | | { |
| | | remove(replicationServer); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Tests that a replication server whose listen port cannot be bound fails fast instead |
| | | * of silently starting without any listener, which used to surface much later, and in |
| | | * an unrelated place, as a "connection refused", and that aborting its initialization |
| | | * leaves the external changelog of the replication server which is already running |
| | | * untouched: the virtual attribute rules are registered globally, by attribute name. |
| | | */ |
| | | @Test |
| | | public void replServerFailsWhenListenPortIsInUse() throws Exception |
| | | { |
| | | TestCaseUtils.startServer(); |
| | | |
| | | ReplicationServer runningServer = null; |
| | | try |
| | | { |
| | | final int[] ports = TestCaseUtils.findFreePorts(1); |
| | | runningServer = new ReplicationServer(new ReplServerFakeConfiguration( |
| | | ports[0], "replServerFailsWhenListenPortIsInUseRunningDb", 0, 1, 0, 0, null)); |
| | | assertTrue(runningServer.isListening()); |
| | | |
| | | final List<String> rulesBefore = changelogVirtualAttributeNames(); |
| | | assertFalse(rulesBefore.isEmpty(), "the running replication server should provide the external changelog"); |
| | | final int instancesBefore = ReplicationServer.getAllInstances().size(); |
| | | |
| | | // Keep the port bound for the whole lifetime of the replication server creation. |
| | | final String dbDirName = "replServerFailsWhenListenPortIsInUseDb"; |
| | | try (ServerSocket portHolder = TestCaseUtils.bindFreePort()) |
| | | { |
| | | final ReplServerFakeConfiguration conf = new ReplServerFakeConfiguration( |
| | | portHolder.getLocalPort(), dbDirName, 0, 1, 0, 0, null); |
| | | try |
| | | { |
| | | final ReplicationServer replicationServer = new ReplicationServer(conf); |
| | | remove(replicationServer); |
| | | fail("Creating a replication server on a port already in use should have failed"); |
| | | } |
| | | catch (ConfigException expected) |
| | | { |
| | | // The failed replication server must not be left registered anywhere, |
| | | assertEquals(ReplicationServer.getAllInstances().size(), instancesBefore); |
| | | // nor must it release what it never acquired. |
| | | assertEquals(changelogVirtualAttributeNames(), rulesBefore, |
| | | "aborting the initialization must not deregister the virtual attribute rules" |
| | | + " of the running replication server"); |
| | | assertTrue(DirectoryServer.getInstance().getServerContext().getBackendConfigManager() |
| | | .hasLocalBackend(ChangelogBackend.BACKEND_ID), "the changelog backend should still be registered"); |
| | | assertTrue(runningServer.isListening(), "the running replication server should still listen"); |
| | | } |
| | | finally |
| | | { |
| | | // The aborted instance is never handed to the test, so its changelog cannot be |
| | | // removed through ReplicationTestCase.remove(). |
| | | recursiveDelete(getFileForPath(dbDirName)); |
| | | } |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | remove(runningServer); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Tests that a listen port which is only momentarily unavailable, as it happens when a |
| | | * socket holding it is being closed, does not prevent the replication server from |
| | | * starting: {@code bindListenPort()} retries the bind a few times. |
| | | * <p> |
| | | * The port is released as soon as the replication server has actually failed to bind it, |
| | | * so the retry is the only thing which can make it start: a test releasing the port after |
| | | * a delay would silently stop exercising the retry as soon as the replication server took |
| | | * longer than that delay to reach its first attempt. |
| | | */ |
| | | @Test |
| | | public void replServerRetriesToBindItsListenPort() throws Exception |
| | | { |
| | | TestCaseUtils.startServer(); |
| | | |
| | | ReplicationServer replicationServer = null; |
| | | final ServerSocket portHolder = TestCaseUtils.bindFreePort(); |
| | | final int bindFailuresBefore = ReplicationServer.listenPortBindFailures.get(); |
| | | try |
| | | { |
| | | final Thread portReleaser = new Thread(() -> { |
| | | try |
| | | { |
| | | final long deadline = System.currentTimeMillis() + 30000; |
| | | while (ReplicationServer.listenPortBindFailures.get() == bindFailuresBefore |
| | | && System.currentTimeMillis() < deadline) |
| | | { |
| | | Thread.sleep(10); |
| | | } |
| | | } |
| | | catch (InterruptedException e) |
| | | { |
| | | Thread.currentThread().interrupt(); |
| | | } |
| | | close(portHolder); |
| | | }, "port releaser of replServerRetriesToBindItsListenPort"); |
| | | portReleaser.start(); |
| | | |
| | | replicationServer = new ReplicationServer(new ReplServerFakeConfiguration( |
| | | portHolder.getLocalPort(), "replServerRetriesToBindItsListenPortDb", 0, 1, 0, 0, null)); |
| | | portReleaser.join(); |
| | | |
| | | assertTrue(ReplicationServer.listenPortBindFailures.get() > bindFailuresBefore, |
| | | "the replication server should have failed its first attempt to bind the port," |
| | | + " otherwise this test does not exercise the retry"); |
| | | assertTrue(replicationServer.isListening(), |
| | | "the replication server should have bound the port which was released while it was retrying"); |
| | | } |
| | | finally |
| | | { |
| | | close(portHolder); |
| | | remove(replicationServer); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Tests that a port change to a port which is not available is rejected, and that a |
| | | * replication server which nevertheless goes through the change keeps its listen port |
| | | * and its whole configuration: the new port is bound before the current one is released, |
| | | * so a failure has nothing to roll back and leaves nothing half applied. |
| | | */ |
| | | @Test |
| | | public void replServerKeepsItsConfigurationWhenAPortChangeFails() throws Exception |
| | | { |
| | | TestCaseUtils.startServer(); |
| | | |
| | | ReplicationServer replicationServer = null; |
| | | try |
| | | { |
| | | final int[] ports = TestCaseUtils.findFreePorts(1); |
| | | final String dbDirName = "replServerKeepsItsConfigurationWhenAPortChangeFailsDb"; |
| | | replicationServer = new ReplicationServer(new ReplServerFakeConfiguration( |
| | | ports[0], dbDirName, 0, 1, 0, 0, null, 1, 2000, 5000, 1)); |
| | | assertTrue(replicationServer.isListening()); |
| | | |
| | | try (ServerSocket portHolder = TestCaseUtils.bindFreePort()) |
| | | { |
| | | // The weight changes too, so that a failed change can be seen not to have applied |
| | | // the part of the new configuration which does not depend on the listen port. |
| | | final ReplServerFakeConfiguration newConf = new ReplServerFakeConfiguration( |
| | | portHolder.getLocalPort(), dbDirName, 0, 1, 0, 0, null, 1, 2000, 5000, 2); |
| | | |
| | | final List<LocalizableMessage> unacceptableReasons = new ArrayList<>(); |
| | | assertFalse(replicationServer.isConfigurationChangeAcceptable(newConf, unacceptableReasons), |
| | | "a change to a listen port which is in use should not be acceptable"); |
| | | assertFalse(unacceptableReasons.isEmpty(), "the rejected change should say why it was rejected"); |
| | | |
| | | final ConfigChangeResult ccr = replicationServer.applyConfigurationChange(newConf); |
| | | assertEquals(ccr.getResultCode(), ResultCode.OPERATIONS_ERROR); |
| | | assertFalse(ccr.getMessages().isEmpty(), "the failed change should say why it failed"); |
| | | assertEquals(replicationServer.getReplicationPort(), ports[0], |
| | | "the replication server should have kept its previous listen port"); |
| | | assertTrue(replicationServer.isListening(), "the replication server should still listen"); |
| | | assertEquals(replicationServer.getWeight(), 1, |
| | | "a failed port change must not apply the rest of the new configuration"); |
| | | } |
| | | |
| | | // and it must still be usable on its original port. |
| | | ReplicationBroker broker = openReplicationSession( |
| | | DN.valueOf(TEST_ROOT_DN_STRING), 1, 10, ports[0], 1000); |
| | | assertTrue(broker.getCurrentSendWindow() != 0); |
| | | } |
| | | finally |
| | | { |
| | | remove(replicationServer); |
| | | } |
| | | } |
| | | |
| | | /** Returns the names of the virtual attributes provided by the external changelog. */ |
| | | private List<String> changelogVirtualAttributeNames() |
| | | { |
| | | final Collection<String> changelogAttributes = Arrays.asList( |
| | | "lastexternalchangelogcookie", "firstchangenumber", "lastchangenumber", "changelog"); |
| | | final List<String> names = new ArrayList<>(); |
| | | for (VirtualAttributeRule rule : DirectoryServer.getVirtualAttributes()) |
| | | { |
| | | final String name = rule.getAttributeType().getNameOrOID().toLowerCase(); |
| | | if (changelogAttributes.contains(name)) |
| | | { |
| | | names.add(name); |
| | | } |
| | | } |
| | | Collections.sort(names); |
| | | return names; |
| | | } |
| | | } |
| | |
| | | * information: "Portions Copyright [year] [name of copyright owner]". |
| | | * |
| | | * Copyright 2014-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.forgerock.opendj.server.core; |
| | | |
| | |
| | | |
| | | private ProductInformation(final String productName) { |
| | | final String resourceName = "/META-INF/product/" + productName + ".properties"; |
| | | final InputStream stream = getClass().getResourceAsStream(resourceName); |
| | | final InputStream stream = ProductInformation.class.getResourceAsStream(resourceName); |
| | | |
| | | if (stream == null) { |
| | | throw new MissingResourceException("Can't find product information " + resourceName, |