/* * 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.scr.impl.metadata; import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; /** * A property descriptor that contains the information for properties * defined in the descriptor * */ public class PropertyMetadata { // Name of the property (required) private String m_name; // Type of the property (optional) private String m_type; // Value of the type (optional) // - before validate: raw value from XML (String or String[]) // - after validate: converted value provided to component private Object m_value; // Flag that indicates if this PropertyMetadata has been validated and thus has become immutable private boolean m_validated = false; /** * Set the name * * @param name */ public void setName(String name) { if (m_validated == true) { return; } m_name = name; } /** * Set the type * * @param type */ public void setType(String type) { if (m_validated == true) { return; } m_type = type; } /** * Set the value * * @param value */ public void setValue(String value) { if (m_validated == true) { return; } m_value = value; } /** * Set multiple values as an array, where the values are contained in * the string as one value per line. * * @param values */ public void setValues(String values) { if (m_validated == true) { return; } // splite th values List<String> valueList = new ArrayList<String>(); StringTokenizer tokener = new StringTokenizer(values, "\r\n"); while (tokener.hasMoreTokens()) { String value = tokener.nextToken().trim(); if (value.length() > 0) { valueList.add( value ); } } m_value = valueList.toArray( new String[valueList.size()] ); } /** * Get the name of the property * * @return the name of the property */ public String getName() { return m_name; } /** * Get the type of the property * * @return the type of the property */ public String getType() { return m_type; } /** * Get the value of the property * * @return the value of the property as an Object */ public Object getValue() { return m_value; } /** * Method used to verify if the semantics of this metadata are correct */ public void validate( ComponentMetadata componentMetadata ) { if ( m_name == null ) { throw componentMetadata.validationFailure( "Property name attribute is mandatory" ); } // check character type name if ( m_type == null ) { m_type = "String"; } else if ( componentMetadata.getDSVersion().isDS11() && m_type.equals( "Char" ) ) { throw componentMetadata .validationFailure( "Illegal property type 'Char' used for DS 1.1 descriptor, use 'Character' instead" ); } else if ( !componentMetadata.getDSVersion().isDS11() && m_type.equals( "Character" ) ) { throw componentMetadata .validationFailure( "Illegal property type 'Character' used for DS 1.0 descriptor, use 'Char' instead" ); } // validate and covert value if ( m_value != null ) { try { if ( m_value instanceof String ) { m_value = toType( ( String ) m_value ); } else { m_value = toTypeArray( ( String[] ) m_value ); } } catch ( NumberFormatException nfe ) { throw componentMetadata.validationFailure( getName() + ": Cannot convert property value to " + getType() ); } catch ( IllegalArgumentException e ) { throw componentMetadata.validationFailure( getName() + ": " + e.getMessage() ); } } m_validated = true; } /** * @throws IllegalArgumentException if the property type is not valid * according to the spec * @throws NumberFormatException if the string value cannot be converted * to the numeric type indicated by the property type */ private Object toType( String value ) { // 112.4.5 Parsing of the value is done by the valueOf(String) method (P. 291) // Should the type accept lowercase too? if ( m_type.equals( "String" ) ) { return value; } else if ( m_type.equals( "Long" ) ) { return Long.valueOf( value ); } else if ( m_type.equals( "Double" ) ) { return Double.valueOf( value ); } else if ( m_type.equals( "Float" ) ) { return Float.valueOf( value ); } else if ( m_type.equals( "Integer" ) ) { return Integer.valueOf( value ); } else if ( m_type.equals( "Byte" ) ) { return Byte.valueOf( value ); } else if ( m_type.equals( "Char" ) || m_type.equals( "Character" ) ) { // DS 1.1 changes the "Char" type to "Character", here we support both // For Character types, the conversion is handled by Integer.valueOf method. // (since valueOf is defined in terms of parseInt we directly call // parseInt to prevent unneeded Object creation) return Character.valueOf( ( char ) Integer.parseInt( value ) ); } else if ( m_type.equals( "Boolean" ) ) { return Boolean.valueOf( value ); } else if ( m_type.equals( "Short" ) ) { return Short.valueOf( value ); } else { throw new IllegalArgumentException( "Undefined property type '" + m_type + "'" ); } } /** * @throws IllegalArgumentException if the property type is not valid * according to the spec * @throws NumberFormatException if the string value cannot be converted * to the numeric type indicated by the property type */ private Object toTypeArray( String[] valueList ) { // 112.4.5 Except for String objects, the result will be translated to an array of primitive types. if ( m_type.equals( "String" ) ) { return valueList; } else if ( m_type.equals( "Double" ) ) { double[] array = new double[valueList.length]; for ( int i = 0; i < array.length; i++ ) { array[i] = Double.parseDouble( valueList[i] ); } return array; } else if ( m_type.equals( "Float" ) ) { float[] array = new float[valueList.length]; for ( int i = 0; i < array.length; i++ ) { array[i] = Float.parseFloat( valueList[i] ); } return array; } else if ( m_type.equals( "Long" ) ) { long[] array = new long[valueList.length]; for ( int i = 0; i < array.length; i++ ) { array[i] = Long.parseLong( valueList[i] ); } return array; } else if ( m_type.equals( "Integer" ) ) { int[] array = new int[valueList.length]; for ( int i = 0; i < array.length; i++ ) { array[i] = Integer.parseInt( valueList[i] ); } return array; } else if ( m_type.equals( "Short" ) ) { short[] array = new short[valueList.length]; for ( int i = 0; i < array.length; i++ ) { array[i] = Short.parseShort( valueList[i] ); } return array; } else if ( m_type.equals( "Byte" ) ) { byte[] array = new byte[valueList.length]; for ( int i = 0; i < array.length; i++ ) { array[i] = Byte.parseByte( valueList[i] ); } return array; } else if ( m_type.equals( "Char" ) || m_type.equals( "Character" ) ) { // DS 1.1 changes the "Char" type to "Character", here we support both char[] array = new char[valueList.length]; for ( int i = 0; i < array.length; i++ ) { array[i] = ( char ) Integer.parseInt( valueList[i] ); } return array; } else if ( m_type.equals( "Boolean" ) ) { boolean[] array = new boolean[valueList.length]; for ( int i = 0; i < array.length; i++ ) { array[i] = Boolean.valueOf( valueList[i] ); } return array; } else { throw new IllegalArgumentException( "Undefined property type '" + m_type + "'" ); } } }