/* * Copyright (c) 2010, IETR/INSA of Rennes * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the IETR/INSA of Rennes nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ package net.sf.orcc.util; import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import net.sf.orcc.OrccProjectNature; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.emf.common.util.Diagnostic; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.util.Diagnostician; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.JavaCore; import com.google.common.base.Joiner; /** * This class contains utility methods for dealing with resources. * * @author Matthieu Wipliez * @author Antoine Lorence * */ public class OrccUtil { public static final String IR_SUFFIX = "ir"; public static final String CAL_SUFFIX = "cal"; public static final String NETWORK_SUFFIX = "xdf"; public static final String DIAGRAM_SUFFIX = "xdfdiag"; public static final String PROJECT_OUTPUT_DIR = "bin"; private static IWorkspaceRoot workspaceRoot; public static IWorkspaceRoot workspaceRoot() { if (workspaceRoot == null) { workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); } return workspaceRoot; } /** /** * If it does not exist, creates the given folder. If the parent folders do * not exist either, create them. * * @param folder * a folder * @throws CoreException */ public static void createFolder(IFolder folder) throws CoreException { IPath path = folder.getFullPath(); if (folder.exists()) { return; } int n = path.segmentCount(); if (n < 2) { throw new IllegalArgumentException("the path of the given folder " + "must have at least two segments"); } // check project IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); IProject project = root.getProject(path.segment(0)); if (!project.exists()) { project.create(null); } // open project if (!project.isOpen()) { project.open(null); } // check folder folder = root.getFolder(path.uptoSegment(2)); if (!folder.exists()) { folder.create(true, true, null); } // and then check all the descendants for (int i = 2; i < n; i++) { folder = folder.getFolder(new Path(path.segment(i))); if (!folder.exists()) { folder.create(true, true, null); } } } /** * Search in given folder for files resources with given suffix, and add * them to the given files list * * @param suffix * @param files * @param folder * @throws CoreException */ private static void findFiles(final String suffix, final List<IFile> files, final IFolder folder) throws CoreException { for (IResource resource : folder.members()) { if (resource.getType() == IResource.FOLDER) { findFiles(suffix, files, (IFolder) resource); } else if (resource.getType() == IResource.FILE && suffix.equals(resource.getFileExtension())) { files.add((IFile) resource); } } } /** * Returns the list of IFolder containing: * <ul> * <li>Source folders of the given project</li> * <li>Source folders of the projects depending on the given project</li> * </ul> * * @param project * @return */ public static List<IFolder> getAllDependingSourceFolders( final IProject project) { final List<IFolder> srcFolders = new ArrayList<IFolder>(); srcFolders.addAll(getSourceFolders(project)); for (final IProject dependingProject : getReferencingProjects(project)) { srcFolders.addAll(getSourceFolders(dependingProject)); } return srcFolders; } /** * Returns all the files with the given extension found in the given * folders. * * @param srcFolders * a list of folders * @return a list of files */ public static List<IFile> getAllFiles(String fileExt, List<IFolder> srcFolders) { List<IFile> vtlFiles = new ArrayList<IFile>(); try { for (IFolder folder : srcFolders) { findFiles(fileExt, vtlFiles, folder); } } catch (CoreException e) { e.printStackTrace(); } // sort them by name Collections.sort(vtlFiles, new Comparator<IFile>() { @Override public int compare(IFile f1, IFile f2) { return f1.getFullPath().toOSString() .compareTo(f2.getFullPath().toOSString()); } }); return vtlFiles; } /** * Returns the list of IFolder containing: * <ul> * <li>Source folders of the given project</li> * <li>Source folders of the projects the given project depends on</li> * </ul> * * @param project * a project * @return a list of absolute workspace paths * @throws CoreException */ public static List<IFolder> getAllSourceFolders(IProject project) { List<IFolder> srcFolders = new ArrayList<IFolder>(); IJavaProject javaProject = JavaCore.create(project); if (!javaProject.exists()) { return srcFolders; } // add source folders of this project srcFolders.addAll(getSourceFolders(project)); // add source folders of required projects IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); try { for (String name : javaProject.getRequiredProjectNames()) { IProject refProject = root.getProject(name); srcFolders.addAll(getAllSourceFolders(refProject)); } } catch (CoreException e) { e.printStackTrace(); } return srcFolders; } /** * Returns a new string that is an escaped version of the given string. * Espaced means that '\\', '\n', '\r', '\t' are replaced by "\\\\", "\\n", * "\\r", "\\t" respectively. * * @param string * a string * @return a new string that is an escaped version of the given string */ public static String getEscapedString(String string) { StringBuilder builder = new StringBuilder(string.length()); for (int i = 0; i < string.length(); i++) { char chr = string.charAt(i); switch (chr) { case '\\': builder.append("\\\\"); break; case '"': builder.append("\""); break; case '\n': builder.append("\\n"); break; case '\r': builder.append("\\r"); break; case '\t': builder.append("\\t"); break; default: builder.append(chr); break; } } return builder.toString(); } /** * Returns the file in the given project that has the given qualified name * and the given extension. Looks in source folders first and then output * folders. * * @param project * project * @param qualifiedName * qualified name of a network * @return if there is such a network, a file, otherwise <code>null</code> */ public static IFile getFile(IProject project, String qualifiedName, String extension) { String name = qualifiedName.replace('.', '/'); IPath path = new Path(name).addFileExtension(extension); for (IFolder folder : getAllSourceFolders(project)) { IFile inputFile = folder.getFile(path); if (inputFile != null && inputFile.exists()) { return inputFile; } } for (IFolder folder : getOutputFolders(project)) { IFile inputFile = folder.getFile(path); if (inputFile != null && inputFile.exists()) { return inputFile; } } return null; } /** * Returns the output folder of the given project. * * @param project * a project * @return the output folder of the given project, or <code>null</code> if * none is found */ public static IFolder getOutputFolder(IProject project) { return project.getFolder(PROJECT_OUTPUT_DIR); } /** * Returns the output locations of the given project and the project it * references in its build path. * * @param project * a project * @return the output location of the given project, or an empty list */ public static List<IFolder> getOutputFolders(IProject project) { List<IFolder> vtlFolders = new ArrayList<IFolder>(); IJavaProject javaProject = JavaCore.create(project); if (!javaProject.exists()) { return vtlFolders; } // add output folders of this project IFolder outputFolder = getOutputFolder(project); if (outputFolder != null) { vtlFolders.add(outputFolder); } // add output folders of required projects IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); try { for (String name : javaProject.getRequiredProjectNames()) { IProject refProject = root.getProject(name); outputFolder = getOutputFolder(refProject); if (outputFolder != null) { vtlFolders.add(outputFolder); } } } catch (CoreException e) { e.printStackTrace(); } return vtlFolders; } /** * Returns the qualified name of the given file, i.e. qualified.name.of.File * for <code>/project/sourceFolder/qualified/name/of/File.fileExt</code> or * <code>/project/outputFolder/qualified/name/of/File.fileExt</code>. * * @param file * a file * @return a qualified name, or <code>null</code> if the file is not in a * source folder */ public static String getQualifiedName(IFile file) { final String name = file.getFullPath().removeFileExtension().lastSegment(); return getQualifiedPackage(file) + '.' + name; } /** * Returns the qualified package of the given file, i.e. qualified.name.of * for <code>/project/sourceFolder/qualified/name/of/File.fileExt</code> * even if the file doesn't exists. * * @param file * a file * @return a qualified name, or an empty String */ public static String getQualifiedPackage(IFile file) { // Get all segments in the file's container's project-relative path final String[] segments = file.getParent().getProjectRelativePath() .segments(); // Remove the first part of these segments (the source folder) final String[] segmentsTail = Arrays.copyOfRange(segments, 1, segments.length); // Join the result with '.', this is the package of the file. return Joiner.on('.').join(segmentsTail); } /** * Returns a list of projects which depends on the given project. * * @param project * @return */ public static Set<IProject> getReferencingProjects(final IProject project) { final Set<IProject> result = new HashSet<IProject>(); final IWorkspaceRoot wpRoot = ResourcesPlugin.getWorkspace().getRoot(); // Check all projects in the workspace root for (final IProject wpProject : wpRoot.getProjects()) { try { // Keep only open Orcc projects, different from the given // project if (!wpProject.isOpen() || !project.hasNature(OrccProjectNature.NATURE_ID) || wpProject == project) { continue; } // Keep only valid Java projects final IJavaProject wpJavaProject = JavaCore.create(wpProject); if (!wpJavaProject.exists()) { // This should never happen continue; } // Loop over all classpath entries of the wpJavaProject for (final String requiredProject : wpJavaProject .getRequiredProjectNames()) { // The wpJavaProject require the given IProject if (wpRoot.getProject(requiredProject).equals(project)) { result.add(wpProject); } } } catch (CoreException e) { e.printStackTrace(); } } return result; } /** * Returns the list of source folders of the given project as a list of * absolute workspace paths. * * @param project * a project * @return a list of absolute workspace paths */ public static List<IFolder> getSourceFolders(IProject project) { List<IFolder> srcFolders = new ArrayList<IFolder>(); IJavaProject javaProject = JavaCore.create(project); if (!javaProject.exists()) { return srcFolders; } // iterate over package roots try { for (IPackageFragmentRoot root : javaProject .getPackageFragmentRoots()) { IResource resource = root.getCorrespondingResource(); if (resource != null && resource.getType() == IResource.FOLDER) { srcFolders.add((IFolder) resource); } } } catch (CoreException e) { e.printStackTrace(); } return srcFolders; } /** * Returns a new string that is an unescaped version of the given string. * Unespaced means that "\\\\", "\\n", "\\r", "\\t" are replaced by '\\', * '\n', '\r', '\t' respectively. * * @param string * a string * @return a new string that is an unescaped version of the given string */ public static String getUnescapedString(String string) { StringBuilder builder = new StringBuilder(string.length()); boolean escape = false; for (int i = 0; i < string.length(); i++) { char chr = string.charAt(i); if (escape) { switch (chr) { case '\\': builder.append('\\'); break; case 'n': builder.append('\n'); break; case 'r': builder.append('\r'); break; case 't': builder.append('\t'); break; default: // we could throw an exception here builder.append(chr); break; } escape = false; } else { if (chr == '\\') { escape = true; } else { builder.append(chr); } } } return builder.toString(); } /** * Checks if the String contains only unicode digits. A decimal point is not * a unicode digit and returns false. <code>null</code> will return <code>false</code>. * An empty String (length()=0) will return <code>true</code>. * * NOTE: method taken from the apache common lang library (scb) * * <pre> * StringUtils.isNumeric(null) = false * StringUtils.isNumeric("") = true * StringUtils.isNumeric(" ") = false * StringUtils.isNumeric("123") = true * StringUtils.isNumeric("12 3") = false * StringUtils.isNumeric("ab2c") = false * StringUtils.isNumeric("12-3") = false * StringUtils.isNumeric("12.3") = false * </pre> * * @param str * the String to check, may be <code>null</code> * @return if only contains digits, and is non-<code>null</code> */ public static boolean isNumeric(final String str) { if (str == null || str.isEmpty()) { return false; } final int sz = str.length(); for (int i = 0; i < sz; i++) { if (Character.isDigit(str.charAt(i)) == false) { return false; } } return true; } /** * Run an external programs with the given commands list * * @param cmdList * the list of command containing the program and its arguments */ public static void runExternalProgram(List<String> cmdList) { try { ProcessBuilder builder = new ProcessBuilder(cmdList); Process process = builder.start(); process.waitFor(); BufferedReader reader = new BufferedReader(new InputStreamReader( process.getInputStream())); String line = new String(); while ((line = reader.readLine()) != null) { OrccLogger.traceln(line); } } catch (Exception e) { OrccLogger.severeln(e.getMessage()); } } /** * Returns a string that contains all objects separated with the given * separator. * * @param objects * an iterable of objects * @param sep * a separator string * @return a string that contains all objects separated with the given * separator */ public static String toString(Iterable<? extends Object> objects, String sep) { StringBuilder builder = new StringBuilder(); Iterator<? extends Object> it = objects.iterator(); if (it.hasNext()) { builder.append(it.next()); while (it.hasNext()) { builder.append(sep); builder.append(it.next()); } } return builder.toString(); } /** * Validate the given object according to the specification of its model. * Knowing that the object will be deeply inspected by the validator, this * method may be time consuming on top-level objects. This method is useful * to validate the OCL-based constraints and invariants that have been * specified in the model. The validation errors and warning are transmitted * directly to the OrccLogger. * * @param headDiagMsg * a message to preface all diagnostic message displayed by the * logger * @param eObject * the object to validate * @return <code>true</code>if the given object is valid, <code>false</code> * otherwise */ public static boolean validateObject(String headDiagMsg, EObject eObject) { Diagnostic diagnostic = Diagnostician.INSTANCE.validate(eObject); if (diagnostic.getSeverity() == Diagnostic.ERROR || diagnostic.getSeverity() == Diagnostic.WARNING) { for (Diagnostic childDiag : diagnostic.getChildren()) { Diagnostic childDiagnostic = childDiag; switch (childDiagnostic.getSeverity()) { case Diagnostic.ERROR: case Diagnostic.WARNING: OrccLogger.warnln(headDiagMsg + " :" + childDiagnostic.getMessage()); } } return false; } return true; } /** * Compute the URI of an IR file corresponding to the given cal file URI * * @param calUri * @return */ public static URI getIrUri(final URI calUri) { // Get the given URI as IFile instance final IFile file = workspaceRoot().getFile( new Path(calUri.toPlatformString(true))); // Get the path relative to project source folder, update suffix final IPath sourceRelativePath = file.getProjectRelativePath() .removeFirstSegments(1).removeFileExtension() .addFileExtension(IR_SUFFIX); // Build the IR path, from project output folder final IPath irPath = getOutputFolder(file.getProject()).getFile( sourceRelativePath).getFullPath(); return URI.createPlatformResourceURI(irPath.toString(), true); } }