blob: 4a0f351562de67095d760d09be46a4cfa2d36dc2 [file] [log] [blame]
/**
* Copyright (c) 2002-2006 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 - Initial API and implementation
*/
package org.eclipse.emf.codegen.jet;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.StringTokenizer;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.emf.codegen.CodeGenPlugin;
import org.eclipse.emf.common.CommonPlugin;
import org.eclipse.emf.common.util.BasicMonitor;
import org.eclipse.emf.common.util.DiagnosticException;
import org.eclipse.emf.common.util.URI;
public class JETCompileTemplateOperation implements IWorkspaceRunnable
{
protected static final String JET_EXTENSION = "jet";
protected IProject project;
protected Collection<?> containers;
protected List<Object> files = new ArrayList<Object>();
protected boolean inBuild;
/**
* Creates an instance given the collection of resources.
*/
public JETCompileTemplateOperation(IProject project, Collection<?> containers) throws CoreException
{
this.project = project;
this.containers = containers;
for (Object container : containers)
{
if (container instanceof IContainer)
{
consider((IContainer)container);
}
else
{
consider(container.toString());
}
}
}
/**
* Creates an instance given the collection of resources.
*/
public JETCompileTemplateOperation(IProject project, Collection<?> containers, Collection<?> resources) throws CoreException
{
super();
this.project = project;
this.containers = containers;
for (Object object : resources)
{
if (object instanceof IFile)
{
IFile file = (IFile)object;
for (IContainer container = file.getParent(); container != null; container = container.getParent())
{
if (containers.contains(container))
{
consider(file);
break;
}
}
}
else if (object instanceof IContainer)
{
for (IContainer container = (IContainer)object; container != null; container = container.getParent())
{
if (containers.contains(container))
{
consider(container);
break;
}
}
}
}
}
/**
* Returns true if there are files to compile.
*/
public boolean shouldCompile()
{
return !files.isEmpty();
}
/**
* Adds the URI.
*/
protected void consider(String uri)
{
URI baseURI = URI.createURI(uri);
URI localURI = CommonPlugin.asLocalURI(baseURI);
if (localURI.isFile() && !localURI.isRelative())
{
File file = new File(localURI.toFileString());
if (file.isDirectory() && !uri.endsWith("/"))
{
baseURI = URI.createURI(uri + "/");
}
consider(baseURI, localURI, new File(localURI.toFileString()));
}
}
protected void consider(URI baseURI, URI localURI, File file)
{
if (file.isDirectory())
{
File [] files = file.listFiles();
for (int i = 0; i < files.length; ++i)
{
consider(baseURI, localURI, files[i]);
}
}
else if (file.isFile() && file.getName().endsWith(JET_EXTENSION) && file.getName().indexOf('.') != -1)
{
files.add(URI.createFileURI(file.getAbsolutePath()).deresolve(localURI).resolve(baseURI));
}
}
/**
* Adds the file to {@link #files} the file ends with the {@link #JET_EXTENSION} extension.
*/
protected void consider(IFile file)
{
if (file.getFileExtension() != null && file.getFileExtension().endsWith(JET_EXTENSION))
{
files.add(file);
}
}
/**
* Considers all the files of a container and all its subcontainer.
*/
protected void consider(IContainer container) throws CoreException
{
IResource[] children = container.members();
if (children != null)
{
for (int i = 0; i < children.length; ++i)
{
IResource resource = children[i];
if (resource instanceof IFile)
{
consider((IFile)resource);
}
else if (resource instanceof IContainer)
{
consider((IContainer)resource);
}
}
}
}
/**
*/
public void run(IProgressMonitor progressMonitor) throws CoreException
{
try
{
progressMonitor.beginTask("", 3 * files.size());
progressMonitor.subTask(CodeGenPlugin.getPlugin().getString("_UI_JETCompilingTemplates_message"));
IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
Collection<IProject> jetProjects = new HashSet<IProject>();
HashSet<String> visitedRelativePaths = new HashSet<String>();
for (Object file : files)
{
String fileName = file instanceof IFile ? ((IFile)file).getName() : file.toString();
progressMonitor.subTask(CodeGenPlugin.getPlugin().getString("_UI_JETCompile_message", new Object [] { fileName }));
JETNature nature = JETNature.getRuntime(project);
IContainer directory = nature.getJavaSourceContainer();
if(!directory.exists())
{
project.getFolder(directory.getProjectRelativePath()).create(true, true, BasicMonitor.subProgress(progressMonitor, 1));
}
IPath filePath = file instanceof IFile ? ((IFile)file).getFullPath() : new Path(file.toString());
List<Object> templateContainers = nature.getTemplateContainers();
List<Object> templateSourceContainers = nature.getTemplateSourceContainers();
String [] containerLocations = new String [templateContainers.size()];
for (ListIterator<Object> j = templateContainers.listIterator(); j.hasNext(); )
{
Object container = j.next();
if (container instanceof IContainer)
{
containerLocations[j.previousIndex()] = URI.createPlatformResourceURI(((IContainer)container).getFullPath().toString(), true).toString();
}
else
{
containerLocations[j.previousIndex()] = container.toString();
}
}
for (Object container : templateSourceContainers)
{
IPath containerPath = container instanceof IContainer ? ((IContainer)container).getFullPath() : new Path(container.toString());
if (containerPath.isPrefixOf(filePath))
{
String relativePath = filePath.removeFirstSegments(containerPath.segmentCount()).setDevice(null).toString();
if (visitedRelativePaths.add(relativePath))
{
JETCompiler compiler = new JETCompiler(containerLocations, relativePath);
compiler.parse();
StringWriter stringWriter = new StringWriter();
compiler.generate(stringWriter);
JETSkeleton skeleton = compiler.getSkeleton();
if (skeleton.getClassName().equals(""))
{
skeleton.setClassName(fileName.substring(0, fileName.indexOf('.')));
}
if (skeleton.getPackageName() != null)
{
directory = getPackageContainer(directory, skeleton.getPackageName(), BasicMonitor.subProgress(progressMonitor, 1));
}
else
{
progressMonitor.worked(1);
}
IFile outputFile =
workspaceRoot.getFile(directory.getFullPath().append(skeleton.getClassName() + ".java"));
progressMonitor.subTask(CodeGenPlugin.getPlugin().getString("_UI_JETUpdate_message", new Object [] { fileName }));
String encoding = outputFile.getCharset();
String result = stringWriter.getBuffer().toString();
byte [] bytes;
try
{
bytes = encoding == null ? result.getBytes() : result.getBytes(encoding);
}
catch (UnsupportedEncodingException exception)
{
bytes = result.getBytes();
}
if (!outputFile.exists())
{
outputFile.create(new ByteArrayInputStream(bytes), true, progressMonitor);
}
else
{
boolean changed = true;
try
{
InputStream inputStream = outputFile.getContents();
byte [] oldBytes = new byte[inputStream.available()];
inputStream.read(oldBytes);
inputStream.close();
changed = !Arrays.equals(oldBytes, bytes);
}
catch (IOException exception)
{
// Ignore
}
if (changed)
{
if (outputFile.isReadOnly())
{
// This call should get the files checked out from version control if the project is a 'team' project.
//
IStatus status = ResourcesPlugin.getWorkspace().validateEdit(new IFile [] { outputFile }, null);
if (!status.isOK())
{
throw new CoreException(status);
}
}
outputFile.setContents(new ByteArrayInputStream(bytes), true, true, progressMonitor);
}
}
jetProjects.add(outputFile.getProject());
progressMonitor.worked(1);
break;
}
}
}
}
// Kick of a Java build if not already in a build.
//
if (!isInBuild())
{
for (IProject project : jetProjects)
{
progressMonitor.subTask
(CodeGenPlugin.getPlugin().getString("_UI_JETJavaCompileProject_message", new Object [] { project.getFullPath() }));
project.build(IncrementalProjectBuilder.INCREMENTAL_BUILD, BasicMonitor.subProgress(progressMonitor, 1));
}
}
}
catch (JETException exception)
{
throw DiagnosticException.toCoreException(exception);
}
finally
{
progressMonitor.done();
}
}
protected IContainer getPackageContainer(IContainer root, String packagename, IProgressMonitor monitor) throws CoreException
{
for (StringTokenizer stringTokenizer = new StringTokenizer(packagename, "."); stringTokenizer.hasMoreTokens(); )
{
IFolder newContainer = root.getFolder(new Path(stringTokenizer.nextToken()));
if (!newContainer.exists())
{
newContainer.create(true, true, monitor);
}
root = newContainer;
}
return root;
}
public boolean isInBuild()
{
return inBuild;
}
public void setInBuild(boolean build)
{
inBuild = build;
}
}