
aQute.bnd.osgi.MessageReporter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of biz.aQute.bndlib Show documentation
Show all versions of biz.aQute.bndlib Show documentation
bndlib: A Swiss Army Knife for OSGi
The newest version!
package aQute.bnd.osgi;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import aQute.bnd.exceptions.Exceptions;
import aQute.bnd.header.Attrs;
import aQute.bnd.header.Parameters;
import aQute.service.reporter.Report.Location;
import aQute.service.reporter.Reporter;
import aQute.service.reporter.Reporter.SetLocation;
/**
* This is the error and warning messages collected. It implements a concurrent
* message handling system.
*/
public class MessageReporter {
final Processor processor;
final AtomicInteger counter = new AtomicInteger(1000);
volatile ConcurrentHashMap messages = new ConcurrentHashMap<>();
class Message extends Location implements SetLocation, Comparable {
@Override
public String toString() {
return "Message [error=" + error + ", sequence=" + sequence + ", message=" + message + "]";
}
final boolean error;
final int sequence;
Message(int sequence, String message, boolean error) {
this.sequence = sequence;
this.message = message;
this.error = error;
}
Message(int sequence, Message m, String actualPrefix) {
m.to(this);
this.sequence = sequence;
this.message = actualPrefix.concat(m.message);
this.error = m.error;
}
@Override
public SetLocation file(String file) {
this.file = file;
return this;
}
@Override
public SetLocation header(String header) {
this.header = header;
return this;
}
@Override
public SetLocation context(String context) {
this.context = context;
return this;
}
@Override
public SetLocation method(String methodName) {
this.methodName = methodName;
return this;
}
@Override
public SetLocation line(int n) {
this.line = n;
return this;
}
@Override
public SetLocation reference(String reference) {
this.reference = reference;
return this;
}
@Override
public SetLocation details(Object details) {
this.details = details;
return null;
}
@Override
public Location location() {
return this;
}
@Override
public SetLocation length(int length) {
this.length = length;
return this;
}
@Override
public int compareTo(Message o) {
return Integer.compare(sequence, o.sequence);
}
Message fixup(Instructions fixupInstrs, boolean failok) {
boolean error = failok ? false : this.error;
Instruction matcher = fixupInstrs.finder(message);
String type = error ? Constants.FIXUPMESSAGES_IS_ERROR : Constants.FIXUPMESSAGES_IS_WARNING;
String message = this.message;
if (matcher != null && !matcher.isNegated()) {
Attrs attrs = fixupInstrs.get(matcher);
String restrict = attrs.get(Constants.FIXUPMESSAGES_RESTRICT_DIRECTIVE);
String replace = attrs.get(Constants.FIXUPMESSAGES_REPLACE_DIRECTIVE);
String is = attrs.get(Constants.FIXUPMESSAGES_IS_DIRECTIVE);
if (restrict == null || restrict.equals(type)) {
if (is != null && !is.equals(type)) {
error = !error;
}
if (replace != null) {
try (Processor replacer = new Processor(processor())) {
replacer.setProperty("@", message);
processor().getLogger()
.debug("replacing {} with {}", message, replace);
message = replacer.getReplacer()
.process(replace);
} catch (Exception e) {
throw Exceptions.duck(e);
}
}
if (attrs.isEmpty() || Constants.FIXUPMESSAGES_IS_IGNORE.equals(is)) {
message = null;
}
}
}
if (message == null)
return null;
if (error == this.error && message.equals(this.message))
return this;
return new Message(sequence, message, error);
}
}
class Cache {
final List errors = new ArrayList<>();
final List warnings = new ArrayList<>();
Cache() {
fixup(messages.values()).stream()
.forEach(m -> {
if (m.error)
errors.add(m.message);
else
warnings.add(m.message);
});
}
}
MessageReporter(Processor processor) {
this.processor = processor;
}
List getWarnings() {
return fixup().warnings;
}
List getErrors() {
return fixup().errors;
}
Cache fixup() {
return new Cache();
}
Location getLocation(String msg) {
return messages.get(msg);
}
public SetLocation error(String format, Object... args) {
try {
for (int i = 0; i < args.length; i++) {
if (args[i] instanceof Throwable t) {
args[i] = Exceptions.causes(t);
}
}
String s = Processor.formatArrays(format, args);
Message m = new Message(counter.getAndIncrement(), s, true);
putMessage(s, m);
return m;
} finally {
processor().signal();
}
}
void putMessage(String s, Message m) {
ConcurrentHashMap current;
do {
current = messages;
current.putIfAbsent(s, m);
} while (current != messages);
}
SetLocation warning(String format, Object... args) {
String s = Processor.formatArrays(format, args);
Message m = new Message(counter.getAndIncrement(), s, false);
putMessage(s, m);
return m;
}
void getInfo(Reporter from, String prefix) {
String actualPrefix = prefix == null ? processor().getBase() + " :" : prefix;
MessageReporter other;
if (from instanceof Processor processor) {
other = processor.reporter;
} else if (from instanceof MessageReporter mr) {
other = mr;
} else {
// backward compatible reporters
addAll(true, actualPrefix, from);
addAll(false, actualPrefix, from);
from.getErrors()
.clear();
from.getWarnings()
.clear();
return;
}
ConcurrentHashMap older = other.clear();
other.fixup(older.values())
.stream()
.map(m -> new Message(counter.getAndIncrement(), m, actualPrefix))
.forEach(m -> {
putMessage(m.message, m);
});
}
/*
*
*/
private List fixup(Collection older) {
boolean failOk = processor().isFailOk();
Instructions fixupInstrs = new Instructions();
Parameters fixup = processor().getMergedParameters(Constants.FIXUPMESSAGES);
fixup.forEach((k, v) -> fixupInstrs.put(Instruction.legacy(k), v));
return older.stream()
.sorted()
.map(m -> m.fixup(fixupInstrs, failOk))
.filter(Objects::nonNull)
.toList();
}
/*
* for backward compatible reporters
*/
void addAll(boolean error, String prefix, Reporter reporter) {
for (String message : new ArrayList<>(error ? reporter.getErrors() : reporter.getWarnings())) {
String newMessage = prefix.isEmpty() ? message : prefix.concat(message);
Message m = new Message(counter.getAndIncrement(), newMessage, error);
Location location = reporter.getLocation(message);
if (location != null)
location.to(m);
putMessage(newMessage, m);
}
}
ConcurrentHashMap clear() {
ConcurrentHashMap previous = messages;
messages = new ConcurrentHashMap<>();
return previous;
}
Processor processor() {
return this.processor.current();
}
Message remove(String message) {
return messages.remove(message);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy