/* * SoapUI, Copyright (C) 2004-2016 SmartBear Software * * Licensed under the EUPL, Version 1.1 or - as soon as they will be approved by the European Commission - subsequent * versions of the EUPL (the "Licence"); * You may not use this work except in compliance with the Licence. * You may obtain a copy of the Licence at: * * http://ec.europa.eu/idabc/eupl * * Unless required by applicable law or agreed to in writing, software distributed under the Licence is * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the Licence for the specific language governing permissions and limitations * under the Licence. */ package com.eviware.soapui.impl.wsdl.teststeps; import com.eviware.soapui.config.PropertyTransferConfig; import com.eviware.soapui.config.PropertyTransferTypesConfig; import com.eviware.soapui.impl.support.http.HttpRequestTestStep; import com.eviware.soapui.model.TestPropertyHolder; import com.eviware.soapui.model.iface.SubmitContext; import com.eviware.soapui.model.propertyexpansion.PropertyExpander; import com.eviware.soapui.model.propertyexpansion.PropertyExpansion; import com.eviware.soapui.model.propertyexpansion.PropertyExpansionContext; import com.eviware.soapui.model.propertyexpansion.PropertyExpansionUtils; import com.eviware.soapui.model.support.TestPropertyListenerAdapter; import com.eviware.soapui.model.support.TestSuiteListenerAdapter; import com.eviware.soapui.model.testsuite.TestCase; import com.eviware.soapui.model.testsuite.TestProperty; import com.eviware.soapui.model.testsuite.TestStep; import com.eviware.soapui.support.JsonPathFacade; import com.eviware.soapui.support.PropertyChangeNotifier; import com.eviware.soapui.support.StringUtils; import com.eviware.soapui.support.resolver.ChooseAnotherPropertySourceResolver; import com.eviware.soapui.support.resolver.ChooseAnotherPropertyTargetResolver; import com.eviware.soapui.support.resolver.CreateMissingPropertyResolver; import com.eviware.soapui.support.resolver.DisablePropertyTransferResolver; import com.eviware.soapui.support.resolver.ResolveContext; import com.eviware.soapui.support.resolver.ResolveContext.PathToResolve; import com.eviware.soapui.support.xml.XmlUtils; import org.apache.log4j.Logger; import org.apache.xmlbeans.XmlCursor; import org.apache.xmlbeans.XmlCursor.TokenType; import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlObject; import org.apache.xmlbeans.XmlOptions; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.util.ArrayList; import java.util.List; import static com.eviware.soapui.tools.PropertyExpansionRemover.removeExpansions; /** * Class for transferring a property value between 2 test steps. This class is * relatively complex due to backwards compatibility issues and to graceful * handling of references test steps and properties. * * @author Ole.Matzura */ public class PropertyTransfer implements PropertyChangeNotifier { private final static Logger log = Logger.getLogger(PropertyTransfer.class); public final static String SOURCE_PATH_PROPERTY = PropertyTransfer.class.getName() + "@sourcePath"; public final static String SOURCE_TYPE_PROPERTY = PropertyTransfer.class.getName() + "@sourceProperty"; public final static String SOURCE_STEP_PROPERTY = PropertyTransfer.class.getName() + "@sourceStep"; public final static String TARGET_PATH_PROPERTY = PropertyTransfer.class.getName() + "@targetPath"; public final static String TARGET_TYPE_PROPERTY = PropertyTransfer.class.getName() + "@targetProperty"; public final static String TARGET_STEP_PROPERTY = PropertyTransfer.class.getName() + "@targetStep"; public final static String NAME_PROPERTY = PropertyTransfer.class.getName() + "@name"; public final static String DISABLED_PROPERTY = PropertyTransfer.class.getName() + "@disabled"; public final static String CONFIG_PROPERTY = PropertyTransfer.class.getName() + "@config"; private TestStep testStep; // create local copies since a deleted/changed property transfer can be referenced from a result private PropertyTransferConfig config; private String sourcePath; private String sourceType; private String targetPath; private String name; private String targetType; private String sourceStep; private String targetStep; private TestPropertyHolder currentTargetStep; private TestPropertyHolder currentSourceStep; private TestProperty currentTargetProperty; private TestProperty currentSourceProperty; private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this); private StepNameChangeListener stepNameChangeListener = new StepNameChangeListener(); private InternalTestPropertyListener propertyNameChangeListener = new InternalTestPropertyListener(); private TestCase testCase; private InternalTestSuiteListener testSuiteListener = new InternalTestSuiteListener(); public PropertyTransfer(TestStep testStep) { this(testStep, PropertyTransferConfig.Factory.newInstance()); } public PropertyTransfer(TestStep testStep, PropertyTransferConfig config) { this.testStep = testStep; if (testStep != null) { this.testCase = testStep.getTestCase(); testCase.getTestSuite().addTestSuiteListener(testSuiteListener); } setConfig(config); } void setConfigOnMove(PropertyTransferConfig config) { this.config = config; } void setConfig(PropertyTransferConfig config) { releaseListeners(); this.config = config; if (!config.isSetSetNullOnMissingSource()) { config.setSetNullOnMissingSource(true); } if (!config.isSetTransferTextContent()) { config.setTransferTextContent(true); } sourceStep = config.getSourceStep(); if (sourceStep == null) { sourceStep = getSourceStepName(); if (sourceStep != null) { config.setSourceStep(sourceStep); } } else { sourceStep = sourceStep.trim(); } currentSourceStep = getPropertyHolder(sourceStep); sourceType = config.getSourceType(); currentSourceProperty = currentSourceStep == null || sourceType == null ? null : currentSourceStep .getProperty(sourceType); sourcePath = config.getSourcePath(); targetStep = config.getTargetStep(); if (targetStep == null) { targetStep = getTargetStepName(); if (targetStep != null) { config.setTargetStep(targetStep); } } else { targetStep = targetStep.trim(); } currentTargetStep = getPropertyHolder(targetStep); targetType = config.getTargetType(); currentTargetProperty = currentTargetStep == null || targetType == null ? null : currentTargetStep .getProperty(targetType); targetPath = config.getTargetPath(); if (!config.getUpgraded()) { if (shouldConvertSourceProperty()) { setSourcePropertyName(WsdlTestStepWithProperties.RESPONSE_AS_XML); } config.setUpgraded(true); } name = config.getName(); initListeners(); propertyChangeSupport.firePropertyChange(CONFIG_PROPERTY, null, null); } private boolean shouldConvertSourceProperty() { return testStep!=null && testStep.getProperties().containsKey(WsdlTestStepWithProperties.RESPONSE_AS_XML) && config.getSourcePath() != null && getSourcePathLanguage() != PathLanguage.JSONPATH && sourcePropertyIsResponse(); } private boolean sourcePropertyIsResponse() { TestProperty property = getSourceProperty(); return property != null && property.getName() != null && property.getName().equals(WsdlTestStepWithProperties.RESPONSE); } public void setSourcePathLanguage(PathLanguage language) { PropertyTransferTypesConfig.Enum languageEnum = language == null ? null : PropertyTransferTypesConfig.Enum.forInt(language.ordinal() + 1); getConfig().setType(languageEnum); } public PathLanguage getSourcePathLanguage() { return transferLanguageFromPropertyTransferType(getConfig().getType()); } private PathLanguage transferLanguageFromPropertyTransferType(PropertyTransferTypesConfig.Enum savedLanguage) { if (savedLanguage == null) { return getUseXQuery() ? PathLanguage.XQUERY : PathLanguage.XPATH; } return PathLanguage.valueOf(savedLanguage.toString()); } public void setTargetPathLanguage(PathLanguage language) { getConfig().setTargetTransferType(PropertyTransferTypesConfig.Enum.forInt(language.ordinal() + 1)); } public PathLanguage getTargetPathLanguage() { return transferLanguageFromPropertyTransferType(getConfig().getTargetTransferType()); } private void initListeners() { if (currentSourceStep != null) { if (currentSourceStep instanceof TestStep) { ((TestStep) currentSourceStep) .addPropertyChangeListener(TestStep.NAME_PROPERTY, stepNameChangeListener); } currentSourceStep.addTestPropertyListener(propertyNameChangeListener); } if (currentTargetStep != null) { if (currentTargetStep instanceof TestStep) { ((TestStep) currentTargetStep) .addPropertyChangeListener(TestStep.NAME_PROPERTY, stepNameChangeListener); } currentTargetStep.addTestPropertyListener(propertyNameChangeListener); } } public void releaseListeners() { if (currentSourceStep != null) { if (currentSourceStep instanceof TestStep) { ((TestStep) currentSourceStep).removePropertyChangeListener(TestStep.NAME_PROPERTY, stepNameChangeListener); } currentSourceStep.removeTestPropertyListener(propertyNameChangeListener); } if (currentTargetStep != null) { if (currentTargetStep instanceof TestStep) { ((TestStep) currentTargetStep).removePropertyChangeListener(TestStep.NAME_PROPERTY, stepNameChangeListener); } currentTargetStep.removeTestPropertyListener(propertyNameChangeListener); } PropertyChangeListener[] listeners = propertyChangeSupport.getPropertyChangeListeners(); for (PropertyChangeListener listener : listeners) { propertyChangeSupport.removePropertyChangeListener(listener); } } public void release() { releaseListeners(); testCase.getTestSuite().removeTestSuiteListener(testSuiteListener); } public PropertyTransferConfig getConfig() { return config; } public String getSourcePath() { return sourcePath; } public String getTargetPath() { return targetPath; } public TestProperty getSourceProperty() { if (sourceType == null) { return null; } if (currentSourceProperty != null) { return currentSourceProperty; } TestPropertyHolder actualSourceStep = getSourceStep(); return actualSourceStep == null ? null : actualSourceStep.getProperty(sourceType); } public String[] transferProperties(SubmitContext context) throws PropertyTransferException { TestProperty sourceProperty = getSourceProperty(); TestProperty targetProperty = getTargetProperty(); try { if (sourceProperty == null) { throw new Exception("Missing source property"); } if (targetProperty == null) { throw new Exception("Missing target property"); } if (sourceProperty.getValue() == null && !getSetNullOnMissingSource() && !getIgnoreEmpty()) { throw new Exception("Source property is null"); } if (bothPathsAreXmlBased()) { return transferXPathToXml(getSourceProperty(), getTargetProperty(), context); } else { Object sourceValue = readSourceValue(context); sourceValue = entitizeIfApplicable(sourceValue); if (isResponseProperty(sourceProperty) && sourceValue instanceof String) { sourceValue = removeExpansions((String) sourceValue); } return writeTargetValue(sourceValue, context); } } catch (Exception e) { throw new PropertyTransferException(e.getMessage(), getSourceStepName(), sourceProperty, getTargetStepName(), targetProperty); } } private boolean isResponseProperty(TestProperty sourceProperty) { String propertyName = sourceProperty.getName(); return propertyName.equals("Response") || propertyName.equals("RawResponse") || propertyName.equals("ResponseAsXml"); } private Object entitizeIfApplicable(Object sourceValue) { if (sourceValue instanceof String && StringUtils.hasContent((String) sourceValue) && getEntitize()) { return XmlUtils.entitize((String) sourceValue); } return sourceValue; } private Object readSourceValue(PropertyExpansionContext context) throws Exception { String sourceValue = getSourceProperty().getValue(); if (!hasSourcePath()) { return sourceValue; } else if (getSourcePathLanguage() == PathLanguage.JSONPATH) { return new JsonPathFacade(sourceValue).readObjectValue(getSourcePath()); } else { XmlObject sourceXml = XmlUtils.createXmlObject(sourceValue); XmlCursor sourceCursor = sourceXml.newCursor(); try { String value = null; String pathExpression = PropertyExpander.expandProperties(context, getSourcePath()); boolean usingXQuery = getSourcePathLanguage() == PathLanguage.XQUERY; if (usingXQuery) { XmlCursor resultCursor = sourceCursor.execQuery(pathExpression); sourceCursor.dispose(); sourceCursor = resultCursor; if (sourceCursor.toNextToken() != TokenType.START && !getSetNullOnMissingSource() && !getIgnoreEmpty()) { throw new Exception("Missing match for Source XQuery [" + pathExpression + "]"); } } else { sourceCursor.selectPath(pathExpression); } if (!usingXQuery && !sourceCursor.toNextSelection()) { if (!getSetNullOnMissingSource() && !getIgnoreEmpty()) { throw new Exception("Missing match for Source XPath [" + pathExpression + "]"); } } Node sourceNode = sourceCursor.getDomNode(); short sourceNodeType = sourceNode.getNodeType(); if (sourceNodeType == Node.DOCUMENT_FRAGMENT_NODE) { sourceNode = sourceNode.getFirstChild(); if (sourceNode != null) { sourceNodeType = sourceNode.getNodeType(); } else { throw new Exception("Missing source value for " + getSourcePropertyName()); } } if (sourceNodeType == Node.TEXT_NODE || sourceNodeType == Node.ATTRIBUTE_NODE) { value = sourceNode.getNodeValue(); } else if (sourceNodeType == Node.ELEMENT_NODE) { if (getTransferTextContent()) { value = XmlUtils.getElementText((Element) sourceNode); } if (value == null || !getTransferTextContent()) { value = sourceCursor.getObject().xmlText( new XmlOptions().setSaveOuter().setSaveAggressiveNamespaces()); } } return value; } finally { if (sourceCursor != null) { sourceCursor.dispose(); } } } } private String[] writeTargetValue(Object value, SubmitContext context) throws Exception { String stringValue = value == null ? null : String.valueOf(value); if (!hasTargetPath()) { getTargetProperty().setValue(stringValue); } else { String targetPath = PropertyExpander.expandProperties(context, getTargetPath()); if (getTargetPathLanguage() == PathLanguage.JSONPATH) { JsonPathFacade jsonPathFacade = new JsonPathFacade(getTargetProperty().getValue()); jsonPathFacade.writeValue(targetPath, value); getTargetProperty().setValue(jsonPathFacade.getCurrentJson()); } else { XmlObject targetXml = XmlObject.Factory.parse(getTargetProperty().getValue()); XmlCursor targetCursor = targetXml.newCursor(); try { List<String> result = new ArrayList<String>(); targetCursor.selectPath(targetPath); if (!targetCursor.toNextSelection()) { throw new Exception("Missing match for Target XPath [" + targetPath + "]"); } Node targetNode = targetCursor.getDomNode(); setNodeValue(stringValue, targetNode); result.add(stringValue); if (getTransferToAll()) { while (targetCursor.toNextSelection()) { targetNode = targetCursor.getDomNode(); setNodeValue(stringValue, targetNode); result.add(stringValue); } } getTargetProperty().setValue(targetXml.xmlText(new XmlOptions().setSaveAggressiveNamespaces())); return result.toArray(new String[result.size()]); } finally { targetCursor.dispose(); } } } return new String[]{stringValue}; } private boolean bothPathsAreXmlBased() { return hasSourcePath() && hasTargetPath() && getSourcePathLanguage() != PathLanguage.JSONPATH && getTargetPathLanguage() != PathLanguage.JSONPATH; } private boolean hasTargetPath() { String path = getTargetPath(); return path != null && path.trim().length() > 0; } private boolean hasSourcePath() { String path = getSourcePath(); return path != null && path.trim().length() > 0; } protected String[] transferXPathToXml(TestProperty sourceProperty, TestProperty targetProperty, SubmitContext context) throws Exception { XmlCursor sourceXml; try { String sourcePropertyValue = sourceProperty.getValue(); if (isResponseProperty(sourceProperty)) { sourcePropertyValue = removeExpansions(sourceProperty.getValue()); } XmlObject sourceXmlObject = sourcePropertyValue == null ? null : XmlUtils .createXmlObject(sourcePropertyValue); sourceXml = sourceXmlObject == null ? null : sourceXmlObject.newCursor(); } catch (XmlException e) { throw new Exception("Error parsing source property [" + e.getMessage() + "]"); } XmlObject targetXmlObject; XmlCursor targetXml; try { String targetPropertyValue = targetProperty.getValue(); targetXmlObject = XmlUtils.createXmlObject(targetPropertyValue); targetXml = targetXmlObject.newCursor(); } catch (XmlException e) { throw new Exception("Error parsing target property [" + e.getMessage() + "]"); } XmlCursor lastSource = null; try { List<String> result = new ArrayList<String>(); String tp = PropertyExpander.expandProperties(context, getTargetPath()); targetXml.selectPath(tp); if (!targetXml.hasNextSelection()) { throw new Exception("Missing match for Target XPath [" + tp + "]"); } if (sourceXml == null) { if (getSetNullOnMissingSource()) { while (targetXml.toNextSelection()) { result.add(setNodeValue(null, targetXml.getDomNode())); if (!getTransferToAll()) { break; } } } } else if (getSourcePathLanguage() == PathLanguage.XQUERY) { String sp = PropertyExpander.expandProperties(context, getSourcePath()); XmlCursor resultCursor = sourceXml.execQuery(sp); sourceXml.dispose(); sourceXml = resultCursor; if (sourceXml.toNextToken() != TokenType.START) { if (getSetNullOnMissingSource()) { while (targetXml.toNextSelection()) { result.add(setNodeValue(null, targetXml.getDomNode())); if (!getTransferToAll()) { break; } } } else if (!getIgnoreEmpty()) { throw new Exception("Missing match for Source XQuery [" + sp + "]"); } } boolean hasTarget = targetXml.toNextSelection(); if (hasTarget) { lastSource = sourceXml.newCursor(); result.add(transferXmlValue(sourceXml, targetXml)); } } else { String sp = PropertyExpander.expandProperties(context, getSourcePath()); sourceXml.selectPath(sp); if (!sourceXml.hasNextSelection()) { if (getSetNullOnMissingSource()) { while (targetXml.toNextSelection()) { result.add(setNodeValue(null, targetXml.getDomNode())); if (!getTransferToAll()) { break; } } } else if (!getIgnoreEmpty()) { throw new Exception("Missing match for Source XPath [" + sp + "]"); } } else { boolean hasSource = sourceXml.toNextSelection(); boolean hasTarget = targetXml.toNextSelection(); while (hasSource && hasTarget) { if (lastSource != null) { lastSource.dispose(); } lastSource = sourceXml.newCursor(); result.add(transferXmlValue(sourceXml, targetXml)); hasSource = sourceXml.toNextSelection(); hasTarget = targetXml.toNextSelection(); } if (getTransferToAll() && !hasSource && hasTarget && lastSource != null) { while (hasTarget) { result.add(transferXmlValue(lastSource, targetXml)); hasTarget = targetXml.toNextSelection(); } } } } if (result.size() > 0) { String value = targetXmlObject.xmlText(new XmlOptions().setSaveAggressiveNamespaces()); // if( getEntitize() ) // value = XmlUtils.entitize( value ); targetProperty.setValue(value); } return result.toArray(new String[result.size()]); } finally { if (sourceXml != null) { sourceXml.dispose(); } if (targetXml != null) { targetXml.dispose(); } if (lastSource != null) { lastSource.dispose(); } } } private String setNodeValue(String value, Node node) throws Exception { short targetNodeType = node.getNodeType(); if (targetNodeType == Node.DOCUMENT_FRAGMENT_NODE) { node = node.getFirstChild(); if (node != null) { targetNodeType = node.getNodeType(); } else { throw new Exception("Missing source value for " + getSourcePropertyName()); } } if (!XmlUtils.setNodeValue(node, value)) { throw new Exception("Failed to set value to node [" + node.toString() + "] of type [" + targetNodeType + "]"); } return value; } /** * Method called for transferring between 2 xml properties.. */ private String transferXmlValue(XmlCursor source, XmlCursor dest) throws Exception { // just copy if nodes are of same type Node destNode = dest.getDomNode(); Node sourceNode = source.getDomNode(); short destNodeType = destNode.getNodeType(); short sourceNodeType = sourceNode.getNodeType(); String value = null; if (getTransferChildNodes()) { while (destNode.hasChildNodes()) { destNode.removeChild(destNode.getFirstChild()); } NodeList childNodes = sourceNode.getChildNodes(); for (int c = 0; c < childNodes.getLength(); c++) { destNode.appendChild(destNode.getOwnerDocument().importNode(childNodes.item(c), true)); } return XmlUtils.serialize(destNode, false); } if (sourceNodeType == Node.DOCUMENT_FRAGMENT_NODE) { sourceNode = sourceNode.getFirstChild(); if (sourceNode != null) { sourceNodeType = sourceNode.getNodeType(); } else { throw new Exception("Missing source value for " + source); } } // same type of node? if (destNodeType == sourceNodeType) { if (destNodeType == Node.TEXT_NODE || destNodeType == Node.ATTRIBUTE_NODE) { value = sourceNode.getNodeValue(); if (!getIgnoreEmpty() || (value != null && value.length() > 0)) { if (getEntitize()) { value = XmlUtils.entitize(value); } destNode.setNodeValue(value); } } else if (config.getTransferTextContent() && destNodeType == Node.ELEMENT_NODE) { value = XmlUtils.getElementText((Element) sourceNode); if (value == null && sourceNode.getFirstChild() != null) { value = source.getObject().xmlText(new XmlOptions().setSaveOuter().setSaveAggressiveNamespaces()); if (getEntitize()) { value = XmlUtils.entitize(value); } destNode.getParentNode().replaceChild(destNode.getOwnerDocument().importNode(sourceNode, true), destNode); } else if (!getIgnoreEmpty() || (value != null && value.length() > 0)) { if (getEntitize()) { value = XmlUtils.entitize(value); } XmlUtils.setElementText((Element) destNode, value); } } else { destNode.getParentNode().replaceChild( destNode.getOwnerDocument().importNode(sourceNode, true), destNode); value = dest.xmlText(); } } // text to attribute? else if ((sourceNodeType == Node.TEXT_NODE && destNodeType == Node.ATTRIBUTE_NODE) || (sourceNodeType == Node.ATTRIBUTE_NODE && destNodeType == Node.TEXT_NODE)) { value = sourceNode.getNodeValue(); if (!getIgnoreEmpty() || (value != null && value.length() > 0)) { if (getEntitize()) { value = XmlUtils.entitize(value); } destNode.setNodeValue(value); } } else if (sourceNodeType == Node.ELEMENT_NODE && destNodeType == Node.ATTRIBUTE_NODE || destNodeType == Node.TEXT_NODE) { value = XmlUtils.getElementText((Element) sourceNode); if (!getIgnoreEmpty() || (value != null && value.length() > 0)) { if (getEntitize()) { value = XmlUtils.entitize(value); } destNode.setNodeValue(value); } } else if (destNodeType == Node.ELEMENT_NODE && sourceNodeType == Node.ATTRIBUTE_NODE || sourceNodeType == Node.TEXT_NODE) { // hmm.. not sure xmlbeans handles this ok value = sourceNode.getNodeValue(); if (!getIgnoreEmpty() || (value != null && value.length() > 0)) { if (getEntitize()) { value = XmlUtils.entitize(value); } XmlUtils.setElementText((Element) destNode, value); } } return value; } /** * Returns the name of the source property. */ public String getSourcePropertyName() { if (sourceType == null) { return null; } if (currentSourceProperty != null) { return currentSourceProperty.getName(); } TestPropertyHolder actualSourceStep = getSourceStep(); if (actualSourceStep == null) { return sourceType; } TestProperty property = actualSourceStep.getProperty(sourceType); return property == null ? sourceType : property.getName(); } public void setSourcePropertyName(String name) { String old = getSourcePropertyName(); // check for change if ((name == null && old == null) || (name != null && old != null && name.equals(old))) { return; } // update sourceType = name; config.setSourceType(name); // update actual property TestPropertyHolder sourceStep2 = getSourceStep(); currentSourceProperty = sourceStep2 != null && sourceType != null ? sourceStep2.getProperty(sourceType) : null; // notify! propertyChangeSupport.firePropertyChange(SOURCE_TYPE_PROPERTY, old, name); } public TestProperty getTargetProperty() { if (targetType == null) { return null; } if (currentTargetProperty != null) { return currentTargetProperty; } TestPropertyHolder actualTargetStep = getTargetStep(); return actualTargetStep == null ? null : actualTargetStep.getProperty(targetType); } public String getTargetPropertyName() { if (targetType == null) { return null; } if (currentTargetProperty != null) { return currentTargetProperty.getName(); } TestPropertyHolder actualTargetStep = getTargetStep(); TestProperty property = actualTargetStep == null ? null : actualTargetStep.getProperty(targetType); return actualTargetStep == null || property == null ? targetType : property.getName(); } public void setTargetPropertyName(String name) { String old = getTargetPropertyName(); // check for change if ((name == null && old == null) || (name != null && old != null && name.equals(old))) { return; } // update targetType = name; config.setTargetType(name); // update actual property TestPropertyHolder targetStep2 = getTargetStep(); currentTargetProperty = targetStep2 != null && targetType != null ? targetStep2.getProperty(targetType) : null; // notify! propertyChangeSupport.firePropertyChange(TARGET_TYPE_PROPERTY, old, name); } public String getName() { return config.getName(); } public void setSourcePath(String path) { String old = sourcePath; sourcePath = path; config.setSourcePath(path); propertyChangeSupport.firePropertyChange(SOURCE_PATH_PROPERTY, old, path); } public void setTargetPath(String path) { String old = targetPath; targetPath = path; config.setTargetPath(path); propertyChangeSupport.firePropertyChange(TARGET_PATH_PROPERTY, old, path); } public void setName(String name) { String old = this.name; this.name = name; config.setName(name); propertyChangeSupport.firePropertyChange(NAME_PROPERTY, old, name); } public TestPropertyHolder getSourceStep() { return getPropertyHolder(getSourceStepName()); } public String getSourceStepName() { if (sourceStep != null) { return sourceStep; } if (testCase == null) { return null; } HttpRequestTestStep step = testCase.findPreviousStepOfType(this.testStep, HttpRequestTestStep.class); return step == null ? null : step.getName(); } public void setSourceStepName(String sourceStep) { String old = getSourceStepName(); // check for change if ((sourceStep == null && old == null) || (sourceStep != null && old != null && sourceStep.equals(old))) { return; } if (sourceStep == null) { log.debug("Setting sourceStep for transfer [" + getName() + "] to null"); } this.sourceStep = sourceStep; config.setSourceStep(sourceStep); if (currentSourceStep != null) { if (currentSourceStep instanceof TestStep) { ((TestStep) currentSourceStep).removePropertyChangeListener(TestStep.NAME_PROPERTY, stepNameChangeListener); } currentSourceStep.removeTestPropertyListener(propertyNameChangeListener); } currentSourceStep = getPropertyHolder(sourceStep); if (currentSourceStep != null) { if (currentSourceStep instanceof TestStep) { ((TestStep) currentSourceStep) .addPropertyChangeListener(TestStep.NAME_PROPERTY, stepNameChangeListener); } currentSourceStep.addTestPropertyListener(propertyNameChangeListener); } else { log.warn("Failed to get sourceStep [" + sourceStep + "]"); } propertyChangeSupport.firePropertyChange(SOURCE_STEP_PROPERTY, old, sourceStep); setSourcePropertyName(null); } public TestPropertyHolder getTargetStep() { return getPropertyHolder(getTargetStepName()); } public String getTargetStepName() { if (targetStep != null) { return targetStep; } if (testCase == null) { return null; } HttpRequestTestStep step = testCase.findNextStepOfType(this.testStep, HttpRequestTestStep.class); return step == null ? null : step.getName(); } public void setTargetStepName(String targetStep) { String old = getTargetStepName(); // check for change if ((targetStep == null && old == null) || (targetStep != null && old != null && targetStep.equals(old))) { return; } if (targetStep == null) { log.debug("Setting targetStep for transfer [" + getName() + "] to null"); } this.targetStep = targetStep; config.setTargetStep(targetStep); if (currentTargetStep != null) { if (currentTargetStep instanceof TestStep) { ((TestStep) currentTargetStep).removePropertyChangeListener(TestStep.NAME_PROPERTY, stepNameChangeListener); } currentTargetStep.removeTestPropertyListener(propertyNameChangeListener); } currentTargetStep = getPropertyHolder(targetStep); if (currentTargetStep != null) { if (currentTargetStep instanceof TestStep) { ((TestStep) currentTargetStep) .addPropertyChangeListener(TestStep.NAME_PROPERTY, stepNameChangeListener); } currentTargetStep.addTestPropertyListener(propertyNameChangeListener); } else { log.warn("Failed to get targetStep [" + targetStep + "]"); } propertyChangeSupport.firePropertyChange(TARGET_STEP_PROPERTY, old, targetStep); setTargetPropertyName(null); } private TestPropertyHolder getPropertyHolder(String name) { if (!StringUtils.hasContent(name) || testCase == null) { return null; } if (name.charAt(0) == PropertyExpansion.SCOPE_PREFIX) { if (name.equals(PropertyExpansion.GLOBAL_REFERENCE)) { return PropertyExpansionUtils.getGlobalProperties(); } if (name.equals(PropertyExpansion.PROJECT_REFERENCE)) { return testCase.getTestSuite().getProject(); } if (name.equals(PropertyExpansion.TESTSUITE_REFERENCE)) { return testCase.getTestSuite(); } if (name.equals(PropertyExpansion.TESTCASE_REFERENCE)) { return testCase; } } return testStep.getTestCase().getTestStepByName(name); } public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { propertyChangeSupport.addPropertyChangeListener(propertyName, listener); } public void addPropertyChangeListener(PropertyChangeListener listener) { propertyChangeSupport.addPropertyChangeListener(listener); } public void removePropertyChangeListener(PropertyChangeListener listener) { propertyChangeSupport.removePropertyChangeListener(listener); } public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { propertyChangeSupport.removePropertyChangeListener(propertyName, listener); } public boolean getFailOnError() { return config.getFailOnError(); } public void setFailOnError(boolean failOnError) { config.setFailOnError(failOnError); } public boolean getTransferToAll() { return config.getTransferToAll(); } public void setTransferToAll(boolean transferToAll) { config.setTransferToAll(transferToAll); } public boolean getUseXQuery() { return config.getUseXQuery(); } public void setUseXQuery(boolean useXQuery) { config.setUseXQuery(useXQuery); } public boolean getEntitize() { return config.getEntitize(); } public void setEntitize(boolean entitize) { config.setEntitize(entitize); } public boolean getIgnoreEmpty() { return config.getIgnoreEmpty(); } public void setIgnoreEmpty(boolean ignoreEmpty) { config.setIgnoreEmpty(ignoreEmpty); } public boolean getSetNullOnMissingSource() { return config.getSetNullOnMissingSource(); } public void setSetNullOnMissingSource(boolean setNullOnMissingSource) { config.setSetNullOnMissingSource(setNullOnMissingSource); } public boolean getTransferTextContent() { return config.getTransferTextContent(); } public void setTransferTextContent(boolean transferTextContent) { config.setTransferTextContent(transferTextContent); } public boolean isDisabled() { return config.getDisabled(); } public void setDisabled(boolean disabled) { config.setDisabled(disabled); } public boolean getTransferChildNodes() { return config.getTransferChildNodes(); } public void setTransferChildNodes(boolean b) { config.setTransferChildNodes(b); } private final class InternalTestSuiteListener extends TestSuiteListenerAdapter { public void testStepRemoved(TestStep testStep, int index) { if (testStep.getTestCase() == testCase) { String stepName = testStep.getName(); if (stepName.equals(sourceStep)) { setSourceStepName(null); } if (stepName.equals(targetStep)) { setTargetStepName(null); } } } } /** * Handle changes to source/target testStep names * * @author Ole.Matzura */ private class StepNameChangeListener implements PropertyChangeListener { public void propertyChange(PropertyChangeEvent evt) { String oldName = (String) evt.getOldValue(); String newValue = (String) evt.getNewValue(); if (newValue == null) { log.error("Tried to change stepname to null!"); Thread.dumpStack(); return; } if (oldName.equals(sourceStep) && currentSourceStep instanceof TestStep) { sourceStep = newValue; config.setSourceStep(sourceStep); propertyChangeSupport.firePropertyChange(SOURCE_STEP_PROPERTY, oldName, sourceStep); } if (oldName.equals(targetStep) && currentTargetStep instanceof TestStep) { targetStep = newValue; config.setTargetStep(targetStep); propertyChangeSupport.firePropertyChange(TARGET_STEP_PROPERTY, oldName, targetStep); } } } /** * Handle changes to source/target property names * * @author Ole.Matzura */ private class InternalTestPropertyListener extends TestPropertyListenerAdapter { public void propertyRenamed(String oldName, String newName) { if (oldName.equals(sourceType)) { sourceType = newName; config.setSourceType(sourceType); propertyChangeSupport.firePropertyChange(SOURCE_TYPE_PROPERTY, oldName, sourceType); } if (oldName.equals(targetType)) { targetType = newName; config.setTargetType(targetType); propertyChangeSupport.firePropertyChange(TARGET_TYPE_PROPERTY, oldName, targetType); } } public void propertyRemoved(String name) { if (name.equals(sourceType)) { log.warn("source property for transfer [" + getName() + "] in teststep [" + testStep.getName() + "/" + testStep.getTestCase().getName() + "/" + testStep.getTestCase().getTestSuite().getName() + "] set to null, was [" + name + "]"); currentSourceProperty = null; setSourcePropertyName(null); } if (name.equals(targetType)) { log.warn("target property for transfer [" + getName() + "] in teststep [" + testStep.getName() + "/" + testStep.getTestCase().getName() + "/" + testStep.getTestCase().getTestSuite().getName() + "] set to null, was [" + name + "]"); currentTargetProperty = null; setTargetPropertyName(null); } } } @SuppressWarnings("unchecked") public void resolve(ResolveContext<?> context, PropertyTransfersTestStep parent) { if (isDisabled()) { return; } if (getSourceProperty() == null) { if (context.hasThisModelItem(parent, "Resolve source property", getConfig().getSourceStep())) { return; } context.addPathToResolve(parent, "Resolve source property", getConfig().getSourceStep()).addResolvers( new DisablePropertyTransferResolver(this), new CreateMissingPropertyResolver(this, parent), new ChooseAnotherPropertySourceResolver(this, parent)); } else { if (context.hasThisModelItem(parent, "Resolve source property", getConfig().getSourceStep())) { PathToResolve path = context.getPath(parent, "Resolve source property", getConfig().getSourceStep()); path.setSolved(true); } } if (getTargetProperty() == null) { if (context.hasThisModelItem(parent, "Resolve target property", getConfig().getTargetStep())) { return; } context.addPathToResolve(parent, "Resolve target property", getConfig().getTargetStep()).addResolvers( new DisablePropertyTransferResolver(this), new CreateMissingPropertyResolver(this, parent), new ChooseAnotherPropertyTargetResolver(this, parent)); } else { if (context.hasThisModelItem(parent, "Resolve target property", getConfig().getTargetStep())) { PathToResolve path = context.getPath(parent, "Resolve target property", getConfig().getTargetStep()); path.setSolved(true); } } } }