blob: 3471df980fbf2aaa6f51b5b04d3e1989c5b5bce1 [file] [log] [blame]
/*
* 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.felix.systemready.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import org.apache.felix.systemready.CheckStatus;
import org.apache.felix.systemready.CheckStatus.State;
import org.apache.felix.systemready.StateType;
import org.apache.felix.systemready.SystemReady;
import org.apache.felix.systemready.SystemReadyCheck;
import org.apache.felix.systemready.SystemReadyMonitor;
import org.apache.felix.systemready.SystemStatus;
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.ReferencePolicy;
import org.osgi.service.component.annotations.ReferencePolicyOption;
import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.Designate;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Component(
name = SystemReadyMonitor.PID
)
@Designate(ocd = SystemReadyMonitorImpl.Config.class)
public class SystemReadyMonitorImpl implements SystemReadyMonitor {
@ObjectClassDefinition(
name = "System Ready Monitor",
description = "System ready monitor for System Ready Checks"
)
public @interface Config {
@AttributeDefinition(name = "Poll interval",
description = "Number of milliseconds between subsequents updates of all the checks")
long poll_interval() default 5000;
}
private final Logger log = LoggerFactory.getLogger(getClass());
@Reference(policyOption = ReferencePolicyOption.GREEDY, policy = ReferencePolicy.DYNAMIC)
private volatile List<SystemReadyCheck> checks;
private BundleContext context;
private ServiceRegistration<SystemReady> sreg;
private ScheduledExecutorService executor;
private AtomicReference<Collection<CheckStatus>> curStates;
public SystemReadyMonitorImpl() {
CheckStatus checkStatus = new CheckStatus("dummy", StateType.READY, State.YELLOW, "");
this.curStates = new AtomicReference<>(Collections.singleton(checkStatus));
}
@Activate
public void activate(BundleContext context, final Config config) {
this.context = context;
this.executor = Executors.newSingleThreadScheduledExecutor();
this.executor.scheduleAtFixedRate(this::check, 0, config.poll_interval(), TimeUnit.MILLISECONDS);
log.info("Activated. Running checks every {} ms.", config.poll_interval());
}
@Deactivate
public void deactivate() {
executor.shutdown();
}
@Override
/**
* Returns a map of the statuses of all the checks
*/
public SystemStatus getStatus(StateType stateType) {
Collection<CheckStatus> filtered = stateType == StateType.READY ? curStates.get() :
curStates.get().stream()
.filter(status -> status.getType() == StateType.ALIVE).collect(Collectors.toList());
return new SystemStatus(filtered);
}
private void check() {
try {
CheckStatus.State prevState = getStatus(StateType.READY).getState();
List<SystemReadyCheck> currentChecks = new ArrayList<>(checks);
List<String> checkNames = currentChecks.stream().map(check -> check.getName()).collect(Collectors.toList());
log.debug("Running system checks {}", checkNames);
List<CheckStatus> statuses = evaluateAllChecks(currentChecks);
this.curStates.set(statuses);
State currState = getStatus(StateType.READY).getState();
if (currState != prevState) {
manageMarkerService(currState);
}
log.debug("Checks finished");
} catch (Exception e) {
log.warn("Exception when running checks", e);
}
}
private List<CheckStatus> evaluateAllChecks(List<SystemReadyCheck> currentChecks) {
return currentChecks.stream()
.map(SystemReadyMonitorImpl::getStatus)
.sorted(Comparator.comparing(CheckStatus::getCheckName))
.collect(Collectors.toList());
}
private void manageMarkerService(CheckStatus.State currState) {
if (currState == CheckStatus.State.GREEN) {
SystemReady readyService = new SystemReady() {
};
sreg = context.registerService(SystemReady.class, readyService, null);
} else if (sreg != null) {
sreg.unregister();
}
}
private static final CheckStatus getStatus(SystemReadyCheck c) {
try {
return c.getStatus();
} catch (Throwable e) {
return new CheckStatus(c.getName(), StateType.READY, CheckStatus.State.RED, e.getMessage());
}
}
}