FELIX-110 completion of the current Felix SCR implementation to take into account components <properties> elements
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@580966 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/BundleComponentActivator.java b/scr/src/main/java/org/apache/felix/scr/BundleComponentActivator.java
index 3080aa3..4fb57c8 100644
--- a/scr/src/main/java/org/apache/felix/scr/BundleComponentActivator.java
+++ b/scr/src/main/java/org/apache/felix/scr/BundleComponentActivator.java
@@ -1,4 +1,4 @@
-/*
+/*
* 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
@@ -77,7 +77,7 @@
* register components with to ensure uniqueness of component names
* and to ensure configuration updates.
* @param context The bundle context owning the components
- *
+ *
* @throws ComponentException if any error occurrs initializing this class
*/
BundleComponentActivator( ComponentRegistry componentRegistry, ComponentActorThread componentActor,
@@ -114,16 +114,16 @@
/**
* Gets the MetaData location, parses the meta data and requests the processing
* of binder instances
- *
+ *
* @param descriptorLocations A comma separated list of locations of
* component descriptors. This must not be <code>null</code>.
- *
+ *
* @throws IllegalStateException If the bundle has already been uninstalled.
*/
private void initialize( String descriptorLocations )
{
- // 112.4.1: The value of the the header is a comma separated list of XML entries within the Bundle
+ // 112.4.1: The value of the the header is a comma separated list of XML entries within the Bundle
StringTokenizer st = new StringTokenizer( descriptorLocations, ", " );
while ( st.hasMoreTokens() )
@@ -146,7 +146,7 @@
stream = descriptorURL.openStream();
BufferedReader in = new BufferedReader( new InputStreamReader( stream ) );
- XmlHandler handler = new XmlHandler();
+ XmlHandler handler = new XmlHandler( m_context.getBundle() );
KXml2SAXParser parser;
parser = new KXml2SAXParser( in );
@@ -334,8 +334,8 @@
* then starting a thread to actually enable all components found.
* <p>
* If no component matching the given name is found the thread is not
- * started and the method does nothing.
- *
+ * started and the method does nothing.
+ *
* @param name The name of the component to enable or <code>null</code> to
* enable all components.
*/
@@ -367,8 +367,8 @@
* then starting a thread to actually disable all components found.
* <p>
* If no component matching the given name is found the thread is not
- * started and the method does nothing.
- *
+ * started and the method does nothing.
+ *
* @param name The name of the component to disable or <code>null</code> to
* disable all components.
*/
@@ -401,10 +401,10 @@
* an array containing a single component manager matching the name is
* returned if one is registered. Finally, if no component manager with the
* given name is registered, <code>null</code> is returned.
- *
+ *
* @param name The name of the component manager to return or
* <code>null</code> to return an array of all component managers.
- *
+ *
* @return An array containing one or more component managers according
* to the <code>name</code> parameter or <code>null</code> if no
* component manager with the given name is currently registered.
@@ -443,7 +443,7 @@
* Schedules the given <code>task</code> for asynchrounous execution or
* synchronously runs the task if the thread is not running. If this instance
* is {@link #isActive() not active}, the task is not executed.
- *
+ *
* @param task The component task to execute
*/
void schedule( Runnable task )
@@ -482,7 +482,7 @@
* Method to actually emit the log message. If the LogService is available,
* the message will be logged through the LogService. Otherwise the message
* is logged to stdout (or stderr in case of LOG_ERROR level messages),
- *
+ *
* @param level The log level to log the message at
* @param message The message to log
* @param ex An optional <code>Throwable</code> whose stack trace is written,
diff --git a/scr/src/main/java/org/apache/felix/scr/XmlHandler.java b/scr/src/main/java/org/apache/felix/scr/XmlHandler.java
index 78b0613..338e44d 100644
--- a/scr/src/main/java/org/apache/felix/scr/XmlHandler.java
+++ b/scr/src/main/java/org/apache/felix/scr/XmlHandler.java
@@ -19,12 +19,18 @@
package org.apache.felix.scr;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.Properties;
import org.apache.felix.scr.parser.KXml2SAXHandler;
import org.apache.felix.scr.parser.ParseException;
+import org.osgi.framework.Bundle;
/**
@@ -36,6 +42,9 @@
public static final String NAMESPACE_URI = "http://www.osgi.org/xmlns/scr/v1.0.0";
+ // the bundle containing the XML resource being parsed
+ private Bundle m_bundle;
+
// A reference to the current component
private ComponentMetadata m_currentComponent;
@@ -55,6 +64,14 @@
protected String overrideNamespace;
+ // creates an instance with the bundle owning the component descriptor
+ // file parsed by this instance
+ XmlHandler( Bundle bundle )
+ {
+ m_bundle = bundle;
+ }
+
+
/**
* Method called when a tag opens
*
@@ -124,7 +141,7 @@
// Set the implementation class name (mandatory)
m_currentComponent.setImplementationClassName( attrib.getProperty( "class" ) );
}
- // 112.4.5 Properties and Property Elements
+ // 112.4.5 [...] Property Elements
else if ( localName.equals( "property" ) )
{
PropertyMetadata prop = new PropertyMetadata();
@@ -149,11 +166,11 @@
// hold the metadata pending
m_pendingProperty = prop;
}
- // TODO: treat the case where a properties file name is provided (p. 292)
}
+ // 112.4.5 Properties [...] Elements
else if ( localName.equals( "properties" ) )
{
- // TODO: implement the properties tag
+ readPropertiesEntry( attrib.getProperty( "entry" ) );
}
// 112.4.6 Service Element
else if ( localName.equals( "service" ) )
@@ -293,4 +310,67 @@
{
// Not used
}
+
+
+ /**
+ * Reads the name property file from the bundle owning this descriptor. All
+ * properties read from the properties file are added to the current
+ * component's property meta data list.
+ *
+ * @param entryName The name of the bundle entry containing the propertes
+ * to be added. This must not be <code>null</code>.
+ *
+ * @throws ParseException If the entry name is <code>null</code> or no
+ * entry with the given name exists in the bundle or an error occurrs
+ * reading the properties file.
+ */
+ private void readPropertiesEntry( String entryName ) throws ParseException
+ {
+ if ( entryName == null )
+ {
+ throw new ParseException( "Missing entry attribute of properties element", null );
+ }
+
+ URL entryURL = m_bundle.getEntry( entryName );
+ if ( entryURL == null )
+ {
+ throw new ParseException( "Missing bundle entry " + entryName, null );
+ }
+
+ Properties props = new Properties();
+ InputStream entryStream = null;
+ try
+ {
+ entryStream = entryURL.openStream();
+ props.load( entryStream );
+ }
+ catch ( IOException ioe )
+ {
+ throw new ParseException( "Failed to read properties entry " + entryName, ioe );
+ }
+ finally
+ {
+ if ( entryStream != null )
+ {
+ try
+ {
+ entryStream.close();
+ }
+ catch ( IOException ignore )
+ {
+ // don't care
+ }
+ }
+ }
+
+ // create PropertyMetadata for the properties from the file
+ for ( Iterator pi = props.entrySet().iterator(); pi.hasNext(); )
+ {
+ Map.Entry pEntry = ( Map.Entry ) pi.next();
+ PropertyMetadata prop = new PropertyMetadata();
+ prop.setName( String.valueOf( pEntry.getKey() ) );
+ prop.setValue( String.valueOf( pEntry.getValue() ) );
+ m_currentComponent.addProperty( prop );
+ }
+ }
}