blob: e5019dd59706a0803b03a5a8d8713363b638593e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 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.equinox.metatype.impl;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.Map.Entry;
import org.eclipse.equinox.metatype.*;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.*;
import org.osgi.service.cm.ManagedService;
import org.osgi.service.cm.ManagedServiceFactory;
import org.osgi.service.metatype.*;
import org.osgi.util.tracker.ServiceTracker;
public class MetaTypeProviderTracker implements EquinoxMetaTypeInformation {
private final Bundle _bundle;
private final LogTracker log;
private final ServiceTracker<Object, Object> _tracker;
/**
* Constructs a MetaTypeProviderTracker which tracks all MetaTypeProviders
* registered by the specified bundle.
* @param context The BundleContext of the MetaTypeService implementation
* @param bundle The bundle to track all MetaTypeProviders for.
* @param log The {@code LogService} to use for logging messages.
*/
public MetaTypeProviderTracker(Bundle bundle, LogTracker log, ServiceTracker<Object, Object> tracker) {
this._bundle = bundle;
this._tracker = tracker;
this.log = log;
}
private String[] getPids(boolean factory) {
if (_bundle.getState() != Bundle.ACTIVE)
return new String[0]; // return none if not active
MetaTypeProviderWrapper[] wrappers = getMetaTypeProviders();
ArrayList<String> results = new ArrayList<String>();
for (int i = 0; i < wrappers.length; i++) {
// return only the correct type of pids (regular or factory)
if (factory == wrappers[i].factory)
results.add(wrappers[i].pid);
}
return results.toArray(new String[results.size()]);
}
public String[] getPids() {
return getPids(false);
}
public String[] getFactoryPids() {
return getPids(true);
}
public Bundle getBundle() {
return _bundle;
}
@Override
public EquinoxObjectClassDefinition getObjectClassDefinition(String id, String locale) {
if (_bundle.getState() != Bundle.ACTIVE)
return null; // return none if not active
MetaTypeProviderWrapper[] wrappers = getMetaTypeProviders();
for (int i = 0; i < wrappers.length; i++) {
if (id.equals(wrappers[i].pid))
// found a matching pid now call the actual provider
return wrappers[i].getObjectClassDefinition(id, locale);
}
return null;
}
public String[] getLocales() {
if (_bundle.getState() != Bundle.ACTIVE)
return new String[0]; // return none if not active
MetaTypeProviderWrapper[] wrappers = getMetaTypeProviders();
ArrayList<String> locales = new ArrayList<String>();
// collect all the unique locales from all providers we found
for (int i = 0; i < wrappers.length; i++) {
String[] wrappedLocales = wrappers[i].getLocales();
if (wrappedLocales == null)
continue;
for (int j = 0; j < wrappedLocales.length; j++)
if (!locales.contains(wrappedLocales[j]))
locales.add(wrappedLocales[j]);
}
return locales.toArray(new String[locales.size()]);
}
private MetaTypeProviderWrapper[] getMetaTypeProviders() {
Map<ServiceReference<Object>, Object> services = _tracker.getTracked();
if (services.isEmpty())
return new MetaTypeProviderWrapper[0];
Set<MetaTypeProviderWrapper> result = new HashSet<MetaTypeProviderWrapper>();
for (Entry<ServiceReference<Object>, Object> entry : services.entrySet()) {
ServiceReference<Object> serviceReference = entry.getKey();
if (serviceReference.getBundle() == _bundle) {
Object service = entry.getValue();
// If the service is not a MetaTypeProvider, we're not interested in it.
if (service instanceof MetaTypeProvider) {
// Include the METATYPE_PID, if present, to return as part of getPids(). Also, include the
// METATYPE_FACTORY_PID, if present, to return as part of getFactoryPids().
// The filter ensures at least one of these properties was set for a standalone MetaTypeProvider.
addMetaTypeProviderWrappers(MetaTypeProvider.METATYPE_PID, serviceReference, (MetaTypeProvider) service, false, result);
addMetaTypeProviderWrappers(MetaTypeProvider.METATYPE_FACTORY_PID, serviceReference, (MetaTypeProvider) service, true, result);
// If the service is a ManagedService, include the SERVICE_PID to return as part of getPids().
// The filter ensures the SERVICE_PID property was set.
if (service instanceof ManagedService) {
addMetaTypeProviderWrappers(Constants.SERVICE_PID, serviceReference, (MetaTypeProvider) service, false, result);
}
// If the service is a ManagedServiceFactory, include the SERVICE_PID to return as part of getFactoryPids().
// The filter ensures the SERVICE_PID property was set.
else if (service instanceof ManagedServiceFactory) {
addMetaTypeProviderWrappers(Constants.SERVICE_PID, serviceReference, (MetaTypeProvider) service, true, result);
}
}
}
}
return result.toArray(new MetaTypeProviderWrapper[result.size()]);
}
private void addMetaTypeProviderWrappers(String servicePropertyName, ServiceReference<Object> serviceReference, MetaTypeProvider service, boolean factory, Set<MetaTypeProviderWrapper> wrappers) {
String[] pids = getStringProperty(servicePropertyName, serviceReference.getProperty(servicePropertyName));
for (String pid : pids) {
wrappers.add(new MetaTypeProviderWrapper(service, pid, factory));
}
}
private String[] getStringProperty(String name, Object value) {
// Don't log a warning if the value is null. The filter guarantees at least one of the necessary properties
// is there. If others are not, this method will get called with value equal to null.
if (value == null)
return new String[0];
if (value instanceof String) {
return new String[] {(String) value};
}
if (value instanceof String[]) {
return (String[]) value;
}
Exception e = null;
if (value instanceof Collection) {
@SuppressWarnings("unchecked")
Collection<String> temp = (Collection<String>) value;
try {
return temp.toArray(new String[temp.size()]);
} catch (ArrayStoreException ase) {
e = ase;
}
}
log.log(LogTracker.LOG_WARNING, NLS.bind(MetaTypeMsg.INVALID_PID_METATYPE_PROVIDER_IGNORED, new Object[] {_bundle.getSymbolicName(), _bundle.getBundleId(), name, value}), e);
return new String[0];
}
// this is a simple class just used to temporarily store information about a provider
public class MetaTypeProviderWrapper implements MetaTypeProvider {
private final MetaTypeProvider provider;
final String pid;
final boolean factory;
MetaTypeProviderWrapper(MetaTypeProvider provider, String pid, boolean factory) {
this.provider = provider;
this.pid = pid;
this.factory = factory;
}
@Override
public boolean equals(Object object) {
if (object == this)
return true;
if (!(object instanceof MetaTypeProviderWrapper))
return false;
MetaTypeProviderWrapper that = (MetaTypeProviderWrapper) object;
return this.provider.equals(that.provider) && this.pid.equals(that.pid) && this.factory == that.factory;
}
@Override
public int hashCode() {
int result = 17;
result = 31 * result + provider.hashCode();
result = 31 * result + pid.hashCode();
result = 31 * result + (factory ? 1 : 0);
return result;
}
public EquinoxObjectClassDefinition getObjectClassDefinition(String id, String locale) {
final ObjectClassDefinition ocd = provider.getObjectClassDefinition(id, locale);
if (ocd == null)
return null;
return new EquinoxObjectClassDefinition() {
public String getName() {
return ocd.getName();
}
public String getID() {
return ocd.getID();
}
public String getDescription() {
return ocd.getDescription();
}
public InputStream getIcon(int size) throws IOException {
return ocd.getIcon(size);
}
@Override
public Map<String, String> getExtensionAttributes(String schema) {
return Collections.<String, String> emptyMap();
}
@Override
public Set<String> getExtensionUris() {
return Collections.<String> emptySet();
}
@Override
public EquinoxAttributeDefinition[] getAttributeDefinitions(int filter) {
AttributeDefinition[] ads = ocd.getAttributeDefinitions(filter);
if (ads == null || ads.length == 0)
return new EquinoxAttributeDefinition[0];
Collection<EquinoxAttributeDefinition> result = new ArrayList<EquinoxAttributeDefinition>(ads.length);
for (final AttributeDefinition ad : ads) {
result.add(new EquinoxAttributeDefinition() {
public String getName() {
return ad.getName();
}
public String getID() {
return ad.getID();
}
public String getDescription() {
return ad.getDescription();
}
public int getCardinality() {
return ad.getCardinality();
}
public int getType() {
return ad.getType();
}
public String[] getOptionValues() {
return ad.getOptionValues();
}
public String[] getOptionLabels() {
return ad.getOptionLabels();
}
public String validate(String value) {
return ad.validate(value);
}
public String[] getDefaultValue() {
return ad.getDefaultValue();
}
@Override
public Map<String, String> getExtensionAttributes(String schema) {
return Collections.<String, String> emptyMap();
}
@Override
public Set<String> getExtensionUris() {
return Collections.<String> emptySet();
}
@Override
public String getMax() {
return null;
}
@Override
public String getMin() {
return null;
}
});
}
return result.toArray(new EquinoxAttributeDefinition[result.size()]);
}
};
}
public String[] getLocales() {
return provider.getLocales();
}
}
}