/******************************************************************************* * Copyright (c) 2009 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.backend.internal; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import org.eclipse.jdt.annotation.NonNull; import org.erlide.backend.BackendUtils; import org.erlide.backend.api.ICodeBundle; import org.erlide.backend.api.ICodeBundle.CodeContext; import org.erlide.backend.debug.BeamUtil; import org.erlide.runtime.api.BeamLoader; import org.erlide.runtime.rpc.IOtpRpc; import org.erlide.runtime.runtimeinfo.RuntimeVersion; import org.erlide.util.ErlLogger; import com.ericsson.otp.erlang.OtpErlangBinary; public class CodeManager { private final IOtpRpc site; private final String backendName; private final List<PathItem> pathA; private final List<PathItem> pathZ; private final RuntimeVersion version; // only to be called by Backend CodeManager(final IOtpRpc site, final String backendName, final RuntimeVersion version) { this.site = site; this.backendName = backendName; this.version = version; pathA = new ArrayList<>(); pathZ = new ArrayList<>(); } public void addPath(final boolean usePathZ, final @NonNull String path) { if (usePathZ) { if (addPath(pathZ, path)) { ErlangCode.addPathZ(site, path); } } else { if (addPath(pathA, path)) { ErlangCode.addPathA(site, path); } } } public void removePath(final @NonNull String path) { if (removePath(pathA, path)) { ErlangCode.removePath(site, path); } } public void register(final CodeContext context, final ICodeBundle bundle) { if (bundle.getVersion() != RuntimeVersion.NO_VERSION && bundle.getVersion().getMajor() != version.getMajor()) { return; } final Collection<String> ebinDirs = bundle.getEbinDirs(context); if (ebinDirs == null) { ErlLogger.warn("Could not find 'ebin' in bundle %s.", bundle.getBundle()); return; } for (final String ebinDir : ebinDirs) { final String localDir = ebinDir.replaceAll("\\\\", "/"); final boolean accessible = BackendUtils.isAccessibleDir(site, localDir); final boolean embedded = ErlangCode.isEmbedded(site); if (accessible && !embedded) { ErlangCode.addPathA(site, localDir); } else { ErlLogger.debug("loading %s for %s", bundle.getBundle(), backendName); loadCodeForBundle(context, bundle, ebinDir); } } } public void unregister(final CodeContext context, final ICodeBundle bundle) { if (bundle == null) { return; } ErlLogger.debug("unloading %s for %s", bundle.getBundle(), backendName); unloadCodeForBundle(context, bundle); } private boolean loadBeam(final String moduleName, final URL beamPath) { final OtpErlangBinary bin = BeamUtil.getBeamBinary(moduleName, beamPath); if (bin == null) { return false; } return BeamLoader.loadBeam(site, moduleName, bin); } private void loadCodeForBundle(final CodeContext context, final ICodeBundle bundle, final String ebinDir2) { final Collection<URL> beams = bundle.getEbinBeamURLs(context); if (beams == null) { return; } for (final URL beam : beams) { final String beamModuleName = BackendUtils.getBeamModuleName(beam.getPath()); if (beamModuleName != null) { ErlLogger.debug(" load " + beamModuleName); if (!loadBeam(beamModuleName, beam)) { ErlLogger.error("Could not load %s", beamModuleName); } } } } private void unloadCodeForBundle(final CodeContext context, final ICodeBundle bundle) { final Collection<URL> beams = bundle.getEbinBeamURLs(context); if (beams == null) { return; } for (final URL beam : beams) { final String beamModuleName = BackendUtils.getBeamModuleName(beam.getPath()); if (beamModuleName != null) { ErlLogger.debug(" unload " + beamModuleName); unloadBeam(beamModuleName); } } } private boolean addPath(final List<PathItem> l, final @NonNull String path) { final PathItem it = findItem(l, path); if (it == null) { l.add(new PathItem(path)); return true; } it.incRef(); return false; } private boolean removePath(final List<PathItem> l, final @NonNull String path) { final PathItem it = findItem(l, path); if (it != null) { it.decRef(); if (it.ref <= 0) { l.remove(it); return true; } } return false; } private PathItem findItem(final List<PathItem> l, final String p) { final Iterator<PathItem> i = l.iterator(); while (i.hasNext()) { final PathItem it = i.next(); if (it.path.equals(p)) { return it; } } return null; } private void unloadBeam(final String moduleName) { ErlangCode.delete(site, moduleName); } private static class PathItem { public PathItem(final String p) { path = p; ref = 1; } public String path; public int ref; public void incRef() { ref++; } public void decRef() { ref--; } } }