blob: 8cf9a5cfa9080cc75ab527d5d6f3cb0405a98326 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.equinox.internal.log.stream;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.ReentrantLock;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.log.LogEntry;
import org.osgi.service.log.LogListener;
import org.osgi.service.log.LogReaderService;
import org.osgi.service.log.stream.LogStreamProvider;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
/* LogStreamManager is used to start and stop the bundle and keeps the track of the logs using the
* ServiceTrackerCustomizer<LogReaderService, AtomicReference<LogReaderService>> which listens to
* the incoming logs using the LogListener. It is also responsible to provide service tracker
* and each log entry to the LogStreamProviderFactory.
*
*/
public class LogStreamManager implements BundleActivator, ServiceTrackerCustomizer<LogReaderService, AtomicReference<LogReaderService>>, LogListener {
private ServiceRegistration<LogStreamProvider> logStreamServiceRegistration;
private LogStreamProviderFactory logStreamProviderFactory;
private ServiceTracker<LogReaderService, AtomicReference<LogReaderService>> logReaderService;
BundleContext context;
ReentrantLock eventProducerLock = new ReentrantLock();
/*
* (non-Javadoc)
* @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
*/
@Override
public void start(BundleContext bc) throws Exception {
this.context = bc;
logReaderService = new ServiceTracker<>(context, LogReaderService.class, this);
logReaderService.open();
logStreamProviderFactory = new LogStreamProviderFactory(logReaderService);
logStreamServiceRegistration = context.registerService(LogStreamProvider.class, logStreamProviderFactory, null);
}
/*
* (non-Javadoc)
* @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
*/
@Override
public void stop(BundleContext bundleContext) throws Exception {
logReaderService.close();
logStreamServiceRegistration.unregister();
logStreamServiceRegistration = null;
}
/*
* (non-Javadoc)
* @see org.osgi.util.tracker.ServiceTrackerCustomizer#addingService(org.osgi.framework.ServiceReference)
*/
@Override
public AtomicReference<LogReaderService> addingService(ServiceReference<LogReaderService> reference) {
AtomicReference<LogReaderService> tracked = new AtomicReference<>();
modifiedService(reference, tracked);
return tracked;
}
/*
* (non-Javadoc)
* @see org.osgi.util.tracker.ServiceTrackerCustomizer#modifiedService(org.osgi.framework.ServiceReference, java.lang.Object)
*/
@Override
public void modifiedService(ServiceReference<LogReaderService> modifiedServiceRef, AtomicReference<LogReaderService> modifiedTracked) {
eventProducerLock.lock();
try {
// Check if the currently used reader service is lower ranked that the modified serviceRef
ServiceReference<LogReaderService> currentServiceRef = logReaderService.getServiceReference();
if (currentServiceRef == null || modifiedServiceRef.compareTo(currentServiceRef) > 0) {
// The modified service reference is higher ranked than the currently used one;
// Use the modified service reference instead.
LogReaderService readerService = context.getService(modifiedServiceRef);
if (readerService != null) {
if (modifiedTracked.get() == null) {
// update our tracked object for the reference with the real service
modifiedTracked.set(readerService);
}
// remove our listener from the currently used service
if (currentServiceRef != null) {
AtomicReference<LogReaderService> currentTracked = logReaderService.getService(currentServiceRef);
if (currentTracked != null) {
LogReaderService currentLogReader = currentTracked.get();
if (currentLogReader != null) {
// we were really using this service;
// remove our listener and unget the service
currentLogReader.removeLogListener(this);
context.ungetService(currentServiceRef);
// finally null out our tracked reference
currentTracked.set(null);
}
}
}
readerService.addLogListener(this);
}
}
} finally {
eventProducerLock.unlock();
}
}
/*
* (non-Javadoc)
* @see org.osgi.util.tracker.ServiceTrackerCustomizer#removedService(org.osgi.framework.ServiceReference, java.lang.Object)
*/
@Override
public void removedService(ServiceReference<LogReaderService> removedRef, AtomicReference<LogReaderService> removedTracked) {
eventProducerLock.lock();
try {
LogReaderService removedLogReader = removedTracked.get();
if (removedLogReader != null) {
// remove the listener
removedLogReader.removeLogListener(this);
context.ungetService(removedRef);
removedTracked.set(null);
}
ServiceReference<LogReaderService> currentRef = logReaderService.getServiceReference();
if (currentRef != null) {
AtomicReference<LogReaderService> currentTracked = logReaderService.getService(currentRef);
if (currentTracked != null) {
LogReaderService currentLogReader = currentTracked.get();
if (currentLogReader == null) {
currentLogReader = context.getService(currentRef);
currentTracked.set(currentLogReader);
}
if (currentLogReader != null) {
currentLogReader.addLogListener(this);
}
}
}
} finally {
eventProducerLock.unlock();
}
}
/* It is used to post each log entry to the LogStreamProviderFactory
* (non-Javadoc)
* @see org.osgi.service.log.LogListener#logged(org.osgi.service.log.LogEntry)
*/
@Override
public void logged(LogEntry entry) {
logStreamProviderFactory.postLogEntry(entry);
}
}