/*******************************************************************************
* Copyright © 2005, 2013 IBM Corporation 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:
* IBM Corporation - initial API and implementation
*
*******************************************************************************/
package org.eclipse.edt.ide.core.internal.lookup;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.edt.compiler.ICompiler;
import org.eclipse.edt.compiler.binding.FileBinding;
import org.eclipse.edt.compiler.binding.IPackageBinding;
import org.eclipse.edt.compiler.binding.IPartBinding;
import org.eclipse.edt.compiler.binding.ITypeBinding;
import org.eclipse.edt.compiler.core.ast.File;
import org.eclipse.edt.compiler.core.ast.Node;
import org.eclipse.edt.compiler.internal.core.builder.AbstractProcessingQueue;
import org.eclipse.edt.compiler.internal.core.builder.CircularBuildRequestException;
import org.eclipse.edt.compiler.internal.core.builder.IBuildNotifier;
import org.eclipse.edt.compiler.internal.core.compiler.BindingCompletor;
import org.eclipse.edt.compiler.internal.core.dependency.NullDependencyRequestor;
import org.eclipse.edt.compiler.internal.core.lookup.BindingCreator;
import org.eclipse.edt.compiler.internal.core.lookup.DefaultCompilerOptions;
import org.eclipse.edt.compiler.internal.core.lookup.EnvironmentScope;
import org.eclipse.edt.compiler.internal.core.lookup.FileASTScope;
import org.eclipse.edt.compiler.internal.core.lookup.FileScope;
import org.eclipse.edt.compiler.internal.core.lookup.IBuildPathEntry;
import org.eclipse.edt.compiler.internal.core.lookup.IEnvironment;
import org.eclipse.edt.compiler.internal.core.lookup.Scope;
import org.eclipse.edt.compiler.internal.core.utils.PartBindingCache;
import org.eclipse.edt.compiler.internal.util.BindingUtil;
import org.eclipse.edt.compiler.internal.util.PackageAndPartName;
import org.eclipse.edt.ide.core.internal.binding.PartRestoreFailedException;
import org.eclipse.edt.ide.core.internal.builder.ASTManager;
import org.eclipse.edt.ide.core.internal.utils.Util;
import org.eclipse.edt.ide.core.utils.ProjectSettingsUtility;
import org.eclipse.edt.mof.EObject;
import org.eclipse.edt.mof.egl.Part;
import org.eclipse.edt.mof.egl.PartNotFoundException;
import org.eclipse.edt.mof.serialization.CachingObjectStore;
import org.eclipse.edt.mof.serialization.DeserializationException;
import org.eclipse.edt.mof.serialization.ObjectStore;
import org.eclipse.edt.mof.utils.NameUtile;
/**
* @author winghong
*/
public class ProjectBuildPathEntry implements IBuildPathEntry {
private class RealizingEnvironment implements IEnvironment {
@Override
public IPartBinding getPartBinding(String packageName, String partName) {
return ProjectBuildPathEntry.this.getPartBinding(packageName, partName, true);
}
@Override
public IPartBinding getNewPartBinding(PackageAndPartName ppName, int kind) {
return ProjectBuildPathEntry.this.getNewPartBinding(ppName, kind);
}
@Override
public boolean hasPackage(String packageName) {
return ProjectBuildPathEntry.this.hasPackage(packageName);
}
@Override
public IPackageBinding getRootPackage() {
return declaringEnvironment.getRootPackage();
}
@Override
public ICompiler getCompiler() {
return ProjectBuildPathEntry.this.getCompiler();
}
}
private ProjectInfo projectInfo;
private PartBindingCache bindingCache;
private AbstractProcessingQueue processingQueue;
private ProjectEnvironment declaringEnvironment;
private IEnvironment realizingEnvironment;
private ObjectStore[] stores;
public static final ObjectStore[] EMPTY_STORES = new ObjectStore[0];
protected ProjectBuildPathEntry(ProjectInfo projectInfo) {
this.projectInfo = projectInfo;
this.bindingCache = new PartBindingCache();
this.stores = EMPTY_STORES;
this.realizingEnvironment = new RealizingEnvironment();
}
protected ProjectEnvironment getDeclaringEnvironment() {
return this.declaringEnvironment;
}
protected void setDeclaringEnvironment(ProjectEnvironment projectEnvironment) {
this.declaringEnvironment = projectEnvironment;
}
protected void setObjectStores(ObjectStore[] stores) {
if (stores == null) {
this.stores = EMPTY_STORES;
}
else {
this.stores = stores;
}
}
@Override
public ObjectStore[] getObjectStores() {
return stores;
}
public void setProcessingQueue(AbstractProcessingQueue processingQueue) {
this.processingQueue = processingQueue;
}
/**
* Called by a level_01 compile to create a binding for a part when the processing queue is too long.
* This should only be called on 'Source' projects, as a read only project would result in the part being loaded
* directly from an IR instead of being compiled.
*/
@Override
public int hasPart(String packageName, String partName) {
return projectInfo.hasPart(packageName, partName);
}
@Override
public boolean hasPackage(String packageName) {
return projectInfo.hasPackage(packageName);
}
public IPartBinding getPartBindingFromCache(String packageName, String partName){
return bindingCache.get(packageName, partName);
}
public IPartBinding getPartBinding(String packageName, String partName) {
return getPartBinding(packageName, partName, false);
}
public IPartBinding getPartBinding(String packageName, String partName, boolean force) {
//Short circuit...do not look in this enry for binary porject parts
if (ProjectBuildPathManager.getInstance().getProjectBuildPath(projectInfo.getProject()).isBinary()) {
return null;
}
IPartBinding result = null;
if(processingQueue != null) {
result = processingQueue.requestCompilationFor(packageName, partName, force);
}
if(result == null){
// Conceptually should check whether it has that part or not, but for performance reason we will try to grab it from
// the cache first.
// The existance of a part in the cache implies that the part does physically exist
result = bindingCache.get(packageName, partName);
if(result != null) {
return result;
}
else {
//RMERUI
if(ProjectBuildPathManager.getInstance().getProjectBuildPath(projectInfo.getProject()).isReadOnly()){
// It is a project with no source, read the IRs
return readPartBinding(packageName, partName);
}else{
// This project has source, compile from the source
if(projectInfo.hasPart(packageName, partName) != ITypeBinding.NOT_FOUND_BINDING) {
IFile declaringFile = projectInfo.getPartOrigin(packageName, partName).getEGLFile();
if(NameUtile.equals(Util.getFilePartName(declaringFile), partName) || projectInfo.hasPart(packageName,partName) == ITypeBinding.FUNCTION_BINDING){
// File and function parts are not stored on disk, create a new one
try{
return compileLevel2Binding(projectInfo.getPackageAndPartName(packageName, partName));
}catch(CircularBuildRequestException e){
// Remove this part from the cache, so that it is not used incorrectly at a different time
removePartBindingInvalid(packageName, partName);
throw e;
}
}
else{
return readPartBinding(packageName, partName);
}
}
else {
return null;
}
}
}
}
return result;
}
public IPartBinding getNewPartBinding(PackageAndPartName ppName, int kind) {
IPartBinding partBinding = bindingCache.get(ppName.getPackageName(), ppName.getPartName());
if(partBinding == null || partBinding.getKind() != kind) {
partBinding = BindingUtil.createPartBinding(kind, ppName);
bindingCache.put(ppName.getPackageName(), ppName.getPartName(), partBinding);
}
else {
partBinding.clear();
partBinding.setValid(false);
}
return partBinding;
}
private IPartBinding readPartBinding(String packageName, String partName) {
try {
EObject ir = readPart(packageName, partName);
if (ir != null) {
IPartBinding partBinding = BindingUtil.createPartBinding(ir);
if (partBinding != null) {
bindingCache.put(packageName, partName, partBinding);
return partBinding;
}
}
return null;
}
catch(Exception e) {
throw new PartRestoreFailedException(packageName, partName, e);
}
}
/**
* Called when a part is on the queue but cannot be completly compiled
*/
public IPartBinding compileLevel2Binding(PackageAndPartName ppName) {
IFile declaringFile = projectInfo.getPartOrigin(ppName.getPackageName(), ppName.getPartName()).getEGLFile();
Node partAST = ASTManager.getInstance().getAST(declaringFile, ppName.getPartName());
IPartBinding partBinding = new BindingCreator(declaringEnvironment, ppName, partAST).getPartBinding();
partBinding.setEnvironment(declaringEnvironment);
Scope scope;
if(partBinding.getKind() == ITypeBinding.FILE_BINDING){
scope = new EnvironmentScope(declaringEnvironment, NullDependencyRequestor.getInstance());
}else{
String fileName = Util.getFilePartName(declaringFile);
IPartBinding fileBinding = getPartBinding(ppName.getPackageName(), fileName, true);
if(!fileBinding.isValid()){
scope = new FileASTScope(new EnvironmentScope(declaringEnvironment, NullDependencyRequestor.getInstance()), (FileBinding)fileBinding, ASTManager.getInstance().getFileAST(declaringFile));
}else{
scope = new FileScope(new EnvironmentScope(declaringEnvironment, NullDependencyRequestor.getInstance()), (FileBinding)fileBinding, NullDependencyRequestor.getInstance());
}
}
BindingCompletor.getInstance().completeBinding(partAST, partBinding, scope, DefaultCompilerOptions.getInstance());
bindingCache.put(ppName.getPackageName(), ppName.getPartName(), partBinding);
return partBinding;
}
/**
*
* Mark this part binding as invalid if it is in the cache.
*/
protected void markPartBindingInvalid(String packageName, String partName) {
IPartBinding result = bindingCache.get(packageName, partName);
if(result != null){
result.setValid(false);
}
}
/**
* Remove this part binding from the cache since it has been removed from the workspace
*/
public void removePartBindingInvalid(String packageName, String partName) {
bindingCache.remove(packageName, partName);
}
/**
* Return this entry's IProject
*/
public IProject getProject(){
return projectInfo.getProject();
}
public IEnvironment getRealizingEnvironment() {
return realizingEnvironment;
}
public void clear(boolean clean) {
bindingCache = new PartBindingCache();
if (clean) {
for (ObjectStore store : stores) {
if (store instanceof CachingObjectStore) {
((CachingObjectStore)store).clearCache();
}
}
}
}
public boolean isZipFile(){
return false;
}
public boolean isProject(){
return true;
}
public String getID(){
return getProject().getName();
}
public FileBinding getFileBinding(String packageName, String fileName, File fileAST) {
String caseInsensitiveInternedFileName = NameUtile.getAsName(fileName);
FileBinding fileBinding = getFileBindingFromCache(packageName, caseInsensitiveInternedFileName);
if (fileBinding != null) {
return fileBinding;
}
PackageAndPartName ppName = new PackageAndPartName(org.eclipse.edt.compiler.Util.createCaseSensitivePackageName(fileAST), caseInsensitiveInternedFileName);
fileBinding = (FileBinding)new BindingCreator(declaringEnvironment, ppName, fileAST).getPartBinding();
fileBinding.setEnvironment(declaringEnvironment);
Scope scope = new EnvironmentScope(declaringEnvironment, NullDependencyRequestor.getInstance());
BindingCompletor.getInstance().completeBinding(fileAST, fileBinding, scope, DefaultCompilerOptions.getInstance());
bindingCache.put(packageName, caseInsensitiveInternedFileName, fileBinding);
return fileBinding;
}
public FileBinding getFileBindingFromCache(String packageName, String partName){
return (FileBinding)bindingCache.get(packageName, partName);
}
@Override
public IPartBinding getCachedPartBinding(String packageName, String partName) {
return getPartBindingFromCache(packageName, partName);
}
private EObject readPart(String packageName, String name) throws DeserializationException {
StringBuilder keyBuf = new StringBuilder( 100 );
keyBuf.append(":");
if (packageName != null && packageName.length() > 0) {
keyBuf.append(packageName);
keyBuf.append('.');
}
keyBuf.append(name);
for (int i = 0; i < stores.length; i++) {
EObject ir = stores[i].get(stores[i].getKeyScheme() + keyBuf.toString());
if (ir != null) {
return ir;
}
}
return null;
}
@Override
public Part findPart(String packageName, String name) throws PartNotFoundException {
if(ProjectBuildPathManager.getInstance().getProjectBuildPath(projectInfo.getProject()).isReadOnly()
|| projectInfo.hasPart(packageName, name) != ITypeBinding.NOT_FOUND_BINDING){
try {
EObject ir = readPart(packageName, name);
if (ir instanceof Part) {
return (Part)ir;
}
}
catch (DeserializationException e) {
throw new PartNotFoundException(e);
}
}
return null;
}
protected ICompiler getCompiler() {
return ProjectSettingsUtility.getCompiler(getProject());
}
public IBuildNotifier getNotifier() {
return processingQueue == null ? null : processingQueue.getNotifier();
}
}