blob: b1a408201aa2fcb858299b39f740d52538a60f9b [file] [log] [blame]
/**
* 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.LFeature;
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.LState;
import org.eclipse.osbp.dsl.semantic.common.types.LStateClass;
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.LDtoAttribute;
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.LServiceOperation;
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.common.types.util.TypeReferences;
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;
/**
* 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 static final String MODELS_BASE_SRC_DIRECTORY = "models";
public static final 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;
/**
* 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;
}
});
for (Iterator<Pending> iterator = pending.iterator(); iterator.hasNext();) {
Pending pending = iterator.next();
try {
String fileExtension = pending.uri.fileExtension();
switch (fileExtension) {
case "entity":
LEntityModel lentity = dtoBuilder.loadSemanticModel(pending.uri);
if (lentity != null) {
dtoBuilder.buildDtos(lentity);
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);
}
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();
if(!contains(uri) && ("entity".equals(fileExtension) || "dto".equals(fileExtension))) {
pending.add(new Pending(uri));
}
}
}
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 LStateClass) {
LStateClass lSourceType = (LStateClass) lType;
LStateClass lDtoType = (LStateClass) findDtoType(lSourceType, tempDtos);
if (lDtoType == null) {
lDtoType = OSBPTypesFactory.eINSTANCE.createLStateClass();
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));
} 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 LStateClass) {
LStateClass lDtoStateClass = (LStateClass) lType;
fixStates(lDtoStateClass);
} 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 LStateClass) {
LStateClass lStateClass = (LStateClass) lType;
// filter dtos
if (dtoNames.contains(lStateClass.getName())) {
// remove duplicate enums
continue;
}
dtoNames.add(lStateClass.getName());
LStateClass sourceType = (LStateClass) SourceTypeStore.findSourceType(lStateClass);
LTypedPackage lSourceTypePkg = (LTypedPackage) sourceType.eContainer();
addDtoToPackage(NamingConventionsUtil.toDtoPackage(lSourceTypePkg), lStateClass,
(LDtoModel) context.dtoResource.getSemanticElement(), sourceType);
} 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 LStateClass) {
LStateClass lStateClass = (LStateClass) lType;
if (lStateClass.getName().equals(lSourceArtefact.getName())) {
return lStateClass;
}
} 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));
}
}
/**
* Removes all states and add them again.
*
* @param lDtoStateClass
* the l dto enum
*/
private void fixStates(LStateClass lDtoStateClass) {
lDtoStateClass.getStates().clear();
LStateClass entityEnum = (LStateClass) SourceTypeStore.findSourceType(lDtoStateClass);
for (LState state : entityEnum.getStates()) {
lDtoStateClass.getStates().add(EcoreUtil.copy(state));
}
}
/**
* 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);
}
}
// handle stateclass
if (currentEntity.getStateClass() != null) {
LDtoAttribute lNewAtt = OSBPDtoFactory.eINSTANCE.createLDtoAttribute();
lNewAtt.setName(NamingConventionsUtil.toFirstLower(currentEntity.getStateClass().getName()));
LDtoFeature lAnnTarget = OSBPDtoFactory.eINSTANCE.createLDtoFeature();
lNewAtt.setAnnotationInfo(lAnnTarget);
lNewAtt.setType(currentEntity.getStateClass());
lDto.getFeatures().add(lNewAtt);
}
} 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 LDtoAttribute && ((LDtoAttribute) lFeature).getType() instanceof LStateClass) {
iterator.remove();
}
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
|| lType instanceof LStateClass) {
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 LStateClass) {
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.
*/
public class ServiceEnhancerContext {
/** The service resource. */
public ISemanticLoadingResource serviceResource;
/** The writeable resource set. */
public 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<>();
List<LType> stateClasses = new ArrayList<>();
final IResourceServiceProvider servicesResourceServiceProvider = IResourceServiceProvider.Registry.INSTANCE
.getResourceServiceProvider(context.serviceResource.getURI());
TypeReferences typeRefs = servicesResourceServiceProvider.get(TypeReferences.class);
// 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);
} else if (lType instanceof LStateClass) {
stateClasses.add(lType);
}
}
// 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 operations if entity not longer having stateClass
List<LServiceOperation> toBeRemoved = new ArrayList<>();
for(LServiceOperation op:lService.getOperations()) {
if(lService.getDto().getWrappedType() instanceof LEntity && ((LEntity)lService.getDto().getWrappedType()).getStateClass() == null) {
toBeRemoved.add(op);
}
}
for(LServiceOperation op : toBeRemoved) {
lService.getOperations().remove(op);
}
}
}
}
// 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
//
ServiceEnhancerHelper serviceEnhancerHelper = new ServiceEnhancerHelper(dtoNameProvider, context, typeRefs);
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);
}
// handle state class
if (lEntity.getStateClass() != null) {
for (LFeature f : lDto.getAllFeatures()) {
if (f instanceof LDtoAttribute && stateClasses.contains(((LDtoAttribute) f).getType())) {
serviceEnhancerHelper.createStateClassMethods(lService, lDto, (LDtoAttribute) f);
break;
}
}
}
}
}
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());
addServicesToPackage(serviceEnhancerHelper.getServicePackageName(lService.getDto()), lService,
(LServiceModel) context.serviceResource.getSemanticElement(), lService.getDto(), stateClasses);
}
try {
Diagnostic diagnostic = Diagnostician.INSTANCE
.validate(context.serviceResource.getSemanticElement());
int sev = diagnostic.getSeverity();
// we must cheat here because I couldn't find out why the new operations cause a severity without error messages
// TODO: somebody should fix this later
sev = 0;
if (sev <= Diagnostic.WARNING) {
context.serviceResource.save(SaveOptions.newBuilder().format().getOptions().toOptionsMap());
} else {
if (!context.serviceResource.getErrors().isEmpty()) {
LOGGER.error(context.serviceResource.getErrors().get(0).toString());
} else {
LOGGER.error("unknown diagnostic error");
}
}
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;
}
/**
* 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, List<LType> stateClasses) {
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);
}
for(LType stateClass:stateClasses) {
String stateClassName = dtoNameProvider.getFullyQualifiedName(stateClass).toString();
if (!containsImport(lModel, stateClassName)) {
OXImportDeclaration lImport = OXtypeFactory.eINSTANCE.createOXImportDeclaration();
lImport.setFqnImport(true);
lImport.setImportedFullyQualifiedName(stateClassName);
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);
}
} else if (lType instanceof LStateClass) {
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;
}
}
}