| /* |
| * 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.webconsole.internal.configuration; |
| |
| |
| import java.io.IOException; |
| import java.lang.reflect.Array; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Vector; |
| |
| import org.apache.felix.utils.json.JSONWriter; |
| import org.osgi.framework.Bundle; |
| import org.osgi.framework.BundleContext; |
| import org.osgi.service.metatype.AttributeDefinition; |
| |
| |
| /** |
| * The <code>ConfigManagerBase</code> is the base class for the |
| * ConfigurationAdmin support in the web console. It provides various helper |
| * methods mostly with respect to using the MetaTypeService to access |
| * configuration descriptions. |
| */ |
| class MetaTypeSupport |
| { |
| |
| |
| /** |
| * Marker value of password fields used as dummy values and |
| * indicating unmodified values. |
| */ |
| static final String PASSWORD_PLACEHOLDER_VALUE = "unmodified"; //$NON-NLS-1$ |
| |
| |
| static Bundle getBundle( final BundleContext bundleContext, final String bundleLocation ) |
| { |
| if ( bundleLocation == null ) |
| { |
| return null; |
| } |
| |
| Bundle[] bundles = bundleContext.getBundles(); |
| for ( int i = 0; i < bundles.length; i++ ) |
| { |
| if ( bundleLocation.equals( bundles[i].getLocation() ) ) |
| { |
| return bundles[i]; |
| } |
| } |
| |
| return null; |
| } |
| |
| |
| static void attributeToJson( final JSONWriter json, final PropertyDescriptor ad, final Object propValue ) |
| throws IOException |
| { |
| json.object(); |
| |
| Object value; |
| if ( propValue != null ) |
| { |
| value = propValue; |
| } |
| else if ( ad.getDefaultValue() != null ) |
| { |
| value = ad.getDefaultValue(); |
| } |
| else if ( ad.getCardinality() == 0 ) |
| { |
| value = ""; //$NON-NLS-1$ |
| } |
| else |
| { |
| value = new String[0]; |
| } |
| |
| json.key( "name" ); //$NON-NLS-1$ |
| json.value( ad.getName() ); |
| json.key( "optional" ); //$NON-NLS-1$ |
| json.value( ad.isOptional() ); |
| json.key( "is_set" ); //$NON-NLS-1$ |
| json.value( propValue != null ); |
| |
| // attribute type - overwrite metatype provided type |
| // if the property name contains "password" and the |
| // type is string |
| int propertyType = getAttributeType( ad ); |
| |
| json.key( "type" ); //$NON-NLS-1$ |
| if ( ad.getOptionLabels() != null && ad.getOptionLabels().length > 0 ) |
| { |
| json.object(); |
| json.key( "labels" ); //$NON-NLS-1$ |
| json.value( Arrays.asList( ad.getOptionLabels() ) ); |
| json.key( "values" ); //$NON-NLS-1$ |
| json.value( Arrays.asList( ad.getOptionValues() ) ); |
| json.endObject(); |
| } |
| else |
| { |
| json.value( propertyType ); |
| } |
| |
| // unless the property is of password type, send it |
| final boolean isPassword = propertyType == AttributeDefinition.PASSWORD; |
| if ( ad.getCardinality() == 0 ) |
| { |
| // scalar |
| if ( isPassword ) |
| { |
| value = PASSWORD_PLACEHOLDER_VALUE; |
| } |
| else if ( value instanceof Vector ) |
| { |
| value = ( ( Vector ) value ).get( 0 ); |
| } |
| else if ( value.getClass().isArray() ) |
| { |
| value = Array.get( value, 0 ); |
| } |
| json.key( "value" ); //$NON-NLS-1$ |
| json.value( value ); |
| } |
| else |
| { |
| json.key( "values" ); //$NON-NLS-1$ |
| json.array(); |
| final List list = toList( value ); |
| final Iterator iter = list.iterator(); |
| while ( iter.hasNext() ) |
| { |
| final Object val = iter.next(); |
| if ( isPassword ) |
| { |
| json.value(PASSWORD_PLACEHOLDER_VALUE); |
| } |
| else |
| { |
| json.value(val); |
| } |
| } |
| json.endArray(); |
| } |
| |
| if ( ad.getDescription() != null ) |
| { |
| json.key( "description" ); //$NON-NLS-1$ |
| json.value( ad.getDescription() + " (" + ad.getID() + ")" ); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| json.endObject(); |
| } |
| |
| |
| private static List toList( Object value ) |
| { |
| if ( value instanceof Vector ) |
| { |
| return ( Vector ) value; |
| } |
| else if ( value.getClass().isArray() ) |
| { |
| if ( value.getClass().getComponentType().isPrimitive() ) |
| { |
| final int len = Array.getLength( value ); |
| final Object[] tmp = new Object[len]; |
| for ( int j = 0; j < len; j++ ) |
| { |
| tmp[j] = Array.get( value, j ); |
| } |
| value = tmp; |
| } |
| return Arrays.asList( ( Object[] ) value ); |
| } |
| else |
| { |
| return Collections.singletonList( value ); |
| } |
| } |
| |
| |
| static PropertyDescriptor createAttributeDefinition( final String id, final Object value ) |
| { |
| int attrType; |
| int attrCardinality; |
| Class type; |
| |
| if ( value == null ) |
| { |
| attrCardinality = 0; |
| type = String.class; |
| } |
| else if ( value instanceof Collection ) |
| { |
| attrCardinality = Integer.MIN_VALUE; |
| Collection coll = ( Collection ) value; |
| if ( coll.isEmpty() ) |
| { |
| type = String.class; |
| } |
| else |
| { |
| type = coll.iterator().next().getClass(); |
| } |
| } |
| else if ( value.getClass().isArray() ) |
| { |
| attrCardinality = Integer.MAX_VALUE; |
| type = value.getClass().getComponentType(); |
| } |
| else |
| { |
| attrCardinality = 0; |
| type = value.getClass(); |
| } |
| |
| if ( type == Boolean.class || type == Boolean.TYPE ) |
| { |
| attrType = AttributeDefinition.BOOLEAN; |
| } |
| else if ( type == Byte.class || type == Byte.TYPE ) |
| { |
| attrType = AttributeDefinition.BYTE; |
| } |
| else if ( type == Character.class || type == Character.TYPE ) |
| { |
| attrType = AttributeDefinition.CHARACTER; |
| } |
| else if ( type == Double.class || type == Double.TYPE ) |
| { |
| attrType = AttributeDefinition.DOUBLE; |
| } |
| else if ( type == Float.class || type == Float.TYPE ) |
| { |
| attrType = AttributeDefinition.FLOAT; |
| } |
| else if ( type == Long.class || type == Long.TYPE ) |
| { |
| attrType = AttributeDefinition.LONG; |
| } |
| else if ( type == Integer.class || type == Integer.TYPE ) |
| { |
| attrType = AttributeDefinition.INTEGER; |
| } |
| else if ( type == Short.class || type == Short.TYPE ) |
| { |
| attrType = AttributeDefinition.SHORT; |
| } |
| else |
| { |
| attrType = AttributeDefinition.STRING; |
| } |
| |
| return new PropertyDescriptor( id, attrType, attrCardinality ); |
| } |
| |
| |
| static int getAttributeType( final PropertyDescriptor ad ) |
| { |
| return ad.getType(); |
| } |
| |
| |
| /** |
| * @throws NumberFormatException If the value cannot be converted to |
| * a number and type indicates a numeric type |
| */ |
| static final Object toType( int type, String value ) |
| { |
| switch ( type ) |
| { |
| case AttributeDefinition.BOOLEAN: |
| return Boolean.valueOf( value ); |
| case AttributeDefinition.BYTE: |
| return Byte.valueOf( value ); |
| case AttributeDefinition.CHARACTER: |
| char c = ( value.length() > 0 ) ? value.charAt( 0 ) : 0; |
| return new Character( c ); |
| case AttributeDefinition.DOUBLE: |
| return Double.valueOf( value ); |
| case AttributeDefinition.FLOAT: |
| return Float.valueOf( value ); |
| case AttributeDefinition.LONG: |
| return Long.valueOf( value ); |
| case AttributeDefinition.INTEGER: |
| return Integer.valueOf( value ); |
| case AttributeDefinition.SHORT: |
| return Short.valueOf( value ); |
| default: |
| // includes AttributeDefinition.STRING |
| // includes AttributeDefinition.PASSWORD |
| return value; |
| } |
| } |
| |
| |
| static void setPasswordProps( final Vector vec, final String[] properties, Object props ) |
| { |
| List propList = ( props == null ) ? new ArrayList() : toList( props ); |
| for ( int i = 0; i < properties.length; i++ ) |
| { |
| if ( PASSWORD_PLACEHOLDER_VALUE.equals( properties[i] ) ) |
| { |
| if ( i < propList.size() && propList.get( i ) != null ) |
| { |
| vec.add( propList.get( i ) ); |
| } |
| } |
| else |
| { |
| vec.add( properties[i] ); |
| } |
| } |
| } |
| |
| |
| static final Object toArray( int type, Vector values ) |
| { |
| int size = values.size(); |
| |
| // short cut for string array |
| if ( type == AttributeDefinition.STRING || type == AttributeDefinition.PASSWORD ) |
| { |
| return values.toArray( new String[size] ); |
| } |
| |
| Object array; |
| switch ( type ) |
| { |
| case AttributeDefinition.BOOLEAN: |
| array = new boolean[size]; |
| break; |
| case AttributeDefinition.BYTE: |
| array = new byte[size]; |
| break; |
| case AttributeDefinition.CHARACTER: |
| array = new char[size]; |
| break; |
| case AttributeDefinition.DOUBLE: |
| array = new double[size]; |
| break; |
| case AttributeDefinition.FLOAT: |
| array = new float[size]; |
| break; |
| case AttributeDefinition.LONG: |
| array = new long[size]; |
| break; |
| case AttributeDefinition.INTEGER: |
| array = new int[size]; |
| break; |
| case AttributeDefinition.SHORT: |
| array = new short[size]; |
| break; |
| default: |
| // unexpected, but assume string |
| array = new String[size]; |
| } |
| |
| for ( int i = 0; i < size; i++ ) |
| { |
| Array.set( array, i, values.get( i ) ); |
| } |
| |
| return array; |
| } |
| |
| } |