blob: d285402450a16f1614019dad9f53f9e2653b09b3 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2013 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.internal.transforms;
import java.io.IOException;
import java.net.URL;
import java.util.*;
import org.eclipse.osgi.internal.log.EquinoxLogServices;
import org.osgi.framework.*;
import org.osgi.util.tracker.ServiceTracker;
/**
* Class that represents a dynamic list of TransformTuples that have been registered against a particular transform type.
*/
public class TransformInstanceListData extends ServiceTracker<URL, URL> {
/**
* Used when there are no transform data types
*/
private static final String[] EMPTY_TYPES = new String[0];
/**
* Stale state of the transform list. Set to true whenever one of the ServiceTrackerCustomization methods are invoked.
*/
private volatile boolean stale = true;
/**
* Map from transformer class -> tuple array
*/
private Map<String, TransformTuple[]> transformerToTuple = new HashMap<String, TransformTuple[]>();
/**
* List of all tuples in the system.
*/
private List<TransformTuple> rawTuples = new ArrayList<TransformTuple>();
/**
* Map from bundle ID -> boolean representing whether or not a given bundle currently has any transforms registered against it.
*/
private Map<String, Boolean> bundleIdToTransformPresence = new HashMap<String, Boolean>();
private final EquinoxLogServices logServices;
/**
* Create a new transform list bound to the given context. If new transforms are registered against the given context the contents of this list will change.
* @param context the bundle context
* @param logServices
* @throws InvalidSyntaxException thrown if there's an issue listening for changes to the given transformer type
*/
public TransformInstanceListData(BundleContext context, EquinoxLogServices logServices) throws InvalidSyntaxException {
super(context, context.createFilter("(&(objectClass=" //$NON-NLS-1$
+ URL.class.getName() + ")(" + TransformTuple.TRANSFORMER_TYPE //$NON-NLS-1$
+ "=*))"), null); //$NON-NLS-1$
this.logServices = logServices;
open();
}
/**
* Return the transforms types currently held by this list. If a change has been detected since the last request this list will be rebuilt.
* @return the transforms types currently held by this list
*/
public synchronized String[] getTransformTypes() {
if (stale)
rebuildTransformMap();
if (transformerToTuple.size() == 0)
return EMPTY_TYPES;
return transformerToTuple.keySet().toArray(new String[transformerToTuple.size()]);
}
/**
* Return the transforms of a particular type currently held by this list. If a change has been detected since the last request this list will be rebuilt.
* @return the transforms currently held by this list
*/
public synchronized TransformTuple[] getTransformsFor(String type) {
if (stale)
rebuildTransformMap();
return transformerToTuple.get(type);
}
/**
* Return whether or not there are any transforms who's bundle pattern matches the ID of the provided bundle. Only transforms with a present transform handler are considered during the invocation of this method.
* @param bundle the bundle to test
* @return the presence of associated transforms.
*/
public synchronized boolean hasTransformsFor(Bundle bundle) {
if (stale)
rebuildTransformMap();
String bundleName = bundle.getSymbolicName();
Boolean hasTransformsFor = bundleIdToTransformPresence.get(bundleName);
if (hasTransformsFor == null) {
hasTransformsFor = Boolean.FALSE;
for (TransformTuple tuple : rawTuples) {
if (tuple.bundlePattern.matcher(bundleName).matches()) {
hasTransformsFor = Boolean.TRUE;
}
}
bundleIdToTransformPresence.put(bundleName, hasTransformsFor);
}
return hasTransformsFor.booleanValue();
}
/**
* Consults the bundle context for services of the transformer type type and builds the internal cache.
*/
private void rebuildTransformMap() {
transformerToTuple.clear();
rawTuples.clear();
bundleIdToTransformPresence.clear();
ServiceReference<URL>[] serviceReferences = getServiceReferences();
stale = false;
if (serviceReferences == null)
return;
for (ServiceReference<URL> serviceReference : serviceReferences) {
String type = serviceReference.getProperty(TransformTuple.TRANSFORMER_TYPE).toString();
URL url = getService(serviceReference);
TransformTuple[] transforms;
try {
transforms = CSVParser.parse(url, logServices);
TransformTuple[] existing = transformerToTuple.get(type);
if (existing != null) {
TransformTuple[] newTransforms = new TransformTuple[existing.length + transforms.length];
System.arraycopy(existing, 0, newTransforms, 0, existing.length);
System.arraycopy(transforms, 0, newTransforms, existing.length, transforms.length);
transformerToTuple.put(type, newTransforms);
} else
transformerToTuple.put(type, transforms);
for (TransformTuple transform : transforms) {
rawTuples.add(transform);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public URL addingService(ServiceReference<URL> reference) {
try {
return super.addingService(reference);
} finally {
stale = true;
}
}
public void modifiedService(ServiceReference<URL> reference, URL service) {
super.modifiedService(reference, service);
stale = true;
}
public void removedService(ServiceReference<URL> reference, URL service) {
super.removedService(reference, service);
stale = true;
}
}