blob: 19554e056bc349d4ef74185582836ff0eea4bb18 [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.impl;
import java.util.Arrays;
import java.util.Collections;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Set;
import org.apache.felix.dm.DependencyManager;
import org.osgi.framework.Bundle;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
/**
* OSGi service utilities.
*
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
public class ServiceUtil {
/**
* Useful when needing to provide empty service properties.
*/
public final static Dictionary<String, Object> EMPTY_PROPERTIES = new Hashtable<>();
/**
* Defines service properties which must not be propagated from the dependencies to component service properties.
*/
public final static Set<String> NOT_PROPAGATABLE_SERVICE_PROPERTIES =
Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
Constants.SERVICE_ID,
Constants.SERVICE_RANKING,
Constants.SERVICE_BUNDLEID,
Constants.SERVICE_SCOPE,
Constants.OBJECTCLASS,
DependencyManager.ASPECT)));
/**
* Helper method used to convert a dictionary with untyped keys to a dictionary having a String key.
* (this method is useful when converting a Properties object into a compatible Dictionary<String, Object>
* object that is often needed in OSGI R6 API.
*/
@SuppressWarnings("unchecked")
public static <K,V> Dictionary<K, V> toR6Dictionary(Dictionary<?,?> properties) {
return (Dictionary<K, V>) properties;
}
/**
* Dump some service properties in a petty form.
*/
public static void appendProperties(StringBuilder result, Dictionary<?, ?> properties) {
if (properties != null && properties.size() > 0) {
result.append("(");
Enumeration<?> enumeration = properties.keys();
while (enumeration.hasMoreElements()) {
Object key = enumeration.nextElement();
result.append(key.toString());
result.append('=');
Object value = properties.get(key);
if (value instanceof String[]) {
String[] values = (String[]) value;
result.append('{');
for (int i = 0; i < values.length; i++) {
if (i > 0) {
result.append(',');
}
result.append(values[i].toString());
}
result.append('}');
}
else {
result.append(value.toString());
}
if (enumeration.hasMoreElements()) {
result.append(',');
}
}
result.append(")");
}
}
/**
* Returns the service ranking of a service, based on its service reference. If
* the service has a property specifying its ranking, that will be returned. If
* not, the default ranking of zero will be returned.
*
* @param ref the service reference to determine the ranking for
* @return the ranking
*/
public static int getRanking(ServiceReference<?> ref) {
return getRankingAsInteger(ref).intValue();
}
/**
* Returns the service ranking of a service, based on its service reference. If
* the service has a property specifying its ranking, that will be returned. If
* not, the default ranking of zero will be returned.
*
* @param ref the service reference to determine the ranking for
* @return the ranking
*/
public static Integer getRankingAsInteger(ServiceReference<?> ref) {
Integer rank = (Integer) ref.getProperty(Constants.SERVICE_RANKING);
if (rank != null) {
return rank;
}
return new Integer(0);
}
/**
* Returns the service ID of a service, based on its service reference. This
* method is aware of service aspects as defined by the dependency manager and
* will return the ID of the orginal service if you give it an aspect.
*
* @param ref the service reference to determine the service ID of
* @return the service ID
*/
public static long getServiceId(ServiceReference<?> ref) {
return getServiceIdAsLong(ref).longValue();
}
/**
* Returns the service ID of a service, based on its service reference. This
* method is aware of service aspects as defined by the dependency manager and
* will return the ID of the orginal service if you give it an aspect.
*
* @param ref the service reference to determine the service ID of
* @return the service ID
*/
public static Long getServiceIdAsLong(ServiceReference<?> ref) {
return getServiceIdObject(ref);
}
public static Long getServiceIdObject(ServiceReference<?> ref) {
Long aid = (Long) ref.getProperty(DependencyManager.ASPECT);
if (aid != null) {
return aid;
}
Long sid = (Long) ref.getProperty(Constants.SERVICE_ID);
if (sid != null) {
return sid;
}
throw new IllegalArgumentException("Invalid service reference, no service ID found");
}
/**
* Determines if the service is an aspect as defined by the dependency manager.
* Aspects are defined by a property and this method will check for its presence.
*
* @param ref the service reference
* @return <code>true</code> if it's an aspect, <code>false</code> otherwise
*/
public static boolean isAspect(ServiceReference<?> ref) {
Long aid = (Long) ref.getProperty(DependencyManager.ASPECT);
return (aid != null);
}
/**
* Converts a service reference to a string, listing both the bundle it was
* registered from and all properties.
*
* @param ref the service reference
* @return a string representation of the service
*/
public static String toString(ServiceReference<?> ref) {
if (ref == null) {
return "ServiceReference[null]";
}
else {
StringBuffer buf = new StringBuffer();
Bundle bundle = ref.getBundle();
if (bundle != null) {
buf.append("ServiceReference[");
buf.append(bundle.getBundleId());
buf.append("]{");
}
else {
buf.append("ServiceReference[unregistered]{");
}
buf.append(propertiesToString(ref, null));
buf.append("}");
return buf.toString();
}
}
/**
* Converts the properties of a service reference to a string.
*
* @param ref the service reference
* @param exclude a list of properties to exclude, or <code>null</code> to show everything
* @return a string representation of the service properties
*/
public static String propertiesToString(ServiceReference<?> ref, List<String> exclude) {
StringBuffer buf = new StringBuffer();
String[] keys = ref.getPropertyKeys();
for (int i = 0; i < keys.length; i++) {
if (i > 0) {
buf.append(',');
}
buf.append(keys[i]);
buf.append('=');
Object val = ref.getProperty(keys[i]);
if (exclude == null || !exclude.contains(val)) {
if (val instanceof String[]) {
String[] valArray = (String[]) val;
StringBuffer valBuf = new StringBuffer();
valBuf.append('{');
for (int j = 0; j < valArray.length; j++) {
if (valBuf.length() > 1) {
valBuf.append(',');
}
valBuf.append(valArray[j].toString());
}
valBuf.append('}');
buf.append(valBuf);
}
else {
buf.append(val.toString());
}
}
}
return buf.toString();
}
/**
* Wraps ServiceReference properties behind a Dictionary object.
* @param ref the ServiceReference to wrap
* @return a new Dictionary used to wrap the ServiceReference properties
*/
public static Dictionary<String, Object> propertiesToDictionary(final ServiceReference<?> ref) {
return new Dictionary<String, Object>() {
private Dictionary<String, Object> m_wrapper;
@Override
public int size() {
return getWrapper().size();
}
@Override
public boolean isEmpty() {
return getWrapper().isEmpty();
}
@Override
public Enumeration<String> keys() {
return getWrapper().keys();
}
@Override
public Enumeration<Object> elements() {
return getWrapper().elements();
}
@Override
public Object get(Object key) {
return ref.getProperty(key.toString());
}
@Override
public Object put(String key, Object value) {
throw new UnsupportedOperationException("Unmodified Dictionary.");
}
@Override
public Object remove(Object key) {
throw new UnsupportedOperationException("Unmodified Dictionary.");
}
@Override
public String toString() {
return getWrapper().toString();
}
private synchronized Dictionary<String, Object> getWrapper() {
if (m_wrapper == null) {
m_wrapper = new Hashtable<String, Object>();
String[] keys = ref.getPropertyKeys();
for (String key : keys) {
m_wrapper.put(key, ref.getProperty(key));
}
}
return m_wrapper;
}
};
}
}