/*
* Copyright © 2013. Palomino Labs (http://palominolabs.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.palominolabs.crm.sf.soap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.concurrent.Immutable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Convenience methods related to Connections and the calls they support.
*/
@Immutable
final class ConnectionUtils {
private static final Logger logger = LoggerFactory.getLogger(ConnectionUtils.class);
/**
* Not instantiable
*/
private ConnectionUtils() {
// no op
}
/**
* Splits fieldNames into chunks, the union of which comprise the whole list joined together with ",". This is
* useful to avoid exceeding the 10,000 character limit for API calls to Salesforce. The individual field names may
* be reordered.
*
* Note that if an individual field name is bigger than the maxSize, then the chunk containing that name will
* necessarily be bigger than the maxSize. In other words, this is a best-effor approach since field names are not
* necessarily constrained.
*
* An alternate approach would be to throw an exception when a field name longer than maxSize is found, but this was
* not done because there is a chance that the oversized field may still be accepted by Salesforce. There is not a
* clear way of knowing how much of the 10,000 character limit will be used by the rest of the request, so we cannot
* say for sure what size field name will or will not be allowed.
*
* @param fieldNames list of field names
* @param maxSize the max size to allow each joined field name chunk to be
*
* @return list of chunks of field names
*/
static List<List<String>> splitFieldList(List<String> fieldNames, int maxSize) {
List<List<String>> chunks = new ArrayList<List<String>>();
String separator = ",";
List<String> chunk = new ArrayList<String>();
for (String fName : fieldNames) {
if (fName.length() > maxSize) {
// special case just so that we can log it
logger.warn("Field name <{}> by itself was bigger than the chunk size; adding it as its own chunk",
fName);
chunks.add(Arrays.asList(fName));
continue;
}
// fName is not super big
if (chunk.isEmpty()) {
chunk.add(fName);
continue;
}
// chunk is not empty
// if chunk + new name + comma is short enough, add it and move on
if (getChunkLength(chunk) + fName.length() + separator.length() <= maxSize) {
chunk.add(fName);
continue;
}
// fName didn't fit in the chunk
// chunk is non-empty, so add the chunk to the chunk list and reset
chunks.add(chunk);
chunk = new ArrayList<String>();
chunk.add(fName);
}
// might have been a leftover chunk if the last chunk did not perfecly match with when the
// buf filled up. This will often be the case. This will also be the case if the buf never
// filled up.
if (!chunk.isEmpty()) {
chunks.add(chunk);
}
return chunks;
}
/**
* @param chunk the chunk of fields
*
* @return how long the chunk would be if it was joined into a comma-separated string
*/
private static int getChunkLength(List<String> chunk) {
if (chunk.isEmpty()) {
return 0;
}
int fieldNameSum = 0;
for (String s : chunk) {
fieldNameSum += s.length();
}
int numCommas = chunk.size() - 1;
return fieldNameSum + numCommas;
}
}