/*
* 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.model.propertyexpansion;
import com.eviware.soapui.SoapUI;
import com.eviware.soapui.SoapUIExtensionClassLoader;
import com.eviware.soapui.SoapUIExtensionClassLoader.SoapUIClassLoaderState;
import com.eviware.soapui.impl.wsdl.support.http.ProxyUtils;
import com.eviware.soapui.model.ModelItem;
import com.eviware.soapui.model.propertyexpansion.resolvers.ContextPropertyResolver;
import com.eviware.soapui.model.propertyexpansion.resolvers.DynamicPropertyResolver;
import com.eviware.soapui.model.propertyexpansion.resolvers.EvalPropertyResolver;
import com.eviware.soapui.model.propertyexpansion.resolvers.GlobalPropertyResolver;
import com.eviware.soapui.model.propertyexpansion.resolvers.MockRunPropertyResolver;
import com.eviware.soapui.model.propertyexpansion.resolvers.ModelItemPropertyResolver;
import com.eviware.soapui.model.propertyexpansion.resolvers.PropertyResolver;
import com.eviware.soapui.model.propertyexpansion.resolvers.PropertyResolverFactory;
import com.eviware.soapui.model.propertyexpansion.resolvers.SubmitPropertyResolver;
import com.eviware.soapui.model.propertyexpansion.resolvers.TestRunPropertyResolver;
import com.eviware.soapui.model.support.ModelSupport;
import com.eviware.soapui.model.testsuite.TestCase;
import com.eviware.soapui.settings.GlobalPropertySettings;
import com.eviware.soapui.support.StringUtils;
import com.eviware.soapui.support.factory.SoapUIFactoryRegistryListener;
import com.eviware.soapui.support.types.StringToStringMap;
import com.eviware.soapui.support.xml.XmlUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Class that can expand properties using property resolvers
*
* @author ole
*/
public class PropertyExpander implements SoapUIFactoryRegistryListener {
private List<PropertyResolver> propertyResolvers = new ArrayList<PropertyResolver>();
private static List<PropertyResolver> defaultResolvers = new ArrayList<PropertyResolver>();
private static PropertyExpander defaultExpander;
private static boolean debuggingMode;
private static Map<String, StringToStringMap> debuggingExpandedProperties;
static {
// add default resolvers - this should be read from some external config
// in the future
defaultResolvers.add(new ModelItemPropertyResolver());
defaultResolvers.add(new TestRunPropertyResolver());
defaultResolvers.add(new MockRunPropertyResolver());
defaultResolvers.add(new SubmitPropertyResolver());
defaultResolvers.add(new ContextPropertyResolver());
defaultResolvers.add(new DynamicPropertyResolver());
defaultResolvers.add(new GlobalPropertyResolver());
defaultResolvers.add(new EvalPropertyResolver());
defaultExpander = new PropertyExpander(true);
for (PropertyResolverFactory factory : SoapUI.getFactoryRegistry().getFactories(PropertyResolverFactory.class)) {
defaultExpander.addResolverFactory(factory);
}
// WORKAROUND: eliminates a potential problem with a circular dependency between HttpClientSupport and this class
ProxyUtils.setGlobalProxy(SoapUI.getSettings());
debuggingExpandedProperties = new HashMap<String, StringToStringMap>();
}
public PropertyExpander(boolean addDefaultResolvers) {
if (addDefaultResolvers) {
propertyResolvers.addAll(defaultResolvers);
SoapUI.getFactoryRegistry().addFactoryRegistryListener( this );
}
}
public static PropertyExpander getDefaultExpander() {
return defaultExpander;
}
@Deprecated
public static void addDefaultResolver(PropertyResolver resolver) {
defaultResolvers.add(resolver);
defaultExpander.addResolver(resolver);
}
public void addResolver(PropertyResolver propertyResolver) {
propertyResolvers.add(propertyResolver);
}
public void addResolverFactory( PropertyResolverFactory factory )
{
PropertyResolver resolver = factory.createPropertyResolver();
addResolver( resolver );
resolverFactories.put( factory, resolver );
}
private Map<PropertyResolverFactory,PropertyResolver> resolverFactories = new HashMap<PropertyResolverFactory, PropertyResolver>();
public void removeResolverFactory( PropertyResolverFactory factory )
{
if( resolverFactories.containsKey( factory )) {
removeResolver( resolverFactories.get( factory ));
resolverFactories.remove(factory);
}
}
private void removeResolver(PropertyResolver propertyResolver) {
propertyResolvers.remove( propertyResolver );
}
public static String expandProperties(String content) {
return defaultExpander.expand(content);
}
public static String expandProperties(PropertyExpansionContext context, String content) {
return defaultExpander.expand(context, content, false);
}
public static String expandProperties(PropertyExpansionContext context, String content, boolean entitize) {
return defaultExpander.expand(context, content, entitize);
}
public String expand(String content) {
return expand(new PropertyExpansionUtils.GlobalPropertyExpansionContext(), content, false);
}
public String expand(PropertyExpansionContext context, String content) {
return expand(context, content, false);
}
public String expand(PropertyExpansionContext context, String content, boolean entitize) {
SoapUIClassLoaderState clState = SoapUIExtensionClassLoader.ensure();
try {
if (StringUtils.isNullOrEmpty(content)) {
return content;
}
int ix = content.indexOf("${");
if (ix == -1) {
return content;
}
StringBuffer buf = new StringBuffer();
int lastIx = 0;
while (ix != -1) {
if (ix > lastIx && content.charAt(ix - 1) == '$') {
buf.append(content.substring(lastIx, ix - 1));
lastIx = ix;
ix = content.indexOf("${", lastIx + 1);
continue;
}
if (ix > lastIx) {
buf.append(content.substring(lastIx, ix));
}
int ix2 = content.indexOf('}', ix + 2);
if (ix2 == -1) {
break;
}
// check for nesting
int ix3 = content.lastIndexOf("${", ix2);
if (ix3 != ix) {
// buf.append( content.substring( ix, ix3 ));
content = content.substring(0, ix3) + expand(context, content.substring(ix3, ix2 + 1))
+ content.substring(ix2 + 1);
lastIx = ix;
continue;
}
String propertyName = content.substring(ix + 2, ix2);
String propertyValue = null;
if (StringUtils.hasContent(propertyName)) {
boolean globalOverrideEnabled = SoapUI.getSettings().getBoolean(GlobalPropertySettings.ENABLE_OVERRIDE);
for (int c = 0; c < propertyResolvers.size() && propertyValue == null; c++) {
propertyValue = propertyResolvers.get(c).resolveProperty(context, propertyName,
globalOverrideEnabled);
}
}
// found a value?
if (propertyValue != null) {
if (!content.equals(propertyValue)) {
propertyValue = expand(context, propertyValue);
}
if (entitize) {
propertyValue = XmlUtils.entitize(propertyValue);
}
TestCase testCase = ModelSupport.getModelItemTestCase(context.getModelItem());
if (debuggingMode && testCase != null) {
StringToStringMap props = debuggingExpandedProperties.get(testCase.getId());
if (props == null) {
props = new StringToStringMap();
}
props.put(propertyName, propertyValue);
debuggingExpandedProperties.put(testCase.getId(), props);
}
buf.append(propertyValue);
} else {
// if( log.isEnabledFor( Priority.WARN ))
// log.warn( "Missing property value for [" + propertyName + "]"
// );
// buf.append( "${" ).append( propertyName ).append( '}' );
}
lastIx = ix2 + 1;
ix = content.indexOf("${", lastIx);
}
if (lastIx < content.length()) {
buf.append(content.substring(lastIx));
}
return buf.toString();
} finally {
clState.restore();
}
}
public String expand(ModelItem contextModelItem, String content) {
return expand(new DefaultPropertyExpansionContext(contextModelItem), content);
}
public static String expandProperties(ModelItem contextModelItem, String content) {
return defaultExpander.expand(contextModelItem, content);
}
public static void setDebuggingMode(String testCaseId, boolean debug) {
debuggingMode = debug;
if (debug) {
if (debuggingExpandedProperties.get(testCaseId) == null) {
debuggingExpandedProperties.put(testCaseId, new StringToStringMap());
}
} else {
if (debuggingExpandedProperties.get(testCaseId) != null) {
debuggingExpandedProperties.remove(testCaseId);
}
}
}
public static StringToStringMap getDebuggingExpandedProperties(String testCaseId) {
return debuggingExpandedProperties.get(testCaseId);
}
public static void clearDebuggingExpandedProperties(String testCaseId) {
debuggingExpandedProperties.remove(testCaseId);
}
@Override
public void factoryAdded(Class<?> factoryType, Object factory) {
if( factory instanceof PropertyResolverFactory )
addResolverFactory((PropertyResolverFactory) factory);
}
@Override
public void factoryRemoved(Class<?> factoryType, Object factory) {
if( factory instanceof PropertyResolverFactory )
removeResolverFactory((PropertyResolverFactory) factory);
}
}