/*
* Copyright (C) 2006-2016 DLR, Germany
*
* All rights reserved
*
* http://www.rcenvironment.de/
*/
package de.rcenvironment.core.log.internal;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.osgi.service.log.LogEntry;
import org.osgi.service.log.LogListener;
import org.osgi.service.log.LogReaderService;
import org.osgi.service.log.LogService;
import de.rcenvironment.core.log.RemotableLogReaderService;
import de.rcenvironment.core.log.SerializableLogEntry;
import de.rcenvironment.core.log.SerializableLogListener;
import de.rcenvironment.core.toolkitbridge.transitional.ConcurrencyUtils;
import de.rcenvironment.core.toolkitbridge.transitional.StatsCounter;
import de.rcenvironment.core.utils.common.rpc.RemoteOperationException;
import de.rcenvironment.core.utils.common.security.AllowRemoteAccess;
import de.rcenvironment.toolkit.modules.concurrency.api.AsyncCallbackExceptionPolicy;
import de.rcenvironment.toolkit.modules.concurrency.api.AsyncOrderedExecutionQueue;
import de.rcenvironment.toolkit.modules.concurrency.api.TaskDescription;
/**
* Implementation of {@link RemotableLogReaderService}.
*
* @author Doreen Seider
* @author Mark Geiger
* @author Robert Mischke
*/
public class RemotableLogReaderServiceImpl implements RemotableLogReaderService {
/**
* Implementation of the OSGi {@link LogListener} interface that asynchronously forwards each event to a given
* {@link SerializableLogListener}.
*
* @author Robert Mischke
*/
private final class SingleReceiverOsgiLogForwarder implements LogListener {
private static final String ASYNC_TASK_DESCRIPTION = "Forward log event to listener";
private final SerializableLogListener externalListener;
// For each event that should be forwarded to the listener, a runnable is enqueued in this queue.
// TODO review exception policy; which is better?
private final AsyncOrderedExecutionQueue orderedExecutionQueue = ConcurrencyUtils.getFactory().createAsyncOrderedExecutionQueue(
AsyncCallbackExceptionPolicy.LOG_AND_CANCEL_LISTENER);
private SingleReceiverOsgiLogForwarder(SerializableLogListener externalListener) {
this.externalListener = externalListener;
}
@Override
public void logged(final LogEntry entry) {
if (entry.getLevel() == LogService.LOG_DEBUG) {
return;
}
orderedExecutionQueue.enqueue(new Runnable() {
@Override
@TaskDescription(ASYNC_TASK_DESCRIPTION)
public void run() {
try {
String exceptionString = "";
if (entry.getException() != null) {
exceptionString = entry.getException().toString();
}
externalListener.logged(new SerializableLogEntry(
entry.getBundle().getSymbolicName(),
entry.getLevel(),
entry.getMessage().replaceAll("\n", SerializableLogEntry.RCE_SEPARATOR),
entry.getTime(),
exceptionString));
} catch (RemoteOperationException e) {
final Log localLog = LogFactory.getLog(getClass());
localLog.debug("Error while forwarding log event to listener "
+ "(delivery of log events to this receiver will be cancelled): " + e.toString());
orderedExecutionQueue.cancelAsync();
}
// the @TaskDescription is not forwarded by AsyncOrderedExecutionQueue, so count a stats event for monitoring - misc_ro
StatsCounter.count(AsyncOrderedExecutionQueue.STATS_COUNTER_SHARED_CATEGORY_NAME, ASYNC_TASK_DESCRIPTION);
}
});
}
public void shutdown() {
orderedExecutionQueue.cancelAsync();
}
}
private static final long serialVersionUID = -7406557933348370062L;
private LogReaderService osgiLogReaderService;
private Map<SerializableLogListener, SingleReceiverOsgiLogForwarder> osgiLogForwardersByExternalListener =
new HashMap<SerializableLogListener, SingleReceiverOsgiLogForwarder>();
protected void bindLogReaderService(LogReaderService newLogReaderService) {
osgiLogReaderService = newLogReaderService;
}
@Override
@AllowRemoteAccess
public void addLogListener(final SerializableLogListener externalListener) {
SingleReceiverOsgiLogForwarder osgiLogForwarder = new SingleReceiverOsgiLogForwarder(externalListener);
synchronized (osgiLogForwardersByExternalListener) {
osgiLogForwardersByExternalListener.put(externalListener, osgiLogForwarder);
}
osgiLogReaderService.addLogListener(osgiLogForwarder);
}
@Override
@AllowRemoteAccess
public void removeLogListener(SerializableLogListener listener) {
final SingleReceiverOsgiLogForwarder osgiLogForwarder;
synchronized (osgiLogForwardersByExternalListener) {
osgiLogForwarder = osgiLogForwardersByExternalListener.remove(listener);
}
if (osgiLogForwarder != null) {
osgiLogForwarder.shutdown();
// note: no need to cancel asynchronous listener events (?)
osgiLogReaderService.removeLogListener(osgiLogForwarder);
} else {
LogFactory.getLog(getClass()).warn("Found no registered log forwarder for a remote listener");
}
}
@Override
@AllowRemoteAccess
public List<SerializableLogEntry> getLog() {
List<SerializableLogEntry> entries = new LinkedList<SerializableLogEntry>();
@SuppressWarnings("unchecked") Enumeration<LogEntry> retrievedEntries = osgiLogReaderService.getLog();
while (retrievedEntries.hasMoreElements()) {
LogEntry entry = retrievedEntries.nextElement();
if (entry.getLevel() != LogService.LOG_DEBUG) {
String exceptionString = "";
if (entry.getException() != null) {
exceptionString = entry.getException().toString();
}
entries.add(entries.size(), new SerializableLogEntry(
entry.getBundle().getSymbolicName(),
entry.getLevel(),
entry.getMessage().replaceAll("\n", SerializableLogEntry.RCE_SEPARATOR),
entry.getTime(),
exceptionString));
}
}
return entries;
}
}