| /* |
| * 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.metatype; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.util.Arrays; |
| import java.util.List; |
| |
| import org.osgi.service.metatype.AttributeDefinition; |
| import org.xmlpull.v1.XmlPullParserException; |
| |
| import junit.framework.TestCase; |
| |
| /** |
| * The <code>MetaDataReaderTest</code> class tests the |
| * <code>MetaDataReader</code> class. |
| * |
| * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a> |
| */ |
| public class MetaDataReaderTest extends TestCase |
| { |
| private MetaDataReader reader; |
| |
| @Override |
| protected void setUp() throws Exception |
| { |
| super.setUp(); |
| |
| reader = new MetaDataReader(); |
| } |
| |
| @Override |
| protected void tearDown() throws Exception |
| { |
| reader = null; |
| |
| super.tearDown(); |
| } |
| |
| public void testEmpty() throws IOException, XmlPullParserException |
| { |
| String empty = "<MetaData />"; |
| MetaData mti = read(empty); |
| |
| // Implicitly assume the lowest version... |
| assertEquals(MetaDataReader.NAMESPACE_1_0, mti.getNamespace()); |
| assertNull(mti.getLocalePrefix()); |
| assertNull(mti.getObjectClassDefinitions()); |
| } |
| |
| public void testOptionalAttributesInMetaData() throws IOException, XmlPullParserException |
| { |
| String name = "myattribute"; |
| String value = "working"; |
| String localization = "test"; |
| String empty = "<MetaData " + name + "=\"" + value + "\" localization=\"" + localization + "\" />"; |
| MetaData mti = read(empty); |
| |
| assertEquals(localization, mti.getLocalePrefix()); |
| assertNull(mti.getObjectClassDefinitions()); |
| assertNotNull(mti.getOptionalAttributes()); |
| assertEquals(1, mti.getOptionalAttributes().size()); |
| assertEquals(value, mti.getOptionalAttributes().get(name)); |
| } |
| |
| public void testWithNamespace_1_0_0() throws IOException, XmlPullParserException |
| { |
| String empty = "<metatype:MetaData xmlns:metatype=\"" + MetaDataReader.NAMESPACE_1_0 + "\" " + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ></metatype:MetaData>"; |
| MetaData mti = read(empty); |
| |
| assertNotNull(mti); |
| assertEquals(MetaDataReader.NAMESPACE_1_0, mti.getNamespace()); |
| assertNull(mti.getLocalePrefix()); |
| assertNull(mti.getObjectClassDefinitions()); |
| } |
| |
| public void testWithNamespace_1_1_0() throws IOException, XmlPullParserException |
| { |
| String empty = "<metatype:MetaData xmlns:metatype=\"" + MetaDataReader.NAMESPACE_1_1 + "\" " + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ></metatype:MetaData>"; |
| MetaData mti = read(empty); |
| |
| assertNotNull(mti); |
| assertEquals(MetaDataReader.NAMESPACE_1_1, mti.getNamespace()); |
| assertNull(mti.getLocalePrefix()); |
| assertNull(mti.getObjectClassDefinitions()); |
| } |
| |
| public void testWithNamespace_1_2_0() throws IOException, XmlPullParserException |
| { |
| String empty = "<metatype:MetaData xmlns:metatype=\"" + MetaDataReader.NAMESPACE_1_2 + "\" " + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ></metatype:MetaData>"; |
| MetaData mti = read(empty); |
| |
| assertNotNull(mti); |
| assertEquals(MetaDataReader.NAMESPACE_1_2, mti.getNamespace()); |
| assertNull(mti.getLocalePrefix()); |
| assertNull(mti.getObjectClassDefinitions()); |
| } |
| |
| public void testWithNamespace_1_3_0() throws IOException, XmlPullParserException |
| { |
| String empty = "<metatype:MetaData xmlns:metatype=\"" + MetaDataReader.NAMESPACE_1_3 + "\" " + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ></metatype:MetaData>"; |
| MetaData mti = read(empty); |
| |
| assertNotNull(mti); |
| assertEquals(MetaDataReader.NAMESPACE_1_3, mti.getNamespace()); |
| assertNull(mti.getLocalePrefix()); |
| assertNull(mti.getObjectClassDefinitions()); |
| } |
| |
| public void testWithNamespace_1_4_0() throws IOException, XmlPullParserException |
| { |
| String empty = "<metatype:MetaData xmlns:metatype=\"" + MetaDataReader.NAMESPACE_1_4 + "\" " + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ></metatype:MetaData>"; |
| MetaData mti = read(empty); |
| |
| assertNotNull(mti); |
| assertEquals(MetaDataReader.NAMESPACE_1_4, mti.getNamespace()); |
| assertNull(mti.getLocalePrefix()); |
| assertNull(mti.getObjectClassDefinitions()); |
| } |
| |
| public void testWithInvalidNamespaceUri() |
| { |
| String empty = "<metatype:MetaData xmlns:metatype=\"http://www.osgi.org/xmlns/datatype/v1.0.0\" " + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ></metatype:MetaData>"; |
| |
| try |
| { |
| read(empty); |
| fail("Parse failure expected for unsupported namespace URI"); |
| } |
| catch (IOException e) |
| { |
| // expected due to unsupported namespace URI |
| } |
| } |
| |
| public void testWithInvalidNamespaceName() |
| { |
| String empty = "<datatype:MetaData xmlns:metatype=\"http://www.osgi.org/xmlns/metatype/v1.0.0\" " + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ></datatype:MetaData>"; |
| |
| try |
| { |
| read(empty); |
| fail("Parse failure expected for undefined namespace prefix"); |
| } |
| catch (IOException e) |
| { |
| // expected due to undefined namespace prefix used |
| } |
| } |
| |
| public void testEmptyLocalization() throws IOException, XmlPullParserException |
| { |
| String testLoc = "OSGI-INF/folder/base"; |
| String empty = "<MetaData localization=\"" + testLoc + "\"/>"; |
| MetaData mti = read(empty); |
| |
| assertEquals(testLoc, mti.getLocalePrefix()); |
| } |
| |
| public void testSingleOCDOk() throws IOException, XmlPullParserException |
| { |
| String ocdName = "ocd0"; |
| String ocdId = "id.ocd0"; |
| String ocdDescription = "ocd0 description"; |
| |
| String empty = "<MetaData><OCD id=\"" + ocdId + "\" name=\"" + ocdName + "\" description=\"" + ocdDescription + "\"><AD id=\"attr\" type=\"String\" required=\"false\" /></OCD></MetaData>"; |
| MetaData mti = read(empty); |
| |
| assertNull(mti.getLocalePrefix()); |
| assertNotNull(mti.getObjectClassDefinitions()); |
| assertEquals(1, mti.getObjectClassDefinitions().size()); |
| |
| OCD ocd = (OCD) mti.getObjectClassDefinitions().values().iterator().next(); |
| assertEquals(ocdId, ocd.getID()); |
| assertEquals(ocdName, ocd.getName()); |
| assertEquals(ocdDescription, ocd.getDescription()); |
| |
| assertNotNull(ocd.getAttributeDefinitions()); |
| } |
| |
| /** |
| * FELIX-4665 - Default values can be empty. |
| */ |
| public void testAttributeWithDefaultValueOk() throws IOException, XmlPullParserException |
| { |
| String xml; |
| |
| xml = "<MetaData><OCD id=\"ocd\" name=\"ocd\"><AD id=\"attr\" type=\"String\" required=\"false\" default=\"\" /></OCD></MetaData>"; |
| MetaData mti = read(xml); |
| OCD ocd = (OCD) mti.getObjectClassDefinitions().get("ocd"); |
| AD ad = (AD) ocd.getAttributeDefinitions().get("attr"); |
| // Cardinality = 0, so *always* return a array with length 1... |
| assertTrue(Arrays.deepEquals(new String[] { "" }, ad.getDefaultValue())); |
| |
| xml = "<MetaData><OCD id=\"ocd\" name=\"ocd\"><AD id=\"attr\" cardinality=\"1\" type=\"String\" required=\"false\" /></OCD></MetaData>"; |
| mti = read(xml); |
| ocd = (OCD) mti.getObjectClassDefinitions().get("ocd"); |
| ad = (AD) ocd.getAttributeDefinitions().get("attr"); |
| // Cardinality = 1, return an array with *up to* 1 elements... |
| assertNull(ad.getDefaultValue()); |
| |
| xml = "<MetaData><OCD id=\"ocd\" name=\"ocd\"><AD id=\"attr\" cardinality=\"1\" type=\"String\" required=\"false\" default=\"\" /></OCD></MetaData>"; |
| mti = read(xml); |
| ocd = (OCD) mti.getObjectClassDefinitions().get("ocd"); |
| ad = (AD) ocd.getAttributeDefinitions().get("attr"); |
| // Cardinality = 1, return an array with *up to* 1 elements... |
| assertTrue(Arrays.deepEquals(new String[] { "" }, ad.getDefaultValue())); |
| |
| // The metatype spec defines that getDefaultValue should never have more entries than defined in its (non-zero) cardinality... |
| xml = "<MetaData><OCD id=\"ocd\" name=\"ocd\"><AD id=\"attr\" cardinality=\"1\" type=\"String\" required=\"false\" default=\",\" /></OCD></MetaData>"; |
| mti = read(xml); |
| ocd = (OCD) mti.getObjectClassDefinitions().get("ocd"); |
| ad = (AD) ocd.getAttributeDefinitions().get("attr"); |
| // Cardinality = 1, return an array with *up to* 1 elements... |
| assertTrue(Arrays.deepEquals(new String[] { "" }, ad.getDefaultValue())); |
| } |
| |
| /** |
| * FELIX-4644 - Enforce that we can only have one Object in a Designate element. |
| */ |
| public void testOCDWithoutADFail() throws IOException, XmlPullParserException |
| { |
| String ocdName = "ocd0"; |
| String ocdId = "id.ocd0"; |
| String ocdDescription = "ocd0 description"; |
| |
| String xml = "<MetaData><OCD id=\"" + ocdId + "\" name=\"" + ocdName + "\" description=\"" + ocdDescription + "\" /></MetaData>"; |
| |
| final MetaData md = read(xml); |
| assertNull(md.getObjectClassDefinitions()); |
| } |
| |
| /** |
| * FELIX-4644 - MetaType v1.3 allows OCDs without ADs. |
| */ |
| public void testOCDWithoutADOk_v13() throws IOException, XmlPullParserException |
| { |
| String ocdName = "ocd0"; |
| String ocdId = "id.ocd0"; |
| String ocdDescription = "ocd0 description"; |
| |
| String xml = "<metatype:MetaData xmlns:metatype=\"" + MetaDataReader.NAMESPACE_1_3 + "\" " + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ><OCD id=\"" + ocdId + "\" name=\"" |
| + ocdName + "\" description=\"" + ocdDescription + "\" /></metatype:MetaData>"; |
| |
| MetaData mti = read(xml); |
| |
| assertNull(mti.getLocalePrefix()); |
| assertNotNull(mti.getObjectClassDefinitions()); |
| assertEquals(1, mti.getObjectClassDefinitions().size()); |
| |
| OCD ocd = (OCD) mti.getObjectClassDefinitions().values().iterator().next(); |
| assertEquals(ocdId, ocd.getID()); |
| assertEquals(ocdName, ocd.getName()); |
| assertEquals(ocdDescription, ocd.getDescription()); |
| |
| assertNull(ocd.getAttributeDefinitions()); |
| } |
| |
| /** |
| * FELIX-4644 - Enforce that we can only have one Object in a Designate element. |
| */ |
| public void testDesignateWithoutObjectFail() throws IOException, XmlPullParserException |
| { |
| String ocdName = "ocd0"; |
| String ocdId = "id.ocd0"; |
| String ocdDescription = "ocd0 description"; |
| String pid = "myPID"; |
| |
| String xml = "<MetaData><OCD id=\"" + ocdId + "\" name=\"" + ocdName + "\" description=\"" + ocdDescription + "\"><AD id=\"attr\" type=\"String\" required=\"false\" /></OCD><Designate pid=\"" |
| + pid + "\" bundle=\"*\"></Designate></MetaData>"; |
| |
| final MetaData md = read(xml); |
| assertNull(md.getDesignates()); |
| assertEquals(1, md.getObjectClassDefinitions().size()); |
| } |
| |
| /** |
| * FELIX-4644 - Enforce that we can only have one Object in a Designate element. |
| */ |
| public void testDesignateWithObjectOk() throws IOException, XmlPullParserException |
| { |
| String ocdName = "ocd0"; |
| String ocdId = "id.ocd0"; |
| String ocdDescription = "ocd0 description"; |
| String pid = "myPID"; |
| |
| String xml = "<MetaData><OCD id=\"" + ocdId + "\" name=\"" + ocdName + "\" description=\"" + ocdDescription + "\"><AD id=\"attr\" type=\"String\" required=\"false\" /></OCD><Designate pid=\"" |
| + pid + "\" bundle=\"*\"><Object ocdref=\"" + ocdId + "\"></Object></Designate></MetaData>"; |
| MetaData mti = read(xml); |
| |
| assertNull(mti.getLocalePrefix()); |
| assertNotNull(mti.getObjectClassDefinitions()); |
| assertEquals(1, mti.getObjectClassDefinitions().size()); |
| |
| OCD ocd = (OCD) mti.getObjectClassDefinitions().values().iterator().next(); |
| assertEquals(ocdId, ocd.getID()); |
| assertEquals(ocdName, ocd.getName()); |
| assertEquals(ocdDescription, ocd.getDescription()); |
| |
| assertNotNull(ocd.getAttributeDefinitions()); |
| |
| List designates = ocd.getMetadata().getDesignates(); |
| assertEquals(1, designates.size()); |
| |
| Designate designate = (Designate) designates.get(0); |
| assertEquals(pid, designate.getPid()); |
| assertNotNull(designate.getObject()); |
| } |
| |
| /** |
| * FELIX-4644 - Enforce that we can only have one Object in a Designate element. |
| */ |
| public void testDesignateWithTwoObjectsFail() throws IOException, XmlPullParserException |
| { |
| String ocdName = "ocd0"; |
| String ocdId = "id.ocd0"; |
| String ocdDescription = "ocd0 description"; |
| String pid = "myPID"; |
| |
| String xml = "<MetaData><OCD id=\"" + ocdId + "\" name=\"" + ocdName + "\" description=\"" + ocdDescription + "\"><AD id=\"attr\" type=\"String\" required=\"false\" /></OCD><Designate pid=\"" |
| + pid + "\" bundle=\"*\"><Object ocdref=\"" + ocdId + "\"></Object><Object ocdref=\"" + ocdId + "\"></Object></Designate></MetaData>"; |
| |
| try |
| { |
| read(xml); // should fail! |
| fail("IOException expected!"); |
| } |
| catch (IOException e) |
| { |
| assertTrue(e.getMessage().contains("Unexpected element Object")); |
| } |
| } |
| |
| /** |
| * FELIX-4799 - tests that we can have multiple designates for the same factory PID in one MetaData configuration. |
| */ |
| public void testMultipleFactoryDesignatesWithSamePidOk() throws IOException, XmlPullParserException |
| { |
| String xml = "<MetaData><OCD id=\"ocd\" name=\"ocd\"><AD id=\"attr\" type=\"String\" required=\"false\" /></OCD>" |
| + "<Designate factoryPid=\"factoryA\" pid=\"A\" bundle=\"*\"><Object ocdref=\"ocd\"><Attribute adref=\"attr\" value=\"foo\" /></Object></Designate>" |
| + "<Designate factoryPid=\"factoryA\" pid=\"B\" bundle=\"*\"><Object ocdref=\"ocd\"><Attribute adref=\"attr\" value=\"bar\" /></Object></Designate>" + "</MetaData>"; |
| |
| MetaData metadata = read(xml); |
| assertNotNull(metadata); |
| |
| assertEquals(1, metadata.getObjectClassDefinitions().size()); |
| assertEquals(2, metadata.getDesignates().size()); |
| } |
| |
| /** |
| * FELIX-4799 - tests that we can have multiple designates for the same factory PID in one MetaData configuration. |
| */ |
| public void testMultipleFactoryDesignatesWithDifferentPidsOk() throws IOException, XmlPullParserException |
| { |
| String xml = "<MetaData><OCD id=\"ocd\" name=\"ocd\"><AD id=\"attr\" type=\"String\" required=\"false\" /></OCD>" |
| + "<Designate factoryPid=\"factoryA\" pid=\"A\" bundle=\"*\"><Object ocdref=\"ocd\"><Attribute adref=\"attr\" value=\"foo\" /></Object></Designate>" |
| + "<Designate factoryPid=\"factoryB\" pid=\"A\" bundle=\"*\"><Object ocdref=\"ocd\"><Attribute adref=\"attr\" value=\"bar\" /></Object></Designate>" + "</MetaData>"; |
| |
| MetaData metadata = read(xml); |
| assertNotNull(metadata); |
| |
| assertEquals(1, metadata.getObjectClassDefinitions().size()); |
| assertEquals(2, metadata.getDesignates().size()); |
| } |
| |
| public void testSingleOCDSingleRequiredAttr() throws IOException, XmlPullParserException |
| { |
| testSingleOCDSingleRequiredAttr("String", AttributeDefinition.STRING, MetaDataReader.NAMESPACE_1_0); |
| testSingleOCDSingleRequiredAttr("String", AttributeDefinition.STRING, MetaDataReader.NAMESPACE_1_1); |
| testSingleOCDSingleRequiredAttr("String", AttributeDefinition.STRING, MetaDataReader.NAMESPACE_1_2); |
| testSingleOCDSingleRequiredAttr("String", AttributeDefinition.STRING, MetaDataReader.NAMESPACE_1_3); |
| |
| testSingleOCDSingleRequiredAttr("Char", AttributeDefinition.CHARACTER, MetaDataReader.NAMESPACE_1_0); |
| testSingleOCDSingleRequiredAttr("Char", AttributeDefinition.CHARACTER, MetaDataReader.NAMESPACE_1_1); |
| testSingleOCDSingleRequiredAttr("Char", AttributeDefinition.CHARACTER, MetaDataReader.NAMESPACE_1_2); |
| testSingleOCDSingleRequiredAttr("Char", AttributeDefinition.CHARACTER, MetaDataReader.NAMESPACE_1_3); |
| |
| testSingleOCDSingleRequiredAttr("Character", AttributeDefinition.CHARACTER, MetaDataReader.NAMESPACE_1_0); |
| testSingleOCDSingleRequiredAttr("Character", AttributeDefinition.CHARACTER, MetaDataReader.NAMESPACE_1_1); |
| testSingleOCDSingleRequiredAttr("Character", AttributeDefinition.CHARACTER, MetaDataReader.NAMESPACE_1_2); |
| testSingleOCDSingleRequiredAttr("Character", AttributeDefinition.CHARACTER, MetaDataReader.NAMESPACE_1_3); |
| |
| } |
| |
| private void testSingleOCDSingleRequiredAttr(String adType, int typeCode, String namespace) throws IOException |
| { |
| String ocdName = "ocd0"; |
| String ocdId = "id.ocd0"; |
| String ocdDescription = "ocd0 description"; |
| |
| String adId = "id.ad0"; |
| String adName = "ad0"; |
| String adDescription = "ad0 description"; |
| int adCardinality = 789; |
| String adDefault = " a , b , c "; |
| |
| String empty = "<metatype:MetaData xmlns:metatype=\"" + namespace + "\">" + "<OCD id=\"" + ocdId + "\" name=\"" + ocdName + "\" description=\"" + ocdDescription + "\">" + "<AD id=\"" + adId |
| + "\" name=\"" + adName + "\" type=\"" + adType + "\" description=\"" + adDescription + "\" cardinality=\"" + adCardinality + "\" default=\"" + adDefault + "\">" + "</AD>" + "</OCD>" |
| + "</metatype:MetaData>"; |
| MetaData mti = read(empty); |
| |
| assertNull(mti.getLocalePrefix()); |
| assertNotNull(mti.getObjectClassDefinitions()); |
| assertEquals(1, mti.getObjectClassDefinitions().size()); |
| |
| OCD ocd = (OCD) mti.getObjectClassDefinitions().values().iterator().next(); |
| |
| assertNotNull(ocd.getAttributeDefinitions()); |
| assertEquals(1, ocd.getAttributeDefinitions().size()); |
| |
| AD ad = (AD) ocd.getAttributeDefinitions().values().iterator().next(); |
| assertEquals(adId, ad.getID()); |
| assertEquals(adName, ad.getName()); |
| assertEquals(adDescription, ad.getDescription()); |
| assertEquals(typeCode, ad.getType()); |
| assertEquals(adCardinality, ad.getCardinality()); |
| assertNotNull(ad.getDefaultValue()); |
| assertEquals(3, ad.getDefaultValue().length); |
| |
| String[] defaultValue = ad.getDefaultValue(); |
| assertEquals("a", defaultValue[0]); |
| assertEquals("b", defaultValue[1]); |
| assertEquals("c", defaultValue[2]); |
| } |
| |
| private MetaData read(String data) throws IOException |
| { |
| InputStream input = new ByteArrayInputStream(data.getBytes("UTF-8")); |
| return reader.parse(input); |
| } |
| } |