/******************************************************************************* * Copyright (c) 2009 Hallvard Traetteberg. * 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: * Hallvard Traetteberg - initial API and implementation ******************************************************************************/ package org.eclipse.e4.tm.ui.builders; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceDelta; import org.eclipse.core.resources.IResourceDeltaVisitor; import org.eclipse.core.resources.IResourceVisitor; import org.eclipse.core.resources.IncrementalProjectBuilder; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.js4emf.ecore.JavascriptSupport; import org.eclipse.emf.js4emf.ecore.ScriptClassLoader; import org.mozilla.javascript.CompilerEnvirons; import org.mozilla.javascript.optimizer.ClassCompiler; public class JavascriptBuilder extends IncrementalProjectBuilder { public final static String BUILDER_NAME = "JavascriptBuilder"; private List<IProject> dependentProjects = new ArrayList<IProject>(); protected IProject[] build(int kind, Map args, IProgressMonitor monitor) throws CoreException { dependentProjects.clear(); if (kind == IncrementalProjectBuilder.FULL_BUILD) { fullBuild(monitor); } else if (kind == IncrementalProjectBuilder.INCREMENTAL_BUILD || kind == IncrementalProjectBuilder.AUTO_BUILD) { IResourceDelta delta = getDelta(getProject()); if (delta == null) { fullBuild(monitor); } else { incrementalBuild(delta, monitor); } } return (IProject[])dependentProjects.toArray(new IProject[dependentProjects.size()]); } protected void clean(IProgressMonitor monitor) { try { super.clean(monitor); getProject().accept(cleanVisitor); } catch (CoreException e) { } } private void fullBuild(IProgressMonitor monitor) { try { getProject().accept(buildVisitor); } catch (CoreException e) { } } private IResourceVisitor buildVisitor = new IResourceVisitor() { public boolean visit(IResource resource) throws CoreException { if (resource instanceof IContainer) { return true; } else if (resource instanceof IFile && changeShouldTriggerBuild((IFile)resource)) { build((IFile)resource); } return false; } }; private IResourceVisitor cleanVisitor = new IResourceVisitor() { public boolean visit(IResource resource) throws CoreException { if (resource instanceof IContainer) { return true; } else if (resource instanceof IFile) { clean((IFile)resource); } return false; } }; protected boolean changeShouldTriggerBuild(IFile file) { return JavascriptSupport.JAVASCRIPT_EXTENSION.equals(file.getFileExtension()); } protected void incrementalBuild(IResourceDelta delta, IProgressMonitor monitor) throws CoreException { delta.accept(buildDeltaVisitor); } private IResourceDeltaVisitor buildDeltaVisitor = new IResourceDeltaVisitor() { public boolean visit(IResourceDelta delta) throws CoreException { int kind = delta.getKind(); if (kind == IResourceDelta.CHANGED || kind == IResourceDelta.ADDED) { return buildVisitor.visit(delta.getResource()); } return false; } }; protected void startupOnInitialize() { super.startupOnInitialize(); } // private CompilerEnvirons compilerEnvironment = new CompilerEnvirons(); private ClassCompiler compiler = new ClassCompiler(compilerEnvironment); private void clean(IFile file) throws CoreException { if (changeShouldTriggerBuild(file)) { file.deleteMarkers(IMarker.PROBLEM, true, IResource.DEPTH_ZERO); } else if ("class".equals(file.getFileExtension())) { String name = file.getName(); if (ScriptClassLoader.hasUriClassNameMarker(name.substring(0, name.lastIndexOf('.')))) { try { file.delete(true, null); } catch (CoreException e1) { } } } } // private IFile getClassFile(IFile jsFile) { // String classFileName = ScriptClassLoader.getUriClassName(URI.createPlatformResourceURI(jsFile.getFullPath().toString(), true)); // int pos = classFileName.lastIndexOf('.'); // if (pos >= 0) { // classFileName = classFileName.substring(pos + 1); // } // return jsFile.getParent().getFile(new Path(classFileName + ".class")); // } protected void build(IFile jsFile) { String fileName = jsFile.getName(); StringBuilder stringBuilder = new StringBuilder(); Object[] compiled = null; try { jsFile.deleteMarkers(IMarker.PROBLEM, true, IResource.DEPTH_ZERO); } catch (CoreException e1) { } String fullClassName = ScriptClassLoader.getUriClassName(URI.createPlatformResourceURI(jsFile.getFullPath().toString(), true)); try { BufferedReader reader = new BufferedReader(new InputStreamReader(jsFile.getContents())); String line = null; while (reader.ready() && (line = reader.readLine()) != null) { stringBuilder.append(line); stringBuilder.append("\n"); } compiled = compiler.compileToClassFiles(stringBuilder.toString(), fileName, 1, fullClassName); } catch (Exception e) { createMarker(jsFile, null, e.getMessage(), IMarker.SEVERITY_ERROR); return; } int pos = fullClassName.lastIndexOf('.'); String packageName = (pos > 0 ? fullClassName.substring(0, pos + 1) : ""); for (int i = 0; i < compiled.length; i += 2) { String className = (String)compiled[i]; String classFileName = (className.startsWith(packageName) ? className.substring(packageName.length()) : className); IFile classFile = jsFile.getParent().getFile(new Path(classFileName + ".class")); byte[] bytes = (byte[])compiled[i + 1]; try { if (! classFile.exists()) { classFile.create(new ByteArrayInputStream(bytes), true, null); } else { classFile.setContents(new ByteArrayInputStream(bytes), true, true, null); } } catch (CoreException e) { createMarker(jsFile, null, e.getMessage(), IMarker.SEVERITY_ERROR); } } } // public static IMarker createMarker(IResource resource, String problemType, String message, int severity) { IMarker marker = null; try { marker = resource.createMarker(IMarker.PROBLEM); marker.setAttribute(IMarker.MESSAGE, message); marker.setAttribute(IMarker.SEVERITY, severity); int priority = IMarker.PRIORITY_NORMAL; if (severity == IMarker.SEVERITY_INFO) { priority = IMarker.PRIORITY_LOW; } else if (severity == IMarker.SEVERITY_ERROR) { priority = IMarker.PRIORITY_HIGH; } marker.setAttribute(IMarker.PRIORITY, priority); } catch (CoreException e) { } return marker; } }