package bndtools.m2e;
import java.io.File;
import java.io.InputStream;
import java.util.AbstractMap;
import java.util.AbstractMap.SimpleImmutableEntry;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.SortedSet;
import org.apache.maven.project.MavenProject;
import org.bndtools.api.ILogger;
import org.bndtools.api.Logger;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.m2e.core.MavenPlugin;
import org.eclipse.m2e.core.project.IMavenProjectChangedListener;
import org.eclipse.m2e.core.project.IMavenProjectFacade;
import org.eclipse.m2e.core.project.IMavenProjectRegistry;
import org.eclipse.m2e.core.project.MavenProjectChangedEvent;
import org.osgi.resource.Capability;
import org.osgi.resource.Requirement;
import org.osgi.service.repository.Repository;
import aQute.bnd.osgi.Domain;
import aQute.bnd.osgi.repository.BaseRepository;
import aQute.bnd.service.Refreshable;
import aQute.bnd.service.RepositoryPlugin;
import aQute.bnd.version.Version;
import aQute.lib.collections.SortedList;
public class MavenWorkspaceRepository extends BaseRepository implements Repository, RepositoryPlugin, Refreshable, IMavenProjectChangedListener {
private final static ILogger logger = Logger.getLogger(MavenWorkspaceRepository.class);
private final IMavenProjectRegistry mavenProjectRegistry = MavenPlugin.getMavenProjectRegistry();
private boolean inited = false;
private final Map<String,Entry<IMavenProjectFacade,MavenProject>> bsnMap = new HashMap<>();
@Override
public Map<Requirement,Collection<Capability>> findProviders(Collection< ? extends Requirement> requirements) {
return null;
}
@Override
public boolean refresh() throws Exception {
return false;
}
@Override
public File getRoot() throws Exception {
return null;
}
@Override
public PutResult put(InputStream stream, PutOptions options) throws Exception {
return null;
}
@Override
public File get(final String bsn, final Version version, Map<String,String> properties, final DownloadListener... listeners) throws Exception {
if (!inited) {
init();
}
final Entry<IMavenProjectFacade,MavenProject> entry = bsnMap.get(bsn);
if (entry == null)
return null;
final MavenProject mavenProject = entry.getValue();
// add the eclipse project that this comes from so we can look it up in the launch
// see bndtools.launch.BndDependencySourceContainer.createSourceContainers()
final String projectName = entry.getKey().getProject().getName();
properties.put("sourceProjectName", projectName);
final File bundleFile = getBundleFile(mavenProject);
if (!bundleFile.exists()) {
for (DownloadListener listener : listeners) {
try {
listener.failure(bundleFile, "Could not get bundle file for " + bsn + ":" + version);
} catch (Throwable t) {
logger.logError("Download listener error", t);
}
}
return null;
}
for (DownloadListener listener : listeners) {
try {
listener.success(bundleFile);
} catch (Throwable t) {
logger.logError("Download listener error", t);
}
}
return bundleFile;
}
private File getBundleFile(final MavenProject mavenProject) {
return new File(mavenProject.getBuild().getDirectory(), mavenProject.getBuild().getFinalName() + ".jar");
}
private String getBsnFromMavenProject(MavenProject mavenProject) throws Exception {
final File bundleFile = getBundleFile(mavenProject);
if (bundleFile.exists()) {
Domain domain = Domain.domain(bundleFile);
String bsn = domain.getBundleSymbolicName().getKey();
return bsn;
}
return null;
}
private void init() {
inited = true;
final IProgressMonitor monitor = new NullProgressMonitor();
for (IMavenProjectFacade projectFacade : mavenProjectRegistry.getProjects()) {
final IProject project = projectFacade.getProject();
try {
final MavenProject mavenProject = getMavenProject(projectFacade, monitor);
final String bsn = getBsnFromMavenProject(mavenProject);
if (bsn != null) {
Entry<IMavenProjectFacade,MavenProject> entry = new AbstractMap.SimpleImmutableEntry<>(projectFacade, mavenProject);
bsnMap.put(bsn, entry);
}
} catch (Exception e) {
logger.logError("Unable to get bundle symbolic name for " + project.getName(), e);
}
}
mavenProjectRegistry.addMavenProjectChangedListener(this);
}
private MavenProject getMavenProject(final IMavenProjectFacade projectFacade, final IProgressMonitor monitor) throws CoreException {
MavenProject mavenProject = projectFacade.getMavenProject();
if (mavenProject == null) {
mavenProject = projectFacade.getMavenProject(monitor);
}
return mavenProject;
}
@Override
public boolean canWrite() {
return false;
}
@Override
public List<String> list(String pattern) throws Exception {
return null;
}
@Override
public SortedSet<Version> versions(String bsn) throws Exception {
if (!inited) {
init();
}
Version version = null;
final Entry<IMavenProjectFacade,MavenProject> entry = bsnMap.get(bsn);
if (entry != null) {
final MavenProject mavenProject = entry.getValue();
final File bundleFile = getBundleFile(mavenProject);
if (bundleFile.exists()) {
Domain domain = Domain.domain(bundleFile);
version = new Version(domain.getBundleVersion());
}
}
if (version == null) {
return SortedList.empty();
}
return new SortedList<Version>(version);
}
@Override
public String getName() {
return "Maven Workspace Repository";
}
@Override
public String getLocation() {
return null;
}
@Override
public void mavenProjectChanged(MavenProjectChangedEvent[] events, IProgressMonitor monitor) {
if (events == null)
return;
for (MavenProjectChangedEvent event : events) {
final IMavenProjectFacade oldProject = event.getOldMavenProject();
final Iterator<Entry<String,Entry<IMavenProjectFacade,MavenProject>>> entries = bsnMap.entrySet().iterator();
while (entries.hasNext()) {
final Entry<String,Entry<IMavenProjectFacade,MavenProject>> entry = entries.next();
if (entry.getValue().getKey().equals(oldProject)) {
String bsn = entry.getKey();
bsnMap.remove(bsn);
break;
}
}
final IMavenProjectFacade newProject = event.getMavenProject();
try {
final MavenProject newMavenProject = getMavenProject(newProject, monitor);
final String newBsn = getBsnFromMavenProject(newMavenProject);
final Entry<IMavenProjectFacade,MavenProject> newEntry = new SimpleImmutableEntry<>(newProject, newMavenProject);
bsnMap.put(newBsn, newEntry);
} catch (Exception e) {
logger.logError("Error getting bsn for new project " + newProject.getProject().getName(), e);
}
}
}
void cleanup() {
mavenProjectRegistry.removeMavenProjectChangedListener(this);
}
}