org.erlide.engine.internal.model.erlang.ModelInternalUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.erlide.engine.internal.model.erlang.ModelInternalUtils.java

Source

/*******************************************************************************
 * Copyright (c) 2009-2013 Vlad Dumitrescu and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available
 * at http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Vlad Dumitrescu
 *******************************************************************************/
package org.erlide.engine.internal.model.erlang;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IPath;
import org.erlide.engine.model.ErlElementKind;
import org.erlide.engine.model.ErlModelException;
import org.erlide.engine.model.IErlElement;
import org.erlide.engine.model.IParent;
import org.erlide.engine.model.erlang.ErlangFunction;
import org.erlide.engine.model.erlang.IErlImport;
import org.erlide.engine.model.root.IErlElementLocator;
import org.erlide.engine.model.root.IErlExternal;
import org.erlide.engine.model.root.IErlModel;
import org.erlide.engine.model.root.IErlModule;
import org.erlide.engine.model.root.IErlProject;
import org.erlide.engine.model.root.IOpenable;
import org.erlide.engine.services.search.ModelUtilService;
import org.erlide.runtime.rpc.IOtpRpc;
import org.erlide.util.ErlLogger;
import org.erlide.util.erlang.TypeConverter;

import com.ericsson.otp.erlang.OtpErlangAtom;
import com.ericsson.otp.erlang.OtpErlangList;
import com.ericsson.otp.erlang.OtpErlangObject;
import com.ericsson.otp.erlang.OtpErlangTuple;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

public class ModelInternalUtils implements ModelUtilService {

    private final IOtpRpc backend;

    public ModelInternalUtils(final IOtpRpc backend) {
        this.backend = backend;
    }

    private static final String DELIMITER = "<>";

    @Override
    public String getExternalModulePath(final IErlElementLocator model, final IErlModule module) {
        final List<String> result = Lists.newArrayList();
        IErlElement element = module;
        while (element != model) {
            if (element instanceof IErlExternal) {
                final IErlExternal external = (IErlExternal) element;
                result.add(external.getName());
            } else {
                result.add(element.getName());
            }
            element = (IErlElement) element.getParent();
        }
        return Joiner.on(ModelInternalUtils.DELIMITER).join(Lists.reverse(result));
    }

    private IErlExternal getElementWithExternalName(final IParent parent, final String name)
            throws ErlModelException {
        System.out.println(" ?? " + name);
        for (final IErlElement e : parent.getChildrenOfKind(ErlElementKind.EXTERNAL_ROOT,
                ErlElementKind.EXTERNAL_APP, ErlElementKind.EXTERNAL_FOLDER)) {
            final IErlExternal external = (IErlExternal) e;
            final String externalName = external.getName();
            System.out.println("   ? " + externalName);
            if (externalName.equals(name)) {
                return external;
            }
        }
        return null;
    }

    @Override
    public IErlModule getModuleFromExternalModulePath(final IErlModel model, final String modulePath)
            throws ErlModelException {
        System.out.println(">> modulePath=" + modulePath);
        final List<String> path = Lists.newArrayList(Splitter.on(ModelInternalUtils.DELIMITER).split(modulePath));
        model.open(null);
        final IErlElement childNamed = model.getChildNamed(path.get(0));
        if (childNamed instanceof IParent) {
            IParent parent = (IParent) childNamed;
            final int n = path.size() - 1;
            for (int i = 1;; i++) {
                if (parent == null) {
                    break;
                }
                if (parent instanceof IOpenable) {
                    final IOpenable openable = (IOpenable) parent;
                    openable.open(null);
                }
                if (i == n) {
                    break;
                }
                parent = getElementWithExternalName(parent, path.get(i));
            }
            if (parent != null) {
                final IErlElement child = parent.getChildNamed(path.get(n));
                if (child instanceof IErlModule) {
                    return (IErlModule) child;
                }
            }
        }
        return null;
    }

    @Override
    public List<String> findUnitsWithPrefix(final String prefix, final IErlProject project,
            final boolean checkExternals, final boolean includes) throws ErlModelException {
        final List<String> result = Lists.newArrayList();
        final Collection<IErlModule> units = getUnits(project, checkExternals, includes);
        addUnitNamesWithPrefix(prefix, result, units, false, includes);
        if (project != null) {
            for (final IErlProject p : project.getReferencedProjects()) {
                if (p != null) {
                    p.open(null);
                    addUnitNamesWithPrefix(prefix, result, getUnits(p, checkExternals, includes), false, includes);
                }
            }
            if (checkExternals) {
                final Collection<IErlModule> externalUnits = includes ? project.getExternalIncludes()
                        : project.getExternalModules();
                addUnitNamesWithPrefix(prefix, result, externalUnits, true, includes);
            }
        }
        return result;
    }

    private Collection<IErlModule> getUnits(final IErlProject project, final boolean checkExternals,
            final boolean includes) throws ErlModelException {
        final Collection<IErlModule> units;
        if (!includes && project != null) {
            units = project.getModules();
        } else if (!checkExternals && project != null) {
            units = project.getIncludes();
        } else {
            units = Sets.newHashSet();
        }
        return units;
    }

    @Override
    public List<OtpErlangObject> getImportsAsList(final IErlModule mod) {
        if (mod == null) {
            return ModelInternalUtils.NO_IMPORTS;
        }
        final Collection<IErlImport> imports = mod.getImports();
        if (imports.isEmpty()) {
            return ModelInternalUtils.NO_IMPORTS;
        }
        final List<OtpErlangObject> result = new ArrayList<>(imports.size());
        for (final IErlImport i : imports) {
            final Collection<ErlangFunction> functions = i.getFunctions();
            final OtpErlangObject funsT[] = new OtpErlangObject[functions.size()];
            int j = 0;
            for (final ErlangFunction f : functions) {
                funsT[j] = f.getNameArityTuple();
                j++;
            }
            final OtpErlangTuple modFunsT = new OtpErlangTuple(
                    new OtpErlangObject[] { new OtpErlangAtom(i.getImportModule()), new OtpErlangList(funsT) });
            result.add(modFunsT);
        }
        return result;
    }

    public static final List<OtpErlangObject> NO_IMPORTS = new ArrayList<>(0);

    private void addUnitNamesWithPrefix(final String prefix, final List<String> result,
            final Collection<IErlModule> modules, final boolean external, final boolean includes) {
        for (final IErlModule module : modules) {
            String moduleName = includes ? module.getName() : module.getModuleName();
            if (external && includes) {
                moduleName = getIncludeLibPath(module);
            }
            boolean nameMatches = moduleName.startsWith(prefix);
            if (!nameMatches && prefix.startsWith("'")) {
                nameMatches = moduleName.startsWith(prefix.substring(1));
            }
            if (nameMatches && (includes || !module.getName().endsWith(".hrl"))) {
                if (!result.contains(moduleName)) {
                    final String name = new OtpErlangAtom(moduleName).toString();
                    result.add(name);
                }
            }
        }
    }

    private String getIncludeLibPath(final IErlModule module) {
        String s = module.getName();
        String prevS = s;
        IErlElement e = module;
        for (;;) {
            final IParent p = e.getParent();
            if (p instanceof IErlProject) {
                break;
            }
            e = (IErlElement) p;
            prevS = s;
            s = e.getName() + "/" + s;
        }
        return prevS;
    }

    @Override
    public String[] getPredefinedMacroNames() {
        return new String[] { "MODULE", "LINE", "FILE", "FUNCTION_NAME", "FUNCTION_ARITY" };
    }

    @Override
    public boolean isOtpModule(final IErlModule module) {
        IParent parent = module.getParent();
        while (parent instanceof IErlExternal) {
            final IErlExternal external = (IErlExternal) parent;
            if (external.isOTP()) {
                return true;
            }
            parent = external.getParent();
        }
        return false;
    }

    @Override
    public IErlModule getModule(final IErlElement element) {
        if (element instanceof IErlModule) {
            return (IErlModule) element;
        }
        return (IErlModule) element.getAncestorOfKind(ErlElementKind.MODULE);
    }

    @Override
    public IErlProject getProject(final IErlElement element) {
        if (element == null) {
            return null;
        }
        final IErlElement ancestor = element.getAncestorOfKind(ErlElementKind.PROJECT);
        if (ancestor instanceof IErlProject) {
            return (IErlProject) ancestor;
        }
        return null;
    }

    /**
     * Helper method - returns the targeted item (IResource if internal or
     * java.io.File if external), or null if unbound Internal items must be
     * referred to using container relative paths.
     */
    @Override
    public Object getTarget(final IContainer container, final IPath path, final boolean checkResourceExistence) {

        if (path == null) {
            return null;
        }

        // lookup - inside the container
        if (path.getDevice() == null) { // container relative paths should not
            // contain a device
            // (see http://dev.eclipse.org/bugs/show_bug.cgi?id=18684)
            // (case of a workspace rooted at d:\ )
            final IResource resource = container.findMember(path);
            if (resource != null) {
                if (!checkResourceExistence || resource.exists()) {
                    return resource;
                }
                return null;
            }
        }

        // if path is relative, it cannot be an external path
        // (see http://dev.eclipse.org/bugs/show_bug.cgi?id=22517)
        if (!path.isAbsolute()) {
            return null;
        }

        // lookup - outside the container
        final File externalFile = new File(path.toOSString());
        if (!checkResourceExistence) {
            return externalFile;
        }
        if (externalFile.exists()) {
            return externalFile;
        }
        return null;
    }

    @Override
    public String getModuleInfo(final IErlModule module) {
        final String errorValue = "There is no module information about this file.";
        if (module == null) {
            return errorValue;
        }

        final IErlProject project = getProject(module);
        final IPath beamPath = project.getProperties().getOutputDir().append(module.getModuleName())
                .addFileExtension("beam");
        final IFile beam = project.getWorkspaceProject().getFile(beamPath);

        try {
            final OtpErlangObject info = backend.call("erlide_backend", "get_module_info", "s",
                    beam.getLocation().toPortableString());
            return (String) TypeConverter.erlang2java(info, String.class);
        } catch (final Exception e) {
            ErlLogger.warn(e);
        }
        return errorValue;
    }
}