/*********************************************************************** * Copyright (c) 2007,2008 Harman/Becker Automotive Systems GmbH 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 * * GenModelBuilder.java * * Contributors: * Daniel Weber - initial API and implementation * Lucas Bigeardel - IP integration * * $Id: GenModelBuilder.java,v 1.4 2008/07/15 15:14:45 lbigearde Exp $ **********************************************************************/ package org.eclipse.emf.ecoretools.codegen.builder.genmodelBuilder; import java.util.Map; 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.resources.ProjectScope; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.emf.codegen.ecore.generator.Generator; import org.eclipse.emf.codegen.ecore.genmodel.GenModel; import org.eclipse.emf.codegen.ecore.genmodel.generator.GenBaseGeneratorAdapter; import org.eclipse.emf.codegen.ecore.genmodel.provider.GenModelEditPlugin; import org.eclipse.emf.codegen.merge.java.JControlModel; import org.eclipse.emf.common.command.CommandStack; import org.eclipse.emf.common.util.BasicDiagnostic; import org.eclipse.emf.common.util.BasicMonitor; import org.eclipse.emf.common.util.Diagnostic; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.plugin.EcorePlugin; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecoretools.codegen.builder.EmfBuilderPrefsInitializer; import org.eclipse.emf.ecoretools.codegen.builder.genmodelBuilder.l10n.Messages; import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain; import org.eclipse.emf.edit.provider.ComposedAdapterFactory; import org.eclipse.ui.preferences.ScopedPreferenceStore; /** * An incremental project builder generating code from emf .genmodel files * * @author DaWeber */ public class GenModelBuilder extends IncrementalProjectBuilder { /** * A resource visitor used during incremental builds. It calls the emf * generator for every genmodel file that has changed. * * @author DaWeber */ private class GenModelDeltaVisitor implements IResourceDeltaVisitor { /* * (non-Javadoc) * * @see org.eclipse.core.resources.IResourceDeltaVisitor#visit(org.eclipse.core.resources.IResourceDelta) */ public boolean visit(IResourceDelta delta) throws CoreException { IResource resource = delta.getResource(); if(resource instanceof IFile && resource.getName().endsWith(".genmodel")) //$NON-NLS-1$ { if(!resource.isDerived()) { resource.deleteMarkers(IMarker.PROBLEM, true, IResource.DEPTH_ONE); switch(delta.getKind()) { case IResourceDelta.ADDED: generateEmfCode(resource); break; case IResourceDelta.CHANGED: generateEmfCode(resource); break; } } } // return true to continue visiting children. return true; } } /** * A resource visitor used during full builds. It calls the emf generator for * all .genmodel files it visits. * * @author DaWeber */ private class GenModelResourceVisitor implements IResourceVisitor { public boolean visit(IResource resource) throws CoreException { if(resource instanceof IFile && resource.getName().endsWith(".genmodel")) //$NON-NLS-1$ { if(!resource.isDerived()) { resource.deleteMarkers(IMarker.PROBLEM, true, IResource.DEPTH_ONE); generateEmfCode(resource); } } return true; } } public static final String BUILDER_ID = "org.eclipse.emf.ecoretools.codegen.genModelBuilder"; //$NON-NLS-1$ private ComposedAdapterFactory adapterFactory; private final GenModelDeltaVisitor deltaVisitor; private AdapterFactoryEditingDomain editingDomain; private Generator generator; private IProgressMonitor monitor; private GenModelResourceVisitor resourceVisitor; /** * */ public GenModelBuilder() { deltaVisitor = new GenModelDeltaVisitor(); resourceVisitor = new GenModelResourceVisitor(); } /* * (non-Javadoc) * * @see org.eclipse.core.internal.events.InternalBuilder#build(int, * java.util.Map, org.eclipse.core.runtime.IProgressMonitor) */ @Override @SuppressWarnings("unchecked") protected IProject[] build(int kind, Map args, IProgressMonitor monitor) throws CoreException { this.monitor = monitor; if(kind == FULL_BUILD) { getProject().accept(resourceVisitor); } else { IResourceDelta delta = getDelta(getProject()); if(delta != null) { delta.accept(deltaVisitor); } } this.monitor = null; return null; } /** * */ private void createEditingDomain() { adapterFactory = new ComposedAdapterFactory( ComposedAdapterFactory.Descriptor.Registry.INSTANCE); // Create the editing domain with a special command stack. // editingDomain = new AdapterFactoryEditingDomain(adapterFactory, null) { @Override public CommandStack getCommandStack() { throw new RuntimeException(Messages.getString("GenModelBuilder.NoCommandStackError")); //$NON-NLS-1$ } @Override public boolean isReadOnly(Resource resource) { return super.isReadOnly(resource) || getResourceSet().getResources().indexOf(resource) != 0; } }; editingDomain.getResourceSet().getURIConverter().getURIMap().putAll( EcorePlugin.computePlatformURIMap()); } /** * Extracts the GenModel from a given resource * * @param resource * containing the GenModel * @return The extracted GenModel, null if something went wrong * @throws CoreException * if error reporting fails */ private GenModel createGenModel(IResource resource) throws CoreException { URI resourceURI = URI.createPlatformResourceURI(resource.getFullPath().toString(), true); Resource emfResource = null; GenModel ret = null; try { // Load the resource through the editing domain. // emfResource = editingDomain.getResourceSet().getResource(resourceURI, true); ret = (GenModel)emfResource.getContents().get(0); ret.reconcile(); ret.setCanGenerate(true); generator = new Generator(); generator.setInput(ret); JControlModel jControlModel = generator.getJControlModel(); if(ret.isCodeFormatting()) { jControlModel.setLeadingTabReplacement(null); jControlModel.setConvertToStandardBraceStyle(false); } } catch(Exception e) { reportBuildError(resource, e); } return ret; } /** * @param resource * @param genModel * @param projectType * @param projectName * @throws CoreException * if error reporting fails */ private void generateCode(IResource resource, final GenModel genModel, final String projectType, final String projectName) throws CoreException { // this is run as part of the build job, don't fork another // job/thread/operation try { BasicDiagnostic diagnostic = new BasicDiagnostic(GenModelEditPlugin.ID, 0, "", //$NON-NLS-1$ null); diagnostic.add(generator.generate(genModel, projectType, projectName, BasicMonitor.toMonitor(new SubProgressMonitor(monitor, 0)))); if(diagnostic.getSeverity() != Diagnostic.OK) { reportBuildError(resource, diagnostic.getMessage()); } } catch(Exception exception) { reportBuildError(resource, exception); } } /** * Generates emf model and edit code * * @param resource * containing the GenModel * @throws CoreException * if error reporting fails */ private void generateEmfCode(IResource resource) throws CoreException { ScopedPreferenceStore preferenceStore = new ScopedPreferenceStore(new ProjectScope( resource.getProject()), EmfBuilderPrefsInitializer.PREFERENCE_NODE_NAME); boolean generateModelCode = preferenceStore .getBoolean(EmfBuilderPrefsInitializer.PREF_GENERATE_MODEL_CODE); boolean generateEditCode = preferenceStore .getBoolean(EmfBuilderPrefsInitializer.PREF_GENERATE_EDIT_CODE); boolean generateEditorCode = preferenceStore .getBoolean(EmfBuilderPrefsInitializer.PREF_GENERATE_EDITOR_CODE); boolean generateTestCode = preferenceStore .getBoolean(EmfBuilderPrefsInitializer.PREF_GENERATE_TEST_CODE); if(generateEditCode || generateEditorCode || generateModelCode || generateTestCode) { createEditingDomain(); GenModel genModel = createGenModel(resource); if(null != genModel) { if(generateModelCode) { generateCode(resource, genModel, GenBaseGeneratorAdapter.MODEL_PROJECT_TYPE, Messages.getString("GenModelBuilder.ModelProjectType.Label")); //$NON-NLS-1$ } if(generateEditCode) { generateCode(resource, genModel, GenBaseGeneratorAdapter.EDIT_PROJECT_TYPE, Messages.getString("GenModelBuilder.EditProjectType.Label")); //$NON-NLS-1$ } if(generateEditorCode) { generateCode(resource, genModel, GenBaseGeneratorAdapter.EDITOR_PROJECT_TYPE, Messages.getString("GenModelBuilder.EditorProjectType.Label")); //$NON-NLS-1$ } if(generateTestCode) { generateCode(resource, genModel, GenBaseGeneratorAdapter.TESTS_PROJECT_TYPE, Messages.getString("GenModelBuilder.TestProjectType.Label")); //$NON-NLS-1$ } } } } /** * @param resource * @param e * @throws CoreException * if reporting the error fails */ private void reportBuildError(IResource resource, Exception e) throws CoreException { reportBuildError(resource, e.getMessage()); } /** * Reports build errors by creating markers for the given resource * * @param resource * @param msg * @throws CoreException * if creating a marker fails */ private void reportBuildError(IResource resource, String msg) throws CoreException { IMarker marker = resource.createMarker(IMarker.PROBLEM); marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH); marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR); marker.setAttribute(IMarker.MESSAGE, msg); } }