/* * 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.sling.extensions.logback.internal; import java.io.StringReader; import java.util.Collection; import java.util.Collections; import java.util.Map; import java.util.concurrent.ConcurrentSkipListMap; import ch.qos.logback.classic.LoggerContext; import org.apache.sling.extensions.logback.ConfigProvider; import org.apache.sling.extensions.logback.internal.util.XmlUtil; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.Filter; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; import org.osgi.util.tracker.ServiceTracker; import org.xml.sax.InputSource; public class ConfigSourceTracker extends ServiceTracker implements LogbackResetListener{ /** * Service property name indicating that String object is a Logback config * fragment */ private static final String PROP_LOGBACK_CONFIG = "logbackConfig"; /** * Reverse sorted map of ConfigSource based on ranking of ServiceReferences */ private final Map<ServiceReference,ConfigSourceInfo> inputSources = new ConcurrentSkipListMap<ServiceReference, ConfigSourceInfo>(Collections.reverseOrder()); private final LogbackManager logbackManager; public ConfigSourceTracker(BundleContext context, LogbackManager logbackManager) throws InvalidSyntaxException { super(context, createFilter(), null); this.logbackManager = logbackManager; super.open(); } public Collection<ConfigSourceInfo> getSources(){ return inputSources.values(); } public void close(){ inputSources.clear(); } //~--------------------------------- ServiceTracker @Override public Object addingService(ServiceReference reference) { Object o = super.addingService(reference); inputSources.put(reference,new ConfigSourceInfo(reference,getConfig(o))); logbackManager.configChanged(); return o; } @Override public void modifiedService(ServiceReference reference, Object service) { super.modifiedService(reference, service); //A ConfigProvider can modify its service registration properties //to indicate that config has changed and a reload is required logbackManager.configChanged(); } @Override public void removedService(ServiceReference reference, Object service) { if(inputSources.remove(reference) != null){ logbackManager.configChanged(); } } //~----------------------------------- LogbackResetListener public void onReset(LoggerContext context) { //export the tracker instance. It would later be used in OSGiInternalAction context.putObject(ConfigSourceTracker.class.getName(),this); } //~----------------------------------ConfigSourceInfo public static class ConfigSourceInfo { private final ServiceReference reference; private final ConfigProvider configProvider; public ConfigSourceInfo(ServiceReference reference, ConfigProvider configProvider) { this.reference = reference; this.configProvider = configProvider; } public ConfigProvider getConfigProvider() { return configProvider; } public ServiceReference getReference() { return reference; } public String getSourceAsString(){ return XmlUtil.prettyPrint(getConfigProvider().getConfigSource()); } public String getSourceAsEscapedString(){ return XmlUtil.escapeXml(getSourceAsString()); } public String toString(){ return String.format("Service ID %s",reference.getProperty(Constants.SERVICE_ID)); } } private static ConfigProvider getConfig(Object o){ //If string then wrap it in StringSourceProvider if(o instanceof String){ return new StringSourceProvider((String) o); } return (ConfigProvider) o; } private static Filter createFilter() throws InvalidSyntaxException { //Look for either ConfigProvider or String's with property logbackConfig set String filter = String.format("(|(objectClass=%s)(&(objectClass=java.lang.String)(%s=*)))", ConfigProvider.class.getName(),PROP_LOGBACK_CONFIG); return FrameworkUtil.createFilter(filter); } private static class StringSourceProvider implements ConfigProvider { private final String source; private StringSourceProvider(String source) { this.source = source; } public InputSource getConfigSource() { return new InputSource(new StringReader(source)); } } }