Skip to content
Open
Show file tree
Hide file tree
Changes from 82 commits
Commits
Show all changes
92 commits
Select commit Hold shift + click to select a range
933f836
[Tech] Change project version to 2.8.0-SNAPSHOT
smiakchilo Apr 23, 2026
49d42fd
[EAK-651] Implement basic Relay Resource Provider logic
smiakchilo Apr 23, 2026
98e8102
[EAK-647] Introduce ResolverUtil to unify resource resolver handling
smiakchilo Apr 8, 2026
d7514f3
[EAK-647] Add ResolverUtil tests
smiakchilo Apr 11, 2026
bb062ee
[Tech] Remove obsolete plugin reference
smiakchilo Apr 27, 2026
cc0a2ba
[Tech] Simplify launching tests
smiakchilo Apr 27, 2026
2a86c63
[EAK-651] Move ResolverUtil
smiakchilo Apr 27, 2026
8f547fb
[EAK-651] Add a JSON-to-entity conversion method
smiakchilo Apr 28, 2026
f56bbda
[EAK-651] Optimize relay code; add Javadoc
smiakchilo Apr 28, 2026
74cfcfd
[EAK-651] Create unit tests
smiakchilo Apr 28, 2026
fbc0756
[EAK-651] Fix incorrect paths
smiakchilo Apr 28, 2026
b5b4e91
[EAK-651] Update path sampling logic; handle NullPointerException in …
smiakchilo Apr 28, 2026
9ed7308
[EAK-651] Implement thread-safe SubsidiaryHolder for ResourceResolver…
smiakchilo Apr 28, 2026
aed6e25
[EAK-651] Rename service class
smiakchilo Apr 28, 2026
f8f3190
[EAK-651] Fix minor linting issues
smiakchilo Apr 28, 2026
b8c173f
[EAK-651] Simplify ResourceHelper method calls
smiakchilo Apr 29, 2026
0970843
[EAK-651] Modify the Relay config structure
smiakchilo Apr 29, 2026
c8b7725
[Tech] Introduce ServiceUtil for operations with OSGi components call…
smiakchilo Apr 29, 2026
644494f
[Tech] Replace marker annotations for uniformity
smiakchilo Apr 29, 2026
f5e4670
[Tech] Improve exception handling
smiakchilo Apr 29, 2026
57cef56
[EAK-651] Add method for creating a resolver for a provided user name
smiakchilo Apr 30, 2026
a984081
[EAK-651] Reaorder methods; cosmetic renaming
smiakchilo Apr 30, 2026
c1e1c4e
[EAK-651] Add utility method
smiakchilo Apr 30, 2026
3daf1f7
[EAK-651] Extract subsidiary data models; add a guardrail against sha…
smiakchilo Apr 30, 2026
469fc47
[EAK-651] Refactor PathSampler; add support for specifying a user
smiakchilo Apr 30, 2026
8cd5426
[EAK-651] Cosmetic config model change
smiakchilo Apr 30, 2026
f5df5ed
[EAK-651] Introduce RelayInfo model
smiakchilo Apr 30, 2026
67d4533
[EAK-651] Improve thread-safety on updating RelayInfo data
smiakchilo Apr 30, 2026
165a1b1
[EAK-651] Lower service retrieval failure log level
smiakchilo Apr 30, 2026
43981ed
[EAK-651] Handle an empty user ID; improve OSGi bundle context checks
smiakchilo Apr 30, 2026
a1d90a7
[EAK-651] Use normalized path for prefix check
smiakchilo Apr 30, 2026
58e59fa
[EAK-651] Improve handling exceptions during deactivation
smiakchilo Apr 30, 2026
247f28a
[EAK-651] Cosmetic wording change
smiakchilo Apr 30, 2026
3d3e325
[EAK-651] Improve sampling routine
smiakchilo Apr 30, 2026
2013d14
[EAK-651] Minor Javadoc fixes
smiakchilo May 1, 2026
f995b81
[EAK-651] Improve log reporting
smiakchilo May 1, 2026
3f3b8ac
[EAK-651] Add a guard against a ResourceResolver leak
smiakchilo May 1, 2026
7c62ff6
[EAK-651] Add missing Sling attribute
smiakchilo May 1, 2026
eb4082c
[EAK-651] Cosmetic syntax changes
smiakchilo May 1, 2026
7f26451
[EAK-651] Remove plain-text credential processing
smiakchilo May 1, 2026
3b847e4
[EAK-651] Add an NPE guard
smiakchilo May 1, 2026
fb3563d
[EAK-651] Reduce PathSampler's "isEmpty" logic; add local copy of vol…
smiakchilo May 1, 2026
4c04831
[EAK-651] Minor doc change
smiakchilo May 1, 2026
869d8cf
[EAK-651] Enhance service retrieval with callback support
smiakchilo May 1, 2026
155f6b9
[EAK-651] Rename helper classes
smiakchilo May 1, 2026
df18889
[EAK-651] Update RelayProviderTest
smiakchilo May 1, 2026
bb552cf
[EAK-651] Update RelayProviderHostTest
smiakchilo May 1, 2026
ca4580a
[EAK-651] Update PathSamplerTest
smiakchilo May 1, 2026
376d051
[EAK-651] Create tests for relay-related model classes
smiakchilo May 2, 2026
f7398fd
[EAK-651] Update ResolverUtilTest
smiakchilo May 2, 2026
66bdb23
[EAK-651] Update ServiceUtilTest
smiakchilo May 3, 2026
8f007e1
[EAK-651] Fix path sampling cache logic
smiakchilo May 3, 2026
36d0135
[EAK-651] Change the fallback child resource listing call
smiakchilo May 4, 2026
9bef4ab
[EAK-651] Fix the re-activation routine with paths property change
smiakchilo May 4, 2026
fa5dd77
[EAK-651] Make subsidiary resource resolvers more persistent
smiakchilo May 4, 2026
70201f0
[EAK-651] Fixed ResourceResolver not reset to the default when empty …
smiakchilo May 4, 2026
a40db7f
[EAK-651] Discard caching sampled paths
smiakchilo May 4, 2026
f7e704c
[EAK-651] Fix falling back to a pre-existent resolver in case of logi…
smiakchilo May 4, 2026
51fd1c4
[EAK-651] Limit RelayMapping identity to the "from" value
smiakchilo May 4, 2026
ceafd32
[EAK-651] Avoid ResourceResolver leaks; limit the number of ResourceR…
smiakchilo May 4, 2026
7908257
[EAK-651] Log duplicate path and user mappings
smiakchilo May 4, 2026
ade30c4
[EAK-651] Add a check for non-null bundle context
smiakchilo May 4, 2026
1979b8a
[EAK-651] Optimize path replacement logic in RelayPathHelper
smiakchilo May 4, 2026
7d5e1a1
[EAK-651] Synchronize update method in RelayProvider; reset sampler o…
smiakchilo May 4, 2026
8ca2173
[EAK-651] Simplify resolution path assignment in RelayResource constr…
smiakchilo May 4, 2026
44f393c
[EAK-651] Prevent duplicate service reference release
smiakchilo May 4, 2026
2aa114d
[EAK-651] Register ExternalResourceChangeListener in RelayProviderHost
smiakchilo May 4, 2026
e18652f
[EAK-651] Prevent overlap with remaining relays when processing a mul…
smiakchilo May 4, 2026
390726f
[EAK-651] Prevent overlap with remaining relays when processing a mul…
smiakchilo May 4, 2026
2b8c51c
[EAK-651] Fix sampling consistency when a replay provider's config up…
smiakchilo May 4, 2026
ab12acf
Merge remote-tracking branch 'origin/feature/EAK-651' into feature/EA…
smiakchilo May 4, 2026
682f0a0
[EAK-651] Develop test coverage for RelayProviderHost
smiakchilo May 4, 2026
d1860d9
[EAK-651] Fix the risk of re-entry cycle in case of incorrect mapping
smiakchilo May 4, 2026
057725d
[EAK-651] Add missing overridden methods in RelayResource
smiakchilo May 4, 2026
9001e28
[EAK-651] Remove legacy configuration for maven-surefire-plugin
smiakchilo May 4, 2026
78d1a52
[EAK-651] Improve null handling for top-level paths
smiakchilo May 5, 2026
500d199
[EAK-651] Use an empty context instead of null
smiakchilo May 5, 2026
7ec3c70
[EAK-651] Improve re-entry cycle breaker
smiakchilo May 5, 2026
a88375e
[EAK-651] Rename method for clarity; add a test case
smiakchilo May 5, 2026
f62567f
[EAK-651] Change callback type from AutoCloseable to Closeable in Res…
smiakchilo May 5, 2026
45d0805
[EAK-651] Add a re-entry guard for listChildren calls
smiakchilo May 5, 2026
e16f1c4
[Tech] Add null check for bundle context in ConfigDefinition
smiakchilo May 5, 2026
e99706b
[EAK-651] Simplify announce logic
smiakchilo May 5, 2026
b93e6d3
[EAK-651] Disable falling back to default resolver when user mapping …
smiakchilo May 5, 2026
8c84a55
[EAK-651] Disable parent resource hint for re-entry breaker
smiakchilo May 5, 2026
be6154a
[EAK-651] Code formatting; renaming
smiakchilo May 5, 2026
7fa9bf4
[EAK-651] Retire redundant setUp/tearDown cycle
smiakchilo May 5, 2026
f2be0b8
[EAK-651] Invalidate nested mappings
smiakchilo May 5, 2026
b4f6ce6
[EAK-651] Improve handling of irregular paths
smiakchilo May 5, 2026
fd5e450
[EAK-651] Improve handling of irregular paths
smiakchilo May 5, 2026
dd4d5c2
Merge remote-tracking branch 'origin/feature/EAK-651' into feature/EA…
smiakchilo May 5, 2026
ad052eb
[EAK-651] Improve handling of irregular paths
smiakchilo May 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion all/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<parent>
<groupId>com.exadel.etoolbox</groupId>
<artifactId>etoolbox-authoring-kit</artifactId>
<version>2.7.1-SNAPSHOT</version>
<version>2.8.0-SNAPSHOT</version>
</parent>

<artifactId>etoolbox-authoring-kit-all</artifactId>
Expand Down
7 changes: 1 addition & 6 deletions core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<parent>
<groupId>com.exadel.etoolbox</groupId>
<artifactId>etoolbox-authoring-kit</artifactId>
<version>2.7.1-SNAPSHOT</version>
<version>2.8.0-SNAPSHOT</version>
</parent>

<artifactId>etoolbox-authoring-kit-core</artifactId>
Expand Down Expand Up @@ -74,11 +74,6 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<includes>
<include>**/AllTests.class</include>
</includes>
</configuration>
</plugin>
</plugins>
</build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,18 @@
*/
package com.exadel.aem.toolkit.core.configurator.models.internal;

import java.util.Objects;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.adobe.granite.ui.components.ExpressionCustomizer;

import com.exadel.aem.toolkit.core.configurator.services.ConfigChangeListener;
import com.exadel.aem.toolkit.core.configurator.utils.PermissionUtil;
import com.exadel.aem.toolkit.core.configurator.utils.RequestUtil;
import com.exadel.aem.toolkit.core.utils.ServiceUtil;

/**
* Enumerates possible outcomes of a configuration access request
Expand Down Expand Up @@ -132,16 +131,10 @@ private static ConfigAccess pick(HttpServletRequest request) {
* @return True or false
*/
static boolean isGrantable(HttpServletRequest request) {
try {
BundleContext context = (BundleContext) request.getAttribute(BundleContext.class.getName());
if (context == null) {
context = Objects.requireNonNull(FrameworkUtil.getBundle(ConfigAccess.class).getBundleContext());
}
ConfigChangeListener listener = Objects.requireNonNull(context.getService(context.getServiceReference(ConfigChangeListener.class)));
return listener.isEnabled();
} catch (RuntimeException e) {
LOG.error("Could not acquire an OSGi entity", e);
return false;
BundleContext context = (BundleContext) request.getAttribute(BundleContext.class.getName());
if (context != null) {
return ServiceUtil.withService(ConfigChangeListener.class, context, ConfigChangeListener::isEnabled, false);
}
return ServiceUtil.withService(ConfigChangeListener.class, ConfigChangeListener::isEnabled, false);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import com.exadel.aem.toolkit.core.configurator.ConfiguratorConstants;
import com.exadel.aem.toolkit.core.configurator.utils.PermissionUtil;
import com.exadel.aem.toolkit.core.configurator.utils.RequestUtil;
import com.exadel.aem.toolkit.core.utils.ServiceUtil;

/**
* Represents a configuration definition, i.e., a set of configuration attributes united by the same PID together
Expand Down Expand Up @@ -293,17 +294,15 @@ public static ConfigDefinition from(HttpServletRequest request) {
* does not exist
*/
private static ConfigDefinition from(String pid, BundleContext context) {
ConfigurationAdmin configurationAdmin;
MetaTypeService metaTypeService;
try {
configurationAdmin = Objects.requireNonNull(context.getService(context.getServiceReference(ConfigurationAdmin.class)));
metaTypeService = Objects.requireNonNull(context.getService(context.getServiceReference(MetaTypeService.class)));
} catch (RuntimeException e) {
LOG.error("Could not acquire OSGi entity", e);
if (context == null) {
LOG.error("Cannot retrieve configuration for {}: no bundle context available", pid);
return EMPTY;
}

Configuration configuration = getConfigurationObject(configurationAdmin, pid);
Configuration configuration = ServiceUtil.withService(
ConfigurationAdmin.class,
context,
ca -> getConfigurationObject(ca, pid),
null);
Comment thread
smiakchilo marked this conversation as resolved.
if (configuration == null) {
return EMPTY;
}
Expand All @@ -312,25 +311,31 @@ private static ConfigDefinition from(String pid, BundleContext context) {
&& !StringUtils.equals(configuration.getPid(), configuration.getFactoryPid());
String metatypePid = isFactoryInstance ? configuration.getFactoryPid() : configuration.getPid();

for (Bundle bundle : context.getBundles()) {
MetaTypeInformation metaTypeInformation = metaTypeService.getMetaTypeInformation(bundle);
if (metaTypeInformation == null) {
continue;
}
ObjectClassDefinition ocd;
try {
ocd = Objects.requireNonNull(metaTypeInformation.getObjectClassDefinition(metatypePid, null));
} catch (IllegalArgumentException | NullPointerException e) {
// Not an error: this actually happens if the configuration is not present in the current bundle
continue;
}
ConfigDefinition result = from(configuration, ocd);
result.isFactory = ArrayUtils.contains(metaTypeInformation.getFactoryPids(), pid);
result.pid = pid;
result.factoryPid = configuration.getFactoryPid();
return result;
}
return EMPTY;
return ServiceUtil.withService(
MetaTypeService.class,
context,
mts -> {
for (Bundle bundle : context.getBundles()) {
MetaTypeInformation metaTypeInformation = mts.getMetaTypeInformation(bundle);
if (metaTypeInformation == null) {
continue;
}
ObjectClassDefinition ocd;
try {
ocd = Objects.requireNonNull(metaTypeInformation.getObjectClassDefinition(metatypePid, null));
} catch (IllegalArgumentException | NullPointerException e) {
// Not an error: this actually happens if the configuration is not present in the current bundle
continue;
}
ConfigDefinition result = from(configuration, ocd);
result.isFactory = ArrayUtils.contains(metaTypeInformation.getFactoryPids(), pid);
result.pid = pid;
result.factoryPid = configuration.getFactoryPid();
return result;
}
return EMPTY;
},
EMPTY);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@

import com.exadel.aem.toolkit.core.CoreConstants;
import com.exadel.aem.toolkit.core.configurator.ConfiguratorConstants;
import com.exadel.aem.toolkit.core.utils.ResolverUtil;
import com.exadel.aem.toolkit.core.utils.ValueMapUtil;

/**
Expand Down Expand Up @@ -96,7 +97,7 @@ public class ConfigChangeListener implements ResourceChangeListener, ExternalRes
@Activate
void activate(BundleContext context, ConfigChangeListenerConfiguration config) {
LOG.info("Configuration change listener is {}", config.enabled() ? "enabled" : "disabled");
try (ResourceResolver resolver = newResolver()) {
try (ResourceResolver resolver = ResolverUtil.newResolver(resourceResolverFactory)) {
if (ArrayUtils.isNotEmpty(config.cleanUp())) {
activateWithCleanUp(resolver, config.cleanUp());
}
Expand Down Expand Up @@ -225,7 +226,7 @@ public void onChange(List<ResourceChange> list) {
return;
}
asyncExecutor.submit(() -> {
try (ResourceResolver resolver = newResolver()) {
try (ResourceResolver resolver = ResolverUtil.newResolver(resourceResolverFactory)) {
for (String path : configsToUpdate) {
Resource resource = resolver.getResource(path);
if (resource == null) {
Expand All @@ -247,21 +248,6 @@ public void onChange(List<ResourceChange> list) {
});
}

/* --------------------
Sling instance logic
-------------------- */

/**
* Creates a new {@link ResourceResolver} instance for accessing repository resources
* @return New instance of {@code ResourceResolver}
* @throws LoginException If the resolver cannot be created
*/
private ResourceResolver newResolver() throws LoginException {
return resourceResolverFactory.getServiceResourceResolver(
Collections.singletonMap(ResourceResolverFactory.SUBSERVICE, "eak-service")
);
}

/* -------------------
Configuration logic
------------------- */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@

package com.exadel.aem.toolkit.core.configurator.servlets.form;

import javax.annotation.Nonnull;
import javax.servlet.Servlet;

import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.servlets.HttpConstants;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
import org.jetbrains.annotations.NotNull;
import org.osgi.service.component.annotations.Component;

import com.exadel.aem.toolkit.core.configurator.models.internal.ConfigDefinition;
Expand All @@ -45,7 +45,7 @@ public class ConfigDataSource extends SlingSafeMethodsServlet {
* @param response The HTTP response
*/
@Override
protected void doGet(@NotNull SlingHttpServletRequest request, @NotNull SlingHttpServletResponse response) {
protected void doGet(@Nonnull SlingHttpServletRequest request, @Nonnull SlingHttpServletResponse response) {
ConfigDefinition config = ConfigDefinition.from(request);
if (config == null || !config.isValid()) {
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import java.io.IOException;
import java.util.Objects;
import javax.annotation.Nonnull;
import javax.jcr.Session;
import javax.servlet.Servlet;

Expand All @@ -25,7 +26,6 @@
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.servlets.HttpConstants;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.jetbrains.annotations.NotNull;
import org.osgi.framework.BundleContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
Expand Down Expand Up @@ -100,8 +100,8 @@ private void deactivate() {
*/
@Override
protected void doPost(
@NotNull SlingHttpServletRequest request,
@NotNull SlingHttpServletResponse response) throws IOException {
@Nonnull SlingHttpServletRequest request,
@Nonnull SlingHttpServletResponse response) throws IOException {

if (!configChangeListener.isEnabled()) {
sendError(response, SlingHttpServletResponse.SC_SERVICE_UNAVAILABLE, ConfigAccess.DISABLED.getError());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* Licensed 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 com.exadel.aem.toolkit.core.relay.models;

import java.util.Objects;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

/**
* Represents a change announcement entry defining a JCR path or XPath to report as changed when the relay is enabled or
* disabled.
* <p><u>Note</u>: This class is not a part of the public API and is subject to change. Do not use it in your own
* code</p>
*/
public class ChangeSample {
private final String path;
private final int limit;
private final String user;

/**
* Creates a new {@code ChangeSample} with the provided path, limit and user values
* @param path JCR path or XPath expression to report as changed
* @param limit Optional limit of resources to report as changed under the provided path
* @param user Optional user identifier to use for reporting changes
*/
@JsonCreator
ChangeSample(
@JsonProperty("path") String path,
@JsonProperty("limit") int limit,
@JsonProperty("user") String user) {
this.path = path;
this.limit = limit;
this.user = user;
}

/**
* Gets the JCR path or XPath expression defined in this announcement
* @return String value
*/
public String getPath() {
return path;
}

/**
* Gets the optional limit of resources to report as changed under the provided path
* @return Integer limit value
*/
public int getLimit() {
return limit;
}

/**
* Gets the optional user identifier to use for reporting changes
* @return A nullable user identifier string
*/
public String getUser() {
return user;
}

/**
* {@inheritDoc}
* <p>The equality check is based solely on the {@code path} property since we do not want to report the
* same path as changed multiple times</p>
*/
@Override
public final boolean equals(Object other) {
if (!(other instanceof ChangeSample)) {
return false;
}
ChangeSample announcement = (ChangeSample) other;
return Objects.equals(path, announcement.path);
}

/**
* {@inheritDoc}
* <p>The hash code is based solely on the {@code path} property since we do not want to report the same path as
* changed multiple times</p>
*/
@Override
public int hashCode() {
return Objects.hashCode(path);
Comment thread
smiakchilo marked this conversation as resolved.
}
}
Loading
Loading