/*******************************************************************************
* Copyright (c) 2005, 2012 eBay Inc.
* 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
*
*******************************************************************************/
package org.eclipse.dltk.mod.internal.core;
import java.net.URI;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.dltk.mod.core.DLTKCore;
import org.eclipse.dltk.mod.core.IBuffer;
import org.eclipse.dltk.mod.core.IModelElement;
import org.eclipse.dltk.mod.core.ISourceElementParserExtension;
import org.eclipse.dltk.mod.core.ISourceModule;
import org.eclipse.dltk.mod.core.IType;
import org.eclipse.dltk.mod.core.ModelException;
import org.eclipse.dltk.mod.core.SourceParserUtil;
import org.eclipse.dltk.mod.core.WorkingCopyOwner;
import org.eclipse.dltk.mod.internal.core.builder.StandardScriptBuilder;
import org.eclipse.dltk.mod.utils.CorePrinter;
import org.eclipse.vjet.dsf.jst.IJstNode;
import org.eclipse.vjet.dsf.jst.IJstType;
import org.eclipse.vjet.dsf.jst.IScriptProblem;
import org.eclipse.vjet.dsf.jst.declaration.JstBlock;
import org.eclipse.vjet.dsf.jstojava.translator.JstUtil;
import org.eclipse.vjet.dsf.ts.type.TypeName;
import org.eclipse.vjet.eclipse.codeassist.CodeassistUtils;
import org.eclipse.vjet.eclipse.core.IVjoSourceModule;
import org.eclipse.vjet.eclipse.core.VjetPlugin;
import org.eclipse.vjet.eclipse.core.parser.VjoParserToJstAndIType;
import org.eclipse.vjet.eclipse.internal.compiler.VjoSourceElementParser;
import org.eclipse.vjet.vjo.tool.typespace.ITypeSpaceRunnable;
import org.eclipse.vjet.vjo.tool.typespace.SourceTypeName;
import org.eclipse.vjet.vjo.tool.typespace.TypeSpaceListener;
import org.eclipse.vjet.vjo.tool.typespace.TypeSpaceMgr;
public class VjoSourceModule extends JSSourceModule implements
TypeSpaceListener, IVjoSourceModule {
private TypeSpaceMgr mgr = TypeSpaceMgr.getInstance();
protected IJstType jstType;
private boolean isConsistent = false;
// private boolean m_typeProcessed;
// private List<IScriptProblem> m_probs;
// private List<JstBlock> m_blockList;
// private JstBlock m_block;
// private IUnitSource m_unitSource = new VjoUnitSource();
private final class SourceStructureBuilder implements ITypeSpaceRunnable {
private final IResource underlyingResource;
private final OpenableElementInfo info;
private final Map newElements;
private final IProgressMonitor progressMonitor;
private boolean isStructureKnown = false;
private SourceStructureBuilder(IResource underlyingResource,
OpenableElementInfo info, Map newElements,
IProgressMonitor progressMonitor) {
this.underlyingResource = underlyingResource;
this.info = info;
this.newElements = newElements;
this.progressMonitor = progressMonitor;
}
public void run() {
try {
isStructureKnown = doBuild(info, progressMonitor, newElements,
underlyingResource);
} catch (ModelException e) {
DLTKCore.error(e.toString(), e);
}
}
public boolean isStructureKnown() {
return isStructureKnown;
}
}
public VjoSourceModule(ScriptFolder parent, String name,
WorkingCopyOwner owner) {
super(parent, name, owner);
}
@Override
protected Object openWhenClosed(Object info, IProgressMonitor monitor)
throws ModelException {
// TypeSpaceMgr mgr = TypeSpaceMgr.getInstance();
return super.openWhenClosed(info, monitor);
}
@Override
protected boolean buildStructure(final OpenableElementInfo info,
final IProgressMonitor progressMonitor, final Map newElements,
final IResource underlyingResource) throws ModelException {
// TODO add this check back not using JstGroupCache
// if (!mgr.existGroup(getGroupName())) {
// return false;
// }
SourceStructureBuilder builder;
builder = new SourceStructureBuilder(underlyingResource, info,
newElements, progressMonitor);
mgr.run(builder);
return builder.isStructureKnown();
}
private boolean doBuild(OpenableElementInfo info,
IProgressMonitor progressMonitor, Map newElements,
IResource underlyingResource) throws ModelException {
try {
final JSSourceModuleElementInfo moduleInfo = (JSSourceModuleElementInfo) info;
// generate structure and compute syntax problems if needed
final VjoSourceModuleStructureRequestor requestor = new VjoSourceModuleStructureRequestor(
this, moduleInfo, newElements);
// System.out.println("==> Parsing: " + resource.getName());
final String natureId = getNatureId();
if (natureId == null) {
throw new ModelException(new ModelStatus(
ModelStatus.INVALID_NAME));
}
SourceTypeName stName = getTypeName();
IResource resource = getResource();
// it is not a workspace file
// if ("".equals(stName.groupName().trim()) && (resource == null ||
// !resource.exists())) {
// jstType = CodeassistUtils.findNativeJstType(stName.typeName());
// } else {
// processType(contents);
// }
final VjoSourceElementParser parser = (VjoSourceElementParser) getSourceElementParser(natureId);
if (!isReadOnly()) {
((ISourceElementParserExtension) parser).setScriptProject(this
.getScriptProject());
}
parser.setRequestor(requestor);
final AccumulatingProblemReporter problemReporter = getAccumulatingProblemReporter();
parser.setReporter(problemReporter);
boolean reparsed = false;
if (problemReporter != null) {
if (!problemReporter.hasErrors()) {
StructureBuilder.build(natureId, this, problemReporter);
reparsed = true;
}
problemReporter.reportToRequestor();
}
if(jstType==null && isVirtualTypeResource(resource)){
jstType = TypeSpaceMgr.QE().findType(stName);
}else if (jstType == null || !reparsed) {
if ("".equals(stName.groupName().trim())
&& (resource == null || !resource.exists())) {
jstType = CodeassistUtils.findNativeJstType(stName
.typeName());
} else {
final char[] contents = getContents(progressMonitor, moduleInfo);
processType(contents);
}
}
// parse source module after getting the JstType
//
SourceParserUtil.parseSourceModule(this, parser);
if (DLTKCore.DEBUG_PRINT_MODEL) {
System.out.println("Source Module Debug print:"); //$NON-NLS-1$
CorePrinter printer = new CorePrinter(System.out);
printNode(printer);
printer.flush();
}
// update timestamp (might be IResource.NULL_STAMP if original does
// not exist)
if (underlyingResource == null) {
underlyingResource = getResource();
}
// underlying resource is null in the case of a working copy out of
// workspace
if (underlyingResource != null) {
moduleInfo.setTimestamp(((IFile) underlyingResource)
.getModificationStamp());
}
isConsistent = true;
return moduleInfo.isStructureKnown();
} catch (CoreException e) {
throw new ModelException(e);
}
}
private char[] getContents(IProgressMonitor progressMonitor,
final JSSourceModuleElementInfo moduleInfo) throws ModelException {
IBuffer buffer = null;
// ensure buffer is opened
if (hasBuffer()) {
buffer = getBufferManager().getBuffer(this);
if (buffer == null) {
buffer = openBuffer(progressMonitor, moduleInfo);
}
}
final char[] contents = (buffer == null) ? null : buffer
.getCharacters();
return contents;
}
private boolean isVirtualTypeResource(IResource fileSystemLoc) {
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
IResource resource = root.findMember(fileSystemLoc.getFullPath());
if (resource != null) {
URI location = resource.getLocationURI();
if (location != null) {
if(location.getScheme().equals("typespace")){
return true;
}
}
}
return false;
}
@Override
public IModelElement[] getChildren(IProgressMonitor monitor)
throws ModelException {
return super.getChildren(monitor);
}
@Override
public IModelElement[] getChildren() throws ModelException {
// TODO Auto-generated method stub
return super.getChildren();
}
@Override
public boolean isConsistent() {
return super.isConsistent() && isConsistent;
}
private void processType(char[] contents) {
// fix bug 2206, add for findbugs NP warning, the contents might be
// null.
if (contents == null) {
return;
}
// String group = getGroupName();
SourceTypeName typeName = getTypeName();
String source = new String(contents);
typeName.setSource(source);
if (isConsistent) {
jstType = parseAndResolve(typeName);
} else {
jstType = mgr.findType(typeName);
if (jstType == null) {
jstType = parseAndResolve(typeName);
}
}
}
private IJstType parseAndResolve(SourceTypeName typeName) {
IJstType jstType = null;
try {
VjoParserToJstAndIType parser = new VjoParserToJstAndIType();
if(VjetPlugin.TRACE_PARSER){
System.out.println("parsing for " + getClass().getName());
}
IJstType scriptUnit = parser.parse(typeName.groupName(),
getTypeName().typeName(), typeName
.source());
if (scriptUnit != null) {
jstType = scriptUnit;
}
} catch (Exception e) {
DLTKCore.error(e.getMessage(), e);
}
return jstType;
}
public SourceTypeName getTypeName() {
IResource path = this.getResource();
return CodeassistUtils.getTypeName(path);
}
public String getGroupName() {
IResource path = this.getResource();
String group = path.getProject().getName();
return group;
}
protected IBuffer getBuffer(IProgressMonitor progressMonitor,
JSSourceModuleElementInfo moduleInfo) throws ModelException {
// get buffer contents
IBuffer buffer = getBufferManager().getBuffer(this);
if (buffer == null) {
buffer = openBuffer(progressMonitor, moduleInfo); // open
// buffer
// independently
// from the info, since we are building the info
}
return buffer;
}
private void check(IResource underlyingResource) throws CoreException,
ModelException {
// check if this source module can be opened
if (!isWorkingCopy()) // no check is done on root kind or
{
// exclusion
// pattern for working copies
IStatus status = validateSourceModule(underlyingResource);
if (!status.isOK()) {
throw newModelException(status);
}
}
// prevents reopening of non-primary working copies (they are closed
// when they are discarded and should not be reopened)
if (preventReopen()) {
// throw newNotPresentException();
}
}
@Override
public IType getType(String typeName) {
return new VjoSourceType(this, typeName);
}
public void loadTypesFinished() {
try {
final NullProgressMonitor monitor = new NullProgressMonitor();
isConsistent = false;
reconcile(true, null, monitor);
//added by huzhou@ebay.com
//this logic is to find the dependents types of the saving jst type
//and update their validations result accordingly
try {
if(jstType != null
&& jstType.getPackage() != null
&& jstType.getPackage().getGroupName() != null
&& jstType.getName() != null){
final List<IJstType> dependents = mgr.getTypeSpace().getAllDependents(new TypeName(jstType.getPackage().getGroupName(), jstType.getName()));
if(dependents != null){
final List<ISourceModule> selectedSourceModules = new LinkedList<ISourceModule>();
final StandardScriptBuilder scriptBuild = new StandardScriptBuilder();
final ScriptProject scriptProject = CodeassistUtils
.getScriptProject(jstType.getPackage().getGroupName());
VjoSourceHelper.getAllSourceModulesFromJst(selectedSourceModules, dependents, scriptProject);
if(selectedSourceModules.size() > 0){
scriptBuild.initialize(scriptProject);
scriptBuild.buildModelElements(scriptProject, selectedSourceModules,
new SubProgressMonitor(monitor, 1), 1);
}
}
}
} catch (Exception e) {
DLTKCore.error(e.toString(), e);
}
finally {
monitor.done();
}
} catch (CoreException e) {
DLTKCore.error(e.toString(), e);
}
}
public IJstType getJstType() {
if (jstType == null) {
jstType = mgr.getController().getJstTypeSpaceMgr()
.getQueryExecutor().findType(getTypeName());
}
return jstType;
}
public void refreshFinished(List<SourceTypeName> list) {
if (list.contains(getTypeName())) {
loadTypesFinished();
}
}
public boolean refreshSourceFields() throws ModelException {
if (jstType == null || !jstType.hasMixins()) { // only refresh types
// with mixins
return false;
}
ModelManager manager = ModelManager.getModelManager();
// mixin types maybe changed, refresh the member fields
try {
final String natureId = getNatureId();
final VjoSourceElementParser parser = (VjoSourceElementParser) getSourceElementParser(natureId);
HashMap newElements = new HashMap();
JSSourceModuleElementInfo info = (JSSourceModuleElementInfo) createElementInfo();
final VjoSourceModuleStructureRequestor requestor = new VjoSourceModuleStructureRequestor(
this, info, newElements);
if (!isReadOnly()) {
((ISourceElementParserExtension) parser).setScriptProject(this
.getScriptProject());
}
parser.setRequestor(requestor);
final AccumulatingProblemReporter problemReporter = getAccumulatingProblemReporter();
parser.setReporter(problemReporter);
SourceParserUtil.parseSourceModule(this, parser);
manager.putInfos(this, newElements);
return true;
} catch (CoreException e) {
throw new ModelException(e);
}
}
public void updateScriptUnit(final JstBlock block,
final List<JstBlock> blockList, final IJstType type,
final List<IScriptProblem> probs) {
// this.m_block = block;
// this.m_blockList = blockList;
this.jstType = type;
// this.m_probs = probs;
}
public IJstNode getNode(int startOffset) {
return JstUtil.getLeafNode(jstType, startOffset, startOffset);
}
// public JstBlock getSyntaxRoot() {
// return m_block;
// }
//
// public List<JstBlock> getJstBlockList() {
// return m_blockList;
// }
// public IJstType getType() {
// return jstType;
// }
// public List<IScriptProblem> getProblems() {
// return m_probs;
// }
// @Override
// public IUnitSource getUnitSource() {
// return m_unitSource ;
// }
//
// class VjoUnitSource implements IUnitSource {
//
// @Override
// public String getGroupName() {
// return VjoSourceModule.this.getGroupName();
// }
//
// @Override
// public String getSource() {
// return VjoSourceModule.this.getSourceContents();
// }
//
// @Override
// public String getUnitId() {
// return getUnitName() + "@" + getGroupName();
// }
//
// @Override
// public String getUnitName() {
// return VjoSourceModule.this.getElementName();
// }
//
// }
}