📄 logreaderservicefactory.java
字号:
/* * Copyright (c) 2003, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */package org.knopflerfish.bundle.log;import java.security.AccessController;import java.security.PrivilegedAction;import java.util.Enumeration;import java.util.Hashtable;import java.util.NoSuchElementException;import org.osgi.framework.Bundle;import org.osgi.framework.BundleContext;import org.osgi.framework.ServiceFactory;import org.osgi.framework.ServiceRegistration;import org.osgi.service.log.LogEntry;/** * * A LogReaderServiceFactory implements the log functionality. * * I.e., it * keeps log entries in memory and initiates callbacks to * LogListeners. It * does not keep track of subscribers, this is * delegated to * LogReaderServiceImpl. * * It uses an instance of FileLog to write log entryes * to file if * that configuration option has been enabled. It also prints log * * entries on System.out if desired. * * * * @author Gatespace AB * * @version $Revision: 1.3 $ * */public final class LogReaderServiceFactory implements ServiceFactory { /** Handle to the framework. */ BundleContext bc; /** * A FileLog that writes log entries to file. * (Accessed from the * LogConfigCommandGroup). */ FileLog fileLog; /** * The logReaderServicies table maps LogReaderServiceImpl object to * the * bundle that owns the instance. * * The key is an instance of * LogReaderServiceImpl and the value the * Bundle object for the bundle * that uses the service. */ Hashtable logReaderServicies = new Hashtable(); LogConfigImpl configuration; /** * * The constructor fetches the destination(s) of the log entries * from * the system properties. */ public LogReaderServiceFactory(BundleContext bc, LogConfigImpl lc) { this.bc = bc; configuration = lc; history = new LogEntry[configuration.getMemorySize()]; historyInsertionPoint = 0; try { if (configuration.getFile()) { fileLog = new FileLog(bc, configuration); } } catch (Exception e) { } configuration.init(this); } /** * * The stop method is called by the bundle activator when the log * bundle * is stoped. If a <code>fileLog</code> is active terminate * it. */ void stop() { if (fileLog != null) { synchronized (fileLog) { fileLog.stop(); fileLog = null; } } configuration.stop(); } /* Methods called when configuration is changed. */ /** * * Reset number of log entries that are kept in memory. * * * @param size * the new maximum number of log entries in memory. */ void resetMemorySize(int size, int memorySize) { if (size <= 0) { size = 1; } synchronized (history) { LogEntry[] new_history = new LogEntry[size]; int leftSize = historyInsertionPoint; // Copy all entries to the left of the insertion point in // history to end of the new_history. if (leftSize > 0) { // There are entries to the left if (leftSize > size) { // To many entries; ignore oldest (leftmost) System.arraycopy(history, leftSize - size + 1, new_history, 1, size - 1); } else { // Copy all entries to the left System.arraycopy(history, 0, new_history, size - leftSize, leftSize); // Are there more entries to the right? int remaindingSize = size - leftSize; int remaindingEntries = memorySize - leftSize; if (remaindingSize > remaindingEntries) { // Copy all entries to the right System.arraycopy(history, leftSize, new_history, remaindingSize - remaindingEntries, remaindingEntries); } else { // Too many entries; ignore oldest (leftmost) System.arraycopy(history, memorySize - remaindingSize, new_history, 0, remaindingSize); } } } else { // Copy the last size entries from history int s = (size > memorySize) ? memorySize : size; int fromPos = (size > memorySize) ? 0 : memorySize - s; System.arraycopy(history, fromPos, new_history, size - s, s); } history = new_history; historyInsertionPoint = 0; } } private void resetFile(Boolean newValue, Boolean oldValue) { if (newValue.booleanValue() && fileLog == null) { fileLog = new FileLog(bc, configuration); if (oldValue == null) { synchronized (fileLog) { synchronized (history) { fileLog.saveMemEntries(new ArrayEnumeration(history, historyInsertionPoint)); } } } } else if (!(newValue.booleanValue()) && (fileLog != null)) { synchronized (fileLog) { fileLog.stop(); fileLog = null; } } } /* Method called by the LogConfig to indicate chage of properties. */ void configChange(String propName, Object oldValue, Object newValue) { String name = propName; if (name.equals(LogConfigImpl.MEM)) { resetMemorySize(((Integer) newValue).intValue(), ((Integer) oldValue).intValue()); } else if (name.equals(LogConfigImpl.FILE)) { resetFile((Boolean) newValue, (Boolean) oldValue); } else if (name.equals(LogConfigImpl.GEN) && fileLog != null) { synchronized (fileLog) { fileLog.resetGenerations(((Integer) newValue).intValue(), ((Integer) oldValue).intValue()); } } } /** * Each Bundle gets its own LogReaderServiceImpl, and the * LogReaderServiceFactory keeps track of the created LogReaderServices. */ public Object getService(Bundle bc, ServiceRegistration sd) { LogReaderServiceImpl lrsi = new LogReaderServiceImpl(this); logReaderServicies.put(lrsi, bc); return lrsi; } public void ungetService(Bundle bc, ServiceRegistration sd, Object s) { logReaderServicies.remove(s); } /* * This is the code that implements the log functionality! It keeps a short * history of the log in memory, this is the part that is returned when * getLog is called. */ /** The history list (an array used as a circular list). */ LogEntry[] history; /** * The index in <code>history</code> where the next entry shall be * * inserted. */ int historyInsertionPoint = 0; /* * Return an enumeration of the historyLength last entries in the log. */ public Enumeration getLog() { return new ArrayEnumeration(history, historyInsertionPoint); } /** * * Returns the filter level for a specific bundle. * * * @param bundel * the bundle to get the filter level for. */ public int getLogLevel(final Bundle bundle) { // The synchronized block below is needed to work around a bug in // JDK1.2.2 on Linux (with green threads). synchronized (configuration) { Integer res = (Integer) AccessController .doPrivileged(new PrivilegedAction() { public Object run() { return new Integer(getFilterLevel(bundle)); } }); return res.intValue(); } } /** * * A new log entry has arrived. If its numeric level is less than * or * equal to the filter level then output it and store it in the * memory * log. All LogReaderServiceImpl is notified for all new * logEntries, i.e., * the logFilter is not used for this. The * LogReaderService will notify * the LogListeners. * * * @param le * The new LogEntry */ protected synchronized void log(final LogEntryImpl le) { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { if (le.getLevel() <= getFilterLevel(le.getBundle())) { if (fileLog != null) { synchronized (fileLog) { fileLog.logged(le); } } if (configuration.getOut()) { System.out.println(le); } synchronized (history) { history[historyInsertionPoint] = le; historyInsertionPoint++; if (historyInsertionPoint == history.length) { historyInsertionPoint = 0; } } } for (Enumeration e = logReaderServicies.keys(); e .hasMoreElements();) { try { ((LogReaderServiceImpl) e.nextElement()).callback(le); } catch (Exception ce) { // TBD Log error? } } return null; } }); } /** * Get current filter level given a bundle. * * * @return filter level. */ int getFilterLevel(Bundle b) { return (b != null) ? configuration.getLevel(b) : configuration .getFilter(); }}/* * Auxiliary class used to create a Enumeration from an array. The array is * cloned to keep the array consistent even if the contents of the orginal array * is changed. * * The elements in the array are not cloned, but they are not changed in the log * anyway. */class ArrayEnumeration implements Enumeration { private Object[] array; private int pos; private int endPos; private boolean more = true; public ArrayEnumeration(Object[] a, int start) { this.array = (Object[]) a.clone(); endPos = start; pos = start; nextPos(); } /** * Decrement i until array[i] is non-null or there are no more * elements. * Sets <code>more</code> to false when the last element * has been * reached. */ private void nextPos() { do { pos = (pos == 0) ? array.length - 1 : pos - 1; } while (array[pos] == null && pos != endPos); more = array[pos] != null; } public boolean hasMoreElements() { return more; } public Object nextElement() { if (more) { Object o = array[pos]; if (pos == endPos) { more = false; } else { nextPos(); } return o; } throw new NoSuchElementException(); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -