Till now the Wise core API has fundamentally been based on the WSEndpoint, WSMethod, WebParameter abstraction:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public interface WSEndpoint { | |
public Map<String, WSMethod> getWSMethods(); | |
public ClassLoader getClassLoader(); | |
// ... | |
} | |
public interface WSMethod { | |
public InvocationResult invoke(Object args) throws InvocationException, IllegalArgumentException, MappingException; | |
public Map<String, ? extends WebParameter> getWebParams(); | |
// ... | |
} | |
public interface WebParameter { | |
public String getName(); | |
public Type getType(); | |
// ... | |
} |
It's well known that Wise core supports Smooks transformations, with the sake of allowing conversion of existing application data models into the object structure required for performing the invocation. However that's not really helping a lot when the target is programmatically testing a given endpoint.
In particular some users expressed the interest in the tree view offered by the Wise GUI on top of the core model: similarly to what is shown in the GUI, a tree model (think about e.g. the DOM tree approach) could be provided to describe each parameter type of a given WSMethod. Each element of the tree would allow getting children and setting values (for leaves only). So here is what I came up with:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public interface Element extends Serializable, Cloneable { | |
public boolean isLeaf(); | |
public boolean isRemovable(); | |
public Type getClassType(); | |
public String getName(); | |
public boolean isNil(); | |
public void setNil(boolean nil); | |
public String getId(); | |
public boolean isNillable(); | |
public boolean isGroup(); | |
public void removeChild(String id); | |
public Element getChild(String id); | |
public Element getChildByName(String name); | |
public Iterator<String> getChildrenIDs(); | |
public Iterator<? extends Element> getChildren(); | |
public String getValue(); | |
public void setValue(String value); | |
public Element getPrototype(); | |
public Element incrementChildren(); | |
public int getChildrenCount(); | |
public boolean isLazy(); | |
public boolean isResolved(); | |
public Element clone(); | |
public Object toObject(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public interface ElementBuilder { | |
public ElementBuilder client(WSDynamicClient client); | |
public ElementBuilder request(boolean request); | |
public ElementBuilder useDefautValuesForNullLeaves(boolean useDefValuesForNullLeaves); | |
public Element buildTree(Type type, String name, Object value, boolean nillable); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//select a method and the parameter(s) to deal with... | |
WSMethod method = client.getWSMethod("RegistrationServiceImplService", "RegistrationServiceImplPort", "Register"); | |
Map<String, ? extends WebParameter> pars = method.getWebParams(); | |
WebParameter customerPar = pars.get("Customer"); | |
//browse the paramter structure and eventually populate the parameter... | |
ElementBuilder builder = ElementBuilderFactory.getElementBuilder().client(client).request(true).useDefautValuesForNullLeaves(true); | |
Element customerElement = builder.buildTree(customerPar.getType(), customerPar.getName(), null, true); | |
customerElement.getChildByName("id").setValue("1234"); | |
customerElement.getChildByName("name").getChildByName("firstName").setValue("Foo"); | |
customerElement.getChildByName("name").getChildByName("lastName").setValue("Bar"); | |
customerElement.getChildByName("name").getChildByName("middleName").setValue("The"); | |
//convert back the tree to an Object and perform the invocation... | |
Map<String, Object> args = new java.util.HashMap<String, Object>(); | |
args.put(customerElement.getName(), customerElement.toObject()); | |
InvocationResult result = method.invoke(args); |
Please note how the parameters type info is completely hidden to the user, who basically ends up setting string values for leaves elements. Strings are parsed into proper primitives (and wrappers) depending on the actual parameter type. Wise default Element impl is currently able to convert values to String, Character, all numerical types, QName, XMLGregorianCalendar and Duration classes.
So, leveraging Wise, a user can invoke / test an endpoint by browsing its contract and setting parameters in a fully dynamic and detyped way, while still being sure the generated SOAP request is compliant with the contract requirements and constraints.
The additions described above are currently being tested and will be included soon in next release. Any comment / feedback is welcome as usual!