package com.redhat.ceylon.eclipse.core.classpath;
import static com.redhat.ceylon.eclipse.core.classpath.CeylonClasspathUtil.ceylonSourceArchiveToJavaSourceArchive;
import static com.redhat.ceylon.eclipse.java2ceylon.Java2CeylonProxies.modelJ2C;
import static com.redhat.ceylon.eclipse.ui.CeylonPlugin.PLUGIN_ID;
import static org.eclipse.jdt.core.JavaCore.newLibraryEntry;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.IClasspathAttribute;
import org.eclipse.jdt.core.IClasspathContainer;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import com.redhat.ceylon.cmr.api.ArtifactContext;
import com.redhat.ceylon.cmr.api.RepositoryManager;
import com.redhat.ceylon.compiler.typechecker.TypeChecker;
import com.redhat.ceylon.ide.common.model.BaseCeylonProject;
/**
* Ceylon Language Module Classpath Container - resolves a classpath container id to the ceylon.language binary archive
*/
public class CeylonLanguageModuleContainer implements IClasspathContainer {
public static final String CONTAINER_ID = PLUGIN_ID + ".cpcontainer.RUNTIME_CONTAINER";
/**
* Container path used to resolve to this CPC
*/
private IPath fPath = null;
/**
* The project this container is for
*/
private IJavaProject fProject = null;
IClasspathEntry[] entries = null;
/**
* Constructs a classpath container for the ceylon language runtime archive on the given project
*
*/
public CeylonLanguageModuleContainer(IProject project) {
modelJ2C().ceylonModel().addProject(project);
fPath = new Path(CeylonLanguageModuleContainer.CONTAINER_ID + "/default");
fProject = JavaCore.create(project);
BaseCeylonProject ceylonProject = modelJ2C().ceylonModel().getProject(project);
RepositoryManager repoManager = ceylonProject != null ? ceylonProject.getRepositoryManager() : null;
List<IClasspathEntry> entriesList = new ArrayList<IClasspathEntry>();
List<String> moduleNames = Arrays.asList("ceylon.language", "com.redhat.ceylon.model", "com.redhat.ceylon.common");
String moduleVersion = TypeChecker.LANGUAGE_MODULE_VERSION;
if (repoManager != null) {
for (String moduleName : moduleNames) {
File moduleArtifact = null;
try {
moduleArtifact = repoManager.getArtifact(new ArtifactContext(null, moduleName, moduleVersion, ArtifactContext.CAR, ArtifactContext.JAR));
} catch (Exception e) {
e.printStackTrace();
}
if (moduleArtifact != null) {
IPath moduleBinaries = new Path(moduleArtifact.getAbsolutePath());
File sourceArchive = repoManager.getArtifact(new ArtifactContext(null, moduleName,moduleVersion, ArtifactContext.SRC));
IPath moduleSources = null;
if (moduleArtifact.getName().endsWith(ArtifactContext.CAR)) {
File moduleJavaSources = null;
try {
moduleJavaSources = ceylonSourceArchiveToJavaSourceArchive(
moduleName,
moduleVersion,
sourceArchive);
} catch(Exception e) {
e.printStackTrace();
}
moduleSources = moduleJavaSources != null ?
new Path(moduleJavaSources.getAbsolutePath()) : null;
} else {
moduleSources = new Path(sourceArchive.getAbsolutePath());
}
IClasspathEntry entry = newLibraryEntry(moduleBinaries, moduleSources, null);
entriesList.add(entry);
}
}
}
IClasspathEntry[] entriesArray = new IClasspathEntry[entriesList.size()];
entries = entriesList.toArray(entriesArray);
}
public IClasspathEntry[] constructModifiedClasspath()
throws JavaModelException {
// Modifies the project classpath :
// Beware to always add the language module container before the application modules container
IClasspathEntry runtimeEntry = JavaCore.newContainerEntry(fPath, null,
new IClasspathAttribute[0], true);
IClasspathEntry[] entries = fProject.getRawClasspath();
List<IClasspathEntry> newEntries = new ArrayList<IClasspathEntry>(Arrays.asList(entries));
int indexFirstContainer = -1;
int indexSecondContainer = -1;
int index = 0;
boolean languageModuleEntryWasExported = false;
IClasspathEntry ceylonClasspathEntry = null;
for (IClasspathEntry entry: newEntries) {
boolean containerToReplace = false;
if (entry.getPath().equals(runtimeEntry.getPath()) ) {
containerToReplace = true;
languageModuleEntryWasExported = entry.isExported();
}
if (entry.getPath().segment(0)
.equals(CeylonProjectModulesContainer.CONTAINER_ID) ) {
containerToReplace = true;
ceylonClasspathEntry = entry;
containerToReplace = true;
}
if (containerToReplace) {
if (indexFirstContainer == -1) {
indexFirstContainer = index;
}
else {
indexSecondContainer = index;
}
}
index++;
}
IClasspathEntry newEntry = JavaCore.newContainerEntry(fPath, null,
new IClasspathAttribute[0], indexFirstContainer == -1 || languageModuleEntryWasExported);
if (indexFirstContainer >= 0) {
newEntries.set(indexFirstContainer, newEntry);
}
else {
newEntries.add(newEntry);
}
if (ceylonClasspathEntry != null) {
if (indexSecondContainer >= 0) {
newEntries.set(indexSecondContainer, ceylonClasspathEntry);
}
else {
newEntries.add(ceylonClasspathEntry);
}
}
return (IClasspathEntry[]) newEntries.toArray(new IClasspathEntry[newEntries.size()]);
}
/**
* @see IClasspathContainer#getClasspathEntries()
*/
public IClasspathEntry[] getClasspathEntries() {
return entries;
}
public String getRuntimeVersion() {
return TypeChecker.LANGUAGE_MODULE_VERSION;
}
/**
* @see IClasspathContainer#getDescription()
*/
public String getDescription() {
return "Ceylon Language Module \u2014 " + getRuntimeVersion();
}
/**
* @see IClasspathContainer#getKind()
*/
public int getKind() {
return IClasspathContainer.K_APPLICATION;
}
/**
* @see IClasspathContainer#getPath()
*/
public IPath getPath() {
return fPath;
}
public void install() throws JavaModelException {
fProject.setRawClasspath(constructModifiedClasspath(), null);
JavaCore.setClasspathContainer(getPath(),
new IJavaProject[] { fProject },
new IClasspathContainer[] { this }, null);
}
}