diff --git a/.gitignore b/.gitignore
index ad3e5f7180..8daf5d4303 100644
--- a/.gitignore
+++ b/.gitignore
@@ -99,4 +99,7 @@ node_modules
# ctags index
tags
-test-output
\ No newline at end of file
+test-output
+
+# OrientDB test databases
+openidm-repo-orientdb/databases/
\ No newline at end of file
diff --git a/openidm-repo-orientdb/pom.xml b/openidm-repo-orientdb/pom.xml
index de42898cf1..8ea554aeea 100644
--- a/openidm-repo-orientdb/pom.xml
+++ b/openidm-repo-orientdb/pom.xml
@@ -74,36 +74,134 @@
${project.version}
-
-
-
+
+
com.orientechnologies
orientdb-core
${orientdb.version}
+ provided
org.xerial.snappy
snappy-java
+
+
+ org.graalvm.sdk
+ graal-sdk
+
+
+ org.graalvm.truffle
+ truffle-api
+
+
+ org.graalvm.js
+ js
+
+
+ org.graalvm.js
+ js-scriptengine
+
+
+ org.graalvm.tools
+ profiler
+
+
+ org.graalvm.tools
+ chromeinspector
+
+
+ org.graalvm.regex
+ regex
+
com.orientechnologies
orientdb-server
${orientdb.version}
+ provided
javax.activation
activation
+
+
+ org.graalvm.sdk
+ graal-sdk
+
+
+ org.graalvm.truffle
+ truffle-api
+
+
+ org.graalvm.js
+ js
+
+
+ org.graalvm.js
+ js-scriptengine
+
+
+ org.graalvm.tools
+ profiler
+
+
+ org.graalvm.tools
+ chromeinspector
+
+
+ org.graalvm.regex
+ regex
+
+
+
+ org.glassfish.jaxb
+ jaxb-runtime
+
+
+ org.glassfish.jaxb
+ jaxb-core
+
+
+ org.glassfish.jaxb
+ txw2
+
+
+ com.sun.istack
+ istack-commons-runtime
+
+
+ jakarta.xml.bind
+ jakarta.xml.bind-api
+
-
- com.orientechnologies
- orientdb-enterprise
- ${orientdb.version}
-
net.java.dev.jna
jna
@@ -158,10 +256,37 @@
true
- persistence-api;scope=provided
+
+ *;groupId=com.orientechnologies|com.github.jnr|com.googlecode.concurrentlinkedhashmap|at.yawk.lz4;inline=false
+ true
org.forgerock.openidm.repo.orientdb.metadata;version=${project.version}
org.forgerock.openidm.repo.orientdb.impl.*
org.forgerock.openidm.repo.orientdb.impl.Activator
+
+ *;resolution:=optional
+ *
diff --git a/openidm-repo-orientdb/src/main/java/org/forgerock/openidm/repo/orientdb/impl/DBHelper.java b/openidm-repo-orientdb/src/main/java/org/forgerock/openidm/repo/orientdb/impl/DBHelper.java
index 39bc1d42c3..af1d641a4c 100644
--- a/openidm-repo-orientdb/src/main/java/org/forgerock/openidm/repo/orientdb/impl/DBHelper.java
+++ b/openidm-repo-orientdb/src/main/java/org/forgerock/openidm/repo/orientdb/impl/DBHelper.java
@@ -52,7 +52,6 @@
import com.orientechnologies.orient.core.metadata.security.OSecurity;
import com.orientechnologies.orient.core.metadata.security.OUser;
import com.orientechnologies.orient.core.record.impl.ODocument;
-import com.orientechnologies.orient.core.storage.OStorage;
import java.util.Collection;
import java.util.Set;
@@ -205,9 +204,6 @@ private static ODatabaseDocumentPool initPool(String dbURL, String user, String
// Immediate disk sync for commit
OGlobalConfiguration.TX_COMMIT_SYNCH.setValue(true);
- // Have the storage closed when the DB is closed.
- OGlobalConfiguration.STORAGE_KEEP_OPEN.setValue(false);
-
boolean success = false;
int maxRetry = 10;
int retryCount = 0;
@@ -512,8 +508,13 @@ private static void createOrUpdateOrientDBClass(ODatabaseDocumentTx db, OSchema
OClass orientClass = schema.getClass(orientClassName);
if (orientClass == null) {
logger.info("OrientDB class {} does not exist and is being created.", orientClassName);
+ // OrientDB 3.x: createClass(String, int) treats the int as "number of
+ // clusters", NOT a cluster id (this was an API change from 2.x).
+ // Bind the class explicitly to the cluster we just created via the
+ // int[] overload to avoid creating N additional clusters per class
+ // (which causes cluster id overflow once it exceeds 32767).
orientClass = schema.createClass(orientClassName,
- db.addCluster(orientClassName));
+ new int[] { db.addCluster(orientClassName) });
}
List indexProperties = new ArrayList();
@@ -547,7 +548,7 @@ private static void createOrUpdateOrientDBClass(ODatabaseDocumentTx db, OSchema
String[] propertyNames = propNamesList.toArray(new String[propNamesList.size()]);
if (propertyNames.length > 0) {
String indexName = uniqueIndexName(orientClass.getName(), propertyNames);
- OIndex> oIndex = orientClass.getClassIndex(indexName);
+ OIndex oIndex = orientClass.getClassIndex(indexName);
if (oIndex != null && !oIndex.getType().equalsIgnoreCase(indexType)) {
indexManager.dropIndex(indexName);
oIndex = null;
@@ -568,8 +569,8 @@ private static void createOrUpdateOrientDBClass(ODatabaseDocumentTx db, OSchema
String propName = property.getName();
if (!indexProperties.contains(propName))
{
- Set> propIndexes = indexManager.getClassInvolvedIndexes(orientClass.getName(), propName);
- for (OIndex> propIndex : propIndexes) {
+ Set propIndexes = indexManager.getClassInvolvedIndexes(orientClass.getName(), propName);
+ for (OIndex propIndex : propIndexes) {
// Ensure that we only drop indexes which we created and
// match the OpenIDM index naming convention
String indexRegex = uniqueIndexName(orientClass.getName(), new String[]{".*"});
diff --git a/openidm-repo-orientdb/src/main/java/org/forgerock/openidm/repo/orientdb/impl/EmbeddedOServerService.java b/openidm-repo-orientdb/src/main/java/org/forgerock/openidm/repo/orientdb/impl/EmbeddedOServerService.java
index f4038bda4c..96e9b3d83b 100644
--- a/openidm-repo-orientdb/src/main/java/org/forgerock/openidm/repo/orientdb/impl/EmbeddedOServerService.java
+++ b/openidm-repo-orientdb/src/main/java/org/forgerock/openidm/repo/orientdb/impl/EmbeddedOServerService.java
@@ -263,12 +263,14 @@ protected OServerConfiguration getOrientDBConfig(JsonValue config) {
new OServerUserConfiguration("guest", null, "server.listDatabases")
};
configuration.properties = new OServerEntryConfiguration[]{
- new OServerEntryConfiguration("server.cache.staticResources", "false"),
- new OServerEntryConfiguration("orientdb.www.path", "db/util/orientdb/studio"),
- new OServerEntryConfiguration("orient.home", dbFolder.getAbsolutePath())
+ new OServerEntryConfiguration("server.cache.staticResources", "false")
+ // Legacy OrientDB 2.x server entries "orientdb.www.path" (OrientDB Studio
+ // is not shipped) and "orient.home" were removed: 3.x logs them as
+ // "Ignored storage configuration because not supported" on every start.
+ // ORIENTDB_HOME is set below as a system property which is the canonical
+ // way in 3.x.
};
- // OrientDB currently logs a warning if this is not set,
- // although it should be taking the setting from the config above instead.
+ // OrientDB expects ORIENTDB_HOME to be set as a system property.
System.setProperty("ORIENTDB_HOME", dbFolder.getAbsolutePath());
return configuration;
diff --git a/openidm-repo-orientdb/src/main/java/org/forgerock/openidm/repo/orientdb/impl/OrientDBRepoService.java b/openidm-repo-orientdb/src/main/java/org/forgerock/openidm/repo/orientdb/impl/OrientDBRepoService.java
index 951265583e..036cb12cb9 100644
--- a/openidm-repo-orientdb/src/main/java/org/forgerock/openidm/repo/orientdb/impl/OrientDBRepoService.java
+++ b/openidm-repo-orientdb/src/main/java/org/forgerock/openidm/repo/orientdb/impl/OrientDBRepoService.java
@@ -88,7 +88,6 @@
import com.orientechnologies.orient.core.index.OIndexException;
import com.orientechnologies.orient.core.record.impl.ODocument;
import com.orientechnologies.orient.core.storage.ORecordDuplicatedException;
-import com.orientechnologies.orient.core.version.OSimpleVersion;
/**
* Repository service implementation using OrientDB
@@ -418,7 +417,7 @@ public ResourceResponse delete(DeleteRequest request) throws ResourceException {
throw new NotFoundException("Object does not exist for delete on: " + request.getResourcePath());
}
- db.delete(existingDoc.getIdentity(), new OSimpleVersion(ver));
+ db.delete(existingDoc.getIdentity(), ver);
logger.debug("delete for id succeeded: {} revision: {}", localId, request.getRevision());
return DocumentUtil.toResource(existingDoc);
} catch (ODatabaseException ex) {
diff --git a/openidm-repo-orientdb/src/test/java/org/forgerock/openidm/repo/orientdb/impl/DocumentUtilTest.java b/openidm-repo-orientdb/src/test/java/org/forgerock/openidm/repo/orientdb/impl/DocumentUtilTest.java
index 71ee2b62ce..bd53cdedcf 100644
--- a/openidm-repo-orientdb/src/test/java/org/forgerock/openidm/repo/orientdb/impl/DocumentUtilTest.java
+++ b/openidm-repo-orientdb/src/test/java/org/forgerock/openidm/repo/orientdb/impl/DocumentUtilTest.java
@@ -29,7 +29,6 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.orientechnologies.common.log.OLogManager;
-import com.orientechnologies.orient.core.db.ODatabaseRecordThreadLocal;
import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx;
import com.orientechnologies.orient.core.metadata.schema.OType;
import com.orientechnologies.orient.core.record.impl.ODocument;
@@ -72,6 +71,10 @@ public void init() throws Exception {
} else {
db.open("admin", "admin");
}
+ // OrientDB 3.x requires the class to exist in the schema before newInstance() can be called
+ if (!db.getMetadata().getSchema().existsClass(orientDocClass)) {
+ db.getMetadata().getSchema().createClass(orientDocClass);
+ }
}
@AfterClass
@@ -82,7 +85,7 @@ public void cleanup() {
}
public ODatabaseDocumentTx getDatabase() {
- ODatabaseRecordThreadLocal.INSTANCE.set(db);
+ db.activateOnCurrentThread();
return db;
}
diff --git a/openidm-zip/src/main/resources/conf/boot/boot.properties b/openidm-zip/src/main/resources/conf/boot/boot.properties
index 04324f8194..e4ab95b5d6 100644
--- a/openidm-zip/src/main/resources/conf/boot/boot.properties
+++ b/openidm-zip/src/main/resources/conf/boot/boot.properties
@@ -1,3 +1,10 @@
+# Maximum time (ms) HealthService waits after framework start before
+# checking that all required services are up and reporting startup failure.
+# Default in code is 15s, but on restart with an existing OrientDB database
+# the pool reopen + bundle reactivation can exceed 15s, causing a spurious
+# "SEVERE: OpenIDM failure during startup" on otherwise healthy restarts.
+openidm.healthservice.servicestartmax=900000
+
openidm.port.http=8080
openidm.port.https=8443
openidm.port.mutualauth=8444
diff --git a/openidm-zip/src/main/resources/conf/logging.properties b/openidm-zip/src/main/resources/conf/logging.properties
index 2727c49b17..c96e84681f 100644
--- a/openidm-zip/src/main/resources/conf/logging.properties
+++ b/openidm-zip/src/main/resources/conf/logging.properties
@@ -73,6 +73,14 @@ org.identityconnectors.framework.impl.api.local.LocalConnectorInfoManagerImpl.le
# Suppress warnings of failed error page model validation
org.ops4j.pax.web.service.spi.model.elements.ErrorPageModel.level=SEVERE
+# OrientDB 3.x: suppress harmless WARNINGs that we cannot act on
+# - OScriptManager logs "ECMAScript engine not found" when no JSR-223 javascript
+# engine is on the classpath (we don't ship one and don't use OrientDB JS).
+# - ONative logs "Error detecting block size ignoring" when the JNA-based
+# filesystem block-size probe fails (e.g. on some Linux/container FS).
+com.orientechnologies.orient.core.command.script.OScriptManager.level=SEVERE
+com.orientechnologies.common.jna.ONative.level=SEVERE
+
############################################################
# Handler specific properties.
# Describes specific configuration info for Handlers.
diff --git a/openidm-zip/src/main/resources/shutdown.sh b/openidm-zip/src/main/resources/shutdown.sh
index d507e491ee..a9e2205e03 100644
--- a/openidm-zip/src/main/resources/shutdown.sh
+++ b/openidm-zip/src/main/resources/shutdown.sh
@@ -50,6 +50,22 @@ EXISTING_START_RUNNING=`ps -p $START_PID -o command= | grep "./startup.sh"`
if [ "$EXISTING_START_RUNNING" ]; then
echo "Stopping OpenIDM ($START_PID)"
pkill -P $START_PID
+ # Wait for the start script and its child JVM to actually exit before
+ # removing the PID file. Without this the caller (or the system)
+ # may immediately start a new instance while the previous JVM is still
+ # flushing on-disk state, which leaves the embedded OrientDB storage
+ # locked ("Database is locked by another process, please shutdown
+ # process and try again") on the next startup.
+ SHUTDOWN_WAIT=${OPENIDM_SHUTDOWN_WAIT:-120}
+ while [ "$SHUTDOWN_WAIT" -gt 0 ] && kill -0 "$START_PID" 2>/dev/null; do
+ sleep 1
+ SHUTDOWN_WAIT=$((SHUTDOWN_WAIT - 1))
+ done
+ if kill -0 "$START_PID" 2>/dev/null; then
+ echo "OpenIDM ($START_PID) did not stop within the timeout; sending SIGKILL"
+ pkill -KILL -P $START_PID
+ kill -KILL "$START_PID" 2>/dev/null
+ fi
cleanupPidFile
exit 0
fi
diff --git a/openidm-zip/src/main/resources/startup.bat b/openidm-zip/src/main/resources/startup.bat
index f3bcc2cfe4..4a5216be57 100755
--- a/openidm-zip/src/main/resources/startup.bat
+++ b/openidm-zip/src/main/resources/startup.bat
@@ -37,6 +37,18 @@ set "ADD_OPENS_ARGS="
if /I %JAVA_VERSION% GEQ 9 (
set ADD_OPENS_ARGS=--add-opens=java.base/jdk.internal.loader=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=jdk.management/com.sun.management.internal=ALL-UNNAMED
)
+rem Silence JDK 17+ "restricted method" warning emitted by jffi (jnr-posix used
+rem by OrientDB) calling System::load to load its native stub.
+if /I %JAVA_VERSION% GEQ 17 (
+ set ADD_OPENS_ARGS=%ADD_OPENS_ARGS% --enable-native-access=ALL-UNNAMED
+)
+rem Silence JDK 23+ "terminally deprecated sun.misc.Unsafe" warning emitted by
+rem org.apache.felix.framework.util.SecureAction#staticFieldOffset. Remove once
+rem org.apache.felix.framework is upgraded to a release that no longer uses
+rem sun.misc.Unsafe::staticFieldOffset.
+if /I %JAVA_VERSION% GEQ 23 (
+ set ADD_OPENS_ARGS=%ADD_OPENS_ARGS% --sun-misc-unsafe-memory-access=allow
+)
set "JPDA="
diff --git a/openidm-zip/src/main/resources/startup.sh b/openidm-zip/src/main/resources/startup.sh
index 3e9bb2974c..619b56eb8a 100755
--- a/openidm-zip/src/main/resources/startup.sh
+++ b/openidm-zip/src/main/resources/startup.sh
@@ -45,6 +45,18 @@ if [ $JAVA_VER -ge 90 ]; then
--add-opens=java.base/java.util=ALL-UNNAMED
--add-opens=jdk.management/com.sun.management.internal=ALL-UNNAMED"
fi
+# Silence JDK 17+ "restricted method" warning emitted by jffi (jnr-posix used by
+# OrientDB) calling System::load to load its native stub.
+if [ $JAVA_VER -ge 170 ]; then
+ ADD_OPENS_ARGS="$ADD_OPENS_ARGS --enable-native-access=ALL-UNNAMED"
+fi
+# Silence JDK 23+ "terminally deprecated sun.misc.Unsafe" warning emitted by
+# org.apache.felix.framework.util.SecureAction#staticFieldOffset. Remove once
+# org.apache.felix.framework is upgraded to a release that no longer uses
+# sun.misc.Unsafe::staticFieldOffset.
+if [ $JAVA_VER -ge 230 ]; then
+ ADD_OPENS_ARGS="$ADD_OPENS_ARGS --sun-misc-unsafe-memory-access=allow"
+fi
# clean up left over pid files if necessary
diff --git a/pom.xml b/pom.xml
index 2ec210eeec..f3ed1b04f0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -116,7 +116,7 @@
3.5.16
- 2.1.25
+ 3.2.51
1.7.10
2.0.0-alpha-1
2.9.4
@@ -185,7 +185,9 @@
--add-opens java.base/java.io=ALL-UNNAMED
--add-opens java.base/java.security=ALL-UNNAMED
--add-opens jdk.management/com.sun.management.internal=ALL-UNNAMED
+ --enable-native-access=ALL-UNNAMED
+
@@ -361,6 +363,22 @@
+
+
+ jdk23-allow-unsafe-memory-access
+
+ [23,)
+
+
+ --sun-misc-unsafe-memory-access=allow
+
+
@@ -777,7 +795,7 @@
maven-surefire-plugin
3.2.5
- ${java.surefire.options}
+ ${java.surefire.options} ${java.surefire.unsafe.options}