jkevan commented on code in PR #715:
URL: https://github.com/apache/unomi/pull/715#discussion_r1939679779
##########
services/src/main/java/org/apache/unomi/services/impl/events/EventServiceImpl.java:
##########
@@ -127,10 +116,17 @@ public String authenticateThirdPartyServer(String key,
String ip) {
for (Map.Entry<String, ThirdPartyServer> entry :
thirdPartyServers.entrySet()) {
ThirdPartyServer server = entry.getValue();
if (server.getKey().equals(key)) {
- IPAddress ipAddress = new IPAddressString(ip).getAddress();
- for (IPAddress serverIpAddress : server.getIpAddresses()) {
- if (serverIpAddress.contains(ipAddress)) {
- return server.getId();
+ // This is a fix to support proper IPv6 parsing
+ if (ip != null) {
+ if (ip.startsWith("[") && ip.endsWith("]")) {
+ // This can happen with IPv6 addresses, we must
remove the markers since our IPAddress library doesn't support them.
+ ip = ip.substring(1, ip.length() - 1);
+ }
+ IPAddress ipAddress = new
IPAddressString(ip).getAddress();
+ for (IPAddress serverIpAddress :
server.getIpAddresses()) {
+ if (serverIpAddress.contains(ipAddress)) {
+ return server.getId();
+ }
Review Comment:
This fix looks ok, but what is the link with open search support ?
If it's fixing a bug or issue, would it be more appropriate to separate it
in a dedicated PR/tests + tickets.
(current PR is already quiet huge, making it difficult to review, I think
that additional fixes not related to open search implem should not be part of
the current PR.)
##########
graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/condition/parsers/SegmentProfileEventsConditionParser.java:
##########
@@ -185,9 +185,16 @@ private Map<String, Object>
createProfileEventPropertyField(final Condition cond
tuple.put("fieldName", "cdp_timestamp_gte");
}
- final OffsetDateTime fieldValue =
DateUtils.offsetDateTimeFromMap((Map<String, Object>)
condition.getParameter("propertyValueDate"));
-
- tuple.put("fieldValue", fieldValue != null ? fieldValue.toString()
: null);
+ Object propertyValueDate =
condition.getParameter("propertyValueDate");
+ if (propertyValueDate == null) {
+ tuple.put("fieldValue", null);
+ } else if (propertyValueDate instanceof Map){
+ // This shouldn't be needed since Jackson was upgraded to >
2.13, but we keep it for backwards compatibility with older data sets
+ final OffsetDateTime fieldValue =
DateUtils.offsetDateTimeFromMap((Map<String, Object>) propertyValueDate);
+ tuple.put("fieldValue", fieldValue != null ?
fieldValue.toString() : null);
+ } else {
+ tuple.put("fieldValue", propertyValueDate.toString());
+ }
Review Comment:
Is this related to OpenSearch implem support ?
or is it a separate additional fix ?
##########
itests/src/test/java/org/apache/unomi/itests/ProgressListener.java:
##########
@@ -0,0 +1,275 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.unomi.itests;
+
+import org.junit.runner.Description;
+import org.junit.runner.Result;
+import org.junit.runner.notification.Failure;
+import org.junit.runner.notification.RunListener;
+
+import java.util.PriorityQueue;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class ProgressListener extends RunListener {
Review Comment:
What is the goal of this new class/runner ?
A bit of java doc would be welcome to understand it.
It's looks to be a nice addition to integration tests (even if I dont get
exactly what it does), but I dont see the relation to open search support.
Due to complexity of current PR that contains a lot of stuff I would greatly
appreciate separation between the open search support and the rest that is not
related.
##########
api/src/main/java/org/apache/unomi/api/services/EventService.java:
##########
@@ -161,4 +161,10 @@ public interface EventService {
* @param profileId identifier of the profile that we want to remove it's
events
*/
void removeProfileEvents(String profileId);
+
+ /**
+ * Delete an event by specifying its event identifier
+ * @param eventIdentifier the unique identifier for the event
+ */
+ void deleteEvent(String eventIdentifier);
Review Comment:
Those new API looks convenient, but I don't see the relation with open
search implem.
What is the need to introduce it now ?
I dont see any test coverage for this new method.
##########
itests/src/test/java/org/apache/unomi/itests/RuleServiceIT.java:
##########
@@ -80,16 +80,27 @@ public void testRuleWithNullActions() throws
InterruptedException {
public void getAllRulesShouldReturnAllRulesAvailable() throws
InterruptedException {
String ruleIDBase = "moreThan50RuleTest";
int originalRulesNumber = rulesService.getAllRules().size();
+
+ // Create a simple condition instead of null
+ Condition defaultCondition = new
Condition(definitionsService.getConditionType("matchAllCondition"));
+
+ // Create a default action
+ Action defaultAction = new
Action(definitionsService.getActionType("setPropertyAction"));
+ defaultAction.setParameter("propertyName", "testProperty");
+ defaultAction.setParameter("propertyValue", "testValue");
+ List<Action> actions = Collections.singletonList(defaultAction);
+
+
for (int i = 0; i < 60; i++) {
String ruleID = ruleIDBase + "_" + i;
Metadata metadata = new Metadata(ruleID);
metadata.setName(ruleID);
metadata.setDescription(ruleID);
metadata.setScope(TEST_SCOPE);
- Rule nullRule = new Rule(metadata);
- nullRule.setCondition(null);
- nullRule.setActions(null);
- createAndWaitForRule(nullRule);
+ Rule rule = new Rule(metadata);
+ rule.setCondition(defaultCondition); // Use default condition
instead of null
+ rule.setActions(actions); // Empty list instead of null
Review Comment:
Your comment seem's not correct, `actions` does contains an action actually.
##########
persistence-spi/src/main/java/org/apache/unomi/persistence/spi/CustomObjectMapper.java:
##########
@@ -58,6 +58,7 @@ public CustomObjectMapper() {
public CustomObjectMapper(Map<Class, StdDeserializer<?>> deserializers) {
super();
super.registerModule(new JaxbAnnotationModule());
+ super.registerModule(new
com.fasterxml.jackson.datatype.jsr310.JavaTimeModule());
Review Comment:
Could you add a comment to explain the necessity of this new jackson module ?
##########
rest/src/main/java/org/apache/unomi/rest/service/impl/RestServiceUtilsImpl.java:
##########
@@ -145,7 +145,13 @@ public EventsRequestContext initEventsRequest(String
scope, String sessionId, St
// Session user has been switched, profile id in
cookie is not up to date
// We must reload the profile with the session ID as
some properties could be missing from the session profile
// #personalIdentifier
-
eventsRequestContext.setProfile(profileService.load(sessionProfile.getItemId()));
+ Profile sessionProfileWithId =
profileService.load(sessionProfile.getItemId());
+ if (sessionProfileWithId != null) {
+
eventsRequestContext.setProfile(sessionProfileWithId);
+ } else {
+ LOGGER.warn("Couldn't find profile ID {}
referenced from session with ID {}, so we re-create it",
sessionProfile.getItemId(), sessionId);
+
eventsRequestContext.setProfile(createNewProfile(sessionProfile.getItemId(),
timestamp));
+ }
Review Comment:
Interesting check for ensuring profile is correctly created, but this does
not look related to open search support, and would prefer to have a dedicated
ticket and test coverage for this new handling.
##########
tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/EventRemove.java:
##########
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.unomi.shell.commands;
+
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.unomi.api.services.EventService;
+
+@Command(scope = "unomi", name = "event-remove", description = "This command
will remove an event.")
+@Service
+public class EventRemove extends RemoveCommandSupport {
Review Comment:
Nice addition, but not related to open search support ?
##########
manual/src/main/asciidoc/configuration.adoc:
##########
@@ -68,20 +68,53 @@
org.apache.unomi.cluster.public.address=http://localhost:8181
org.apache.unomi.cluster.internal.address=https://localhost:9443
----
-If you need to specify an ElasticSearch cluster name, or a host and port that
are different than the default,
-it is recommended to do this BEFORE you start the server for the first time,
or you will loose all the data
+If you need to specify a search engine configuration that is different than
the default,
+it is recommended to do this BEFORE you start the server for the first time,
or you will lose all the data
you have stored previously.
-You can use the following properties for the ElasticSearch configuration
+Apache Unomi supports both ElasticSearch and OpenSearch as search engine
backends. Here are the configuration properties for each:
+
+For ElasticSearch:
[source]
----
org.apache.unomi.elasticsearch.cluster.name=contextElasticSearch
-# The elasticsearch.adresses may be a comma seperated list of host names and
ports such as
+# The elasticsearch.addresses may be a comma separated list of host names and
ports such as
# hostA:9200,hostB:9200
# Note: the port number must be repeated for each host.
org.apache.unomi.elasticsearch.addresses=localhost:9200
----
+For OpenSearch:
+[source]
+----
+org.apache.unomi.opensearch.cluster.name=opensearch-cluster
+# The opensearch.addresses may be a comma separated list of host names and
ports such as
+# hostA:9200,hostB:9200
+# Note: the port number must be repeated for each host.
+org.apache.unomi.opensearch.addresses=localhost:9200
+
+# OpenSearch security settings (required by default since OpenSearch 2.0)
+org.apache.unomi.opensearch.ssl.enable=true
+org.apache.unomi.opensearch.username=admin
+org.apache.unomi.opensearch.password=${env:OPENSEARCH_INITIAL_ADMIN_PASSWORD:-admin}
+org.apache.unomi.opensearch.sslTrustAllCertificates=true
+----
+
+To select which search engine to use, you can:
+1. Use the appropriate configuration properties above
+2. When building from source, use the appropriate Maven profile:
+ * For ElasticSearch (default): no special profile needed
+ * For OpenSearch: add `-Duse.opensearch=true` to your Maven command
Review Comment:
To be clarified, mention that it have an impact on build, but this
`use.opensearch` seem's only for integration tests purpose. So I'm not sure
it's interesting to document this option in this place.
##########
extensions/privacy-extension/rest/pom.xml:
##########
@@ -88,6 +88,7 @@
<build>
<plugins>
+ <!--
Review Comment:
Why is this disabled ?
A comment with explaination here would be welcome.
##########
docker/src/main/docker/entrypoint.sh:
##########
@@ -16,28 +16,110 @@
# See the License for the specific language governing permissions and
# limitations under the License.
################################################################################
-# Wait for healthy ElasticSearch
-# next wait for ES status to turn to Green
-if [ "$UNOMI_ELASTICSEARCH_SSL_ENABLE" == 'true' ]; then
- schema='https'
+# Near the top of the file, add these default debug settings
+KARAF_DEBUG=${KARAF_DEBUG:-false}
+KARAF_DEBUG_PORT=${KARAF_DEBUG_PORT:-5005}
+KARAF_DEBUG_SUSPEND=${KARAF_DEBUG_SUSPEND:-n}
+
+# Before starting Karaf, add debug configuration
+if [ "$KARAF_DEBUG" = "true" ]; then
+ echo "Enabling Karaf debug mode on port $KARAF_DEBUG_PORT
(suspend=$KARAF_DEBUG_SUSPEND)"
+ export
JAVA_DEBUG_OPTS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=$KARAF_DEBUG_SUSPEND,address=*:$KARAF_DEBUG_PORT"
+ export KARAF_DEBUG=true
+fi
+
+# Determine search engine type from UNOMI_AUTO_START
+SEARCH_ENGINE="${UNOMI_AUTO_START:-elasticsearch}"
+export KARAF_OPTS="-Dunomi.autoStart=${UNOMI_AUTO_START}"
+
+if [ "$SEARCH_ENGINE" = "true" ]; then
+ SEARCH_ENGINE="elasticsearch"
+fi
+echo "SEARCH_ENGINE: $SEARCH_ENGINE"
+echo "KARAF_OPTS: $KARAF_OPTS"
+
+# Function to check cluster health for a specific node
+check_node_health() {
+ local node_url="$1"
+ local curl_opts="$2"
+ response=$(eval curl -v -fsSL ${curl_opts} "${node_url}" 2>&1)
+ if [ $? -eq 0 ]; then
+ echo "$response" | grep -o '"status"[ ]*:[ ]*"[^"]*"' | cut -d'"' -f4
+ else
+ echo ""
+ fi
+}
+
+# Configure connection parameters based on search engine type
+if [ "$SEARCH_ENGINE" = "opensearch" ]; then
+ # OpenSearch configuration
+ if [ -z "$UNOMI_OPENSEARCH_PASSWORD" ]; then
+ echo "Error: UNOMI_OPENSEARCH_PASSWORD must be set when using
OpenSearch"
+ exit 1
+ fi
+
+ schema='https'
+ auth_header="Authorization: Basic $(echo -n
"admin:${UNOMI_OPENSEARCH_PASSWORD}" | base64)"
+ health_endpoint="_cluster/health"
+ curl_opts="-k -H \"${auth_header}\" -H \"Content-Type: application/json\""
else
- schema='http'
+ # Elasticsearch configuration
+ if [ "$UNOMI_ELASTICSEARCH_SSL_ENABLE" = 'true' ]; then
+ schema='https'
+ else
+ schema='http'
+ fi
+
+ if [ -v UNOMI_ELASTICSEARCH_USERNAME ] && [ -v
UNOMI_ELASTICSEARCH_PASSWORD ]; then
+ auth_header="Authorization: Basic $(echo -n
"${UNOMI_ELASTICSEARCH_USERNAME}:${UNOMI_ELASTICSEARCH_PASSWORD}" | base64)"
+ curl_opts="-H \"${auth_header}\""
+ fi
+ health_endpoint="_cluster/health"
fi
-if [ -v UNOMI_ELASTICSEARCH_USERNAME ] && [ -v UNOMI_ELASTICSEARCH_PASSWORD ];
then
-
elasticsearch_addresses="$schema://$UNOMI_ELASTICSEARCH_USERNAME:$UNOMI_ELASTICSEARCH_PASSWORD@$UNOMI_ELASTICSEARCH_ADDRESSES/_cat/health?h=status"
+# Build array of node URLs
+if [ "$SEARCH_ENGINE" = "opensearch" ]; then
Review Comment:
Seem's this if/else testing again: `$SEARCH_ENGINE`
could be merge with the previous one:
https://github.com/apache/unomi/pull/715/files#diff-f7001630e8e432c22a83c67318dbe3b91a44ccd7ffd2548251309ba4551ccdf1R55.
##########
docker/README.md:
##########
@@ -48,21 +48,66 @@ For ElasticSearch:
docker pull docker.elastic.co/elasticsearch/elasticsearch:7.4.2
docker network create unomi
docker run --name elasticsearch --net unomi -p 9200:9200 -p 9300:9300 -e
"discovery.type=single-node" -e cluster.name=contextElasticSearch
docker.elastic.co/elasticsearch/elasticsearch:7.4.2
+
+For OpenSearch:
+
+ docker pull opensearchproject/opensearch:2.18.0
+ docker network create unomi
+ export OPENSEARCH_ADMIN_PASSWORD=enter_your_custom_admin_password_here
+ docker run --name opensearch --net unomi -p 9200:9200 -p 9300:9300 -e
"discovery.type=single-node" -e
OPENSEARCH_INITIAL_ADMIN_PASSWORD=${OPENSEARCH_ADMIN_PASSWORD}
opensearchproject/opensearch:2.18.0
-For Unomi:
+For Unomi (with ElasticSearch):
+
+ docker pull apache/unomi:2.7.0-SNAPSHOT
+ docker run --name unomi --net unomi -p 8181:8181 -p 9443:9443 -p 8102:8102
\
+ -e UNOMI_ELASTICSEARCH_ADDRESSES=elasticsearch:9200 \
+ apache/unomi:2.7.0-SNAPSHOT
- docker pull apache/unomi:2.0.0-SNAPSHOT
- docker run --name unomi --net unomi -p 8181:8181 -p 9443:9443 -p 8102:8102
-e UNOMI_ELASTICSEARCH_ADDRESSES=elasticsearch:9200 apache/unomi:2.0.0-SNAPSHOT
+For Unomi (with OpenSearch):
-## Using a host OS ElasticSearch installation (only supported on macOS &
Windows)
+ docker pull apache/unomi:2.7.0-SNAPSHOT
+ docker run --name unomi --net unomi -p 8181:8181 -p 9443:9443 -p 8102:8102
\
+ -e UNOMI_AUTO_START=opensearch \
+ -e UNOMI_OPENSEARCH_ADDRESSES=opensearch:9200 \
+ -e UNOMI_OPENSEARCH_PASSWORD=${OPENSEARCH_ADMIN_PASSWORD} \
+ apache/unomi:2.7.0-SNAPSHOT
+
+## Using a host OS Search Engine installation (only supported on macOS &
Windows)
+
+For ElasticSearch:
- docker run --name unomi -p 8181:8181 -p 9443:9443 -p 8102:8102 -e
UNOMI_ELASTICSEARCH_ADDRESSES=host.docker.internal:9200
apache/unomi:2.0.0-SNAPSHOT
+ docker run --name unomi -p 8181:8181 -p 9443:9443 -p 8102:8102 \
+ -e UNOMI_ELASTICSEARCH_ADDRESSES=host.docker.internal:9200 \
+ apache/unomi:2.7.0-SNAPSHOT
+
+For OpenSearch:
+
+ docker run --name unomi -p 8181:8181 -p 9443:9443 -p 8102:8102 \
+ -e UNOMI_AUTO_START=opensearch \
+ -e UNOMI_OPENSEARCH_ADDRESSES=host.docker.internal:9200 \
+ -e UNOMI_OPENSEARCH_PASSWORD=${OPENSEARCH_ADMIN_PASSWORD} \
+ apache/unomi:2.7.0-SNAPSHOT
Note: Linux doesn't support the host.docker.internal DNS lookup method yet, it
should be available in an upcoming version of Docker. See
https://github.com/docker/for-linux/issues/264
+## Environment Variables
+
+### Common Variables
+- `UNOMI_AUTO_START`: Specifies the search engine type (`elasticsearch` or
`opensearch`, defaults to `elasticsearch`)
Review Comment:
`UNOMI_AUTO_START` naming does not reflect that it's used for choosing which
persistence implem gonna be use. I would suggest to look for a more meaningful
naming for this option.
##########
api/src/main/java/org/apache/unomi/api/services/ProfileService.java:
##########
@@ -443,4 +443,10 @@ default Session loadSession(String sessionId) {
*/
@Deprecated
void purgeMonthlyItems(int existsNumberOfMonths);
+
+ /**
+ * Delete a session using its identifier
+ * @param sessionIdentifier the unique identifier for the session
+ */
+ void deleteSession(String sessionIdentifier);
Review Comment:
Those new API looks convenient, but I don't see the relation with open
search implem.
What is the need to introduce it now ?
I dont see any test coverage for this new method.
##########
itests/README.md:
##########
@@ -260,3 +281,60 @@ And the final step is, zipping the new version of the
snapshot repository and re
> In case you are using docker, do zip in the container and use `docker cp` to
> get the zip file from the docker container.
Now you can modify the migration test class to test that your added data in
1.6.x is correctly migrated in 2.0.0
+
+# Known issues
+
+In the OpenSearch test logs, you will see a lot of lines that look like this :
+
+ opensearch> [2024-12-31T15:33:14,652][WARN ][o.o.w.QueryGroupTask ]
[f3200971b164] QueryGroup _id can't be null, It should be set before accessing
it. This is abnormal behaviour
+
+This is due to a bug in OpenSearch 2.18 but it has no impact on the actual
functionality. You can track this bug here:
+
+ https://github.com/opensearch-project/OpenSearch/issues/16874
+
+## Karaf Tools
+
+The `kt.sh` script (short for "Karaf Tools") provides convenient utilities for
working with Karaf logs and directories during integration testing. Since Karaf
test directories are created with unique UUIDs for each test run, this script
helps locate and work with the latest test instance.
+
+### Usage
+
+```bash
+./kt.sh COMMAND [ARGS]
+```
+
+### Available Commands
+
+| Command | Alias | Description
|
+|-------------|-------|-------------------------------------------------------|
+| `log` | `l` | View the latest Karaf log file using less |
+| `tail` | `t` | Tail the current Karaf log file |
+| `grep` | `g` | Grep the latest Karaf log file (requires pattern) |
+| `dir` | `d` | Print the latest Karaf directory path |
+| `pushd` | `p` | Change to the latest Karaf directory using pushd |
+| `help` | `h` | Show help message |
Review Comment:
Karaf tools looks to be a nice addition, but I would prefer to have this
work out the current PR, it doesn't sounds related to open search support, and
therefore should be reviewed in it's own scope ticket/review etc.
##########
itests/src/test/java/org/apache/unomi/itests/BaseIT.java:
##########
@@ -309,6 +375,9 @@ public Option[] config() {
karafOptions.add(editConfigurationFilePut("etc/org.ops4j.pax.logging.cfg",
"log4j2.logger.customLogging.level", customLoggingParts[1]));
}
+ searchEngine = System.getProperty(SEARCH_ENGINE_PROPERTY,
SEARCH_ENGINE_ELASTICSEARCH);
+ System.out.println("Search Engine: " + searchEngine);
Review Comment:
Should we not use the `LOGGER` instead of SysOut ?
##########
tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/ActionRemove.java:
##########
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.unomi.shell.commands;
+
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.unomi.api.services.DefinitionsService;
+
+@Command(scope = "unomi", name = "action-remove", description = "This command
will remove an action type.")
+@Service
+public class ActionRemove extends RemoveCommandSupport {
Review Comment:
Nice addition, but not related to open search support ?
##########
itests/src/test/java/org/apache/unomi/itests/JSONSchemaIT.java:
##########
@@ -340,7 +339,14 @@ public void testFlattenedProperties() throws Exception {
condition.setParameter("propertyName",
"flattenedProperties.interests.cars");
condition.setParameter("comparisonOperator", "greaterThan");
condition.setParameter("propertyValueInteger", 2);
- assertNull(persistenceService.query(condition, null, Event.class, 0,
-1));
+ // OpenSearch handles flattened fields differently than Elasticsearch
+ if ("opensearch".equals(searchEngine)) {
+ assertNotNull("OpenSearch should return results for flattened
properties",
+ persistenceService.query(condition, null, Event.class, 0, -1));
+ } else {
+ assertNull("Elasticsearch should return null for flattened
properties",
+ persistenceService.query(condition, null, Event.class, 0, -1));
+ }
Review Comment:
This could be a problem, does it means that implems doesn't behave the same ?
##########
itests/src/test/resources/org.apache.unomi.healthcheck.cfg:
##########
@@ -22,10 +22,18 @@ esLogin = ${org.apache.unomi.elasticsearch.username:-}
esPassword = ${org.apache.unomi.elasticsearch.password:-}
httpClient.trustAllCertificates =
${org.apache.unomi.elasticsearch.sslTrustAllCertificates:-false}
+# OpenSearch configuration
+osAddresses = ${org.apache.unomi.opensearch.addresses:-localhost:9200}
+osSSLEnabled = ${org.apache.unomi.opensearch.sslEnable:-false}
+osLogin = ${org.apache.unomi.opensearch.username:-admin}
+osPassword = ${org.apache.unomi.opensearch.password:-}
+osMinimalClusterState =
${org.apache.unomi.opensearch.minimalClusterState:-YELLOW}
+httpClient.trustAllCertificates =
${org.apache.unomi.opensearch.sslTrustAllCertificates:-false}
Review Comment:
is it not conflicting with the es setting ?
it looks like it will override ES settings. may be safer to use an other
name.
##########
kar/src/main/feature/feature.xml:
##########
@@ -16,12 +16,12 @@
~ limitations under the License.
-->
-<features name="unomi-kar"
xmlns="http://karaf.apache.org/xmlns/features/v1.3.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.3.0
http://karaf.apache.org/xmlns/features/v1.3.0">
+<features name="unomi-features"
xmlns="http://karaf.apache.org/xmlns/features/v1.3.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.3.0
http://karaf.apache.org/xmlns/features/v1.3.0">
Review Comment:
All this kar -> feature improvement is welcome, and I do understand the
need, to handle correctly different persistence layer implems.
But I'm scared that some project will be impacted, I'm thinking of project
that are repackaging unomi with additional features, they probably rely on the
existing structure/naming of the kar/features in places.
##########
itests/src/test/java/org/apache/unomi/itests/BaseIT.java:
##########
@@ -200,13 +218,28 @@ public void waitForStartup() throws InterruptedException {
httpClient = initHttpClient(getHttpClientCredentialProvider());
}
+ private void waitForUnomiManagementService() throws InterruptedException {
+ UnomiManagementService unomiManagementService =
getOsgiService(UnomiManagementService.class, 600000);
+ while (unomiManagementService == null) {
+ LOGGER.info("Waiting for Unomi Management Service to be
available...");
+ Thread.sleep(1000);
+ unomiManagementService =
getOsgiService(UnomiManagementService.class, 600000);
+ }
Review Comment:
Could it generate endless loop ?
Should it not be found correctly the first time with the first call to
getOsgiService, the timeout looks reasonable.
##########
package/src/main/resources/etc/custom.system.properties:
##########
@@ -165,6 +165,80 @@
org.apache.unomi.elasticsearch.password=${env:UNOMI_ELASTICSEARCH_PASSWORD:-}
org.apache.unomi.elasticsearch.sslEnable=${env:UNOMI_ELASTICSEARCH_SSL_ENABLE:-false}
org.apache.unomi.elasticsearch.sslTrustAllCertificates=${env:UNOMI_ELASTICSEARCH_SSL_TRUST_ALL_CERTIFICATES:-false}
+#######################################################################################################################
+## OpenSearch settings
##
+#######################################################################################################################
+org.apache.unomi.opensearch.cluster.name=${env:UNOMI_OPENSEARCH_CLUSTERNAME:-opensearch-cluster}
+# The opensearch.addresses may be a comma seperated list of host names and
ports such as
+# hostA:9200,hostB:9200
+# Note: the port number must be repeated for each host.
+org.apache.unomi.opensearch.addresses=${env:UNOMI_OPENSEARCH_ADDRESSES:-localhost:9200}
+# refresh policy per item type in Json.
+# Valid values are WAIT_UNTIL/IMMEDIATE/NONE. The default refresh policy is
NONE.
+# Example: "{"event":"WAIT_UNTIL","rule":"NONE"}
+org.apache.unomi.opensearch.itemTypeToRefreshPolicy=${env:UNOMI_OPENSEARCH_REFRESH_POLICY_PER_ITEM_TYPE:-}
+org.apache.unomi.opensearch.fatalIllegalStateErrors=${env:UNOMI_OPENSEARCH_FATAL_STATE_ERRORS:-}
+org.apache.unomi.opensearch.index.prefix=${env:UNOMI_OPENSEARCH_INDEXPREFIX:-context}
+
+# These monthlyIndex properties are now deprecated, please use rollover
equivalent.
Review Comment:
Deprecate props could probably not be re-add to the open search implem ?
##########
itests/src/test/java/org/apache/unomi/itests/BaseIT.java:
##########
@@ -164,10 +167,25 @@ public abstract class BaseIT extends KarafTestSupport {
public void waitForStartup() throws InterruptedException {
// disable retry
retry = new KarafTestSupport.Retry(false);
+ searchEngine = System.getProperty(SEARCH_ENGINE_PROPERTY,
SEARCH_ENGINE_ELASTICSEARCH);
// Start Unomi if not already done
if (!unomiStarted) {
- executeCommand("unomi:start");
+ // We must check that the Unomi Management Service is up and
running before launching the
+ // command otherwise the start configuration will not be properly
populated.
+ waitForUnomiManagementService();
+ if (SEARCH_ENGINE_ELASTICSEARCH.equals(searchEngine)) {
+ LOGGER.info("Starting Unomi with elasticsearch search
engine...");
+ System.out.println("==== Starting Unomi with elasticsearch
search engine...");
+ executeCommand("unomi:start");
+ } else if (SEARCH_ENGINE_OPENSEARCH.equals(searchEngine)){
+ LOGGER.info("Starting Unomi with opensearch search engine...");
+ System.out.println("==== Starting Unomi with opensearch search
engine...");
+ executeCommand("unomi:start " + SEARCH_ENGINE_OPENSEARCH);
Review Comment:
I am not sure that mixin the unomi:start command with the search engine to
be used is a good idea, normally config should be self suficient to configure
properly the search engine, without the need to complexify the `unomi:start`
command.
##########
itests/src/test/java/org/apache/unomi/itests/ProgressSuite.java:
##########
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.unomi.itests;
+
+import org.junit.Test;
+import org.junit.runner.Description;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.Suite;
+import org.junit.runners.model.InitializationError;
+
+import java.lang.reflect.Method;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class ProgressSuite extends Suite {
Review Comment:
Same a bit of java doc would be welcome to understand what is it used for.
(looks also out of open search support scope.)
##########
extensions/web-tracker/wab/yarn.lock:
##########
@@ -4,27 +4,27 @@
"@ampproject/remapping@^2.1.0":
version "2.2.0"
- resolved
"https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d"
Review Comment:
Do you know why this file have been updated ?
##########
plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PropertyConditionEvaluator.java:
##########
@@ -91,14 +93,15 @@ private int compare(Object actualValue, String
expectedValue, Object expectedVal
} else if (expectedValueDateExpr != null) {
return
getDate(actualValue).compareTo(getDate(expectedValueDateExpr));
} else {
- return actualValue.toString().compareTo(expectedValue);
+ // We use toLowerCase here to match the behavior of the analyzer
configuration in the persistence configuration
+ return
actualValue.toString().toLowerCase().compareTo(expectedValue);
Review Comment:
Should we not call `ConditionContextHelper.foldToASCII` instead of manual
lowercasing here ?
##########
itests/src/test/java/org/apache/unomi/itests/BaseIT.java:
##########
@@ -223,12 +256,34 @@ protected void refreshPersistence(final Class<? extends
Item>... classes) throws
@Override
public MavenArtifactUrlReference getKarafDistribution() {
- return
CoreOptions.maven().groupId("org.apache.unomi").artifactId("unomi").versionAsInProject().type("tar.gz");
+ return
maven().groupId("org.apache.unomi").artifactId("unomi").versionAsInProject().type("tar.gz");
}
@Configuration
public Option[] config() {
System.out.println("==== Configuring container");
+
+ searchEngine = System.getProperty(SEARCH_ENGINE_PROPERTY,
SEARCH_ENGINE_ELASTICSEARCH);
+ System.out.println("Search Engine: " + searchEngine);
+
+ // Define features option based on search engine
+ Option featuresOption;
+ if (SEARCH_ENGINE_ELASTICSEARCH.equals(searchEngine)) {
+ featuresOption = features(maven().groupId("org.apache.unomi")
+
.artifactId("unomi-kar").versionAsInProject().type("xml").classifier("features"),
+ "unomi-persistence-elasticsearch", "unomi-services",
+ "unomi-router-karaf-feature", "unomi-groovy-actions",
+ "unomi-web-applications", "unomi-rest-ui",
"unomi-healthcheck", "cdp-graphql-feature");
+ } else if (SEARCH_ENGINE_OPENSEARCH.equals(searchEngine)) {
+ featuresOption = features(maven().groupId("org.apache.unomi")
+
.artifactId("unomi-kar").versionAsInProject().type("xml").classifier("features"),
+ "unomi-persistence-opensearch", "unomi-services",
+ "unomi-router-karaf-feature", "unomi-groovy-actions",
+ "unomi-web-applications", "unomi-rest-ui",
"unomi-healthcheck", "cdp-graphql-feature");
+ } else {
+ throw new IllegalArgumentException("Unknown search engine: " +
searchEngine);
+ }
Review Comment:
Seem's it could be simplified if the only difference in this two block is:
`unomi-persistence-opensearch` and `unomi-persistence-elasticsearch`
##########
itests/src/test/java/org/apache/unomi/itests/migration/Migrate16xTo220IT.java:
##########
@@ -59,16 +79,31 @@ public void waitForStartup() throws InterruptedException {
// Restore the snapshot
HttpUtils.executePostRequest(httpClient,
"http://localhost:9400/_snapshot/snapshots_repository/snapshot_1.6.x/_restore?wait_for_completion=true",
"{}", null);
+ String snapshotStatus = HttpUtils.executeGetRequest(httpClient,
"http://localhost:9400/_snapshot/_status", null);
+ System.out.println(snapshotStatus);
+ LOGGER.info(snapshotStatus);
+
Review Comment:
is it necessary ?
##########
persistence-spi/src/main/java/org/apache/unomi/persistence/spi/conditions/DateUtils.java:
##########
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.unomi.persistence.spi.conditions;
+
+import
org.apache.unomi.persistence.spi.conditions.datemath.DateMathParseException;
+import org.apache.unomi.persistence.spi.conditions.datemath.DateMathParser;
+import org.apache.unomi.persistence.spi.conditions.datemath.JavaDateFormatter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.time.Instant;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+import java.util.Date;
+
+public class DateUtils {
Review Comment:
A little bit of javadoc would be welcome here. both on class and methods.
##########
persistence-spi/src/main/java/org/apache/unomi/persistence/spi/conditions/datemath/JavaDateFormatter.java:
##########
@@ -0,0 +1,351 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.unomi.persistence.spi.conditions.datemath;
+
+import java.time.*;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.temporal.ChronoField;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalQueries;
+import java.util.ArrayList;
+import java.util.List;
+
+public class JavaDateFormatter {
Review Comment:
What is the reason for re-implementing a Java date formatter, what was wrong
with the previous `JodaDateMathParser` ?
A bit of context with comments/java doc would be greatly appreciate the
necessity of this new implem.
##########
persistence-spi/src/main/java/org/apache/unomi/persistence/spi/conditions/ConditionEvaluatorDispatcher.java:
##########
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.unomi.persistence.spi.conditions;
+
+import org.apache.unomi.api.Item;
+import org.apache.unomi.api.conditions.Condition;
+
+import java.util.Map;
+
+public interface ConditionEvaluatorDispatcher {
Review Comment:
Missing java doc on this interface.
##########
persistence-spi/src/main/java/org/apache/unomi/persistence/spi/conditions/geo/DistanceUnit.java:
##########
@@ -0,0 +1,163 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.unomi.persistence.spi.conditions.geo;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public enum DistanceUnit {
Review Comment:
I understand that because those classes was previously used from
elasticsearch library, you tried best effort to replace them by home made
implementation.
May be a using JSR 385 would be better idea for maintanability ?
https://github.com/unitsofmeasurement/indriya
##########
persistence-spi/src/main/java/org/apache/unomi/persistence/spi/conditions/datemath/DateMathParser.java:
##########
@@ -0,0 +1,270 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.unomi.persistence.spi.conditions.datemath;
+
+import java.time.*;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoField;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdjusters;
+import java.time.temporal.TemporalQueries;
+import java.util.function.Function;
+import java.util.function.LongSupplier;
+
+public class DateMathParser {
Review Comment:
Missing javadoc here, would appreciate some explaination regarding the
necessity of a custom date math parser VS using existing implems.
##########
persistence-spi/src/main/java/org/apache/unomi/persistence/spi/conditions/geo/GeoDistance.java:
##########
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.unomi.persistence.spi.conditions.geo;
+
+public enum GeoDistance {
Review Comment:
Same proposition, should we consider using jsr 385
(https://github.com/unitsofmeasurement/indriya) instead of re-implementing
those utilities ?
##########
persistence-spi/src/main/java/org/apache/unomi/persistence/spi/conditions/PastEventConditionPersistenceQueryBuilder.java:
##########
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.unomi.persistence.spi.conditions;
+
+import org.apache.unomi.api.conditions.Condition;
+import org.apache.unomi.api.services.DefinitionsService;
+import org.apache.unomi.scripting.ScriptExecutor;
+
+import java.util.Map;
+
+public interface PastEventConditionPersistenceQueryBuilder {
Review Comment:
Missing javadoc on this new interface.
##########
plugins/hover-event/src/main/java/org/apache/unomi/plugins/events/hover/querybuilders/HoverEventConditionESQueryBuilder.java:
##########
Review Comment:
Should we not move this ESQueryBuilder to the elasticsearch persistence
package ?
##########
persistence-elasticsearch/core/src/main/java/org/apache/unomi/persistence/elasticsearch/ElasticSearchPersistenceServiceImpl.java:
##########
@@ -1307,7 +1317,7 @@ protected Boolean execute(Object... args) throws
Exception {
itemType = customItemType;
}
String documentId = getDocumentIDForItemType(itemId,
itemType);
- String index = getIndexNameForQuery(itemType);
+ String index = getIndex(itemType);
Review Comment:
I'm not sure this will works for rollover indices like sessions and events.
What if the to_be_removed_itemId is in a past rolled over indice ?
##########
tools/shell-commands/src/main/java/org/apache/unomi/shell/actions/Start.java:
##########
@@ -29,8 +31,20 @@ public class Start implements Action {
@Reference
UnomiManagementService unomiManagementService;
+ @Argument(name = "persistence", description = "Persistence implementation
to use (elasticsearch/opensearch)", valueToShowInHelp = "elasticsearch")
+ private String selectedPersistenceImplementation = "elasticsearch";
+
Review Comment:
Still looks strnge that the start command is responsible of choosing the
persistence implem, I still think this should be handled by configuration.
##########
tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/ConditionRemove.java:
##########
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.unomi.shell.commands;
+
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.unomi.api.services.DefinitionsService;
+
+@Command(scope = "unomi", name = "condition-remove", description = "This
command will remove an condition type.")
+@Service
+public class ConditionRemove extends RemoveCommandSupport {
Review Comment:
Nice addition, but not related to open search support ?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]