blob: 60b2b636471bb91efadb4a0d7b0faac7448741bc [file] [log] [blame]
/*
* 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.dm.annotation.plugin.bnd;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import aQute.bnd.osgi.Annotation;
/**
* This class encodes a component descriptor entry line, using json.
* We are using a slightly adapted version of the nice JsonSerializingImpl class from the Apache Felix Converter project.
*
* Internally, we store parameters in a map. The format of key/values stored in the map is the following:
*
* The JSON object has the following form:
*
* entry ::= String | String[] | dictionary
* dictionary ::= key-value-pair*
* key-value-pair ::= key value
* value ::= String | String[] | value-type
* value-type ::= jsonObject with value-type-info
* value-type-info ::= "type"=primitive java type
* "value"=String|String[]
*
* Exemple:
*
* {"string-param" : "string-value",
* "string-array-param" : ["string1", "string2"],
* "properties" : {
* "string-param" : "string-value",
* "string-array-param" : ["str1", "str2],
* "long-param" : {"type":"java.lang.Long", "value":"1"}}
* "long-array-param" : {"type":"java.lang.Long", "value":["1"]}}
* }
* }
*
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
public class EntryWriter
{
/**
* Every descriptor entries contains a type parameter for identifying the kind of entry
*/
private final static String TYPE = "type";
/**
* All parameters as stored in a map object
*/
private final HashMap<String, Object> m_params = new HashMap<>();
/** The entry type */
private final EntryType m_type;
/**
* Makes a new component descriptor entry.
*/
public EntryWriter(EntryType type)
{
m_type = type;
m_params.put("type", type.toString());
}
/**
* Returns this entry type.
*/
EntryType getEntryType()
{
return m_type;
}
/**
* Returns a string representation for the given component descriptor entry.
* @param m_logger
*/
public String toString()
{
return new JsonWriter(m_params).toString();
}
/**
* Adds a String parameter in this descritor entry.
*/
public void put(EntryParam param, String value)
{
checkType(param.toString());
m_params.put(param.toString(), value);
}
/**
* Adds a String[] parameter in this descriptor entry.
*/
public void put(EntryParam param, String[] values)
{
checkType(param.toString());
m_params.put(param.toString(), Arrays.asList(values));
}
/**
* Adds a property in this descriptor entry.
*/
@SuppressWarnings("unchecked")
public void addProperty(String name, Object value, Class<?> type)
{
Map<String, Object> properties = (Map<String, Object>) m_params.get(EntryParam.properties.toString());
if (properties == null) {
properties = new HashMap<>();
m_params.put(EntryParam.properties.toString(), properties);
}
if (value.getClass().isArray())
{
Object[] array = (Object[]) value;
if (array.length == 1)
{
value = array[0];
}
}
if (type.equals(String.class))
{
properties.put(name, value.getClass().isArray() ? Arrays.asList((Object[]) value) : value);
}
else
{
Map<String, Object> val = new HashMap<>();
val.put("type", type.getName());
val.put("value", value.getClass().isArray() ? Arrays.asList((Object[]) value) : value);
properties.put(name, val);
}
}
/**
* Get a String attribute value from an annotation and write it into this descriptor entry.
*/
public String putString(Annotation annotation, EntryParam param, String def)
{
checkType(param.toString());
Object value = annotation.get(param.toString());
if (value == null && def != null)
{
value = def;
}
if (value != null)
{
put(param, value.toString());
}
return value == null ? null : value.toString();
}
/**
* Get a class attribute value from an annotation and write it into this descriptor entry.
*/
public void putClass(Annotation annotation, EntryParam param)
{
checkType(param.toString());
String value = AnnotationCollector.parseClassAttrValue(annotation.get(param.toString()));
if (value != null)
{
put(param, value);
}
}
/**
* Get a class array attribute value from an annotation and write it into this descriptor entry.
*
* @param annotation the annotation containing an array of classes
* @param param the attribute name corresponding to an array of classes
* @param def the default array of classes (String[]), if the attribute is not defined in the annotation
* @return the class array size.
*/
public int putClassArray(Annotation annotation, EntryParam param, Object def, Set<String> collect)
{
checkType(param.toString());
boolean usingDefault = false;
Object value = annotation.get(param.toString());
if (value == null && def != null)
{
value = def;
usingDefault = true;
}
if (value != null)
{
if (!(value instanceof Object[]))
{
throw new IllegalArgumentException("annotation parameter " + param
+ " has not a class array type");
}
List<String> classes = new ArrayList<>();
for (Object v: ((Object[]) value))
{
if (! usingDefault)
{
// Parse the annotation attribute value.
v = AnnotationCollector.parseClassAttrValue(v);
}
classes.add(v.toString());
collect.add(v.toString());
}
m_params.put(param.toString(), classes);
return ((Object[]) value).length;
}
return 0;
}
/**
* Check if the written key is not equals to "type" ("type" is an internal attribute we are using
* in order to identify a kind of descriptor entry (Service, ServiceDependency, etc ...).
*/
private void checkType(String key)
{
if (TYPE.equals(key))
{
throw new IllegalArgumentException("\"" + TYPE + "\" parameter can't be overriden");
}
}
}