Skip to content

Commit

Permalink
#618 Allow startup hook to run asynchronously for mutable content
Browse files Browse the repository at this point in the history
  • Loading branch information
ghenzler committed Nov 16, 2021
1 parent 64f9411 commit 1c7d139
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ public void installConfigurationFiles(PersistableInstallationLogger installLog,
sw.stop();
long executionTime = sw.getTime();
installLog.setExecutionTime(executionTime);
installLog.addVerboseMessage(LOG, "Finished at bundle start level " + RuntimeHelper.getCurrentStartLevel());
installLog.addMessage(LOG, "Successfully applied AC Tool configuration in " + msHumanReadable(executionTime));
} catch (Exception e) {
installLog.addError("Could not process yaml files", e); // ensure exception is added to installLog before it's persisted in log in finally clause
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.List;

import javax.jcr.Node;
Expand All @@ -20,10 +22,15 @@

import org.apache.jackrabbit.JcrConstants;
import org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants;
import org.apache.sling.event.jobs.Job;
import org.apache.sling.event.jobs.JobManager;
import org.apache.sling.event.jobs.consumer.JobConsumer;
import org.apache.sling.jcr.api.SlingRepository;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferencePolicyOption;
import org.osgi.service.metatype.annotations.AttributeDefinition;
Expand All @@ -40,6 +47,8 @@
@Designate(ocd=AcToolStartupHookServiceImpl.Config.class)
public class AcToolStartupHookServiceImpl {
private static final Logger LOG = LoggerFactory.getLogger(AcToolStartupHookServiceImpl.class);

private static final String JOB_TOPIC_ACTOOL = "biz/netcentric/actool/apply";

@ObjectClassDefinition(name = "AC Tool Startup Hook", description = "Applies AC Tool config automatically upon startup (depending on configuration/runtime)")
public static @interface Config {
Expand All @@ -49,13 +58,21 @@ public enum StartupHookActivation {

@AttributeDefinition(name = "Activation Mode", description = "Apply on startup - CLOUD_ONLY autodetects the cloud (by missing OSGi installer bundle) and only runs on startup if deployed in the cloud. ALWAYS can be useful for local testing. NEVER disables AC Tool runs on startup entirely.")
StartupHookActivation activationMode() default StartupHookActivation.CLOUD_ONLY;

@AttributeDefinition(name = "Async for Mutable Content", description = "Will execute on the mutable content asynchronously using a Sling Job")
boolean runAsyncForMutableConent() default false;
}

@Reference(policyOption = ReferencePolicyOption.GREEDY)
private AcInstallationService acInstallationService;

@Reference(policyOption = ReferencePolicyOption.GREEDY)
private SlingRepository repository;

@Reference(policyOption = ReferencePolicyOption.GREEDY)
private JobManager jobManager;

private ServiceRegistration<JobConsumer> jobHandlerRegistration;

private boolean isCompositeNodeStore;

Expand All @@ -64,36 +81,76 @@ public void activate(BundleContext bundleContext, Config config) {

boolean isCloudReady = RuntimeHelper.isCloudReadyInstance();
Config.StartupHookActivation activationMode = config.activationMode();
LOG.info("AcTool Startup Hook (start level: {} isCloudReady: {} activationMode: {})",
boolean runAsyncForMutableConent = config.runAsyncForMutableConent();
LOG.info("AcTool Startup Hook (start level: {} isCloudReady: {} activationMode: {} runAsyncForMutableConent: {})",
RuntimeHelper.getCurrentStartLevel(bundleContext),
isCloudReady,
activationMode);
activationMode,
runAsyncForMutableConent);

boolean applyOnStartup = (activationMode == Config.StartupHookActivation.ALWAYS)
|| (isCloudReady && activationMode == Config.StartupHookActivation.CLOUD_ONLY);

if(applyOnStartup) {

try {

List<String> relevantPathsForInstallation = getRelevantPathsForInstallation();
LOG.info("Running AcTool with "
+ (relevantPathsForInstallation.isEmpty() ? "all paths" : "paths " + relevantPathsForInstallation) + "...");
acInstallationService.apply(null, relevantPathsForInstallation.toArray(new String[relevantPathsForInstallation.size()]),
true);
LOG.info("AC Tool Startup Hook done. (start level " + RuntimeHelper.getCurrentStartLevel(bundleContext) + ")");

copyAcHistoryToOrFromApps(isCloudReady);

} catch (RepositoryException e) {
LOG.error("Exception while triggering AC Tool on startup: " + e, e);
if (runAsyncForMutableConent && isCompositeNodeStore) {
runAcToolAsync(bundleContext, isCloudReady);
} else {
runAcTool(bundleContext, isCloudReady);
}

} else {
LOG.debug("Skipping AcTool Startup Hook: activationMode: {} isCloudReady: {}", activationMode, isCloudReady);
}

}

@Deactivate
public void deactivate() {
if (jobHandlerRegistration != null) {
jobHandlerRegistration.unregister();
}
}

private void runAcTool(BundleContext bundleContext, boolean isCloudReady) {
try {

List<String> relevantPathsForInstallation = getRelevantPathsForInstallation();
LOG.info("Running AcTool with "
+ (relevantPathsForInstallation.isEmpty() ? "all paths" : "paths " + relevantPathsForInstallation) + "...");
acInstallationService.apply(null, relevantPathsForInstallation.toArray(new String[relevantPathsForInstallation.size()]),
true);
LOG.info("AC Tool Startup Hook done. (start level " + RuntimeHelper.getCurrentStartLevel(bundleContext) + ")");

copyAcHistoryToOrFromApps(isCloudReady);

} catch (RepositoryException e) {
LOG.error("Exception while triggering AC Tool on startup: " + e, e);
}
}

private void runAcToolAsync(final BundleContext bundleContext, final boolean isCloudReady) {

final AcToolStartupHookServiceImpl startupHook = this;
JobConsumer acToolJobConsumer = new JobConsumer() {

@Override
public JobResult process(Job job) {
startupHook.runAcTool(bundleContext, isCloudReady);
return JobResult.OK;
}
};

Dictionary<String, String> serviceProps = new Hashtable<>();
serviceProps.put(JobConsumer.PROPERTY_TOPICS, JOB_TOPIC_ACTOOL);

// register handler
jobHandlerRegistration = bundleContext.registerService(JobConsumer.class, acToolJobConsumer, serviceProps);

LOG.info("Running AcTool asynchronously...");
jobManager.createJob(JOB_TOPIC_ACTOOL).add();
}

private List<String> getRelevantPathsForInstallation() throws RepositoryException {
Session session = null;
try {
Expand Down

0 comments on commit 1c7d139

Please sign in to comment.