FELIX-1436 Ensure duplicate implementation and/or service elements render
the descriptor invalid. Include unit tests for this.
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@799809 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/metadata/ComponentMetadata.java b/scr/src/main/java/org/apache/felix/scr/impl/metadata/ComponentMetadata.java
index cb24da7..173a6ac 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/metadata/ComponentMetadata.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/metadata/ComponentMetadata.java
@@ -49,6 +49,12 @@
// set of valid configuration policy settings
private static final Set CONFIGURATION_POLICY_VALID;
+ // marker value indicating duplicate implementation class setting
+ private static final String IMPLEMENTATION_CLASS_DUPLICATE = "icd";
+
+ // marker value indicating duplicate service setting
+ private static final ServiceMetadata SERVICE_DUPLICATE = new ServiceMetadata();
+
// the namespace code of the namespace declaring this component, this is
// one of the XmlHandler.DS_VERSION_* constants
private final int m_namespaceCode;
@@ -186,7 +192,16 @@
{
return;
}
- m_implementationClassName = implementationClassName;
+
+ // set special flag value if implementation class is already set
+ if ( m_implementationClassName != null )
+ {
+ m_implementationClassName = IMPLEMENTATION_CLASS_DUPLICATE;
+ }
+ else
+ {
+ m_implementationClassName = implementationClassName;
+ }
}
@@ -284,7 +299,16 @@
{
return;
}
- m_service = service;
+
+ // set special flag value if implementation class is already set
+ if ( m_service != null )
+ {
+ m_service = SERVICE_DUPLICATE;
+ }
+ else
+ {
+ m_service = service;
+ }
}
@@ -550,6 +574,10 @@
{
throw validationFailure( "Implementation class name missing" );
}
+ else if ( m_implementationClassName == IMPLEMENTATION_CLASS_DUPLICATE )
+ {
+ throw validationFailure( "Implementation element must occur exactly once" );
+ }
// 112.4.3 configuration-policy (since DS 1.1)
if ( m_configurationPolicy == null )
@@ -614,7 +642,11 @@
m_propertyMetaData.clear();
// Check that the provided services are valid too
- if ( m_service != null )
+ if ( m_service == SERVICE_DUPLICATE )
+ {
+ throw validationFailure( "Service element must occur at most once" );
+ }
+ else if ( m_service != null )
{
m_service.validate( this );
}
diff --git a/scr/src/test/java/org/apache/felix/scr/impl/metadata/ComponentMetadataTest.java b/scr/src/test/java/org/apache/felix/scr/impl/metadata/ComponentMetadataTest.java
index 57f56d7..ba4b78a 100644
--- a/scr/src/test/java/org/apache/felix/scr/impl/metadata/ComponentMetadataTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/impl/metadata/ComponentMetadataTest.java
@@ -474,6 +474,72 @@
}
+ public void test_duplicate_implementation_ds10()
+ {
+ final ComponentMetadata cm = createComponentMetadata( Boolean.TRUE, null );
+ cm.setImplementationClassName( "second.implementation.class" );
+ try
+ {
+ cm.validate( logger );
+ fail( "Expect validation failure for duplicate implementation element" );
+ }
+ catch ( ComponentException ce )
+ {
+ // expected
+ }
+ }
+
+
+ public void test_duplicate_implementation_ds11()
+ {
+ final ComponentMetadata cm = createComponentMetadata11( Boolean.TRUE, null );
+ cm.setImplementationClassName( "second.implementation.class" );
+ try
+ {
+ cm.validate( logger );
+ fail( "Expect validation failure for duplicate implementation element" );
+ }
+ catch ( ComponentException ce )
+ {
+ // expected
+ }
+ }
+
+
+ public void test_duplicate_service_ds10()
+ {
+ final ComponentMetadata cm = createComponentMetadata( Boolean.TRUE, null );
+ cm.setService( createServiceMetadata( Boolean.TRUE ) );
+ cm.setService( createServiceMetadata( Boolean.TRUE ) );
+ try
+ {
+ cm.validate( logger );
+ fail( "Expect validation failure for duplicate service element" );
+ }
+ catch ( ComponentException ce )
+ {
+ // expected
+ }
+ }
+
+
+ public void test_duplicate_service_ds11()
+ {
+ final ComponentMetadata cm = createComponentMetadata11( Boolean.TRUE, null );
+ cm.setService( createServiceMetadata( Boolean.TRUE ) );
+ cm.setService( createServiceMetadata( Boolean.TRUE ) );
+ try
+ {
+ cm.validate( logger );
+ fail( "Expect validation failure for duplicate service element" );
+ }
+ catch ( ComponentException ce )
+ {
+ // expected
+ }
+ }
+
+
//---------- Helper methods
// Creates DS 1.0 Component Metadata
diff --git a/scr/src/test/java/org/apache/felix/scr/impl/metadata/XmlHandlerTest.java b/scr/src/test/java/org/apache/felix/scr/impl/metadata/XmlHandlerTest.java
index a206790..b659a54 100644
--- a/scr/src/test/java/org/apache/felix/scr/impl/metadata/XmlHandlerTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/impl/metadata/XmlHandlerTest.java
@@ -198,6 +198,74 @@
}
+ public void test_duplicate_implementation_class_10() throws Exception
+ {
+ final List metadataList10 = readMetadata( "/components_duplicate_implementation_10.xml" );
+ assertEquals( "Component Descriptors", 1, metadataList10.size() );
+ final ComponentMetadata cm10 = ( ComponentMetadata ) metadataList10.get( 0 );
+ try
+ {
+ cm10.validate( logger );
+ fail( "Expect validation failure for duplicate implementation element" );
+ }
+ catch ( ComponentException ce )
+ {
+ // expected
+ }
+ }
+
+
+ public void test_duplicate_implementation_class_11() throws Exception
+ {
+ final List metadataList11 = readMetadata( "/components_duplicate_implementation_11.xml" );
+ assertEquals( "Component Descriptors", 1, metadataList11.size() );
+ final ComponentMetadata cm11 = ( ComponentMetadata ) metadataList11.get( 0 );
+ try
+ {
+ cm11.validate( logger );
+ fail( "Expect validation failure for duplicate implementation element" );
+ }
+ catch ( ComponentException ce )
+ {
+ // expected
+ }
+ }
+
+
+ public void test_duplicate_service_10() throws Exception
+ {
+ final List metadataList10 = readMetadata( "/components_duplicate_service_10.xml" );
+ assertEquals( "Component Descriptors", 1, metadataList10.size() );
+ final ComponentMetadata cm10 = ( ComponentMetadata ) metadataList10.get( 0 );
+ try
+ {
+ cm10.validate( logger );
+ fail( "Expect validation failure for duplicate service element" );
+ }
+ catch ( ComponentException ce )
+ {
+ // expected
+ }
+ }
+
+
+ public void test_duplicate_service_11() throws Exception
+ {
+ final List metadataList11 = readMetadata( "/components_duplicate_service_11.xml" );
+ assertEquals( "Component Descriptors", 1, metadataList11.size() );
+ final ComponentMetadata cm11 = ( ComponentMetadata ) metadataList11.get( 0 );
+ try
+ {
+ cm11.validate( logger );
+ fail( "Expect validation failure for duplicate service element" );
+ }
+ catch ( ComponentException ce )
+ {
+ // expected
+ }
+ }
+
+
//---------- helper
private List readMetadata( String filename ) throws IOException, ComponentException, XmlPullParserException,
diff --git a/scr/src/test/resources/components_duplicate_implementation_10.xml b/scr/src/test/resources/components_duplicate_implementation_10.xml
new file mode 100644
index 0000000..2cfd478
--- /dev/null
+++ b/scr/src/test/resources/components_duplicate_implementation_10.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<components>
+ <scr:component name="components.duplicate.implementation.10"
+ xmlns:scr="http://www.osgi.org/xmlns/scr/v1.0.0">
+ <implementation class="components.duplicate.implementation.10.first" />
+ <implementation class="components.duplicate.implementation.10.second" />
+ </scr:component>
+</components>
diff --git a/scr/src/test/resources/components_duplicate_implementation_11.xml b/scr/src/test/resources/components_duplicate_implementation_11.xml
new file mode 100644
index 0000000..5f2cc38
--- /dev/null
+++ b/scr/src/test/resources/components_duplicate_implementation_11.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<components>
+ <scr:component name="components.duplicate.implementation.11"
+ xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0">
+ <implementation class="components.duplicate.implementation.11.first" />
+ <implementation class="components.duplicate.implementation.11.second" />
+ </scr:component>
+</components>
diff --git a/scr/src/test/resources/components_duplicate_service_10.xml b/scr/src/test/resources/components_duplicate_service_10.xml
new file mode 100644
index 0000000..dab7772
--- /dev/null
+++ b/scr/src/test/resources/components_duplicate_service_10.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<components>
+ <scr:component name="components.duplicate.service.10"
+ xmlns:scr="http://www.osgi.org/xmlns/scr/v1.0.0">
+ <implementation class="components.duplicate.implementation.10" />
+ <service>
+ <provide interface="if.service.first" />
+ </service>
+ <service>
+ <provide interface="if.service.second" />
+ </service>
+ </scr:component>
+</components>
diff --git a/scr/src/test/resources/components_duplicate_service_11.xml b/scr/src/test/resources/components_duplicate_service_11.xml
new file mode 100644
index 0000000..2356a11
--- /dev/null
+++ b/scr/src/test/resources/components_duplicate_service_11.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<components>
+ <scr:component name="components.duplicate.service.11"
+ xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0">
+ <implementation class="components.duplicate.implementation.11" />
+ <service>
+ <provide interface="if.service.first" />
+ </service>
+ <service>
+ <provide interface="if.service.second" />
+ </service>
+ </scr:component>
+</components>