| /** |
| * |
| * Copyright (c) 2011, 2016 - Loetz GmbH&Co.KG (69115 Heidelberg, Germany) |
| * |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Christophe Loetz (Loetz GmbH&Co.KG) - initial implementation |
| */ |
| package org.eclipse.osbp.ide.core.ui.softwarefactory.builder; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.concurrent.CopyOnWriteArrayList; |
| |
| 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.IResourceDelta; |
| import org.eclipse.core.resources.IResourceDeltaVisitor; |
| import org.eclipse.core.resources.IResourceVisitor; |
| import org.eclipse.core.resources.IWorkspace; |
| import org.eclipse.core.resources.IncrementalProjectBuilder; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.OperationCanceledException; |
| import org.eclipse.core.runtime.ProgressMonitorWrapper; |
| import org.eclipse.core.runtime.SubMonitor; |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.emf.common.util.WrappedException; |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.emf.ecore.resource.ResourceSet; |
| import org.eclipse.osbp.ide.core.ui.softwarefactory.constants.Constants; |
| import org.eclipse.osbp.ide.core.ui.softwarefactory.extender.IModelExtenderProvider; |
| import org.eclipse.osbp.ide.core.ui.softwarefactory.extender.IModelExtenderProvider.Event.Listener; |
| import org.eclipse.osbp.ide.core.ui.softwarefactory.extender.ModelExtendedEvent; |
| import org.eclipse.osbp.ide.core.ui.softwarefactory.extender.ModelExtenderUtils; |
| import org.eclipse.osbp.ide.core.ui.softwarefactory.extender.ModelInstanceDescription; |
| import org.eclipse.xtext.resource.XtextResourceSet; |
| import org.eclipse.xtext.ui.editor.findrefs.IReferenceFinder; |
| import org.eclipse.xtext.ui.resource.XtextResourceSetProvider; |
| import org.eclipse.xtext.util.concurrent.IUnitOfWork; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import com.google.inject.Inject; |
| |
| public class OSBP2Builder extends IncrementalProjectBuilder { |
| |
| public static final String BUILDER_ID = Constants.BUILDER_ID; |
| |
| private static final Logger LOGGER = LoggerFactory.getLogger(OSBP2Builder.class); |
| |
| public static final String MODELS_BASE_SRC_DIRECTORY = "models"; |
| public static final String SOURCE_BASE_SRC_DIRECTORY = "src"; |
| |
| public static final String ENTITY_MODEL_EXTENSION = "entity"; |
| public static final String AUTHORIZATION_MODEL_EXTENSION = "authorization"; |
| public static final String DATAMART_MODEL_EXTENSION = "datamart"; |
| public static final String DATAINTERCHANGE_MODEL_EXTENSION = "data"; |
| public static final String DTO_MODEL_EXTENSION = "dto"; |
| public static final String SERVICE_MODEL_EXTENSION = "service"; |
| public static final String ACTION_MODEL_EXTENSION = "action"; |
| public static final String TABLE_MODEL_EXTENSION = "table"; |
| public static final String DIALOG_MODEL_EXTENSION = "dialog"; |
| public static final String UIMODEL_MODEL_EXTENSION = "ui"; |
| public static final String PERSPECTIVE_MODEL_EXTENSION = "perspective"; |
| public static final String MENU_MODEL_EXTENSION = "menu"; |
| |
| @SuppressWarnings("serial") |
| private Map<String, List<String>> dependencyTree = new HashMap<String, List<String>>() {{ //NOSONAR |
| // put("datatype", new ArrayList<String>() {{ // NOSONAR |
| // add("entity"); |
| // add("dialog"); |
| // }}); |
| // put("entity", new ArrayList<String>() {{ // NOSONAR |
| // add("datamart"); |
| // add("datainterchange"); |
| // }}); |
| // put("dto", new ArrayList<String>() {{ // NOSONAR |
| // add("dialog"); |
| // add("ui"); |
| // add("statemachine"); |
| // add("functionlibrary"); |
| // add("entitymock"); |
| // add("blip"); |
| // }}); |
| // put("datamart", new ArrayList<String>() {{ // NOSONAR |
| // add("report"); |
| // add("table"); |
| // add("chart"); |
| // }}); |
| // put("data", new ArrayList<String>() {{ // NOSONAR |
| // add("action"); |
| // add("entitymock"); |
| // }}); |
| // put("functionlibrary", new ArrayList<String>() {{ // NOSONAR |
| // add("action"); |
| // add("statemachine"); |
| // add("blip"); |
| // }}); |
| // put("authorization", new ArrayList<String>() {{ // NOSONAR |
| // add("dialog"); |
| // }}); |
| // put("message", new ArrayList<String>() {{ // NOSONAR |
| // add("action"); |
| // }}); |
| }}; |
| |
| @Inject |
| private XtextResourceSetProvider rsProvider; |
| |
| @Inject |
| private IModelExtenderProvider.Event.Source modelExtenderBuilder; |
| |
| @Inject |
| private IWorkspace workspace; |
| |
| private boolean firstBuild = true; |
| |
| @Override |
| protected IProject[] build(int kind, Map<String, String> args, IProgressMonitor monitor) throws CoreException { |
| SubMonitor progress = null; |
| |
| boolean isModelExtending = false; |
| List<String> extensionsRebuilt = new CopyOnWriteArrayList<>(); |
| for (String fileExtension : modelExtenderBuilder.getPending()) { |
| for (Listener listener : modelExtenderBuilder.getListenerList()) { |
| Map<String, ModelInstanceDescription> modelInstanceDecriptionMap = modelExtenderBuilder |
| .getModelInstanceDescriptionMap(listener); |
| isModelExtending = true; |
| for (Entry<String, ModelInstanceDescription> extension : modelInstanceDecriptionMap.entrySet()) { |
| if (extension.getKey().equals(fileExtension) |
| && extension.getValue().getProject().equals(getProject()) |
| && extension.getValue().isDone() |
| && !extension.getValue().isBuilt()) { |
| LOGGER.debug("rebuild for {}", extension.getKey()); |
| extension.getValue().setBuilt(true); |
| needRebuild(); |
| extensionsRebuilt.add(extension.getKey()); |
| modelExtenderBuilder.getPending().remove(fileExtension); |
| } |
| } |
| } |
| } |
| |
| if (!isModelExtending) { // this disturbs the model extender workflow |
| try { |
| final String taskName = "Building" + getProject().getName() + ": "; //$NON-NLS-2$ |
| progress = SubMonitor.convert(new ProgressMonitorWrapper(monitor) { // NOSONAR |
| // - |
| // lambda |
| @Override |
| public void subTask(String name) { // NOSONAR |
| super.subTask(taskName + name); |
| } |
| }, 8); |
| if (kind == FULL_BUILD || firstBuild) { |
| firstBuild = false; |
| fullBuild(progress.newChild(1)); |
| } else { |
| IResourceDelta delta = getDelta(getProject()); |
| if (delta == null || isOpened(delta)) { |
| fullBuild(progress.newChild(1)); |
| } else { |
| incrementalBuild(delta, progress.newChild(1)); |
| } |
| } |
| progress.worked(8); |
| } catch (CoreException e) { |
| LOGGER.error(e.getMessage(), e); |
| throw e; |
| } catch (OperationCanceledException e) { |
| forgetLastBuiltState(); |
| throw e; |
| } catch (Exception e) { |
| LOGGER.error(e.getMessage(), e); |
| } finally { |
| if (progress != null) { |
| progress.done(); |
| } |
| } |
| } |
| if (!extensionsRebuilt.isEmpty()) { |
| for (String extension : extensionsRebuilt) { |
| LOGGER.debug("extending finished for {}", extension); |
| modelExtenderBuilder.notifyListeners(new ModelExtendedEvent(extension)); |
| } |
| } |
| return getProject().getReferencedProjects(); |
| } |
| |
| private boolean checkFolder(IFolder folder) { |
| return (MODELS_BASE_SRC_DIRECTORY.equals(folder.getName()) || SOURCE_BASE_SRC_DIRECTORY.equals(folder.getName())); |
| } |
| |
| private boolean checkFile(IFile file) { |
| return buildUpstream(file.getFileExtension()); |
| } |
| |
| private boolean buildUpstream(String extension) { |
| if(!dependencyTree.containsKey(extension)) { |
| return false; |
| } |
| Map<URI, IProject> result = new LinkedHashMap<>(); |
| iterateDeps(extension, result); |
| for(Entry<URI, IProject> res:result.entrySet()) { |
| XtextResourceSet resourceSet = (XtextResourceSet) rsProvider.get(res.getValue()); |
| Resource resource = resourceSet.getResource(res.getKey(), true); |
| ModelExtenderUtils.writeResource(resource, res.getValue().getName()); |
| } |
| return true; |
| } |
| |
| private void iterateDeps(String extension, Map<URI, IProject> result) { |
| if(dependencyTree.containsKey(extension)) { |
| for(String depExt:dependencyTree.get(extension)) { |
| iterateDeps(depExt, result); |
| getProjectsByExtension(depExt, result); |
| } |
| } |
| } |
| |
| private void getProjectsByExtension(String extension, Map<URI, IProject> result) { |
| for(IProject project:workspace.getRoot().getProjects()) { |
| if(project.isOpen() && extension.equals(project.getFileExtension())) { |
| try { |
| project.accept(new IResourceVisitor() { |
| @Override |
| public boolean visit(IResource resource) throws CoreException { |
| if (resource.getType() == IResource.FILE) { |
| IFile file = (IFile) resource; |
| if (extension.equalsIgnoreCase(file.getFileExtension()) && !file.getFullPath().toString().contains("target/classes")) { |
| result.put(URI.createPlatformPluginURI(file.getFullPath().toString(), false), project); |
| } |
| } |
| return true; |
| } |
| }); |
| } catch (CoreException e) { |
| LOGGER.error("{}", e); |
| } |
| break; |
| } |
| } |
| } |
| |
| /** |
| * @param monitor |
| * the progress monitor to use for reporting progress to the |
| * user. It is the caller's responsibility to call done() on the |
| * given monitor. Accepts null, indicating that no progress |
| * should be reported and that the operation cannot be cancelled. |
| */ |
| protected void incrementalBuild(IResourceDelta delta, final IProgressMonitor monitor) throws CoreException { |
| final SubMonitor progress = SubMonitor.convert(monitor, "Updating references", 4); |
| progress.subTask("Updating references"); |
| if (progress.isCanceled()) |
| throw new OperationCanceledException(); |
| progress.worked(2); |
| |
| IProject project = getProject(); |
| if (!project.getDescription().hasNature(Constants.NATURE_ID)) { |
| return; |
| } |
| |
| delta.accept(new IResourceDeltaVisitor() { // NOSONAR - anonymous to |
| // lambda |
| @Override |
| public boolean visit(IResourceDelta delta) throws CoreException { |
| if (progress.isCanceled()) { |
| throw new OperationCanceledException(); |
| } |
| if (delta.getResource() instanceof IProject) { |
| return delta.getResource() == getProject(); |
| } else if (delta.getResource() instanceof IFolder) { |
| return checkFolder((IFolder) delta.getResource()); |
| } else if (delta.getResource() instanceof IFile) { |
| return checkFile((IFile) delta.getResource()); |
| } |
| return false; |
| } |
| }); |
| |
| if (progress.isCanceled()) |
| throw new OperationCanceledException(); |
| progress.worked(4); |
| |
| } |
| |
| /** |
| * @param monitor |
| * the progress monitor to use for reporting progress to the |
| * user. It is the caller's responsibility to call done() on the |
| * given monitor. Accepts null, indicating that no progress |
| * should be reported and that the operation cannot be cancelled. |
| */ |
| protected void fullBuild(final IProgressMonitor monitor) throws CoreException { |
| |
| IProject project = getProject(); |
| if (!project.getDescription().hasNature(Constants.NATURE_ID)) { |
| return; |
| } |
| |
| // monitor.worked(2); |
| // project.accept(new IResourceVisitor() { |
| // @Override |
| // // NOSONAR - anonymous to lambda |
| // public boolean visit(IResource resource) throws CoreException { |
| // if (resource == getProject()) { |
| // return true; |
| // } else if (resource instanceof IFolder) { |
| // return checkFolder((IFolder) resource); |
| // } else if (resource instanceof IFile) { |
| // return checkFile((IFile) resource); |
| // } |
| // return false; |
| // } |
| // }); |
| // monitor.worked(6); |
| } |
| |
| /** |
| * Returns true, if delta is from our projectentity is contained in |
| * entityModel. |
| * |
| * @param entity |
| * @param entityModel |
| * @return |
| */ |
| protected boolean isOpened(IResourceDelta delta) { |
| return delta.getResource() instanceof IProject && (delta.getFlags() & IResourceDelta.OPEN) != 0 |
| && ((IProject) delta.getResource()).isOpen(); |
| } |
| |
| @Override |
| protected void clean(IProgressMonitor monitor) throws CoreException { |
| if (monitor != null) { |
| monitor.done(); |
| } |
| } |
| |
| public static class LocalResourceAccess implements IReferenceFinder.ILocalResourceAccess { |
| |
| private ResourceSet resourceSet; |
| |
| public LocalResourceAccess(ResourceSet resourceSet) { |
| this.resourceSet = resourceSet; |
| } |
| |
| public <R> R readOnly(URI targetURI, IUnitOfWork<R, ResourceSet> work) { |
| try { |
| return work.exec(resourceSet); |
| } catch (OperationCanceledException e) { |
| throw e; |
| } catch (Exception exc) { |
| throw new WrappedException(exc); |
| } |
| } |
| |
| } |
| } |