001/*
002 * Copyright (C) 2019 Michael N. Lipp (http://www.mnl.de)
003 * 
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *        http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package de.mnl.osgi.lf4osgi.core;
018
019import java.security.AccessController;
020import java.security.PrivilegedAction;
021import java.util.Arrays;
022
023import org.osgi.framework.Bundle;
024import org.osgi.service.log.LogLevel;
025import org.osgi.service.log.Logger;
026import org.osgi.service.log.LoggerFactory;
027
028/**
029 * Provides a container for the buffered event information.
030 */
031@SuppressWarnings("PMD.DataflowAnomalyAnalysis")
032public class BufferedEvent {
033
034    private static final Object[] EMPTY_ARRAY = new Object[0];
035    private final Bundle bundle;
036    private final String threadName;
037    private final String name;
038    private final LogLevel level;
039    private final String message;
040    private final Object[] arguments;
041
042    /**
043     * Instantiates a new buffered event.
044     *
045     * @param bundle the bundle
046     * @param name the name
047     * @param level the level
048     * @param message the message
049     * @param arguments the parameters
050     */
051    public BufferedEvent(Bundle bundle, String name, LogLevel level,
052            String message, Object... arguments) {
053        this.bundle = bundle;
054        this.name = name;
055        this.level = level;
056        this.message = message;
057        this.arguments = Arrays.copyOf(arguments, arguments.length);
058        threadName = Thread.currentThread().getName();
059    }
060
061    /**
062     * Instantiates a new buffered event.
063     *
064     * @param bundle the bundle
065     * @param name the name
066     * @param level the level
067     * @param message the message
068     */
069    public BufferedEvent(Bundle bundle, String name, LogLevel level,
070            String message) {
071        this.bundle = bundle;
072        this.name = name;
073        this.level = level;
074        this.message = message;
075        arguments = EMPTY_ARRAY;
076        threadName = Thread.currentThread().getName();
077    }
078
079    /**
080     * Forward the log event using the provided logger factory.
081     *
082     * @param factory the factory
083     */
084    @SuppressWarnings({ "PMD.AvoidLiteralsInIfCondition", "PMD.EmptyCatchBlock",
085        "PMD.NcssCount" })
086    public void forward(LoggerFactory factory) {
087        String savedName = Thread.currentThread().getName();
088        try {
089            // Set thread name to get nice thread info
090            try {
091                AccessController.doPrivileged(new PrivilegedAction<Void>() {
092                    @Override
093                    public Void run() {
094                        Thread.currentThread()
095                            .setName(threadName + " [recorded]");
096                        return null;
097                    }
098                });
099            } catch (SecurityException e) {
100                // Ignored, was just a best effort.
101            }
102            // Now process
103            doForward(factory);
104        } finally {
105            try {
106                AccessController.doPrivileged(new PrivilegedAction<Void>() {
107                    @Override
108                    public Void run() {
109                        Thread.currentThread().setName(savedName);
110                        return null; // NOPMD
111                    }
112                });
113            } catch (SecurityException e) {
114                // Ignored. If resetting doesn't work, setting hasn't worked
115                // either
116            }
117        }
118
119    }
120
121    @SuppressWarnings("PMD.NcssCount")
122    private void doForward(LoggerFactory factory) {
123        Logger logger;
124        if ((bundle.getState() & (Bundle.RESOLVED | Bundle.STARTING
125            | Bundle.ACTIVE | Bundle.STOPPING)) == 0) {
126            // Cannot log with unresolved bundle.
127            logger = factory.getLogger(name, Logger.class);
128        } else {
129            logger = factory.getLogger(bundle, name, Logger.class);
130        }
131        switch (level) {
132        case TRACE:
133            if (arguments.length == 0) {
134                logger.trace(l -> l.trace(message));
135            } else {
136                logger.trace(l -> l.trace(message, arguments));
137            }
138            break;
139        case DEBUG:
140            if (arguments.length == 0) {
141                logger.debug(l -> l.debug(message));
142            } else {
143                logger.debug(l -> l.debug(message, arguments));
144            }
145            break;
146        case INFO:
147            if (arguments.length == 0) {
148                logger.info(l -> l.info(message));
149            } else {
150                logger.info(l -> l.info(message, arguments));
151            }
152            break;
153        case WARN:
154            if (arguments.length == 0) {
155                logger.warn(l -> l.warn(message));
156            } else {
157                logger.warn(l -> l.warn(message, arguments));
158            }
159            break;
160        case ERROR:
161            if (arguments.length == 0) {
162                logger.error(l -> l.error(message));
163            } else {
164                logger.error(l -> l.error(message, arguments));
165            }
166            break;
167        case AUDIT:
168            if (arguments.length == 0) {
169                logger.audit(message);
170            } else {
171                logger.audit(message, arguments);
172            }
173            break;
174        }
175    }
176
177}