com.sforce.ws.codegen.ConnectionMetadataConstructor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of force-wsc Show documentation
Show all versions of force-wsc Show documentation
Force.com Web Service Connector
The newest version!
/*
* Copyright (c) 2017, salesforce.com, inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided
* that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
* the following disclaimer in the documentation and/or other materials provided with the distribution.
*
* Neither the name of salesforce.com, inc. nor the names of its contributors may be used to endorse or
* promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package com.sforce.ws.codegen;
import java.util.*;
import javax.xml.namespace.QName;
import com.sforce.ws.ConnectionException;
import com.sforce.ws.bind.NameMapper;
import com.sforce.ws.bind.TypeMapper;
import com.sforce.ws.codegen.metadata.*;
import com.sforce.ws.codegen.metadata.HeaderMetadata.HeaderElementMetadata;
import com.sforce.ws.util.FileUtil;
import com.sforce.ws.wsdl.*;
import com.sforce.ws.wsdl.Collection;
/**
* @author hhildebrand
* @since 184
*/
public class ConnectionMetadataConstructor {
private final String className;
private final String packageName;
private final Definitions definitions;
protected final TypeMapper typeMapper;
public ConnectionMetadataConstructor(Definitions definitions, TypeMapper typeMapper, String packagePrefix) {
this.definitions = definitions;
this.typeMapper = typeMapper;
this.className = (definitions.getApiType() != null ? definitions.getApiType().name() : "Soap") + "Connection";
this.packageName = NameMapper.getPackageName(definitions.getTargetNamespace(), packagePrefix);
}
/**
* Converts a fully qualified java class to an interface using the convention of prefix an "I" to the classname
*/
static String convertJavaClassToInterface(String javaClassName, boolean isComplexType) {
if (!isComplexType) {
return javaClassName;
}
int i = javaClassName.lastIndexOf(".");
return javaClassName.substring(0, i+1) + "I" + javaClassName.substring(i+1);
}
public ConnectionClassMetadata getConnectionClassMetadata() {
try {
List headers = new ArrayList();
List operations = new ArrayList();
for (Iterator i = headers(); i.hasNext();) {
Part header = i.next();
List elements = new ArrayList();
for (Iterator j = headerElements(header); j.hasNext();) {
Element element = j.next();
elements.add(HeaderElementMetadata.newInstance(argSetMethod(element), argName(element)));
}
headers.add(HeaderMetadata.newInstance(headerType(header), headerName(header), headerArgs(header),
headerElement(header), elements));
}
for (Iterator i = getOperations(); i.hasNext();) {
Operation operation = i.next();
List elements = new ArrayList();
for (Iterator j = argElements(operation); j.hasNext();) {
Element element = j.next();
elements.add(ElementMetadata.newInstance(argSetMethod(element), argName(element)));
}
List operationHeaders = new ArrayList();
for (Iterator j = headersFor(operation); j.hasNext();) {
Part part = j.next();
operationHeaders.add(HeaderMetadata.newInstance(null, headerName(part), null, headerElement(part),
null));
}
operations.add(OperationMetadata.newInstance(returnType(operation), getOperationName(operation),
requestType(operation), responseType(operation), getArgs(operation, ArgListTypesToGenerate.CLASSES),
getArgs(operation, ArgListTypesToGenerate.NONE), getArgs(operation, ArgListTypesToGenerate.INTERFACE),
getArgs(operation, ArgListTypesToGenerate.CAST_TO_CLASSES), soapAction(operation),
requestName(operation), responseName(operation), getResultCall(operation), elements,
operationHeaders, isReturnTypeComplexType(operation), returnTypeInterface(operation)));
}
ConnectionClassMetadata connectionClassMetadata = ConnectionClassMetadata.newInstance(getPackagePrefix(),
packageName, className, hasLoginCall(), hasLoginCall() == true ? loginResult() : null,
verifyEndpoint(), hasSessionHeader(), sobjectNamespace(), dumpQNames(), dumpKnownHeaders(),
headers, operations);
return connectionClassMetadata;
} catch (ConnectionException e) {
throw new IllegalStateException(e);
}
}
protected String returnTypeInterface(Operation operation) throws ConnectionException {
return convertJavaClassToInterface(returnType(operation), isReturnTypeComplexType(operation));
}
protected boolean isReturnTypeComplexType(Operation operation) throws ConnectionException {
Element el = getResponseElement(operation);
return el != null && isComplexType(el);
}
public String getPackageName() {
return packageName;
}
public String endpoint() {
return definitions.getService().getPort().getSoapAddress().getLocation();
}
public String verifyEndpoint() {
return definitions.getApiType() == null ? null : definitions.getApiType().getVerifyEndpoint();
}
public String getPackagePrefix() {
String prefix = typeMapper.getPackagePrefix();
return (prefix == null) ? "null" : "\"" + prefix + "\"";
}
public String getTargetNamespace() {
return definitions.getTargetNamespace();
}
public String sobjectNamespace() {
if(definitions.getApiType() == SfdcApiType.Tooling && !hasSobjectNamespace(definitions)){
return "\"" + definitions.getApiType().getNamespace() + "\"";
}
return definitions.getApiType() == null ? "null" : "\"" + definitions.getApiType().getSobjectNamespace() + "\"";
}
private boolean hasSobjectNamespace(Definitions definitions){
for(Schema schema : definitions.getTypes().getSchemas()){
if(definitions.getApiType().getSobjectNamespace().equals(schema.getTargetNamespace())){
return true;
}
}
return false;
}
public String dumpQNames() throws ConnectionException {
StringBuilder sb = new StringBuilder();
Iterator oit = definitions.getPortType().getOperations();
while (oit.hasNext()) {
Operation operation = oit.next();
Part in = operation.getInput().getParts().next();
addQName(sb, in.getElement());
Part out = operation.getOutput().getParts().next();
addQName(sb, out.getElement());
}
Iterator parts = headers();
while (parts.hasNext()) {
Part hp = parts.next();
addQName(sb, hp.getElement());
}
return sb.toString();
}
public String dumpKnownHeaders() throws ConnectionException {
StringBuilder sb = new StringBuilder();
Iterator parts = headers();
while (parts.hasNext()) {
Part hp = parts.next();
String varName = qname(hp.getElement().getLocalPart());
sb.append(" knownHeaders.put(");
sb.append(varName).append(",");
sb.append(headerType(hp)).append(".class");
sb.append(");").append(FileUtil.EOL);
}
return sb.toString();
}
private boolean isSimpleType(Part header) throws ConnectionException {
Types types = definitions.getTypes();
Element element = types.getElement(header.getElement());
if (!element.isComplexType()) { return true; }
return typeMapper.isWellKnownType(element.getType().getNamespaceURI(), element.getType().getLocalPart());
}
public String headerName(Part header) {
return header.getName();
}
public String headerElement(Part header) throws ConnectionException {
return qname(header.getElement().getLocalPart());
}
private void addQName(StringBuilder sb, QName el) {
sb.append(" private static final javax.xml.namespace.QName ");
sb.append(qname(el.getLocalPart()));
sb.append(" = new javax.xml.namespace.QName(\"");
sb.append(el.getNamespaceURI());
sb.append("\", \"");
sb.append(el.getLocalPart());
sb.append("\");");
sb.append(FileUtil.EOL);
}
public boolean hasLoginCall() {
return definitions.getApiType() != null && definitions.getApiType().hasLoginCall();
}
private String qname(String str) {
return str + "_qname";
}
public boolean hasSessionHeader() throws ConnectionException {
Iterator it = headers();
while (it.hasNext()) {
Part part = it.next();
if (part.getName().equals("SessionHeader")) { return true; }
}
return false;
}
public Iterator headersFor(Operation operation) throws ConnectionException {
BindingOperation bop = definitions.getBinding().getOperation(operation.getName());
ArrayList parts = new ArrayList();
Iterator hit = bop.getInput().getHeaders();
while (hit.hasNext()) {
SoapHeader sh = hit.next();
parts.add(definitions.getMessage(sh.getMessage()).getPart(sh.getPart()));
}
return parts.iterator();
}
public Iterator headers() throws ConnectionException {
return definitions.getBinding().getAllHeaders();
}
public String headerType(Part header) throws ConnectionException {
if (isSimpleType(header)) {
return "java.lang.String";
} else {
ComplexType type = getType(header);
QName qn = new QName(type.getSchema().getTargetNamespace(), type.getName());
return typeMapper.getJavaClassName(qn, definitions.getTypes(), false);
}
}
public String getResultCall(Operation operation) throws ConnectionException {
// return "void".equals(returnType(operation)) ? "" : "return __response.getResult();";
Element el = getResponseElement(operation);
if (el == null) { return ""; }
return "return __response.get" + NameMapper.getMethodName(el.getName()) + "();";
}
public String soapAction(Operation operation) throws ConnectionException {
BindingOperation bop = definitions.getBinding().getOperation(operation.getName());
String soapAction = bop.getSoapAction();
return "\"" + soapAction + "\"";
}
public String returnType(Operation operation) throws ConnectionException {
Element el = getResponseElement(operation);
if (el == null) { return "void"; }
return getJavaClassName(el, true);
}
public Element getResponseElement(Operation operation) throws ConnectionException {
ComplexType ct = getType(operation.getOutput());
Collection sequence = ct.getContent();
if (sequence == null) { //
return null;
}
Iterator eit = sequence.getElements();
Element result;
if (eit.hasNext()) {
result = eit.next();
if (eit.hasNext()) { throw new IllegalArgumentException("Operation.output got more than one element:"
+ operation); }
} else {
result = null; //
}
return result;
}
public String headerArgs(Part header) throws ConnectionException {
Iterator eit = headerElements(header);
return toArgs(eit, ArgListTypesToGenerate.CLASSES);
}
public Iterator headerElements(Part header) throws ConnectionException {
if (isSimpleType(header)) {
ArrayList list = new ArrayList();
return list.iterator();
} else {
ComplexType ct = getType(header);
Collection sequence = ct.getContent();
return sequence.getElements();
}
}
// For a list of arguments, generate either the types (as concrete classes or interfaces), cast them to types, or just generate the variable names
protected enum ArgListTypesToGenerate {
NONE,
CLASSES,
INTERFACE,
CAST_TO_CLASSES
}
public String getArgs(Operation operation, ArgListTypesToGenerate types) throws ConnectionException {
Iterator eit = argElements(operation);
return toArgs(eit, types);
}
private String toArgs(Iterator eit, ArgListTypesToGenerate types) {
StringBuilder sb = new StringBuilder();
while (eit.hasNext()) {
boolean appendedArgName=false;
Element el = eit.next();
if (types == ArgListTypesToGenerate.INTERFACE) {
sb.append(getJavaInterfaceName(el));
} else if (types == ArgListTypesToGenerate.CLASSES) {
sb.append(getJavaClassName(el, true));
} else if (types == ArgListTypesToGenerate.CAST_TO_CLASSES) {
if (isComplexType(el)) {
if (isArray(el)) {
// The ConnectionWrapper calls the Connection, which expects arguments of the concrete class type.
// An array of an interface type can't just be cast to the concrete class, or it'll throw a runtime
// ClassCastException. Unfortunately, it's necessary to copy the array elements to another array of
// the concrete's class type.
sb.append("castArray(").append(getJavaClassName(el, false)).append(".class, ").append(argName(el)).append(")");
appendedArgName = true;
} else {
sb.append("(").append(getJavaClassName(el, true)).append(")");
}
}
}
if (!appendedArgName) {
sb.append(" ").append(argName(el));
}
if (eit.hasNext()) {
sb.append(",");
}
}
return sb.toString();
}
public String argSetMethod(Element element) {
return "set" + NameMapper.getMethodName(element.getName());
}
public String argName(Element element) {
return element.getName();
}
public Iterator argElements(Operation operation) throws ConnectionException {
ComplexType ct = getType(operation.getInput());
Collection sequence = ct.getContent();
return (sequence == null) ? new ArrayList().iterator() : sequence.getElements();
}
public String getJavaClassName(Element el, boolean addBracketsForArray) {
String clazz = typeMapper.getJavaClassName(el.getType(), definitions.getTypes(), el.isNillable());
if (addBracketsForArray && isArray(el)) {
clazz += "[]";
}
return clazz;
}
public boolean isArray(Element el) {
return el.getMaxOccurs() != 1;
}
protected String getJavaInterfaceName(Element el) {
String clazz = getJavaClassName(el, true);
return convertJavaClassToInterface(clazz, isComplexType(el));
}
public boolean isComplexType(Element el) {
return definitions.getTypes().getComplexTypeAllowNull(el.getType()) != null;
}
public String loginResult() throws ConnectionException {
QName ln = new QName(definitions.getTargetNamespace(), "login");
Operation op = definitions.getPortType().getOperation(ln);
return returnType(op);
}
public String responseName(Operation operation) throws ConnectionException {
return qname(operation.getOutput().getParts().next().getElement().getLocalPart());
}
public String requestName(Operation operation) throws ConnectionException {
return qname(operation.getInput().getParts().next().getElement().getLocalPart());
}
public String responseType(Operation operation) throws ConnectionException {
ComplexType ct = getType(operation.getOutput());
QName type = new QName(ct.getSchema().getTargetNamespace(), ct.getName());
return typeMapper.getJavaClassName(type, definitions.getTypes(), false);
}
public String requestType(Operation operation) throws ConnectionException {
ComplexType ct = getType(operation.getInput());
QName type = new QName(ct.getSchema().getTargetNamespace(), ct.getName());
return typeMapper.getJavaClassName(type, definitions.getTypes(), false);
}
private ComplexType getType(Message message) throws ConnectionException {
Iterator it = message.getParts();
if (!it.hasNext()) { throw new IllegalArgumentException("Input for operation " + message
+ " does not have a part"); }
Part part = it.next();
if (it.hasNext()) throw new IllegalArgumentException("Found more than one part for operation " + message);
return getType(part);
}
private ComplexType getType(Part part) throws ConnectionException {
Types types = definitions.getTypes();
Element element = types.getElement(part.getElement());
QName type = element.getType();
return types.getComplexType(type);
}
public Iterator getOperations() {
return definitions.getPortType().getOperations();
}
public String getOperationName(Operation operation) {
return operation.getName().getLocalPart();
}
}