| /******************************************************************************* |
| * 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; |
| } |
| } |