// Copyright 2012 Georg-August-Universität Göttingen, Germany // // 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 de.ugoe.cs.autoquest.plugin.uml; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.Level; import org.apache.commons.lang.mutable.MutableInt; import org.eclipse.emf.common.util.EList; import org.eclipse.uml2.uml.CallConcurrencyKind; import org.eclipse.uml2.uml.Component; import org.eclipse.uml2.uml.Connector; import org.eclipse.uml2.uml.DataType; import org.eclipse.uml2.uml.Element; import org.eclipse.uml2.uml.Enumeration; import org.eclipse.uml2.uml.Generalization; import org.eclipse.uml2.uml.InstanceSpecification; import org.eclipse.uml2.uml.InstanceValue; import org.eclipse.uml2.uml.Interaction; import org.eclipse.uml2.uml.Interface; import org.eclipse.uml2.uml.Lifeline; import org.eclipse.uml2.uml.LiteralBoolean; import org.eclipse.uml2.uml.LiteralInteger; import org.eclipse.uml2.uml.LiteralReal; import org.eclipse.uml2.uml.LiteralString; import org.eclipse.uml2.uml.Message; import org.eclipse.uml2.uml.MessageOccurrenceSpecification; import org.eclipse.uml2.uml.MessageSort; import org.eclipse.uml2.uml.Model; import org.eclipse.uml2.uml.Operation; import org.eclipse.uml2.uml.Package; import org.eclipse.uml2.uml.Parameter; import org.eclipse.uml2.uml.PrimitiveType; import org.eclipse.uml2.uml.Property; import org.eclipse.uml2.uml.Relationship; import org.eclipse.uml2.uml.Slot; import org.eclipse.uml2.uml.Type; import org.eclipse.uml2.uml.UMLFactory; import org.eclipse.uml2.uml.UMLPackage; import de.ugoe.cs.autoquest.eventcore.Event; import de.ugoe.cs.autoquest.plugin.http.SOAPUtils; import de.ugoe.cs.autoquest.plugin.http.eventcore.SimpleSOAPEventType.CallType; import de.ugoe.cs.util.StringTools; import de.ugoe.cs.util.console.Console; /** *

* Utility class to create UML Interactions from event sequences *

* * @author Steffen Herbold */ class UMLInteractionCreator { /** * model for which the interactions are created */ private final Model model; /** * name of the test context in which the interactions are created */ private final String testContextName; /** * defines whether random message bodies are used or the ones associated with the SOAP events */ private final boolean useRandomMsgBodies; /** * a cache of the already created instance specification; used to create the overall number of * generated specifications */ private final Map instanceSpecificationCache; /** *

* Creates a new UMLInteractionCreator *

* * @param model * UML model to which the interaction is added * @param testContextName * Name of the test context that should be used. If this value is null, the first * test context found is used. * @param useRandomRequestBodies * defines is random request bodies are used or the body of the associated event */ public UMLInteractionCreator(Model model, String testContextName, boolean useRandomMsgBodies) { this.model = model; this.testContextName = testContextName; this.useRandomMsgBodies = useRandomMsgBodies; instanceSpecificationCache = new HashMap(); } /** *

* Creates the UML Interaction for the given sequence *

* * @param sequence * for which the interaction is created * @param interactionName * name of the interaction * @return created interaction */ public Interaction createInteraction(List sequence, String interactionName) { Console.traceln(Level.FINEST, "creating interaction: " + interactionName); final Component testContext = UMLUtils.fetchTestContext(model, testContextName); if (testContext == null) { throw new RuntimeException("Could not find any test context in the model"); } final Operation operation = testContext.createOwnedOperation(interactionName, null, null); operation.applyStereotype(UTPUtils.getTestCaseStereotype(model)); final Interaction interaction = (Interaction) testContext.createPackagedElement(interactionName + "_Impl", UMLPackage.Literals.INTERACTION); operation.getMethods().add(interaction); // create lifelines Lifeline userLifeline = null; for (Property property : UMLUtils.fetchAllSUTProperties(testContext)) { String serviceName = property.getName(); Lifeline targetLifeline = interaction.createLifeline(serviceName); targetLifeline.setRepresents(property); } for (Property property : UMLUtils.fetchAllTestComponentProperties(testContext)) { userLifeline = interaction.createLifeline(property.getName()); userLifeline.setRepresents(property); } if (userLifeline == null) { throw new RuntimeException("No TestComponent found, could not create user lifeline."); } if (interaction.getLifelines().size() < 2) { throw new RuntimeException("Fewer than two lifelines created. No SUT found."); } int i = 0; for (Event event : sequence) { Console.traceln(Level.FINEST, "creating message for event: " + event.toString()); if (!(event.equals(Event.STARTEVENT) || event.equals(Event.ENDEVENT))) { String serviceName = SOAPUtils.getServiceNameFromEvent(event); String methodName = SOAPUtils.getCalledMethodFromEvent(event); String clientName = SOAPUtils.getClientNameFromEvent(event); String prefix = interactionName + "_" + i + "_" + methodName + "_"; // determine lifelines Lifeline msgTargetLifeline; Lifeline msgSourceLifeline; msgSourceLifeline = interaction.getLifeline(clientName); msgTargetLifeline = interaction.getLifeline(serviceName); if (msgSourceLifeline == null) { throw new RuntimeException( "Error creating message: could not determine source lifeline for component: " + clientName); } if (msgTargetLifeline == null) { throw new RuntimeException( "Error creating message: could not determine target lifeline for component: " + serviceName); } // determine correct target interface Set targetInterfaces = UMLUtils.getRealizedInterfacesFromProperty((Property) msgTargetLifeline .getRepresents()); if (targetInterfaces.isEmpty()) { throw new RuntimeException("no interface associated with the property " + msgTargetLifeline.getRepresents().getName()); } Interface targetInterface = null; for (Interface intface : targetInterfaces) { if (UMLUtils.getOperationFromName(intface.getOperations(), methodName) != null) { // interface found targetInterface = intface; break; } } if (targetInterface == null) { StringBuilder errStrBuilder = new StringBuilder(); errStrBuilder .append("Error creating message: operation not found in the implementing interfaces ("); Iterator iter = targetInterfaces.iterator(); while (iter.hasNext()) { String interfaceName = iter.next().getName(); errStrBuilder.append(interfaceName); if (iter.hasNext()) { errStrBuilder.append(","); } else { errStrBuilder.append("): " + methodName); } } throw new RuntimeException(errStrBuilder.toString()); } Operation calledOperation = UMLUtils.getOperationFromName(targetInterface.getOperations(), methodName); // get connector Connector connector = UMLUtils.inferConnector(msgSourceLifeline, msgTargetLifeline, targetInterface); if (connector == null) { throw new RuntimeException( "Error creating message: could not find connector between the two life lines that supports the target interface at the target lifeline"); } boolean asynch = false; if (calledOperation.getConcurrency() == CallConcurrencyKind.CONCURRENT_LITERAL) { asynch = true; } if (!hasOutParameters(operation)) { asynch = true; } if (SOAPUtils.isSOAPRequest(event)) { // setup for both SYNCH and ASYNCH calls MessageOccurrenceSpecification callSendFragment = (MessageOccurrenceSpecification) interaction .createFragment(prefix + "callSendFragment", UMLPackage.Literals.MESSAGE_OCCURRENCE_SPECIFICATION); MessageOccurrenceSpecification callRecvFragment = (MessageOccurrenceSpecification) interaction .createFragment(prefix + "callRecvFragment", UMLPackage.Literals.MESSAGE_OCCURRENCE_SPECIFICATION); callSendFragment.setCovered(msgSourceLifeline); callRecvFragment.setCovered(msgTargetLifeline); // create call Message callMessage = interaction.createMessage(prefix + "call"); callMessage.setSignature(calledOperation); setMessageParameters(callMessage, calledOperation, event, prefix); callMessage.setConnector(connector); callMessage.setSendEvent(callSendFragment); callMessage.setReceiveEvent(callRecvFragment); callSendFragment.setMessage(callMessage); callRecvFragment.setMessage(callMessage); if (asynch) { // Create ASYNCH call callMessage.setMessageSort(MessageSort.ASYNCH_CALL_LITERAL); } else { // SYNCH call callMessage.setMessageSort(MessageSort.SYNCH_CALL_LITERAL); } } if (!asynch && SOAPUtils.isSOAPResponse(event)) { if (hasOutParameters(calledOperation)) { // setup reply and behavior execution specifications MessageOccurrenceSpecification replySendFragment = (MessageOccurrenceSpecification) interaction .createFragment(prefix + "replySendFragment", UMLPackage.Literals.MESSAGE_OCCURRENCE_SPECIFICATION); MessageOccurrenceSpecification replyRecvFragment = (MessageOccurrenceSpecification) interaction .createFragment(prefix + "replyRecvFragment", UMLPackage.Literals.MESSAGE_OCCURRENCE_SPECIFICATION); replySendFragment.setCovered(msgTargetLifeline); replyRecvFragment.setCovered(msgSourceLifeline); /* * BehaviorExecutionSpecification sourceBehaviorExecutionSpecification = * (BehaviorExecutionSpecification) interaction .createFragment(":" + * methodName + "_sourceBhvExecSpec", * UMLPackage.Literals.BEHAVIOR_EXECUTION_SPECIFICATION); * BehaviorExecutionSpecification targetBehaviorExecutionSpecification = * (BehaviorExecutionSpecification) interaction .createFragment(":" + * methodName + "_targetBhvExecSpec", * UMLPackage.Literals.BEHAVIOR_EXECUTION_SPECIFICATION); * * sourceBehaviorExecutionSpecification.setStart(callSendFragment); * sourceBehaviorExecutionSpecification.setFinish(replyRecvFragment); * targetBehaviorExecutionSpecification.setStart(callRecvFragment); * targetBehaviorExecutionSpecification.setFinish(replySendFragment); */ // create reply Message replyMessage = interaction.createMessage(prefix + "_reply"); replyMessage.setMessageSort(MessageSort.REPLY_LITERAL); replyMessage.setSignature(calledOperation); // setReplyMessageParameters(replyMessage, calledOperation); setMessageParameters(replyMessage, calledOperation, event, prefix); replyMessage.setConnector(connector); replyMessage.setSendEvent(replySendFragment); replyMessage.setReceiveEvent(replyRecvFragment); replySendFragment.setMessage(replyMessage); replyRecvFragment.setMessage(replyMessage); } } i++; } } return interaction; } /** *

* Sets values for the parameters of a call message. The values are, if possible, inferred from * the event that is provided. *

* * @param message * call message for which the parameters are set * @param calledOperation * operation that is called by the message * @param event * event that provides the parameters; in case of null, default values are assumed * @param prefix * prefix of the call message; used to create good warnings and debugging information */ private void setMessageParameters(Message message, Operation calledOperation, Event event, String prefix) { // printParameters(calledOperation); // FOR DEBUGGING org.w3c.dom.Element requestBody; if (SOAPUtils.isSOAPRequest(event)) { requestBody = SOAPUtils.getSoapBodyFromEvent(event, useRandomMsgBodies, CallType.REQUEST); } else { requestBody = SOAPUtils.getSoapBodyFromEvent(event, useRandomMsgBodies, CallType.RESPONSE); } Package instSpecPkg = null; MutableInt instSpecNumber = new MutableInt(0); // Set parameters of operation for (Parameter param : calledOperation.getOwnedParameters()) { if (instSpecPkg == null) { instSpecPkg = getOrCreateInstanceSpecificationPackage(event); } String path = calledOperation.getName() + ":" + getNormalizedTypeName(param.getType()); if ((UMLUtils.isInParameter(param) && SOAPUtils.isSOAPRequest(event)) || (UMLUtils.isOutParameter(param) && SOAPUtils.isSOAPResponse(event))) { // create parameters node if (!(param.getType() instanceof DataType)) { throw new RuntimeException("TODO error handling; parameters missing"); } DataType parametersNode = (DataType) param.getType(); InstanceSpecification instSpecParameters = (InstanceSpecification) instSpecPkg .createPackagedElement(prefix + "instspec" + instSpecNumber.intValue() + "_" + getNormalizedTypeName(param.getType()), UMLPackage.Literals.INSTANCE_SPECIFICATION); instSpecParameters.getClassifiers().add((DataType) param.getType()); instSpecNumber.setValue(instSpecNumber.intValue() + 1); InstanceValue instanceValue = (InstanceValue) message.createArgument(param.getName(), param.getType(), UMLPackage.Literals.INSTANCE_VALUE); instanceValue.setInstance(instSpecParameters); for (Property internalParameter : parametersNode.getAllAttributes()) { if (internalParameter.getType() instanceof DataType) { List paramNodes = SOAPUtils.getMatchingChildNode(getNormalizedTypeName(internalParameter .getType()), requestBody); int multiplicityChosen = paramNodes.size(); if (multiplicityChosen == 0 && internalParameter.getLower() > 0 && requestBody != null) { Console .traceln(Level.WARNING, "required attribute not found in SOAP message: " + path); Console .traceln(Level.WARNING, "setting default values for this attribute and all its children"); Console.traceln(Level.FINE, "XML structure of path:" + StringTools.ENDLINE + SOAPUtils.getSerialization(requestBody)); multiplicityChosen = internalParameter.getLower(); } if (multiplicityChosen == 0 && requestBody == null) { // create parameters node with empty instance specification as value Slot slot = instSpecParameters.createSlot(); slot.setDefiningFeature(internalParameter); InstanceValue value = (InstanceValue) slot .createValue(internalParameter.getName() + "_" + 0, internalParameter.getType(), UMLPackage.Literals.INSTANCE_VALUE); InstanceSpecification instSpec = (InstanceSpecification) instSpecPkg .createPackagedElement(prefix + "instspec" + instSpecNumber.intValue() + "_" + internalParameter.getType() .getName(), UMLPackage.Literals.INSTANCE_SPECIFICATION); instSpec.getClassifiers().add((DataType) internalParameter.getType()); instSpecNumber.setValue(instSpecNumber.intValue() + 1); value.setInstance(instSpec); } else if (multiplicityChosen > 0) { Slot slot = instSpecParameters.createSlot(); slot.setDefiningFeature(internalParameter); for (int i = 0; i < multiplicityChosen; i++) { org.w3c.dom.Element paramNode = null; if (!paramNodes.isEmpty()) { paramNode = paramNodes.get(i); } InstanceValue value = (InstanceValue) slot .createValue(internalParameter.getName() + "_" + i, internalParameter.getType(), UMLPackage.Literals.INSTANCE_VALUE); InstanceSpecification instSpec = createInstanceSpecification((DataType) internalParameter .getType(), instSpecPkg, prefix, instSpecNumber, paramNode, path); value.setInstance(instSpec); /* * InstanceValue value = (InstanceValue) argument * .createOperand(null, internalParameter.getType(), * UMLPackage.Literals.INSTANCE_VALUE); value.setInstance(instSpec); */ } } } else if (internalParameter.getType() instanceof PrimitiveType) { createSlotPrimitiveType(instSpecParameters, internalParameter, requestBody, path); } } } else { // set literalNull for out and return parameters // argument.createOperand(null, param.getType(), UMLPackage.Literals.LITERAL_NULL); message.createArgument(param.getName(), param.getType(), UMLPackage.Literals.LITERAL_NULL); } } } /** *

* Creates an {@link InstanceSpecification} for a data type in the given package. The values are * inferred, if possible, from the DOM node. The prefix and the path are used for naming the * instance specification and to provide good warnings and debug information in case of * problems. *

* * @param type * DataType for which the {@link InstanceSpecification} is created * @param pkg * package in which the {@link InstanceSpecification} is created * @param prefix * prefix used for naming the {@link InstanceSpecification} * @param currentNode * node of a DOM from which values are inferred * @param path * used for warnings and debug information * @return {@link InstanceSpecification} for the given type */ private InstanceSpecification createInstanceSpecification(DataType type, Package pkg, String prefix, MutableInt instSpecNumber, org.w3c.dom.Element currentNode, String path) { if (instanceSpecificationCache.containsKey(SOAPUtils.getSerialization(currentNode))) { return instanceSpecificationCache.get(SOAPUtils.getSerialization(currentNode)); } if ("".equals(path)) { path = type.getName(); } InstanceSpecification instSpec = (InstanceSpecification) pkg .createPackagedElement(prefix + "instspec" + instSpecNumber.intValue() + "_" + type.getName(), UMLPackage.Literals.INSTANCE_SPECIFICATION); instSpec.getClassifiers().add(type); instSpecNumber.setValue(instSpecNumber.intValue() + 1); for (Property prop : type.getAllAttributes()) { if (prop.getType() instanceof PrimitiveType) { createSlotPrimitiveType(instSpec, prop, currentNode, path); } else if (prop.getType() instanceof Enumeration) { createSlotEnumeration(instSpec, prop, currentNode, path); } else if (prop.getType() instanceof DataType) { if (isXSDSequence(prop.getType())) { // XSD sequence, no real type List childNames = SOAPUtils.getChildNodeNames(currentNode); List childNodes = SOAPUtils.getChildElements(currentNode); EList sequenceProperties = ((DataType) prop.getType()).getAllAttributes(); boolean sequenceIsMatch = true; // can currently only work with exactly one sequence and no optional elements if (sequenceProperties.size() == childNames.size()) { for (int i = 0; sequenceIsMatch && i < sequenceProperties.size(); i++) { Property propSeq = sequenceProperties.get(i); String currentChildName = childNames.get(i); if (isXSDChoice(propSeq.getType())) { boolean choiceMatchFound = false; for (Property propChoice : ((DataType) propSeq.getType()) .getAllAttributes()) { if (currentChildName.equals(propChoice.getName())) { choiceMatchFound = true; } } sequenceIsMatch &= choiceMatchFound; } else { sequenceIsMatch &= currentChildName.equals(propSeq.getName()); } } if (sequenceIsMatch) { // this is the correct sequence, it matches; now appropriate data must // be created // first we create the slot and instance specification for the sequence Slot slot = instSpec.createSlot(); slot.setDefiningFeature(prop); InstanceValue value = (InstanceValue) slot .createValue(prop.getName(), prop.getType(), UMLPackage.Literals.INSTANCE_VALUE); InstanceSpecification instSpecSequence = (InstanceSpecification) pkg .createPackagedElement(prefix + prop.getName() + "_instspec" + instSpecNumber.intValue() + "_" + type.getName(), UMLPackage.Literals.INSTANCE_SPECIFICATION); instSpecSequence.getClassifiers().add((DataType) prop.getType()); instSpecNumber.setValue(instSpecNumber.intValue() + 1); value.setInstance(instSpecSequence); // now we create the slots and instance specifications for the elements // of the sequence for (int i = 0; i < sequenceProperties.size(); i++) { Property propSeq = sequenceProperties.get(i); String currentChildName = childNames.get(i); slot = instSpecSequence.createSlot(); slot.setDefiningFeature(propSeq); value = (InstanceValue) slot .createValue(propSeq.getName(), propSeq.getType(), UMLPackage.Literals.INSTANCE_VALUE); if (isXSDChoice(propSeq.getType())) { // create the inner choice instance spec InstanceSpecification instSpecSequenceChoice = (InstanceSpecification) pkg .createPackagedElement(prefix + propSeq.getName() + "_instspec" + instSpecNumber.intValue() + "_" + propSeq.getType().getName(), UMLPackage.Literals.INSTANCE_SPECIFICATION); instSpecSequenceChoice.getClassifiers().add((DataType) propSeq .getType()); instSpecNumber.setValue(instSpecNumber.intValue() + 1); value.setInstance(instSpecSequenceChoice); for (Property propChoice : ((DataType) propSeq.getType()) .getAllAttributes()) { if (currentChildName.equals(propChoice.getName())) { slot = instSpecSequenceChoice.createSlot(); slot.setDefiningFeature(propChoice); value = (InstanceValue) slot .createValue(propChoice.getName(), propChoice.getType(), UMLPackage.Literals.INSTANCE_VALUE); value .setInstance(createInstanceSpecification((DataType) propChoice .getType(), pkg, prefix, instSpecNumber, childNodes .get(i), path + "." + propChoice .getName())); break; } } } else { value .setInstance(createInstanceSpecification((DataType) propSeq .getType(), pkg, prefix, instSpecNumber, childNodes .get(i), path + "." + propSeq.getName())); } } } } } else if (isXSDChoice(prop.getType())) { for (Property propChoice : ((DataType) prop.getType()).getAllAttributes()) { List matchingChildren = SOAPUtils.getMatchingChildNode(propChoice.getName(), currentNode); if (!matchingChildren.isEmpty()) { // create instance specification for the choice Slot slot = instSpec.createSlot(); slot.setDefiningFeature(prop); InstanceValue value = (InstanceValue) slot .createValue(prop.getName(), prop.getType(), UMLPackage.Literals.INSTANCE_VALUE); InstanceSpecification instSpecSequence = (InstanceSpecification) pkg .createPackagedElement(prefix + prop.getName() + "_instspec" + instSpecNumber.intValue() + "_" + type.getName(), UMLPackage.Literals.INSTANCE_SPECIFICATION); instSpecSequence.getClassifiers().add((DataType) prop.getType()); instSpecNumber.setValue(instSpecNumber.intValue() + 1); value.setInstance(instSpecSequence); // now the slot and instance specification for the matching choice slot = instSpecSequence.createSlot(); slot.setDefiningFeature(propChoice); value = (InstanceValue) slot .createValue(propChoice.getName(), propChoice.getType(), UMLPackage.Literals.INSTANCE_VALUE); value .setInstance(createInstanceSpecification((DataType) propChoice .getType(), pkg, prefix, instSpecNumber, matchingChildren .get(0), path + "." + propChoice.getName())); } } } else { // normal child, neither choice nor sequence List attributeNodes = null; int multiplicityChosen = 0; if (currentNode != null) { attributeNodes = SOAPUtils.getMatchingChildNode(prop.getName(), currentNode); multiplicityChosen = attributeNodes.size(); } if (multiplicityChosen == 0 && prop.getLower() > 0) { if (currentNode != null) { Console.traceln(Level.WARNING, "required attribute not found in SOAP message: " + path + "." + prop.getName()); Console .traceln(Level.WARNING, "setting default values for this attribute and all its children"); Console.traceln(Level.FINE, "XML structure of path:" + StringTools.ENDLINE + SOAPUtils.getSerialization(currentNode)); } multiplicityChosen = prop.getLower(); } if (multiplicityChosen == 1) { org.w3c.dom.Element attributeNode = null; if (attributeNodes != null && !attributeNodes.isEmpty()) { attributeNode = attributeNodes.get(0); } Slot slot = instSpec.createSlot(); slot.setDefiningFeature(prop); InstanceValue value = (InstanceValue) slot.createValue(prop.getName() + "_" + 1, prop.getType(), UMLPackage.Literals.INSTANCE_VALUE); value.setInstance(createInstanceSpecification((DataType) prop.getType(), pkg, prefix, instSpecNumber, attributeNode, path + "." + prop.getName())); } else if (multiplicityChosen > 1) { Slot slot = instSpec.createSlot(); slot.setDefiningFeature(prop); for (int i = 0; i < multiplicityChosen; i++) { org.w3c.dom.Element attributeNode = null; if (attributeNodes != null && !attributeNodes.isEmpty()) { attributeNode = attributeNodes.get(i); } InstanceValue value = UMLFactory.eINSTANCE.createInstanceValue(); value .setInstance(createInstanceSpecification((DataType) prop.getType(), pkg, prefix, instSpecNumber, attributeNode, path + "." + prop.getName())); slot.getValues().add(value); } } } } else { Console.traceln(Level.SEVERE, "property neither DataType nor PrimitiveType: " + prop.getType()); throw new RuntimeException( "can only handle DataType and PrimitiveType properties but was: " + prop.getType().getClass().getName()); } } instanceSpecificationCache.put(SOAPUtils.getSerialization(currentNode), instSpec); return instSpec; } /** *

* Creates a {@link Slot} in an {@link InstanceSpecification} for a primitive type. *

* * @param instSpec * instance specification to which the slot is added * @param prop * property that describes the slot * @param currentNode * DOM node from which is value for the slot is inferred * @param path * used for warnings and debug information */ private void createSlotPrimitiveType(InstanceSpecification instSpec, Property prop, org.w3c.dom.Element currentNode, String path) { List attributeValues = SOAPUtils.getValuesFromElement(prop.getName(), currentNode); if (attributeValues.isEmpty()) { if (prop.getLower() == 0) { // ignoring optional attribute return; } else { if (currentNode != null) { Console.traceln(Level.WARNING, "required attribute not found in SOAP message: " + path + "." + prop.getName()); Console.traceln(Level.WARNING, "setting default values for this attribute"); Console.traceln(Level.FINE, "XML structure of path:" + StringTools.ENDLINE + SOAPUtils.getSerialization(currentNode)); } attributeValues.add(null); } } for (String attributeValue : attributeValues) { Slot slot = instSpec.createSlot(); slot.setDefiningFeature(prop); if (isPrimitiveTypeOf(prop.getType(), "String")) { LiteralString value = (LiteralString) slot.createValue(prop.getName(), null, UMLPackage.Literals.LITERAL_STRING); if (attributeValue != null) { value.setValue(attributeValue); } else { value.setValue("foobar"); } } else if (isPrimitiveTypeOf(prop.getType(), "Integer")) { LiteralInteger value = (LiteralInteger) slot.createValue(prop.getName(), null, UMLPackage.Literals.LITERAL_INTEGER); if (attributeValue != null) { value.setValue(Integer.parseInt(attributeValue)); } else { value.setValue(42); } } else if (isPrimitiveTypeOf(prop.getType(), "Boolean")) { LiteralBoolean value = (LiteralBoolean) slot.createValue(prop.getName(), null, UMLPackage.Literals.LITERAL_BOOLEAN); if (attributeValue != null) { value.setValue(Boolean.parseBoolean(attributeValue)); } else { value.setValue(true); } } else if (isPrimitiveTypeOf(prop.getType(), "Real")) { LiteralReal value = (LiteralReal) slot.createValue(prop.getName(), null, UMLPackage.Literals.LITERAL_REAL); if (attributeValue != null) { System.out.println(attributeValue); value.setValue(Double.parseDouble(attributeValue)); } else { value.setValue(3.14); } } else { Console.traceln(Level.SEVERE, "could not create literal for primitive type: " + prop.getType().getName()); Console.traceln(Level.SEVERE, "attribute is ignored!"); } } } /** *

* Creates a {@link Slot} in an {@link InstanceSpecification} for an enumeration. *

* * @param instSpec * instance specification to which the slot is added * @param prop * property that describes the slot * @param currentNode * DOM node from which is value for the slot is inferred * @param path * used for warnings and debug information */ private void createSlotEnumeration(InstanceSpecification instSpec, Property prop, org.w3c.dom.Element currentNode, String path) { List attributeValues = SOAPUtils.getValuesFromElement(prop.getName(), currentNode); if (attributeValues.isEmpty()) { if (prop.getLower() == 0) { // ignoring optional attribute return; } else { if (currentNode != null) { Console.traceln(Level.WARNING, "required attribute not found in SOAP message: " + path + "." + prop.getName()); Console.traceln(Level.WARNING, "setting default values for this attribute"); Console.traceln(Level.FINE, "XML structure of path:" + StringTools.ENDLINE + SOAPUtils.getSerialization(currentNode)); } attributeValues.add(null); } } for (String attributeValue : attributeValues) { Slot slot = instSpec.createSlot(); slot.setDefiningFeature(prop); InstanceValue value = (InstanceValue) slot.createValue(prop.getName(), null, UMLPackage.Literals.INSTANCE_VALUE); if (attributeValue != null) { value.setInstance(((Enumeration) prop.getType()).getOwnedLiteral(attributeValue)); } else { throw new RuntimeException("cannot create enumeration literal with dummy value"); } } } /** *

* Gets or creates a {@link Package} for {@link InstanceSpecification} created by the * usage-based testing. Each service gets its own sub-package within a package called * UBT_InstanceSpecifications. " *

* * @param event * event from which the service name is inferred * @return package for the {@link InstanceSpecification}s */ private Package getOrCreateInstanceSpecificationPackage(Event event) { String pkgUBTInstSpecs = "UBT_InstanceSpecifications"; Package ubtInstSpecPkg = (Package) model.getOwnedMember(pkgUBTInstSpecs); if (ubtInstSpecPkg == null) { ubtInstSpecPkg = (Package) model.createPackagedElement(pkgUBTInstSpecs, UMLPackage.Literals.PACKAGE); } String serviceName = SOAPUtils.getServiceNameFromEvent(event); Package serviceInstSpecPkg = (Package) ubtInstSpecPkg.getOwnedMember(serviceName); if (serviceInstSpecPkg == null) { serviceInstSpecPkg = (Package) ubtInstSpecPkg.createPackagedElement(serviceName, UMLPackage.Literals.PACKAGE); } return serviceInstSpecPkg; } /** *

* Checks if a type is a instance of a primitive type defined by its name, e.g., String, * Integer, or Boolean. The functions also checks whether the type is a generalization. *

* * @param type * type that is checked * @param typeNam * name of the primitive type * @return true if the type is of the specified primitive type; false otherwise */ private boolean isPrimitiveTypeOf(Type type, String typeName) { if (typeName == null) { throw new RuntimeException("typename must not be null"); } if (!(type instanceof PrimitiveType)) { return false; } if (typeName.equals(type.getName())) { return true; } for (Relationship relationship : type.getRelationships()) { if (relationship instanceof Generalization) { Element target = ((Generalization) relationship).getTargets().get(0); if (target instanceof PrimitiveType) { if (typeName.equals(((PrimitiveType) target).getName())) { return true; } } } } return false; } /** *

* Checks if a type is an anonymous inner type that represents an XSD sequence *

* * @param type * type that is checked * @return true if XSD sequence; false otherwise */ private boolean isXSDSequence(Type type) { if (type == null || type.getName() == null) { return false; } return type.getName().matches("sequence\\d*"); } /** *

* Checks if a type is an anonymous inner type that represents an XSD choice *

* * @param type * type that is checked * @return true if XSD choice; false otherwise */ private boolean isXSDChoice(Type type) { if (type == null || type.getName() == null) { return false; } return type.getName().matches("choice\\d*"); } /** *

* Returns the name of a type and removes the suffix _._type. *

* * @param the * type * @return type name of the type without the possible suffix */ private String getNormalizedTypeName(Type type) { if (type == null) { throw new RuntimeException("type must not be null"); } String typeName = type.getName(); if (typeName != null && typeName.endsWith("_._type")) { typeName = typeName.substring(0, typeName.length() - 7); } return typeName; } /** *

* Checks if a operation has an output parameter. *

* * @param operation * operation that is checked * @return true if pilot has an operation */ private boolean hasOutParameters(Operation operation) { if (operation == null) { throw new RuntimeException("operation must not be null"); } for (Parameter param : operation.getOwnedParameters()) { if (UMLUtils.isOutParameter(param)) { return true; } } return false; } // ///////////////////// // DEBUGGING METHODS // // ///////////////////// @SuppressWarnings("unused") private void printParameters(Operation operation) { System.out.println("operation name: " + operation.getName()); for (Parameter param : operation.getOwnedParameters()) { printParameters(param, 0); } } private void printParameters(Parameter param, int depth) { for (int i = 0; i < depth; i++) { System.out.print(" "); } System.out.println(param.getName() + " - " + getNormalizedTypeName(param.getType())); if (param.getType() instanceof DataType) { for (Property prop : ((DataType) param.getType()).getAllAttributes()) { printParameters(prop, depth + 2); } } } private void printParameters(Property prop, int depth) { if (depth > 10) return; for (int i = 0; i < depth; i++) { System.out.print(" "); } System.out.println(prop.getName() + " - " + getNormalizedTypeName(prop.getType())); if (prop.getType() instanceof DataType) { for (Property prop2 : ((DataType) prop.getType()).getAllAttributes()) { printParameters(prop2, depth + 2); } } } }