Java tutorial
/* * Copyright 2013 Modeliosoft * * This file is part of Modelio. * * Modelio is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Modelio is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Modelio. If not, see <http://www.gnu.org/licenses/>. * */ package org.modelio.app.project.core.services; import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.nio.file.FileSystemException; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Path; import java.nio.file.PathMatcher; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.UUID; import java.util.zip.ZipEntry; import javax.inject.Inject; import com.modeliosoft.modelio.javadesigner.annotations.objid; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.core.runtime.preferences.InstanceScope; import org.eclipse.e4.core.contexts.IEclipseContext; import org.eclipse.e4.core.di.annotations.Optional; import org.eclipse.e4.core.di.extensions.EventTopic; import org.eclipse.e4.core.services.events.IEventBroker; import org.eclipse.e4.core.services.statusreporter.StatusReporter; import org.eclipse.e4.ui.services.IServiceConstants; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.jface.window.IShellProvider; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.modelio.app.core.IModelioEventService; import org.modelio.app.core.events.ModelioEvent; import org.modelio.app.preferences.GProjectPreferenceNode; import org.modelio.app.preferences.GProjectPreferenceStore; import org.modelio.app.project.core.creation.IProjectCreationData; import org.modelio.app.project.core.creation.IProjectCreator; import org.modelio.app.project.core.plugin.AppProjectCore; import org.modelio.app.project.core.prefs.ProjectPreferencesHelper; import org.modelio.app.project.core.prefs.ProjectPreferencesKeys; import org.modelio.core.ui.progress.ModelioProgressAdapter; import org.modelio.gproject.data.project.DescriptorWriter; import org.modelio.gproject.data.project.FragmentDescriptor; import org.modelio.gproject.data.project.ProjectDescriptor; import org.modelio.gproject.fragment.FragmentAuthenticationException; import org.modelio.gproject.fragment.FragmentMigrationNeededException; import org.modelio.gproject.fragment.FragmentState; import org.modelio.gproject.fragment.Fragments; import org.modelio.gproject.fragment.IProjectFragment; import org.modelio.gproject.gproject.FragmentConflictException; import org.modelio.gproject.gproject.GProject; import org.modelio.gproject.gproject.GProjectAuthenticationException; import org.modelio.gproject.gproject.GProjectConfigurer.Failure; import org.modelio.gproject.gproject.GProjectEvent; import org.modelio.gproject.gproject.GProjectEventType; import org.modelio.gproject.gproject.GProjectFactory; import org.modelio.gproject.gproject.IProjectMonitor; import org.modelio.gproject.model.IMModelServices; import org.modelio.gproject.model.MModelServices; import org.modelio.gproject.module.IModuleCatalog; import org.modelio.mda.infra.service.IModuleService; import org.modelio.metamodel.factory.ModelFactory; import org.modelio.metamodel.uml.statik.DataType; import org.modelio.metamodel.uml.statik.VisibilityMode; import org.modelio.ui.progress.IModelioProgressService; import org.modelio.vbasic.auth.IAuthData; import org.modelio.vbasic.files.FileUtils; import org.modelio.vbasic.files.Unzipper; import org.modelio.vbasic.files.Zipper; import org.modelio.vbasic.progress.IModelioProgress; import org.modelio.vcore.session.api.ICoreSession; import org.modelio.vcore.smkernel.AccessDeniedException; import org.modelio.vcore.smkernel.mapi.MRef; import org.osgi.service.event.Event; import org.osgi.service.event.EventHandler; import org.osgi.service.prefs.BackingStoreException; /** * {@link IProjectService} implementation. */ @objid("00964fc4-9ea6-103b-a520-001ec947cd2a") class ProjectService implements IProjectService, EventHandler { @objid("00270c0e-1e45-105b-aa42-001ec947cd2a") private final IEclipseContext context; @objid("003dc516-7baa-10b3-9941-001ec947cd2a") private static final String LAST_USED_WORKSPACE_PREFERENCE_KEY = "workspace.last"; @objid("00801182-acc2-103b-a520-001ec947cd2a") private Path workspace; @objid("008017fe-acc2-103b-a520-001ec947cd2a") private GProject project; @objid("00801e98-acc2-103b-a520-001ec947cd2a") private ICoreSession session; @objid("f354133c-7447-4867-895c-f63bf790b2f0") private GProjectPreferenceStore prefsStore; /** * C'tor * @param context the Eclipse context. */ @objid("00802442-acc2-103b-a520-001ec947cd2a") public ProjectService(final IEclipseContext context) { this.context = context; final IEventBroker eventBroker = context.get(IEventBroker.class); eventBroker.subscribe("BATCH", this); } /** * @Inheritdoc */ @objid("008063d0-acc2-103b-a520-001ec947cd2a") @Override public void changeWorkspace(Path workspacePath) { if (this.project != null) { throw new IllegalStateException("A project is already opened."); } if (Files.exists(workspacePath) && Files.isDirectory(workspacePath)) { this.workspace = workspacePath; writePreferedWorkspace(workspacePath); this.context.get(IModelioEventService.class).postAsyncEvent(this, ModelioEvent.WORKSPACE_SWITCH, workspacePath); } else { throw new IllegalArgumentException("Invalid workspace path: " + workspacePath); } } @objid("e92ae6b5-2c62-44c7-8665-3a6bd7f76ee9") @Override public void createProject(final IProjectCreator projectCreator, final IProjectCreationData data, IProgressMonitor monitor) throws IOException { Objects.requireNonNull(projectCreator); Objects.requireNonNull(data); // Get the module catalog used by the application. final IModuleCatalog moduleCatalog = getModuleCatalog(); IModelioProgress progress = monitor == null ? null : new ModelioProgressAdapter(monitor); projectCreator.createProject(data, moduleCatalog, progress); this.context.get(IModelioEventService.class).postAsyncEvent(this, ModelioEvent.WORKSPACE_CONTENTS, getWorkspace()); } @objid("971ad6d9-026d-11e2-8189-001ec947ccaf") @Override public void openProject(ProjectDescriptor projectToOpen, IAuthData authData, IProgressMonitor monitor) throws GProjectAuthenticationException, IOException { if (this.project != null) { throw new IllegalStateException("A project is already opened."); } if (projectToOpen == null) { throw new IllegalArgumentException("Cannot open 'null' project."); } final String taskName = AppProjectCore.I18N.getMessage("ProjectService.open.task", projectToOpen.getName()); final SubMonitor mon = SubMonitor.convert(monitor, taskName, 200); mon.subTask(taskName); // Get the module catalog used by the application. final IModuleCatalog moduleCatalog = getModuleCatalog(); final ProjectMonitor projectMonitor = new ProjectMonitor(); this.project = GProjectFactory.openProject(projectToOpen, authData, moduleCatalog, projectMonitor, new ModelioProgressAdapter(mon.newChild(50))); try (ProjectCloser closer = new ProjectCloser()) { this.session = this.project.getSession(); // Project preferences this.prefsStore = new GProjectPreferenceStore(this.project); // Add the services that depends on project to the context // model service final MModelServices modelServices = new MModelServices(this.project); this.context.set(IMModelServices.class, modelServices); // Check for migration migrateFragments(mon, 50); mon.setWorkRemaining(100); // Fire PROJECT_OPENING this.context.get(IModelioEventService.class).postSyncEvent(this, ModelioEvent.PROJECT_OPENING, this.project); // Start all modules IModuleService moduleService = this.context.get(IModuleService.class); moduleService.startAllModules(this.project, mon.newChild(50)); // Synchronize the project against server try { ProjectSynchronizer projectSynchronizer = new ProjectSynchronizer(this.project, moduleService); projectSynchronizer.synchronize(mon.newChild(50)); if (!projectSynchronizer.getFailures().isEmpty()) reportSynchronizationFailures(projectSynchronizer); } catch (IOException e) { reportSynchronizationFail(e); } // Configure project preferences installProjectPreferencesDefaults(); installProjectPreferences(); // Fire PROJECT_OPENED this.context.get(IModelioEventService.class).postAsyncEvent(this, ModelioEvent.PROJECT_OPENED, this.project); // Validate project opening closer.abort(); projectMonitor.openInProgress = false; } } @objid("004dc0f6-8d1e-10b4-9941-001ec947cd2a") @Override public void openProject(String projectName, IAuthData authData, IProgressMonitor monitor) throws GProjectAuthenticationException { final Path projectPath = getWorkspace().resolve(projectName); final Path confFile = projectPath.resolve("project.conf"); if (Files.isRegularFile(confFile)) { try { ProjectDescriptor pDesc = GProjectFactory.readProjectDirectory(projectPath); openProject(pDesc, authData, monitor); } catch (final IOException e) { AppProjectCore.LOG.error(e); } } } @objid("00809bf2-acc2-103b-a520-001ec947cd2a") @Override public void closeProject(GProject projectToClose) throws IllegalStateException { checkProjectOpened(); if (projectToClose == null || projectToClose != this.project) { throw new IllegalArgumentException("Closing invalid " + projectToClose + " project."); } this.context.get(IModelioEventService.class).postSyncEvent(this, ModelioEvent.PROJECT_CLOSING, projectToClose); // FIXME use the current monitor... IModuleService moduleService = this.context.get(IModuleService.class); if (moduleService != null) moduleService.stopAllModules(this.project); this.project.close(); this.project = null; this.session = null; // preferences store this.prefsStore = null; // Invalidate the current model services instance before removing it // so that if some reference have been kept on it by @&#!%*!& // programmers, the error will be detected. final IMModelServices s = this.context.get(IMModelServices.class); ((MModelServices) s).invalidateProject(null); this.context.remove(IMModelServices.class); // remove IModuleService from context this.context.remove(IModuleService.class); this.context.get(IModelioEventService.class).postAsyncEvent(this, ModelioEvent.PROJECT_CLOSED, null); } @objid("0080b83a-acc2-103b-a520-001ec947cd2a") @Override public void saveProject(IProgressMonitor monitor) throws IOException { checkProjectOpened(); try { final String taskName = AppProjectCore.I18N.getMessage("ProjectService.save.task", this.project.getName()); SubMonitor m = SubMonitor.convert(monitor, taskName, 1000); this.context.set(IProgressMonitor.class, m.newChild(50)); this.context.get(IModelioEventService.class).postSyncEvent(this, ModelioEvent.PROJECT_SAVING, this.project); this.context.remove(IProgressMonitor.class); this.project.save(new ModelioProgressAdapter(m.newChild(900))); this.prefsStore.save(); this.context.get(IModelioEventService.class).postAsyncEvent(this, ModelioEvent.PROJECT_SAVED, this.project); } catch (final IOException e) { throw e; } } @objid("00804076-acc2-103b-a520-001ec947cd2a") @Override public String getName() { return "ProjectService"; } @objid("0080cffa-acc2-103b-a520-001ec947cd2a") @Override public GProject getOpenedProject() { return this.project; } @objid("14aa57e7-a7cb-4ee1-82ed-973bb22d6870") @Override public IPreferenceStore getProjectPreferences(String nodeId) { return new GProjectPreferenceNode(this.prefsStore, nodeId); } @objid("0053aa84-bb2f-103c-a520-001ec947cd2a") @Override public ICoreSession getSession() { return (this.project != null) ? this.project.getSession() : null; } @objid("0080f426-acc2-103b-a520-001ec947cd2a") @Override public Path getWorkspace() { if (this.workspace == null) { this.workspace = readPreferedWorkspace(); } return this.workspace; } @objid("ca2f60e4-1f24-4956-965e-92f53059258c") @Override public boolean isDirty() { boolean isSessionDirty = this.session != null && this.session.isDirty(); boolean isPrefStoreDirty = this.prefsStore != null && this.prefsStore.needsSaving(); return isSessionDirty || isPrefStoreDirty; } @objid("0089dd7a-8c65-103c-a520-001ec947cd2a") @Override public void deleteProject(ProjectDescriptor projectToDelete) throws IOException, FileSystemException { // TODO this is a quite naive implementation // should deal with project path for delegating project FileUtils.delete(projectToDelete.getPath()); refreshWorkspace(); } @objid("0089fb8e-8c65-103c-a520-001ec947cd2a") @Override public void exportProject(ProjectDescriptor projectToExport, Path archivePath, IModelioProgress monitor) { final Zipper zipper = new Zipper(archivePath); try { // not export .runtime directory PathMatcher directoryMatcher = FileSystems.getDefault() .getPathMatcher(("glob:**" + projectToExport.getPath().resolve(".runtime").resolve("modules")) .replace("\\", "\\\\")); List<PathMatcher> skipDirectoryMatchers = new ArrayList<>(); skipDirectoryMatchers.add(directoryMatcher); zipper.compress(projectToExport.getPath(), skipDirectoryMatchers, null, monitor, null); AppProjectCore.LOG.info("Exported archive '%s' %d bytes.", archivePath, Files.size(archivePath)); } catch (final IOException e) { AppProjectCore.LOG.error(e); } } @objid("008a1ee8-8c65-103c-a520-001ec947cd2a") @Override public void importProject(Path archiveFile) { final Unzipper unzipper = new Unzipper(); final IModelioProgress monitor = null; try { ZipEntry[] projectConf = unzipper.findEntry(archiveFile.toFile(), "^[^/]+/project\\.conf$"); String projectName = ""; if (projectConf.length == 1) { projectName = projectConf[0].getName().substring(0, projectConf[0].getName().indexOf("/")); if (getWorkspace().resolve(projectName).toFile().exists()) { // Checks for an already existing project if (!MessageDialog.openQuestion(null, AppProjectCore.I18N.getString("CannotImportExistingProjectTitle"), AppProjectCore.I18N.getMessage("CannotImportExistingProjectMsg", projectName))) { return; } } unzipper.unzip(archiveFile, getWorkspace(), monitor); AppProjectCore.LOG.info("Imported archive '%s' %d bytes.", archiveFile, Files.size(archiveFile)); refreshWorkspace(); } else { MessageDialog.openInformation(null, AppProjectCore.I18N.getString("InvalidProjectArchiveTitle"), AppProjectCore.I18N.getMessage("InvalidProjectArchiveMsg", archiveFile.toString())); } } catch (final IOException e) { AppProjectCore.LOG.error(e); } } @objid("008a3cfc-8c65-103c-a520-001ec947cd2a") @Override public void createProject(final IProjectCreator projectCreator, final IProjectCreationData data) { Objects.requireNonNull(projectCreator); Objects.requireNonNull(data); // Get the module catalog used by the application. final IModuleCatalog moduleCatalog = getModuleCatalog(); // Provide a progress monitor as parameter if possible IModelioProgressService progressService = this.context.get(IModelioProgressService.class); if (progressService != null) { try { final String title = AppProjectCore.I18N.getString("CreateProject.ProgressDialog.title"); progressService.run(title, false, false, new IRunnableWithProgress() { @Override public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { try { IModelioProgress progress = new ModelioProgressAdapter(monitor); progress.beginTask(title, 100); projectCreator.createProject(data, moduleCatalog, progress); } catch (IOException e) { AppProjectCore.LOG.error(e); } } }); } catch (InvocationTargetException | InterruptedException e) { AppProjectCore.LOG.error(e); } } else { // No progress service available try { projectCreator.createProject(data, moduleCatalog, null); } catch (IOException e) { AppProjectCore.LOG.error(e); } } this.context.get(IModelioEventService.class).postAsyncEvent(this, ModelioEvent.WORKSPACE_CONTENTS, getWorkspace()); } @objid("005385e0-bb2f-103c-a520-001ec947cd2a") @Override public void addFragment(GProject openedProject, FragmentDescriptor fragmentDescriptor, IProgressMonitor monitor) throws FragmentConflictException { final IProjectFragment newFragment = Fragments.getFactory(fragmentDescriptor) .instantiate(fragmentDescriptor); openedProject.registerFragment(newFragment, new ModelioProgressAdapter(monitor)); this.context.get(IModelioEventService.class).postAsyncEvent(this, ModelioEvent.FRAGMENT_ADDED, newFragment); } @objid("002e01f8-a4c3-1044-a30e-001ec947cd2a") @Override public void removeFragment(GProject openedProject, IProjectFragment fragmentToRemove) { if (fragmentToRemove == null) { throw new IllegalArgumentException("Fragment must not be null."); } openedProject.unregisterFragment(fragmentToRemove); // Delete the fragment files. try { fragmentToRemove.delete(); } catch (final IOException e) { AppProjectCore.LOG.warning(e); } this.context.get(IModelioEventService.class).postAsyncEvent(this, ModelioEvent.FRAGMENT_REMOVED, fragmentToRemove); } @objid("008118fc-acc2-103b-a520-001ec947cd2a") @Override public void refreshWorkspace() { this.context.get(IModelioEventService.class).postAsyncEvent(this, ModelioEvent.WORKSPACE_CONTENTS, this.workspace); } @objid("6bcf2ddb-37b3-11e2-82ed-001ec947ccaf") IEclipseContext getContext() { return this.context; } @objid("004d1728-8d1e-10b4-9941-001ec947cd2a") @Inject @Optional public void onBATCH(@EventTopic("BATCH") final CommandLineData data) { final IEventBroker eventBroker = this.context.get(IEventBroker.class); eventBroker.unsubscribe(this); AppProjectCore.LOG.info("Running batch: %s", data.toString()); if (!data.isEmpty()) { Display.getCurrent().asyncExec(new BatchRunner(this, data)); } } @objid("004d9dc4-8d1e-10b4-9941-001ec947cd2a") @Override public void handleEvent(Event event) { switch (event.getTopic()) { case "BATCH": onBATCH((CommandLineData) event.getProperty("org.eclipse.e4.data")); return; default: return; } } /** * Get the workspace to use: * <ol> * <li>use the last used workspace as saved in the preferences</li> * <li>default to user's home directory otherwise</li> * </ol> * @return the workspace path */ @objid("0035c4b0-7baa-10b3-9941-001ec947cd2a") private static Path readPreferedWorkspace() { final IEclipsePreferences prefs = InstanceScope.INSTANCE.getNode(AppProjectCore.PLUGIN_ID); final String lastUsed = prefs.get(LAST_USED_WORKSPACE_PREFERENCE_KEY, null); if (lastUsed != null) { final Path lastPath = Paths.get(lastUsed); if (lastPath != null && Files.isDirectory(lastPath)) { return lastPath; // we are done } } // Preferences could not provide a valid workspace, default to user's // home Path defaultPath = Paths.get(System.getProperty("user.home"), "modelio", "workspace"); if (!Files.exists(defaultPath, LinkOption.NOFOLLOW_LINKS)) { (new File(defaultPath.toString())).mkdirs(); // create if the // default workspace // doesn't exist. } return defaultPath; } /** * Write the workspace preferences * @param workspace the workspace path */ @objid("0035eddc-7baa-10b3-9941-001ec947cd2a") private static void writePreferedWorkspace(Path workspace) { if (workspace != null) { final IEclipsePreferences prefs = InstanceScope.INSTANCE.getNode(AppProjectCore.PLUGIN_ID); prefs.put(LAST_USED_WORKSPACE_PREFERENCE_KEY, workspace.toString()); try { prefs.flush(); } catch (final BackingStoreException e) { AppProjectCore.LOG.error(e); } } } @objid("9de1f14d-8669-48e5-b0c0-11c43702c837") private void checkProjectOpened() throws IllegalStateException { if (this.project == null) { throw new IllegalStateException("No current project."); } } /** * Get a module catalog. * <p> * Returns the module catalog cache. Instantiate the module catalog and the * cache on first call. * @return the module catalog cache. */ @objid("e84ef926-a1af-4f78-9342-507d1c7efcb4") private IModuleCatalog getModuleCatalog() { // look for the module catalog return this.context.get(IModuleCatalog.class); } @objid("cb61fb6e-713f-480a-8fe4-42c7e06a13ec") private void installProjectPreferences() { // Setup the model factory initializer ModelFactory.INITIALIZER.setDefaultAttributeType(ProjectPreferencesHelper.getAttributeDefaultType(this)); ModelFactory.INITIALIZER .setDefaultAttributeVisibility(ProjectPreferencesHelper.getAttributeDefaultVisibility(this)); ModelFactory.INITIALIZER.setDefaultParameterType(ProjectPreferencesHelper.getParameterDefaultType(this)); ModelFactory.INITIALIZER.setDefaultReturnType(ProjectPreferencesHelper.getReturnDefaultType(this)); // Setup a listener for changes that will reconfigure the INITIALIZER // when project preferences change this.prefsStore.addPropertyChangeListener(new IPropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent event) { String name = event.getProperty(); if (name.endsWith(ProjectPreferencesKeys.ATT_DEFAULT_TYPE_PREFKEY)) ModelFactory.INITIALIZER.setDefaultAttributeType( ProjectPreferencesHelper.getAttributeDefaultType(ProjectService.this)); else if (name.endsWith(ProjectPreferencesKeys.ATT_DEFAULT_VIS_PREFKEY)) ModelFactory.INITIALIZER.setDefaultAttributeVisibility( ProjectPreferencesHelper.getAttributeDefaultVisibility(ProjectService.this)); else if (name.endsWith(ProjectPreferencesKeys.PARAM_DEFAULT_TYPE_PREFKEY)) ModelFactory.INITIALIZER.setDefaultParameterType( ProjectPreferencesHelper.getParameterDefaultType(ProjectService.this)); else if (name.endsWith(ProjectPreferencesKeys.RETURN_DEFAULT_TYPE_PREFKEY)) ModelFactory.INITIALIZER.setDefaultReturnType( ProjectPreferencesHelper.getReturnDefaultType(ProjectService.this)); } }); } @objid("7b203cde-7d61-4515-88a8-cb2cc182b426") private void installProjectPreferencesDefaults() { DataType stringDataType = this.project.getSession().getModel().findById(DataType.class, UUID.fromString("00000004-0000-000d-0000-000000000000")); DataType integerDataType = this.project.getSession().getModel().findById(DataType.class, UUID.fromString("00000004-0000-0009-0000-000000000000")); // During project creation the project might be opened once without // modeler module because of some configuration defect. In this case it is not possible to set the default // values, just do nothing to avoid stopping here where things would be difficult to understand by the user. if (stringDataType != null && integerDataType != null) { // Define default values if not already defined IPreferenceStore store = this.getProjectPreferences(ProjectPreferencesKeys.NODE_ID); if (store.getDefaultString(ProjectPreferencesKeys.ATT_DEFAULT_TYPE_PREFKEY).isEmpty()) { store.setDefault(ProjectPreferencesKeys.ATT_DEFAULT_TYPE_PREFKEY, new MRef(stringDataType).toString()); store.setToDefault(ProjectPreferencesKeys.ATT_DEFAULT_TYPE_PREFKEY); } if (store.getDefaultString(ProjectPreferencesKeys.ATT_DEFAULT_VIS_PREFKEY).isEmpty()) { store.setDefault(ProjectPreferencesKeys.ATT_DEFAULT_VIS_PREFKEY, VisibilityMode.PUBLIC.getName()); store.setToDefault(ProjectPreferencesKeys.ATT_DEFAULT_VIS_PREFKEY); } if (store.getDefaultString(ProjectPreferencesKeys.PARAM_DEFAULT_TYPE_PREFKEY).isEmpty()) { store.setDefault(ProjectPreferencesKeys.PARAM_DEFAULT_TYPE_PREFKEY, new MRef(stringDataType).toString()); store.setToDefault(ProjectPreferencesKeys.PARAM_DEFAULT_TYPE_PREFKEY); } if (store.getDefaultString(ProjectPreferencesKeys.RETURN_DEFAULT_TYPE_PREFKEY).isEmpty()) { store.setDefault(ProjectPreferencesKeys.RETURN_DEFAULT_TYPE_PREFKEY, new MRef(integerDataType).toString()); store.setToDefault(ProjectPreferencesKeys.RETURN_DEFAULT_TYPE_PREFKEY); } if (store.getDefaultString(ProjectPreferencesKeys.RICHNOTE_DEFAULT_TYPE_PREFKEY).isEmpty()) { // Use a default value String defaultValue; if (System.getProperty("os.name").equals("Linux")) { defaultValue = "application/vnd.oasis.opendocument.text"; } else { defaultValue = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; } store.setDefault(ProjectPreferencesKeys.RICHNOTE_DEFAULT_TYPE_PREFKEY, defaultValue); store.setToDefault(ProjectPreferencesKeys.RICHNOTE_DEFAULT_TYPE_PREFKEY); } } } @objid("ddfed9a9-bcb8-4683-9326-13ed63566396") @Override public void renameProject(ProjectDescriptor projectDescriptor, String name) throws IOException { final Path oldPath = projectDescriptor.getPath(); // Set the project name projectDescriptor.setName(name); // Save the new project conf Path confFilePath = oldPath.resolve("project.conf"); new DescriptorWriter().write(projectDescriptor, confFilePath); // Move the project directory itself final Path targetPath = oldPath.resolveSibling(name); Files.move(oldPath, targetPath, StandardCopyOption.ATOMIC_MOVE); refreshWorkspace(); } @objid("9cb90edd-3cb3-4b86-a51b-f0a3992de641") private void reportSynchronizationFail(final IOException e) { final String err = FileUtils.getLocalizedMessage(e); final String message = AppProjectCore.I18N.getMessage("ProjectService.ProjectSynchroFailed.message", this.project.getName(), err); AppProjectCore.LOG.warning(message); AppProjectCore.LOG.debug(e); // TODO detect batch mode and not display dialog box Display.getDefault().asyncExec(new Runnable() { @Override public void run() { String title = AppProjectCore.I18N.getMessage("ProjectService.ProjectSynchroFailed.title", getOpenedProject().getName()); MessageDialog.openWarning(Display.getCurrent().getActiveShell(), title, message); } }); } @objid("bc6e9b7c-48b4-4f36-ab76-51e1b856a5f2") private void migrateFragments(SubMonitor mon, int allowedMonWork) { new FragmentsMigrator(this.project).migrateFragments(mon, allowedMonWork); } @objid("41d09262-e599-4095-b93d-6e639bd3bc9a") private void reportSynchronizationFailures(ProjectSynchronizer projectSynchronizer) { // TODO detect batch mode and not display dialog box // TODO make a better dialog final StringBuilder sb = new StringBuilder(); sb.append(AppProjectCore.I18N.getMessage("ProjectService.ProjectSynchroProblems.message", this.project.getName())); for (Failure f : projectSynchronizer.getFailures()) { sb.append(" - ").append(f.getSourceIdentifier()).append(": "); Throwable cause = f.getCause(); if (cause instanceof IOException) sb.append(FileUtils.getLocalizedMessage((IOException) cause)); else if (cause instanceof AccessDeniedException) sb.append(cause.getLocalizedMessage()); else if (cause instanceof RuntimeException) sb.append(cause.toString()); else sb.append(cause.getLocalizedMessage()); } // Get a shell Shell shell = (Shell) this.context.getActive(IServiceConstants.ACTIVE_SHELL); if (shell == null) { IShellProvider sp = this.context.getActive(IShellProvider.class); if (sp != null) shell = sp.getShell(); } final Shell fshell = shell; final String title = AppProjectCore.I18N.getMessage("ProjectService.ProjectSynchroProblems.title", this.project.getName()); Display d = shell != null ? shell.getDisplay() : Display.getDefault(); d.syncExec(new Runnable() { @Override public void run() { MessageDialog.openWarning(fshell, title, sb.toString()); } }); } /** * ProjectService project monitor * <p> * TODO make a real implementation. This one only sends events to log. */ @objid("6bc806dc-37b3-11e2-82ed-001ec947ccaf") private final class ProjectMonitor implements IProjectMonitor { @objid("2f56600c-3346-4f15-920c-0ba9ca220429") boolean openInProgress = true; @objid("6bca6931-37b3-11e2-82ed-001ec947ccaf") ProjectMonitor() { // nothing } @objid("6bca6933-37b3-11e2-82ed-001ec947ccaf") @Override public void handleProjectEvent(GProjectEvent ev) { switch (ev.type) { case FRAGMENT_DOWN: if (this.openInProgress && ev.throwable instanceof FragmentMigrationNeededException) { // don't report migration needs because dialog asks for migration // on project opening. AppProjectCore.LOG.info("%s fragment requires migration: %s", ev.fragment.getId(), ev.message); } else if (this.openInProgress && ev.throwable instanceof FragmentAuthenticationException) { // don't report migration needs because caller asks for auth // on project opening. AppProjectCore.LOG.info("%s fragment requires authentication: %s", ev.fragment.getId(), ev.message); } else { AppProjectCore.LOG.error("'%s' fragment falled DOWN: %s", ev.fragment.getId(), ev.message); AppProjectCore.LOG.error(ev.throwable); // display problem to user reportAsStatus(ev); } getContext().get(IModelioEventService.class).postAsyncEvent(ProjectService.this, ModelioEvent.FRAGMENT_DOWN, ev.fragment); break; case WARNING: if (ev.throwable != null) { AppProjectCore.LOG.warning(ev.throwable); } else if (ev.message != null) { if (ev.fragment != null) AppProjectCore.LOG.warning("%s : %s", ev.fragment.getId(), ev.message); else AppProjectCore.LOG.warning(ev.message); } break; case FRAGMENT_STATE_CHANGED: AppProjectCore.LOG.debug("'%s' fragment state changed to '%s'.", ev.fragment.getId(), ev.fragment.getState().toString()); if (ev.fragment.getState() == FragmentState.UP_FULL || ev.fragment.getState() == FragmentState.UP_LIGHT) getContext().get(IModelioEventService.class).postAsyncEvent(ProjectService.this, ModelioEvent.FRAGMENT_UP, ev.fragment); break; default: if (ev.message != null) { AppProjectCore.LOG.info(ev.message); } if (ev.throwable != null) { AppProjectCore.LOG.info(ev.throwable); } break; } } @objid("ff9cf99a-5c5e-47ba-8ea7-57daa521a97b") String getMessage(GProjectEvent ev) { if (ev.message != null && !ev.message.isEmpty()) return ev.message; else if (ev.throwable == null) return AppProjectCore.I18N.getMessage("ProjectService.noEventMessage"); else if (ev.throwable instanceof FileSystemException) return FileUtils.getLocalizedMessage((FileSystemException) ev.throwable); else if (ev.throwable instanceof RuntimeException) return ev.throwable.toString(); // some runtime exceptions have no message at all else return ev.throwable.getLocalizedMessage(); } @objid("357af83e-da98-41b2-8095-e74ddcdffa42") private void reportAsStatus(final GProjectEvent ev) { final StatusReporter statusReporter = getContext().get(StatusReporter.class); if (statusReporter != null) { Display.getDefault().asyncExec(new Runnable() { @Override public void run() { IStatus s1; if (ev.type == GProjectEventType.FRAGMENT_DOWN) { String message = AppProjectCore.I18N.getMessage("ProjectService.fragmentDown", ev.fragment.getId()); s1 = statusReporter.newStatus(StatusReporter.WARNING, message, ev.throwable); } else { s1 = statusReporter.newStatus(StatusReporter.WARNING, getMessage(ev), ev.throwable); } statusReporter.report(s1, StatusReporter.SHOW, ev); } }); } } } /** * To be used in try-with-resource to automatically close the project unless * abort is called. * * @author cmarin */ @objid("db5f4a1c-12ac-4142-a3c3-ea0d159d9669") private class ProjectCloser implements AutoCloseable { @objid("8f4b6e4e-040b-41c6-bc9c-03e32fa18ad9") private boolean abort = false; @objid("0d7b407c-27ba-46bf-9bf2-06fff2bc4286") public ProjectCloser() { // nothing } @objid("be54458f-6225-4ced-aba2-963ce44de6f0") @Override public void close() { if (!this.abort) closeProject(getOpenedProject()); } @objid("d8c4e9a6-9abb-44b7-a308-7c0d155518b6") public void abort() { this.abort = true; } } }