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;
022import org.osgi.framework.Bundle;
023import org.osgi.service.log.LogLevel;
024import org.osgi.service.log.Logger;
025import org.osgi.service.log.LoggerFactory;
026
027/**
028 * Provides a container for the buffered event information.
029 */
030@SuppressWarnings("PMD.DataflowAnomalyAnalysis")
031public class BufferedEvent {
032
033    private static final Object[] EMPTY_ARRAY = new Object[0];
034    private final Bundle bundle;
035    private final String threadName;
036    private final String name;
037    private final LogLevel level;
038    private final String message;
039    private final Object[] arguments;
040
041    /**
042     * Instantiates a new buffered event.
043     *
044     * @param bundle the bundle
045     * @param name the name
046     * @param level the level
047     * @param message the message
048     * @param arguments the parameters
049     */
050    public BufferedEvent(Bundle bundle, String name, LogLevel level,
051            String message, Object... arguments) {
052        this.bundle = bundle;
053        this.name = name;
054        this.level = level;
055        this.message = message;
056        this.arguments = Arrays.copyOf(arguments, arguments.length);
057        threadName = Thread.currentThread().getName();
058    }
059
060    /**
061     * Instantiates a new buffered event.
062     *
063     * @param bundle the bundle
064     * @param name the name
065     * @param level the level
066     * @param message the message
067     */
068    public BufferedEvent(Bundle bundle, String name, LogLevel level,
069            String message) {
070        this.bundle = bundle;
071        this.name = name;
072        this.level = level;
073        this.message = message;
074        arguments = EMPTY_ARRAY;
075        threadName = Thread.currentThread().getName();
076    }
077
078    /**
079     * Forward the log event using the provided logger factory.
080     *
081     * @param factory the factory
082     */
083    @SuppressWarnings({ "PMD.AvoidLiteralsInIfCondition", "PMD.EmptyCatchBlock",
084        "PMD.NcssCount" })
085    public void forward(LoggerFactory factory) {
086        String savedName = Thread.currentThread().getName();
087        try {
088            // Set thread name to get nice thread info
089            try {
090                AccessController.doPrivileged(new PrivilegedAction<Void>() {
091                    @Override
092                    public Void run() {
093                        Thread.currentThread()
094                            .setName(threadName + " [recorded]");
095                        return null;
096                    }
097                });
098            } catch (SecurityException e) {
099                // Ignored, was just a best effort.
100            }
101            // Now process
102            doForward(factory);
103        } finally {
104            try {
105                AccessController.doPrivileged(new PrivilegedAction<Void>() {
106                    @Override
107                    public Void run() {
108                        Thread.currentThread().setName(savedName);
109                        return null; // NOPMD
110                    }
111                });
112            } catch (SecurityException e) {
113                // Ignored. If resetting doesn't work, setting hasn't worked
114                // either
115            }
116        }
117
118    }
119
120    @SuppressWarnings({ "PMD.NcssCount", "PMD.CognitiveComplexity" })
121    private void doForward(LoggerFactory factory) {
122        Logger logger;
123        if ((bundle.getState() & (Bundle.RESOLVED | Bundle.STARTING
124            | Bundle.ACTIVE | Bundle.STOPPING)) == 0) {
125            // Cannot log with unresolved bundle.
126            logger = factory.getLogger(name, Logger.class);
127        } else {
128            logger = factory.getLogger(bundle, name, Logger.class);
129        }
130        switch (level) {
131        case TRACE:
132            if (arguments.length == 0) {
133                logger.trace(l -> l.trace(message));
134            } else {
135                logger.trace(l -> l.trace(message, arguments));
136            }
137            break;
138        case DEBUG:
139            if (arguments.length == 0) {
140                logger.debug(l -> l.debug(message));
141            } else {
142                logger.debug(l -> l.debug(message, arguments));
143            }
144            break;
145        case INFO:
146            if (arguments.length == 0) {
147                logger.info(l -> l.info(message));
148            } else {
149                logger.info(l -> l.info(message, arguments));
150            }
151            break;
152        case WARN:
153            if (arguments.length == 0) {
154                logger.warn(l -> l.warn(message));
155            } else {
156                logger.warn(l -> l.warn(message, arguments));
157            }
158            break;
159        case ERROR:
160            if (arguments.length == 0) {
161                logger.error(l -> l.error(message));
162            } else {
163                logger.error(l -> l.error(message, arguments));
164            }
165            break;
166        case AUDIT:
167            if (arguments.length == 0) {
168                logger.audit(message);
169            } else {
170                logger.audit(message, arguments);
171            }
172            break;
173        }
174    }
175
176}