| /** |
| * Copyright (c) 2011, 2015 - Lunifera GmbH (Gross Enzersdorf, Austria), 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: |
| * Florian Pirchner - Initial implementation |
| */ |
| package org.eclipse.osbp.ide.core.ui.builder; |
| |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Optional; |
| import java.util.Set; |
| |
| 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.IResourceVisitor; |
| import org.eclipse.core.resources.IStorage; |
| import org.eclipse.core.resources.IncrementalProjectBuilder; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.OperationCanceledException; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.emf.common.notify.Adapter; |
| import org.eclipse.emf.common.notify.impl.AdapterImpl; |
| import org.eclipse.emf.common.util.Diagnostic; |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.emf.common.util.WrappedException; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.emf.ecore.resource.ResourceSet; |
| import org.eclipse.emf.ecore.util.Diagnostician; |
| import org.eclipse.emf.ecore.util.EcoreUtil; |
| import org.eclipse.jface.dialogs.ErrorDialog; |
| import org.eclipse.osbp.dsl.semantic.common.types.LAttribute; |
| import org.eclipse.osbp.dsl.semantic.common.types.LEnum; |
| import org.eclipse.osbp.dsl.semantic.common.types.LEnumLiteral; |
| import org.eclipse.osbp.dsl.semantic.common.types.LReference; |
| import org.eclipse.osbp.dsl.semantic.common.types.LScalarType; |
| import org.eclipse.osbp.dsl.semantic.common.types.LType; |
| import org.eclipse.osbp.dsl.semantic.common.types.LTypedPackage; |
| import org.eclipse.osbp.dsl.semantic.common.types.OSBPTypesFactory; |
| import org.eclipse.osbp.dsl.semantic.dto.LAutoInheritDto; |
| import org.eclipse.osbp.dsl.semantic.dto.LDto; |
| import org.eclipse.osbp.dsl.semantic.dto.LDtoFeature; |
| import org.eclipse.osbp.dsl.semantic.dto.LDtoInheritedAttribute; |
| import org.eclipse.osbp.dsl.semantic.dto.LDtoInheritedReference; |
| import org.eclipse.osbp.dsl.semantic.dto.LDtoModel; |
| import org.eclipse.osbp.dsl.semantic.dto.OSBPDtoFactory; |
| import org.eclipse.osbp.dsl.semantic.dto.OSBPDtoPackage; |
| import org.eclipse.osbp.dsl.semantic.dto.util.NamingConventionsUtil; |
| import org.eclipse.osbp.dsl.semantic.entity.LBean; |
| import org.eclipse.osbp.dsl.semantic.entity.LBeanAttribute; |
| import org.eclipse.osbp.dsl.semantic.entity.LBeanFeature; |
| import org.eclipse.osbp.dsl.semantic.entity.LBeanReference; |
| import org.eclipse.osbp.dsl.semantic.entity.LEntity; |
| import org.eclipse.osbp.dsl.semantic.entity.LEntityAttribute; |
| import org.eclipse.osbp.dsl.semantic.entity.LEntityFeature; |
| import org.eclipse.osbp.dsl.semantic.entity.LEntityModel; |
| import org.eclipse.osbp.dsl.semantic.entity.LEntityReference; |
| import org.eclipse.osbp.dsl.semantic.service.LDTOService; |
| import org.eclipse.osbp.dsl.semantic.service.LService; |
| import org.eclipse.osbp.dsl.semantic.service.LServiceModel; |
| import org.eclipse.osbp.dsl.semantic.service.OSBPServiceFactory; |
| import org.eclipse.osbp.dsl.semantic.service.OSBPServicePackage; |
| import org.eclipse.osbp.ide.core.api.i18n.CoreUtil; |
| import org.eclipse.osbp.ide.core.ui.CoreUiActivator; |
| import org.eclipse.osbp.ide.core.ui.nature.OSBPNature; |
| import org.eclipse.osbp.xtext.builder.ui.access.IXtextUtilService; |
| import org.eclipse.osbp.xtext.oxtype.logger.TimeLogger; |
| import org.eclipse.osbp.xtext.oxtype.oxtype.OXImportDeclaration; |
| import org.eclipse.osbp.xtext.oxtype.oxtype.OXtypeFactory; |
| import org.eclipse.osbp.xtext.oxtype.resource.ISemanticLoadingResource; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.xtext.builder.builderState.IBuilderState; |
| import org.eclipse.xtext.common.types.TypesPackage; |
| import org.eclipse.xtext.naming.IQualifiedNameProvider; |
| import org.eclipse.xtext.resource.IEObjectDescription; |
| import org.eclipse.xtext.resource.IReferenceDescription; |
| import org.eclipse.xtext.resource.IResourceDescription; |
| import org.eclipse.xtext.resource.IResourceDescription.Delta; |
| import org.eclipse.xtext.resource.IResourceServiceProvider; |
| import org.eclipse.xtext.resource.SaveOptions; |
| import org.eclipse.xtext.resource.XtextResourceSet; |
| import org.eclipse.xtext.ui.editor.findrefs.IReferenceFinder; |
| import org.eclipse.xtext.ui.resource.IStorage2UriMapper; |
| import org.eclipse.xtext.ui.resource.XtextResourceSetProvider; |
| import org.eclipse.xtext.util.IAcceptor; |
| import org.eclipse.xtext.util.Pair; |
| import org.eclipse.xtext.util.concurrent.IUnitOfWork; |
| import org.eclipse.xtext.xtype.XImportDeclaration; |
| import org.eclipse.xtext.xtype.XImportSection; |
| import org.eclipse.xtext.xtype.XtypeFactory; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import com.google.inject.Inject; |
| import com.google.inject.Injector; |
| |
| // TODO: Auto-generated Javadoc |
| /** |
| * This builder is aware about the Xtext index. If changes occurred there, we |
| * pend the {@link IResourceDescription} and do a model-enhancing-build later. |
| * See {@link #needRebuild()}. It reinvoked the build chain later. So we can |
| * ensure, that the index for our enhanced models is created too. |
| */ |
| @SuppressWarnings("restriction") |
| public class OSBPModelEnhancingBuilder extends IncrementalProjectBuilder |
| implements IResourceDescription.Event.Listener { |
| |
| /** The Constant BUILDER_ID. */ |
| public static final String BUILDER_ID = CoreUtil.BUILDER_MODEL_ENHANCING_ID; |
| |
| public final static String MODELS_BASE_SRC_DIRECTORY = "models"; |
| public final static String SOURCE_BASE_SRC_DIRECTORY = "src"; |
| |
| /** The Constant LOGGER. */ |
| private static final Logger LOGGER = LoggerFactory.getLogger(OSBPModelEnhancingBuilder.class); |
| |
| /** The state. */ |
| @Inject |
| private IBuilderState state; |
| |
| /** The injector. */ |
| @Inject |
| private Injector injector; |
| |
| /** The uri storage mapper. */ |
| @Inject |
| private IStorage2UriMapper uriStorageMapper; |
| |
| /** The dto builder. */ |
| private DtoEnhancer dtoBuilder; |
| |
| /** The service builder. */ |
| private ServiceEnhancer serviceBuilder; |
| |
| private List<Pending> pending = new ArrayList<Pending>(); |
| private boolean firstBuild = true; |
| |
| private IQualifiedNameProvider entityNameProvider; |
| private IQualifiedNameProvider dtoNameProvider; |
| |
| /** |
| * Instantiates a new OSBP model enhancing builder. |
| */ |
| public OSBPModelEnhancingBuilder() { |
| |
| } |
| |
| /** |
| * Listens for changes of Xtext builder. If entity or dto are being changed, |
| * then we store the models for later. |
| * |
| * @param event |
| * the event |
| */ |
| @Override |
| public void descriptionsChanged(org.eclipse.xtext.resource.IResourceDescription.Event event) { |
| for (Delta delta : event.getDeltas()) { |
| // do not check for changes in the eobject description. Causes |
| // confusion for the user |
| if (delta.getNew() == null) { |
| continue; |
| } |
| |
| if (shouldUse(delta.getUri())) { |
| |
| String fileExtension = delta.getUri().fileExtension(); |
| switch (fileExtension) { |
| case "entity": |
| if (!contains(delta.getUri())) { |
| pending.add(new Pending(delta.getNew())); |
| } |
| break; |
| case "dto": |
| if (!contains(delta.getUri())) { |
| pending.add(new Pending(delta.getNew())); |
| } |
| break; |
| } |
| } |
| } |
| } |
| |
| /** |
| * Contains. |
| * |
| * @param uri |
| * the uri |
| * @return true, if successful |
| */ |
| private boolean contains(URI uri) { |
| return pending.stream().filter(e -> e.uri.equals(uri)).count() > 0; |
| } |
| |
| /** |
| * Should use. |
| * |
| * @param uri |
| * the uri |
| * @return true, if successful |
| */ |
| private boolean shouldUse(URI uri) { |
| if (uri == null) { |
| return false; |
| } |
| |
| String platformResourcePath = uri.toPlatformString(true); |
| if (platformResourcePath == null) { |
| return false; |
| } |
| IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(platformResourcePath)); |
| if (file == null || !file.exists()) { |
| // if resource is not in workspace continue |
| return false; |
| } |
| |
| Iterable<Pair<IStorage, IProject>> pairs = uriStorageMapper.getStorages(uri); |
| if (pairs.iterator().hasNext()) { |
| Pair<IStorage, IProject> pair = pairs.iterator().next(); |
| IProject dtoProject = pair.getSecond(); |
| if (dtoProject != null && pair.getFirst() instanceof IFile) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.core.resources.IncrementalProjectBuilder#build(int, |
| * java.util.Map, org.eclipse.core.runtime.IProgressMonitor) |
| */ |
| @Override |
| protected IProject[] build(int kind, Map<String, String> args, IProgressMonitor monitor) throws CoreException { |
| ensureParticipants(); |
| |
| if (kind == FULL_BUILD || firstBuild) { |
| firstBuild = false; |
| collectInitialPending(); |
| } |
| |
| if (!pending.isEmpty()) { |
| Collections.sort(pending, new Comparator<Pending>() { |
| @Override |
| public int compare(Pending o1, Pending o2) { |
| if (o1.uri.fileExtension().equals("entity")) { |
| return -1; |
| } |
| if (o1.uri.fileExtension().equals("dto")) { |
| return 1; |
| } |
| return 0; |
| } |
| }); |
| |
| boolean processed = false; |
| for (Iterator<Pending> iterator = pending.iterator(); iterator.hasNext() && !processed;) { |
| Pending pending = iterator.next(); |
| try { |
| |
| // URI uri = pending.uri; |
| // if(uri.isPlatform()) { |
| // // String projectName = getProject().getName(); |
| // // if(uri.device().equals(projectName)) |
| // ResourcesPlugin.getWorkspace().getRoot().get |
| // } |
| |
| String fileExtension = pending.uri.fileExtension(); |
| switch (fileExtension) { |
| case "entity": |
| LEntityModel lentity = dtoBuilder.loadSemanticModel(pending.uri); |
| if (lentity != null) { |
| dtoBuilder.buildDtos(lentity); |
| processed = true; |
| needRebuild(); |
| } |
| break; |
| case "dto": |
| LDtoModel lDtoModel = serviceBuilder.loadSemanticModel(pending.uri); |
| if (lDtoModel != null) { |
| // touch the ui and dialog models |
| try { |
| serviceBuilder |
| .buildUiAndDialogModels(lDtoModel); |
| } catch (Exception e) { |
| LOGGER.error("{}", e); |
| } |
| try { |
| serviceBuilder.buildServices(lDtoModel); |
| } catch (Exception e) { |
| LOGGER.error("{}", e); |
| } |
| processed = true; |
| needRebuild(); |
| } |
| break; |
| } |
| } finally { |
| iterator.remove(); |
| } |
| } |
| } |
| |
| return getProject().getReferencedProjects(); |
| } |
| |
| /** |
| * Collects all resources that should be used for an initial build. |
| * |
| * @throws CoreException |
| */ |
| private void collectInitialPending() throws CoreException { |
| IProject project = getProject(); |
| if (!project.getDescription().hasNature(OSBPNature.NATURE_ID)) { |
| return; |
| } |
| 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) { |
| IFile file = (IFile) resource; |
| |
| org.eclipse.emf.common.util.URI uri = org.eclipse.emf.common.util.URI |
| .createPlatformResourceURI(file.getFullPath().toString(), false); |
| if (shouldUse(uri)) { |
| String fileExtension = uri.fileExtension(); |
| switch (fileExtension) { |
| case "entity": |
| if (!contains(uri)) { |
| pending.add(new Pending(uri)); |
| } |
| break; |
| case "dto": |
| if (!contains(uri)) { |
| pending.add(new Pending(uri)); |
| } |
| break; |
| } |
| } |
| |
| } |
| return false; |
| } |
| }); |
| } |
| |
| private boolean checkFolder(IFolder folder) { // NOSONAR - complexity |
| if (MODELS_BASE_SRC_DIRECTORY.equals(folder.getName())) { |
| return true; |
| } |
| if (SOURCE_BASE_SRC_DIRECTORY.equals(folder.getName())) { |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Ensure participants. |
| */ |
| private void ensureParticipants() { |
| if (dtoBuilder == null) { |
| // on startup add the state listener |
| state.addListener(this); |
| |
| dtoBuilder = new DtoEnhancer(); |
| injector.injectMembers(dtoBuilder); |
| } |
| |
| if (serviceBuilder == null) { |
| serviceBuilder = new ServiceEnhancer(); |
| injector.injectMembers(serviceBuilder); |
| } |
| |
| if (entityNameProvider == null) { |
| entityNameProvider = IResourceServiceProvider.Registry.INSTANCE |
| .getResourceServiceProvider(URI.createURI("osbp_builder:/my.entity")) |
| .get(IQualifiedNameProvider.class); |
| } |
| |
| if (dtoNameProvider == null) { |
| dtoNameProvider = IResourceServiceProvider.Registry.INSTANCE |
| .getResourceServiceProvider(URI.createURI("osbp_builder:/my.dto")) |
| .get(IQualifiedNameProvider.class); |
| } |
| } |
| |
| /** |
| * The Class DtoEnhancer. |
| */ |
| public class DtoEnhancer { |
| |
| /** |
| * The Class DtoEnhancerContext. |
| */ |
| private class DtoEnhancerContext { |
| |
| /** The dto resource. */ |
| private ISemanticLoadingResource dtoResource; |
| |
| /** The writeable resource set. */ |
| private ResourceSet writeableResourceSet; |
| } |
| |
| /** The rs provider. */ |
| @Inject |
| private XtextResourceSetProvider rsProvider; |
| |
| /** The reference finder. */ |
| @Inject |
| private IReferenceFinder referenceFinder; |
| |
| /** The uri storage mapper. */ |
| @Inject |
| private IStorage2UriMapper uriStorageMapper; |
| |
| /** |
| * Builds the dto. |
| * |
| * @param tempLEntityModel |
| * the temp l entity model |
| */ |
| public void buildDtos(LEntityModel tempLEntityModel) { |
| IXtextUtilService service = CoreUiActivator.getDefault().getUtilService(); |
| if (service == null) { |
| LOGGER.error("Skipping dto build since IXtextUtilService is not available!"); |
| return; |
| } |
| |
| TimeLogger timeLogger = TimeLogger.start(getClass()); |
| |
| // |
| // we need to prepare a dtoResource and a writeableResourceSet |
| // |
| // find referencing dto model |
| Set<URI> entityURIs = findEntityURIs(tempLEntityModel); |
| final List<IReferenceDescription> targetDtoReferences = findTargetDtoReferences(entityURIs, |
| tempLEntityModel.eResource().getResourceSet()); |
| |
| // ------- create the build context ------- |
| DtoEnhancerContext context = createDtoBuildContext(tempLEntityModel, targetDtoReferences); |
| |
| ISemanticLoadingResource entityResource = (ISemanticLoadingResource) context.writeableResourceSet |
| .getResource(tempLEntityModel.eResource().getURI(), true); |
| |
| List<LType> sourceArtifacts = collectEntities((LEntityModel) entityResource.getSemanticElement()); |
| |
| List<LType> tempDtos = collectDtos((LDtoModel) context.dtoResource.getSemanticElement()); |
| |
| List<SourceTypeStore> sourceTypeStores = new ArrayList<SourceTypeStore>(); |
| List<LType> dtosToPersist = new ArrayList<LType>(); |
| |
| // create all dtos -> no linking |
| // |
| Set<LTypedPackage> touchedPackages = new HashSet<LTypedPackage>(); |
| for (LType lType : sourceArtifacts) { |
| if (lType instanceof LEntity) { |
| LEntity lEntity = (LEntity) lType; |
| LDto lDto = (LDto) findDtoType(lEntity, tempDtos); |
| if (lDto == null) { |
| lDto = OSBPDtoFactory.eINSTANCE.createLAutoInheritDto(); |
| lDto.setAnnotationInfo(OSBPDtoFactory.eINSTANCE.createLDto()); |
| tempDtos.add(lDto); |
| } else { |
| // remove from package for a while |
| LTypedPackage lPkg = (LTypedPackage) lDto.eContainer(); |
| lPkg.getTypes().remove(lDto); |
| // collect all touched packages -> They need cleanup |
| // later |
| touchedPackages.add(lPkg); |
| } |
| lDto.setName(NamingConventionsUtil.toDtoName(lEntity)); |
| lDto.setWrappedType(lEntity); |
| |
| dtosToPersist.add(lDto); |
| |
| // store the source type of the new enum |
| sourceTypeStores.add(new SourceTypeStore(lEntity, lDto)); |
| |
| } else if (lType instanceof LBean) { |
| LBean lBean = (LBean) lType; |
| LDto lDto = (LDto) findDtoType(lBean, tempDtos); |
| if (lDto == null) { |
| lDto = OSBPDtoFactory.eINSTANCE.createLAutoInheritDto(); |
| lDto.setAnnotationInfo(OSBPDtoFactory.eINSTANCE.createLDto()); |
| tempDtos.add(lDto); |
| } else { |
| // remove from package for a while |
| LTypedPackage lPkg = (LTypedPackage) lDto.eContainer(); |
| lPkg.getTypes().remove(lDto); |
| |
| // collect all touched packages -> They need cleanup |
| // later |
| touchedPackages.add(lPkg); |
| } |
| lDto.setName(NamingConventionsUtil.toDtoName(lBean)); |
| lDto.setWrappedType(lBean); |
| |
| dtosToPersist.add(lDto); |
| |
| // store the source type of the new enum |
| sourceTypeStores.add(new SourceTypeStore(lBean, lDto)); |
| } else if (lType instanceof LEnum) { |
| LEnum lSourceType = (LEnum) lType; |
| LEnum lDtoType = (LEnum) findDtoType(lSourceType, tempDtos); |
| if (lDtoType == null) { |
| lDtoType = OSBPTypesFactory.eINSTANCE.createLEnum(); |
| // lDtoType.setAnnotationInfo(OSBPTypesFactory.eINSTANCE |
| // .createLEnum()); |
| tempDtos.add(lDtoType); |
| } else { |
| // remove from package for a while |
| LTypedPackage lPkg = (LTypedPackage) lDtoType.eContainer(); |
| lPkg.getTypes().remove(lDtoType); |
| |
| // collect all touched packages -> They need cleanup |
| // later |
| touchedPackages.add(lPkg); |
| } |
| lDtoType.setName(NamingConventionsUtil.toDtoName(lSourceType)); |
| |
| dtosToPersist.add(lDtoType); |
| |
| // store the source type of the new enum |
| sourceTypeStores.add(new SourceTypeStore(lSourceType, lDtoType)); |
| |
| } |
| } |
| |
| // clean touched packages -> Also remove dtos that are not based on |
| // an |
| // entity anymore |
| for (LTypedPackage lPkg : touchedPackages) { |
| for (Iterator<LType> iterator = lPkg.getTypes().iterator(); iterator.hasNext();) { |
| LType lType = (LType) iterator.next(); |
| if (lType instanceof LAutoInheritDto) { |
| LDto lDto = (LDto) lType; |
| if (lDto.getWrappedType() == null || lDto.getWrappedType().eIsProxy()) { |
| lDto.setSuperType(null); |
| iterator.remove(); |
| } |
| } |
| } |
| } |
| |
| // remove all dtos having no wrapped type anymore |
| // |
| for (LType lType : new ArrayList<>(tempDtos)) { |
| if (lType instanceof LAutoInheritDto) { |
| LDto lDto = (LDto) lType; |
| if (lDto.getWrappedType() == null || lDto.getWrappedType().eIsProxy()) { |
| tempDtos.remove(lDto); |
| } |
| } |
| } |
| |
| // clean super types |
| // |
| for (LType lType : dtosToPersist) { |
| if (lType instanceof LAutoInheritDto) { |
| LDto lDto = (LDto) lType; |
| lDto.setSuperType(null); |
| } |
| } |
| |
| // link super types |
| // |
| for (LType lType : sourceArtifacts) { |
| if (lType instanceof LEntity) { |
| LEntity lEntity = (LEntity) lType; |
| if (lEntity.getSuperType() != null && !lEntity.getSuperType().eIsProxy()) { |
| LEntity lEntitySuperType = lEntity.getSuperType(); |
| LDto lDto = (LDto) findDtoType(lEntity, tempDtos); |
| LDto lDtoSuperType = (LDto) findDtoType(lEntitySuperType, tempDtos); |
| lDto.setSuperType(lDtoSuperType); |
| } |
| } else if (lType instanceof LBean) { |
| LBean lBean = (LBean) lType; |
| if (lBean.getSuperType() != null && !lBean.getSuperType().eIsProxy()) { |
| LBean lBeanSuperType = lBean.getSuperType(); |
| LDto lDto = (LDto) findDtoType(lBean, tempDtos); |
| LDto lDtoSuperType = (LDto) findDtoType(lBeanSuperType, tempDtos); |
| lDto.setSuperType(lDtoSuperType); |
| } |
| } |
| } |
| |
| // fix features |
| // |
| for (LType lType : dtosToPersist) { |
| if (lType instanceof LAutoInheritDto) { |
| LDto lDto = (LDto) lType; |
| fixFeatures(lDto, dtosToPersist); |
| } else if (lType instanceof LEnum) { |
| LEnum lDtoEnum = (LEnum) lType; |
| fixLiterals(lDtoEnum); |
| } |
| } |
| |
| if (!dtosToPersist.isEmpty()) { |
| // add the dtos to the package in the proper order |
| // |
| Set<String> dtoNames = new HashSet<String>(); |
| for (LType lType : dtosToPersist) { |
| |
| if (lType instanceof LDto) { |
| LDto lDto = (LDto) lType; |
| // filter dtos |
| if (dtoNames.contains(lDto.getName())) { |
| // remove duplicate dtos |
| continue; |
| } else if (lDto.getWrappedType().eIsProxy()) { |
| // remove dto without a proper entity reference |
| continue; |
| } |
| dtoNames.add(lDto.getName()); |
| |
| LType wrappedType = lDto.getWrappedType(); |
| LTypedPackage lSourceTypePkg = (LTypedPackage) wrappedType.eContainer(); |
| addDtoToPackage(NamingConventionsUtil.toDtoPackage(lSourceTypePkg), lDto, |
| (LDtoModel) context.dtoResource.getSemanticElement(), wrappedType); |
| } else if (lType instanceof LEnum) { |
| LEnum lEnum = (LEnum) lType; |
| // filter dtos |
| if (dtoNames.contains(lEnum.getName())) { |
| // remove duplicate enums |
| continue; |
| } |
| dtoNames.add(lEnum.getName()); |
| |
| LEnum sourceType = (LEnum) SourceTypeStore.findSourceType(lEnum); |
| LTypedPackage lSourceTypePkg = (LTypedPackage) sourceType.eContainer(); |
| addDtoToPackage(NamingConventionsUtil.toDtoPackage(lSourceTypePkg), lEnum, |
| (LDtoModel) context.dtoResource.getSemanticElement(), sourceType); |
| } |
| } |
| |
| // remove all added adapters |
| // |
| for (SourceTypeStore store : sourceTypeStores) { |
| store.dispose(); |
| } |
| |
| // save the dtos |
| // |
| try { |
| Diagnostic diagnostic = Diagnostician.INSTANCE.validate(context.dtoResource.getSemanticElement()); |
| int sev = diagnostic.getSeverity(); |
| if (sev <= Diagnostic.WARNING) { |
| context.dtoResource.save(SaveOptions.newBuilder().format().getOptions().toOptionsMap()); |
| } else { |
| if (!context.dtoResource.getErrors().isEmpty()) { |
| String message = context.dtoResource.getErrors() |
| .get(0).toString(); |
| LOGGER.error(message); |
| |
| IStatus status = new Status(IStatus.ERROR, |
| "org.eclipse.osbp.ide.core.ui", message); |
| Display.getDefault().asyncExec( |
| () -> { |
| ErrorDialog.openError(Display |
| .getDefault().getActiveShell(), |
| "Error", message, status); |
| }); |
| } else { |
| String message = diagnostic.toString(); |
| LOGGER.error(diagnostic.toString()); |
| |
| IStatus status = new Status(IStatus.ERROR, |
| "org.eclipse.osbp.ide.core.ui", message); |
| Display.getDefault().asyncExec( |
| () -> { |
| ErrorDialog.openError(Display |
| .getDefault().getActiveShell(), |
| "Error", message, status); |
| }); |
| } |
| } |
| context.dtoResource.unload(); |
| |
| // invoke the incremental build |
| // |
| needRebuild(); |
| } catch (IOException e) { |
| LOGGER.error("{}", e); |
| } |
| |
| timeLogger.stop(LOGGER, "Finished OSBPBuilder#buildDtos in "); |
| |
| } |
| } |
| |
| /** |
| * Creates the dto build context. |
| * |
| * @param tempLEntityModel |
| * the temp l entity model |
| * @param targetDtoReferences |
| * the target dto references |
| * @return the dto enhancer context |
| */ |
| private DtoEnhancerContext createDtoBuildContext(LEntityModel tempLEntityModel, |
| final List<IReferenceDescription> targetDtoReferences) { |
| DtoEnhancerContext context = new DtoEnhancerContext(); |
| if (!targetDtoReferences.isEmpty()) { |
| // |
| // if we could find referenced dtos, then we use this |
| // information to |
| // create dtoResource and writeableResourceSet |
| // |
| |
| // access entity resource |
| ISemanticLoadingResource tempEntityResource = (ISemanticLoadingResource) tempLEntityModel.eResource(); |
| ResourceSet readonlyResourceSet = tempEntityResource.getResourceSet(); |
| |
| // access dto resource based on entityResourceSet |
| IReferenceDescription firstDesc = targetDtoReferences.get(0); |
| LDto tempDto = (LDto) readonlyResourceSet.getEObject(firstDesc.getSourceEObjectUri(), true); |
| |
| // create the proper dto resourceSet to save the dto |
| context.writeableResourceSet = getProjectResourceSet(EcoreUtil.getURI(tempDto)); |
| |
| // load the dtoResource based on the dto resourceSet |
| context.dtoResource = (ISemanticLoadingResource) context.writeableResourceSet |
| .getResource(EcoreUtil.getURI(tempDto).trimFragment(), true); |
| } else { |
| |
| URI entityURI = EcoreUtil.getURI(tempLEntityModel); |
| // create the proper dto resourceSet to save the dto |
| context.writeableResourceSet = getProjectResourceSet(entityURI); |
| |
| // try to find a file with extension .dtos in same project |
| IResource member = findDtoFile(entityURI); |
| String dtoResourcePath = null; |
| if (member != null) { |
| dtoResourcePath = member.getFullPath().toString(); |
| } else { |
| // |
| // if we could not find referenced dtos, then we use the |
| // folder |
| // of |
| // the entity and put the dtos in there |
| // |
| |
| // convert a path from |
| // "org/my/foo/entity/MyEntity.entity" |
| // to |
| // "org/my/foo/entity/MyEntity.dtos" |
| dtoResourcePath = NamingConventionsUtil.toDtoPackage(entityURI.path().replace("/resource", "")); |
| } |
| |
| // now create a dtoResource |
| |
| URI dtoModelURI = URI.createPlatformResourceURI(dtoResourcePath, true); |
| context.dtoResource = (ISemanticLoadingResource) context.writeableResourceSet |
| .createResource(dtoModelURI); |
| context.dtoResource.getContents().add(OSBPDtoFactory.eINSTANCE.createLDtoModel()); |
| } |
| return context; |
| } |
| |
| private IResource findDtoFile(URI entityURI) { |
| String dtoFileName = entityURI.path().substring(entityURI.path().lastIndexOf("/") + 1).replace(".entity", |
| ".dto"); |
| |
| IResource[] temp = new IResource[1]; |
| try { |
| getProject().accept(new IResourceVisitor() { |
| public boolean visit(IResource res) { |
| if (res instanceof IFile) { |
| if (res.getName().equals(dtoFileName)) { |
| temp[0] = res; |
| } |
| return true; |
| } else if (res instanceof IFolder) { |
| if (res.getName().equals("bin") || res.getName().equals("target")) { |
| return false; |
| } |
| return true; |
| } else if (res instanceof IProject) { |
| return true; |
| } |
| return false; |
| } |
| }); |
| } catch (CoreException e) { |
| LOGGER.warn("{}", e); |
| } |
| |
| IResource member = temp[0]; |
| return member; |
| } |
| |
| /** |
| * Find dto type. |
| * |
| * @param lSourceArtefact |
| * the l source artefact |
| * @param dtos |
| * the dtos |
| * @return the l type |
| */ |
| private LType findDtoType(LType lSourceArtefact, List<LType> dtos) { |
| for (LType lType : dtos) { |
| if (lType instanceof LDto) { |
| LDto lDto = (LDto) lType; |
| if (lDto.getWrappedType() == lSourceArtefact) { |
| return lDto; |
| } |
| } else if (lType instanceof LEnum) { |
| LEnum lEnum = (LEnum) lType; |
| if (lEnum.getName().equals(lSourceArtefact.getName())) { |
| return lEnum; |
| } |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Adds the dto to the package maching the packageName. |
| * |
| * @param packageName |
| * the package name |
| * @param newDto |
| * the new dto |
| * @param lDtoModel |
| * the l dto model |
| * @param entityPackage |
| * the entity package |
| */ |
| private void addDtoToPackage(String packageName, LType newDto, LDtoModel lDtoModel, LType wrappedType) { |
| |
| XImportSection section = lDtoModel.getImportSection(); |
| if (section == null) { |
| section = XtypeFactory.eINSTANCE.createXImportSection(); |
| lDtoModel.setImportSection(section); |
| } |
| |
| Optional<LTypedPackage> optPkg = lDtoModel.getPackages().stream() |
| .filter(p -> p.getName().equals(packageName)).findFirst(); |
| LTypedPackage pkg = null; |
| if (optPkg.isPresent()) { |
| pkg = optPkg.get(); |
| } |
| if (pkg == null) { |
| pkg = OSBPTypesFactory.eINSTANCE.createLTypedPackage(); |
| pkg.setName(packageName); |
| lDtoModel.getPackages().add(pkg); |
| } |
| |
| String typeName = entityNameProvider.getFullyQualifiedName(wrappedType).toString(); |
| |
| // check if typeName is imported |
| if (!containsImport(lDtoModel, typeName)) { |
| OXImportDeclaration lImport = OXtypeFactory.eINSTANCE.createOXImportDeclaration(); |
| lImport.setFqnImport(true); |
| lImport.setImportedFullyQualifiedName(typeName); |
| section.getImportDeclarations().add(lImport); |
| } |
| |
| pkg.getTypes().add(newDto); |
| } |
| |
| /** |
| * Contains import. |
| * |
| * @param model |
| * the pkg |
| * @param entityPackageImport |
| * the entity package import |
| * @return true, if successful |
| */ |
| private boolean containsImport(LDtoModel model, String typeFqn) { |
| if (model.getImportSection() == null) { |
| return false; |
| } |
| |
| for (XImportDeclaration lImport : model.getImportSection().getImportDeclarations()) { |
| OXImportDeclaration decl = (OXImportDeclaration) lImport; |
| if (decl.isFqnImport()) { |
| if (decl.getImportedFullyQualifiedName().equals(typeFqn.toString())) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Removes all inherited features and adds them again. |
| * |
| * @param lDto |
| * the l dto |
| * @param dtos |
| * the dtos |
| */ |
| private void fixFeatures(LDto lDto, List<LType> dtos) { |
| removeAllInheritedFeatures(lDto); |
| addInheritedFeaturesFromEntity(lDto, dtos); |
| } |
| |
| /** |
| * Removes all literals and add them again. |
| * |
| * @param lDtoEnum |
| * the l dto enum |
| */ |
| private void fixLiterals(LEnum lDtoEnum) { |
| lDtoEnum.getLiterals().clear(); |
| |
| LEnum entityEnum = (LEnum) SourceTypeStore.findSourceType(lDtoEnum); |
| for (LEnumLiteral literal : entityEnum.getLiterals()) { |
| lDtoEnum.getLiterals().add(EcoreUtil.copy(literal)); |
| } |
| } |
| |
| /** |
| * Adds all inherited features from the entity or bean. |
| * |
| * @param lDto |
| * the l dto |
| * @param dtos |
| * the dtos |
| */ |
| private void addInheritedFeaturesFromEntity(LDto lDto, List<LType> dtos) { |
| if (lDto.getWrappedType() instanceof LEntity) { |
| LEntity currentEntity = (LEntity) lDto.getWrappedType(); |
| // now add all features from the entity as inherited |
| // feature |
| |
| // also add features from supertype, if dto does not |
| // extend any dto. |
| List<LEntityFeature> features = lDto.getSuperType() == null ? currentEntity.getAllFeatures() |
| : currentEntity.getFeatures(); |
| for (LEntityFeature lEntityFeature : features) { |
| if (lEntityFeature instanceof LEntityAttribute) { |
| LDtoInheritedAttribute lNewAtt = OSBPDtoFactory.eINSTANCE.createLDtoInheritedAttribute(); |
| lNewAtt.setInheritedFeature((LAttribute) lEntityFeature); |
| LDtoFeature lAnnTarget = OSBPDtoFactory.eINSTANCE.createLDtoFeature(); |
| lNewAtt.setAnnotationInfo(lAnnTarget); |
| |
| LAttribute att = (LAttribute) lEntityFeature; |
| if (att.getType() instanceof LBean) { |
| // Mapped dto |
| LDto mapToDto = getMapToDto((LEntityAttribute) lEntityFeature, dtos); |
| if (mapToDto == null) { |
| LOGGER.error("No Mapping-DTO could be found for " + lEntityFeature.getEntity()); |
| continue; |
| } |
| lNewAtt.setType(mapToDto); |
| } |
| |
| lDto.getFeatures().add(lNewAtt); |
| } else if (lEntityFeature instanceof LEntityReference) { |
| // Mapped dto |
| LDto mapToDto = getMapToDto((LEntityReference) lEntityFeature, dtos); |
| if (mapToDto == null) { |
| LOGGER.error("No Mapping-DTO could be found for " + lEntityFeature.getEntity()); |
| continue; |
| } |
| |
| LDtoInheritedReference lNewRef = OSBPDtoFactory.eINSTANCE.createLDtoInheritedReference(); |
| lNewRef.setInheritedFeature((LReference) lEntityFeature); |
| LDtoFeature lAnnTarget = OSBPDtoFactory.eINSTANCE.createLDtoFeature(); |
| lNewRef.setAnnotationInfo(lAnnTarget); |
| lDto.getFeatures().add(lNewRef); |
| lNewRef.setType(mapToDto); |
| } |
| } |
| } else if (lDto.getWrappedType() instanceof LBean) { |
| LBean currentBean = (LBean) lDto.getWrappedType(); |
| // now add all features from the entity as inherited |
| // feature |
| |
| // also add features from supertype, if dto does not |
| // extend any dto. |
| List<LBeanFeature> features = lDto.getSuperType() == null ? currentBean.getAllFeatures() |
| : currentBean.getFeatures(); |
| for (LBeanFeature lBeanFeature : features) { |
| if (lBeanFeature instanceof LBeanAttribute) { |
| LDtoInheritedAttribute lNewAtt = OSBPDtoFactory.eINSTANCE.createLDtoInheritedAttribute(); |
| lNewAtt.setInheritedFeature((LAttribute) lBeanFeature); |
| LDtoFeature lAnnTarget = OSBPDtoFactory.eINSTANCE.createLDtoFeature(); |
| lNewAtt.setAnnotationInfo(lAnnTarget); |
| |
| LAttribute att = (LAttribute) lBeanFeature; |
| if (att.getType() instanceof LBean) { |
| // Mapped dto |
| LDto mapToDto = getMapToDto((LAttribute) lBeanFeature, dtos); |
| if (mapToDto == null) { |
| LOGGER.error("No Mapping-DTO could be found for " + att.getType()); |
| continue; |
| } |
| lNewAtt.setType(mapToDto); |
| } |
| |
| lDto.getFeatures().add(lNewAtt); |
| } else if (lBeanFeature instanceof LEntityReference) { |
| LDto mapToDto = getMapToDto((LEntityReference) lBeanFeature, dtos); |
| if (mapToDto == null) { |
| LOGGER.error("No Mapping-DTO could be found for " + lBeanFeature.getBean()); |
| continue; |
| } |
| |
| LDtoInheritedReference lNewRef = OSBPDtoFactory.eINSTANCE.createLDtoInheritedReference(); |
| lNewRef.setInheritedFeature((LReference) lBeanFeature); |
| LDtoFeature lAnnTarget = OSBPDtoFactory.eINSTANCE.createLDtoFeature(); |
| lNewRef.setAnnotationInfo(lAnnTarget); |
| lDto.getFeatures().add(lNewRef); |
| lNewRef.setType(mapToDto); |
| } else if (lBeanFeature instanceof LBeanReference) { |
| LDto mapToDto = getMapToDto((LBeanReference) lBeanFeature, dtos); |
| if (mapToDto == null) { |
| LOGGER.error("No Mapping-DTO could be found for " + lBeanFeature.getBean()); |
| continue; |
| } |
| |
| LDtoInheritedReference lNewRef = OSBPDtoFactory.eINSTANCE.createLDtoInheritedReference(); |
| lNewRef.setInheritedFeature((LReference) lBeanFeature); |
| LDtoFeature lAnnTarget = OSBPDtoFactory.eINSTANCE.createLDtoFeature(); |
| lNewRef.setAnnotationInfo(lAnnTarget); |
| lDto.getFeatures().add(lNewRef); |
| lNewRef.setType(mapToDto); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Removes all inherited features. |
| * |
| * @param lDto |
| * the l dto |
| */ |
| private void removeAllInheritedFeatures(LDto lDto) { |
| for (Iterator<LDtoFeature> iterator = lDto.getFeatures().iterator(); iterator.hasNext();) { |
| LDtoFeature lFeature = iterator.next(); |
| if ((lFeature instanceof LDtoInheritedAttribute) || (lFeature instanceof LDtoInheritedReference)) { |
| iterator.remove(); |
| } |
| } |
| } |
| |
| /** |
| * Gets the project resource set. |
| * |
| * @param uri |
| * the uri |
| * @return the project resource set |
| */ |
| private XtextResourceSet getProjectResourceSet(URI uri) { |
| IProject dtoProject = null; |
| Iterable<Pair<IStorage, IProject>> pairs = uriStorageMapper.getStorages(uri); |
| if (pairs.iterator().hasNext()) { |
| dtoProject = pairs.iterator().next().getSecond(); |
| } |
| |
| if (dtoProject == null) { |
| LOGGER.error("No project could be found for " + uri); |
| return null; |
| } |
| |
| XtextResourceSet resourceSet = (XtextResourceSet) rsProvider.get(dtoProject); |
| return resourceSet; |
| } |
| |
| /** |
| * Find entity ur is. |
| * |
| * @param lEntityModel |
| * the l entity model |
| * @return the sets the |
| */ |
| private Set<URI> findEntityURIs(LEntityModel lEntityModel) { |
| Set<URI> entityURIs = new HashSet<URI>(); |
| for (LTypedPackage lPkg : lEntityModel.getPackages()) { |
| for (LType lType : lPkg.getTypes()) { |
| if (lType instanceof LEntity || lType instanceof LBean) { |
| entityURIs.add(EcoreUtil.getURI(lType)); |
| } |
| } |
| } |
| return entityURIs; |
| } |
| |
| /** |
| * Collect entities. |
| * |
| * @param lEntityModel |
| * the l entity model |
| * @return the list |
| */ |
| private List<LType> collectEntities(LEntityModel lEntityModel) { |
| List<LType> entities = new ArrayList<LType>(); |
| for (LTypedPackage lPkg : lEntityModel.getPackages()) { |
| for (LType lType : lPkg.getTypes()) { |
| if (lType instanceof LEntity || lType instanceof LBean || lType instanceof LEnum) { |
| entities.add(lType); |
| } |
| } |
| } |
| return entities; |
| } |
| |
| /** |
| * Collect dtos. |
| * |
| * @param lDtoModel |
| * the l dto model |
| * @return the list |
| */ |
| private List<LType> collectDtos(LDtoModel lDtoModel) { |
| List<LType> dtos = new ArrayList<LType>(); |
| for (LTypedPackage lPkg : lDtoModel.getPackages()) { |
| for (LType lType : lPkg.getTypes()) { |
| if (lType instanceof LDto) { |
| LDto lDto = (LDto) lType; |
| if (lDto.getWrappedType() != null) { |
| dtos.add(lType); |
| } |
| } else if (lType instanceof LEnum) { |
| dtos.add(lType); |
| } |
| } |
| } |
| return dtos; |
| } |
| |
| /** |
| * Find target dto references. |
| * |
| * @param entityURIs |
| * the entity ur is |
| * @param resourceSet |
| * the resource set |
| * @return the list |
| */ |
| private List<IReferenceDescription> findTargetDtoReferences(Set<URI> entityURIs, ResourceSet resourceSet) { |
| final List<IReferenceDescription> targetDtoReferences = new ArrayList<IReferenceDescription>(); |
| referenceFinder.findAllReferences(entityURIs, new LocalResourceAccess(resourceSet), |
| new IAcceptor<IReferenceDescription>() { |
| @Override |
| public void accept(IReferenceDescription t) { |
| if (t.getEReference() == OSBPDtoPackage.Literals.LDTO__WRAPPED_TYPE) { |
| targetDtoReferences.add(t); |
| } |
| } |
| }, null); |
| return targetDtoReferences; |
| } |
| |
| // @SuppressWarnings("restriction") |
| // private List<IReferenceDescription> findTargetUiModelReferences( |
| // Set<URI> entityURIs) { |
| // final List<IReferenceDescription> targetUiModelReferences = new |
| // ArrayList<IReferenceDescription>(); |
| // referenceFinder.findAllReferences(entityURIs, null, |
| // new IAcceptor<IReferenceDescription>() { |
| // @Override |
| // public void accept(IReferenceDescription t) { |
| // if (t.getEReference() == |
| // UiModelPackage.Literals.UI_BEAN_SLOT__JVM_TYPE) |
| // { |
| // targetUiModelReferences.add(t); |
| // } |
| // } |
| // }, null); |
| // return targetUiModelReferences; |
| // } |
| |
| /** |
| * Returns the mapped DTO or <code>null</code>. |
| * |
| * @param lEntityFeature |
| * the l entity feature |
| * @param dtos |
| * the dtos |
| * @return the map to dto |
| */ |
| private LDto getMapToDto(LEntityReference lEntityFeature, List<LType> dtos) { |
| LEntity entity = lEntityFeature.getType(); |
| return (LDto) findDtoType(entity, dtos); |
| } |
| |
| private LDto getMapToDto(LAttribute lEntityFeature, List<LType> dtos) { |
| LScalarType entity = lEntityFeature.getType(); |
| return (LDto) findDtoType(entity, dtos); |
| } |
| |
| /** |
| * Returns the mapped DTO or <code>null</code>. |
| * |
| * @param lEntityFeature |
| * the l entity feature |
| * @param dtos |
| * the dtos |
| * @return the map to dto |
| */ |
| // private LDto getMapToDto(LBeanReference lEntityFeature, List<LType> |
| // dtos) { |
| // LEntity entity = (LEntity) lEntityFeature.getType(); |
| // return (LDto) findDtoType(entity, dtos); |
| // } |
| private LDto getMapToDto(LBeanReference lEntityFeature, List<LType> dtos) { |
| LType entity = (LType) lEntityFeature.getType(); |
| return (LDto) findDtoType(entity, dtos); |
| } |
| |
| /** |
| * Load semantic model. |
| * |
| * @param <A> |
| * the generic type |
| * @param modelURI |
| * the model uri |
| * @return the a |
| */ |
| @SuppressWarnings("unchecked") |
| private <A extends EObject> A loadSemanticModel(URI modelURI) { |
| // LOGGER.info("loading:" + file.getName()); |
| // org.eclipse.emf.common.util.URI modelURI = |
| // org.eclipse.emf.common.util.URI |
| // .createPlatformResourceURI(file.getFullPath().toString(), |
| // false); |
| XtextResourceSet rs = (XtextResourceSet) rsProvider.get(getProject()); |
| Resource resource = rs.getResource(modelURI, true); |
| try { |
| resource.load(null); |
| } catch (IOException e) { |
| e.printStackTrace(); |
| return null; |
| } |
| A semanticModel = null; |
| if (resource instanceof ISemanticLoadingResource) { |
| semanticModel = (A) ((ISemanticLoadingResource) resource).getSemanticElement(); |
| } else { |
| semanticModel = (A) resource.getContents().get(0); |
| } |
| |
| // LOGGER.info("finished loading:" + modelURI.getName()); |
| return semanticModel; |
| } |
| } |
| |
| /** |
| * The Class ServiceEnhancer. |
| */ |
| public class ServiceEnhancer { |
| |
| /** |
| * The Class ServiceEnhancerContext. |
| */ |
| private class ServiceEnhancerContext { |
| |
| /** The service resource. */ |
| private ISemanticLoadingResource serviceResource; |
| |
| /** The writeable resource set. */ |
| private ResourceSet writeableResourceSet; |
| } |
| |
| /** The rs provider. */ |
| @Inject |
| private XtextResourceSetProvider rsProvider; |
| |
| /** The reference finder. */ |
| @Inject |
| private IReferenceFinder referenceFinder; |
| |
| /** The uri storage mapper. */ |
| @Inject |
| private IStorage2UriMapper uriStorageMapper; |
| |
| /** |
| * Instantiates a new service enhancer. |
| */ |
| public ServiceEnhancer() { |
| |
| } |
| |
| /** |
| * This method touches UI and dialog models to ensure that the |
| * AutowireHelper is executed. |
| * |
| * @param tempLDtoModel |
| * the temp l dto model |
| */ |
| public void buildUiAndDialogModels(LDtoModel tempLDtoModel) { |
| |
| TimeLogger timeLogger = TimeLogger.start(getClass()); |
| |
| // find referencing dto model |
| Set<URI> dtoURIs = findDtoJvmTypeURIs(tempLDtoModel); |
| final Set<URI> uiModelURIs = findTargetUiAndDialogModelReferences( |
| dtoURIs, tempLDtoModel.eResource().getResourceSet()); |
| if (uiModelURIs.isEmpty()) { |
| return; |
| } |
| |
| Map<URI, XtextResourceSet> resourceSets = getProjectResourceSetMap(uiModelURIs); |
| for (URI uiModelURI : uiModelURIs) { |
| // create the proper dto resourceSet to save the dto |
| ResourceSet writeableResourceSet = resourceSets.get(uiModelURI); |
| if (writeableResourceSet == null) { |
| LOGGER.error("Can not save {} since resource set not available", uiModelURI); |
| continue; |
| } |
| |
| Resource uiModelResource = (Resource) writeableResourceSet.getResource(uiModelURI, true); |
| // ensures that the inferrer is invoked |
| uiModelResource.getContents(); |
| try { |
| Diagnostic diagnostic = Diagnostician.INSTANCE.validate(uiModelResource.getContents().get(0)); |
| int sev = diagnostic.getSeverity(); |
| if (sev <= Diagnostic.WARNING) { |
| uiModelResource.save(SaveOptions.newBuilder().format().getOptions().toOptionsMap()); |
| } else { |
| LOGGER.error(uiModelResource.getErrors().get(0).toString()); |
| } |
| uiModelResource.unload(); |
| } catch (IOException e) { |
| LOGGER.error("{}", e); |
| } |
| } |
| |
| timeLogger.stop(LOGGER, "Finished OSBPServiceBuilder#buildUiModels in "); |
| } |
| |
| /** |
| * Finds all target ui models that have a reference to one of the given |
| * dto JvmTypes. |
| * |
| * @param dtoJvmTypeURIs |
| * the dto jvm type ur is |
| * @param resourceSet |
| * the resource set |
| * @return the sets the |
| */ |
| private Set<URI> findTargetUiAndDialogModelReferences( |
| Set<URI> dtoJvmTypeURIs, ResourceSet resourceSet) { |
| final Set<URI> targetUiModelReferences = new HashSet<>(); |
| referenceFinder.findAllReferences(dtoJvmTypeURIs, new LocalResourceAccess(resourceSet), |
| new IAcceptor<IReferenceDescription>() { |
| @Override |
| public void accept(IReferenceDescription t) { |
| if (t.getSourceEObjectUri().fileExtension() |
| .equals("ui") |
| || t.getSourceEObjectUri().fileExtension() |
| .equals("dialog")) { |
| targetUiModelReferences.add(t |
| .getContainerEObjectURI() |
| .trimFragment()); |
| } |
| } |
| }, null); |
| return targetUiModelReferences; |
| } |
| |
| /** |
| * Builds the services. |
| * |
| * @param tempLDtoModel |
| * the temp l dto model |
| */ |
| public void buildServices(LDtoModel tempLDtoModel) { |
| IXtextUtilService service = CoreUiActivator.getDefault().getUtilService(); |
| if (service == null) { |
| LOGGER.error("Skipping dto build since IXtextUtilService is not available!"); |
| return; |
| } |
| |
| TimeLogger timeLogger = TimeLogger.start(getClass()); |
| |
| // |
| // we need to prepare a serviceResource and a writeableResourceSet |
| // |
| // find referencing service model |
| Set<URI> dtoURIs = findDtoURIs(tempLDtoModel); |
| final List<IReferenceDescription> targetServiceReferences = findTargetServiceReferences(dtoURIs, |
| tempLDtoModel.eResource().getResourceSet()); |
| |
| // ------- create the build context ------- |
| ServiceEnhancerContext context = createServiceBuildContext(tempLDtoModel, targetServiceReferences); |
| |
| ISemanticLoadingResource dtoResource = (ISemanticLoadingResource) context.writeableResourceSet |
| .getResource(tempLDtoModel.eResource().getURI(), true); |
| |
| List<LType> sourceArtifacts = collectDtos((LDtoModel) dtoResource.getSemanticElement()); |
| |
| List<LType> tempServices = collectServices((LServiceModel) context.serviceResource.getSemanticElement()); |
| |
| List<LType> servicesToPersist = new ArrayList<LType>(); |
| |
| // create all services -> no linking |
| // |
| Set<LTypedPackage> touchedPackages = new HashSet<LTypedPackage>(); |
| for (LType lType : sourceArtifacts) { |
| if (lType instanceof LDto) { |
| LDto lDto = (LDto) lType; |
| if (!(lDto.getWrappedType() instanceof LEntity)) { |
| continue; |
| } |
| |
| LEntity lEntity = (LEntity) lDto.getWrappedType(); |
| if (lEntity.isAbstract() || lEntity.isMappedSuperclass()) { |
| continue; |
| } |
| |
| LDTOService lService = findService(lDto, tempServices); |
| if (lService == null) { |
| lService = OSBPServiceFactory.eINSTANCE.createLDTOService(); |
| lService.setAnnotationInfo(OSBPServiceFactory.eINSTANCE.createLDTOService()); |
| lService.setInjectedServices(OSBPServiceFactory.eINSTANCE.createLInjectedServices()); |
| tempServices.add(lService); |
| } else { |
| // remove from package for a while |
| LTypedPackage lPkg = (LTypedPackage) lService.eContainer(); |
| lPkg.getTypes().remove(lService); |
| // collect all touched packages -> They need cleanup |
| // later |
| touchedPackages.add(lPkg); |
| } |
| lService.setName(getServiceName(lDto)); |
| lService.setDto(lDto); |
| |
| servicesToPersist.add(lService); |
| } |
| } |
| |
| // clean touched packages -> Also remove services that are not based |
| // on |
| // an dto anymore |
| for (LTypedPackage lPkg : touchedPackages) { |
| for (Iterator<LType> iterator = lPkg.getTypes().iterator(); iterator.hasNext();) { |
| LType lType = (LType) iterator.next(); |
| if (lType instanceof LDTOService) { |
| LDTOService lService = (LDTOService) lType; |
| if (lService.getDto() == null || lService.getDto().eIsProxy() |
| || !(lService.getDto().getWrappedType() instanceof LEntity)) { |
| iterator.remove(); |
| } |
| } |
| } |
| } |
| |
| // remove all services having no wrapped type anymore |
| // |
| for (LType lType : new ArrayList<>(servicesToPersist)) { |
| LDTOService lService = (LDTOService) lType; |
| if (lService.getDto() == null || lService.getDto().eIsProxy()) { |
| servicesToPersist.remove(lService); |
| } |
| } |
| |
| // fix features |
| // |
| for (LType lType : servicesToPersist) { |
| LDTOService lService = (LDTOService) lType; |
| LDto lDto = lService.getDto(); |
| // can never be a bean! |
| if (lDto.getWrappedType() instanceof LEntity) { |
| LEntity lEntity = (LEntity) lDto.getWrappedType(); |
| String pu = lEntity.getPersistenceUnit(); |
| if (pu != null && !pu.equals("")) { |
| lService.setMutablePersistenceId(true); |
| lService.setPersistenceId(pu); |
| } |
| } |
| } |
| |
| if (!servicesToPersist.isEmpty()) { |
| // add the services to the package in the proper order |
| // |
| Set<String> serviceNames = new HashSet<String>(); |
| for (LType lType : servicesToPersist) { |
| LDTOService lService = (LDTOService) lType; |
| |
| // filter dtos |
| if (serviceNames.contains(lService.getName())) { |
| // remove duplicate dtos |
| continue; |
| } else if (lService.getDto().eIsProxy()) { |
| // remove dto without a proper entity reference |
| continue; |
| } |
| serviceNames.add(lService.getName()); |
| |
| LTypedPackage lSourceTypePkg = (LTypedPackage) lService.getDto().eContainer(); |
| addServicesToPackage(getServicePackageName(lSourceTypePkg), lService, |
| (LServiceModel) context.serviceResource.getSemanticElement(), lService.getDto()); |
| } |
| |
| try { |
| Diagnostic diagnostic = Diagnostician.INSTANCE |
| .validate(context.serviceResource.getSemanticElement()); |
| int sev = diagnostic.getSeverity(); |
| if (sev <= Diagnostic.WARNING) { |
| context.serviceResource.save(SaveOptions.newBuilder().format().getOptions().toOptionsMap()); |
| } else { |
| LOGGER.error(context.serviceResource.getErrors().get(0).toString()); |
| } |
| context.serviceResource.unload(); |
| |
| // invoke the incremental build |
| // |
| needRebuild(); |
| } catch (IOException e) { |
| LOGGER.error("{}", e); |
| } |
| |
| timeLogger.stop(LOGGER, "Finished OSBPServiceBuilder#buildServices in "); |
| } |
| } |
| |
| /** |
| * Creates the service build context. |
| * |
| * @param tempLDtoModel |
| * the temp l dto model |
| * @param targetServiceReferences |
| * the target service references |
| * @return the service enhancer context |
| */ |
| private ServiceEnhancerContext createServiceBuildContext(LDtoModel tempLDtoModel, |
| final List<IReferenceDescription> targetServiceReferences) { |
| ServiceEnhancerContext context = new ServiceEnhancerContext(); |
| if (!targetServiceReferences.isEmpty()) { |
| // |
| // if we could find referenced dtos, then we use this |
| // information to |
| // create dtoResource and writeableResourceSet |
| // |
| |
| // access entity resource |
| ISemanticLoadingResource tempDtoResource = (ISemanticLoadingResource) tempLDtoModel.eResource(); |
| ResourceSet readonlyResourceSet = tempDtoResource.getResourceSet(); |
| |
| // access dto resource based on entityResourceSet |
| IReferenceDescription firstDesc = targetServiceReferences.get(0); |
| LService tempService = (LService) readonlyResourceSet.getEObject(firstDesc.getSourceEObjectUri(), true); |
| |
| // create the proper dto resourceSet to save the dto |
| context.writeableResourceSet = getProjectResourceSet(EcoreUtil.getURI(tempService)); |
| |
| // load the dtoResource based on the dto resourceSet |
| context.serviceResource = (ISemanticLoadingResource) context.writeableResourceSet |
| .getResource(EcoreUtil.getURI(tempService).trimFragment(), true); |
| } else { |
| URI dtoURI = EcoreUtil.getURI(tempLDtoModel); |
| // create the proper dto resourceSet to save the dto |
| context.writeableResourceSet = getProjectResourceSet(dtoURI); |
| |
| // try to find a file with extension .services in same project |
| IResource member = findServiceFile(dtoURI); |
| String serviceResourcePath = null; |
| if (member != null) { |
| serviceResourcePath = member.getFullPath().toString(); |
| } else { |
| // |
| // if we could not find referenced dtos, then we use the |
| // folder |
| // of |
| // the entity and put the dtos in there |
| // |
| // now create a dtoResource |
| |
| serviceResourcePath = org.eclipse.osbp.dsl.semantic.service.util.NamingConventionsUtil |
| .toServicePackage(dtoURI.path().replace("/resource", "")); |
| } |
| |
| URI serviceModelURI = URI.createPlatformResourceURI(serviceResourcePath, true); |
| context.serviceResource = (ISemanticLoadingResource) context.writeableResourceSet |
| .createResource(serviceModelURI); |
| context.serviceResource.getContents().add(OSBPServiceFactory.eINSTANCE.createLServiceModel()); |
| } |
| return context; |
| } |
| |
| private IResource findServiceFile(URI entityURI) { |
| String dtoFileName = entityURI.path().substring(entityURI.path().lastIndexOf("/") + 1).replace(".dto", |
| ".service"); |
| |
| IResource[] temp = new IResource[1]; |
| try { |
| getProject().accept(new IResourceVisitor() { |
| public boolean visit(IResource res) { |
| if (res instanceof IFile) { |
| if (res.getName().equals(dtoFileName)) { |
| temp[0] = res; |
| } |
| return true; |
| } else if (res instanceof IFolder) { |
| if (res.getName().equals("bin") || res.getName().equals("target")) { |
| return false; |
| } |
| return true; |
| } else if (res instanceof IProject) { |
| return true; |
| } |
| return false; |
| } |
| }); |
| } catch (CoreException e) { |
| LOGGER.warn("{}", e); |
| } |
| |
| IResource member = temp[0]; |
| return member; |
| } |
| |
| /** |
| * Find service. |
| * |
| * @param lDto |
| * the l dto |
| * @param services |
| * the services |
| * @return the LDTO service |
| */ |
| private LDTOService findService(LType lDto, List<LType> services) { |
| for (LType lType : services) { |
| if (lType instanceof LDTOService) { |
| LDTOService lService = (LDTOService) lType; |
| if (lService.getDto() == lDto) { |
| return lService; |
| } |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Gets the service package name. |
| * |
| * @param lTypePkg |
| * the l type pkg |
| * @return the service package name |
| */ |
| private String getServicePackageName(LTypedPackage lTypePkg) { |
| return lTypePkg.getName() + ".service"; |
| } |
| |
| /** |
| * Adds the service to the package maching the packageName. |
| * |
| * @param packageName |
| * the package name |
| * @param newService |
| * the new service |
| * @param lModel |
| * the l model |
| * @param dtoPackage |
| * the dto package |
| */ |
| private void addServicesToPackage(String packageName, LService newService, LServiceModel lModel, |
| LType dtoType) { |
| |
| XImportSection section = lModel.getImportSection(); |
| if (section == null) { |
| section = XtypeFactory.eINSTANCE.createXImportSection(); |
| lModel.setImportSection(section); |
| } |
| |
| Optional<LTypedPackage> optPkg = lModel.getPackages().stream().filter(p -> p.getName().equals(packageName)) |
| .findFirst(); |
| LTypedPackage pkg = null; |
| if (optPkg.isPresent()) { |
| pkg = optPkg.get(); |
| } |
| if (pkg == null) { |
| pkg = OSBPTypesFactory.eINSTANCE.createLTypedPackage(); |
| pkg.setName(packageName); |
| lModel.getPackages().add(pkg); |
| } |
| |
| String typeName = dtoNameProvider.getFullyQualifiedName(dtoType).toString(); |
| |
| // check if entityPackage is imported |
| if (!containsImport(lModel, typeName)) { |
| OXImportDeclaration lImport = OXtypeFactory.eINSTANCE.createOXImportDeclaration(); |
| lImport.setFqnImport(true); |
| lImport.setImportedFullyQualifiedName(typeName); |
| section.getImportDeclarations().add(lImport); |
| } |
| |
| pkg.getTypes().add(newService); |
| } |
| |
| /** |
| * Contains import. |
| * |
| * @param model |
| * the pkg |
| * @param entityPackageImport |
| * the entity package import |
| * @return true, if successful |
| */ |
| private boolean containsImport(LServiceModel model, String typeFqn) { |
| if (model.getImportSection() == null) { |
| return false; |
| } |
| |
| for (XImportDeclaration lImport : model.getImportSection().getImportDeclarations()) { |
| OXImportDeclaration decl = (OXImportDeclaration) lImport; |
| if (decl.isFqnImport()) { |
| if (decl.getImportedFullyQualifiedName().equals(typeFqn.toString())) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Gets the service name. |
| * |
| * @param lType |
| * the l type |
| * @return the service name |
| */ |
| private String getServiceName(LDto lType) { |
| return org.eclipse.osbp.dsl.semantic.service.util.NamingConventionsUtil.toServiceName(lType); |
| } |
| |
| /** |
| * Gets the project resource set. |
| * |
| * @param uri |
| * the uri |
| * @return the project resource set |
| */ |
| private XtextResourceSet getProjectResourceSet(URI uri) { |
| IProject dtoProject = null; |
| Iterable<Pair<IStorage, IProject>> pairs = uriStorageMapper.getStorages(uri); |
| if (pairs.iterator().hasNext()) { |
| dtoProject = pairs.iterator().next().getSecond(); |
| } |
| |
| if (dtoProject == null) { |
| LOGGER.error("No project could be found for " + uri); |
| return null; |
| } |
| |
| XtextResourceSet resourceSet = (XtextResourceSet) rsProvider.get(dtoProject); |
| return resourceSet; |
| } |
| |
| /** |
| * Creates a map with a resource set for each uri. Ensures, that |
| * resource sets are reused by project to enhance performance. |
| * |
| * @param uris |
| * the uris |
| * @return the project resource set map |
| */ |
| private Map<URI, XtextResourceSet> getProjectResourceSetMap(Set<URI> uris) { |
| IProject project = null; |
| Map<IProject, XtextResourceSet> byProject = new HashMap<>(); |
| Map<URI, XtextResourceSet> result = new HashMap<>(); |
| for (URI uri : uris) { |
| Iterable<Pair<IStorage, IProject>> pairs = uriStorageMapper.getStorages(uri); |
| if (pairs.iterator().hasNext()) { |
| project = pairs.iterator().next().getSecond(); |
| } |
| |
| if (project == null) { |
| LOGGER.error("No project could be found for " + uri); |
| continue; |
| } |
| |
| if (byProject.containsKey(project)) { |
| // same projects use shared resource set |
| result.put(uri, byProject.get(project)); |
| } else { |
| XtextResourceSet resourceSet = (XtextResourceSet) rsProvider.get(project); |
| byProject.put(project, resourceSet); |
| result.put(uri, resourceSet); |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * Find dto ur is. |
| * |
| * @param lDtoModel |
| * the l dto model |
| * @return the sets the |
| */ |
| private Set<URI> findDtoURIs(LDtoModel lDtoModel) { |
| Set<URI> dtoURIs = new HashSet<URI>(); |
| for (LTypedPackage lPkg : lDtoModel.getPackages()) { |
| for (LType lType : lPkg.getTypes()) { |
| if (lType instanceof LDto) { |
| dtoURIs.add(EcoreUtil.getURI(lType)); |
| } |
| } |
| } |
| return dtoURIs; |
| } |
| |
| /** |
| * Iterates all dtos in the model and creates the URIs for their |
| * JvmTypes. |
| * |
| * @param lDtoModel |
| * the l dto model |
| * @return the sets the |
| */ |
| private Set<URI> findDtoJvmTypeURIs(LDtoModel lDtoModel) { |
| Set<URI> dtoURIs = new HashSet<URI>(); |
| |
| IXtextUtilService service = CoreUiActivator.getDefault().getUtilService(); |
| for (LTypedPackage lPkg : lDtoModel.getPackages()) { |
| for (LType lType : lPkg.getTypes()) { |
| if (lType instanceof LDto) { |
| for (IEObjectDescription desc : service.getEObjectDescriptions(TypesPackage.Literals.JVM_TYPE, |
| toFqn(lType))) { |
| dtoURIs.add(desc.getEObjectURI()); |
| } |
| } |
| } |
| } |
| return dtoURIs; |
| } |
| |
| /** |
| * Returns the fully qualified name for the given type. |
| * |
| * @param lType |
| * the l type |
| * @return the string |
| */ |
| private String toFqn(LType lType) { |
| LTypedPackage pkg = (LTypedPackage) lType.eContainer(); |
| return pkg.getName() + "." + lType.getName(); |
| } |
| |
| /** |
| * Collect dtos. |
| * |
| * @param lDtoModel |
| * the l dto model |
| * @return the list |
| */ |
| private List<LType> collectDtos(LDtoModel lDtoModel) { |
| List<LType> dtos = new ArrayList<LType>(); |
| for (LTypedPackage lPkg : lDtoModel.getPackages()) { |
| for (LType lType : lPkg.getTypes()) { |
| if (lType instanceof LDto) { |
| LDto lDto = (LDto) lType; |
| if (lDto.getWrappedType() != null) { |
| dtos.add(lType); |
| } |
| } |
| } |
| } |
| return dtos; |
| } |
| |
| /** |
| * Collect services. |
| * |
| * @param lServiceModel |
| * the l service model |
| * @return the list |
| */ |
| private List<LType> collectServices(LServiceModel lServiceModel) { |
| List<LType> services = new ArrayList<LType>(); |
| for (LTypedPackage lPkg : lServiceModel.getPackages()) { |
| for (LType lType : lPkg.getTypes()) { |
| if (lType instanceof LService) { |
| services.add(lType); |
| } |
| } |
| } |
| return services; |
| } |
| |
| /** |
| * Find target service references. |
| * |
| * @param dtoURIs |
| * the dto ur is |
| * @param resourceSet |
| * the resource set |
| * @return the list |
| */ |
| private List<IReferenceDescription> findTargetServiceReferences(Set<URI> dtoURIs, ResourceSet resourceSet) { |
| final List<IReferenceDescription> targetServiceReferences = new ArrayList<IReferenceDescription>(); |
| referenceFinder.findAllReferences(dtoURIs, new LocalResourceAccess(resourceSet), |
| new IAcceptor<IReferenceDescription>() { |
| @Override |
| public void accept(IReferenceDescription t) { |
| if (t.getEReference() == OSBPServicePackage.Literals.LDTO_SERVICE__DTO) { |
| targetServiceReferences.add(t); |
| } |
| } |
| }, null); |
| return targetServiceReferences; |
| } |
| |
| /** |
| * Load semantic model. |
| * |
| * @param <A> |
| * the generic type |
| * @param modelURI |
| * the model uri |
| * @return the a |
| */ |
| @SuppressWarnings("unchecked") |
| private <A extends EObject> A loadSemanticModel(URI modelURI) { |
| XtextResourceSet rs = (XtextResourceSet) rsProvider.get(getProject()); |
| Resource resource = rs.getResource(modelURI, true); |
| try { |
| resource.load(null); |
| } catch (IOException e) { |
| e.printStackTrace(); |
| return null; |
| } |
| A semanticModel = null; |
| if (resource instanceof ISemanticLoadingResource) { |
| semanticModel = (A) ((ISemanticLoadingResource) resource).getSemanticElement(); |
| } else { |
| semanticModel = (A) resource.getContents().get(0); |
| } |
| |
| LOGGER.info("finished loading:" + modelURI); |
| return semanticModel; |
| } |
| |
| /** |
| * Clean. |
| * |
| * @param monitor |
| * the monitor |
| * @throws CoreException |
| * the core exception |
| */ |
| protected void clean(IProgressMonitor monitor) throws CoreException { |
| } |
| } |
| |
| /** |
| * The Class SourceTypeStore. |
| */ |
| private static class SourceTypeStore extends AdapterImpl { |
| |
| /** The source type. */ |
| private final LType sourceType; |
| |
| /** The adapted. */ |
| private final LType adapted; |
| |
| /** |
| * Instantiates a new source type store. |
| * |
| * @param sourceType |
| * the source type |
| * @param adapted |
| * the adapted |
| */ |
| public SourceTypeStore(LType sourceType, LType adapted) { |
| super(); |
| this.sourceType = sourceType; |
| this.adapted = adapted; |
| |
| adapted.eAdapters().add(this); |
| } |
| |
| /** |
| * Dispose. |
| */ |
| public void dispose() { |
| adapted.eAdapters().remove(this); |
| } |
| |
| /** |
| * Find source type. |
| * |
| * @param adapted |
| * the adapted |
| * @return the l type |
| */ |
| public static LType findSourceType(LType adapted) { |
| for (Adapter adapter : adapted.eAdapters()) { |
| if (adapter instanceof SourceTypeStore) { |
| SourceTypeStore store = (SourceTypeStore) adapter; |
| return store.sourceType; |
| } |
| } |
| return null; |
| } |
| |
| } |
| |
| /** |
| * The Class LocalResourceAccess. |
| */ |
| public static class LocalResourceAccess implements IReferenceFinder.ILocalResourceAccess { |
| |
| /** The resource set. */ |
| private ResourceSet resourceSet; |
| |
| /** |
| * Instantiates a new local resource access. |
| * |
| * @param resourceSet |
| * the resource set |
| */ |
| public LocalResourceAccess(ResourceSet resourceSet) { |
| this.resourceSet = resourceSet; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.xtext.findReferences.IReferenceFinder.IResourceAccess |
| * #readOnly(org.eclipse.emf.common.util.URI, |
| * org.eclipse.xtext.util.concurrent.IUnitOfWork) |
| */ |
| 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); |
| } |
| } |
| |
| } |
| |
| private static class Pending { |
| |
| // if empty, then pending was triggered for initial build |
| public final IResourceDescription desc; |
| |
| public final URI uri; |
| |
| public Pending(IResourceDescription desc) { |
| this.desc = desc; |
| this.uri = desc.getURI(); |
| } |
| |
| public Pending(URI uri) { |
| this.desc = null; |
| this.uri = uri; |
| } |
| |
| } |
| } |