package org.archstudio.dblgen.builder;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.ParserConfigurationException;
import org.archstudio.dblgen.DataBindingGenerationStatus;
import org.archstudio.dblgen.DataBindingGeneratorImpl;
import org.archstudio.dblgen.core.Activator;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
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.IncrementalProjectBuilder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.util.BasicMonitor;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.URIConverter;
import org.eclipse.pde.core.plugin.IExtensions;
import org.eclipse.pde.core.plugin.IPluginElement;
import org.eclipse.pde.core.plugin.IPluginExtension;
import org.eclipse.pde.core.plugin.IPluginModelBase;
import org.eclipse.pde.core.plugin.IPluginObject;
import org.eclipse.pde.core.plugin.PluginRegistry;
import org.osgi.framework.BundleException;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
import com.google.common.base.Preconditions;
import com.google.common.collect.Iterables;
public class Xadl3SchemaBuilder extends IncrementalProjectBuilder {
public static final String BUILDER_ID = "org.archstudio.dblgen.xadl3SchemaBuilder";
/*
* This ID has to match one in the plugin.xml file for this to work, and for these to show up in the problems view,
* the marker type has to have the Problem marker type set as a 'super' in its attributes.
*/
public static final String MARKER_TYPE = "org.archstudio.dblgen.xadl3SchemaBuilderProblem";
protected final DataBindingGeneratorImpl dbGenerator;
public Xadl3SchemaBuilder()
throws ParserConfigurationException, SAXException, IOException, CoreException, BundleException {
this.dbGenerator = new DataBindingGeneratorImpl();
}
private void addMarker(IFile file, String message, int lineNumber, int severity) {
try {
IMarker marker = file.createMarker(MARKER_TYPE);
marker.setAttribute(IMarker.MESSAGE, message);
marker.setAttribute(IMarker.SEVERITY, severity);
if (lineNumber == -1) {
lineNumber = 1;
}
marker.setAttribute(IMarker.LINE_NUMBER, lineNumber);
}
catch (CoreException e) {
}
}
private void deleteMarkers(IFile file) {
try {
file.deleteMarkers(MARKER_TYPE, false, IResource.DEPTH_ZERO);
}
catch (CoreException ce) {
}
}
private void deleteMarkers(IProject project) {
try {
project.deleteMarkers(MARKER_TYPE, false, IResource.DEPTH_ZERO);
}
catch (CoreException ce) {
}
}
@Override
protected IProject[] build(int kind, @SuppressWarnings("rawtypes") Map args, IProgressMonitor monitor)
throws CoreException {
try {
if (kind == FULL_BUILD) {
fullBuild(monitor);
}
else {
IResourceDelta delta = getDelta(getProject());
if (delta == null) {
fullBuild(monitor);
}
else {
incrementalBuild(delta, monitor);
}
}
getProject().refreshLocal(IResource.DEPTH_INFINITE, monitor);
}
catch (IOException e) {
throw new CoreException(new Status(IStatus.ERROR, Activator.getSingleton().getId(), e.getMessage(), e));
}
return null;
}
private class Xadl3ResourceDeltaVisitor implements IResourceDeltaVisitor {
public boolean projectNeedsRebuild = false;
protected final IFolder modelFolder;
protected final IFile pluginFile;
public Xadl3ResourceDeltaVisitor(IProject project) {
modelFolder = getProject().getFolder("model");
pluginFile = getProject().getFile("plugin.xml");
}
@Override
public boolean visit(IResourceDelta delta) {
if (modelFolder != null) {
IResource res = delta.getResource();
IContainer parent = res.getParent();
while (parent != null) {
if (parent.equals(modelFolder)) {
projectNeedsRebuild = true;
return false;
}
parent = parent.getParent();
}
}
if (pluginFile != null) {
if (pluginFile.equals(delta.getResource())) {
projectNeedsRebuild = true;
return false;
}
}
return true; // visit the children
}
}
private void incrementalBuild(IResourceDelta delta, IProgressMonitor monitor) throws IOException, CoreException {
/*
* See if anything in the model directory changed that would require a rebuild. If so, do a full build.
*/
Xadl3ResourceDeltaVisitor visitor = new Xadl3ResourceDeltaVisitor(getProject());
delta.accept(visitor);
if (visitor.projectNeedsRebuild) {
fullBuild(monitor);
}
}
private List<IFile> getFileChildren(IContainer container) throws CoreException {
IResource[] resources = container.members(IResource.FILE);
List<IFile> files = new ArrayList<IFile>();
for (IResource resource : resources) {
if (resource instanceof IFile) {
files.add((IFile) resource);
}
}
return files;
}
private List<IFolder> getFolderChildren(IContainer container) throws CoreException {
List<IFolder> folders = new ArrayList<IFolder>();
if (container.exists()) {
IResource[] resources = container.members(IResource.FOLDER);
for (IResource resource : resources) {
if (resource instanceof IFolder) {
folders.add((IFolder) resource);
}
}
}
return folders;
}
@Override
protected void clean(IProgressMonitor monitor) throws CoreException {
super.clean(monitor);
deleteMarkers(getProject());
IProject project = getProject();
List<IFile> filesAtProjectRoot = getFileChildren(project);
for (IFile file : filesAtProjectRoot) {
if (file.getFileExtension().equals("genmodel")) {
file.delete(true, monitor);
}
else if (file.getFileExtension().equals("xsd2ecore")) {
file.delete(true, monitor);
}
else if (file.getFileExtension().equals("ecore")) {
file.delete(true, monitor);
}
}
IFolder sourceFolder = project.getFolder("src");
for (IFolder childFolder : getFolderChildren(sourceFolder)) {
if (!(childFolder.isHidden() || childFolder.isDerived() || childFolder.isTeamPrivateMember())) {
childFolder.delete(true, monitor);
}
}
}
private List<IFile> getSchemaFiles() throws CoreException {
List<IFile> schemaFiles = new ArrayList<IFile>();
IFolder modelFolder = getProject().getFolder("model");
if (modelFolder.exists()) {
IResource[] fileResources = modelFolder.members(IResource.FILE);
for (IResource fileResource : fileResources) {
if (fileResource instanceof IFile) {
IFile file = (IFile) fileResource;
if (file.exists()) {
String extension = file.getFileExtension();
if (extension != null && extension.equals("xsd")) {
schemaFiles.add(file);
}
}
}
}
}
return schemaFiles;
}
protected void fullBuild(final IProgressMonitor monitor) throws IOException, CoreException {
// Always clean up old stuff
clean(monitor);
// Delete any markers on the project itself.
deleteMarkers(getProject());
List<IFile> schemaFilesToProcess = getSchemaFiles();
if (schemaFilesToProcess.size() > 0) {
// Delete any existing markers on the schema files
for (IFile schemaFile : schemaFilesToProcess) {
deleteMarkers(schemaFile);
}
}
// Update schemas if necessary
Xadl3SchemaUpdater.getInstance().updateSchemasIfNecessary(getProject());
List<Xadl3SchemaLocation> schemaLocations = Xadl3SchemaLocation.parse(getProject());
addURIMappings(getProject());
// Now build with latest schemas.
schemaFilesToProcess = getSchemaFiles();
if (schemaFilesToProcess.size() > 0 || schemaLocations.size() > 0) {
// Get URIs for each schema file
List<String> fileURIs = new ArrayList<String>();
Map<String, IFile> uriToFileMap = new HashMap<String, IFile>();
for (IFile schemaFile : schemaFilesToProcess) {
fileURIs.add(schemaFile.getLocationURI().toString());
uriToFileMap.put(schemaFile.getLocationURI().toString(), schemaFile);
}
// Generate new bindings
String projectName = getProject().getName();
dbGenerator.setMonitor(BasicMonitor.toMonitor(monitor));
List<DataBindingGenerationStatus> statusList =
dbGenerator.generateBindings(fileURIs, schemaLocations, projectName);
for (DataBindingGenerationStatus status : statusList) {
if (status.getThrowable() != null) {
status.getThrowable().printStackTrace();
}
String schemaURI = status.getSchemaURIString();
IFile schemaFile = null;
if (schemaURI != null) {
schemaFile = uriToFileMap.get(schemaURI);
}
if (schemaFile != null) {
String message = status.getMessage();
if (status.getThrowable() != null) {
status.getThrowable().printStackTrace();
message += "; " + status.getThrowable().getMessage();
}
DataBindingGenerationStatus.Status statusType = status.getStatus();
if (statusType.equals(DataBindingGenerationStatus.Status.WARNING)) {
addMarker(schemaFile, message, 1, IMarker.SEVERITY_WARNING);
}
else if (statusType.equals(DataBindingGenerationStatus.Status.FAILURE)) {
addMarker(schemaFile, message, 1, IMarker.SEVERITY_ERROR);
}
}
else {
System.err.println(status.getMessage());
}
}
}
final IProject project = getProject();
project.getFolder("src").refreshLocal(IResource.DEPTH_INFINITE, monitor);
needRebuild();
}
private void addURIMappings(IProject project) {
IPluginModelBase workspacePluginModelBase = PluginRegistry.findModel(project);
if (workspacePluginModelBase != null) {
IExtensions extensions = workspacePluginModelBase.getExtensions();
if (extensions != null) {
for (IPluginExtension pluginExtension : extensions.getExtensions()) {
if (pluginExtension.getPoint() != null
&& pluginExtension.getPoint().equals("org.eclipse.emf.ecore.uri_mapping")) {
IPluginObject[] pluginObjects = pluginExtension.getChildren();
if (pluginObjects != null && pluginObjects.length > 0) {
for (IPluginElement pluginElement : Iterables.filter(Arrays.asList(pluginObjects),
IPluginElement.class)) {
URI source = URI.createURI(
Preconditions.checkNotNull(pluginElement.getAttribute("source").getValue()));
URI target = URI.createURI(
Preconditions.checkNotNull(pluginElement.getAttribute("target").getValue()));
if (source != null && target != null) {
URIConverter.URI_MAP.put(source, target);
}
}
}
}
}
}
}
}
class XMLErrorHandler extends DefaultHandler {
private final IFile file;
public XMLErrorHandler(IFile file) {
this.file = file;
}
private void addMarker(SAXParseException e, int severity) {
Xadl3SchemaBuilder.this.addMarker(file, e.getMessage(), e.getLineNumber(), severity);
}
@Override
public void error(SAXParseException exception) throws SAXException {
addMarker(exception, IMarker.SEVERITY_ERROR);
}
@Override
public void fatalError(SAXParseException exception) throws SAXException {
addMarker(exception, IMarker.SEVERITY_ERROR);
}
@Override
public void warning(SAXParseException exception) throws SAXException {
addMarker(exception, IMarker.SEVERITY_WARNING);
}
}
}