/** * This file is protected by Copyright. * Please refer to the COPYRIGHT file distributed with this source distribution. * * This file is part of REDHAWK IDE. * * All rights reserved. This program and the accompanying materials are made available under * the terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html. * */ package gov.redhawk.core.internal.resourcefactory; import gov.redhawk.core.filemanager.IFileManager; import gov.redhawk.core.resourcefactory.IResourceFactoryProvider; import gov.redhawk.core.resourcefactory.IResourceFactoryRegistry; import gov.redhawk.core.resourcefactory.ResourceDesc; import gov.redhawk.core.resourcefactory.ResourceFactoryPlugin; import gov.redhawk.sca.util.OrbSession; import gov.redhawk.sca.util.PropertyChangeSupport; import mil.jpeojtrs.sca.util.CFErrorFormatter; import mil.jpeojtrs.sca.util.CFErrorFormatter.FileOperation; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtension; import org.eclipse.core.runtime.IExtensionPoint; import org.eclipse.core.runtime.IExtensionRegistry; import org.eclipse.core.runtime.ISafeRunnable; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.SafeRunner; import org.eclipse.core.runtime.Status; import CF.FileException; import CF.FileSystem; import CF.InvalidFileName; import CF.FileManagerPackage.InvalidFileSystem; import CF.FileManagerPackage.MountPointAlreadyExists; import CF.FileManagerPackage.NonExistentMount; import CF.FileSystemPackage.FileType; /** * The resource factory registry instantiates instances of resource factories ({@link IResourceFactoryProvider}) * declared via extension point (see {@link #EP_ID}). The registry receives resource descriptions * ({@link ResourceDesc}) from the factories, which it then fuses into a unified file system ({@link IFileManager}). */ public enum ResourceFactoryRegistry implements IResourceFactoryRegistry { INSTANCE; private static final String EP_ID = "resourceFactories"; private static final String ELM_PROVIDER = "factoryProvider"; private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); private final List<ResourceDesc> registry = Collections.synchronizedList(new ArrayList<ResourceDesc>()); private final Set<String> mountPoints = Collections.synchronizedSet(new HashSet<String>()); private final List<IResourceFactoryProvider> providerRegistry = Collections.synchronizedList(new ArrayList<IResourceFactoryProvider>()); private ResourceFactoryRegistryFileManager fileManager = null; private OrbSession session = OrbSession.createSession(ResourceFactoryPlugin.ID); private final PropertyChangeListener listener = new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if (IResourceFactoryProvider.PROPERTY_RESOURCE_DESCRIPTORS.equals(evt.getPropertyName())) { if (evt.getOldValue() instanceof ResourceDesc) { removeResourceDesc((ResourceDesc) evt.getOldValue()); } if (evt.getNewValue() instanceof ResourceDesc) { ResourceDesc desc = (ResourceDesc) evt.getNewValue(); try { addResourceDesc(desc); } catch (CoreException e) { ResourceFactoryPlugin.getDefault().getLog().log( new Status(IStatus.ERROR, ResourceFactoryPlugin.ID, "Failed to add resource descriptor: " + desc.getIdentifier(), e)); } } } else if (IResourceFactoryProvider.PROPERTY_FILE_SYSTEM_MOUNTS.equals(evt.getPropertyName())) { if (evt.getOldValue() != null) { String mountPoint = (String) evt.getOldValue(); removeFileSystemMount(mountPoint); } if (evt.getNewValue() != null) { IResourceFactoryProvider factory = (IResourceFactoryProvider) evt.getSource(); String mountPoint = (String) evt.getNewValue(); FileSystem fs = factory.getFileSystemMounts().get(mountPoint); addFileSystemMount(fs, mountPoint); } } } }; private ResourceFactoryRegistry() { try { fileManager = new ResourceFactoryRegistryFileManager(session.getOrb(), session.getPOA()); } catch (CoreException e) { ResourceFactoryPlugin.getDefault().getLog().log( new Status(IStatus.ERROR, ResourceFactoryPlugin.ID, "Unable to initialize resource factory file manager", e)); } // Find resource factories declared in extension points final IExtensionRegistry reg = Platform.getExtensionRegistry(); final IExtensionPoint ep = reg.getExtensionPoint(ResourceFactoryPlugin.ID, ResourceFactoryRegistry.EP_ID); if (ep != null) { final IExtension[] extensions = ep.getExtensions(); for (final IExtension extension : extensions) { addExtension(extension); } } } private void addExtension(final IExtension extension) { for (final IConfigurationElement element : extension.getConfigurationElements()) { final String id = element.getAttribute("id"); if (element.getName().equals(ResourceFactoryRegistry.ELM_PROVIDER)) { SafeRunner.run(new ISafeRunnable() { @Override public void run() throws Exception { try { final IResourceFactoryProvider provider = (IResourceFactoryProvider) element.createExecutableExtension("class"); provider.addPropertyChangeListener(listener); providerRegistry.add(provider); for (String mountPoint : provider.getFileSystemMounts().keySet()) { addFileSystemMount(provider.getFileSystemMounts().get(mountPoint), mountPoint); } for (ResourceDesc desc : provider.getResourceDescriptors()) { addResourceDesc(desc); } } catch (final CoreException e) { ResourceFactoryPlugin.getDefault().getLog().log( new Status(IStatus.ERROR, ResourceFactoryPlugin.ID, "Failed to add Factory Provider: " + id, e)); } } @Override public void handleException(Throwable e) { // PASS - Logged by SafeRunner } }); } } } private void addResourceDesc(final ResourceDesc desc) throws CoreException { this.fileManager.mount(desc); this.registry.add(desc); pcs.firePropertyChange(IResourceFactoryRegistry.PROP_RESOURCES, null, desc); } private void removeResourceDesc(final ResourceDesc desc) { if (registry.remove(desc)) { this.fileManager.unmount(desc); desc.dispose(); } pcs.firePropertyChange(IResourceFactoryRegistry.PROP_RESOURCES, desc, null); } private void addFileSystemMount(FileSystem fs, String mountPoint) { try { // Only mount the file system if the mount point doesn't exist or is a directory with no files if (fileManager.exists(mountPoint)) { try { if (fileManager.list(mountPoint)[0].kind.value() != FileType.DIRECTORY.value() || fileManager.list(mountPoint + "/*").length != 0) { return; } } catch (FileException e) { return; } } fileManager.mount(mountPoint, fs); mountPoints.add(mountPoint); } catch (InvalidFileName e) { ResourceFactoryPlugin.logError(CFErrorFormatter.format(e, FileOperation.Mount, mountPoint), e); } catch (InvalidFileSystem e) { String msg = String.format("Invalid file system (mount point %s)", mountPoint); ResourceFactoryPlugin.logError(msg, e); } catch (MountPointAlreadyExists e) { String msg = String.format("File system already mounted at %s", mountPoint); ResourceFactoryPlugin.logError(msg, e); } } private void removeFileSystemMount(String mountPoint) { try { if (mountPoints.remove(mountPoint)) { fileManager.unmount(mountPoint); } } catch (NonExistentMount e) { ResourceFactoryPlugin.logError(CFErrorFormatter.format(e, mountPoint), e); } } @Override public void dispose() { // Dispose the resource factory providers for (final IResourceFactoryProvider provider : this.providerRegistry) { provider.dispose(); } this.providerRegistry.clear(); // There should be no file systems or resource descriptors remaining unless a provider failed to unregister // them synchronized (this.mountPoints) { for (String mountPoint : this.mountPoints) { removeFileSystemMount(mountPoint); } } synchronized (this.registry) { for (final ResourceDesc desc : this.registry) { this.fileManager.unmount(desc); desc.dispose(); } this.registry.clear(); } if (session != null) { session.dispose(); session = null; } } @Override public IFileManager getFileManager() { return this.fileManager; } @Override public ResourceDesc[] getResourceDescriptors() { return registry.toArray(new ResourceDesc[registry.size()]); } @Override public ResourceDesc getResourceDesc(final String profile) { if (profile == null) { return null; } return fileManager.getResourceDesc(profile); } @Override public void addListener(PropertyChangeListener listener) { pcs.addPropertyChangeListener(listener); } @Override public void removeListener(PropertyChangeListener listener) { pcs.removePropertyChangeListener(listener); } @Override public ResourceDesc getResourceDesc(String refID, String version) { synchronized (registry) { for (ResourceDesc desc : registry) { if (desc.getIdentifier().equals(refID) && desc.getVersion().equals(version)) { return desc; } } } return null; } }