Skip to content

Commit e52b428

Browse files
Copilotvharsekocopilot
authored
Upgrade OrientDB from 2.1.25 to 3.2.51 (#166)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: vharseko <6818498+vharseko@users.noreply.github.com> Co-authored-by: copilot <copilot@github.com> Co-authored-by: Valera V Harseko <vharseko@3a-systems.ru>
1 parent a146dcd commit e52b428

12 files changed

Lines changed: 246 additions & 30 deletions

File tree

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,4 +99,7 @@ node_modules
9999

100100
# ctags index
101101
tags
102-
test-output
102+
test-output
103+
104+
# OrientDB test databases
105+
openidm-repo-orientdb/databases/

openidm-repo-orientdb/pom.xml

Lines changed: 135 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
~ "Portions Copyrighted [year] [name of copyright owner]"
2424
~
2525
~ Portions Copyrighted 2024 3A Systems LLC.
26+
~ Portions copyright 2026 3A Systems, LLC.
2627
-->
2728
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
2829
<modelVersion>4.0.0</modelVersion>
@@ -74,36 +75,134 @@
7475
<version>${project.version}</version>
7576
</dependency>
7677

77-
<!-- Commons -->
78-
79-
<!-- OrientDB -->
78+
<!-- OrientDB -->
79+
<!--
80+
OrientDB and its transitive dependencies (jnr-*, jffi, jaxb-*, ...) are embedded
81+
into the openidm-repo-orientdb bundle (see Embed-Dependency below). They are
82+
scoped 'provided' so they (and their transitives) are not also deployed as
83+
standalone bundles by openidm-zip, where many of them either lack OSGi
84+
metadata (jffi has no Bundle-SymbolicName) or have unsatisfied OSGi
85+
requirements in the OpenIDM runtime (jnr-ffi → com.kenai.jffi,
86+
jaxb-core → jakarta.xml.bind 3.x). 'provided' deps are still on the
87+
compile/test classpath, so unit tests work.
88+
-->
8089
<dependency>
8190
<groupId>com.orientechnologies</groupId>
8291
<artifactId>orientdb-core</artifactId>
8392
<version>${orientdb.version}</version>
93+
<scope>provided</scope>
8494
<exclusions>
8595
<exclusion>
8696
<groupId>org.xerial.snappy</groupId>
8797
<artifactId>snappy-java</artifactId>
8898
</exclusion>
99+
<!--
100+
OrientDB 3.x pulls in GraalVM/Truffle for SQL JS scripting via the java11+
101+
profile. These jars are not OSGi bundles and several of them
102+
(graal-sdk, regex, js-scriptengine, profiler, chromeinspector) do not even
103+
contain a META-INF/MANIFEST.MF entry, which causes Felix to abort with
104+
"FileNotFoundException: META-INF/MANIFEST.MF" during bundle install.
105+
OpenIDM does not use OrientDB's JS scripting, so they are excluded.
106+
-->
107+
<exclusion>
108+
<groupId>org.graalvm.sdk</groupId>
109+
<artifactId>graal-sdk</artifactId>
110+
</exclusion>
111+
<exclusion>
112+
<groupId>org.graalvm.truffle</groupId>
113+
<artifactId>truffle-api</artifactId>
114+
</exclusion>
115+
<exclusion>
116+
<groupId>org.graalvm.js</groupId>
117+
<artifactId>js</artifactId>
118+
</exclusion>
119+
<exclusion>
120+
<groupId>org.graalvm.js</groupId>
121+
<artifactId>js-scriptengine</artifactId>
122+
</exclusion>
123+
<exclusion>
124+
<groupId>org.graalvm.tools</groupId>
125+
<artifactId>profiler</artifactId>
126+
</exclusion>
127+
<exclusion>
128+
<groupId>org.graalvm.tools</groupId>
129+
<artifactId>chromeinspector</artifactId>
130+
</exclusion>
131+
<exclusion>
132+
<groupId>org.graalvm.regex</groupId>
133+
<artifactId>regex</artifactId>
134+
</exclusion>
89135
</exclusions>
90136
</dependency>
91137
<dependency>
92138
<groupId>com.orientechnologies</groupId>
93139
<artifactId>orientdb-server</artifactId>
94140
<version>${orientdb.version}</version>
141+
<scope>provided</scope>
95142
<exclusions>
96143
<exclusion>
97144
<groupId>javax.activation</groupId>
98145
<artifactId>activation</artifactId>
99146
</exclusion>
147+
<!-- See orientdb-core above: excluded GraalVM transitive dependencies. -->
148+
<exclusion>
149+
<groupId>org.graalvm.sdk</groupId>
150+
<artifactId>graal-sdk</artifactId>
151+
</exclusion>
152+
<exclusion>
153+
<groupId>org.graalvm.truffle</groupId>
154+
<artifactId>truffle-api</artifactId>
155+
</exclusion>
156+
<exclusion>
157+
<groupId>org.graalvm.js</groupId>
158+
<artifactId>js</artifactId>
159+
</exclusion>
160+
<exclusion>
161+
<groupId>org.graalvm.js</groupId>
162+
<artifactId>js-scriptengine</artifactId>
163+
</exclusion>
164+
<exclusion>
165+
<groupId>org.graalvm.tools</groupId>
166+
<artifactId>profiler</artifactId>
167+
</exclusion>
168+
<exclusion>
169+
<groupId>org.graalvm.tools</groupId>
170+
<artifactId>chromeinspector</artifactId>
171+
</exclusion>
172+
<exclusion>
173+
<groupId>org.graalvm.regex</groupId>
174+
<artifactId>regex</artifactId>
175+
</exclusion>
176+
<!--
177+
JAXB stack pulled in by orientdb-server for OServerConfiguration XML
178+
(de)serialization. OpenIDM's EmbeddedOServerService builds the OServer
179+
config programmatically (no XML), so JAXB is not needed at runtime.
180+
The jaxb bundles fail OSGi resolution because they require
181+
jakarta.xml.bind 3.0.x which is not provided by any other bundle in
182+
the OpenIDM runtime.
183+
-->
184+
<exclusion>
185+
<groupId>org.glassfish.jaxb</groupId>
186+
<artifactId>jaxb-runtime</artifactId>
187+
</exclusion>
188+
<exclusion>
189+
<groupId>org.glassfish.jaxb</groupId>
190+
<artifactId>jaxb-core</artifactId>
191+
</exclusion>
192+
<exclusion>
193+
<groupId>org.glassfish.jaxb</groupId>
194+
<artifactId>txw2</artifactId>
195+
</exclusion>
196+
<exclusion>
197+
<groupId>com.sun.istack</groupId>
198+
<artifactId>istack-commons-runtime</artifactId>
199+
</exclusion>
200+
<exclusion>
201+
<groupId>jakarta.xml.bind</groupId>
202+
<artifactId>jakarta.xml.bind-api</artifactId>
203+
</exclusion>
100204
</exclusions>
101205
</dependency>
102-
<dependency>
103-
<groupId>com.orientechnologies</groupId>
104-
<artifactId>orientdb-enterprise</artifactId>
105-
<version>${orientdb.version}</version>
106-
</dependency>
107206
<dependency>
108207
<groupId>net.java.dev.jna</groupId>
109208
<artifactId>jna</artifactId>
@@ -158,10 +257,37 @@
158257
<extensions>true</extensions>
159258
<configuration>
160259
<instructions>
161-
<Embed-Dependency>persistence-api;scope=provided</Embed-Dependency>
260+
<!--
261+
Embed only the OrientDB core/server jars and the JNR/jffi
262+
stack into this bundle. These artifacts are NOT OSGi bundles
263+
(OrientDB jars lack Bundle-SymbolicName; jffi lacks any OSGi
264+
metadata at all), so installing them as standalone bundles in
265+
openidm/bundle/ fails OSGi resolution. Embedding them here
266+
keeps the bundle self-contained.
267+
268+
JNA is excluded because it is already a proper OSGi bundle and
269+
is deployed standalone via openidm-zip's runtime scope.
270+
271+
Embed-Transitive is intentionally false to avoid accidentally
272+
embedding unrelated artifacts (e.g. osgi.core or other
273+
openidm-* bundles) which would cause ClassCastExceptions at
274+
runtime due to duplicate classes loaded by different
275+
classloaders.
276+
-->
277+
<Embed-Dependency>*;groupId=com.orientechnologies|com.github.jnr|com.googlecode.concurrentlinkedhashmap|at.yawk.lz4;inline=false</Embed-Dependency>
278+
<Embed-Transitive>true</Embed-Transitive>
162279
<Export-Package>org.forgerock.openidm.repo.orientdb.metadata;version=${project.version}</Export-Package>
163280
<Private-Package>org.forgerock.openidm.repo.orientdb.impl.*</Private-Package>
164281
<Bundle-Activator>org.forgerock.openidm.repo.orientdb.impl.Activator</Bundle-Activator>
282+
<!--
283+
The embedded OrientDB and JNR code references many
284+
optional/platform-specific packages (graalvm, truffle,
285+
jakarta.xml.bind, com.sun.management, ...) that are not
286+
present in the OpenIDM runtime. Marking imports optional
287+
lets the bundle resolve and start without them.
288+
-->
289+
<Import-Package>*;resolution:=optional</Import-Package>
290+
<DynamicImport-Package>*</DynamicImport-Package>
165291
</instructions>
166292
</configuration>
167293
</plugin>

openidm-repo-orientdb/src/main/java/org/forgerock/openidm/repo/orientdb/impl/DBHelper.java

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
* with the fields enclosed by brackets [] replaced by
2121
* your own identifying information:
2222
* "Portions Copyrighted [year] [name of copyright owner]"
23+
*
24+
* Portions copyright 2026 3A Systems, LLC.
2325
*/
2426
package org.forgerock.openidm.repo.orientdb.impl;
2527

@@ -52,7 +54,6 @@
5254
import com.orientechnologies.orient.core.metadata.security.OSecurity;
5355
import com.orientechnologies.orient.core.metadata.security.OUser;
5456
import com.orientechnologies.orient.core.record.impl.ODocument;
55-
import com.orientechnologies.orient.core.storage.OStorage;
5657

5758
import java.util.Collection;
5859
import java.util.Set;
@@ -205,9 +206,6 @@ private static ODatabaseDocumentPool initPool(String dbURL, String user, String
205206
// Immediate disk sync for commit
206207
OGlobalConfiguration.TX_COMMIT_SYNCH.setValue(true);
207208

208-
// Have the storage closed when the DB is closed.
209-
OGlobalConfiguration.STORAGE_KEEP_OPEN.setValue(false);
210-
211209
boolean success = false;
212210
int maxRetry = 10;
213211
int retryCount = 0;
@@ -512,8 +510,13 @@ private static void createOrUpdateOrientDBClass(ODatabaseDocumentTx db, OSchema
512510
OClass orientClass = schema.getClass(orientClassName);
513511
if (orientClass == null) {
514512
logger.info("OrientDB class {} does not exist and is being created.", orientClassName);
513+
// OrientDB 3.x: createClass(String, int) treats the int as "number of
514+
// clusters", NOT a cluster id (this was an API change from 2.x).
515+
// Bind the class explicitly to the cluster we just created via the
516+
// int[] overload to avoid creating N additional clusters per class
517+
// (which causes cluster id overflow once it exceeds 32767).
515518
orientClass = schema.createClass(orientClassName,
516-
db.addCluster(orientClassName));
519+
new int[] { db.addCluster(orientClassName) });
517520
}
518521

519522
List<String> indexProperties = new ArrayList<String>();
@@ -547,7 +550,7 @@ private static void createOrUpdateOrientDBClass(ODatabaseDocumentTx db, OSchema
547550
String[] propertyNames = propNamesList.toArray(new String[propNamesList.size()]);
548551
if (propertyNames.length > 0) {
549552
String indexName = uniqueIndexName(orientClass.getName(), propertyNames);
550-
OIndex<?> oIndex = orientClass.getClassIndex(indexName);
553+
OIndex oIndex = orientClass.getClassIndex(indexName);
551554
if (oIndex != null && !oIndex.getType().equalsIgnoreCase(indexType)) {
552555
indexManager.dropIndex(indexName);
553556
oIndex = null;
@@ -568,8 +571,8 @@ private static void createOrUpdateOrientDBClass(ODatabaseDocumentTx db, OSchema
568571
String propName = property.getName();
569572
if (!indexProperties.contains(propName))
570573
{
571-
Set<OIndex<?>> propIndexes = indexManager.getClassInvolvedIndexes(orientClass.getName(), propName);
572-
for (OIndex<?> propIndex : propIndexes) {
574+
Set<OIndex> propIndexes = indexManager.getClassInvolvedIndexes(orientClass.getName(), propName);
575+
for (OIndex propIndex : propIndexes) {
573576
// Ensure that we only drop indexes which we created and
574577
// match the OpenIDM index naming convention
575578
String indexRegex = uniqueIndexName(orientClass.getName(), new String[]{".*"});

openidm-repo-orientdb/src/main/java/org/forgerock/openidm/repo/orientdb/impl/EmbeddedOServerService.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
* with the fields enclosed by brackets [] replaced by
2121
* your own identifying information:
2222
* "Portions Copyrighted [year] [name of copyright owner]"
23+
*
24+
* Portions copyright 2026 3A Systems, LLC.
2325
*/
2426
package org.forgerock.openidm.repo.orientdb.impl;
2527

@@ -263,12 +265,14 @@ protected OServerConfiguration getOrientDBConfig(JsonValue config) {
263265
new OServerUserConfiguration("guest", null, "server.listDatabases")
264266
};
265267
configuration.properties = new OServerEntryConfiguration[]{
266-
new OServerEntryConfiguration("server.cache.staticResources", "false"),
267-
new OServerEntryConfiguration("orientdb.www.path", "db/util/orientdb/studio"),
268-
new OServerEntryConfiguration("orient.home", dbFolder.getAbsolutePath())
268+
new OServerEntryConfiguration("server.cache.staticResources", "false")
269+
// Legacy OrientDB 2.x server entries "orientdb.www.path" (OrientDB Studio
270+
// is not shipped) and "orient.home" were removed: 3.x logs them as
271+
// "Ignored storage configuration because not supported" on every start.
272+
// ORIENTDB_HOME is set below as a system property which is the canonical
273+
// way in 3.x.
269274
};
270-
// OrientDB currently logs a warning if this is not set,
271-
// although it should be taking the setting from the config above instead.
275+
// OrientDB expects ORIENTDB_HOME to be set as a system property.
272276
System.setProperty("ORIENTDB_HOME", dbFolder.getAbsolutePath());
273277

274278
return configuration;

openidm-repo-orientdb/src/main/java/org/forgerock/openidm/repo/orientdb/impl/OrientDBRepoService.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
*
1414
* Copyright 2011-2016 ForgeRock AS.
1515
* Portions Copyrighted 2024 3A Systems LLC.
16+
* Portions copyright 2026 3A Systems, LLC.
1617
*/
1718
package org.forgerock.openidm.repo.orientdb.impl;
1819

@@ -88,7 +89,6 @@
8889
import com.orientechnologies.orient.core.index.OIndexException;
8990
import com.orientechnologies.orient.core.record.impl.ODocument;
9091
import com.orientechnologies.orient.core.storage.ORecordDuplicatedException;
91-
import com.orientechnologies.orient.core.version.OSimpleVersion;
9292

9393
/**
9494
* Repository service implementation using OrientDB
@@ -418,7 +418,7 @@ public ResourceResponse delete(DeleteRequest request) throws ResourceException {
418418
throw new NotFoundException("Object does not exist for delete on: " + request.getResourcePath());
419419
}
420420

421-
db.delete(existingDoc.getIdentity(), new OSimpleVersion(ver));
421+
db.delete(existingDoc.getIdentity(), ver);
422422
logger.debug("delete for id succeeded: {} revision: {}", localId, request.getRevision());
423423
return DocumentUtil.toResource(existingDoc);
424424
} catch (ODatabaseException ex) {

openidm-repo-orientdb/src/test/java/org/forgerock/openidm/repo/orientdb/impl/DocumentUtilTest.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
* with the fields enclosed by brackets [] replaced by
2121
* your own identifying information:
2222
* "Portions Copyrighted [year] [name of copyright owner]"
23+
*
24+
* Portions copyright 2026 3A Systems, LLC.
2325
*/
2426
package org.forgerock.openidm.repo.orientdb.impl;
2527

@@ -29,7 +31,6 @@
2931

3032
import com.fasterxml.jackson.databind.ObjectMapper;
3133
import com.orientechnologies.common.log.OLogManager;
32-
import com.orientechnologies.orient.core.db.ODatabaseRecordThreadLocal;
3334
import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx;
3435
import com.orientechnologies.orient.core.metadata.schema.OType;
3536
import com.orientechnologies.orient.core.record.impl.ODocument;
@@ -72,6 +73,10 @@ public void init() throws Exception {
7273
} else {
7374
db.open("admin", "admin");
7475
}
76+
// OrientDB 3.x requires the class to exist in the schema before newInstance() can be called
77+
if (!db.getMetadata().getSchema().existsClass(orientDocClass)) {
78+
db.getMetadata().getSchema().createClass(orientDocClass);
79+
}
7580
}
7681

7782
@AfterClass
@@ -82,7 +87,7 @@ public void cleanup() {
8287
}
8388

8489
public ODatabaseDocumentTx getDatabase() {
85-
ODatabaseRecordThreadLocal.INSTANCE.set(db);
90+
db.activateOnCurrentThread();
8691
return db;
8792
}
8893

openidm-zip/src/main/resources/conf/boot/boot.properties

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
# Maximum time (ms) HealthService waits after framework start before
2+
# checking that all required services are up and reporting startup failure.
3+
# Default in code is 15s, but on restart with an existing OrientDB database
4+
# the pool reopen + bundle reactivation can exceed 15s, causing a spurious
5+
# "SEVERE: OpenIDM failure during startup" on otherwise healthy restarts.
6+
openidm.healthservice.servicestartmax=900000
7+
18
openidm.port.http=8080
29
openidm.port.https=8443
310
openidm.port.mutualauth=8444

openidm-zip/src/main/resources/conf/logging.properties

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,14 @@ org.identityconnectors.framework.impl.api.local.LocalConnectorInfoManagerImpl.le
7373
# Suppress warnings of failed error page model validation
7474
org.ops4j.pax.web.service.spi.model.elements.ErrorPageModel.level=SEVERE
7575

76+
# OrientDB 3.x: suppress harmless WARNINGs that we cannot act on
77+
# - OScriptManager logs "ECMAScript engine not found" when no JSR-223 javascript
78+
# engine is on the classpath (we don't ship one and don't use OrientDB JS).
79+
# - ONative logs "Error detecting block size ignoring" when the JNA-based
80+
# filesystem block-size probe fails (e.g. on some Linux/container FS).
81+
com.orientechnologies.orient.core.command.script.OScriptManager.level=SEVERE
82+
com.orientechnologies.common.jna.ONative.level=SEVERE
83+
7684
############################################################
7785
# Handler specific properties.
7886
# Describes specific configuration info for Handlers.

0 commit comments

Comments
 (0)