diff --git a/tools/create-architecture-model/build.gradle b/tools/create-architecture-model/build.gradle index f39b956b120ed072af54f4f8aa105a767a8fc8c8..9897bc5215160b23470cc2e892a67a3363487e90 100644 --- a/tools/create-architecture-model/build.gradle +++ b/tools/create-architecture-model/build.gradle @@ -18,6 +18,8 @@ dependencies { implementation 'org.eclipse.emf:org.eclipse.emf.ecore:2.23.0' runtime 'org.eclipse.emf:org.eclipse.emf.ecore:2.23.0' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.12.0' + runtime 'jakarta.xml.bind:jakarta.xml.bind-api:2.3.3' runtime 'com.sun.xml.bind:jaxb-impl:2.3.3' } diff --git a/tools/create-architecture-model/src/main/java/org/oceandsl/architecture/model/ArchitectureModelMain.java b/tools/create-architecture-model/src/main/java/org/oceandsl/architecture/model/ArchitectureModelMain.java index b356bb76b0f1816daf5f9119273dd5a76d208154..9190fae55fda3d6f169f6b2c5210876d5502068b 100644 --- a/tools/create-architecture-model/src/main/java/org/oceandsl/architecture/model/ArchitectureModelMain.java +++ b/tools/create-architecture-model/src/main/java/org/oceandsl/architecture/model/ArchitectureModelMain.java @@ -76,6 +76,9 @@ public class ArchitectureModelMain extends AbstractService<TeetimeConfiguration, this.logger.error("Output directory {} is not directory", this.parameterConfiguration.getOutputFile()); return false; } + if (this.parameterConfiguration.getPrefix() == null) { + this.parameterConfiguration.setPrefix(""); + } return true; } diff --git a/tools/create-architecture-model/src/main/java/org/oceandsl/architecture/model/ArchitectureModelSettings.java b/tools/create-architecture-model/src/main/java/org/oceandsl/architecture/model/ArchitectureModelSettings.java index 60320e058a9bdf2bce0e718e9477523c0532d30c..10e9fde9d77846259bd74909a133c1b15d73e9a1 100644 --- a/tools/create-architecture-model/src/main/java/org/oceandsl/architecture/model/ArchitectureModelSettings.java +++ b/tools/create-architecture-model/src/main/java/org/oceandsl/architecture/model/ArchitectureModelSettings.java @@ -53,4 +53,8 @@ public class ArchitectureModelSettings { public String getPrefix() { return this.prefix; } + + public void setPrefix(final String prefix) { + this.prefix = prefix; + } } diff --git a/tools/create-architecture-model/src/main/java/org/oceandsl/architecture/model/ModelSerializerStage.java b/tools/create-architecture-model/src/main/java/org/oceandsl/architecture/model/ModelSerializerStage.java new file mode 100644 index 0000000000000000000000000000000000000000..c4621537a92f723682247762684524fd0aad09ed --- /dev/null +++ b/tools/create-architecture-model/src/main/java/org/oceandsl/architecture/model/ModelSerializerStage.java @@ -0,0 +1,210 @@ +/*************************************************************************** + * Copyright (C) 2021 OceanDSL (https://oceandsl.uni-kiel.de) + * + * 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.oceandsl.architecture.model; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; + +import kieker.analysis.statistics.Properties; +import kieker.analysis.statistics.StatisticsModel; +import kieker.analysis.statistics.Units; +import kieker.analysis.util.ComposedKey; +import kieker.analysis.util.stage.trigger.Trigger; +import kieker.analysisteetime.model.analysismodel.assembly.AssemblyComponent; +import kieker.analysisteetime.model.analysismodel.assembly.AssemblyModel; +import kieker.analysisteetime.model.analysismodel.assembly.AssemblyOperation; +import kieker.analysisteetime.model.analysismodel.deployment.DeployedComponent; +import kieker.analysisteetime.model.analysismodel.deployment.DeployedOperation; +import kieker.analysisteetime.model.analysismodel.deployment.DeploymentContext; +import kieker.analysisteetime.model.analysismodel.deployment.DeploymentModel; +import kieker.analysisteetime.model.analysismodel.execution.AggregatedInvocation; +import kieker.analysisteetime.model.analysismodel.execution.ExecutionModel; +import kieker.analysisteetime.model.analysismodel.type.ComponentType; +import kieker.analysisteetime.model.analysismodel.type.OperationType; +import kieker.analysisteetime.model.analysismodel.type.TypeModel; +import teetime.framework.AbstractConsumerStage; + +/** + * @author reiner + * + */ +public class ModelSerializerStage extends AbstractConsumerStage<Trigger> { + + private final File outputFile; + private final TypeModel typeModel; + private final AssemblyModel assemblyModel; + private final DeploymentModel deploymentModel; + private final ExecutionModel executionModel; + private final StatisticsModel statisticsModel; + private final String prefix; + + public ModelSerializerStage(final TypeModel typeModel, final AssemblyModel assemblyModel, + final DeploymentModel deploymentModel, final ExecutionModel executionModel, + final StatisticsModel statisticsModel, final String prefix, final File outputDirectoryPath) + throws IOException { + this.typeModel = typeModel; + this.assemblyModel = assemblyModel; + this.deploymentModel = deploymentModel; + this.executionModel = executionModel; + this.statisticsModel = statisticsModel; + this.prefix = prefix; + this.outputFile = new File(outputDirectoryPath.getAbsolutePath() + File.separator + "model.json"); + } + + @Override + protected void execute(final Trigger element) throws Exception { + final ObjectMapper objectMapper = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT); + + final HashMap<String, Object> modelMap = new HashMap<>(); + + modelMap.put("type-model", this.createTypeModel()); + modelMap.put("assembly-model", this.createAssemblyModel()); + modelMap.put("deployment-model", this.createDeplyomentModel()); + modelMap.put("execution-aggregate-model", this.createExecutionAggregateModel()); + + objectMapper.writeValue(this.outputFile, modelMap); + } + + private Map<String, Object> createTypeModel() { + final Map<String, Object> typeModelMap = new HashMap<>(); + for (final Entry<String, ComponentType> componentTypeEntry : this.typeModel.getComponentTypes()) { + final ComponentType componentType = componentTypeEntry.getValue(); + final Map<String, Object> componentMap = new HashMap<>(); + + componentMap.put("name", componentType.getName()); + componentMap.put("package", componentType.getPackage()); + componentMap.put("signature", this.fixSignature(componentType.getSignature())); + + final Map<String, Object> operationsMap = new HashMap<>(); + for (final Entry<String, OperationType> operationEntry : componentType.getProvidedOperations()) { + final OperationType operation = operationEntry.getValue(); + final Map<String, Object> operationMap = new HashMap<>(); + operationMap.put("name", operation.getName()); + operationMap.put("signature", operation.getSignature()); + operationMap.put("return-type", operation.getReturnType()); + operationMap.put("modifiers", operation.getModifiers()); + operationMap.put("parameters", operation.getParameterTypes()); + operationsMap.put(operation.getName(), operationMap); + } + componentMap.put("operations", operationsMap); + typeModelMap.put(this.fixSignature(componentTypeEntry.getKey()), componentMap); + } + + return typeModelMap; + } + + private String fixSignature(final String signature) { + if (signature.startsWith(this.prefix)) { + return signature.substring(this.prefix.length()); + } else { + return signature; + } + } + + private Map<String, Object> createAssemblyModel() { + final Map<String, Object> assemblyModelMap = new HashMap<>(); + + for (final Entry<String, AssemblyComponent> assemblyComponentEntry : this.assemblyModel + .getAssemblyComponents()) { + final AssemblyComponent assemblyComponent = assemblyComponentEntry.getValue(); + final Map<String, Object> assemblyComponentMap = new HashMap<>(); + + assemblyComponentMap.put("component-type", + this.fixSignature(assemblyComponent.getComponentType().getSignature())); + + final Map<String, Object> assemblyOperationsMap = new HashMap<>(); + for (final Entry<String, AssemblyOperation> assemblyOperationEntry : assemblyComponent + .getAssemblyOperations()) { + final AssemblyOperation assemblyOperation = assemblyOperationEntry.getValue(); + final Map<String, Object> assemblyOperationMap = new HashMap<>(); + + assemblyOperationMap.put("operation-type", assemblyOperation.getOperationType().getSignature()); + assemblyOperationsMap.put(assemblyOperationEntry.getKey(), assemblyOperationMap); + } + assemblyComponentMap.put("assembly-operations", assemblyOperationsMap); + + assemblyModelMap.put(this.fixSignature(assemblyComponentEntry.getKey()), assemblyComponentMap); + } + + return assemblyModelMap; + } + + private Map<String, Object> createDeplyomentModel() { + final Map<String, Object> deploymentModelMap = new HashMap<>(); + + for (final Entry<String, DeploymentContext> deploymentContextEntry : this.deploymentModel + .getDeploymentContexts()) { + final DeploymentContext deploymentContext = deploymentContextEntry.getValue(); + final Map<String, Object> deploymentContextMap = new HashMap<>(); + + deploymentContextMap.put("deployment-context", deploymentContext.getName()); + final Map<String, Object> deployedComponentsMap = new HashMap<>(); + for (final Entry<String, DeployedComponent> deployedComponentEntry : deploymentContext.getComponents()) { + final DeployedComponent deployedComponent = deployedComponentEntry.getValue(); + final Map<String, Object> deployedComponentMap = new HashMap<>(); + + deployedComponentMap.put("assembly-component", + this.fixSignature(deployedComponent.getAssemblyComponent().getComponentType().getSignature())); + final Map<String, Object> containedOperationsMap = new HashMap<>(); + for (final Entry<String, DeployedOperation> containedOperationEntry : deployedComponent + .getContainedOperations()) { + final DeployedOperation containedOperation = containedOperationEntry.getValue(); + final Map<String, Object> containedOperationMap = new HashMap<>(); + + containedOperationMap.put("contained-operation", + containedOperation.getAssemblyOperation().getOperationType().getSignature()); + containedOperationsMap.put(containedOperationEntry.getKey(), containedOperationMap); + } + deployedComponentMap.put("contained-operations", containedOperationsMap); + deployedComponentsMap.put(this.fixSignature(deployedComponentEntry.getKey()), deployedComponentMap); + } + deploymentContextMap.put("deployed-components", deployedComponentsMap); + deploymentModelMap.put(this.fixSignature(deploymentContextEntry.getKey()), deploymentContextMap); + } + + return deploymentModelMap; + } + + private List<Object> createExecutionAggregateModel() { + final List<Object> executionAggregateModels = new ArrayList<>(); + + for (final Entry<ComposedKey<DeployedOperation, DeployedOperation>, AggregatedInvocation> aggregatedInvocationEntry : this.executionModel + .getAggregatedInvocations()) { + final AggregatedInvocation aggregatedInvocation = aggregatedInvocationEntry.getValue(); + final long numberOfcalls = this.statisticsModel.get(aggregatedInvocation).getStatistic(Units.RESPONSE_TIME) + .getProperty(Properties.COUNT); + + final Map<String, Object> aggregatedLinkMap = new HashMap<>(); + + aggregatedLinkMap.put("source", + aggregatedInvocation.getSource().getAssemblyOperation().getOperationType().getSignature()); + aggregatedLinkMap.put("target", + aggregatedInvocation.getTarget().getAssemblyOperation().getOperationType().getSignature()); + aggregatedLinkMap.put("number-of-calls", numberOfcalls); + executionAggregateModels.add(aggregatedLinkMap); + } + + return executionAggregateModels; + } +} diff --git a/tools/create-architecture-model/src/main/java/org/oceandsl/architecture/model/TeetimeConfiguration.java b/tools/create-architecture-model/src/main/java/org/oceandsl/architecture/model/TeetimeConfiguration.java index f2d59cfb20954bb11b9fe6152d17576b0de9e014..337f214e3b08333d6b723937237cd77771d65bb7 100644 --- a/tools/create-architecture-model/src/main/java/org/oceandsl/architecture/model/TeetimeConfiguration.java +++ b/tools/create-architecture-model/src/main/java/org/oceandsl/architecture/model/TeetimeConfiguration.java @@ -110,6 +110,10 @@ public class TeetimeConfiguration extends Configuration { final Distributor<Trigger> distributor = new Distributor<>(new CopyByReferenceStrategy()); + final ModelSerializerStage executionModelSerializerStage = new ModelSerializerStage(typeModel, assemblyModel, + deploymentModel, executionModel, statisticsModel, parameterConfiguration.getPrefix(), + parameterConfiguration.getOutputFile()); + final DependencyGraphCreatorStage operationDependencyGraphCreatorStage = new DependencyGraphCreatorStage( executionModel, statisticsModel, new AssemblyLevelOperationDependencyGraphBuilderFactory()); final DotFileWriterStage dotFileOperationDependencyWriterStage = new DotFileWriterStage( @@ -146,6 +150,7 @@ public class TeetimeConfiguration extends Configuration { this.connectPorts(distributor.getNewOutputPort(), operationDependencyGraphCreatorStage.getInputPort()); this.connectPorts(distributor.getNewOutputPort(), componentDependencyGraphCreatorStage.getInputPort()); + this.connectPorts(distributor.getNewOutputPort(), executionModelSerializerStage.getInputPort()); this.connectPorts(operationDependencyGraphCreatorStage.getOutputPort(), distributorGraphs.getInputPort()); this.connectPorts(distributorGraphs.getNewOutputPort(), dotFileOperationDependencyWriterStage.getInputPort());