blob: 29ac598bb45301a71adb1483bcd86685b9bdf2ff [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2003, 2017 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.osgi.internal.serviceregistry;
import java.lang.reflect.Array;
import java.util.*;
import org.eclipse.osgi.framework.util.CaseInsensitiveDictionaryMap;
import org.eclipse.osgi.internal.messages.Msg;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.Constants;
/**
* Service properties.
*
* Supports case-insensitive key lookup.
*/
class ServiceProperties extends CaseInsensitiveDictionaryMap<String, Object> {
/**
* Create a properties object from a Dictionary.
*
* @param props The properties for this service.
* @throws IllegalArgumentException If a case-variants of a key are
* in the props parameter.
*/
ServiceProperties(Dictionary<String, ?> props) {
this(props, 0);
}
/**
* Create a properties object from a Dictionary.
*
* @param props The properties for this service.
* @param extra Extra capacity in the map.
* @throws IllegalArgumentException If a case-variants of a key are
* in the props parameter.
*/
ServiceProperties(Dictionary<String, ?> props, int extra) {
super(initialCapacity((props == null) ? extra : props.size() + extra));
if (props == null) {
return;
}
synchronized (props) {
Enumeration<?> keysEnum = props.keys();
while (keysEnum.hasMoreElements()) {
Object key = keysEnum.nextElement();
if (key instanceof String) {
String header = (String) key;
Object value = cloneValue(props.get(header));
if (value != null && put(header, value) != null) {
throw new IllegalArgumentException(NLS.bind(Msg.HEADER_DUPLICATE_KEY_EXCEPTION, key));
}
}
}
}
}
/**
* Create a properties object from a Map.
*
* @param props The properties for this service.
* @throws IllegalArgumentException If a case-variants of a key are
* in the props parameter.
*/
ServiceProperties(Map<String, ?> props) {
super(initialCapacity((props == null) ? 0 : props.size()));
if (props == null) {
return;
}
synchronized (props) {
for (Entry<?, ?> e : props.entrySet()) {
Object key = e.getKey();
if (key instanceof String) {
String header = (String) key;
Object value = cloneValue(props.get(header));
if (value != null && put(header, value) != null) {
throw new IllegalArgumentException(NLS.bind(Msg.HEADER_DUPLICATE_KEY_EXCEPTION, key));
}
}
}
}
}
/**
* Attempt to clone the value if necessary and possible.
*
* For some strange reason, you can test to see if an Object is
* Cloneable but you can't call the clone method since it is
* protected on Object!
*
* @param value object to be cloned.
* @return cloned object or original object if we didn't clone it.
*/
static Object cloneValue(Object value) {
if (value == null)
return null;
if (value instanceof String) /* shortcut String */
return value;
if (value instanceof Number) /* shortcut Number */
return value;
if (value instanceof Character) /* shortcut Character */
return value;
if (value instanceof Boolean) /* shortcut Boolean */
return value;
Class<?> clazz = value.getClass();
if (clazz.isArray()) {
// Do an array copy
Class<?> type = clazz.getComponentType();
int len = Array.getLength(value);
Object clonedArray = Array.newInstance(type, len);
System.arraycopy(value, 0, clonedArray, 0, len);
return clonedArray;
}
if (value instanceof Cloneable) {
// must use reflection because Object clone method is protected!!
try {
return clazz.getMethod("clone", (Class<?>[]) null).invoke(value, (Object[]) null); //$NON-NLS-1$
} catch (Exception e) {
/* clone is not a public method on value's class */
}
}
return value;
}
@Override
public String toString() {
Set<String> keys = keySet();
StringBuilder sb = new StringBuilder(20 * keys.size());
sb.append('{');
int n = 0;
for (String key : keys) {
if (!key.equals(Constants.OBJECTCLASS)) {
if (n > 0)
sb.append(", "); //$NON-NLS-1$
sb.append(key);
sb.append('=');
Object value = get(key);
if (value.getClass().isArray()) {
sb.append('[');
int length = Array.getLength(value);
for (int j = 0; j < length; j++) {
if (j > 0)
sb.append(',');
sb.append(Array.get(value, j));
}
sb.append(']');
} else {
sb.append(value);
}
n++;
}
}
sb.append('}');
return sb.toString();
}
}