| /* |
| * 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 SF 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.hc.core.impl.util; |
| |
| import static org.apache.felix.hc.api.execution.HealthCheckSelector.empty; |
| |
| import org.apache.felix.hc.api.HealthCheck; |
| import org.apache.felix.hc.api.execution.HealthCheckSelector; |
| import org.osgi.framework.BundleContext; |
| import org.osgi.framework.InvalidSyntaxException; |
| import org.osgi.framework.ServiceReference; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| /** Select from available {@link HealthCheck} services. Once this filter object and the returned health check services are no longer be used |
| * {@link #dispose()} should be called, to free the service references. |
| * |
| * This class is not thread safe and instances shouldn't be used concurrently from different threads. */ |
| public class HealthCheckFilter { |
| |
| private final Logger log = LoggerFactory.getLogger(getClass()); |
| |
| // object class (supporting current interface and legacy) |
| public static final String HC_FILTER_OBJECT_CLASS = "(|(objectClass="+HealthCheck.class.getName()+")(objectClass=org.apache.sling.hc.api.HealthCheck))"; |
| public static final String OMIT_PREFIX = "-"; |
| |
| private final BundleContext bundleContext; |
| |
| /** Create a new filter object */ |
| public HealthCheckFilter(final BundleContext bc) { |
| bundleContext = bc; |
| } |
| |
| public ServiceReference<HealthCheck>[] getHealthCheckServiceReferences(final HealthCheckSelector selector) { |
| return getHealthCheckServiceReferences(selector, false); |
| } |
| |
| public ServiceReference<HealthCheck>[] getHealthCheckServiceReferences(final HealthCheckSelector selector, boolean combineTagsWithOr) { |
| final CharSequence filterBuilder = selector != null ? getServiceFilter(selector, combineTagsWithOr) |
| : getServiceFilter(empty(), combineTagsWithOr); |
| |
| log.trace("OSGi service filter in getHealthCheckServiceReferences(): {}", filterBuilder); |
| |
| try { |
| final String filterString = filterBuilder.length() == 0 ? null : filterBuilder.toString(); |
| bundleContext.createFilter(filterString); // check syntax early |
| final ServiceReference[] refs = bundleContext.getServiceReferences((String) null, filterString); |
| if (refs == null) { |
| log.debug("Found no HealthCheck services for filter: {}", filterString); |
| return new ServiceReference[0]; |
| } else { |
| log.debug("Found {} HealthCheck services for filter: {}", refs.length, filterString); |
| } |
| return refs; |
| } catch (final InvalidSyntaxException ise) { |
| // this should not happen, but we fail gracefully |
| log.error("Invalid OSGi filter syntax in '" + filterBuilder + "'", ise); |
| return new ServiceReference[0]; |
| } |
| } |
| |
| |
| CharSequence getServiceFilter(HealthCheckSelector selector, boolean combineTagsWithOr) { |
| // Build service filter |
| final StringBuilder filterBuilder = new StringBuilder(); |
| filterBuilder.append("(&"); |
| filterBuilder.append(HC_FILTER_OBJECT_CLASS); |
| |
| final int prefixLen = HealthCheckFilter.OMIT_PREFIX.length(); |
| final StringBuilder filterBuilderForOrOperator = new StringBuilder(); // or filters |
| final StringBuilder tagsBuilder = new StringBuilder(); |
| int tagsAndClauses = 0; |
| if (selector.tags() != null) { |
| for (String tag : selector.tags()) { |
| tag = tag.trim(); |
| if (tag.length() == 0) { |
| continue; |
| } |
| if (tag.startsWith(HealthCheckFilter.OMIT_PREFIX)) { |
| // ommit tags always have to be added as and-clause |
| filterBuilder.append("(!(").append(HealthCheck.TAGS).append("=").append(tag.substring(prefixLen)).append("))"); |
| } else { |
| // add regular tags in the list either to outer and-clause or inner or-clause |
| if (combineTagsWithOr) { |
| filterBuilderForOrOperator.append("(").append(HealthCheck.TAGS).append("=").append(tag).append(")"); |
| } else { |
| tagsBuilder.append("(").append(HealthCheck.TAGS).append("=").append(tag).append(")"); |
| tagsAndClauses++; |
| } |
| } |
| } |
| } |
| boolean addedNameToOrBuilder = false; |
| if (selector.names() != null) { |
| for (String name : selector.names()) { |
| name = name.trim(); |
| if (name.length() == 0) { |
| continue; |
| } |
| if (name.startsWith(HealthCheckFilter.OMIT_PREFIX)) { |
| // ommit tags always have to be added as and-clause |
| filterBuilder.append("(!(").append(HealthCheck.NAME).append("=").append(escapeOsgiFilterLiteral(name.substring(prefixLen))).append("))"); |
| } else { |
| // names are always ORd |
| filterBuilderForOrOperator.append("(").append(HealthCheck.NAME).append("=").append(escapeOsgiFilterLiteral(name)).append(")"); |
| addedNameToOrBuilder = true; |
| } |
| } |
| } |
| if (addedNameToOrBuilder) { |
| if (tagsAndClauses > 1) { |
| filterBuilderForOrOperator.append("(&").append(tagsBuilder).append(")"); |
| } else { |
| filterBuilderForOrOperator.append(tagsBuilder); |
| } |
| } else { |
| filterBuilder.append(tagsBuilder); |
| } |
| // add "or" clause if we have accumulated any |
| if (filterBuilderForOrOperator.length() > 0) { |
| filterBuilder.append("(|").append(filterBuilderForOrOperator).append(")"); |
| } |
| filterBuilder.append(")"); |
| return filterBuilder; |
| } |
| |
| private Object escapeOsgiFilterLiteral(String name) { |
| return name.replace("*", "\\*").replace("(", "\\(").replace(")", "\\)"); |
| } |
| } |