Package com.salesforce.dataloader.client

Source Code of com.salesforce.dataloader.client.PartnerClient

/*
* Copyright (c) 2012, 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.salesforce.dataloader.client;

/**
* The sfdc api client class - implemented using the partner wsdl
*
* @author Lexi Viripaeff
* @since 6.0
*/

import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;

import org.apache.commons.beanutils.DynaBean;
import org.apache.log4j.Logger;

import com.salesforce.dataloader.config.Config;
import com.salesforce.dataloader.config.Messages;
import com.salesforce.dataloader.controller.Controller;
import com.salesforce.dataloader.dyna.SforceDynaBean;
import com.salesforce.dataloader.exception.ParameterLoadException;
import com.salesforce.dataloader.exception.PasswordExpiredException;
import com.sforce.soap.partner.*;
import com.sforce.soap.partner.Error;
import com.sforce.soap.partner.fault.ApiFault;
import com.sforce.soap.partner.sobject.SObject;
import com.sforce.ws.*;

public class PartnerClient extends ClientBase<PartnerConnection> {

    private static Logger LOG = Logger.getLogger(PartnerClient.class);

    PartnerConnection client;

    private static interface ClientOperation<RESULT, ARG> {
        String getName();

        RESULT run(ARG arg) throws ConnectionException;
    }

    private final ClientOperation<SaveResult[], SObject[]> INSERT_OPERATION = new ClientOperation<SaveResult[], SObject[]>() {
        @Override
        public String getName() {
            return "insert";
        }

        @Override
        public SaveResult[] run(SObject[] sObjects) throws ConnectionException {
            return getClient().create(sObjects);
        }
    };

    private final ClientOperation<SaveResult[], SObject[]> UPDATE_OPERATION = new ClientOperation<SaveResult[], SObject[]>() {
        @Override
        public String getName() {
            return "update";
        }

        @Override
        public SaveResult[] run(SObject[] sObjects) throws ConnectionException {
            return getClient().update(sObjects);
        }
    };

    private final ClientOperation<UpsertResult[], SObject[]> UPSERT_OPERATION = new ClientOperation<UpsertResult[], SObject[]>() {
        @Override
        public String getName() {
            return "upsert";
        }

        @Override
        public UpsertResult[] run(SObject[] sObjects) throws ConnectionException {
            return getClient().upsert(config.getString(Config.EXTERNAL_ID_FIELD), sObjects);
        }
    };

    private final ClientOperation<DeleteResult[], String[]> DELETE_OPERATION = new ClientOperation<DeleteResult[], String[]>() {
        @Override
        public String getName() {
            return "delete";
        }

        @Override
        public DeleteResult[] run(String[] ids) throws ConnectionException {
            return getClient().delete(ids);
        }
    };

    private final ClientOperation<QueryResult, String> QUERY_OPERATION = new ClientOperation<QueryResult, String>() {
        @Override
        public String getName() {
            return "query";
        }

        @Override
        public QueryResult run(String queryString) throws ConnectionException {
            return getClient().query(queryString);
        }
    };

    private final ClientOperation<QueryResult, String> QUERY_ALL_OPERATION = new ClientOperation<QueryResult, String>() {
        @Override
        public String getName() {
            return "queryAll";
        }

        @Override
        public QueryResult run(String queryString) throws ConnectionException {
            return getClient().queryAll(queryString);
        }
    };

    private final ClientOperation<QueryResult, String> QUERY_MORE_OPERATION = new ClientOperation<QueryResult, String>() {
        @Override
        public String getName() {
            return "queryMore";
        }

        @Override
        public QueryResult run(String queryString) throws ConnectionException {
            return getClient().queryMore(queryString);
        }
    };

    private final ClientOperation<LoginResult, PartnerConnection> LOGIN_OPERATION = new ClientOperation<LoginResult, PartnerConnection>() {
        @Override
        public String getName() {
            return "login";
        }

        @Override
        public LoginResult run(PartnerConnection client) throws ConnectionException {
            ConnectorConfig cc = client.getConfig();
            return client.login(cc.getUsername(), cc.getPassword());
        }
    };

    private final ClientOperation<DescribeGlobalResult, Object> DESCRIBE_GLOBAL_OPERATION = new ClientOperation<DescribeGlobalResult, Object>() {
        @Override
        public String getName() {
            return "describeGlobal";
        }

        @Override
        public DescribeGlobalResult run(Object ignored) throws ConnectionException {
            return getClient().describeGlobal();
        }
    };

    private final ClientOperation<DescribeSObjectResult, String> DESCRIBE_SOBJECT_OPERATION = new ClientOperation<DescribeSObjectResult, String>() {
        @Override
        public String getName() {
            return "describeSObject";
        }

        @Override
        public DescribeSObjectResult run(String entity) throws ConnectionException {
            return getClient().describeSObject(entity);
        }
    };

    private DescribeGlobalResult entityTypes;
    private final Map<String, DescribeRefObject> referenceDescribes = new HashMap<String, DescribeRefObject>();
    private final Map<String, DescribeGlobalSObjectResult> describeGlobalResults = new HashMap<String, DescribeGlobalSObjectResult>();
    private final Map<String, DescribeSObjectResult> entityDescribes = new HashMap<String, DescribeSObjectResult>();

    private final boolean enableRetries;
    private final int maxRetries;

    public PartnerClient(Controller controller) {
        super(controller, LOG);
        int retries = -1;
        this.enableRetries = config.getBoolean(Config.ENABLE_RETRIES);
        if (this.enableRetries) {
            try {
                // limit the number of max retries in case limit is exceeded
                retries = Math.min(Config.MAX_RETRIES_LIMIT, config.getInt(Config.MAX_RETRIES));
            } catch (ParameterLoadException e) {
                retries = Config.DEFAULT_MAX_RETRIES;
            }
        }
        this.maxRetries = retries;
    }

    public boolean connect() throws ConnectionException {
        return login();
    }

    @Override
    protected boolean connectPostLogin(ConnectorConfig cc) {
        if (getClient() == null) throw new IllegalStateException("Client should be logged in already");

        getClient().setCallOptions(ClientBase.getClientName(this.config), null);
        // query header
        int querySize;
        try {
            querySize = config.getInt(Config.EXTRACT_REQUEST_SIZE);
        } catch (ParameterLoadException e) {
            querySize = Config.DEFAULT_EXTRACT_REQUEST_SIZE;
        }
        if (querySize > 0) {
            getClient().setQueryOptions(querySize);
        }

        // assignment rule for update
        if (config.getString(Config.ASSIGNMENT_RULE).length() > 14) {
            String rule = config.getString(Config.ASSIGNMENT_RULE);
            if (rule.length() > 15) {
                rule = rule.substring(0, 15);
            }
            getClient().setAssignmentRuleHeader(rule, false);
        }

        // field truncation
        getClient().setAllowFieldTruncationHeader(config.getBoolean(Config.TRUNCATE_FIELDS));

        // TODO: make this configurable
        getClient().setDisableFeedTrackingHeader(true);
        return true;
    }

    public UpsertResult[] loadUpserts(List<DynaBean> dynaBeans) throws ConnectionException {
        UpsertResult[] ur = runOperation(UPSERT_OPERATION, getSobjects(dynaBeans, UPSERT_OPERATION.getName()));

        for (int j = 0; j < ur.length; j++) {
            if (ur[j].getSuccess()) {
                if (ur[j].getCreated()) {
                    logger.debug(Messages.getString("Client.itemCreated") + ur[j].getId()); //$NON-NLS-1$
                } else {
                    logger.debug(Messages.getString("Client.itemUpdated") + ur[j].getId()); //$NON-NLS-1$
                }
            }
            processResult(ur[j].getSuccess(), "Client.itemUpserted", ur[j].getId(), ur[j].getErrors(), j);
        }
        return ur;
    }

    /**
     * @param dynaBeans
     * @return SaveResult array
     * @throws ConnectionException
     */
    public SaveResult[] loadUpdates(List<DynaBean> dynaBeans) throws ConnectionException {
        return runSaveOperation(dynaBeans, UPDATE_OPERATION, false);
    }

    /**
     * @param dynaBeans
     * @return SaveResult array
     * @throws ConnectionException
     */
    public SaveResult[] loadInserts(List<DynaBean> dynaBeans) throws ConnectionException {
        return runSaveOperation(dynaBeans, INSERT_OPERATION, true);

    }

    private SaveResult[] runSaveOperation(List<DynaBean> dynaBeans, ClientOperation<SaveResult[], SObject[]> op,
            boolean isInsert) throws ApiFault, ConnectionException {
        SaveResult[] sr = runOperation(op, getSobjects(dynaBeans, op.getName()));
        String saveMessage = isInsert ? "Client.itemCreated" : "Client.itemUpdated";
        for (int j = 0; j < sr.length; j++) {
            processResult(sr[j].isSuccess(), saveMessage, sr[j].getId(), sr[j].getErrors(), j);
        }
        return sr;
    }

    private SObject[] getSobjects(List<DynaBean> dynaBeans, String opName) {
        try {
            SObject[] sobjects = SforceDynaBean.getSObjectArray(controller, dynaBeans, config.getString(Config.ENTITY),
                    config.getBoolean(Config.INSERT_NULLS));
            logger.debug(Messages.getString("Client.arraySize") + sobjects.length); //$NON-NLS-1$
            return sobjects;
        } catch (IllegalAccessException ex) {
            logger.error(
                    Messages.getFormattedString("Client.operationError", new String[] { opName, ex.getMessage() }), ex); //$NON-NLS-1$
            throw new RuntimeException(ex);
        } catch (InvocationTargetException ex) {
            logger.error(
                    Messages.getFormattedString("Client.operationError", new String[] { opName, ex.getMessage() }), ex); //$NON-NLS-1$
            throw new RuntimeException(ex);
        } catch (NoSuchMethodException ex) {
            logger.error(
                    Messages.getFormattedString("Client.operationError", new String[] { opName, ex.getMessage() }), ex); //$NON-NLS-1$
            throw new RuntimeException(ex);
        } catch (ParameterLoadException ex) {
            logger.error(
                    Messages.getFormattedString("Client.operationError", new String[] { opName, ex.getMessage() }), ex); //$NON-NLS-1$
            throw new RuntimeException(ex);
        }
    }

    protected <R, A> R runOperation(ClientOperation<R, A> op, A arg) throws ConnectionException {
        logger.debug(Messages.getFormattedString("Client.beginOperation", op.getName())); //$NON-NLS-1$
        if (op != this.LOGIN_OPERATION && !isSessionValid()) {
            connect();
        }
        int totalAttempts = 1 + (this.enableRetries ? this.maxRetries : 0);
        ConnectionException connectionException = null;
        for (int tryNum = 0; tryNum < totalAttempts; tryNum++) {
            try {
                R result = op.run(arg);
                if (result == null) logger.info(Messages.getString("Client.resultNull")); //$NON-NLS-1$
                return result;
            } catch (ConnectionException ex) {
                logger.error(
                        Messages.getFormattedString(
                                "Client.operationError", new String[] { op.getName(), ex.getMessage() }), ex); //$NON-NLS-1$
                // check retries
                if (!checkConnectionException(ex, op.getName(), tryNum)) throw ex;
                connectionException = ex;
            }
        }
        throw connectionException;
    }

    /**
     * @param dynaBeans
     * @return DeleteResult array
     * @throws ConnectionException
     */
    public DeleteResult[] loadDeletes(List<DynaBean> dynaBeans) throws ConnectionException {


        DynaBean dynaBean;
        String[] dels = new String[dynaBeans.size()];
        for (int i = 0; i < dynaBeans.size(); i++) {
            dynaBean = dynaBeans.get(i);
            String id = (String)dynaBean.get("Id"); //$NON-NLS-1$
            if (id == null) {
                id = "";
            }
            dels[i] = id;
        }
        logger.debug(Messages.getString("Client.arraySize") + dels.length); //$NON-NLS-1$



        DeleteResult[] result = runOperation(DELETE_OPERATION, dels);

        for (int j = 0; j < result.length; j++) {
            processResult(result[j].isSuccess(), "Client.itemDeleted", result[j].getId(), result[j].getErrors(), j);
        }
        return result;
    }

    /**
     * Query next batch of records using the query cursor
     *
     * @param soql
     * @return query results
     * @throws ConnectionException
     */
    public QueryResult queryMore(String soql) throws ConnectionException {
        return runOperation(QUERY_MORE_OPERATION, soql);
    }

    /**
     * Query objects excluding the deleted objects
     *
     * @param soql
     * @return query results
     * @throws ConnectionException
     */
    public QueryResult query(String soql) throws ConnectionException {
        return runOperation(QUERY_OPERATION, soql);
    }

    /**
     * Query objects including the deleted objects
     *
     * @param soql
     * @return query results
     */
    public QueryResult queryAll(String soql) throws ConnectionException {
        return runOperation(QUERY_ALL_OPERATION, soql);
    }

    /**
     * Process result of a change operation that returns data success / errors (examples of operations with such
     * results: insert, update, upsert, delete, merge)
     *
     * @param success
     *            True if result is success
     * @param successMsgKey
     * @param id
     *            Item id(if available)
     * @param errors
     *            Error array(if available)
     * @param itemNbr
     *            Item number in the result
     */
    private void processResult(boolean success, String successMsgKey, String id, Error[] errors, int itemNbr) {
        if (success) {
            logger.debug(Messages.getString(successMsgKey) + id);
        } else {
            // there were errors during the delete call, go through the errors
            // array and write them to the screen
            for (Error err : errors) {
                int startRow;
                try {
                    startRow = config.getInt(Config.LOAD_ROW_TO_START_AT);
                } catch (ParameterLoadException e) {
                    startRow = 0;
                }
                logger.error(Messages.getString("Client.itemError") //$NON-NLS-1$
                        + new Integer((itemNbr + startRow)).toString());
                logger.error(Messages.getString("Client.errorCode") + err.getStatusCode().toString()); //$NON-NLS-1$
                logger.error(Messages.getString("Client.errorMessage") + err.getMessage()); //$NON-NLS-1$
            }
        }
    }

    @Override
    public PartnerConnection getClient() {
        return this.client;
    }

    public Map<String, DescribeGlobalSObjectResult> getDescribeGlobalResults() {
        return describeGlobalResults;
    }

    Map<String, DescribeSObjectResult> getEntityDescribeMap() {
        return this.entityDescribes;
    }

    DescribeGlobalResult getEntityTypes() {
        return entityTypes;
    }

    public DescribeSObjectResult getFieldTypes() {
        String entity = this.config.getString(Config.ENTITY);
        try {
            return describeSObject(entity);
        } catch (ConnectionException e) {
            throw new RuntimeException("Unexpected failure describing main entity " + entity, e);
        }
    }

    public Map<String, DescribeRefObject> getReferenceDescribes() {
        return referenceDescribes;
    }

    boolean isSessionValid() {
        if (config.getBoolean(Config.SFDC_INTERNAL) && config.getBoolean(Config.SFDC_INTERNAL_IS_SESSION_ID_LOGIN)) { return true; }
        return isLoggedIn();
    }

    private boolean login() throws ConnectionException, ApiFault {
        disconnect();
        // Attempt the login giving the user feedback
        logger.info(Messages.getString("Client.sforceLogin")); //$NON-NLS-1$
        final ConnectorConfig cc = getLoginConnectorConfig();
        final PartnerConnection conn = Connector.newConnection(cc);
        // identify the client as dataloader
        conn.setCallOptions(ClientBase.getClientName(this.config), null);

        if (config.getBoolean(Config.SFDC_INTERNAL) && config.getBoolean(Config.SFDC_INTERNAL_IS_SESSION_ID_LOGIN)) {
            setConfiguredSessionId(conn);
        } else {
            setSessionRenewer(conn);
            loginInternal(conn);
        }
        return true;

    }

    private void setSessionRenewer(final PartnerConnection conn) {
        conn.getConfig().setSessionRenewer(new SessionRenewer() {
            @Override
            public SessionRenewalHeader renewSession(ConnectorConfig connectorConfig) throws ConnectionException {
                loginInternal(conn);
                return null;
            }
        });
    }

    private void setConfiguredSessionId(final PartnerConnection conn) throws ConnectionException {
        logger.info("Using manually configured session id to bypass login");
        conn.setSessionHeader(config.getString(Config.SFDC_INTERNAL_SESSION_ID));
        try {
            conn.getUserInfo(); // check to make sure we have a good connection
        } catch (ConnectionException e) {
            logger.error("Failed to get user info using manually configured session id", e);
            throw e;
        }
        loginSuccess(conn, getServerUrl(config.getString(Config.ENDPOINT)));
    }

    private void loginInternal(final PartnerConnection conn) throws ConnectionException, PasswordExpiredException {
        final ConnectorConfig cc = conn.getConfig();
        try {
            logger.info(Messages.getMessage(getClass(), "sforceLoginDetail", cc.getAuthEndpoint(), cc.getUsername()));
            LoginResult loginResult = runOperation(LOGIN_OPERATION, conn);
            // if password has expired, throw an exception
            if (loginResult.getPasswordExpired()) { throw new PasswordExpiredException(Messages
                    .getString("Client.errorExpiredPassword")); //$NON-NLS-1$
            }
            // update session id and service endpoint based on response
            conn.setSessionHeader(loginResult.getSessionId());
            String serverUrl = loginResult.getServerUrl();
            String server = getServerUrl(serverUrl);
            if (config.getBoolean(Config.RESET_URL_ON_LOGIN)) {
                cc.setServiceEndpoint(serverUrl);
            }
            loginSuccess(conn, server);
        } catch (ConnectionException ex) {
            logger.error(Messages.getMessage(getClass(), "loginError", cc.getAuthEndpoint(), ex.getMessage()), ex);
            throw ex;
        }
    }

    private void loginSuccess(PartnerConnection conn, String serv) {
        this.client = conn;
        setSession(conn.getSessionHeader().getSessionId(), serv);
    }

    private String getServerStringFromUrl(URL url) {
        return url.getProtocol() + "://" + url.getAuthority();
    }

    private String getServerUrl(String serverUrl) {
        if (config.getBoolean(Config.RESET_URL_ON_LOGIN)) {
            try {
                return getServerStringFromUrl(new URL(serverUrl));
            } catch (MalformedURLException e) {
                logger.fatal("Unexpected error", e);
                throw new RuntimeException(e);
            }
        }
        return getDefaultServer();
    }

    public boolean logout() {
        try {
            PartnerConnection pc = getClient();
            if (pc != null) pc.logout();
        } catch (ConnectionException e) {
            // ignore
        } finally {
            disconnect();
        }
        return true;
    }

    public void disconnect() {
        clearSession();
        this.client = null;
    }

    /**
     * @param operationName
     */
    private void retrySleep(String operationName, int retryNum) {
        int sleepSecs;
        try {
            sleepSecs = config.getInt(Config.MIN_RETRY_SLEEP_SECS);
        } catch (ParameterLoadException e1) {
            sleepSecs = Config.DEFAULT_MIN_RETRY_SECS;
        }
        // sleep between retries is based on the retry attempt #. Sleep for longer periods with each retry
        sleepSecs = sleepSecs + (retryNum * 10); // sleep for MIN_RETRY_SLEEP_SECS + 10, 20, 30, etc.

        logger.info(Messages.getFormattedString("Client.retryOperation", new String[] { Integer.toString(retryNum + 1),
                operationName, Integer.toString(sleepSecs) }));
        try {
            Thread.sleep(sleepSecs * 1000);
        } catch (InterruptedException e) { // ignore
        }
    }

    /**
     * Gets the sObject describes for all entities
     */
    public boolean setEntityDescribes() throws ConnectionException {
        setEntityTypes();
        if (this.describeGlobalResults.isEmpty()) {
            for (DescribeGlobalSObjectResult res : entityTypes.getSobjects()) {
                if (res != null) this.describeGlobalResults.put(res.getName(), res);
            }
        }

        return true;
    }

    /**
     * Gets the available objects from the global describe
     */
    private void setEntityTypes() throws ConnectionException {
        if (this.entityTypes == null)
            this.entityTypes = runOperation(DESCRIBE_GLOBAL_OPERATION, null);
    }

    /**
     * Set the map of references to object external id info for current entity
     *
     * @throws ConnectionException
     */
    public void setFieldReferenceDescribes() throws ConnectionException {
        referenceDescribes.clear();
        if (getDescribeGlobalResults().isEmpty()) {
            setEntityDescribes();
        }
        if (getFieldTypes() == null) {
            setFieldTypes();
        }
        if (getDescribeGlobalResults() != null) {
            Field[] entityFields = getFieldTypes().getFields();
            for (Field entityField : entityFields) {
                // upsert on references (aka foreign keys) is supported only
                // 1. When field has relationship is set and refers to exactly one object
                // 2. When field is either createable or updateable. If neither is true, upsert will never work for that
                // relationship.
                if (entityField.isCreateable() || entityField.isUpdateable()) {
                    String relationshipName = entityField.getRelationshipName();
                    String[] referenceTos = entityField.getReferenceTo();
                    if (referenceTos != null && referenceTos.length == 1 && referenceTos[0] != null
                            && relationshipName != null && relationshipName.length() > 0
                            && (entityField.isCreateable() || entityField.isUpdateable())) {

                        String refEntityName = referenceTos[0];

                        // make sure that the object is legal to upsert
                        Field[] refObjectFields = describeSObject(refEntityName).getFields();
                        Map<String, Field> refFieldInfo = new HashMap<String, Field>();
                        for (Field refField : refObjectFields) {
                            if (refField.isExternalId()) {
                                refField.setCreateable(entityField.isCreateable());
                                refField.setUpdateable(entityField.isUpdateable());
                                refFieldInfo.put(refField.getName(), refField);
                            }
                        }
                        if (!refFieldInfo.isEmpty()) {
                            DescribeRefObject describe = new DescribeRefObject(refEntityName, refFieldInfo);
                            referenceDescribes.put(relationshipName, describe);
                        }
                    }
                }
            }
        }
    }

    /**
     * Gets the sobject describe for the given entity
     *
     * @throws ConnectionException
     */
    public void setFieldTypes() throws ConnectionException {
        describeSObject(config.getString(Config.ENTITY));
    }

    /**
     * @return true if loggedIn
     */
    public boolean isLoggedIn() {
        return getSession().isSessionValid();
    }

    public void validateSession() {
        getSession().validate();
    }

    @Override
    protected ConnectorConfig getConnectorConfig() {
        ConnectorConfig cc = super.getConnectorConfig();
        cc.setManualLogin(true);
        return cc;
    }

    private ConnectorConfig getLoginConnectorConfig() {
        ConnectorConfig cc = getConnectorConfig();
        String serverUrl = getDefaultServer();
        cc.setAuthEndpoint(serverUrl + DEFAULT_AUTH_ENDPOINT_URL.getPath());
        cc.setServiceEndpoint(serverUrl + DEFAULT_AUTH_ENDPOINT_URL.getPath());
        return cc;
    }

    private String getDefaultServer() {
        String serverUrl = config.getString(Config.ENDPOINT);
        if (serverUrl == null || serverUrl.length() == 0) {
            serverUrl = getServerStringFromUrl(DEFAULT_AUTH_ENDPOINT_URL);
        }
        return serverUrl;
    }

    /**
     * This function returns the describe call for an sforce entity
     *
     * @return DescribeSObjectResult
     * @throws ConnectionException
     */

    public DescribeSObjectResult describeSObject(String entity) throws ConnectionException {
        DescribeSObjectResult result = getEntityDescribeMap().get(entity);
        if (result == null) {
            result = runOperation(DESCRIBE_SOBJECT_OPERATION, entity);
            if (result != null) {
                getEntityDescribeMap().put(result.getName(), result);
            }
        }
        return result;
    }

    /**
     * Checks whether retry makes sense for the given exception and given the number of current vs. max retries. If
     * retry makes sense, then before returning, this method will put current thread to sleep before allowing another
     * retry.
     *
     * @param ex
     * @param operationName
     * @return true if retry should be executed for operation. false if there's no retry.
     */
    private boolean checkConnectionException(ConnectionException ex, String operationName, int retryNum) {
        if (!this.enableRetries) return false;
        final String msg = ex.getMessage();
        if (msg != null && msg.toLowerCase().indexOf("connection reset") >= 0) {
            retrySleep(operationName, retryNum);
        }
        return false;
    }

    private final Map<String, Field> fieldsByName = new HashMap<String, Field>();

    public Field getField(String apiName) {
        apiName = apiName.toLowerCase();
        Field field = this.fieldsByName.get(apiName);
        if (field == null) {
            field = lookupField(apiName);
            this.fieldsByName.put(apiName, field);
        }
        return field;
    }

    private Field lookupField(String apiName) {
        // look for field on target object
        for (Field f : getFieldTypes().getFields()) {
            if (apiName.equals(f.getName().toLowerCase()) || apiName.equals(f.getLabel().toLowerCase())) return f;
        }
        // look for reference field on target object
        if (apiName.contains(":")) {
            Map<String, DescribeRefObject> refs = getReferenceDescribes();
            for (Map.Entry<String, DescribeRefObject> ent : refs.entrySet()) {
                String relName = ent.getKey().toLowerCase();
                if (apiName.startsWith(relName)) {
                    for (Map.Entry<String, Field> refEntry : ent.getValue().getFieldInfoMap().entrySet()) {
                        String thisRefName = relName + ":" + refEntry.getKey().toLowerCase();
                        if (apiName.equals(thisRefName)) return refEntry.getValue();
                    }
                }
            }
        }
        return null;
    }

}
TOP

Related Classes of com.salesforce.dataloader.client.PartnerClient

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.