Skip to content

Commit

Permalink
[697] Add queryBasedInt into EditingContext GraphQL API.
Browse files Browse the repository at this point in the history
Bug: #697
Signed-off-by: Florian Barbin <[email protected]>
  • Loading branch information
florianbarbin committed Aug 26, 2021
1 parent 5346286 commit f156706
Show file tree
Hide file tree
Showing 10 changed files with 554 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*******************************************************************************
* Copyright (c) 2021 Obeo.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.sirius.web.emf.query;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import org.eclipse.emf.ecore.EPackage;
import org.eclipse.sirius.web.core.api.ErrorPayload;
import org.eclipse.sirius.web.core.api.IEditingContext;
import org.eclipse.sirius.web.core.api.IPayload;
import org.eclipse.sirius.web.emf.services.IEditingContextEPackageService;
import org.eclipse.sirius.web.interpreter.AQLInterpreter;
import org.eclipse.sirius.web.interpreter.Result;
import org.eclipse.sirius.web.spring.collaborative.api.IQueryService;
import org.eclipse.sirius.web.spring.collaborative.handlers.QueryBasedIntInput;
import org.eclipse.sirius.web.spring.collaborative.handlers.QueryBasedIntSuccessPayload;
import org.springframework.stereotype.Service;

/**
* A specific implementation of {@link IQueryService} for EMF.
*
* @author fbarbin
*/
@Service
public class EMFQueryService implements IQueryService {

private final IEditingContextEPackageService editingContextEPackageService;

public EMFQueryService(IEditingContextEPackageService editingContextEPackageService) {
this.editingContextEPackageService = Objects.requireNonNull(editingContextEPackageService);
}

@Override
public IPayload execute(IEditingContext editingContext, QueryBasedIntInput input) {
List<Class<?>> classes = List.of(EditingContextServices.class);
List<EPackage> ePackages = this.editingContextEPackageService.getEPackages(editingContext.getId());

Map<String, Object> variables = new HashMap<>();
variables.put(IEditingContext.EDITING_CONTEXT, editingContext);

var interpreter = new AQLInterpreter(classes, ePackages);
String query = input.getQuery();
Result result = interpreter.evaluateExpression(variables, query);

if (result.asInt().isPresent()) {
return new QueryBasedIntSuccessPayload(input.getId(), result.asInt().getAsInt());
} else {
return new ErrorPayload(input.getId(), "An error occured while evaluation the expression. Status : " + result.getStatus()); //$NON-NLS-1$
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*******************************************************************************
* Copyright (c) 2021 Obeo.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.sirius.web.emf.query;

import java.util.Collection;
import java.util.Collections;
import java.util.Optional;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.sirius.web.annotations.Immutable;
import org.eclipse.sirius.web.core.api.IEditingContext;
import org.eclipse.sirius.web.emf.services.EditingContext;

/**
* An utility class providing various query services.
*
* @author fbarbin
*/
@Immutable
public final class EditingContextServices {

private EditingContextServices() {

}

public static Collection<EObject> eAllContents(IEditingContext editingContext) {
//@formatter:off
var resourceSet = Optional.of(editingContext)
.filter(EditingContext.class::isInstance)
.map(EditingContext.class::cast)
.map(EditingContext::getDomain)
.map(EditingDomain::getResourceSet)
.orElse(null);
//@formatter:on
if (resourceSet != null) {
//@formatter:off
return resourceSet.getResources().stream()
.flatMap(EditingContextServices::collectAllContent)
.collect(Collectors.toList());
//@formatter:on
} else {
return Collections.emptyList();
}
}

private static Stream<EObject> collectAllContent(Resource resource) {
Spliterator<EObject> spliterator = Spliterators.spliteratorUnknownSize(resource.getAllContents(), Spliterator.ORDERED);
return StreamSupport.stream(spliterator, false);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*******************************************************************************
* Copyright (c) 2021 Obeo.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.sirius.web.emf.query;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.List;
import java.util.UUID;

import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EcoreFactory;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl;
import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
import org.eclipse.sirius.web.core.api.IEditingContext;
import org.eclipse.sirius.web.core.api.IPayload;
import org.eclipse.sirius.web.emf.services.EditingContext;
import org.eclipse.sirius.web.emf.services.EditingDomainFactory;
import org.eclipse.sirius.web.emf.services.IEditingContextEPackageService;
import org.eclipse.sirius.web.spring.collaborative.api.IQueryService;
import org.eclipse.sirius.web.spring.collaborative.handlers.QueryBasedIntInput;
import org.eclipse.sirius.web.spring.collaborative.handlers.QueryBasedIntSuccessPayload;
import org.junit.jupiter.api.Test;

/**
* Unit tests for {@link EMFQueryService}.
*
* @author fbarbin
*/
public class EMFQueryServiceTests {

@Test
public void testEMFQueryService() {

IEditingContext editingContext = this.createEditingContext();

IEditingContextEPackageService editingContextEPackageService = new IEditingContextEPackageService() {

@Override
public List<EPackage> getEPackages(UUID editingContextId) {
return List.of(EcorePackage.eINSTANCE);
}
};
IQueryService queryService = new EMFQueryService(editingContextEPackageService);

QueryBasedIntInput input = new QueryBasedIntInput(UUID.randomUUID(), "aql:editingContext.eAllContents()->size()"); //$NON-NLS-1$
IPayload payload = queryService.execute(editingContext, input);
assertTrue(payload instanceof QueryBasedIntSuccessPayload);
assertEquals(8, ((QueryBasedIntSuccessPayload) payload).getResult().intValue());
}

private IEditingContext createEditingContext() {
Resource resource = this.createResourceWith4Elements();
Resource resource2 = this.createResourceWith4Elements();
AdapterFactoryEditingDomain editingDomain = new EditingDomainFactory().create(resource, resource2);
return new EditingContext(UUID.randomUUID(), editingDomain);
}

private Resource createResourceWith4Elements() {
Resource resource = new XMIResourceImpl();
EPackage ePackage = EcoreFactory.eINSTANCE.createEPackage();
EClass class1 = EcoreFactory.eINSTANCE.createEClass();
EClass class2 = EcoreFactory.eINSTANCE.createEClass();
EClass class3 = EcoreFactory.eINSTANCE.createEClass();
ePackage.getEClassifiers().addAll(List.of(class1, class2, class3));
resource.getContents().add(ePackage);
return resource;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*******************************************************************************
* Copyright (c) 2019, 2021 Obeo.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.sirius.web.emf.services;

import org.eclipse.emf.common.command.BasicCommandStack;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.impl.EPackageRegistryImpl;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.util.ECrossReferenceAdapter;
import org.eclipse.emf.ecore.util.EcoreAdapterFactory;
import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
import org.eclipse.emf.edit.provider.ReflectiveItemProviderAdapterFactory;

/**
* Service used to create an editing domain for the unit tests.
*
* @author sbegaudeau
*/
public class EditingDomainFactory {
public AdapterFactoryEditingDomain create(Resource... resources) {
ComposedAdapterFactory composedAdapterFactory = new ComposedAdapterFactory();
composedAdapterFactory.addAdapterFactory(new EcoreAdapterFactory());
composedAdapterFactory.addAdapterFactory(new ReflectiveItemProviderAdapterFactory());

EPackage.Registry ePackageRegistry = new EPackageRegistryImpl();
ePackageRegistry.put(EcorePackage.eINSTANCE.getNsURI(), EcorePackage.eINSTANCE);

ResourceSet resourceSet = new ResourceSetImpl();
for (Resource resource : resources) {
resourceSet.getResources().add(resource);
}
resourceSet.setPackageRegistry(ePackageRegistry);
resourceSet.eAdapters().add(new ECrossReferenceAdapter());

AdapterFactoryEditingDomain editingDomain = new AdapterFactoryEditingDomain(composedAdapterFactory, new BasicCommandStack(), resourceSet);
return editingDomain;
}

public AdapterFactoryEditingDomain create() {
return this.create(new Resource[0]);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*******************************************************************************
* Copyright (c) 2021 Obeo.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.sirius.web.spring.collaborative.api;

import org.eclipse.sirius.web.core.api.IEditingContext;
import org.eclipse.sirius.web.core.api.IPayload;
import org.eclipse.sirius.web.spring.collaborative.handlers.QueryBasedIntInput;

/**
* Common interface for services capable of executing a Query.
*
* @author fbarbin
*/
public interface IQueryService {
IPayload execute(IEditingContext editingContext, QueryBasedIntInput input);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*******************************************************************************
* Copyright (c) 2021 Obeo.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.sirius.web.spring.collaborative.handlers;

import java.util.Objects;

import org.eclipse.sirius.web.core.api.ErrorPayload;
import org.eclipse.sirius.web.core.api.IEditingContext;
import org.eclipse.sirius.web.core.api.IInput;
import org.eclipse.sirius.web.core.api.IPayload;
import org.eclipse.sirius.web.spring.collaborative.api.ChangeDescription;
import org.eclipse.sirius.web.spring.collaborative.api.ChangeKind;
import org.eclipse.sirius.web.spring.collaborative.api.EventHandlerResponse;
import org.eclipse.sirius.web.spring.collaborative.api.IEditingContextEventHandler;
import org.eclipse.sirius.web.spring.collaborative.api.IQueryService;
import org.eclipse.sirius.web.spring.collaborative.api.Monitoring;
import org.eclipse.sirius.web.spring.collaborative.messages.ICollaborativeMessageService;
import org.springframework.stereotype.Service;

import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;

/**
* Handler used to execute query based int.
*
* @author fbarbin
*/
@Service
public class QueryBasedIntEventHandler implements IEditingContextEventHandler {

private final IQueryService queryService;

private final ICollaborativeMessageService messageService;

private final Counter counter;

public QueryBasedIntEventHandler(ICollaborativeMessageService messageService, MeterRegistry meterRegistry, IQueryService queryService) {
this.messageService = Objects.requireNonNull(messageService);
this.queryService = Objects.requireNonNull(queryService);

// @formatter:off
this.counter = Counter.builder(Monitoring.EVENT_HANDLER)
.tag(Monitoring.NAME, this.getClass().getSimpleName())
.register(meterRegistry);
// @formatter:on
}

@Override
public boolean canHandle(IInput input) {
return input instanceof QueryBasedIntInput;
}

@Override
public EventHandlerResponse handle(IEditingContext editingContext, IInput input) {
this.counter.increment();
String message = this.messageService.invalidInput(input.getClass().getSimpleName(), QueryBasedIntInput.class.getSimpleName());
ChangeDescription changeDescription = new ChangeDescription(ChangeKind.NOTHING, editingContext.getId());
if (input instanceof QueryBasedIntInput) {
QueryBasedIntInput createChildInput = (QueryBasedIntInput) input;
IPayload payload = this.queryService.execute(editingContext, createChildInput);
return new EventHandlerResponse(changeDescription, payload);
}
ErrorPayload errorPayload = new ErrorPayload(input.getId(), message);
return new EventHandlerResponse(changeDescription, errorPayload);
}
}
Loading

0 comments on commit f156706

Please sign in to comment.