All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.contextmapper.dsl.refactoring.DeriveBoundedContextFromSubdomains Maven / Gradle / Ivy

/*
 * Copyright 2020 The Context Mapper Project Team
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.contextmapper.dsl.refactoring;

import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import org.contextmapper.dsl.contextMappingDSL.Aggregate;
import org.contextmapper.dsl.contextMappingDSL.BoundedContext;
import org.contextmapper.dsl.contextMappingDSL.BoundedContextType;
import org.contextmapper.dsl.contextMappingDSL.ContextMappingDSLFactory;
import org.contextmapper.dsl.contextMappingDSL.Domain;
import org.contextmapper.dsl.contextMappingDSL.DomainPart;
import org.contextmapper.dsl.contextMappingDSL.Subdomain;
import org.contextmapper.dsl.refactoring.exception.RefactoringInputException;
import org.contextmapper.tactic.dsl.tacticdsl.Attribute;
import org.contextmapper.tactic.dsl.tacticdsl.ComplexType;
import org.contextmapper.tactic.dsl.tacticdsl.Entity;
import org.contextmapper.tactic.dsl.tacticdsl.Parameter;
import org.contextmapper.tactic.dsl.tacticdsl.Service;
import org.contextmapper.tactic.dsl.tacticdsl.ServiceOperation;
import org.contextmapper.tactic.dsl.tacticdsl.TacticdslFactory;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

public class DeriveBoundedContextFromSubdomains extends AbstractRefactoring implements Refactoring {

	private Set subdomainIds = Sets.newHashSet();
	private String boundedContextName;

	public DeriveBoundedContextFromSubdomains(String boundedContextName, Set subdomainIds) {
		this.boundedContextName = boundedContextName;
		this.subdomainIds = subdomainIds;
	}

	@Override
	protected void doRefactor() {
		Set selectedSubdomains = collectSubdomains();
		if (selectedSubdomains.isEmpty())
			throw new RefactoringInputException("Please provide at least one subdomain name that can be found in the given CML model.");

		BoundedContext newBC = ContextMappingDSLFactory.eINSTANCE.createBoundedContext();
		newBC.setName(getUniqueBoundedContextName(boundedContextName));
		newBC.setDomainVisionStatement(
				"This Bounded Context realizes the following subdomains: " + String.join(", ", selectedSubdomains.stream().map(sd -> sd.getName()).collect(Collectors.toList())));
		newBC.setType(BoundedContextType.FEATURE);
		for (Subdomain subdomain : selectedSubdomains) {
			addElementToEList(newBC.getImplementedDomainParts(), (DomainPart) subdomain);
			createAggregate4Subdomain(subdomain, newBC);
		}

		addElementToEList(rootResource.getContextMappingModel().getBoundedContexts(), newBC);
		markResourceChanged(rootResource);

		saveResources();
	}

	private void createAggregate4Subdomain(Subdomain subdomain, BoundedContext newBC) {
		Aggregate aggregate = ContextMappingDSLFactory.eINSTANCE.createAggregate();
		aggregate.setName(subdomain.getName() + "Aggregate");
		aggregate.setComment("/* This Aggregate contains the entities and services of the '" + subdomain.getName() + "' subdomain." + System.lineSeparator()
				+ "	 * TODO: You can now refactor the Aggregate, for example by using the 'Split Aggregate by Entities' architectural refactoring." + System.lineSeparator()
				+ "	 * TODO: Add attributes and operations to the entities." + System.lineSeparator()
				+ "	 * TODO: Add operations to the services." + System.lineSeparator()
				+ "	 * Find examples and further instructions on our website: https://contextmapper.org/docs/rapid-ooad/ */");

		createEntities(subdomain, aggregate);
		createServices(subdomain, aggregate);

		addElementToEList(newBC.getAggregates(), aggregate);
	}

	private void createEntities(Subdomain subdomain, Aggregate aggregate) {
		for (Entity entity : subdomain.getEntities()) {
			Entity newEntity = TacticdslFactory.eINSTANCE.createEntity();
			newEntity.setName(entity.getName());
			newEntity.setAggregateRoot(false);

			Attribute idAttribute = TacticdslFactory.eINSTANCE.createAttribute();
			idAttribute.setType(entity.getName() + "ID");
			idAttribute.setName(entity.getName().toLowerCase() + "Id");

			addElementToEList(newEntity.getAttributes(), idAttribute);
			addElementToEList(aggregate.getDomainObjects(), newEntity);
		}
	}

	private void createServices(Subdomain subdomain, Aggregate aggregate) {
		for (Service service : subdomain.getServices()) {
			Service newService = TacticdslFactory.eINSTANCE.createService();
			newService.setName(service.getName());
			newService.setDoc(service.getDoc());
			newService.setHint(service.getHint());

			addElementsToEList(newService.getOperations(), copyAndEnhanceOperations(service));
			addElementToEList(aggregate.getServices(), newService);
		}
	}

	private List copyAndEnhanceOperations(Service service) {
		List operations = Lists.newLinkedList();
		for (ServiceOperation operation : service.getOperations()) {
			ServiceOperation copiedOperation = TacticdslFactory.eINSTANCE.createServiceOperation();
			copiedOperation.setName(operation.getName());
			copiedOperation.setDelegateHolder(operation.getDelegateHolder());
			copiedOperation.setHint(operation.getHint());
			copiedOperation.setDoc(operation.getDoc());
			copiedOperation.setPublish(operation.getPublish());
			copiedOperation.setThrows(operation.getThrows());
			copiedOperation.setVisibility(operation.getVisibility());
			operations.add(copiedOperation);

			if (operation.getReturnType() == null)
				copiedOperation.setReturnType(createComplexType(operation.getName().substring(0, 1).toUpperCase() + operation.getName().substring(1) + "Output"));

			if (operation.getParameters().isEmpty())
				addElementToEList(copiedOperation.getParameters(),
						createParameter("input", createComplexType(operation.getName().substring(0, 1).toUpperCase() + operation.getName().substring(1) + "Input")));

		}
		return operations;
	}

	private ComplexType createComplexType(String type) {
		ComplexType complexType = TacticdslFactory.eINSTANCE.createComplexType();
		complexType.setType(type);
		return complexType;
	}

	private Parameter createParameter(String name, ComplexType type) {
		Parameter parameter = TacticdslFactory.eINSTANCE.createParameter();
		parameter.setName(name);
		parameter.setParameterType(type);
		return parameter;
	}

	private String getUniqueBoundedContextName(String initialName) {
		String bcName = initialName;
		Set allBCNames = getAllBoundedContexts().stream().map(bc -> bc.getName()).collect(Collectors.toSet());
		int counter = 2;
		while (allBCNames.contains(bcName)) {
			bcName = initialName + "_" + counter;
			counter++;
		}
		return bcName;
	}

	private Set collectSubdomains() {
		Set allSubdomains = Sets.newHashSet();
		for (Domain domain : getAllDomains()) {
			allSubdomains.addAll(domain.getSubdomains());
		}
		Set subdomains = Sets.newHashSet();
		for (String subdomainId : subdomainIds) {
			Optional optSubdomain = allSubdomains.stream().filter(sd -> subdomainId.equals(sd.getName())).findFirst();
			if (optSubdomain.isPresent())
				subdomains.add(optSubdomain.get());
		}
		return subdomains;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy