/* * Copyright (c) 2012 Data Harmonisation Panel * * All rights reserved. This program and the accompanying materials are made * available under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution. If not, see <http://www.gnu.org/licenses/>. * * Contributors: * HUMBOLDT EU Integrated Project #030962 * Data Harmonisation Panel <http://www.dhpanel.eu> */ package eu.esdihumboldt.hale.ui.service.project.internal; import java.io.File; import java.lang.reflect.InvocationTargetException; import java.net.URI; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import java.util.Set; import java.util.TreeSet; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.content.IContentType; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.MessageBox; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.operations.IWorkbenchOperationSupport; import org.osgi.framework.Version; import com.google.common.base.Function; import com.google.common.collect.Collections2; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList.Builder; import com.google.common.collect.Iterables; import com.google.common.util.concurrent.ListenableFuture; import de.fhg.igd.osgi.util.configuration.AbstractDefaultConfigurationService; import de.fhg.igd.slf4jplus.ALogger; import de.fhg.igd.slf4jplus.ALoggerFactory; import de.fhg.igd.slf4jplus.ATransaction; import eu.esdihumboldt.hale.common.core.HalePlatform; import eu.esdihumboldt.hale.common.core.io.CachingImportProvider; import eu.esdihumboldt.hale.common.core.io.HaleIO; import eu.esdihumboldt.hale.common.core.io.IOAdvisor; import eu.esdihumboldt.hale.common.core.io.IOProvider; import eu.esdihumboldt.hale.common.core.io.ImportProvider; import eu.esdihumboldt.hale.common.core.io.Value; import eu.esdihumboldt.hale.common.core.io.extension.IOProviderDescriptor; import eu.esdihumboldt.hale.common.core.io.extension.IOProviderExtension; import eu.esdihumboldt.hale.common.core.io.impl.AbstractIOAdvisor; import eu.esdihumboldt.hale.common.core.io.project.ComplexConfigurationService; import eu.esdihumboldt.hale.common.core.io.project.ProjectDescription; import eu.esdihumboldt.hale.common.core.io.project.ProjectIO; import eu.esdihumboldt.hale.common.core.io.project.ProjectInfo; import eu.esdihumboldt.hale.common.core.io.project.ProjectReader; import eu.esdihumboldt.hale.common.core.io.project.ProjectWriter; import eu.esdihumboldt.hale.common.core.io.project.model.IOConfiguration; import eu.esdihumboldt.hale.common.core.io.project.model.IOConfigurationResource; import eu.esdihumboldt.hale.common.core.io.project.model.Project; import eu.esdihumboldt.hale.common.core.io.project.model.ProjectFile; import eu.esdihumboldt.hale.common.core.io.project.model.Resource; import eu.esdihumboldt.hale.common.core.io.project.util.LocationUpdater; import eu.esdihumboldt.hale.common.core.io.report.IOReport; import eu.esdihumboldt.hale.common.core.io.supplier.DefaultInputSupplier; import eu.esdihumboldt.hale.common.core.io.supplier.FileIOSupplier; import eu.esdihumboldt.hale.common.core.service.cleanup.Cleanup; import eu.esdihumboldt.hale.common.core.service.cleanup.CleanupContext; import eu.esdihumboldt.hale.common.core.service.cleanup.CleanupService; import eu.esdihumboldt.hale.common.core.service.cleanup.TemporaryFiles; import eu.esdihumboldt.hale.common.instance.helper.PropertyResolver; import eu.esdihumboldt.hale.common.instance.io.InstanceIO; import eu.esdihumboldt.hale.ui.HaleUI; import eu.esdihumboldt.hale.ui.io.project.OpenProjectWizard; import eu.esdihumboldt.hale.ui.io.project.SaveProjectWizard; import eu.esdihumboldt.hale.ui.io.project.update.SchemaUpdateDialog; import eu.esdihumboldt.hale.ui.service.instance.InstanceService; import eu.esdihumboldt.hale.ui.service.project.CacheCallback; import eu.esdihumboldt.hale.ui.service.project.ProjectResourcesUtil; import eu.esdihumboldt.hale.ui.service.project.ProjectService; import eu.esdihumboldt.hale.ui.service.project.RecentProjectsService; import eu.esdihumboldt.hale.ui.service.project.UILocationUpdater; import eu.esdihumboldt.hale.ui.service.report.ReportService; import eu.esdihumboldt.hale.ui.util.io.ThreadProgressMonitor; import eu.esdihumboldt.hale.ui.util.wizard.HaleWizardDialog; /** * Default implementation of the {@link ProjectService}. * * @author Thorsten Reitz * @author Simon Templer */ public class ProjectServiceImpl extends AbstractProjectService implements ProjectService { /** * Advisor for opening a project. */ private final class OpenProjectAdvisor extends AbstractIOAdvisor<ProjectReader> { private final boolean updateSchema; /** * Create an advisor for opening a project. * * @param updateSchema if the option to update the schema should be * offered */ public OpenProjectAdvisor(boolean updateSchema) { super(); this.updateSchema = updateSchema; } @Override public void updateConfiguration(ProjectReader provider) { super.updateConfiguration(provider); // set project files Map<String, ProjectFile> projectFiles = ProjectIO .createDefaultProjectFiles(HaleUI.getServiceProvider()); provider.setProjectFiles(projectFiles); } @Override public void handleResults(ProjectReader provider) { // no change check as this is performed by clean if (!internalClean()) { return; } // check if project reader requires clean-up if (provider instanceof TemporaryFiles || provider instanceof Cleanup) { CleanupService cs = HalePlatform.getService(CleanupService.class); if (provider instanceof TemporaryFiles) { cs.addTemporaryFiles(CleanupContext.PROJECT, Iterables .toArray(((TemporaryFiles) provider).getTemporaryFiles(), File.class)); } if (provider instanceof Cleanup) { cs.addCleaner(CleanupContext.PROJECT, ((Cleanup) provider)); } } synchronized (ProjectServiceImpl.this) { main = provider.getProject(); if (provider.getSource() != null) { // loaded project updater = new UILocationUpdater(main, provider.getSource().getLocation()); updater.updateProject(true); if ("file".equalsIgnoreCase(provider.getSource().getLocation().getScheme())) { projectFile = new File(provider.getSource().getLocation()); } else { projectFile = null; } projectLocation = provider.getSource().getLocation(); } else { // project template (from object) projectFile = null; projectLocation = null; } changed = false; RecentProjectsService rfs = PlatformUI.getWorkbench() .getService(RecentProjectsService.class); if (projectFile != null) { rfs.add(projectFile.getAbsolutePath(), main.getName()); } // XXX safe history in case of non-file loaded projects? // possibly always safe URI raw paths (and show the history // with decoded paths and removed file:/ in case of files)? // else // rfs.add(provider.getSource().getLocation().getRawPath(), // main.getName()); // store the content type the project was loaded with IContentType ct = provider.getContentType(); if (ct == null && provider.getSource() != null) { log.warn( "Project content type was not determined during load, trying auto-detection"); try { URI loc = provider.getSource().getLocation(); String filename = null; if (loc != null) { filename = loc.getPath(); } ct = HaleIO.findContentType(ProjectReader.class, provider.getSource(), filename); } catch (Exception e) { // ignore } if (ct == null) { log.error("Could not determine content type of loaded project"); } } projectLoadContentType = ct; } updateWindowTitle(); // execute loaded I/O configurations List<IOConfiguration> confs; synchronized (ProjectServiceImpl.this) { confs = new ArrayList<IOConfiguration>(main.getResources()); } // before execution, perform eventual schema update boolean updated = false; if (updateSchema) { final Display display = PlatformUI.getWorkbench().getDisplay(); final AtomicReference<List<IOConfiguration>> updatedConfigs = new AtomicReference<>(); final List<IOConfiguration> original = confs; display.syncExec(new Runnable() { @Override public void run() { SchemaUpdateDialog dlg = new SchemaUpdateDialog(display.getActiveShell(), original); if (dlg.open() == Dialog.OK) { updatedConfigs.set(dlg.getConfigurations()); } } }); List<IOConfiguration> newConfs = updatedConfigs.get(); if (newConfs != null && !newConfs.equals(confs)) { // update project synchronized (ProjectServiceImpl.this) { main.getResources().clear(); main.getResources().addAll(newConfs); } // replace confs confs = newConfs; updated = true; } } executeConfigurations(confs); // notify listeners Map<String, ProjectFile> projectFiles = provider.getProjectFiles(); notifyExportConfigurationChanged(); // apply remaining project files for (ProjectFile file : projectFiles.values()) { // XXX do this in a Job or something? file.apply(); } // reset changed to false if it was altered through the project // files being applied // FIXME this is ugly XXX what if there actually is a real // resulting change? synchronized (ProjectServiceImpl.this) { changed = updated; } notifyAfterLoad(); updateWindowTitle(); } } /** * Configuration service backed by the internal {@link Project} */ private class ProjectConfigurationService extends AbstractDefaultConfigurationService implements ComplexConfigurationService { /** * Default constructor */ public ProjectConfigurationService() { super(new Properties()); } @Override protected String getValue(String key) { synchronized (ProjectServiceImpl.this) { Value value = main.getProperties().get(key); if (value == null) { return null; } return value.as(String.class); } } @Override protected void removeValue(String key) { synchronized (ProjectServiceImpl.this) { main.getProperties().remove(key); } setChanged(); notifyProjectSettingChanged(key, Value.NULL); } @Override protected void setValue(String key, String value) { synchronized (ProjectServiceImpl.this) { main.getProperties().put(key, Value.of(value)); } setChanged(); notifyProjectSettingChanged(key, Value.of(value)); } @Override public void setProperty(String name, Value value) { synchronized (ProjectServiceImpl.this) { if (value == null || value.getValue() == null) { main.getProperties().remove(name); } else { main.getProperties().put(name, value); } } setChanged(); notifyProjectSettingChanged(name, (value != null) ? (value) : (Value.NULL)); } @Override public Value getProperty(String name) { synchronized (ProjectServiceImpl.this) { Value value = main.getProperties().get(name); return (value != null) ? (value) : (Value.NULL); } } } private static final ALogger log = ALoggerFactory.getLogger(ProjectServiceImpl.class); private Project main; private final Version haleVersion; /** * The project file the project was loaded from. */ private File projectFile; /** * Location the project was loaded from, even if it was not a file. */ private URI projectLocation; private String appTitle; private final IOAdvisor<ProjectWriter> saveProjectAdvisor; private final IOAdvisor<ProjectReader> openProjectAdvisor; private final ProjectConfigurationService configurationService = new ProjectConfigurationService(); private boolean changed = false; private UILocationUpdater updater = new UILocationUpdater(null, null); /** * Stores the content type of the loaded project. */ private IContentType projectLoadContentType; private final OpenProjectAdvisor updateProjectAdvisor; /** * Default constructor */ public ProjectServiceImpl() { haleVersion = HalePlatform.getCoreVersion(); // Version.parseVersion(Display.getAppVersion()); synchronized (this) { main = createDefaultProject(); } // create advisors openProjectAdvisor = new OpenProjectAdvisor(false); updateProjectAdvisor = new OpenProjectAdvisor(true); saveProjectAdvisor = new AbstractIOAdvisor<ProjectWriter>() { @Override public void prepareProvider(ProjectWriter provider) { synchronized (ProjectServiceImpl.this) { provider.setProject(main); } } @Override public void updateConfiguration(ProjectWriter provider) { provider.getProject().setModified(new Date()); provider.getProject().setHaleVersion(haleVersion); Map<String, ProjectFile> projectFiles = ProjectIO .createDefaultProjectFiles(HaleUI.getServiceProvider()); provider.setProjectFiles(projectFiles); if (projectLocation != null) { provider.setPreviousTarget(projectLocation); } } @Override public void handleResults(ProjectWriter provider) { synchronized (ProjectServiceImpl.this) { projectFile = new File(provider.getTarget().getLocation()); projectLocation = provider.getTarget().getLocation(); changed = false; RecentProjectsService rfs = PlatformUI.getWorkbench() .getService(RecentProjectsService.class); rfs.add(projectFile.getAbsolutePath(), provider.getProject().getName()); // override the project load content type projectLoadContentType = provider.getContentType(); } notifyAfterSave(); updateWindowTitle(); } }; } /** * @see ProjectService#isChanged() */ @Override public boolean isChanged() { return changed; } /** * @see ProjectService#setChanged() */ @Override public void setChanged() { synchronized (this) { changed = true; } updateWindowTitle(); } /** * Execute a set of I/O configurations. * * @param configurations the I/O configurations */ private void executeConfigurations(final List<IOConfiguration> configurations) { // TODO sort by dependencies for (IOConfiguration conf : configurations) { executeConfiguration(conf); } } /** * Execute a single I/O configuration. * * @param conf the I/O configuration */ private void executeConfiguration(final IOConfiguration conf) { // work with a cloned configuration for the case that we make a relative // URI absolute IOConfiguration cloned = conf.clone(); updater.updateIOConfiguration(cloned, false); ProjectResourcesUtil.executeConfiguration(cloned, new CacheCallback() { @Override public void update(Value cache) { // update the original configuration with the new cache value conf.setCache(cache); // set the project status to changed setChanged(); } }); } private boolean internalClean() { if (!changeCheck()) { return false; } // reset current session descriptor ReportService repService = PlatformUI.getWorkbench().getService(ReportService.class); repService.updateCurrentSessionDescription(); // clean final IRunnableWithProgress op = new IRunnableWithProgress() { @Override public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { ATransaction trans = log.begin("Clean project"); CleanupService cs = HalePlatform.getService(CleanupService.class); if (cs != null) { cs.triggerProjectCleanup(); } monitor.beginTask("Clean project", IProgressMonitor.UNKNOWN); try { synchronized (this) { main = createDefaultProject(); projectFile = null; projectLocation = null; changed = false; } updateWindowTitle(); notifyClean(); // schemas aren't valid anymore, clear property resolver // cache PropertyResolver.clearCache(); } finally { monitor.done(); trans.end(); } // clean workbench history AFTER other cleans since they can // create operations IWorkbenchOperationSupport os = PlatformUI.getWorkbench().getOperationSupport(); os.getOperationHistory().dispose(os.getUndoContext(), true, true, false); // suppress the status being set to changed by the clean synchronized (ProjectServiceImpl.this) { changed = false; } updateWindowTitle(); } }; try { ThreadProgressMonitor.runWithProgressDialog(op, false); } catch (Exception e) { log.error("Error cleaning the project.", e); } return true; } /** * @see ProjectService#clean() */ @Override public void clean() { internalClean(); } /** * @see ProjectService#load(URI) */ @Override public void load(URI uri) { // no change check as this is done by clean before a new project is // loaded // use I/O provider and content type mechanisms to enable loading of a // project file ProjectReader reader = HaleIO.findIOProvider(ProjectReader.class, new DefaultInputSupplier(uri), uri.getPath()); if (reader != null) { // configure reader reader.setSource(new DefaultInputSupplier(uri)); ProjectResourcesUtil.executeProvider(reader, openProjectAdvisor, null); } else { log.userError("The project format is not supported."); } } @Override public void loadTemplate(Project project) { // no change check as this is done by clean before a new project is // loaded ProjectReader reader = new DummyProjectReader(project); ProjectResourcesUtil.executeProvider(reader, openProjectAdvisor, null); } /** * Update the window title */ private void updateWindowTitle() { Runnable run = new Runnable() { @Override public void run() { // init appTitle if (appTitle == null) { if (PlatformUI.getWorkbench().getWorkbenchWindowCount() > 0) { appTitle = PlatformUI.getWorkbench() ./* * getWorkbenchWindows( )[0] */getActiveWorkbenchWindow().getShell().getText(); } else { return; } } String title; if (projectFile == null) { title = appTitle; } else { String pn = getProjectInfo().getName(); title = appTitle + " - " + ((pn == null || pn.isEmpty()) ? ("Unnamed") : (pn)) + " - " + projectFile; } if (changed) { title = title + "*"; //$NON-NLS-1$ } PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell().setText(title); } }; PlatformUI.getWorkbench().getDisplay().syncExec(run); } /** * @see ProjectService#save() */ @Override public void save() { File projectFile; IOConfiguration saveConfig; synchronized (this) { projectFile = this.projectFile; saveConfig = main.getSaveConfiguration(); } if (projectFile != null) { Collection<IOProviderDescriptor> providers = HaleIO .getProviderFactories(ProjectWriter.class); // use configuration from previous save if possible if (saveConfig != null) { // get provider ... ProjectWriter writer = null; for (IOProviderDescriptor factory : providers) { if (factory.getIdentifier().equals(saveConfig.getProviderId())) { // found the matching factory /* * Check if the content type the project was loaded with * is supported for saving. * * Example for a changed content type: A saved project * archive may have been extracted and the internal XML * project file loaded. */ if (projectLoadContentType != null) { if (factory.getSupportedTypes() == null || !factory.getSupportedTypes() .contains(projectLoadContentType)) { log.warn( "Project cannot be saved with the same settings it was originally saved with, as the content type has changed."); break; } } try { writer = (ProjectWriter) factory.createExtensionObject(); } catch (Exception e) { log.error("Could not create project writer", e); } } } if (writer != null) { // configure provider writer.loadConfiguration(saveConfig.getProviderConfiguration()); // overwrite target with projectFile (as it may have been // moved externally) writer.setTarget(new FileIOSupplier(projectFile)); ProjectResourcesUtil.executeProvider(writer, saveProjectAdvisor, null); } else { log.info( "The project cannot be saved because the format the project was saved with is not available or has changed."); // use save as instead saveAs(); } } else { // use I/O provider and content type mechanisms to try saving // the project file ProjectWriter writer = HaleIO.findIOProvider(ProjectWriter.class, new FileIOSupplier(projectFile), projectFile.getAbsolutePath()); if (writer != null) { ProjectResourcesUtil.executeProvider(writer, saveProjectAdvisor, null); } else { log.error("The project cannot be saved because the format is not available."); // use save as instead saveAs(); } } } else { saveAs(); } } /** * @see ProjectService#getConfigurationService() */ @Override public ComplexConfigurationService getConfigurationService() { return configurationService; } /** * @see ProjectService#saveAs() */ @Override public void saveAs() { PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() { @Override public void run() { SaveProjectWizard wizard; if (projectLoadContentType != null && projectLoadContentType.getId() .equals(ProjectIO.PROJECT_ARCHIVE_CONTENT_TYPE_ID)) { /* * For project archives, saving the project has to be * restricted to project archives again, as the files only * reside in a temporary location. */ wizard = new SaveProjectWizard(projectLoadContentType); } else { wizard = new SaveProjectWizard(null); } wizard.setAdvisor(saveProjectAdvisor, null); Shell shell = Display.getCurrent().getActiveShell(); HaleWizardDialog dialog = new HaleWizardDialog(shell, wizard); dialog.open(); } }); } @Override public ListenableFuture<IOReport> export(ProjectWriter writer) { IOAdvisor<ProjectWriter> exportAdvisor = new AbstractIOAdvisor<ProjectWriter>() { @Override public void prepareProvider(ProjectWriter provider) { saveProjectAdvisor.prepareProvider(provider); } @Override public void updateConfiguration(ProjectWriter provider) { saveProjectAdvisor.updateConfiguration(provider); } }; return ProjectResourcesUtil.executeProvider(writer, exportAdvisor, true, null); } /** * @see ProjectService#open() */ @Override public void open() { // no change check as this is done by clean before a new project is // loaded // open PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() { @Override public void run() { OpenProjectWizard wizard = new OpenProjectWizard(); wizard.setAdvisor(openProjectAdvisor, null); Shell shell = Display.getCurrent().getActiveShell(); HaleWizardDialog dialog = new HaleWizardDialog(shell, wizard); dialog.open(); } }); } @Override public void update() { // no change check as this is done by clean before a new project is // loaded URI currentLocation = null; synchronized (this) { currentLocation = projectLocation; } if (currentLocation != null) { // use I/O provider and content type mechanisms to enable loading of // a project file ProjectReader reader = HaleIO.findIOProvider(ProjectReader.class, new DefaultInputSupplier(currentLocation), currentLocation.getPath()); if (reader != null) { // configure reader reader.setSource(new DefaultInputSupplier(currentLocation)); ProjectResourcesUtil.executeProvider(reader, updateProjectAdvisor, null); } else { log.userError("The project format is not supported."); } } else { log.userError("The project needs to be saved to a file before you can reload it."); } } /** * Check if there are changes and offer the user to save the project. * * @return if the caller should continue */ private boolean changeCheck() { if (!isChanged()) { return true; } final Display display = PlatformUI.getWorkbench().getDisplay(); final AtomicBoolean returnValue = new AtomicBoolean(); display.syncExec(new Runnable() { @Override public void run() { MessageBox mb = new MessageBox(display.getActiveShell(), SWT.YES | SWT.NO | SWT.CANCEL | SWT.ICON_QUESTION); mb.setMessage("Save changes to the current project?"); //$NON-NLS-1$ mb.setText("Unsaved changes"); //$NON-NLS-1$ int result = mb.open(); if (result == SWT.CANCEL) { returnValue.set(false); } else if (result == SWT.YES) { // try saving project save(); if (isChanged()) { returnValue.set(false); } else { returnValue.set(true); } } else { returnValue.set(true); } } }); return returnValue.get(); } /** * Create a project with default values * * @return the created project */ private Project createDefaultProject() { Project project = new Project(); project.setCreated(new Date()); project.setAuthor(System.getProperty("user.name")); project.setHaleVersion(haleVersion); project.setName(null); return project; } /** * @see ProjectService#getProjectInfo() */ @Override public ProjectInfo getProjectInfo() { synchronized (this) { return main; } } @Override public void updateProjectInfo(ProjectDescription info) { synchronized (this) { if (main != null) { main.setAuthor(info.getAuthor()); main.setDescription(info.getDescription()); main.setName(info.getName()); } } notifyProjectInfoChanged(getProjectInfo()); } /** * @see ProjectService#rememberIO(String, String, IOProvider) */ @Override public void rememberIO(String actionId, String providerId, IOProvider provider) { // populate an IOConfiguration from the given data IOConfiguration conf = new IOConfiguration(); conf.setActionId(actionId); conf.setProviderId(providerId); provider.storeConfiguration(conf.getProviderConfiguration()); if (provider instanceof CachingImportProvider) { conf.setCache(((CachingImportProvider) provider).getCache()); } // add configuration to project synchronized (this) { main.getResources().add(conf); } setChanged(); notifyResourceAdded(actionId, new IOConfigurationResource(conf, projectLocation)); } @Override public List<? extends Resource> removeResources(String actionId) { Builder<Resource> removedBuilder = ImmutableList.builder(); synchronized (this) { Iterator<IOConfiguration> iter = main.getResources().iterator(); while (iter.hasNext()) { IOConfiguration conf = iter.next(); if (conf.getActionId().equals(actionId)) { iter.remove(); removedBuilder.add(new IOConfigurationResource(conf, projectLocation)); } } } setChanged(); List<Resource> removedResources = removedBuilder.build(); notifyResourcesRemoved(actionId, removedResources); return removedResources; } @Override public void removeResource(String resourceId) { Resource removedResource = null; synchronized (this) { Iterator<IOConfiguration> iter = main.getResources().iterator(); while (iter.hasNext()) { IOConfiguration conf = iter.next(); Value idValue = conf.getProviderConfiguration() .get(ImportProvider.PARAM_RESOURCE_ID); if (idValue != null) { String id = idValue.as(String.class); if (resourceId.equals(id)) { // match found, remove iter.remove(); removedResource = new IOConfigurationResource(conf, projectLocation); break; } } } } if (removedResource != null) { setChanged(); notifyResourcesRemoved(removedResource.getActionId(), Collections.singletonList(removedResource)); } } @Override public boolean hasResources(String actionId) { synchronized (this) { Iterator<IOConfiguration> iter = main.getResources().iterator(); while (iter.hasNext()) { IOConfiguration conf = iter.next(); if (conf.getActionId().equals(actionId)) { return true; } } } return false; } @Override public void executeAndRemember(IOConfiguration conf) { executeConfiguration(conf); synchronized (this) { main.getResources().add(conf); } setChanged(); notifyResourceAdded(conf.getActionId(), new IOConfigurationResource(conf, projectLocation)); } @Override public void reloadSourceData() { IRunnableWithProgress op = new IRunnableWithProgress() { @Override public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { monitor.beginTask("Reload source data", IProgressMonitor.UNKNOWN); monitor.subTask("Clear loaded instances"); // drop the existing instances InstanceService is = PlatformUI.getWorkbench().getService(InstanceService.class); is.dropInstances(); // reload the instances for (IOConfiguration conf : main.getResources()) { if (InstanceIO.ACTION_LOAD_SOURCE_DATA.equals(conf.getActionId())) { executeConfiguration(conf); } } monitor.done(); } }; try { ThreadProgressMonitor.runWithProgressDialog(op, false); } catch (Exception e) { log.error("Executing data reload failed", e); } } @Override public Iterable<? extends Resource> getResources() { synchronized (this) { return Collections2.transform(main.getResources(), new Function<IOConfiguration, Resource>() { @Override public Resource apply(IOConfiguration conf) { return new IOConfigurationResource(conf, projectLocation); } }); } } /** * @see eu.esdihumboldt.hale.ui.service.project.ProjectService#getLocationUpdater() */ @Override public LocationUpdater getLocationUpdater() { return updater; } @Override public void addExportConfiguration(String name, IOConfiguration conf) { main.getExportConfigurations().put(name, conf); setChanged(); notifyExportConfigurationChanged(); } @Override public void removeExportConfiguration(String name) { main.getExportConfigurations().remove(name); setChanged(); notifyExportConfigurationChanged(); } @Override public IOConfiguration getExportConfiguration(String name) { IOConfiguration conf = main.getExportConfigurations().get(name); if (conf != null) { return conf.clone(); } return null; } @Override public Collection<String> getExportConfigurationNames() { return Collections.unmodifiableSet(main.getExportConfigurations().keySet()); } @Override public Collection<String> getExportConfigurationNames( Class<? extends IOProvider> providerClass) { Set<String> result = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); for (Entry<String, IOConfiguration> entry : main.getExportConfigurations().entrySet()) { IOConfiguration conf = entry.getValue(); String providerId = conf.getProviderId(); IOProviderDescriptor descr = IOProviderExtension.getInstance().getFactory(providerId); if (descr != null && providerClass.isAssignableFrom(descr.getProviderType())) { result.add(entry.getKey()); } } return result; } @Override public URI getLoadLocation() { return projectLocation; } @Override public Value getProperty(String name) { return getConfigurationService().getProperty(name); } }