From af9796c48cdef3e4f83fbd382fbb69b4441267c4 Mon Sep 17 00:00:00 2001 From: Thomas Watson Date: Fri, 3 Nov 2017 10:41:37 -0500 Subject: Bug 526732 - Update to latest Core API Change-Id: Ibec9d2adcd3cb52dafa8d25d3b8466af448f0270 Signed-off-by: Thomas Watson --- bundles/org.eclipse.osgi/.settings/.api_filters | 61 + .../osgi/internal/log/ExtendedLogServiceImpl.java | 26 + .../org/eclipse/osgi/internal/log/LoggerImpl.java | 38 +- .../src/org/osgi/framework/AdaptPermission.java | 4 +- .../src/org/osgi/framework/AdminPermission.java | 4 +- .../org/osgi/framework/CapabilityPermission.java | 4 +- .../osgi/src/org/osgi/framework/Constants.java | 34 + .../osgi/src/org/osgi/framework/FrameworkUtil.java | 1496 +++++++++++++++++++- .../src/org/osgi/framework/PackagePermission.java | 4 +- .../src/org/osgi/framework/ServicePermission.java | 4 +- .../osgi/src/org/osgi/service/log/Logger.java | 45 + .../src/org/osgi/service/log/LoggerConsumer.java | 42 + .../org/osgi/service/resolver/ResolveContext.java | 2 +- .../src/org/osgi/service/resolver/Resolver.java | 2 +- .../src/org/osgi/util/tracker/BundleTracker.java | 2 +- 15 files changed, 1752 insertions(+), 16 deletions(-) create mode 100644 bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/LoggerConsumer.java diff --git a/bundles/org.eclipse.osgi/.settings/.api_filters b/bundles/org.eclipse.osgi/.settings/.api_filters index b7fb09582..41baf7f67 100644 --- a/bundles/org.eclipse.osgi/.settings/.api_filters +++ b/bundles/org.eclipse.osgi/.settings/.api_filters @@ -13,6 +13,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + @@ -33,6 +57,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -144,6 +196,15 @@ + + + + + + + + + diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/ExtendedLogServiceImpl.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/ExtendedLogServiceImpl.java index cc4d186cd..43c1a1efe 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/ExtendedLogServiceImpl.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/ExtendedLogServiceImpl.java @@ -15,6 +15,7 @@ import org.eclipse.osgi.internal.log.ExtendedLogServiceFactory.EquinoxLoggerCont import org.osgi.framework.Bundle; import org.osgi.framework.ServiceReference; import org.osgi.service.log.FormatterLogger; +import org.osgi.service.log.LoggerConsumer; import org.osgi.service.log.admin.LoggerContext; public class ExtendedLogServiceImpl implements ExtendedLogService { @@ -308,6 +309,31 @@ public class ExtendedLogServiceImpl implements ExtendedLogService { getLogger((String) null).audit(format, arguments); } + @Override + public void trace(LoggerConsumer consumer) throws E { + getLogger((String) null).trace(consumer); + } + + @Override + public void debug(LoggerConsumer consumer) throws E { + getLogger((String) null).debug(consumer); + } + + @Override + public void info(LoggerConsumer consumer) throws E { + getLogger((String) null).info(consumer); + } + + @Override + public void warn(LoggerConsumer consumer) throws E { + getLogger((String) null).warn(consumer); + } + + @Override + public void error(LoggerConsumer consumer) throws E { + getLogger((String) null).error(consumer); + } + void applyLogLevels(EquinoxLoggerContext effectiveLoggerContext) { for (Map loggers : loggerCache.values()) { for (LoggerImpl logger : loggers.values()) { diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/LoggerImpl.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/LoggerImpl.java index 1876e10ba..90a2ee3bf 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/LoggerImpl.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/LoggerImpl.java @@ -12,8 +12,7 @@ import java.util.regex.Pattern; import org.eclipse.equinox.log.Logger; import org.osgi.framework.Bundle; import org.osgi.framework.ServiceReference; -import org.osgi.service.log.LogLevel; -import org.osgi.service.log.LogService; +import org.osgi.service.log.*; import org.osgi.service.log.admin.LoggerContext; public class LoggerImpl implements Logger { @@ -238,6 +237,41 @@ public class LoggerImpl implements Logger { log(LogLevel.AUDIT, format, arguments); } + @Override + public void trace(LoggerConsumer consumer) throws E { + if (isTraceEnabled()) { + consumer.accept(this); + } + } + + @Override + public void debug(LoggerConsumer consumer) throws E { + if (isDebugEnabled()) { + consumer.accept(this); + } + } + + @Override + public void info(LoggerConsumer consumer) throws E { + if (isInfoEnabled()) { + consumer.accept(this); + } + } + + @Override + public void warn(LoggerConsumer consumer) throws E { + if (isWarnEnabled()) { + consumer.accept(this); + } + } + + @Override + public void error(LoggerConsumer consumer) throws E { + if (isErrorEnabled()) { + consumer.accept(this); + } + } + private static final Pattern pattern = Pattern.compile("(\\\\?)(\\\\?)(\\{\\})"); //$NON-NLS-1$ private void log(LogLevel level, String format, Object... arguments) { diff --git a/bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/AdaptPermission.java b/bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/AdaptPermission.java index 0ac35f219..a2bc7aac5 100644 --- a/bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/AdaptPermission.java +++ b/bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/AdaptPermission.java @@ -1,5 +1,5 @@ /* - * Copyright (c) OSGi Alliance (2010, 2016). All Rights Reserved. + * Copyright (c) OSGi Alliance (2010, 2017). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -443,7 +443,7 @@ public final class AdaptPermission extends BasicPermission { AccessController.doPrivileged(new PrivilegedAction() { @Override public Void run() { - map.put("id", new Long(bundle.getBundleId())); + map.put("id", Long.valueOf(bundle.getBundleId())); map.put("location", bundle.getLocation()); String name = bundle.getSymbolicName(); if (name != null) { diff --git a/bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/AdminPermission.java b/bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/AdminPermission.java index 35d7725e3..7906054ba 100644 --- a/bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/AdminPermission.java +++ b/bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/AdminPermission.java @@ -1,5 +1,5 @@ /* - * Copyright (c) OSGi Alliance (2000, 2016). All Rights Reserved. + * Copyright (c) OSGi Alliance (2000, 2017). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -843,7 +843,7 @@ public final class AdminPermission extends BasicPermission { AccessController.doPrivileged(new PrivilegedAction() { @Override public Void run() { - map.put("id", new Long(bundle.getBundleId())); + map.put("id", Long.valueOf(bundle.getBundleId())); map.put("location", bundle.getLocation()); String name = bundle.getSymbolicName(); if (name != null) { diff --git a/bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/CapabilityPermission.java b/bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/CapabilityPermission.java index 90e1d0c01..8a38df04e 100644 --- a/bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/CapabilityPermission.java +++ b/bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/CapabilityPermission.java @@ -1,5 +1,5 @@ /* - * Copyright (c) OSGi Alliance (2000, 2016). All Rights Reserved. + * Copyright (c) OSGi Alliance (2000, 2017). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -507,7 +507,7 @@ public final class CapabilityPermission extends BasicPermission { AccessController.doPrivileged(new PrivilegedAction() { @Override public Void run() { - props.put("id", new Long(bundle.getBundleId())); + props.put("id", Long.valueOf(bundle.getBundleId())); props.put("location", bundle.getLocation()); String name = bundle.getSymbolicName(); if (name != null) { diff --git a/bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/Constants.java b/bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/Constants.java index 2747cd815..b53b1a9b4 100644 --- a/bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/Constants.java +++ b/bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/Constants.java @@ -1846,4 +1846,38 @@ public interface Constants { * @since 1.9 */ String SERVICE_CHANGECOUNT = "service.changecount"; + + /** + * Intent supported by Remote Services implementations that support Basic + * Remote Services as defined for the {@code osgi.basic} intent. + * + * @since 1.9 + */ + String INTENT_BASIC = "osgi.basic"; + + /** + * Intent supported by Remote Service implementations that support + * Asynchronous Remote Services as defined for the {@code osgi.async} + * intent. + * + * @since 1.9 + */ + String INTENT_ASYNC = "osgi.async"; + + /** + * Intent supported by Remote Service implementation that provide + * confidential communications as defined for the {@code osgi.confidential} + * intent. + * + * @since 1.9 + */ + String INTENT_CONFIDENTIAL = "osgi.confidential"; + + /** + * Intent supported by Remote Service implementations that provide private + * communications as defined for the {@code osgi.private} intent. + * + * @since 1.9 + */ + String INTENT_PRIVATE = "osgi.private"; } diff --git a/bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/FrameworkUtil.java b/bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/FrameworkUtil.java index cb98cc18d..90d50e4d3 100644 --- a/bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/FrameworkUtil.java +++ b/bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/FrameworkUtil.java @@ -32,8 +32,8 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; + import javax.security.auth.x500.X500Principal; -import org.eclipse.osgi.internal.framework.FilterImpl; /** * Framework Utility class. @@ -219,6 +219,1500 @@ public class FrameworkUtil { return null; } + /** + * RFC 1960-based Filter. Filter objects can be created by calling the + * constructor with the desired filter string. A Filter object can be called + * numerous times to determine if the match argument matches the filter + * string that was used to create the Filter object. + * + *

+ * The syntax of a filter string is the string representation of LDAP search + * filters as defined in RFC 1960: A String Representation of LDAP Search + * Filters (available at http://www.ietf.org/rfc/rfc1960.txt). It should + * be noted that RFC 2254: A String Representation of LDAP Search + * Filters (available at http://www.ietf.org/rfc/rfc2254.txt) supersedes + * RFC 1960 but only adds extensible matching and is not applicable for this + * API. + * + *

+ * The string representation of an LDAP search filter is defined by the + * following grammar. It uses a prefix format. + * + *

+	 *   <filter> ::= '(' <filtercomp> ')'
+	 *   <filtercomp> ::= <and> | <or> | <not> | <item>
+	 *   <and> ::= '&' <filterlist>
+	 *   <or> ::= '|' <filterlist>
+	 *   <not> ::= '!' <filter>
+	 *   <filterlist> ::= <filter> | <filter> <filterlist>
+	 *   <item> ::= <simple> | <present> | <substring>
+	 *   <simple> ::= <attr> <filtertype> <value>
+	 *   <filtertype> ::= <equal> | <approx> | <greater> | <less>
+	 *   <equal> ::= '='
+	 *   <approx> ::= '˜='
+	 *   <greater> ::= '>='
+	 *   <less> ::= '<='
+	 *   <present> ::= <attr> '=*'
+	 *   <substring> ::= <attr> '=' <initial> <any> <final>
+	 *   <initial> ::= NULL | <value>
+	 *   <any> ::= '*' <starval>
+	 *   <starval> ::= NULL | <value> '*' <starval>
+	 *   <final> ::= NULL | <value>
+	 * 
+ * + * {@code <attr>} is a string representing an attribute, or key, in + * the properties objects of the registered services. Attribute names are + * not case sensitive; that is cn and CN both refer to the same attribute. + * {@code <value>} is a string representing the value, or part of one, + * of a key in the properties objects of the registered services. If a + * {@code <value>} must contain one of the characters ' {@code *}' or + * '{@code (}' or '{@code )}', these characters should be escaped by + * preceding them with the backslash '{@code \}' character. Note that + * although both the {@code <substring>} and {@code <present>} + * productions can produce the {@code 'attr=*'} construct, this construct is + * used only to denote a presence filter. + * + *

+ * Examples of LDAP filters are: + * + *

+	 *   "(cn=Babs Jensen)"
+	 *   "(!(cn=Tim Howes))"
+	 *   "(&(" + Constants.OBJECTCLASS + "=Person)(|(sn=Jensen)(cn=Babs J*)))"
+	 *   "(o=univ*of*mich*)"
+	 * 
+ * + *

+ * The approximate match ({@code ~=}) is implementation specific but should + * at least ignore case and white space differences. Optional are codes like + * soundex or other smart "closeness" comparisons. + * + *

+ * Comparison of values is not straightforward. Strings are compared + * differently than numbers and it is possible for a key to have multiple + * values. Note that that keys in the match argument must always be strings. + * The comparison is defined by the object type of the key's value. The + * following rules apply for comparison: + * + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Property Value Type Comparison Type
StringString comparison
Integer, Long, Float, Double, Byte, Short, BigInteger, BigDecimalnumerical comparison
Charactercharacter comparison
Booleanequality comparisons only
[] (array)recursively applied to values
Collectionrecursively applied to values
+ * Note: arrays of primitives are also supported.
+ * + * A filter matches a key that has multiple values if it matches at least + * one of those values. For example, + * + *
+	 * Dictionary d = new Hashtable();
+	 * d.put("cn", new String[] {"a", "b", "c"});
+	 * 
+ * + * d will match {@code (cn=a)} and also {@code (cn=b)} + * + *

+ * A filter component that references a key having an unrecognizable data + * type will evaluate to {@code false} . + */ + static private final class FilterImpl implements Filter { + /* filter operators */ + private static final int EQUAL = 1; + private static final int APPROX = 2; + private static final int GREATER = 3; + private static final int LESS = 4; + private static final int PRESENT = 5; + private static final int SUBSTRING = 6; + private static final int AND = 7; + private static final int OR = 8; + private static final int NOT = 9; + + /** filter operation */ + private final int op; + /** filter attribute or null if operation AND, OR or NOT */ + private final String attr; + /** filter operands */ + private final Object value; + + /* normalized filter string for Filter object */ + private transient String filterString; + + /** + * Constructs a {@link FilterImpl} object. This filter object may be + * used to match a {@link ServiceReference} or a Dictionary. + * + *

+ * If the filter cannot be parsed, an {@link InvalidSyntaxException} + * will be thrown with a human readable message where the filter became + * unparsable. + * + * @param filterString the filter string. + * @throws InvalidSyntaxException If the filter parameter contains an + * invalid filter string that cannot be parsed. + */ + static FilterImpl newInstance(String filterString) throws InvalidSyntaxException { + return new Parser(filterString).parse(); + } + + FilterImpl(int operation, String attr, Object value) { + this.op = operation; + this.attr = attr; + this.value = value; + filterString = null; + } + + /** + * Filter using a service's properties. + *

+ * This {@code Filter} is executed using the keys and values of the + * referenced service's properties. The keys are looked up in a case + * insensitive manner. + * + * @param reference The reference to the service whose properties are + * used in the match. + * @return {@code true} if the service's properties match this + * {@code Filter}; {@code false} otherwise. + */ + @Override + public boolean match(ServiceReference reference) { + return matches(new ServiceReferenceMap(reference)); + } + + /** + * Filter using a {@code Dictionary} with case insensitive key lookup. + * This {@code Filter} is executed using the specified + * {@code Dictionary}'s keys and values. The keys are looked up in a + * case insensitive manner. + * + * @param dictionary The {@code Dictionary} whose key/value pairs are + * used in the match. + * @return {@code true} if the {@code Dictionary}'s values match this + * filter; {@code false} otherwise. + * @throws IllegalArgumentException If {@code dictionary} contains case + * variants of the same key name. + */ + @Override + public boolean match(Dictionary dictionary) { + return matches(new CaseInsensitiveMap(dictionary)); + } + + /** + * Filter using a {@code Dictionary}. This {@code Filter} is executed + * using the specified {@code Dictionary}'s keys and values. The keys + * are looked up in a normal manner respecting case. + * + * @param dictionary The {@code Dictionary} whose key/value pairs are + * used in the match. + * @return {@code true} if the {@code Dictionary}'s values match this + * filter; {@code false} otherwise. + * @since 1.3 + */ + @Override + public boolean matchCase(Dictionary dictionary) { + switch (op) { + case AND : { + FilterImpl[] filters = (FilterImpl[]) value; + for (FilterImpl f : filters) { + if (!f.matchCase(dictionary)) { + return false; + } + } + return true; + } + + case OR : { + FilterImpl[] filters = (FilterImpl[]) value; + for (FilterImpl f : filters) { + if (f.matchCase(dictionary)) { + return true; + } + } + return false; + } + + case NOT : { + FilterImpl filter = (FilterImpl) value; + return !filter.matchCase(dictionary); + } + + case SUBSTRING : + case EQUAL : + case GREATER : + case LESS : + case APPROX : { + Object prop = (dictionary == null) ? null : dictionary.get(attr); + return compare(op, prop, value); + } + + case PRESENT : { + Object prop = (dictionary == null) ? null : dictionary.get(attr); + return prop != null; + } + } + + return false; + } + + /** + * Filter using a {@code Map}. This {@code Filter} is executed using the + * specified {@code Map}'s keys and values. The keys are looked up in a + * normal manner respecting case. + * + * @param map The {@code Map} whose key/value pairs are used in the + * match. Maps with {@code null} key or values are not supported. + * A {@code null} value is considered not present to the filter. + * @return {@code true} if the {@code Map}'s values match this filter; + * {@code false} otherwise. + * @since 1.6 + */ + @Override + public boolean matches(Map map) { + switch (op) { + case AND : { + FilterImpl[] filters = (FilterImpl[]) value; + for (FilterImpl f : filters) { + if (!f.matches(map)) { + return false; + } + } + return true; + } + + case OR : { + FilterImpl[] filters = (FilterImpl[]) value; + for (FilterImpl f : filters) { + if (f.matches(map)) { + return true; + } + } + return false; + } + + case NOT : { + FilterImpl filter = (FilterImpl) value; + return !filter.matches(map); + } + + case SUBSTRING : + case EQUAL : + case GREATER : + case LESS : + case APPROX : { + Object prop = (map == null) ? null : map.get(attr); + return compare(op, prop, value); + } + + case PRESENT : { + Object prop = (map == null) ? null : map.get(attr); + return prop != null; + } + } + + return false; + } + + /** + * Returns this {@code Filter}'s filter string. + *

+ * The filter string is normalized by removing whitespace which does not + * affect the meaning of the filter. + * + * @return This {@code Filter}'s filter string. + */ + @Override + public String toString() { + String result = filterString; + if (result == null) { + filterString = result = normalize().toString(); + } + return result; + } + + /** + * Returns this {@code Filter}'s normalized filter string. + *

+ * The filter string is normalized by removing whitespace which does not + * affect the meaning of the filter. + * + * @return This {@code Filter}'s filter string. + */ + private StringBuilder normalize() { + StringBuilder sb = new StringBuilder(); + sb.append('('); + + switch (op) { + case AND : { + sb.append('&'); + + FilterImpl[] filters = (FilterImpl[]) value; + for (FilterImpl f : filters) { + sb.append(f.normalize()); + } + + break; + } + + case OR : { + sb.append('|'); + + FilterImpl[] filters = (FilterImpl[]) value; + for (FilterImpl f : filters) { + sb.append(f.normalize()); + } + + break; + } + + case NOT : { + sb.append('!'); + FilterImpl filter = (FilterImpl) value; + sb.append(filter.normalize()); + + break; + } + + case SUBSTRING : { + sb.append(attr); + sb.append('='); + + String[] substrings = (String[]) value; + + for (String substr : substrings) { + if (substr == null) /* * */{ + sb.append('*'); + } else /* xxx */{ + sb.append(encodeValue(substr)); + } + } + + break; + } + case EQUAL : { + sb.append(attr); + sb.append('='); + sb.append(encodeValue((String) value)); + + break; + } + case GREATER : { + sb.append(attr); + sb.append(">="); + sb.append(encodeValue((String) value)); + + break; + } + case LESS : { + sb.append(attr); + sb.append("<="); + sb.append(encodeValue((String) value)); + + break; + } + case APPROX : { + sb.append(attr); + sb.append("~="); + sb.append(encodeValue(approxString((String) value))); + + break; + } + + case PRESENT : { + sb.append(attr); + sb.append("=*"); + + break; + } + } + + sb.append(')'); + + return sb; + } + + /** + * Compares this {@code Filter} to another {@code Filter}. + * + *

+ * This implementation returns the result of calling + * {@code this.toString().equals(obj.toString()}. + * + * @param obj The object to compare against this {@code Filter}. + * @return If the other object is a {@code Filter} object, then returns + * the result of calling + * {@code this.toString().equals(obj.toString()}; {@code false} + * otherwise. + */ + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + + if (!(obj instanceof Filter)) { + return false; + } + + return this.toString().equals(obj.toString()); + } + + /** + * Returns the hashCode for this {@code Filter}. + * + *

+ * This implementation returns the result of calling + * {@code this.toString().hashCode()}. + * + * @return The hashCode of this {@code Filter}. + */ + @Override + public int hashCode() { + return this.toString().hashCode(); + } + + /** + * Encode the value string such that '(', '*', ')' and '\' are escaped. + * + * @param value unencoded value string. + * @return encoded value string. + */ + private static String encodeValue(String value) { + boolean encoded = false; + int inlen = value.length(); + int outlen = inlen << 1; /* inlen 2 */ + + char[] output = new char[outlen]; + value.getChars(0, inlen, output, inlen); + + int cursor = 0; + for (int i = inlen; i < outlen; i++) { + char c = output[i]; + + switch (c) { + case '(' : + case '*' : + case ')' : + case '\\' : { + output[cursor] = '\\'; + cursor++; + encoded = true; + + break; + } + } + + output[cursor] = c; + cursor++; + } + + return encoded ? new String(output, 0, cursor) : value; + } + + private boolean compare(int operation, Object value1, Object value2) { + if (value1 == null) { + return false; + } + if (value1 instanceof String) { + return compare_String(operation, (String) value1, value2); + } + if (value1 instanceof Version) { + return compare_Version(operation, (Version) value1, value2); + } + + Class clazz = value1.getClass(); + if (clazz.isArray()) { + Class type = clazz.getComponentType(); + if (type.isPrimitive()) { + return compare_PrimitiveArray(operation, type, value1, value2); + } + return compare_ObjectArray(operation, (Object[]) value1, value2); + } + if (value1 instanceof Collection) { + return compare_Collection(operation, (Collection) value1, value2); + } + if (value1 instanceof Integer) { + return compare_Integer(operation, ((Integer) value1).intValue(), value2); + } + if (value1 instanceof Long) { + return compare_Long(operation, ((Long) value1).longValue(), value2); + } + if (value1 instanceof Byte) { + return compare_Byte(operation, ((Byte) value1).byteValue(), value2); + } + if (value1 instanceof Short) { + return compare_Short(operation, ((Short) value1).shortValue(), value2); + } + if (value1 instanceof Character) { + return compare_Character(operation, ((Character) value1).charValue(), value2); + } + if (value1 instanceof Float) { + return compare_Float(operation, ((Float) value1).floatValue(), value2); + } + if (value1 instanceof Double) { + return compare_Double(operation, ((Double) value1).doubleValue(), value2); + } + if (value1 instanceof Boolean) { + return compare_Boolean(operation, ((Boolean) value1).booleanValue(), value2); + } + if (value1 instanceof Comparable) { + @SuppressWarnings("unchecked") + Comparable comparable = (Comparable) value1; + return compare_Comparable(operation, comparable, value2); + } + return compare_Unknown(operation, value1, value2); + } + + private boolean compare_Collection(int operation, Collection collection, Object value2) { + for (Object value1 : collection) { + if (compare(operation, value1, value2)) { + return true; + } + } + return false; + } + + private boolean compare_ObjectArray(int operation, Object[] array, Object value2) { + for (Object value1 : array) { + if (compare(operation, value1, value2)) { + return true; + } + } + return false; + } + + private boolean compare_PrimitiveArray(int operation, Class type, Object primarray, Object value2) { + if (Integer.TYPE.isAssignableFrom(type)) { + int[] array = (int[]) primarray; + for (int value1 : array) { + if (compare_Integer(operation, value1, value2)) { + return true; + } + } + return false; + } + if (Long.TYPE.isAssignableFrom(type)) { + long[] array = (long[]) primarray; + for (long value1 : array) { + if (compare_Long(operation, value1, value2)) { + return true; + } + } + return false; + } + if (Byte.TYPE.isAssignableFrom(type)) { + byte[] array = (byte[]) primarray; + for (byte value1 : array) { + if (compare_Byte(operation, value1, value2)) { + return true; + } + } + return false; + } + if (Short.TYPE.isAssignableFrom(type)) { + short[] array = (short[]) primarray; + for (short value1 : array) { + if (compare_Short(operation, value1, value2)) { + return true; + } + } + return false; + } + if (Character.TYPE.isAssignableFrom(type)) { + char[] array = (char[]) primarray; + for (char value1 : array) { + if (compare_Character(operation, value1, value2)) { + return true; + } + } + return false; + } + if (Float.TYPE.isAssignableFrom(type)) { + float[] array = (float[]) primarray; + for (float value1 : array) { + if (compare_Float(operation, value1, value2)) { + return true; + } + } + return false; + } + if (Double.TYPE.isAssignableFrom(type)) { + double[] array = (double[]) primarray; + for (double value1 : array) { + if (compare_Double(operation, value1, value2)) { + return true; + } + } + return false; + } + if (Boolean.TYPE.isAssignableFrom(type)) { + boolean[] array = (boolean[]) primarray; + for (boolean value1 : array) { + if (compare_Boolean(operation, value1, value2)) { + return true; + } + } + return false; + } + return false; + } + + private boolean compare_String(int operation, String string, Object value2) { + switch (operation) { + case SUBSTRING : { + String[] substrings = (String[]) value2; + int pos = 0; + for (int i = 0, size = substrings.length; i < size; i++) { + String substr = substrings[i]; + + if (i + 1 < size) /* if this is not that last substr */{ + if (substr == null) /* * */{ + String substr2 = substrings[i + 1]; + + if (substr2 == null) /* ** */ + continue; /* ignore first star */ + /* xxx */ + int index = string.indexOf(substr2, pos); + if (index == -1) { + return false; + } + + pos = index + substr2.length(); + if (i + 2 < size) // if there are more + // substrings, increment + // over the string we just + // matched; otherwise need + // to do the last substr + // check + i++; + } else /* xxx */{ + int len = substr.length(); + if (string.regionMatches(pos, substr, 0, len)) { + pos += len; + } else { + return false; + } + } + } else /* last substr */{ + if (substr == null) /* * */{ + return true; + } + /* xxx */ + return string.endsWith(substr); + } + } + + return true; + } + case EQUAL : { + return string.equals(value2); + } + case APPROX : { + string = approxString(string); + String string2 = approxString((String) value2); + + return string.equalsIgnoreCase(string2); + } + case GREATER : { + return string.compareTo((String) value2) >= 0; + } + case LESS : { + return string.compareTo((String) value2) <= 0; + } + } + return false; + } + + private boolean compare_Integer(int operation, int intval, Object value2) { + if (operation == SUBSTRING) { + return false; + } + int intval2; + try { + intval2 = Integer.parseInt(((String) value2).trim()); + } catch (IllegalArgumentException e) { + return false; + } + switch (operation) { + case APPROX : + case EQUAL : { + return intval == intval2; + } + case GREATER : { + return intval >= intval2; + } + case LESS : { + return intval <= intval2; + } + } + return false; + } + + private boolean compare_Long(int operation, long longval, Object value2) { + if (operation == SUBSTRING) { + return false; + } + long longval2; + try { + longval2 = Long.parseLong(((String) value2).trim()); + } catch (IllegalArgumentException e) { + return false; + } + + switch (operation) { + case APPROX : + case EQUAL : { + return longval == longval2; + } + case GREATER : { + return longval >= longval2; + } + case LESS : { + return longval <= longval2; + } + } + return false; + } + + private boolean compare_Byte(int operation, byte byteval, Object value2) { + if (operation == SUBSTRING) { + return false; + } + byte byteval2; + try { + byteval2 = Byte.parseByte(((String) value2).trim()); + } catch (IllegalArgumentException e) { + return false; + } + + switch (operation) { + case APPROX : + case EQUAL : { + return byteval == byteval2; + } + case GREATER : { + return byteval >= byteval2; + } + case LESS : { + return byteval <= byteval2; + } + } + return false; + } + + private boolean compare_Short(int operation, short shortval, Object value2) { + if (operation == SUBSTRING) { + return false; + } + short shortval2; + try { + shortval2 = Short.parseShort(((String) value2).trim()); + } catch (IllegalArgumentException e) { + return false; + } + + switch (operation) { + case APPROX : + case EQUAL : { + return shortval == shortval2; + } + case GREATER : { + return shortval >= shortval2; + } + case LESS : { + return shortval <= shortval2; + } + } + return false; + } + + private boolean compare_Character(int operation, char charval, Object value2) { + if (operation == SUBSTRING) { + return false; + } + char charval2; + try { + charval2 = ((String) value2).charAt(0); + } catch (IndexOutOfBoundsException e) { + return false; + } + + switch (operation) { + case EQUAL : { + return charval == charval2; + } + case APPROX : { + return (charval == charval2) || (Character.toUpperCase(charval) == Character.toUpperCase(charval2)) || (Character.toLowerCase(charval) == Character.toLowerCase(charval2)); + } + case GREATER : { + return charval >= charval2; + } + case LESS : { + return charval <= charval2; + } + } + return false; + } + + private boolean compare_Boolean(int operation, boolean boolval, Object value2) { + if (operation == SUBSTRING) { + return false; + } + boolean boolval2 = Boolean.valueOf(((String) value2).trim()).booleanValue(); + switch (operation) { + case APPROX : + case EQUAL : + case GREATER : + case LESS : { + return boolval == boolval2; + } + } + return false; + } + + private boolean compare_Float(int operation, float floatval, Object value2) { + if (operation == SUBSTRING) { + return false; + } + float floatval2; + try { + floatval2 = Float.parseFloat(((String) value2).trim()); + } catch (IllegalArgumentException e) { + return false; + } + + switch (operation) { + case APPROX : + case EQUAL : { + return Float.compare(floatval, floatval2) == 0; + } + case GREATER : { + return Float.compare(floatval, floatval2) >= 0; + } + case LESS : { + return Float.compare(floatval, floatval2) <= 0; + } + } + return false; + } + + private boolean compare_Double(int operation, double doubleval, Object value2) { + if (operation == SUBSTRING) { + return false; + } + double doubleval2; + try { + doubleval2 = Double.parseDouble(((String) value2).trim()); + } catch (IllegalArgumentException e) { + return false; + } + + switch (operation) { + case APPROX : + case EQUAL : { + return Double.compare(doubleval, doubleval2) == 0; + } + case GREATER : { + return Double.compare(doubleval, doubleval2) >= 0; + } + case LESS : { + return Double.compare(doubleval, doubleval2) <= 0; + } + } + return false; + } + + private static Object valueOf(Class target, String value2) { + do { + Method method; + try { + method = target.getMethod("valueOf", String.class); + } catch (NoSuchMethodException e) { + break; + } + if (Modifier.isStatic(method.getModifiers()) && target.isAssignableFrom(method.getReturnType())) { + setAccessible(method); + try { + return method.invoke(null, value2.trim()); + } catch (IllegalAccessException e) { + return null; + } catch (InvocationTargetException e) { + return null; + } + } + } while (false); + + do { + Constructor constructor; + try { + constructor = target.getConstructor(String.class); + } catch (NoSuchMethodException e) { + break; + } + setAccessible(constructor); + try { + return constructor.newInstance(value2.trim()); + } catch (IllegalAccessException e) { + return null; + } catch (InvocationTargetException e) { + return null; + } catch (InstantiationException e) { + return null; + } + } while (false); + + return null; + } + + private static void setAccessible(AccessibleObject accessible) { + if (!accessible.isAccessible()) { + AccessController.doPrivileged(new SetAccessibleAction(accessible)); + } + } + + private boolean compare_Comparable(int operation, Comparable value1, Object value2) { + if (operation == SUBSTRING) { + return false; + } + value2 = valueOf(value1.getClass(), (String) value2); + if (value2 == null) { + return false; + } + try { + switch (operation) { + case APPROX : + case EQUAL : { + return value1.compareTo(value2) == 0; + } + case GREATER : { + return value1.compareTo(value2) >= 0; + } + case LESS : { + return value1.compareTo(value2) <= 0; + } + } + } catch (Exception e) { + // if the compareTo method throws an exception; return false + return false; + } + return false; + } + + private boolean compare_Version(int operation, Version value1, Object value2) { + if (operation == SUBSTRING) { + return false; + } + try { + Version version2 = Version.valueOf((String) value2); + switch (operation) { + case APPROX : + case EQUAL : { + return value1.compareTo(version2) == 0; + } + case GREATER : { + return value1.compareTo(version2) >= 0; + } + case LESS : { + return value1.compareTo(version2) <= 0; + } + } + } catch (Exception e) { + // if the valueOf or compareTo method throws an exception + return false; + } + return false; + } + + private boolean compare_Unknown(int operation, Object value1, Object value2) { + if (operation == SUBSTRING) { + return false; + } + value2 = valueOf(value1.getClass(), (String) value2); + if (value2 == null) { + return false; + } + try { + switch (operation) { + case APPROX : + case EQUAL : + case GREATER : + case LESS : { + return value1.equals(value2); + } + } + } catch (Exception e) { + // if the equals method throws an exception; return false + return false; + } + return false; + } + + /** + * Map a string for an APPROX (~=) comparison. + * + * This implementation removes white spaces. This is the minimum + * implementation allowed by the OSGi spec. + * + * @param input Input string. + * @return String ready for APPROX comparison. + */ + private static String approxString(String input) { + boolean changed = false; + char[] output = input.toCharArray(); + int cursor = 0; + for (char c : output) { + if (Character.isWhitespace(c)) { + changed = true; + continue; + } + + output[cursor] = c; + cursor++; + } + + return changed ? new String(output, 0, cursor) : input; + } + + /** + * Parser class for OSGi filter strings. This class parses the complete + * filter string and builds a tree of Filter objects rooted at the + * parent. + */ + static private final class Parser { + private final String filterstring; + private final char[] filterChars; + private int pos; + + Parser(String filterstring) { + this.filterstring = filterstring; + filterChars = filterstring.toCharArray(); + pos = 0; + } + + FilterImpl parse() throws InvalidSyntaxException { + FilterImpl filter; + try { + filter = parse_filter(); + } catch (ArrayIndexOutOfBoundsException e) { + throw new InvalidSyntaxException("Filter ended abruptly", filterstring, e); + } + + if (pos != filterChars.length) { + throw new InvalidSyntaxException("Extraneous trailing characters: " + filterstring.substring(pos), filterstring); + } + return filter; + } + + private FilterImpl parse_filter() throws InvalidSyntaxException { + FilterImpl filter; + skipWhiteSpace(); + + if (filterChars[pos] != '(') { + throw new InvalidSyntaxException("Missing '(': " + filterstring.substring(pos), filterstring); + } + + pos++; + + filter = parse_filtercomp(); + + skipWhiteSpace(); + + if (filterChars[pos] != ')') { + throw new InvalidSyntaxException("Missing ')': " + filterstring.substring(pos), filterstring); + } + + pos++; + + skipWhiteSpace(); + + return filter; + } + + private FilterImpl parse_filtercomp() throws InvalidSyntaxException { + skipWhiteSpace(); + + char c = filterChars[pos]; + + switch (c) { + case '&' : { + pos++; + return parse_and(); + } + case '|' : { + pos++; + return parse_or(); + } + case '!' : { + pos++; + return parse_not(); + } + } + return parse_item(); + } + + private FilterImpl parse_and() throws InvalidSyntaxException { + int lookahead = pos; + skipWhiteSpace(); + + if (filterChars[pos] != '(') { + pos = lookahead - 1; + return parse_item(); + } + + List operands = new ArrayList(10); + + while (filterChars[pos] == '(') { + FilterImpl child = parse_filter(); + operands.add(child); + } + + return new FilterImpl(FilterImpl.AND, null, + operands.toArray(new FilterImpl[0])); + } + + private FilterImpl parse_or() throws InvalidSyntaxException { + int lookahead = pos; + skipWhiteSpace(); + + if (filterChars[pos] != '(') { + pos = lookahead - 1; + return parse_item(); + } + + List operands = new ArrayList(10); + + while (filterChars[pos] == '(') { + FilterImpl child = parse_filter(); + operands.add(child); + } + + return new FilterImpl(FilterImpl.OR, null, + operands.toArray(new FilterImpl[0])); + } + + private FilterImpl parse_not() throws InvalidSyntaxException { + int lookahead = pos; + skipWhiteSpace(); + + if (filterChars[pos] != '(') { + pos = lookahead - 1; + return parse_item(); + } + + FilterImpl child = parse_filter(); + + return new FilterImpl(FilterImpl.NOT, null, child); + } + + private FilterImpl parse_item() throws InvalidSyntaxException { + String attr = parse_attr(); + + skipWhiteSpace(); + + switch (filterChars[pos]) { + case '~' : { + if (filterChars[pos + 1] == '=') { + pos += 2; + return new FilterImpl(FilterImpl.APPROX, attr, parse_value()); + } + break; + } + case '>' : { + if (filterChars[pos + 1] == '=') { + pos += 2; + return new FilterImpl(FilterImpl.GREATER, attr, parse_value()); + } + break; + } + case '<' : { + if (filterChars[pos + 1] == '=') { + pos += 2; + return new FilterImpl(FilterImpl.LESS, attr, parse_value()); + } + break; + } + case '=' : { + if (filterChars[pos + 1] == '*') { + int oldpos = pos; + pos += 2; + skipWhiteSpace(); + if (filterChars[pos] == ')') { + return new FilterImpl(FilterImpl.PRESENT, attr, null); + } + pos = oldpos; + } + + pos++; + Object string = parse_substring(); + + if (string instanceof String) { + return new FilterImpl(FilterImpl.EQUAL, attr, string); + } + return new FilterImpl(FilterImpl.SUBSTRING, attr, string); + } + } + + throw new InvalidSyntaxException("Invalid operator: " + filterstring.substring(pos), filterstring); + } + + private String parse_attr() throws InvalidSyntaxException { + skipWhiteSpace(); + + int begin = pos; + int end = pos; + + char c = filterChars[pos]; + + while (c != '~' && c != '<' && c != '>' && c != '=' && c != '(' && c != ')') { + pos++; + + if (!Character.isWhitespace(c)) { + end = pos; + } + + c = filterChars[pos]; + } + + int length = end - begin; + + if (length == 0) { + throw new InvalidSyntaxException("Missing attr: " + filterstring.substring(pos), filterstring); + } + + return new String(filterChars, begin, length); + } + + private String parse_value() throws InvalidSyntaxException { + StringBuilder sb = new StringBuilder(filterChars.length - pos); + + parseloop: while (true) { + char c = filterChars[pos]; + + switch (c) { + case ')' : { + break parseloop; + } + + case '(' : { + throw new InvalidSyntaxException("Invalid value: " + filterstring.substring(pos), filterstring); + } + + case '\\' : { + pos++; + c = filterChars[pos]; + /* fall through into default */ + } + + default : { + sb.append(c); + pos++; + break; + } + } + } + + if (sb.length() == 0) { + throw new InvalidSyntaxException("Missing value: " + filterstring.substring(pos), filterstring); + } + + return sb.toString(); + } + + private Object parse_substring() throws InvalidSyntaxException { + StringBuilder sb = new StringBuilder(filterChars.length - pos); + + List operands = new ArrayList(10); + + parseloop: while (true) { + char c = filterChars[pos]; + + switch (c) { + case ')' : { + if (sb.length() > 0) { + operands.add(sb.toString()); + } + + break parseloop; + } + + case '(' : { + throw new InvalidSyntaxException("Invalid value: " + filterstring.substring(pos), filterstring); + } + + case '*' : { + if (sb.length() > 0) { + operands.add(sb.toString()); + } + + sb.setLength(0); + + operands.add(null); + pos++; + + break; + } + + case '\\' : { + pos++; + c = filterChars[pos]; + /* fall through into default */ + } + + default : { + sb.append(c); + pos++; + break; + } + } + } + + int size = operands.size(); + + if (size == 0) { + return ""; + } + + if (size == 1) { + Object single = operands.get(0); + + if (single != null) { + return single; + } + } + + return operands.toArray(new String[0]); + } + + private void skipWhiteSpace() { + for (int length = filterChars.length; (pos < length) && Character.isWhitespace(filterChars[pos]);) { + pos++; + } + } + } + } + + /** + * This Map is used for case-insensitive key lookup during filter + * evaluation. This Map implementation only supports the get operation using + * a String key as no other operations are used by the Filter + * implementation. + */ + static private final class CaseInsensitiveMap extends AbstractMap implements Map { + private final Dictionary dictionary; + private final String[] keys; + + /** + * Create a case insensitive map from the specified dictionary. + * + * @param dictionary + * @throws IllegalArgumentException If {@code dictionary} contains case + * variants of the same key name. + */ + CaseInsensitiveMap(Dictionary dictionary) { + if (dictionary == null) { + this.dictionary = null; + this.keys = new String[0]; + return; + } + this.dictionary = dictionary; + List keyList = new ArrayList(dictionary.size()); + for (Enumeration e = dictionary.keys(); e.hasMoreElements();) { + Object k = e.nextElement(); + if (k instanceof String) { + String key = (String) k; + for (String i : keyList) { + if (key.equalsIgnoreCase(i)) { + throw new IllegalArgumentException(); + } + } + keyList.add(key); + } + } + this.keys = keyList.toArray(new String[0]); + } + + @Override + public Object get(Object o) { + String k = (String) o; + for (String key : keys) { + if (key.equalsIgnoreCase(k)) { + return dictionary.get(key); + } + } + return null; + } + + @Override + public Set> entrySet() { + throw new UnsupportedOperationException(); + } + } + + /** + * This Map is used for key lookup from a ServiceReference during filter + * evaluation. This Map implementation only supports the get operation using + * a String key as no other operations are used by the Filter + * implementation. + */ + static private final class ServiceReferenceMap extends AbstractMap implements Map { + private final ServiceReference reference; + + ServiceReferenceMap(ServiceReference reference) { + this.reference = reference; + } + + @Override + public Object get(Object key) { + if (reference == null) { + return null; + } + return reference.getProperty((String) key); + } + + @Override + public Set> entrySet() { + throw new UnsupportedOperationException(); + } + } + + static private final class SetAccessibleAction implements PrivilegedAction { + private final AccessibleObject accessible; + + SetAccessibleAction(AccessibleObject accessible) { + this.accessible = accessible; + } + + @Override + public Void run() { + accessible.setAccessible(true); + return null; + } + } + /** * This class contains a method to match a distinguished name (DN) chain * against and DN chain pattern. diff --git a/bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/PackagePermission.java b/bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/PackagePermission.java index 79379880a..264ccd683 100644 --- a/bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/PackagePermission.java +++ b/bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/PackagePermission.java @@ -1,5 +1,5 @@ /* - * Copyright (c) OSGi Alliance (2000, 2016). All Rights Reserved. + * Copyright (c) OSGi Alliance (2000, 2017). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -544,7 +544,7 @@ public final class PackagePermission extends BasicPermission { AccessController.doPrivileged(new PrivilegedAction() { @Override public Void run() { - map.put("id", new Long(bundle.getBundleId())); + map.put("id", Long.valueOf(bundle.getBundleId())); map.put("location", bundle.getLocation()); String name = bundle.getSymbolicName(); if (name != null) { diff --git a/bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/ServicePermission.java b/bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/ServicePermission.java index 868d24c0c..8db61d0b1 100644 --- a/bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/ServicePermission.java +++ b/bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/ServicePermission.java @@ -1,5 +1,5 @@ /* - * Copyright (c) OSGi Alliance (2000, 2016). All Rights Reserved. + * Copyright (c) OSGi Alliance (2000, 2017). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -562,7 +562,7 @@ public final class ServicePermission extends BasicPermission { AccessController.doPrivileged(new PrivilegedAction() { @Override public Void run() { - props.put("id", new Long(bundle.getBundleId())); + props.put("id", Long.valueOf(bundle.getBundleId())); props.put("location", bundle.getLocation()); String name = bundle.getSymbolicName(); if (name != null) { diff --git a/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/Logger.java b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/Logger.java index a9cc36a67..863d1404f 100644 --- a/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/Logger.java +++ b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/Logger.java @@ -105,6 +105,15 @@ public interface Logger { */ void trace(String format, Object... arguments); + /** + * Call the specified function if logging enabled for the + * {@link LogLevel#TRACE} level. + * + * @param consumer The function to call passing this Logger. + * @throws E An exception thrown by the function. + */ + void trace(LoggerConsumer consumer) throws E; + /** * Is logging enabled for the {@link LogLevel#DEBUG} level? * @@ -145,6 +154,15 @@ public interface Logger { */ void debug(String format, Object... arguments); + /** + * Call the specified function if logging enabled for the + * {@link LogLevel#DEBUG} level. + * + * @param consumer The function to call passing this Logger. + * @throws E An exception thrown by the function. + */ + void debug(LoggerConsumer consumer) throws E; + /** * Is logging enabled for the {@link LogLevel#INFO} level? * @@ -185,6 +203,15 @@ public interface Logger { */ void info(String format, Object... arguments); + /** + * Call the specified function if logging enabled for the + * {@link LogLevel#INFO} level. + * + * @param consumer The function to call passing this Logger. + * @throws E An exception thrown by the function. + */ + void info(LoggerConsumer consumer) throws E; + /** * Is logging enabled for the {@link LogLevel#WARN} level? * @@ -225,6 +252,15 @@ public interface Logger { */ void warn(String format, Object... arguments); + /** + * Call the specified function if logging enabled for the + * {@link LogLevel#WARN} level. + * + * @param consumer The function to call passing this Logger. + * @throws E An exception thrown by the function. + */ + void warn(LoggerConsumer consumer) throws E; + /** * Is logging enabled for the {@link LogLevel#ERROR} level? * @@ -265,6 +301,15 @@ public interface Logger { */ void error(String format, Object... arguments); + /** + * Call the specified function if logging enabled for the + * {@link LogLevel#ERROR} level. + * + * @param consumer The function to call passing this Logger. + * @throws E An exception thrown by the function. + */ + void error(LoggerConsumer consumer) throws E; + /** * Log a message at the {@link LogLevel#AUDIT} level. * diff --git a/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/LoggerConsumer.java b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/LoggerConsumer.java new file mode 100644 index 000000000..82201dc52 --- /dev/null +++ b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/LoggerConsumer.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) OSGi Alliance (2017). All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.osgi.service.log; + +import org.osgi.annotation.versioning.ConsumerType; + +/** + * A function that accepts a {@link Logger} argument and produces no result. + *

+ * This is a functional interface and can be used as the assignment target for a + * lambda expression or method reference. + * + * @param The type of the exception that may be thrown. + * @ThreadSafe + * @since 1.4 + * @author $Id$ + */ +@ConsumerType +@FunctionalInterface +public interface LoggerConsumer { + /** + * Applies this function to the specified {@link Logger}. + * + * @param l The {@link Logger} input to this function. + * @throws E An exception thrown by the method. + */ + void accept(Logger l) throws E; +} diff --git a/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/resolver/ResolveContext.java b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/resolver/ResolveContext.java index 887cb785c..5a3d32eb9 100644 --- a/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/resolver/ResolveContext.java +++ b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/resolver/ResolveContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) OSGi Alliance (2011, 2016). All Rights Reserved. + * Copyright (c) OSGi Alliance (2011, 2017). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/resolver/Resolver.java b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/resolver/Resolver.java index b51c25d7a..86bff0073 100644 --- a/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/resolver/Resolver.java +++ b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/resolver/Resolver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) OSGi Alliance (2006, 2016). All Rights Reserved. + * Copyright (c) OSGi Alliance (2006, 2017). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/bundles/org.eclipse.osgi/osgi/src/org/osgi/util/tracker/BundleTracker.java b/bundles/org.eclipse.osgi/osgi/src/org/osgi/util/tracker/BundleTracker.java index e00c3bf5c..ac16c218a 100644 --- a/bundles/org.eclipse.osgi/osgi/src/org/osgi/util/tracker/BundleTracker.java +++ b/bundles/org.eclipse.osgi/osgi/src/org/osgi/util/tracker/BundleTracker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) OSGi Alliance (2007, 2016). All Rights Reserved. + * Copyright (c) OSGi Alliance (2007, 2017). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. -- cgit v1.2.3