added MetaType support in DependencyManager API
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@919860 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/dependencymanager/core/pom.xml b/dependencymanager/core/pom.xml
index 6acd83c..e16724e 100644
--- a/dependencymanager/core/pom.xml
+++ b/dependencymanager/core/pom.xml
@@ -54,7 +54,7 @@
<Bundle-Vendor>The Apache Software Foundation</Bundle-Vendor>
<Export-Package>org.apache.felix.dm;version="3.0.0",org.apache.felix.dm.service;version="3.0.0",org.apache.felix.dm.management;version="3.0.0",org.apache.felix.dm.dependencies;version="3.0.0",org.apache.felix.dm.resources;version="3.0.0"</Export-Package>
<Import-Package>!org.apache.felix.dm,!org.apache.felix.dm.service,!org.apache.felix.dm.management,!org.apache.felix.dm.dependencies,!org.apache.felix.dm.resources,*</Import-Package>
- <Private-Package>org.apache.felix.dm.impl,org.apache.felix.dm.impl.dependencies,org.apache.felix.dm.impl.tracker</Private-Package>
+ <Private-Package>org.apache.felix.dm.impl,org.apache.felix.dm.impl.dependencies,org.apache.felix.dm.impl.tracker,org.apache.felix.dm.impl.metatype</Private-Package>
<!-- Uncomment this line to include source code in the bundle.-->
<Include-Resource>src/main/java</Include-Resource>
<!-- -->
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyActivatorBase.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyActivatorBase.java
index 03c5738..cab04b6 100644
--- a/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyActivatorBase.java
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyActivatorBase.java
@@ -23,6 +23,7 @@
import org.apache.felix.dm.dependencies.BundleDependency;
import org.apache.felix.dm.dependencies.ConfigurationDependency;
+import org.apache.felix.dm.dependencies.PropertyMetaData;
import org.apache.felix.dm.dependencies.ResourceDependency;
import org.apache.felix.dm.dependencies.ServiceDependency;
import org.apache.felix.dm.dependencies.TemporalServiceDependency;
@@ -134,6 +135,14 @@
public ConfigurationDependency createConfigurationDependency() {
return m_manager.createConfigurationDependency();
}
+
+ /**
+ * Creates a new configuration property MetaData.
+ * @return a new configuration property MetaData
+ */
+ public PropertyMetaData createPropertyMetaData() {
+ return m_manager.createPropertyMetaData();
+ }
/**
* Creates a new bundle dependency.
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java
index 65b97b7..981c13f 100644
--- a/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java
@@ -25,6 +25,7 @@
import org.apache.felix.dm.dependencies.BundleDependency;
import org.apache.felix.dm.dependencies.ConfigurationDependency;
+import org.apache.felix.dm.dependencies.PropertyMetaData;
import org.apache.felix.dm.dependencies.ResourceDependency;
import org.apache.felix.dm.dependencies.ServiceDependency;
import org.apache.felix.dm.dependencies.TemporalServiceDependency;
@@ -39,6 +40,7 @@
import org.apache.felix.dm.impl.dependencies.ResourceDependencyImpl;
import org.apache.felix.dm.impl.dependencies.ServiceDependencyImpl;
import org.apache.felix.dm.impl.dependencies.TemporalServiceDependencyImpl;
+import org.apache.felix.dm.impl.metatype.PropertyMetaDataImpl;
import org.apache.felix.dm.resources.Resource;
import org.apache.felix.dm.service.Service;
import org.osgi.framework.BundleContext;
@@ -136,6 +138,14 @@
}
/**
+ * Creates a new configuration property MetaData.
+ * @return a new Configuration property MetaData.
+ */
+ public PropertyMetaData createPropertyMetaData() {
+ return new PropertyMetaDataImpl();
+ }
+
+ /**
* Creates a new bundle dependency.
*
* @return
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/dependencies/ConfigurationDependency.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/dependencies/ConfigurationDependency.java
index bd165c3..06b2bfa 100644
--- a/dependencymanager/core/src/main/java/org/apache/felix/dm/dependencies/ConfigurationDependency.java
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/dependencies/ConfigurationDependency.java
@@ -11,23 +11,7 @@
*/
package org.apache.felix.dm.dependencies;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Dictionary;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Properties;
-import java.util.Set;
-
-import org.apache.felix.dm.dependencies.Dependency;
-import org.apache.felix.dm.impl.Logger;
import org.apache.felix.dm.management.ServiceComponentDependency;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-import org.osgi.framework.ServiceRegistration;
-import org.osgi.service.cm.ConfigurationException;
-import org.osgi.service.cm.ManagedService;
/**
* Configuration dependency that can track the availability of a (valid) configuration. To use
@@ -61,4 +45,29 @@
* service properties specified directly are merged with these.
*/
ConfigurationDependency setPropagate(boolean propagate);
+
+ /**
+ * The label used to display the tab name (or section) where the properties are displayed. Example: "Printer Service".
+ * @return The label used to display the tab name where the properties are displayed (may be localized)
+ */
+ ConfigurationDependency setHeading(String heading);
+
+ /**
+ * A human readable description of the PID this annotation is associated with. Example: "Configuration for the PrinterService bundle".
+ * @return A human readable description of the PID this annotation is associated with (may be localized)
+ */
+ ConfigurationDependency setDescription(String description);
+
+ /**
+ * Points to the basename of the Properties file that can localize the Meta Type informations.
+ * By default, (e.g. <code>setLocalization("person")</code> would match person_du_NL.properties in the root bundle directory.
+ * The default localization base name for the properties is OSGI-INF/l10n/bundle, but can
+ * be overridden by the manifest Bundle-Localization header (see core specification, in section Localization on page 68).
+ */
+ ConfigurationDependency setLocalization(String path);
+
+ /**
+ * Add Configuration MetaData
+ */
+ ConfigurationDependency add(PropertyMetaData properties);
}
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/dependencies/PropertyMetaData.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/dependencies/PropertyMetaData.java
new file mode 100644
index 0000000..743c115
--- /dev/null
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/dependencies/PropertyMetaData.java
@@ -0,0 +1,72 @@
+package org.apache.felix.dm.dependencies;
+
+public interface PropertyMetaData
+{
+ /**
+ * The label used to display the property. Example: "Log Level".
+ * @return The label used to display the property (may be localized)
+ */
+ PropertyMetaData setHeading(String heading);
+
+ /**
+ * The key of a ConfigurationAdmin property. Example: "printer.logLevel"
+ * @return The Configuration Admin property name
+ */
+ PropertyMetaData setId(String id);
+
+ /**
+ * Return the property primitive type. If must be either one of the following types:<p>
+ * <ul>
+ * <li>String.class</li>
+ * <li>Long.class</li>
+ * <li>Integer.class</li>
+ * <li>Character.class</li>
+ * <li>Byte.class</li>
+ * <li>Double.class</li>
+ * <li>Float.class</li>
+ * <li>Boolean.class</li>
+ * </ul>
+ */
+ PropertyMetaData setType(Class type);
+
+ /**
+ * Return a default for this property. The object must be of the appropriate type as defined by the cardinality and getType().
+ * The return type is a list of String objects that can be converted to the appropriate type. The cardinality of the return
+ * array must follow the absolute cardinality of this type. E.g. if the cardinality = 0, the array must contain 1 element.
+ * If the cardinality is 1, it must contain 0 or 1 elements. If it is -5, it must contain from 0 to max 5 elements. Note that
+ * the special case of a 0 cardinality, meaning a single value, does not allow arrays or vectors of 0 elements.
+ */
+ PropertyMetaData setDefaults(String[] defaults);
+
+ /**
+ * Returns the property description. The description may be localized and must describe the semantics of this type and any
+ * constraints. Example: "Select the log level for the Printer Service".
+ * @return The localized description of the definition.
+ */
+ PropertyMetaData setDescription(String description);
+
+ /**
+ * Return the cardinality of this property. The OSGi environment handles multi valued properties in arrays ([]) or in Vector objects.
+ * The return value is defined as follows:<p>
+ *
+ * <ul>
+ * <li> x = Integer.MIN_VALUE no limit, but use Vector</li>
+ * <li> x < 0 -x = max occurrences, store in Vector</li>
+ * <li> x > 0 x = max occurrences, store in array []</li>
+ * <li> x = Integer.MAX_VALUE no limit, but use array []</li>
+ * <li> x = 0 1 occurrence required</li>
+ * </ul>
+ */
+ PropertyMetaData setCardinality(int cardinality);
+
+ /**
+ * Tells if this property is required or not.
+ */
+ PropertyMetaData setRequired(boolean required);
+
+ /**
+ * Return a list of valid options for this property (the labels may be localized).
+ * @return the list of valid options for this property.
+ */
+ PropertyMetaData addOption(String optionLabel, String optionValue);
+}
\ No newline at end of file
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ConfigurationDependencyImpl.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ConfigurationDependencyImpl.java
index 1446957..5588d68 100644
--- a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ConfigurationDependencyImpl.java
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ConfigurationDependencyImpl.java
@@ -28,7 +28,9 @@
import java.util.Set;
import org.apache.felix.dm.dependencies.ConfigurationDependency;
+import org.apache.felix.dm.dependencies.PropertyMetaData;
import org.apache.felix.dm.impl.Logger;
+import org.apache.felix.dm.impl.metatype.MetaTypeProviderImpl;
import org.apache.felix.dm.management.ServiceComponentDependency;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
@@ -67,6 +69,7 @@
private String m_callback;
private boolean m_isStarted;
private final Set m_updateInvokedCache = new HashSet();
+ private MetaTypeProviderImpl m_metaType;
public ConfigurationDependencyImpl(BundleContext context, Logger logger) {
m_context = context;
@@ -115,7 +118,11 @@
if (needsStarting) {
Properties props = new Properties();
props.put(Constants.SERVICE_PID, m_pid);
- m_registration = m_context.registerService(ManagedService.class.getName(), this, props);
+ ManagedService ms = this;
+ if (m_metaType != null) {
+ ms = m_metaType;
+ }
+ m_registration = m_context.registerService(ManagedService.class.getName(), ms, props);
}
}
@@ -307,4 +314,46 @@
public Dictionary getProperties() {
return getConfiguration();
}
+
+ public BundleContext getBundleContext() {
+ return m_context;
+ }
+
+ public Logger getLogger() {
+ return m_logger;
+ }
+
+ public ConfigurationDependency add(PropertyMetaData properties)
+ {
+ createMetaTypeImpl();
+ m_metaType.add(properties);
+ return this;
+ }
+
+ public ConfigurationDependency setDescription(String description)
+ {
+ createMetaTypeImpl();
+ m_metaType.setDescription(description);
+ return this;
+ }
+
+ public ConfigurationDependency setHeading(String heading)
+ {
+ createMetaTypeImpl();
+ m_metaType.setName(heading);
+ return this;
+ }
+
+ public ConfigurationDependency setLocalization(String path)
+ {
+ createMetaTypeImpl();
+ m_metaType.setLocalization(path);
+ return this;
+ }
+
+ private synchronized void createMetaTypeImpl() {
+ if (m_metaType == null) {
+ m_metaType = new MetaTypeProviderImpl(this);
+ }
+ }
}
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/metatype/AttributeDefinitionImpl.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/metatype/AttributeDefinitionImpl.java
new file mode 100644
index 0000000..3d4711e
--- /dev/null
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/metatype/AttributeDefinitionImpl.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.felix.dm.impl.metatype;
+
+import org.osgi.service.metatype.AttributeDefinition;
+
+public class AttributeDefinitionImpl implements AttributeDefinition
+{
+ private PropertyMetaDataImpl m_propertyMetaData;
+ private Resource m_resource;
+
+ public AttributeDefinitionImpl(PropertyMetaDataImpl propertyMetaData, Resource resource)
+ {
+ m_propertyMetaData = propertyMetaData;
+ m_resource = resource;
+ }
+
+ public int getCardinality()
+ {
+ return m_propertyMetaData.getCardinality();
+ }
+
+ public String[] getDefaultValue()
+ {
+ return m_propertyMetaData.getDefaults();
+ }
+
+ public String getDescription()
+ {
+ return m_resource.localize(m_propertyMetaData.getDescription());
+ }
+
+ public String getID()
+ {
+ return m_propertyMetaData.getId();
+ }
+
+ public String getName()
+ {
+ return m_resource.localize(m_propertyMetaData.getHeading());
+ }
+
+ public String[] getOptionLabels()
+ {
+ String[] labels = m_propertyMetaData.getOptionLabels();
+ if (labels != null)
+ {
+ for (int i = 0; i < labels.length; i++)
+ {
+ labels[i] = m_resource.localize(labels[i]);
+ }
+ }
+ return labels;
+ }
+
+ public String[] getOptionValues()
+ {
+ return m_propertyMetaData.getOptionValues();
+ }
+
+ public int getType()
+ {
+ return m_propertyMetaData.getType();
+ }
+
+ public String validate(String value)
+ {
+ return null;
+ }
+}
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/metatype/MetaTypeProviderImpl.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/metatype/MetaTypeProviderImpl.java
new file mode 100644
index 0000000..c5af035
--- /dev/null
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/metatype/MetaTypeProviderImpl.java
@@ -0,0 +1,265 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.felix.dm.impl.metatype;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Properties;
+import java.util.StringTokenizer;
+import java.util.TreeSet;
+
+import org.apache.felix.dm.dependencies.PropertyMetaData;
+import org.apache.felix.dm.impl.Logger;
+import org.apache.felix.dm.impl.dependencies.ConfigurationDependencyImpl;
+import org.osgi.framework.Constants;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+import org.osgi.service.log.LogService;
+import org.osgi.service.metatype.MetaTypeProvider;
+import org.osgi.service.metatype.ObjectClassDefinition;
+
+/**
+ * When a ConfigurationDepdendency is configured with properties metadata, we provide
+ * a specific ManagedService which also implements the MetaTypeProvider interface. This interface
+ * allows the MetaTypeService to retrieve our properties metadata, which will then be handled by webconsole.
+ */
+public class MetaTypeProviderImpl implements MetaTypeProvider, ManagedService
+{
+ private ConfigurationDependencyImpl m_configDependency;
+ private List m_propertiesMetaData = new ArrayList();
+ private String m_description;
+ private String m_heading;
+ private String m_localization;
+ private Map m_localesProperties = new HashMap();
+ private Logger m_logger;
+
+ public MetaTypeProviderImpl(ConfigurationDependencyImpl configurationDependency)
+ {
+ m_configDependency = configurationDependency;
+ m_logger = configurationDependency.getLogger();
+ // Set the default localization file base name (see core specification, in section Localization on page 68).
+ // By default, this file can be stored in OSGI-INF/l10n/bundle.properties (and corresponding localized version
+ // in OSGI-INF/l10n/bundle_en_GB_welsh.properties, OSGI-INF/l10n/bundle_en_GB.properties, etc ...
+ // This default localization property file name can be overriden using the PropertyMetaData.setLocalization method.
+ m_localization = (String) m_configDependency.getBundleContext().getBundle().getHeaders().get(
+ Constants.BUNDLE_LOCALIZATION);
+ if (m_localization == null)
+ {
+ m_localization = Constants.BUNDLE_LOCALIZATION_DEFAULT_BASENAME;
+ }
+ }
+
+ /**
+ * Registers the metatype information of a given configuration property
+ * @param property
+ */
+ public void add(PropertyMetaData property)
+ {
+ m_propertiesMetaData.add(property);
+ }
+
+ /**
+ * A human readable description of the PID this annotation is associated with. Example: "Configuration for the PrinterService bundle".
+ * @return A human readable description of the PID this annotation is associated with (may be localized)
+ */
+ public void setDescription(String description)
+ {
+ m_description = description;
+ }
+
+ /**
+ * The label used to display the tab name (or section) where the properties are displayed. Example: "Printer Service".
+ * @return The label used to display the tab name where the properties are displayed (may be localized)
+ */
+ public void setName(String heading)
+ {
+ m_heading = heading;
+ }
+
+ /**
+ * Points to the basename of the Properties file that can localize the Meta Type informations.
+ * By default, (e.g. <code>setLocalization("person")</code> would match person_du_NL.properties in the root bundle directory.
+ * The default localization base name for the properties is OSGI-INF/l10n/bundle, but can
+ * be overridden by the manifest Bundle-Localization header (see core specification, in section Localization on page 68).
+ */
+ public void setLocalization(String path)
+ {
+ if (path.endsWith(".properties"))
+ {
+ throw new IllegalArgumentException(
+ "path must point to the base name of the propertie file, "
+ + "excluding local suffixes. For example: "
+ + "foo/bar/person is valid and matches the property file \"foo/bar/person_bundle_en_GB_welsh.properties\"");
+ }
+ m_localization = path.startsWith("/") ? path.substring(1) : path;
+ }
+
+ // --------------- MetaTypeProvider interface -------------------------------------------------
+
+ /**
+ * Returns all the Locales our bundle is containing. For instance, if our bundle contains the following localization files:
+ * OSGI-INF/l10n/bundle_en_GB_welsh.properties and OSGI-INF/l10n/bundle_en_GB.properties, then this method will return
+ * "en_GB", "en_GB_welsh" ...
+ * @return the list of Locale supported by our bundle.
+ */
+ public String[] getLocales()
+ {
+ int lastSlash = m_localization.lastIndexOf("/");
+ String path = (lastSlash == -1) ? "/" : ("/" + m_localization.substring(0, lastSlash - 1));
+ String base = (lastSlash == -1) ? m_localization : m_localization.substring(lastSlash + 1);
+ Enumeration e = m_configDependency.getBundleContext().getBundle().findEntries(path,
+ base + "*.properties", false);
+ TreeSet set = new TreeSet();
+ while (e.hasMoreElements())
+ {
+ // We have found a locale property file in the form of "path/file[_language[_ country[_variation]].properties"
+ // And now, we have to get the "language[_country[_variation]]" part ...
+ URL url = (URL) e.nextElement();
+ String name = url.getPath();
+ name = name.substring(name.lastIndexOf("/") + 1);
+ int underscore = name.indexOf("_");
+ if (underscore != -1)
+ {
+ name = name.substring(underscore + 1, name.length() - ".properties".length());
+ }
+ if (name.length() > 0)
+ {
+ set.add(name);
+ }
+ }
+
+ String[] locales = (String[]) set.toArray(new String[set.size()]);
+ return locales.length == 0 ? null : locales;
+ }
+
+ /**
+ * Returns the ObjectClassDefinition for a given Pid/Locale.
+ */
+ public ObjectClassDefinition getObjectClassDefinition(String id, String locale)
+ {
+ try
+ {
+ // Check if the id matches our PID
+ if (!id.equals(m_configDependency.getName()))
+ {
+ m_configDependency.getLogger().log(LogService.LOG_ERROR,
+ "id " + id + " does not match pid " + m_configDependency.getName());
+ return null;
+ }
+
+ Properties localeProperties = getLocaleProperties(locale);
+ return new ObjectClassDefinitionImpl(m_configDependency.getName(), m_heading,
+ m_description, m_propertiesMetaData, new Resource(localeProperties));
+ }
+
+ catch (Throwable t)
+ {
+ m_configDependency.getLogger().log(
+ Logger.LOG_ERROR,
+ "Unexpected exception while geting ObjectClassDefinition for " + id + " (locale="
+ + locale + ")", t);
+ return null;
+ }
+ }
+
+ /**
+ * We also implements the ManagedService and we just delegates the configuration handling to
+ * our associated ConfigurationDependency.
+ */
+ public void updated(Dictionary properties) throws ConfigurationException
+ {
+ m_configDependency.updated(properties);
+ }
+
+ /**
+ * Gets the properties for a given Locale.
+ * @param locale
+ * @return
+ * @throws IOException
+ */
+ private synchronized Properties getLocaleProperties(String locale) throws IOException
+ {
+ locale = locale == null ? Locale.getDefault().toString() : locale;
+ Properties properties = (Properties) m_localesProperties.get(locale);
+ if (properties == null)
+ {
+ properties = new Properties();
+ URL url = m_configDependency.getBundleContext().getBundle().getEntry(
+ m_localization + ".properties");
+ if (url != null)
+ {
+ loadLocale(properties, url);
+ }
+
+ String path = m_localization;
+ StringTokenizer tok = new StringTokenizer(locale, "_");
+ while (tok.hasMoreTokens())
+ {
+ path += "_" + tok.nextToken();
+ url = m_configDependency.getBundleContext().getBundle().getEntry(path + ".properties");
+ if (url != null)
+ {
+ properties = new Properties(properties);
+ loadLocale(properties, url);
+ }
+ }
+
+ m_localesProperties.put(locale, properties);
+ }
+
+ return properties;
+ }
+
+ /**
+ * Loads a Locale Properties file.
+ * @param properties
+ * @param url
+ * @throws IOException
+ */
+ private void loadLocale(Properties properties, URL url) throws IOException
+ {
+ InputStream in = null;
+ try
+ {
+ in = url.openStream();
+ properties.load(in);
+ }
+ finally
+ {
+ if (in != null)
+ {
+ try
+ {
+ in.close();
+ }
+ catch (IOException ignored)
+ {
+ }
+ }
+ }
+ }
+}
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/metatype/ObjectClassDefinitionImpl.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/metatype/ObjectClassDefinitionImpl.java
new file mode 100644
index 0000000..47e28ff
--- /dev/null
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/metatype/ObjectClassDefinitionImpl.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.felix.dm.impl.metatype;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.osgi.service.metatype.AttributeDefinition;
+import org.osgi.service.metatype.ObjectClassDefinition;
+
+/**
+ * ObjectClassDefinition implementation.
+ */
+public class ObjectClassDefinitionImpl implements ObjectClassDefinition
+{
+ // Our OCD name (may be localized)
+ private String m_name;
+
+ // Our OCD description (may be localized)
+ private String m_description;
+
+ // Our OCD id
+ private String m_id;
+
+ // The list of Properties MetaData objects (from DependencyManager API)
+ private List m_propertiesMetaData;
+
+ // The localized resource that can be used when localizing some parameters
+ private Resource m_resource;
+
+ public ObjectClassDefinitionImpl(String id, String name, String description, List propertiesMetaData, Resource resource)
+ {
+ m_id = id;
+ m_name = name;
+ m_description = description;
+ m_propertiesMetaData = propertiesMetaData;
+ m_resource = resource;
+ }
+
+ // --------------------- ObjectClassDefinition ----------------------------------------
+
+ public AttributeDefinition[] getAttributeDefinitions(int filter)
+ {
+ List attrs = new ArrayList();
+ for (int i = 0; i < m_propertiesMetaData.size(); i++)
+ {
+ PropertyMetaDataImpl metaData = (PropertyMetaDataImpl) m_propertiesMetaData.get(i);
+ switch (filter)
+ {
+ case ObjectClassDefinition.ALL:
+ attrs.add(new AttributeDefinitionImpl(metaData, m_resource));
+ break;
+ case ObjectClassDefinition.OPTIONAL:
+ if (!metaData.isRequired())
+ {
+ attrs.add(new AttributeDefinitionImpl(metaData, m_resource));
+ }
+ break;
+ case ObjectClassDefinition.REQUIRED:
+ if (metaData.isRequired())
+ {
+ attrs.add(new AttributeDefinitionImpl(metaData, m_resource));
+ }
+ break;
+ }
+ }
+
+ AttributeDefinition[] array = new AttributeDefinitionImpl[attrs.size()];
+ return (AttributeDefinition[]) attrs.toArray(array);
+ }
+
+ public String getDescription()
+ {
+ return m_resource.localize(m_description);
+ }
+
+ public String getID()
+ {
+ return m_id;
+ }
+
+ public InputStream getIcon(int size) throws IOException
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public String getName()
+ {
+ return m_resource.localize(m_name);
+ }
+}
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/metatype/PropertyMetaDataImpl.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/metatype/PropertyMetaDataImpl.java
new file mode 100644
index 0000000..f64c093
--- /dev/null
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/metatype/PropertyMetaDataImpl.java
@@ -0,0 +1,224 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.felix.dm.impl.metatype;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.felix.dm.dependencies.PropertyMetaData;
+import org.osgi.service.metatype.AttributeDefinition;
+
+/**
+ * DependencyManager PropertyMetaData Implementation. This class describes meta informations regarding
+ * one given configuration property.
+ */
+public class PropertyMetaDataImpl implements PropertyMetaData
+{
+ /**
+ * List of option labels (may be localized)
+ */
+ List m_optionsLabels = new ArrayList();
+
+ /**
+ * List of option values
+ */
+ List m_optionsValues = new ArrayList();
+
+ /**
+ * Property cardinality.
+ * @see {@link AttributeDefinition#getCardinality()}
+ */
+ private int m_cardinality;
+
+ /**
+ * Valid default property values
+ */
+ private String[] m_defaults;
+
+ /**
+ * Property description.
+ */
+ private String m_description;
+
+ /**
+ * Property title.
+ */
+ private String m_heading;
+
+ /**
+ * Property unique Id
+ */
+ private String m_id;
+
+ /**
+ * Required flag.
+ */
+ private boolean m_required;
+
+ /**
+ * Property Type.
+ * @see {@link AttributeDefinition#getType()}
+ */
+ private int m_type = AttributeDefinition.STRING;
+
+ /**
+ * Mapping between java types and valid MetaType types.
+ * @see {@link AttributeDefinition#getType()}
+ */
+ private final static Map m_typeMapping = new HashMap()
+ {
+ {
+ put(Boolean.class, new Integer(AttributeDefinition.BOOLEAN));
+ put(Byte.class, new Integer(AttributeDefinition.BYTE));
+ put(Character.class, new Integer(AttributeDefinition.CHARACTER));
+ put(Double.class, new Integer(AttributeDefinition.FLOAT));
+ put(Integer.class, new Integer(AttributeDefinition.INTEGER));
+ put(Long.class, new Integer(AttributeDefinition.LONG));
+ put(Short.class, new Integer(AttributeDefinition.SHORT));
+ put(String.class, new Integer(AttributeDefinition.STRING));
+ }
+ };
+
+ public PropertyMetaData addOption(String optionLabel, String optionValue)
+ {
+ m_optionsLabels.add(optionLabel);
+ m_optionsValues.add(optionValue);
+ return this;
+ }
+
+ public PropertyMetaData setCardinality(int cardinality)
+ {
+ m_cardinality = cardinality;
+ return this;
+ }
+
+ public PropertyMetaData setDefaults(String[] defaults)
+ {
+ m_defaults = defaults;
+ return this;
+ }
+
+ public PropertyMetaData setDescription(String description)
+ {
+ m_description = description;
+ return this;
+ }
+
+ public PropertyMetaData setHeading(String heading)
+ {
+ m_heading = heading;
+ return this;
+ }
+
+ public PropertyMetaData setId(String id)
+ {
+ m_id = id;
+ return this;
+ }
+
+ public PropertyMetaData setRequired(boolean required)
+ {
+ m_required = required;
+ return this;
+ }
+
+ public PropertyMetaData setType(Class classType)
+ {
+ Integer type = (Integer) m_typeMapping.get(classType);
+ if (type == null)
+ {
+ throw new IllegalArgumentException("Invalid type: " + classType + ". Valid types are "
+ + m_typeMapping.keySet());
+ }
+ m_type = type.intValue();
+ return this;
+ }
+
+ public String[] getOptionLabels()
+ {
+ String[] optionLabels = new String[m_optionsLabels.size()];
+ return (String[]) m_optionsLabels.toArray(optionLabels);
+ }
+
+ public String[] getOptionValues()
+ {
+ String[] optionValues = new String[m_optionsValues.size()];
+ return (String[]) m_optionsValues.toArray(optionValues);
+ }
+
+ public int getCardinality()
+ {
+ return m_cardinality;
+ }
+
+ public String[] getDefaults()
+ {
+ return m_defaults;
+ }
+
+ public String getDescription()
+ {
+ return m_description;
+ }
+
+ public String getHeading()
+ {
+ return m_heading;
+ }
+
+ public String getId()
+ {
+ return m_id;
+ }
+
+ public boolean isRequired()
+ {
+ return m_required;
+ }
+
+ public int getType()
+ {
+ return m_type;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("cardinality=").append(m_cardinality);
+ sb.append("; defaults=");
+ for (int i = 0; i < m_defaults.length; i ++) {
+ sb.append(m_defaults[i]).append(" ");
+ }
+ sb.append("; description=").append(m_description);
+ sb.append("; heading=").append(m_heading);
+ sb.append("; id=").append(m_id);
+ sb.append("; required=").append(m_required);
+ sb.append("; type=").append(getType());
+ sb.append("; optionLabels=");
+ for (int i = 0; i < m_optionsLabels.size(); i ++) {
+ sb.append(m_optionsLabels.get(i)).append(" ");
+ }
+ sb.append("; optionValues=");
+ for (int i = 0; i < m_optionsValues.size(); i ++) {
+ sb.append(m_optionsValues.get(i)).append(" ");
+ }
+ return sb.toString();
+ }
+}
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/metatype/Resource.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/metatype/Resource.java
new file mode 100644
index 0000000..529e494
--- /dev/null
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/metatype/Resource.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.felix.dm.impl.metatype;
+
+import java.util.Properties;
+
+/**
+ * Helper class used to localize a given Property Meta Data.
+ */
+public class Resource
+{
+ private Properties m_properties;
+
+ public Resource(Properties properties) {
+ m_properties = properties;
+ }
+
+ public String localize(String param)
+ {
+ if (m_properties != null && param != null && param.startsWith("%"))
+ {
+ param = param.substring(1);
+ return m_properties.getProperty(param);
+ }
+ return param;
+ }
+}