/*******************************************************************************
* 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.vjet.eclipse.core.builder;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.eclipse.core.internal.resources.ResourceException;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.dltk.mod.core.DLTKContentTypeManager;
import org.eclipse.dltk.mod.core.DLTKCore;
import org.eclipse.dltk.mod.core.IBuildpathEntry;
import org.eclipse.dltk.mod.core.IScriptProject;
import org.eclipse.dltk.mod.core.ISourceModule;
import org.eclipse.dltk.mod.core.ModelException;
import org.eclipse.dltk.mod.internal.core.Model;
import org.eclipse.dltk.mod.internal.core.ModelManager;
import org.eclipse.dltk.mod.internal.core.ScriptProject;
import org.eclipse.dltk.mod.internal.core.VjoSourceHelper;
import org.eclipse.dltk.mod.internal.core.builder.StandardScriptBuilder;
import org.eclipse.vjet.dsf.jsgen.shared.validation.vjo.VjoValidationDriver;
import org.eclipse.vjet.dsf.jsgen.shared.validation.vjo.VjoValidationResult;
import org.eclipse.vjet.dsf.jst.IJstType;
import org.eclipse.vjet.dsf.jst.declaration.JstType;
import org.eclipse.vjet.dsf.jst.ts.JstTypeSpaceMgr;
import org.eclipse.vjet.dsf.jstojava.mixer.TypeExtensionRegistry;
import org.eclipse.vjet.dsf.jstojava.resolver.FunctionMetaRegistry;
import org.eclipse.vjet.dsf.jstojava.resolver.TypeResolverRegistry;
import org.eclipse.vjet.dsf.ts.event.EventListenerStatus;
import org.eclipse.vjet.dsf.ts.event.ISourceEventCallback;
import org.eclipse.vjet.dsf.ts.event.dispatch.IEventListenerHandle;
import org.eclipse.vjet.dsf.ts.event.group.AddGroupDependencyEvent;
import org.eclipse.vjet.dsf.ts.event.group.AddGroupEvent;
import org.eclipse.vjet.dsf.ts.event.group.BatchGroupLoadingEvent;
import org.eclipse.vjet.dsf.ts.event.group.IGroupEventListener;
import org.eclipse.vjet.dsf.ts.event.group.RemoveGroupDependencyEvent;
import org.eclipse.vjet.dsf.ts.event.group.RemoveGroupEvent;
import org.eclipse.vjet.dsf.ts.event.type.AddTypeEvent;
import org.eclipse.vjet.dsf.ts.event.type.ITypeEventListener;
import org.eclipse.vjet.dsf.ts.event.type.ModifyTypeEvent;
import org.eclipse.vjet.dsf.ts.event.type.RemoveTypeEvent;
import org.eclipse.vjet.dsf.ts.event.type.RenameTypeEvent;
import org.eclipse.vjet.eclipse.codeassist.CodeassistUtils;
import org.eclipse.vjet.eclipse.core.PiggyBackClassPathUtil;
import org.eclipse.vjet.eclipse.core.VjetPlugin;
import org.eclipse.vjet.eclipse.core.VjoLanguageToolkit;
import org.eclipse.vjet.eclipse.core.ts.EclipseTypeLoadMonitor;
import org.eclipse.vjet.eclipse.core.ts.TypeSpaceTracer;
import org.eclipse.vjet.vjo.lib.TsLibLoader;
import org.eclipse.vjet.vjo.tool.typespace.GroupInfo;
import org.eclipse.vjet.vjo.tool.typespace.SourcePathInfo;
import org.eclipse.vjet.vjo.tool.typespace.SourceTypeName;
import org.eclipse.vjet.vjo.tool.typespace.TypeSpaceMgr;
public class TypeSpaceBuilder {
public TypeSpaceBuilder() {
}
public void buildProject(ScriptProject project, Map args,
IProgressMonitor monitor, List<String> groupDepends,
IBuildpathEntry bootstrapPath) {
// add group event
// String name = project.getProject().getName();
// File groupPath = project.getProject().getLocation().toFile();
// SourcePathInfo sourceInfo = PiggyBackClassPathUtil
// .getProjectSrcPath_DLTK(project);
// List<String> srcPaths = sourceInfo.getSourcePaths();
// TODO support library zip entries
// List<String> classPaths = new ArrayList<String>();
List<String> bootstrapDirs = new ArrayList<String>();
if (bootstrapPath != null) {
String portableString = "";
portableString = getRelativeProjectPath(project, bootstrapPath);
bootstrapDirs.add(portableString);
}
List<GroupInfo> info = new ArrayList<GroupInfo>();
processAddGroup(info, project.getProject());
TypeSpaceMgr mgr = TypeSpaceMgr.getInstance();
// // log list of groups being processed
TypeSpaceTracer.logLoadEvent(info);
mgr.load(new EclipseTypeLoadMonitor(monitor), info);
if (VjetPlugin.TRACE_TYPESPACE) {
System.out.println("project: " + project);
System.out.println("args: " + args);
System.out.println("monitor: " + monitor);
System.out.println("project buildpath: " + groupDepends);
System.out.println("bootstrapPath: " + bootstrapPath);
}
}
public void incrementalBuildProject(List<SourceTypeName> changedTypes) {
// IResourceDelta[] resourceDeltas = delta
// .getAffectedChildren();
// TypeSpaceMgr tsmgr = TypeSpaceMgr.getInstance();
// List<GroupInfo> info = new ArrayList<GroupInfo>();
// List<SourceTypeName> changedTypes = new ArrayList<SourceTypeName>();
//
// for (IResourceDelta resourceDelta : resourceDeltas) {
// IProject project = resourceDelta.getResource().getProject();
//
// if (!project.exists() || !project.isOpen()) {
// continue;
// }
//
// // process delta if project exist and type space loading is
// // finished else create add group event.
// if (tsmgr.existGroup(project.getName()) ) {
// changedTypes.addAll(processDelta(resourceDelta));
// } else if (tsmgr.isLoaded()) {
// // for (Object o :
// //
// m_tsmgr.getController().getJstTypeSpaceMgr().getTypeSpace().getGroups().keySet().toArray())
// // {
// // String s = (String)o;
// // if (!s.endsWith(".jar")) {
// // System.out.println(o);
// // }
// // }
// // updateGroupDepends();
// processAddGroup(info, project);
// }
//
// }
//
// // Calls group load job if group info list in not empty else call
// // refresh job for changes resources.
// if (!info.isEmpty()) {
//
// TypeSpaceGroupLoadJob groupLoadJob = new TypeSpaceGroupLoadJob(info);
// tsmgr.setLoaded(false);
// groupLoadJob.schedule();
if (!changedTypes.isEmpty()) {
TypeSpaceTracer.loadRefreshEvent(changedTypes);
for (SourceTypeName type : changedTypes) {
TypeSpaceMgr.doProcessType(type, null);
}
}
}
public static void processAddGroup(List<GroupInfo> info, IProject project) {
try {
IScriptProject scriptProject;
Model model = ModelManager.getModelManager().getModel();
scriptProject = model.getScriptProject(project.getName());
if (scriptProject.exists()) {
Map<String, List<String>> groups = new HashMap<String, List<String>>();
createDepends(groups, scriptProject);
populateGroupInfos(info, scriptProject, groups);
}
} catch (ModelException e) {
DLTKCore.error(e.getMessage(), e);
}
}
private static IBuildpathEntry[] createDepends(
Map<String, List<String>> groups, IScriptProject project)
throws ModelException {
List<String> list = getDependsProjects(groups, project.getElementName());
IBuildpathEntry[] entries = TypeSpaceBuilder.getSerFileGroupDepends(
project, list);
groups.put(project.getElementName(), list);
return entries;
}
private static List<String> getDependsProjects(
Map<String, List<String>> groups, String group) {
List<String> list = groups.get(group);
if (list == null) {
list = new ArrayList<String>();
groups.put(group, list);
}
return list;
}
private List<SourceTypeName> loadFile(IResourceDelta delta,
IResource resource) {
IFile file = (IFile) resource;
SourceTypeName name = null;
if (isValidFile(file)) {
return loadVjoFile(delta, file);
}
return null;
}
private boolean isValidFile(IFile file) {
return isValidName(file)
&& PiggyBackClassPathUtil.isInSourceFolder(file);
}
private boolean isValidName(IFile file) {
boolean isValid = false;
try {
isValid = DLTKContentTypeManager.isValidFileNameForContentType(
VjoLanguageToolkit.getDefault(), file.getLocation());
} catch (Exception e) {
DLTKCore.error(e.getMessage(), e);
}
return isValid;
}
private SourceTypeName createSourceTypeName(IFile file) {
byte[] content = SourceTypeName.EMPTY_CONTENT;
content = getFileContent(file);
return createSourceTypeName(file, content);
}
private byte[] getFileContent(IFile file) {
byte[] bs = SourceTypeName.EMPTY_CONTENT;
try {
bs = doGetFileContent(file);
} catch (IOException e) {
logError(e);
} catch (ResourceException e) {
refresh(file);
try {
bs = doGetFileContent(file);
} catch (Exception e1) {
logError(e1);
}
} catch (CoreException e) {
logError(e);
}
return bs;
}
/**
* Refresh file from the disk to workspace.
*
* @param file
* {@link IFile} object.
*/
private void refresh(IFile file) {
try {
file.refreshLocal(IResource.DEPTH_INFINITE, null);
} catch (CoreException e) {
DLTKCore.error(e.toString(), e);
}
}
private void logError(Exception e1) {
DLTKCore.error(e1.getMessage(), e1);
}
/**
* Read content of the {@link IFile} object to the bytes array.
*
* @param file
* {@link IFile}
* @return file content in bytes array.
* @throws CoreException
* @throws IOException
*/
private byte[] doGetFileContent(IFile file) throws CoreException,
IOException {
InputStream stream = file.getContents();
int available = stream.available();
byte[] bs = new byte[available];
stream.read(bs);
stream.close();
return bs;
}
private SourceTypeName createSourceTypeName(IFile file, byte[] bs) {
String group = file.getProject().getName();
String source = new String(bs);
String name = CodeassistUtils.getClassName(file);
// SourceTypeName typeName = new SourceTypeName(group,
// file.getRawLocation().toPortableString(), source);
SourceTypeName typeName = new SourceTypeName(group, name, source);
return typeName;
}
/**
* Create for {@link File} object corresponding {@link SourceTypeName}
* object and adding to the inner list of changed types.
*
* @param delta
* {@link IResourceDelta} object
* @param file
* {@link File} object.
*/
private List<SourceTypeName> loadVjoFile(IResourceDelta delta, IFile file) {
SourceTypeName name;
List<SourceTypeName> changedTypes = new ArrayList<SourceTypeName>();
TypeSpaceMgr tsmgr = TypeSpaceMgr.getInstance();
if (file.exists()) {
name = createSourceTypeName(file);
} else {
name = createSourceTypeName(file, SourceTypeName.EMPTY_CONTENT);
}
String typeName = CodeassistUtils.getClassName(file);
switch (delta.getKind()) {
case IResourceDelta.ADDED:
if (!tsmgr.existType(file.getProject().getName(), typeName)) {
name.setAction(SourceTypeName.ADDED);
changedTypes.add(name);
if (file.exists()) {
tsmgr.getController().parseAndResolve(name.groupName(),
file.getLocation().toFile());
}
}
break;
case IResourceDelta.CHANGED:
if (tsmgr.existType(file.getProject().getName(), typeName)) {
name.setAction(SourceTypeName.CHANGED);
changedTypes.add(name);
}
break;
case IResourceDelta.REMOVED:
if (tsmgr.existType(file.getProject().getName(), typeName)) {
name.setAction(SourceTypeName.REMOVED);
changedTypes.add(name);
}
break;
default:
break;
}
return changedTypes;
// return !(delta.getKind() == IResourceDelta.ADDED &&
// m_tsmgr.existType(file.getProject().getName(), typeName));
}
private List<SourceTypeName> processDelta(IResourceDelta delta) {
IResource resource = delta.getResource();
// fix typespace not updated after refactor finished
List<SourceTypeName> changedTypes = new ArrayList<SourceTypeName>();
if (resource instanceof IFile) {
switch (delta.getKind()) {
case IResourceDelta.CHANGED:
if ((delta.getFlags() & ~(IResourceDelta.SYNC | IResourceDelta.MARKERS)) != 0) {
changedTypes.addAll(loadFile(delta, resource));
}
break;
case IResourceDelta.ADDED:
changedTypes.addAll(loadFile(delta, resource));
break;
case IResourceDelta.REMOVED:
changedTypes.addAll(loadFile(delta, resource));
break;
default:
break;
}
} else if (PiggyBackClassPathUtil.isInSourceFolder(resource)
|| resource instanceof IProject) {
IResourceDelta[] deltas = delta.getAffectedChildren();
for (IResourceDelta resourceDelta : deltas) {
changedTypes.addAll(processDelta(resourceDelta));
}
}
return changedTypes;
}
private static void populateGroupInfos(final List<GroupInfo> info,
final IScriptProject project,
final Map<String, List<String>> groupDependency)
throws ModelException {
// initialize dltk build path
if (!PiggyBackClassPathUtil
.ifScriptProjectInitializedFromJavaProject(project)) {
PiggyBackClassPathUtil
.initializeScriptProjectFromJavProject(project);
}
// initialize dependant jars
List<String> classPaths = new ArrayList<String>();
List<URL> urls = PiggyBackClassPathUtil
.getProjectDependantJars_DLTK(project);
List<String> groupDepends = new ArrayList<String>();
TypeSpaceBuilder.getSerFileGroupDepends(project, groupDepends);
IBuildpathEntry bootstrapPath = TypeSpaceBuilder
.getBootstrapDir(project);
for (URL u : urls) {
java.io.File file = new java.io.File(u.getFile());
String fileName = file.getName();
// Skip the file which has been calculated into type space
if (TypeSpaceMgr.getInstance().existGroup(fileName)) {
continue;
}
// Check if the jar has been added into list
if (!classPaths.contains(fileName)) {
SourcePathInfo srcPathInfo = new SourcePathInfo();
srcPathInfo.addSourcePath(file.getPath());
GroupInfo groupInfo = new GroupInfo(file.getName(),
file.getAbsolutePath(), srcPathInfo, null,
groupDependency.get(file.getName()));
groupInfo.setLibrary(true);
info.add(groupInfo);
classPaths.add(fileName);
System.out.println("ScriptProject<" + project.getElementName()
+ "> depends on :" + u);
}
}
// initialize src path
SourcePathInfo sourcePathInfo = PiggyBackClassPathUtil
.getProjectSrcPath_DLTK(project);
List<String> srcPaths = sourcePathInfo.getSourcePaths();
sourcePathInfo.setSourcePaths(srcPaths);
String name = project.getProject().getName();
java.io.File groupPath = project.getProject().getLocation().toFile();
List<String> bootstrapDirs = new ArrayList<String>();
if (bootstrapPath != null) {
String portableString = "";
portableString = getRelativeProjectPath(project, bootstrapPath);
bootstrapDirs.add(portableString);
}
info.add(new GroupInfo(name, groupPath.getAbsolutePath(),
sourcePathInfo, classPaths, groupDependency.get(name),
bootstrapDirs));
}
private static String getRelativeProjectPath(IScriptProject project,
IBuildpathEntry bootstrap) {
String name = project.getElementName();
String bootstrapPath = bootstrap.getPath().toPortableString();
if (bootstrapPath.lastIndexOf(name) != -1) {
if (bootstrapPath.equals(name)) {
bootstrapPath = "";
} else {
bootstrapPath = bootstrapPath.substring(bootstrapPath
.indexOf(name) + name.length());
}
}
return bootstrapPath;
}
public static IBuildpathEntry getBootstrapDir(IScriptProject project)
throws ModelException {
IBuildpathEntry[] entries = project.getRawBuildpath();
for (IBuildpathEntry entry : entries) {
if (entry.getEntryKind() == IBuildpathEntry.BPE_BOOTSTRAP) {
return entry;
}
}
return null;
}
public static IBuildpathEntry[] getSerFileGroupDepends(
IScriptProject project, List<String> list) throws ModelException {
IBuildpathEntry[] entries = project.getRawBuildpath();
for (IBuildpathEntry entry : entries) {
// process only project entries
if (entry.getEntryKind() == IBuildpathEntry.BPE_PROJECT) {
// add first segment of the project entry - project name.
list.add(entry.getPath().segment(0));
// add transitive project dependencies
getSerFileGroupDepends(CodeassistUtils.getScriptProject(entry
.getPath().segment(0)), list);
} else if (entry.getEntryKind() == IBuildpathEntry.BPE_LIBRARY) {
String id = entry.getPath().segment(
entry.getPath().segmentCount() - 1);
list.add(id);
} else if (entry.getEntryKind() == IBuildpathEntry.BPE_CONTAINER) {
String id = entry.getPath().segment(0);
if (VjetPlugin.VJETTL_ID.equals(id)) {
// add built in libs
list.add(entry.getPath().lastSegment());
}
if (VjetPlugin.VJOLIB_ID.equals(id)) {
// add built in libs
String[] defaultLibs = TsLibLoader.getVjoGroups();
for (int i = 0; i < defaultLibs.length; i++) {
list.add(defaultLibs[i]);
}
}
if (VjetPlugin.BROWSERSDK_ID.equals(id)) {
// add built in libs
String[] defaultLibs = TsLibLoader.getBrowserGroups();
for (int i = 0; i < defaultLibs.length; i++) {
list.add(defaultLibs[i]);
}
}
if (VjetPlugin.JSNATIVESDK_ID.equals(id)) {
// add built in libs
String[] defaultLibs = TsLibLoader.getJsNativeGroups();
for (int i = 0; i < defaultLibs.length; i++) {
list.add(defaultLibs[i]);
}
}
if (VjetPlugin.SDK_CONTAINER.equals(id)) {
// add built in libs
String[] defaultLibs = TsLibLoader.getDefaultLibNames();
for (int i = 0; i < defaultLibs.length; i++) {
list.add(defaultLibs[i]);
}
}
}
}
return entries;
}
public static void addGroupTraceEventListeners(JstTypeSpaceMgr jstTypeSpace) {
jstTypeSpace
.registerSourceEventListener(new IGroupEventListener<IJstType>() {
@Override
public EventListenerStatus<IJstType> onBatchGroupLoaded(
BatchGroupLoadingEvent event,
IEventListenerHandle handle,
ISourceEventCallback callBack) {
System.out.println("on batch group add dependendency");
TypeSpaceTracer.onBatchLoaded(event);
return null;
}
@Override
public EventListenerStatus onGroupAddDependency(
AddGroupDependencyEvent event,
IEventListenerHandle handle,
ISourceEventCallback callBack) {
// TODO Auto-generated method stub
System.out.println("onGroupAddDependency for group:"
+ event.getGroupName());
System.out.println("\tgroup path: "
+ event.getGroupPath());
System.out.println("\tdependency list: "
+ event.getDependencyList());
return null;
}
@Override
public EventListenerStatus onGroupAdded(
AddGroupEvent event, IEventListenerHandle handle,
ISourceEventCallback callBack) {
// TODO Auto-generated method stub
System.out.println("on group added");
System.out.println("bootstrap paths:"
+ event.getBootStrapList());
System.out.println(event);
return null;
}
@Override
public EventListenerStatus onGroupRemoveDependency(
RemoveGroupDependencyEvent event,
IEventListenerHandle handle,
ISourceEventCallback callBack) {
System.out.println("on group remove dependency");
System.out.println(event);
return null;
}
@Override
public void onGroupRemoved(RemoveGroupEvent event) {
// TODO Auto-generated method stub
System.out.println("on group removed");
System.out.println(event);
}
});
}
public static void addGroupEventListeners(JstTypeSpaceMgr jstTypeSpaceMgr) {
jstTypeSpaceMgr
.registerSourceEventListener((new ITypeEventListener<JstType>() {
@Override
public EventListenerStatus<JstType> onTypeAdded(
AddTypeEvent<JstType> event,
IEventListenerHandle handle,
ISourceEventCallback<JstType> callBack) {
// TODO Auto-generated method stub
return null;
}
@Override
public EventListenerStatus<JstType> onTypeRenamed(
RenameTypeEvent event, IEventListenerHandle handle,
ISourceEventCallback<JstType> callBack) {
// TODO Auto-generated method stub
return null;
}
@Override
public EventListenerStatus<JstType> onTypeModified(
ModifyTypeEvent event, IEventListenerHandle handle,
ISourceEventCallback<JstType> callBack) {
// TODO Auto-generated method stub
// revalidate type now
// String filename = event.getFileName();
TypeSpaceMgr ts = TypeSpaceMgr.getInstance();
// IJstType type = ts.findType(event.getTypeName());
// need to revalidate type -- issue is with script unit
// block validtion removal.
// validte type and update markers
// we need to figure out if we should remove the idea of
// script unit
// since it is no longer helpful in this case
IJstType type = ts.findType(event.getTypeName());
if(type==null){
return null;
}
buildType(type);
List<IJstType> dependents = ts.getTypeSpace()
.getAllDependents(event.getTypeName());
if (dependents != null) {
for (IJstType jstType : dependents) {
buildType(jstType);
}
}
// how to get vjosource module?
// IProblemReporter reporter =
// module.getProblemReporter();
// ProblemUtility.reportProblems(result.getAllProblems());
// for (IProblem problem : ) {
// reporter.reportProblem(problem);
// }
return null;
}
private void buildType(IJstType jstType) {
final List<ISourceModule> selectedSourceModules = new LinkedList<ISourceModule>();
final StandardScriptBuilder scriptBuild = new StandardScriptBuilder();
final ScriptProject scriptProject = CodeassistUtils
.getScriptProject(jstType.getPackage()
.getGroupName());
List<IJstType> dependant = new ArrayList<IJstType>();
dependant.add(jstType);
VjoSourceHelper.getAllSourceModulesFromJst(
selectedSourceModules, dependant,
scriptProject);
if (selectedSourceModules.size() > 0) {
scriptBuild.initialize(scriptProject);
scriptBuild.buildModelElements(
scriptProject,
selectedSourceModules,
new NullProgressMonitor(), 1);
}
}
@Override
public EventListenerStatus<JstType> onTypeRemoved(
RemoveTypeEvent event, IEventListenerHandle handle,
ISourceEventCallback<JstType> callBack) {
// TODO Auto-generated method stub
return null;
}
}));
jstTypeSpaceMgr
.registerSourceEventListener(new IGroupEventListener<JstType>() {
@Override
public EventListenerStatus<JstType> onBatchGroupLoaded(
BatchGroupLoadingEvent event,
IEventListenerHandle handle,
ISourceEventCallback<JstType> callBack) {
// TODO Auto-generated method stub
return null;
}
@Override
public EventListenerStatus<JstType> onGroupAddDependency(
AddGroupDependencyEvent event,
IEventListenerHandle handle,
ISourceEventCallback<JstType> callBack) {
// TODO Auto-generated method stub
return null;
}
@Override
public EventListenerStatus<JstType> onGroupAdded(
AddGroupEvent event, IEventListenerHandle handle,
ISourceEventCallback<JstType> callBack) {
// TODO Auto-generated method stub
return null;
}
@Override
public EventListenerStatus<JstType> onGroupRemoveDependency(
RemoveGroupDependencyEvent event,
IEventListenerHandle handle,
ISourceEventCallback<JstType> callBack) {
// TODO Auto-generated method stub
return null;
}
@Override
public void onGroupRemoved(RemoveGroupEvent event) {
// remove the bootstrap entries for the group
String groupId = event.getGroupName();
TypeResolverRegistry.getInstance().clear(groupId);
TypeExtensionRegistry.getInstance().clear(groupId);
FunctionMetaRegistry.getInstance().clear(groupId);
}
});
}
}