Temporarily include bndlib 1.47 for testing purposes (not yet on central)

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1185095 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/bundleplugin/src/main/java/aQute/bnd/annotation/ConsumerType.java b/bundleplugin/src/main/java/aQute/bnd/annotation/ConsumerType.java
new file mode 100644
index 0000000..cbbc17b
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/annotation/ConsumerType.java
@@ -0,0 +1,14 @@
+package aQute.bnd.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * Adding this annotation to a type in an API package indicates the the owner of
+ * that package will not change this interface in a minor update. Any backward
+ * compatible change to this interface requires a major update of the version of
+ * this package.
+ * 
+ */
+@Retention(RetentionPolicy.CLASS) @Target(ElementType.TYPE) public @interface ConsumerType {
+
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/annotation/Export.java b/bundleplugin/src/main/java/aQute/bnd/annotation/Export.java
new file mode 100644
index 0000000..27ea389
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/annotation/Export.java
@@ -0,0 +1,30 @@
+package aQute.bnd.annotation;
+
+import java.lang.annotation.*;
+
+@Retention(RetentionPolicy.CLASS)
+@Target(ElementType.PACKAGE)
+public @interface Export {
+    String MANDATORY = "mandatory";
+    String OPTIONAL  = "optional";
+    String USES      = "uses";
+    String EXCLUDE   = "exclude";
+    String INCLUDE   = "include";
+
+    String[] mandatory() default "";
+
+    String[] optional() default "";
+
+    Class<?>[] exclude() default Object.class;
+
+    Class<?>[] include() default Object.class;
+    
+    /**
+     * Use {@link @Version} annotation instead
+     * @return
+     */
+    @Deprecated()
+    String version() default "";
+    
+    
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/annotation/ProviderType.java b/bundleplugin/src/main/java/aQute/bnd/annotation/ProviderType.java
new file mode 100644
index 0000000..15ee17e
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/annotation/ProviderType.java
@@ -0,0 +1,19 @@
+package aQute.bnd.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * This type is provided for convenience because it is the default. A change 
+ * in a provider type (that is all except Consumer types) can be changed with
+ * only a minor update to the package API version number.
+ * 
+ * This interface is similar to the Eclipse @noextend and @noimplement annotations.
+ * 
+ * 
+ * 
+ */
+@Retention(RetentionPolicy.CLASS)
+@Target(ElementType.TYPE)
+public @interface ProviderType {
+
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/annotation/UsePolicy.java b/bundleplugin/src/main/java/aQute/bnd/annotation/UsePolicy.java
new file mode 100644
index 0000000..36f0eaf
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/annotation/UsePolicy.java
@@ -0,0 +1,20 @@
+package aQute.bnd.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * This annotation can be applied to interface where an implementation should be
+ * treated as a use policy, not an implementation policy. Many package have
+ * interfaces that are very stable and can be maintained backward compatible for
+ * implementers during minor changes. For example, in Event Admin, the
+ * EventAdmin implementers should follow the minor version, e.g. [1.1,1.2), however,
+ * an implementer of EventHandler should not require such a small range. Therefore
+ * an interface like EventHandler should use this anotation.
+ */
+@Retention(RetentionPolicy.CLASS)
+@Target(ElementType.TYPE)
+@Deprecated
+public @interface UsePolicy {
+    String RNAME = "LaQute/bnd/annotation/UsePolicy;";
+
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/annotation/Version.java b/bundleplugin/src/main/java/aQute/bnd/annotation/Version.java
new file mode 100644
index 0000000..fae42b1
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/annotation/Version.java
@@ -0,0 +1,9 @@
+package aQute.bnd.annotation;
+
+import java.lang.annotation.*;
+
+@Retention(RetentionPolicy.CLASS)
+@Target({ElementType.PACKAGE})
+public @interface Version {
+	String value();
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/annotation/component/Activate.java b/bundleplugin/src/main/java/aQute/bnd/annotation/component/Activate.java
new file mode 100644
index 0000000..52284a0
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/annotation/component/Activate.java
@@ -0,0 +1,10 @@
+package aQute.bnd.annotation.component;
+
+import java.lang.annotation.*;
+
+@Retention(RetentionPolicy.CLASS)
+@Target(ElementType.METHOD)
+public @interface Activate {
+    String RNAME = "LaQute/bnd/annotation/component/Activate;";
+    
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/annotation/component/Attribute.java b/bundleplugin/src/main/java/aQute/bnd/annotation/component/Attribute.java
new file mode 100644
index 0000000..f089b75
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/annotation/component/Attribute.java
@@ -0,0 +1,10 @@
+package aQute.bnd.annotation.component;
+
+public @interface Attribute {
+	class C {}
+	
+	String name() default "";
+	String description() default "";
+	String[] options();
+	
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/annotation/component/Component.java b/bundleplugin/src/main/java/aQute/bnd/annotation/component/Component.java
new file mode 100644
index 0000000..1fb39d6
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/annotation/component/Component.java
@@ -0,0 +1,38 @@
+package aQute.bnd.annotation.component;
+
+import java.lang.annotation.*;
+
+@Retention(RetentionPolicy.CLASS) @Target(ElementType.TYPE) public @interface Component {
+	String	RNAME					= "LaQute/bnd/annotation/component/Component;";
+	String	PROVIDE					= "provide";
+	String	NAME					= "name";
+	String	FACTORY					= "factory";
+	String	SERVICEFACTORY			= "servicefactory";
+	String	IMMEDIATE				= "immediate";
+	String	CONFIGURATION_POLICY	= "configurationPolicy";
+	String	ENABLED					= "enabled";
+	String	PROPERTIES				= "properties";
+	String	VERSION					= "version";
+	String	DESIGNATE				= "designate";
+	String	DESIGNATE_FACTORY		= "designateFactory";
+
+	String name() default "";
+
+	Class<?>[] provide() default Object.class;
+
+	String factory() default "";
+
+	boolean servicefactory() default false;
+
+	boolean enabled() default true;
+
+	boolean immediate() default false;
+
+	ConfigurationPolicy configurationPolicy() default ConfigurationPolicy.optional;
+
+	String[] properties() default {};
+
+	Class<?> designate() default Object.class;
+
+	Class<?> designateFactory() default Object.class;
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/annotation/component/ConfigurationPolicy.java b/bundleplugin/src/main/java/aQute/bnd/annotation/component/ConfigurationPolicy.java
new file mode 100644
index 0000000..7651557
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/annotation/component/ConfigurationPolicy.java
@@ -0,0 +1,5 @@
+package aQute.bnd.annotation.component;
+
+public enum ConfigurationPolicy {
+    optional, require, ignore;
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/annotation/component/Deactivate.java b/bundleplugin/src/main/java/aQute/bnd/annotation/component/Deactivate.java
new file mode 100644
index 0000000..5858ea0
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/annotation/component/Deactivate.java
@@ -0,0 +1,10 @@
+package aQute.bnd.annotation.component;
+
+import java.lang.annotation.*;
+
+@Retention(RetentionPolicy.CLASS)
+@Target(ElementType.METHOD)
+public @interface Deactivate {
+    String RNAME = "LaQute/bnd/annotation/component/Deactivate;";
+
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/annotation/component/Modified.java b/bundleplugin/src/main/java/aQute/bnd/annotation/component/Modified.java
new file mode 100644
index 0000000..655a535
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/annotation/component/Modified.java
@@ -0,0 +1,10 @@
+package aQute.bnd.annotation.component;
+
+import java.lang.annotation.*;
+
+@Retention(RetentionPolicy.CLASS)
+@Target(ElementType.METHOD)
+public @interface Modified {
+    String RNAME = "LaQute/bnd/annotation/component/Modified;";
+
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/annotation/component/Reference.java b/bundleplugin/src/main/java/aQute/bnd/annotation/component/Reference.java
new file mode 100644
index 0000000..58894dd
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/annotation/component/Reference.java
@@ -0,0 +1,33 @@
+package aQute.bnd.annotation.component;
+
+import java.lang.annotation.*;
+
+@Retention(RetentionPolicy.CLASS)
+@Target(ElementType.METHOD)
+public @interface Reference {
+    String RNAME    = "LaQute/bnd/annotation/component/Reference;";
+    String NAME     = "name";
+    String SERVICE  = "service";
+    String OPTIONAL = "optional";
+    String MULTIPLE = "multiple";
+    String DYNAMIC  = "dynamic";
+    String TARGET   = "target";
+    String TYPE     = "type";
+    String UNBIND   = "unbind";
+
+    String name() default "";
+
+    Class<?> service() default Object.class;
+
+    boolean optional() default false;
+
+    boolean multiple() default false;
+
+    boolean dynamic() default false;
+
+    String target() default "";
+    
+    String unbind() default "";
+
+    char type() default 0;
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/annotation/component/packageinfo b/bundleplugin/src/main/java/aQute/bnd/annotation/component/packageinfo
new file mode 100644
index 0000000..ec0efd4
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/annotation/component/packageinfo
@@ -0,0 +1 @@
+version 1.43.1
diff --git a/bundleplugin/src/main/java/aQute/bnd/annotation/metatype/Configurable.java b/bundleplugin/src/main/java/aQute/bnd/annotation/metatype/Configurable.java
new file mode 100644
index 0000000..6dcf614
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/annotation/metatype/Configurable.java
@@ -0,0 +1,262 @@
+package aQute.bnd.annotation.metatype;
+
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.regex.*;
+
+public class Configurable<T> {
+
+	
+	
+	
+	public static <T> T createConfigurable(Class<T> c, Map<?, ?> properties) {
+		Object o = Proxy.newProxyInstance(c.getClassLoader(), new Class<?>[] { c },
+				new ConfigurableHandler(properties, c.getClassLoader()));
+		return c.cast(o);
+	}
+
+	public static <T> T createConfigurable(Class<T> c, Dictionary<?, ?> properties) {
+		Map<Object,Object> alt = new HashMap<Object,Object>();
+		for( Enumeration<?> e = properties.keys(); e.hasMoreElements(); ) {
+			Object key = e.nextElement();
+			alt.put(key, properties.get(key));
+		}
+		return createConfigurable(c, alt);
+	}
+
+	static class ConfigurableHandler implements InvocationHandler {
+		final Map<?, ?>	properties;
+		final ClassLoader			loader;
+
+		ConfigurableHandler(Map<?, ?> properties, ClassLoader loader) {
+			this.properties = properties;
+			this.loader = loader;
+		}
+
+		public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+			Meta.AD ad = method.getAnnotation(Meta.AD.class);
+			String id = Configurable.mangleMethodName(method.getName());
+
+			if (ad != null && !ad.id().equals(Meta.NULL))
+				id = ad.id();
+
+			Object o = properties.get(id);
+
+			if (o == null) {
+				if (ad != null) {
+					if (ad.required())
+						throw new IllegalStateException("Attribute is required but not set "
+								+ method.getName());
+
+					o = ad.deflt();
+					if (o.equals(Meta.NULL))
+						o = null;
+				}
+			}
+			if (o == null) {
+				if (method.getReturnType().isPrimitive()
+						|| Number.class.isAssignableFrom(method.getReturnType())) {
+
+					o = "0";
+				} else
+					return null;
+			}
+
+			return convert(method.getGenericReturnType(), o);
+		}
+
+		@SuppressWarnings( { "unchecked" }) public Object convert(Type type, Object o)
+				throws Exception {
+			if (type instanceof ParameterizedType) {
+				ParameterizedType pType = (ParameterizedType) type;
+				return convert(pType, o);
+			}
+
+			if (type instanceof GenericArrayType) {
+				GenericArrayType gType = (GenericArrayType) type;
+				return convertArray(gType.getGenericComponentType(), o);
+			}
+
+			Class<?> resultType = (Class<?>) type;
+
+			if (resultType.isArray()) {
+				return convertArray(resultType.getComponentType(), o);
+			}
+
+			Class<?> actualType = o.getClass();
+			if (actualType.isAssignableFrom(resultType))
+				return o;
+
+			if (resultType == boolean.class || resultType == Boolean.class) {
+				if ( actualType == boolean.class || actualType == Boolean.class)
+					return o;
+				
+				if (Number.class.isAssignableFrom(actualType)) {
+					double b = ((Number) o).doubleValue();
+					if (b == 0)
+						return false;
+					else
+						return true;
+				}
+				return true;
+				
+			} else if (resultType == byte.class || resultType == Byte.class) {
+				if (Number.class.isAssignableFrom(actualType))
+					return ((Number) o).byteValue();
+				resultType = Byte.class;
+			} else if (resultType == char.class) {
+				resultType = Character.class;
+			} else if (resultType == short.class) {
+				if (Number.class.isAssignableFrom(actualType))
+					return ((Number) o).shortValue();
+				resultType = Short.class;
+			} else if (resultType == int.class) {
+				if (Number.class.isAssignableFrom(actualType))
+					return ((Number) o).intValue();
+				resultType = Integer.class;
+			} else if (resultType == long.class) {
+				if (Number.class.isAssignableFrom(actualType))
+					return ((Number) o).longValue();
+				resultType = Long.class;
+			} else if (resultType == float.class) {
+				if (Number.class.isAssignableFrom(actualType))
+					return ((Number) o).floatValue();
+				resultType = Float.class;
+			} else if (resultType == double.class) {
+				if (Number.class.isAssignableFrom(actualType))
+					return ((Number) o).doubleValue();
+				resultType = Double.class;
+			}
+
+			if (resultType.isPrimitive())
+				throw new IllegalArgumentException("Unknown primitive: " + resultType);
+
+			if (Number.class.isAssignableFrom(resultType) && actualType == Boolean.class) {
+				Boolean b = (Boolean) o;
+				o = b ? "1" : "0";
+			} else if (actualType == String.class) {
+				String input = (String) o;
+				if (Enum.class.isAssignableFrom(resultType)) {
+					return Enum.valueOf((Class<Enum>) resultType, input);
+				}
+				if (resultType == Class.class && loader != null) {
+					return loader.loadClass(input);
+				}
+				if (resultType == Pattern.class) {
+					return Pattern.compile(input);
+				}
+			}
+
+			try {
+				Constructor<?> c = resultType.getConstructor(String.class);
+				return c.newInstance(o.toString());
+			} catch (Throwable t) {
+				// handled on next line
+			}
+			throw new IllegalArgumentException("No conversion to " + resultType + " from "
+					+ actualType + " value " + o);
+		}
+
+		private Object convert(ParameterizedType pType, Object o) throws InstantiationException,
+				IllegalAccessException, Exception {
+			Class<?> resultType = (Class<?>) pType.getRawType();
+			if (Collection.class.isAssignableFrom(resultType)) {
+				Collection<?> input = toCollection(o);
+				if (resultType.isInterface()) {
+					if (resultType == Collection.class || resultType == List.class)
+						resultType = ArrayList.class;
+					else if (resultType == Set.class || resultType == SortedSet.class)
+						resultType = TreeSet.class;
+					else if (resultType == Queue.class /*|| resultType == Deque.class*/)
+						resultType = LinkedList.class;
+					else if (resultType == Queue.class /*|| resultType == Deque.class*/)
+						resultType = LinkedList.class;
+					else
+						throw new IllegalArgumentException(
+								"Unknown interface for a collection, no concrete class found: "
+										+ resultType);
+				}
+				
+				@SuppressWarnings("unchecked") Collection<Object> result = (Collection<Object>) resultType
+						.newInstance();
+				Type componentType = pType.getActualTypeArguments()[0];
+
+				for (Object i : input) {
+					result.add(convert(componentType, i));
+				}
+				return result;
+			} else if (pType.getRawType() == Class.class) {
+				return loader.loadClass(o.toString());
+			}
+			throw new IllegalArgumentException("cannot convert to " + pType
+					+ " because it uses generics and is not a Collection");
+		}
+
+		Object convertArray(Type componentType, Object o) throws Exception {
+			Collection<?> input = toCollection(o);
+			Class<?> componentClass = getRawClass(componentType);
+			Object array = Array.newInstance(componentClass, input.size());
+
+			int i = 0;
+			for (Object next : input) {
+				Array.set(array, i++, convert(componentType, next));
+			}
+			return array;
+		}
+
+		private Class<?> getRawClass(Type type) {
+			if (type instanceof Class)
+				return (Class<?>) type;
+
+			if (type instanceof ParameterizedType)
+				return (Class<?>) ((ParameterizedType) type).getRawType();
+
+			throw new IllegalArgumentException(
+					"For the raw type, type must be ParamaterizedType or Class but is " + type);
+		}
+
+		private Collection<?> toCollection(Object o) {
+			if (o instanceof Collection)
+				return (Collection<?>) o;
+
+			if (o.getClass().isArray()) {
+				if ( o.getClass().getComponentType().isPrimitive()) {
+					int length = Array.getLength(o);
+					List<Object> result = new ArrayList<Object>(length);
+					for ( int i=0; i<length; i++) {
+						result.add( Array.get(o, i));
+					}
+					return result;
+				} else
+					return Arrays.asList((Object[]) o);
+			}
+
+			if ( o instanceof String) {
+				String s = (String)o;
+				if (s.indexOf('|')>0)
+					return Arrays.asList(s.split("\\|"));					
+			}
+			return Arrays.asList(o);
+		}
+
+	}
+	
+	
+	public static String mangleMethodName(String id) {
+		StringBuilder sb = new StringBuilder(id);
+		for ( int i =0; i<sb.length(); i++) {
+			char c  = sb.charAt(i);
+			boolean twice = i < sb.length()-1 && sb.charAt(i+1) ==c;
+			if ( c == '$' || c == '_') {
+				if ( twice )
+					sb.deleteCharAt(i+1);
+				else 
+					if ( c == '$')
+						sb.deleteCharAt(i--); // Remove dollars
+					else
+						sb.setCharAt(i, '.'); // Make _ into .
+			}				
+		}
+		return sb.toString();
+	}
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/annotation/metatype/Meta.java b/bundleplugin/src/main/java/aQute/bnd/annotation/metatype/Meta.java
new file mode 100644
index 0000000..a2686e5
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/annotation/metatype/Meta.java
@@ -0,0 +1,180 @@
+package aQute.bnd.annotation.metatype;
+
+import java.lang.annotation.*;
+
+/**
+ * The Metadata interface provides access to the properties that underly a
+ * Configurable interface. Any Configurable interface can implement this
+ * interface. The interface provides the annotations that can be used to create
+ * metatype objects.
+ * 
+ * @ConsumerInterface
+ */
+
+public interface Meta {
+	enum Type {
+		Boolean,
+		Byte,
+		Character,
+		Short,
+		Integer,
+		Long,
+		Float,
+		Double,
+		String,
+		Password
+	}
+
+	/**
+	 * Constant NULL for default usage
+	 */
+	final String	NULL	= "§NULL§";
+
+	/**
+	 * The OCD Annotation maps to the OCD element in the Metatype specification.
+	 * The only difference is that it is possible to create a Designate element
+	 * as well.
+	 * 
+	 */
+	@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @interface OCD {
+		/**
+		 * The name for this component. The default name is a the short class
+		 * name that us un-camel cased to make it more readable.
+		 * 
+		 * @return The name of this component
+		 */
+		String name() default NULL;
+
+		/**
+		 * The id of the component. Default the name of the class in FQN
+		 * notation but with nested classes using the $ as separator (not .).
+		 * 
+		 * The Felix webconsole always uses this id as the PID and not the pid
+		 * in the Designate element. Reported as an error.
+		 * 
+		 * @return the id
+		 */
+		String id() default NULL;
+
+		/**
+		 * The localization prefix. The default localization prefix is the name
+		 * of the class with a $ separator for nested classes.
+		 * 
+		 * @return the localization prefix.
+		 */
+		String localization() default NULL;
+
+		/**
+		 * A description for this ocd. The default is empty.
+		 * 
+		 * @return the description
+		 */
+		String description() default NULL;
+
+		/**
+		 * Defines if this is for a factory or not.
+		 */
+		boolean factory() default false;
+	}
+
+	/**
+	 * The AD element in the Metatype specification.
+	 * 
+	 */
+	@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @interface AD {
+		/**
+		 * A description of the attribute. Default is empty.
+		 * 
+		 * @return The description of the attribute.
+		 */
+		String description() default NULL;
+
+		/**
+		 * The name of the attribute. By default the un-camel cased version of
+		 * the method name.
+		 * 
+		 * @return the name
+		 */
+		String name() default NULL;
+
+		/**
+		 * The id of the attribute. By default the name of the method. The id is
+		 * the key used to access the properties. This is the reason the AD is a
+		 * runtime annotation so the runtime can find the proper key.
+		 * 
+		 * @return the id
+		 */
+		String id() default NULL;
+
+		/**
+		 * The type of the field. This must be one of the basic types in the
+		 * metatype specification. By default, the type is derived from the
+		 * return type of the method. This includes most collections and arrays.
+		 * Unrecognized types are defaulted to String.
+		 * 
+		 * @return the type to be used.
+		 */
+		Type type() default Type.String;
+
+		/**
+		 * The cardinality of the attribute. If not explicitly set it will be
+		 * derived from the attributes return type. Collections return
+		 * Integer.MIN_VALUE and arrays use Integer.MAX_VALUE.
+		 * 
+		 * If a single string needs to be converted to a Collection or array
+		 * then the | will be used as a separator to split the line.
+		 * 
+		 * @return the cardinality of the attribute
+		 */
+		int cardinality() default 0;
+
+		/**
+		 * The minimum value. This string must be converted to the attribute
+		 * type before comparison takes place.
+		 * 
+		 * @return the min value
+		 */
+		String min() default NULL;
+
+		/**
+		 * The maximum value. This string must be converted to the attribute
+		 * type before comparison takes place.
+		 * 
+		 * @return the max value
+		 */
+		String max() default NULL;
+
+		/**
+		 * The default value. This value must be converted to the return type of
+		 * the attribute. For multi valued returns use the | as separator.
+		 * 
+		 * @return the default value
+		 */
+		String deflt() default NULL;
+
+		/**
+		 * Indicates that this attribute is required. By default attributes are
+		 * required.
+		 * 
+		 * @return
+		 */
+		boolean required() default true;
+
+		/**
+		 * Provide labels for options. These labels must match the values. If no
+		 * labels are set, the un-cameled version of the values are used (if
+		 * they are set of course).
+		 * 
+		 * @return the option labels
+		 */
+		String[] optionLabels() default NULL;
+
+		/**
+		 * The values of options. If not set and the return type is an enum
+		 * class then the values will be derived from this return type.
+		 * 
+		 * @return the option labels
+		 */
+		String[] optionValues() default NULL;
+	}
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/annotation/metatype/packageinfo b/bundleplugin/src/main/java/aQute/bnd/annotation/metatype/packageinfo
new file mode 100644
index 0000000..ec0efd4
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/annotation/metatype/packageinfo
@@ -0,0 +1 @@
+version 1.43.1
diff --git a/bundleplugin/src/main/java/aQute/bnd/annotation/packageinfo b/bundleplugin/src/main/java/aQute/bnd/annotation/packageinfo
new file mode 100644
index 0000000..ec0efd4
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/annotation/packageinfo
@@ -0,0 +1 @@
+version 1.43.1