Java tutorial
/* * Copyright 2015 Nokia Solutions and Networks * Licensed under the Apache License, Version 2.0, * see license.txt file for details. */ package org.robotframework.ide.eclipse.main.plugin.model; import static com.google.common.collect.Iterables.filter; import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Maps.newLinkedHashMap; import static com.google.common.collect.Sets.newLinkedHashSet; import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.part.FileEditorInput; import org.rf.ide.core.dryrun.RobotDryRunKeywordSource; import org.rf.ide.core.executor.RobotRuntimeEnvironment; import org.rf.ide.core.project.ImportSearchPaths.PathsProvider; import org.rf.ide.core.project.RobotProjectConfig; import org.rf.ide.core.project.RobotProjectConfig.LibraryType; import org.rf.ide.core.project.RobotProjectConfig.ReferencedLibrary; import org.rf.ide.core.project.RobotProjectConfig.ReferencedVariableFile; import org.rf.ide.core.project.RobotProjectConfig.RemoteLocation; import org.rf.ide.core.project.RobotProjectConfig.SearchPath; import org.rf.ide.core.project.RobotProjectConfigReader.CannotReadProjectConfigurationException; import org.rf.ide.core.testdata.RobotParser; import org.rf.ide.core.testdata.model.RobotExpressions; import org.rf.ide.core.testdata.model.RobotProjectHolder; import org.robotframework.ide.eclipse.main.plugin.RedPlugin; import org.robotframework.ide.eclipse.main.plugin.RedWorkspace; import org.robotframework.ide.eclipse.main.plugin.project.LibrariesWatchHandler; import org.robotframework.ide.eclipse.main.plugin.project.RedEclipseProjectConfig; import org.robotframework.ide.eclipse.main.plugin.project.RedEclipseProjectConfig.PathResolvingException; import org.robotframework.ide.eclipse.main.plugin.project.RedEclipseProjectConfigReader; import org.robotframework.ide.eclipse.main.plugin.project.editor.RedProjectEditor; import org.robotframework.ide.eclipse.main.plugin.project.editor.RedProjectEditorInput; import org.robotframework.ide.eclipse.main.plugin.project.library.LibrarySpecification; import org.robotframework.ide.eclipse.main.plugin.project.library.LibrarySpecificationReader; import org.robotframework.ide.eclipse.main.plugin.project.library.LibrarySpecificationReader.CannotReadLibrarySpecificationException; import org.robotframework.red.swt.SwtThread; import org.robotframework.red.swt.SwtThread.Evaluation; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; import com.google.common.base.Joiner; import com.google.common.base.Predicates; public class RobotProject extends RobotContainer { private RobotProjectHolder projectHolder; private Map<String, LibrarySpecification> stdLibsSpecs; private Map<ReferencedLibrary, LibrarySpecification> refLibsSpecs; private List<ReferencedVariableFile> referencedVariableFiles; private RobotProjectConfig configuration; private final LibrariesWatchHandler librariesWatchHandler; private final Map<String, RobotDryRunKeywordSource> kwSources = new ConcurrentHashMap<>(); RobotProject(final RobotModel model, final IProject project) { super(model, project); librariesWatchHandler = new LibrariesWatchHandler(this); } public synchronized RobotProjectHolder getRobotProjectHolder() { if (projectHolder == null) { projectHolder = new RobotProjectHolder(getRuntimeEnvironment()); } projectHolder.configure(getRobotProjectConfig(), getProject().getLocation().toFile()); return projectHolder; } public RobotParser getEagerRobotParser() { return RobotParser.createEager(getRobotProjectHolder(), createPathsProvider()); } public RobotParser getRobotParser() { return RobotParser.create(getRobotProjectHolder(), createPathsProvider()); } public IProject getProject() { return (IProject) container; } public String getVersion() { readProjectConfigurationIfNeeded(); final RobotRuntimeEnvironment env = getRuntimeEnvironment(); return env == null ? "???" : env.getVersion(); } public Collection<LibrarySpecification> getLibrariesSpecifications() { final List<LibrarySpecification> specifications = newArrayList(); specifications.addAll(getStandardLibraries().values()); specifications.addAll(getReferencedLibraries().values()); return newArrayList(filter(specifications, Predicates.notNull())); } public synchronized boolean hasStandardLibraries() { readProjectConfigurationIfNeeded(); if (stdLibsSpecs != null && !stdLibsSpecs.isEmpty()) { return true; } return configuration != null; } public synchronized Map<String, LibrarySpecification> getStandardLibraries() { if (stdLibsSpecs != null) { return stdLibsSpecs; } readProjectConfigurationIfNeeded(); final RobotRuntimeEnvironment env = getRuntimeEnvironment(); if (env == null || configuration == null) { return newLinkedHashMap(); } stdLibsSpecs = newLinkedHashMap(); for (final String stdLib : env.getStandardLibrariesNames()) { stdLibsSpecs.put(stdLib, stdLibToSpec(getProject()).apply(stdLib)); } for (final RemoteLocation location : configuration.getRemoteLocations()) { stdLibsSpecs.put("Remote " + location.getUri(), remoteLibToSpec(getProject()).apply(location)); } return stdLibsSpecs; } @VisibleForTesting public void setStandardLibraries(final Map<String, LibrarySpecification> libs) { stdLibsSpecs = libs; } public synchronized boolean hasReferencedLibraries() { readProjectConfigurationIfNeeded(); if (refLibsSpecs != null && !refLibsSpecs.isEmpty()) { return true; } return configuration != null && configuration.hasReferencedLibraries(); } public synchronized Map<ReferencedLibrary, LibrarySpecification> getReferencedLibraries() { if (refLibsSpecs != null) { return refLibsSpecs; } readProjectConfigurationIfNeeded(); if (configuration == null) { return newLinkedHashMap(); } refLibsSpecs = newLinkedHashMap(); for (final ReferencedLibrary library : configuration.getLibraries()) { final LibrarySpecification spec = reflibToSpec(getProject()).apply(library); librariesWatchHandler.registerLibrary(library, spec); if (librariesWatchHandler.isLibSpecDirty(spec)) { spec.setIsModified(true); } refLibsSpecs.put(library, spec); } removeUnusedLibspecFiles(refLibsSpecs); return refLibsSpecs; } @VisibleForTesting public void setReferencedLibraries(final Map<ReferencedLibrary, LibrarySpecification> libs) { refLibsSpecs = libs; } public synchronized void unregisterWatchingOnReferencedLibraries(final List<ReferencedLibrary> libraries) { librariesWatchHandler.unregisterLibraries(libraries); } public void clearDirtyLibSpecs(final Collection<LibrarySpecification> libSpecs) { librariesWatchHandler.removeDirtySpecs(libSpecs); } private static Function<String, LibrarySpecification> stdLibToSpec(final IProject project) { return new Function<String, LibrarySpecification>() { @Override public LibrarySpecification apply(final String libraryName) { try { final IFile file = LibspecsFolder.get(project).getSpecFile(libraryName); return LibrarySpecificationReader.readStandardLibrarySpecification(file, libraryName); } catch (final CannotReadLibrarySpecificationException e) { return null; } } }; } private static Function<RemoteLocation, LibrarySpecification> remoteLibToSpec(final IProject project) { return new Function<RemoteLocation, LibrarySpecification>() { @Override public LibrarySpecification apply(final RemoteLocation remoteLocation) { try { final IFile file = LibspecsFolder.get(project) .getSpecFile(remoteLocation.createLibspecFileName()); return LibrarySpecificationReader.readRemoteSpecification(file, remoteLocation); } catch (final CannotReadLibrarySpecificationException e) { return null; } } }; } private static Function<ReferencedLibrary, LibrarySpecification> reflibToSpec(final IProject project) { return new Function<ReferencedLibrary, LibrarySpecification>() { @Override public LibrarySpecification apply(final ReferencedLibrary lib) { try { final IPath path = Path.fromPortableString(lib.getPath()); final IResource libspec = project.getParent().findMember(path); final IFile fileToRead; if (lib.provideType() == LibraryType.VIRTUAL && libspec != null && libspec.exists()) { fileToRead = (IFile) libspec; } else { fileToRead = LibspecsFolder.get(project).getSpecFile(lib.getName()); } return LibrarySpecificationReader.readReferencedSpecification(fileToRead, lib); } catch (final CannotReadLibrarySpecificationException e) { return null; } } }; } private synchronized RobotProjectConfig readProjectConfigurationIfNeeded() { if (configuration == null) { try { configuration = new RedEclipseProjectConfigReader().readConfiguration(getProject()); } catch (final CannotReadProjectConfigurationException e) { // oh well... } } return configuration; } public synchronized RobotProjectConfig getRobotProjectConfig() { readProjectConfigurationIfNeeded(); return configuration; } /** * Returns the configuration model from opened editor. * * @return opened configuration */ public RobotProjectConfig getOpenedProjectConfig() { final RedProjectEditorInput redProjectInput = findEditorInputIfAlreadyOpened(); if (redProjectInput != null) { return redProjectInput.getProjectConfiguration(); } else { return null; } } private RedProjectEditorInput findEditorInputIfAlreadyOpened() { return SwtThread.syncEval(new Evaluation<RedProjectEditorInput>() { @Override public RedProjectEditorInput runCalculation() { final IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); if (window == null) { // in the meantime window could be destroyed actually.. return null; } final IWorkbenchPage page = window.getActivePage(); final FileEditorInput input = new FileEditorInput(getConfigurationFile()); final IEditorPart editor = page.findEditor(input); return editor instanceof RedProjectEditor ? ((RedProjectEditor) editor).getRedProjectEditorInput() : null; } }); } public void clearCachedData() { if (projectHolder != null) { projectHolder.clearModelFiles(); } } /** * Clearing should be done when user changed his/hers execution environment (python+robot) */ public synchronized void clearAll() { projectHolder = null; clearConfiguration(); clearKwSources(); } public synchronized void clearConfiguration() { configuration = null; referencedVariableFiles = null; stdLibsSpecs = null; refLibsSpecs = null; } public synchronized void clearKwSources() { kwSources.clear(); } public synchronized RobotRuntimeEnvironment getRuntimeEnvironment() { readProjectConfigurationIfNeeded(); if (configuration == null || configuration.usesPreferences()) { return RedPlugin.getDefault().getActiveRobotInstallation(); } return RedPlugin.getDefault().getRobotInstallation(configuration.providePythonLocation(), configuration.providePythonInterpreter()); } public IFile getConfigurationFile() { return getProject().getFile(RobotProjectConfig.FILENAME); } public IFile getFile(final String filename) { return getProject().getFile(filename); } public PathsProvider createPathsProvider() { return new ProjectPathsProvider(); } public void setModuleSearchPaths(final List<File> paths) { getRobotProjectHolder().setModuleSearchPaths(paths); } public synchronized List<File> getModuleSearchPaths() { return getRobotProjectHolder().getModuleSearchPaths(); } public synchronized List<String> getPythonpath() { readProjectConfigurationIfNeeded(); final Set<String> pp = newLinkedHashSet(); if (configuration != null) { pp.addAll(getReferenceLibPaths(LibraryType.PYTHON)); pp.addAll(getAdditionalPaths(configuration.getPythonPath())); } return newArrayList(pp); } public synchronized List<String> getClasspath() { readProjectConfigurationIfNeeded(); final Set<String> cp = newLinkedHashSet(); cp.add("."); if (configuration != null) { cp.addAll(getReferenceLibPaths(LibraryType.JAVA)); cp.addAll(getAdditionalPaths(configuration.getClassPath())); } return newArrayList(cp); } private synchronized List<String> getReferenceLibPaths(final LibraryType libType) { final List<String> paths = newArrayList(); for (final ReferencedLibrary lib : configuration.getLibraries()) { if (lib.provideType() == libType) { paths.add(RedWorkspace.Paths.toAbsoluteFromWorkspaceRelativeIfPossible(new Path(lib.getPath())) .toOSString()); } } return paths; } private synchronized List<String> getAdditionalPaths(final List<SearchPath> searchPaths) { final RedEclipseProjectConfig redConfig = new RedEclipseProjectConfig(configuration); final List<String> paths = newArrayList(); for (final SearchPath searchPath : searchPaths) { try { paths.add(redConfig.toAbsolutePath(searchPath, getProject()).getPath()); } catch (final PathResolvingException e) { // we don't want to add syntax-problematic paths } } return paths; } public synchronized boolean isStandardLibrary(final LibrarySpecification spec) { final Map<String, LibrarySpecification> stdLibs = getStandardLibraries(); return isLibraryFrom(spec, stdLibs == null ? null : stdLibs.values()); } public synchronized boolean isReferencedLibrary(final LibrarySpecification spec) { final Map<ReferencedLibrary, LibrarySpecification> refLibs = getReferencedLibraries(); return isLibraryFrom(spec, refLibs == null ? null : refLibs.values()); } private boolean isLibraryFrom(final LibrarySpecification spec, final Collection<LibrarySpecification> libs) { if (libs == null) { return false; } for (final LibrarySpecification librarySpecification : libs) { if (librarySpecification == spec) { return true; } } return false; } public synchronized String getPythonLibraryPath(final String libName) { readProjectConfigurationIfNeeded(); if (configuration != null) { for (final ReferencedLibrary lib : configuration.getLibraries()) { if (lib.provideType() == LibraryType.PYTHON && lib.getName().equals(libName)) { return RedWorkspace.Paths.toAbsoluteFromWorkspaceRelativeIfPossible( new Path(lib.getPath()).append(lib.getName() + ".py")).toPortableString(); } } } return ""; } public List<String> getVariableFilePaths() { readProjectConfigurationIfNeeded(); final List<String> list = new ArrayList<>(); if (configuration != null) { for (final ReferencedVariableFile variableFile : configuration.getReferencedVariableFiles()) { final String path = RedWorkspace.Paths .toAbsoluteFromWorkspaceRelativeIfPossible(new Path(variableFile.getPath())).toOSString(); final List<String> args = variableFile.getArguments(); final String arguments = args == null || args.isEmpty() ? "" : ":" + Joiner.on(":").join(args); list.add(path + arguments); } } return list; } @VisibleForTesting public void setReferencedVariablesFiles(final List<ReferencedVariableFile> varFiles) { this.referencedVariableFiles = varFiles; } public synchronized List<ReferencedVariableFile> getVariablesFromReferencedFiles() { if (referencedVariableFiles != null) { return referencedVariableFiles; } readProjectConfigurationIfNeeded(); if (configuration != null) { referencedVariableFiles = newArrayList(); for (final ReferencedVariableFile variableFile : configuration.getReferencedVariableFiles()) { IPath path = new Path(variableFile.getPath()); if (!path.isAbsolute()) { final IResource targetFile = getProject().getWorkspace().getRoot().findMember(path); if (targetFile != null && targetFile.exists()) { path = targetFile.getLocation(); } } final Map<String, Object> varsMap = getRuntimeEnvironment() .getVariablesFromFile(path.toPortableString(), variableFile.getArguments()); if (varsMap != null && !varsMap.isEmpty()) { variableFile.setVariables(varsMap); referencedVariableFiles.add(variableFile); } } return referencedVariableFiles; } return newArrayList(); } public String resolve(final String expression) { return RobotExpressions.resolve(getRobotProjectHolder().getVariableMappings(), expression); } private void removeUnusedLibspecFiles(final Map<ReferencedLibrary, LibrarySpecification> refLibsSpecs) { if (!librariesWatchHandler.getRemovedSpecs().isEmpty()) { for (final LibrarySpecification removedSpec : librariesWatchHandler.getRemovedSpecs()) { if (!refLibsSpecs.containsValue(removedSpec)) { final IFile libspecFile = removedSpec.getSourceFile(); if (libspecFile != null) { final IPath libspecFileLocation = libspecFile.getLocation(); if (libspecFileLocation != null) { libspecFileLocation.toFile().delete(); } } } } librariesWatchHandler.clearRemovedSpecs(); } } public void addKeywordSource(final RobotDryRunKeywordSource keywordSource) { final String qualifiedKwName = keywordSource.getLibraryName() + "." + keywordSource.getName(); kwSources.put(qualifiedKwName, keywordSource); } public synchronized Optional<RobotDryRunKeywordSource> getKeywordSource(final String qualifiedKwName) { return Optional.ofNullable(kwSources.get(qualifiedKwName)); } private class ProjectPathsProvider implements PathsProvider { @Override public List<File> providePythonModulesSearchPaths() { return getModuleSearchPaths(); } @Override public List<File> provideUserSearchPaths() { final RobotProjectConfig configuration = getRobotProjectConfig(); if (configuration == null) { return new ArrayList<>(); } final List<File> paths = new ArrayList<>(); final RedEclipseProjectConfig redConfig = new RedEclipseProjectConfig(configuration); for (final SearchPath searchPath : configuration.getPythonPath()) { try { final File searchPathParent = redConfig.toAbsolutePath(searchPath, getProject()); paths.add(searchPathParent); } catch (final PathResolvingException e) { continue; } } return paths; } } }