diff --git a/pom.xml b/pom.xml
index 1c85f02..94aea04 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,198 +1,202 @@
- 4.0.0
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ 4.0.0
- com.springml
- salesforce-wave-api
- 1.0.7
- jar
+ com.springml
+ salesforce-wave-api
+ 1.0.9
+ jar
- salesforce-wave-api
- Java client for Salesforce Wave API
-
-
- samuel-pt
- Samuel Alexander
-
-
+ salesforce-wave-api
+ Java client for Salesforce Wave API
+
+
+ samuel-pt
+ Samuel Alexander
+
+
+ kagan-turgut
+ Kagan Turgut
+
+
- https://github.com/springml/salesforce-wave-api
-
-
- Apache License, Version 2.0
- http://www.apache.org/licenses/LICENSE-2.0.txt
- repo
-
-
+ https://github.com/springml/salesforce-wave-api
+
+
+ Apache License, Version 2.0
+ http://www.apache.org/licenses/LICENSE-2.0.txt
+ repo
+
+
-
- scm:git:github.com/springml/salesforce-wave-api
- scm:git:git@github.com:springml/salesforce-wave-api
- github.com/springml/salesforce-wave-api
-
+
+ scm:git:github.com/springml/salesforce-wave-api
+ scm:git:git@github.com:springml/salesforce-wave-api
+ github.com/springml/salesforce-wave-api
+
-
-
- ossrh
- https://oss.sonatype.org/content/repositories/snapshots
-
-
- ossrh
- https://oss.sonatype.org/service/local/staging/deploy/maven2/
-
-
+
+
+ ossrh
+ https://oss.sonatype.org/content/repositories/snapshots
+
+
+ ossrh
+ https://oss.sonatype.org/service/local/staging/deploy/maven2/
+
+
-
- UTF-8
- 1.8
-
+
+ UTF-8
+ 1.8
+ true
+
-
-
- com.force.api
- force-partner-api
- 34.0.0
-
-
- com.force.api
- force-wsc
- 34.2.2
-
-
- org.apache.httpcomponents
- httpclient
- 4.5
-
-
- com.fasterxml.jackson.core
- jackson-core
- 2.4.4
-
-
- com.fasterxml.jackson.core
- jackson-databind
- 2.4.4
-
-
- commons-io
- commons-io
- 2.5
-
-
- log4j
- log4j
- 1.2.17
-
-
- com.fasterxml.jackson.dataformat
- jackson-dataformat-xml
- 2.4.4
-
-
- org.codehaus.woodstox
- woodstox-core-asl
- 4.4.0
-
-
- org.apache.commons
- commons-lang3
- 3.4
-
+
+
+ com.force.api
+ force-partner-api
+ 39.0.0
+
+
+ com.force.api
+ force-wsc
+ 39.0.1
+
+
+ org.apache.httpcomponents
+ httpclient
+ 4.5.3
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+ 2.8.7
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.8.7
+
+
+ com.fasterxml.jackson.dataformat
+ jackson-dataformat-xml
+ 2.8.7
+
+
+ com.fasterxml.jackson.dataformat
+ jackson-dataformat-csv
+ 2.8.7
+
+
+
+ commons-io
+ commons-io
+ 2.5
+
+
+ log4j
+ log4j
+ 1.2.17
+
+
+
+ org.apache.commons
+ commons-lang3
+ 3.5
+
+
+ junit
+ junit
+ 4.12
+ test
+
+
+ org.mockito
+ mockito-core
+ 2.7.10
+
-
- junit
- junit
- 4.12
- test
-
-
- org.mockito
- mockito-core
- 2.0.31-beta
- test
-
-
- org.mockito
- mockito-core
- 2.0.31-beta
- test
-
+
-
+
+
+
+
+ org.apache.maven.plugins
+ maven-release-plugin
+ 2.5
+
+ false
+ release
+ deploy
+
+
+
+
-
-
-
-
- org.apache.maven.plugins
- maven-release-plugin
- 2.5
-
- false
- release
- deploy
-
-
-
-
+
+
+ org.sonatype.plugins
+ nexus-staging-maven-plugin
+ 1.6.3
+ true
+
+ ossrh
+ https://oss.sonatype.org/
+ true
+
+
-
-
- org.sonatype.plugins
- nexus-staging-maven-plugin
- 1.6.3
- true
-
- ossrh
- https://oss.sonatype.org/
- true
-
-
-
-
- org.apache.maven.plugins
- maven-source-plugin
- 2.2.1
-
-
- attach-sources
-
- jar-no-fork
-
-
-
-
-
- org.apache.maven.plugins
- maven-javadoc-plugin
- 2.9.1
-
-
- attach-javadocs
-
- jar
-
-
- -Xdoclint:none
-
-
-
-
-
- org.apache.maven.plugins
- maven-gpg-plugin
- 1.5
-
-
- sign-artifacts
- verify
-
- sign
-
-
-
-
-
-
+
+ org.apache.maven.plugins
+ maven-source-plugin
+ 2.2.1
+
+
+ attach-sources
+
+ jar-no-fork
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+ 2.9.1
+
+
+ attach-javadocs
+
+ jar
+
+
+ -Xdoclint:none
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-gpg-plugin
+ 1.5
+
+ true
+
+
+
+ sign-artifacts
+ verify
+
+ sign
+
+
+
+
+
+
diff --git a/src/main/java/com/springml/salesforce/wave/api/APIFactory.java b/src/main/java/com/springml/salesforce/wave/api/APIFactory.java
index 60d8263..23b0db5 100644
--- a/src/main/java/com/springml/salesforce/wave/api/APIFactory.java
+++ b/src/main/java/com/springml/salesforce/wave/api/APIFactory.java
@@ -1,3 +1,21 @@
+/*
+ * Copyright 2015 - 2017, salesforce-wave-api, springml, oolong
+ * Contributors :
+ * Samual Alexander, springml
+ * Kagan Turgut
+ *
+ * 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.springml.salesforce.wave.api;
import com.springml.salesforce.wave.impl.BulkAPIImpl;
diff --git a/src/main/java/com/springml/salesforce/wave/api/BulkAPI.java b/src/main/java/com/springml/salesforce/wave/api/BulkAPI.java
index f2141be..613b22e 100644
--- a/src/main/java/com/springml/salesforce/wave/api/BulkAPI.java
+++ b/src/main/java/com/springml/salesforce/wave/api/BulkAPI.java
@@ -1,8 +1,31 @@
+/*
+ * Copyright 2015 - 2017, salesforce-wave-api, oolong, springml
+ * Contributors :
+ * Kagan Turgut, oolong
+ * Samual Alexander, springml
+ *
+ * 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.springml.salesforce.wave.api;
+import java.io.InputStream;
+import java.util.List;
+
import com.springml.salesforce.wave.model.BatchInfo;
import com.springml.salesforce.wave.model.BatchInfoList;
+import com.springml.salesforce.wave.model.BatchResult;
import com.springml.salesforce.wave.model.JobInfo;
+import com.springml.salesforce.wave.model.SOQLResult;
/**
* Java client for Salesforce Bulk API
@@ -15,8 +38,58 @@ public interface BulkAPI {
* @param The Salesforce object to be updated
* @return @JobInfo
* @throws Exception
+ * @deprecated Use createUpdateJob or createQueryJob instead
*/
public JobInfo createJob(String object) throws Exception;
+
+ /**
+ * Create Update Job
+ * @param object
+ * @return
+ * @throws Exception
+ */
+ public JobInfo createUpdateJob(String object) throws Exception;
+
+ /**
+ *
+ * @param object
+ * @return
+ * @throws Exception
+ */
+ public JobInfo createQueryJob(String object) throws Exception;
+
+ /**
+ * Create bulk query job with PK chunking
+ * @param object
+ * @param pkChunking
+ * @return
+ * @throws Exception
+ */
+ public JobInfo createQueryJob(String object, Boolean pkChunking) throws Exception;
+
+
+ /**
+ * Create bulk query job with PK chunking. if QueryAll is set, it will bring deleted Salesforce records as well.
+ * @param object : name of the object in salesforce
+ * @param pkChunking : whether the result will be returned in batches
+ * @param queryAll : whether to bring deleted records from salesforce. subject to Salesforce garbage bin limitations
+ * @return
+ * @throws Exception
+ */
+ public JobInfo createQueryJob(String object, Boolean pkChunking, Boolean queryAll) throws Exception;
+
+ /**
+ * Create bulk query job with PK chunking. if QueryAll is set, it will bring deleted Salesforce records as well.
+ * Use this method if you want to specify additional pkChunking parameters such as chunkSize.
+ * @param object
+ * @param pkChunkingKey
+ * @param pkChunkingValue : you can optionally pass chunksize, but better to go with the default.
+ * @param queryAll : if true, it will bring deleted records as well.
+ * @return
+ * @throws Exception
+ */
+ public JobInfo createQueryJob(String object, String pkChunkingKey, String pkChunkingValue, Boolean queryAll) throws Exception;
+
/**
* Create a new Bulk Job
@@ -35,6 +108,7 @@ public interface BulkAPI {
* @throws Exception
*/
public JobInfo createJob(JobInfo jobInfo) throws Exception;
+
/**
* Add a batch to an existing Job
@@ -45,6 +119,15 @@ public interface BulkAPI {
* @throws Exception
*/
public BatchInfo addBatch(String jobId, String csvContent) throws Exception;
+
+ /**
+ * Close the job
+ * @param jobId
+ * @param checkBatchesFirst
+ * @return
+ * @throws Exception
+ */
+ public JobInfo closeJob(String jobId, Boolean checkBatchesFirst) throws Exception;
/**
* Close the specified Salesforce Bulk Job
@@ -88,4 +171,34 @@ public interface BulkAPI {
* @throws Exception
*/
public BatchInfo getBatchInfo(String jobId, String batchId) throws Exception;
+
+ /**
+ * Get list of active jobs
+ * @return
+ */
+ public List getActiveJobIds();
+
+ /**
+ * Get list of recently completed jobs
+ * @return
+ */
+ public List getCompletedJobIds();
+
+ /**
+ * Return batchResults for this batch. This is in CSV format, and by default includes the header rows
+ * @param batch
+ * @return
+ * @throws Exception
+ */
+ public BatchResult queryBatch(BatchInfo batch) throws Exception;
+
+ /**
+ * Return batchresults as a stream. CSV format, includes the header rows by default.
+ * @param batch
+ * @return
+ * @throws Exception
+ */
+ public InputStream queryBatchStream(BatchInfo batch) throws Exception;
+
+
}
diff --git a/src/main/java/com/springml/salesforce/wave/api/ForceAPI.java b/src/main/java/com/springml/salesforce/wave/api/ForceAPI.java
index 1b90a3b..95db20c 100644
--- a/src/main/java/com/springml/salesforce/wave/api/ForceAPI.java
+++ b/src/main/java/com/springml/salesforce/wave/api/ForceAPI.java
@@ -1,3 +1,21 @@
+/*
+ * Copyright 2015 - 2017, salesforce-wave-api, springml, oolong
+ * Contributors :
+ * Samual Alexander, springml
+ * Kagan Turgut
+ *
+ * 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.springml.salesforce.wave.api;
import com.springml.salesforce.wave.model.AddTaskRequest;
diff --git a/src/main/java/com/springml/salesforce/wave/api/WaveAPI.java b/src/main/java/com/springml/salesforce/wave/api/WaveAPI.java
index d6d77d9..035d8df 100644
--- a/src/main/java/com/springml/salesforce/wave/api/WaveAPI.java
+++ b/src/main/java/com/springml/salesforce/wave/api/WaveAPI.java
@@ -1,3 +1,21 @@
+/*
+ * Copyright 2015 - 2017, salesforce-wave-api, springml, oolong
+ * Contributors :
+ * Samual Alexander, springml
+ * Kagan Turgut
+ *
+ * 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.springml.salesforce.wave.api;
import com.springml.salesforce.wave.model.QueryResult;
diff --git a/src/main/java/com/springml/salesforce/wave/impl/AbstractAPIImpl.java b/src/main/java/com/springml/salesforce/wave/impl/AbstractAPIImpl.java
index dd20daf..12c42ac 100644
--- a/src/main/java/com/springml/salesforce/wave/impl/AbstractAPIImpl.java
+++ b/src/main/java/com/springml/salesforce/wave/impl/AbstractAPIImpl.java
@@ -1,8 +1,30 @@
+/*
+ * Copyright 2015 - 2017, salesforce-wave-api, springml
+ * Contributors :
+ * Samual Alexander, springml
+ * Kagan Turgut
+ *
+ * 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.springml.salesforce.wave.impl;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.ObjectReader;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
+import com.fasterxml.jackson.dataformat.csv.CsvMapper;
+import com.fasterxml.jackson.dataformat.csv.CsvSchema;
+import com.fasterxml.jackson.dataformat.csv.CsvParser;
import com.springml.salesforce.wave.util.HTTPHelper;
import com.springml.salesforce.wave.util.SFConfig;
@@ -12,8 +34,10 @@
public abstract class AbstractAPIImpl {
private ObjectMapper objectMapper;
private XmlMapper xmlMapper;
+ private CsvMapper csvMapper;
private HTTPHelper httpHelper;
private SFConfig sfConfig;
+ private ObjectReader objectReader;
public AbstractAPIImpl(SFConfig sfConfig) throws Exception {
setHttpHelper(new HTTPHelper());
@@ -24,6 +48,12 @@ public AbstractAPIImpl(SFConfig sfConfig) throws Exception {
setObjectMapper(objectMapper);
this.xmlMapper = new XmlMapper();
+
+ this.csvMapper = new CsvMapper();
+ CsvSchema schema = CsvSchema.builder().setColumnSeparator(',').build();
+ csvMapper.enable(CsvParser.Feature.WRAP_AS_ARRAY);
+ objectReader = csvMapper.readerFor(String[].class).with(schema);
+
this.sfConfig = sfConfig;
}
@@ -58,5 +88,21 @@ public XmlMapper getXmlMapper() {
public void setXmlMapper(XmlMapper xmlMapper) {
this.xmlMapper = xmlMapper;
}
+
+ public CsvMapper getCsvMapper() {
+ return csvMapper;
+ }
+
+ public ObjectReader getObjectReader() {
+ return objectReader;
+ }
+
+ public void setObjectReader(ObjectReader reader) {
+ this.objectReader=reader;
+ }
+
+ public void setCsvMapper(CsvMapper csvMapper) {
+ this.csvMapper = csvMapper;
+ }
}
diff --git a/src/main/java/com/springml/salesforce/wave/impl/BulkAPIImpl.java b/src/main/java/com/springml/salesforce/wave/impl/BulkAPIImpl.java
index 2e842e5..ef474fd 100644
--- a/src/main/java/com/springml/salesforce/wave/impl/BulkAPIImpl.java
+++ b/src/main/java/com/springml/salesforce/wave/impl/BulkAPIImpl.java
@@ -1,10 +1,54 @@
+/*
+ * Copyright 2015 - 2017, salesforce-wave-api, springml, oolong
+ * Authors :
+ * Kagan Turgut, oolong
+ * Samual Alexander, springml
+ *
+ * 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.springml.salesforce.wave.impl;
-import static com.springml.salesforce.wave.util.WaveAPIConstants.*;
-
+import static com.springml.salesforce.wave.util.WaveAPIConstants.CONTENT_TYPE_APPLICATION_JSON;
+import static com.springml.salesforce.wave.util.WaveAPIConstants.CONTENT_TYPE_APPLICATION_XML;
+import static com.springml.salesforce.wave.util.WaveAPIConstants.CONTENT_TYPE_TEXT_CSV;
+import static com.springml.salesforce.wave.util.WaveAPIConstants.PATH_BATCH;
+import static com.springml.salesforce.wave.util.WaveAPIConstants.PATH_JOB;
+import static com.springml.salesforce.wave.util.WaveAPIConstants.PATH_RESULT;
+import static com.springml.salesforce.wave.util.WaveAPIConstants.SERVICE_ASYNC_PATH;
+import static com.springml.salesforce.wave.util.WaveAPIConstants.STR_CLOSED;
+import static com.springml.salesforce.wave.util.WaveAPIConstants.STR_COMPLETED;
+import static com.springml.salesforce.wave.util.WaveAPIConstants.STR_CSV;
+import static com.springml.salesforce.wave.util.WaveAPIConstants.STR_FAILED;
+import static com.springml.salesforce.wave.util.WaveAPIConstants.STR_JSON;
+import static com.springml.salesforce.wave.util.WaveAPIConstants.STR_PARALLEL;
+import static com.springml.salesforce.wave.util.WaveAPIConstants.STR_QUERY;
+import static com.springml.salesforce.wave.util.WaveAPIConstants.STR_QUERY_ALL;
+import static com.springml.salesforce.wave.util.WaveAPIConstants.STR_UPDATE;
+import static com.springml.salesforce.wave.util.WaveAPIConstants.STR_XML;
+
+
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
@@ -13,194 +57,356 @@
import com.springml.salesforce.wave.api.BulkAPI;
import com.springml.salesforce.wave.model.BatchInfo;
import com.springml.salesforce.wave.model.BatchInfoList;
+import com.springml.salesforce.wave.model.BatchResult;
import com.springml.salesforce.wave.model.JobInfo;
import com.springml.salesforce.wave.util.LRUCache;
import com.springml.salesforce.wave.util.SFConfig;
public class BulkAPIImpl extends AbstractAPIImpl implements BulkAPI {
- private static final Logger LOG = Logger.getLogger(BulkAPIImpl.class);
- private Map jobContentTypeMap = new LRUCache(100);
-
- public BulkAPIImpl(SFConfig sfConfig) throws Exception {
- super(sfConfig);
- }
-
- public JobInfo createJob(String object) throws Exception {
- JobInfo jobInfo = new JobInfo(STR_CSV, object, STR_UPDATE);
-
- return createJob(jobInfo);
- }
-
- public JobInfo createJob(String object, String operation, String contentType) throws Exception {
- JobInfo jobInfo = new JobInfo(contentType, object, operation);
-
- return createJob(jobInfo);
- }
-
- public JobInfo createJob(JobInfo jobInfo) throws Exception {
- PartnerConnection connection = getSfConfig().getPartnerConnection();
- URI requestURI = getSfConfig().getRequestURI(connection, getJobPath());
-
- String response = getHttpHelper().post(requestURI, getSfConfig().getSessionId(),
- getObjectMapper().writeValueAsString(jobInfo), true);
- LOG.debug("Response from Salesforce Server " + response);
-
- JobInfo respJobInfo = getObjectMapper().readValue(response.getBytes(), JobInfo.class);
- jobContentTypeMap.put(respJobInfo.getId(), getRespectiveCntType(jobInfo));
-
- return respJobInfo;
- }
-
- public BatchInfo addBatch(String jobId, String csvContent) throws Exception {
- PartnerConnection connection = getSfConfig().getPartnerConnection();
- URI requestURI = getSfConfig().getRequestURI(connection, getBatchPath(jobId));
-
- String contentType = getContentType(jobId);
- String response = getHttpHelper().post(requestURI, getSfConfig().getSessionId(),
- csvContent, contentType, true);
- LOG.debug("Response from Salesforce Server " + response);
-
- // Response is in xml though Accept is set to application/json
- if (CONTENT_TYPE_APPLICATION_JSON.equals(contentType)) {
- return getObjectMapper().readValue(response.getBytes(), BatchInfo.class);
- }
-
- return getXmlMapper().readValue(response.getBytes(), BatchInfo.class);
- }
-
- public JobInfo closeJob(String jobId) throws Exception {
- PartnerConnection connection = getSfConfig().getPartnerConnection();
- URI requestURI = getSfConfig().getRequestURI(connection, getJobPath(jobId));
-
- JobInfo jobInfo = new JobInfo(STR_CLOSED);
- String response = getHttpHelper().post(requestURI, getSfConfig().getSessionId(),
- getObjectMapper().writeValueAsString(jobInfo), true);
- LOG.debug("Response from Salesforce Server " + response);
-
- return getObjectMapper().readValue(response.getBytes(), JobInfo.class);
- }
-
- public boolean isCompleted(String jobId) throws Exception {
- BatchInfoList batchInfoList = getBatchInfoList(jobId);
- List batchInfos = batchInfoList.getBatchInfo();
- boolean isCompleted = false;
- LOG.debug("BatchInfos : " + batchInfos);
- if (batchInfos != null) {
- for (BatchInfo batchInfo : batchInfos) {
- LOG.debug("Batch state : " + batchInfo.getState());
- isCompleted = STR_COMPLETED.equals(batchInfo.getState());
- if (STR_FAILED.equals(batchInfo.getState())) {
- throw new Exception("Batch '" + batchInfo.getId() + "' failed with error '" + batchInfo.getStateMessage() + "'");
- }
-
- LOG.info("Number of records failed : " + batchInfo.getNumberRecordsFailed());
- if (batchInfo.getNumberRecordsFailed() > 0) {
- String result = getResult(jobId, batchInfo.getId());
- LOG.error("Failed record details \n " + result);
- throw new Exception("Batch '" + batchInfo.getId() +
- "' failed. Number of failed records is " + batchInfo.getNumberRecordsFailed());
- }
- }
- }
-
- return isCompleted;
- }
-
- private String getResult(String jobId, String batchId) throws Exception {
- PartnerConnection connection = getSfConfig().getPartnerConnection();
- URI requestURI = getSfConfig().getRequestURI(connection, getBatchResultPath(jobId, batchId));
- return getHttpHelper().get(requestURI, getSfConfig().getSessionId(), true);
- }
-
- public BatchInfoList getBatchInfoList(String jobId) throws Exception {
- PartnerConnection connection = getSfConfig().getPartnerConnection();
- URI requestURI = getSfConfig().getRequestURI(connection, getBatchPath(jobId));
-
- String response = getHttpHelper().get(requestURI, getSfConfig().getSessionId(), true);
- LOG.debug("Response from Salesforce Server " + response);
-
- if (CONTENT_TYPE_APPLICATION_JSON.equals(getContentType(jobId))) {
- return getObjectMapper().readValue(response.getBytes(), BatchInfoList.class);
+
+ private static final Logger LOG = Logger.getLogger(BulkAPIImpl.class);
+
+ private Map jobContentTypeMap = new LRUCache(200);
+ private Map batchedJobMap = new LRUCache(200);
+ private Map finishedJobMap = new LRUCache(100);
+
+ public BulkAPIImpl(SFConfig sfConfig) throws Exception {
+ super(sfConfig);
+ }
+
+ public JobInfo createJob(String object) throws Exception {
+ return createUpdateJob(object);
+ }
+
+ public JobInfo createUpdateJob(String object) throws Exception {
+ JobInfo jobInfo = new JobInfo(STR_CSV, object, STR_UPDATE);
+
+ return createJob(jobInfo);
+ }
+
+ public JobInfo createQueryJob(String object) throws Exception {
+ return createQueryJob(object, false);
+ }
+
+ public JobInfo createQueryJob(String object, Boolean pkChunking) throws Exception {
+ return createQueryJob(object,pkChunking, true);
+ }
+
+ public JobInfo createQueryJob(String object, Boolean pkChunking, Boolean queryAll) throws Exception {
+ return (pkChunking)?
+ createQueryJob(object, "Sforce-Enable-PKChunking", "true", queryAll):
+ createQueryJob(object, null, null, queryAll);
+ }
+
+ public JobInfo createQueryJob(String object, String pkChunkingKey, String pkChunkingValue, Boolean queryAll) throws Exception {
+ // TODO fix JSON handling for non-pk chunking requests
+ String contentType = (pkChunkingKey!=null && !"false".equals(pkChunkingValue))?STR_CSV:STR_CSV;
+ JobInfo jobInfo = new JobInfo(contentType, object, queryAll?STR_QUERY_ALL:STR_QUERY);
+ jobInfo.setConcurrencyMode(STR_PARALLEL);
+ if (pkChunkingKey != null && pkChunkingValue != null)
+ jobInfo.setHeader(pkChunkingKey, pkChunkingValue);
+
+ return createJob(jobInfo);
+ }
+
+ public JobInfo createJob(String object, String operation, String contentType, String concurrencyMode, String header)
+ throws Exception {
+ JobInfo jobInfo = new JobInfo(contentType, object, operation, header);
+
+ return createJob(jobInfo);
+ }
+
+ public JobInfo createJob(String object, String operation, String contentType) throws Exception {
+ return createJob(object, operation, contentType, null, null);
+ }
+
+ public JobInfo createJob(JobInfo jobInfo) throws Exception {
+ PartnerConnection connection = getSfConfig().getPartnerConnection();
+ URI requestURI = getSfConfig().getRequestURI(connection, getJobPath());
+
+ String response = getHttpHelper().post(requestURI, getSfConfig().getSessionId(),
+ getObjectMapper().writeValueAsString(jobInfo), true, jobInfo.getHeader());
+ LOG.debug("Response from Salesforce Server " + response);
+
+ JobInfo respJobInfo = getObjectMapper().readValue(response.getBytes(), JobInfo.class);
+ jobContentTypeMap.put(respJobInfo.getId(), getRespectiveCntType(jobInfo));
+
+ return respJobInfo;
+ }
+
+ public BatchInfo addBatch(String jobId, String csvContent) throws Exception {
+ PartnerConnection connection = getSfConfig().getPartnerConnection();
+ URI requestURI = getSfConfig().getRequestURI(connection, getBatchPath(jobId));
+
+ String contentType = getContentType(jobId);
+ String response = getHttpHelper().post(requestURI, getSfConfig().getSessionId(), csvContent, contentType, true);
+ LOG.debug("Response from Salesforce Server " + response);
+
+ // Response is in xml though Accept is set to application/json
+ if (CONTENT_TYPE_APPLICATION_JSON.equals(contentType)) {
+ return getObjectMapper().readValue(response.getBytes(), BatchInfo.class);
+ }
+
+ BatchInfo result = getXmlMapper().readValue(response.getBytes(), BatchInfo.class);
+ if (result.isQueued()) {
+ batchedJobMap.put(result.getJobId(), result);
+ }
+ return result;
+ }
+
+ public JobInfo closeJob(String jobId, Boolean checkBatchesFirst) throws Exception {
+ if (checkBatchesFirst && !this.isCompleted(jobId)) {
+ LOG.error("Job " + jobId + " has unprocessed batches. Can not be closed");
+ return null;
+ }
+ PartnerConnection connection = getSfConfig().getPartnerConnection();
+ URI requestURI = getSfConfig().getRequestURI(connection, getJobPath(jobId));
+
+ JobInfo jobInfo = new JobInfo(STR_CLOSED);
+ String response = getHttpHelper().post(requestURI, getSfConfig().getSessionId(),
+ getObjectMapper().writeValueAsString(jobInfo), true);
+ LOG.debug("Response from Salesforce Server " + response);
+
+ return getObjectMapper().readValue(response.getBytes(), JobInfo.class);
+ }
+
+ public JobInfo closeJob(String jobId) throws Exception {
+ return closeJob(jobId, false);
+ }
+
+ public boolean isCompleted(String jobId) throws Exception {
+ BatchInfoList batchInfoList = getBatchInfoList(jobId);
+ List batchInfos = batchInfoList.getBatchInfo();
+ boolean isCompleted = true;
+ LOG.debug("BatchInfos : " + batchInfos);
+ if (batchInfos != null) {
+ for (BatchInfo batchInfo : batchInfos) {
+ LOG.debug("Batch state : " + batchInfo.getState());
+ isCompleted = STR_COMPLETED.equals(batchInfo.getState());
+ if (STR_FAILED.equals(batchInfo.getState())) {
+ throw new Exception("Batch '" + batchInfo.getId() + "' failed with error '"
+ + batchInfo.getStateMessage() + "'");
+ }
+
+ LOG.info("Number of records failed : " + batchInfo.getNumberRecordsFailed());
+ if (batchInfo.getNumberRecordsFailed() > 0) {
+ String result = getResult(jobId, batchInfo.getId());
+ LOG.error("Failed record details \n " + result);
+ throw new Exception("Batch '" + batchInfo.getId() + "' failed. Number of failed records is "
+ + batchInfo.getNumberRecordsFailed());
+ }
+ }
+ }
+
+ return isCompleted;
+ }
+
+ private String getResult(String jobId, String batchId) throws Exception {
+ PartnerConnection connection = getSfConfig().getPartnerConnection();
+ URI requestURI = getSfConfig().getRequestURI(connection, getBatchResultPath(jobId, batchId));
+ return getHttpHelper().get(requestURI, getSfConfig().getSessionId(), true);
+ }
+
+ public BatchInfoList getBatchInfoList(String jobId) throws Exception {
+ PartnerConnection connection = getSfConfig().getPartnerConnection();
+ URI requestURI = getSfConfig().getRequestURI(connection, getBatchPath(jobId));
+
+ String response = getHttpHelper().get(requestURI, getSfConfig().getSessionId(), true);
+ // LOG.debug("Response from Salesforce Server " + response);
+
+ if (CONTENT_TYPE_APPLICATION_JSON.equals(getContentType(jobId))) {
+ return getObjectMapper().readValue(response.getBytes(), BatchInfoList.class);
+ }
+
+ return getXmlMapper().readValue(response.getBytes(), BatchInfoList.class);
+ }
+
+ public BatchInfo getBatchInfo(String jobId, String batchId) throws Exception {
+ PartnerConnection connection = getSfConfig().getPartnerConnection();
+ URI requestURI = getSfConfig().getRequestURI(connection, getBatchPath(jobId, batchId));
+
+ String response = getHttpHelper().get(requestURI, getSfConfig().getSessionId(), true);
+ // LOG.debug("Response from Salesforce Server " + response);
+
+ String contentType = getContentType(jobId);
+
+ // Response is in xml though Accept is set to application/json
+ if (CONTENT_TYPE_APPLICATION_JSON.equals(contentType)) {
+ return getObjectMapper().readValue(response.getBytes(), BatchInfo.class);
+ }
+ else
+ return getXmlMapper().readValue(response.getBytes(), BatchInfo.class);
+ }
+
+ public boolean isSuccess(String jobId) throws Exception {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ private String getContentType(String jobId) {
+ String contentType = jobContentTypeMap.get(jobId);
+ if (StringUtils.isEmpty(contentType)) {
+ contentType = CONTENT_TYPE_TEXT_CSV;
+ }
+
+ return contentType;
+ }
+
+ private String getRespectiveCntType(JobInfo jobInfo) {
+ String contentType = null;
+ if (STR_JSON.equals(jobInfo.getContentType())) {
+ contentType = CONTENT_TYPE_APPLICATION_JSON;
+ } else if (STR_XML.equals(jobInfo.getContentType())) {
+ contentType = CONTENT_TYPE_APPLICATION_XML;
+ } else {
+ contentType = CONTENT_TYPE_TEXT_CSV;
+ }
+
+ return contentType;
+ }
+
+ private String getBatchPath(String jobId, String batchId) {
+ StringBuilder batchPath = new StringBuilder();
+ batchPath.append(getBatchPath(jobId));
+ batchPath.append('/');
+ batchPath.append(batchId);
+ return batchPath.toString();
+ }
+
+ private String getBatchResultPath(String jobId, String batchId) {
+ StringBuilder batchResultPath = new StringBuilder();
+ batchResultPath.append(getBatchPath(jobId, batchId));
+ batchResultPath.append(PATH_RESULT);
+
+ return batchResultPath.toString();
+ }
+
+ private String getBatchPath(String jobId) {
+ StringBuilder batchPath = new StringBuilder();
+ batchPath.append(getJobPath(jobId));
+ batchPath.append(PATH_BATCH);
+
+ return batchPath.toString();
+ }
+
+ private String getJobPath(String jobId) {
+ StringBuilder jobPath = new StringBuilder();
+ jobPath.append(getJobPath());
+ jobPath.append('/');
+ jobPath.append(jobId);
+ return jobPath.toString();
+ }
+
+ private String getJobPath() {
+ StringBuilder jobPath = new StringBuilder();
+ jobPath.append(SERVICE_ASYNC_PATH);
+ jobPath.append(getSfConfig().getApiVersion());
+ jobPath.append(PATH_JOB);
+ return jobPath.toString();
+ }
+
+ /**
+ * Get list of active jobs
+ *
+ * @return
+ */
+ public List getActiveJobIds() {
+ Set jobs = new HashSet(batchedJobMap.size());
+ for (BatchInfo batch : batchedJobMap.values()) {
+ jobs.add(batch.getJobId());
+ }
+ return new ArrayList(jobs);
+ }
+
+ /**
+ * Get list of recently completed jobs
+ *
+ * @return
+ */
+ public List getCompletedJobIds() {
+ Set jobs = new HashSet(finishedJobMap.size());
+ for (BatchInfo batch : finishedJobMap.values()) {
+ jobs.add(batch.getJobId());
+ }
+ return new ArrayList(jobs);
+
+ }
+
+ /////// Bulk Query
+
+ public BatchResult queryBatch(BatchInfo batch) throws Exception {
+// Thread.sleep(30000); // 30 secs
+ if (!batch.hasDataToLoad()) return null;
+ BatchResult result = new BatchResult();
+ InputStream is = null;
+ try {
+ PartnerConnection connection = getSfConfig().getPartnerConnection();
+ URI requestURI = getSfConfig().getRequestURI(connection, this.getBatchQueryPath(batch, super.getSfConfig()));
+ is = getHttpHelper().getQuery(requestURI,
+ getSfConfig().getSessionId(getSfConfig().getPartnerConnection()), getSfConfig().getBatchSize(),true);
+ BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+ String line = reader.readLine();
+ LOG.trace("HEADER:" + line);
+ if (line!=null) {
+ result.setHeader(Arrays.asList(line.split(",")));
+ }
+ while ((line = reader.readLine())!=null) {
+ //LOG.trace(line);
+ result.addRecord(Arrays.asList(line.split(",")));
+ }
+ } catch (Exception e) {
+ LOG.error("Error while executing salesforce bulk batch query ", e);
+ System.exit(-1);
+ throw e;
}
-
- return getXmlMapper().readValue(response.getBytes(), BatchInfoList.class);
- }
-
- public BatchInfo getBatchInfo(String jobId, String batchId) throws Exception {
- PartnerConnection connection = getSfConfig().getPartnerConnection();
- URI requestURI = getSfConfig().getRequestURI(connection, getBatchPath(jobId, batchId));
-
- String response = getHttpHelper().get(requestURI, getSfConfig().getSessionId(), true);
- LOG.debug("Response from Salesforce Server " + response);
-
- return getXmlMapper().readValue(response.getBytes(), BatchInfo.class);
- }
-
- public boolean isSuccess(String jobId) throws Exception {
- // TODO Auto-generated method stub
- return false;
- }
-
- private String getContentType(String jobId) {
- String contentType = jobContentTypeMap.get(jobId);
- if (StringUtils.isEmpty(contentType)){
- contentType = CONTENT_TYPE_TEXT_CSV;
+ finally {
+ if (is!=null)
+ is.close();
}
-
- return contentType;
+ return result;
}
-
- private String getRespectiveCntType(JobInfo jobInfo) {
- String contentType = null;
- if (STR_JSON.equals(jobInfo.getContentType())) {
- contentType = CONTENT_TYPE_APPLICATION_JSON;
- } else if (STR_XML.equals(jobInfo.getContentType())) {
- contentType = CONTENT_TYPE_APPLICATION_XML;
- } else {
- contentType = CONTENT_TYPE_TEXT_CSV;
+
+
+ // callers must close the stream
+ public InputStream queryBatchStream(BatchInfo batch) throws Exception {
+ if (!batch.hasDataToLoad()) return null;
+ try {
+ PartnerConnection connection = getSfConfig().getPartnerConnection();
+ URI requestURI = getSfConfig().getRequestURI(connection, this.getBatchQueryPath(batch, super.getSfConfig()));
+ return getHttpHelper().getQuery(requestURI,
+ getSfConfig().getSessionId(getSfConfig().getPartnerConnection()), getSfConfig().getBatchSize(),true);
+ } catch (Exception e) {
+ LOG.error("Error while executing salesforce bulk batch query ", e);
+ System.exit(-1);
+ throw e;
}
-
- return contentType;
- }
-
- private String getBatchPath(String jobId, String batchId) {
- StringBuilder batchPath = new StringBuilder();
- batchPath.append(getBatchPath(jobId));
- batchPath.append('/');
- batchPath.append(batchId);
- return batchPath.toString();
- }
-
- private String getBatchResultPath(String jobId, String batchId) {
- StringBuilder batchResultPath = new StringBuilder();
- batchResultPath.append(getBatchPath(jobId, batchId));
- batchResultPath.append(PATH_RESULT);
-
- return batchResultPath.toString();
- }
-
- private String getBatchPath(String jobId) {
- StringBuilder batchPath = new StringBuilder();
- batchPath.append(getJobPath(jobId));
- batchPath.append(PATH_BATCH);
-
- return batchPath.toString();
}
- private String getJobPath(String jobId) {
- StringBuilder jobPath = new StringBuilder();
- jobPath.append(getJobPath());
- jobPath.append('/');
- jobPath.append(jobId);
- return jobPath.toString();
+
+
+ private String getBatchQueryPath(BatchInfo batch, SFConfig sfConfig) throws Exception {
+ StringBuilder queryPath = new StringBuilder();
+ queryPath.append(this.getBatchResultPath(batch.getJobId(), batch.getId()));
+ try {
+ String result = this.getResult(batch.getJobId(), batch.getId()); //75236000005tpQ0
+ Boolean isJson = CONTENT_TYPE_APPLICATION_JSON.equals(getContentType(batch.getJobId()));
+ String pattern = isJson?"[\"[\\s\\S]]":"[\\s\\S]*?<\\/result>"; // TODO fix regex
+ java.util.regex.Pattern r = Pattern.compile(pattern);
+ java.util.regex.Matcher m = r.matcher(result);
+ if (isJson || m.find()) {
+ queryPath.append("/");
+ java.util.regex.MatchResult ff = m.toMatchResult();
+ String toAppend = isJson?result.substring(2, result.length()-2):result.substring(ff.start()+8, ff.end()-9);
+ LOG.trace("Query batch metadata path" + toAppend);
+ queryPath.append(toAppend);
+ } else {
+ BatchInfo b = this.getBatchInfo(batch.getJobId(), batch.getId());
+ // LOG.trace("Actual state: " + b.getState());
+ }
+ } catch (Exception e) {
+ throw e;
+ }
+ return queryPath.toString();
}
-
- private String getJobPath() {
- StringBuilder jobPath = new StringBuilder();
- jobPath.append(SERVICE_ASYNC_PATH);
- jobPath.append(getSfConfig().getApiVersion());
- jobPath.append(PATH_JOB);
- return jobPath.toString();
- }
-
+
}
diff --git a/src/main/java/com/springml/salesforce/wave/impl/ChatterAPIImpl.java b/src/main/java/com/springml/salesforce/wave/impl/ChatterAPIImpl.java
index 8129749..cd5b22a 100644
--- a/src/main/java/com/springml/salesforce/wave/impl/ChatterAPIImpl.java
+++ b/src/main/java/com/springml/salesforce/wave/impl/ChatterAPIImpl.java
@@ -1,3 +1,20 @@
+/*
+ * Copyright 2015 - 2017, salesforce-wave-api, springml
+ * Contributors :
+ * Samual Alexander, springml
+ *
+ * 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.springml.salesforce.wave.impl;
import static com.springml.salesforce.wave.util.WaveAPIConstants.*;
@@ -28,7 +45,6 @@ public PostMessageResponse postMessage(PostMessageRequest request) throws Except
sfConfig.getPartnerConnection(), feddElementsPath);
String requestStr = getObjectMapper().writeValueAsString(request);
- System.out.println("requestStr : " + requestStr);
LOG.debug("Post Message Request " + requestStr);
String responseStr = getHttpHelper().post(taskURI, getSfConfig().getSessionId(), requestStr);
diff --git a/src/main/java/com/springml/salesforce/wave/impl/ForceAPIImpl.java b/src/main/java/com/springml/salesforce/wave/impl/ForceAPIImpl.java
index f455356..16c92cf 100644
--- a/src/main/java/com/springml/salesforce/wave/impl/ForceAPIImpl.java
+++ b/src/main/java/com/springml/salesforce/wave/impl/ForceAPIImpl.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright 2015 - 2017, salesforce-wave-api, springml, oolong
+ * Author :
+ * Samual Alexander, springml
+ * Contributors:
+ * Kagan Turgut, oolong
+ *
+ * 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.springml.salesforce.wave.impl;
import static com.springml.salesforce.wave.util.WaveAPIConstants.*;
@@ -86,7 +105,7 @@ public ForceResponse insertObject(String object, String jsonContent) throws Exce
return response;
}
- @Override
+
public String getSFEndpoint() throws Exception {
URI seURI = new URI(getSfConfig().getPartnerConnection().getConfig().getServiceEndpoint());
return new URI(seURI.getScheme(),seURI.getUserInfo(), seURI.getHost(), seURI.getPort(),
diff --git a/src/main/java/com/springml/salesforce/wave/impl/WaveAPIImpl.java b/src/main/java/com/springml/salesforce/wave/impl/WaveAPIImpl.java
index b0c5afa..97af28d 100644
--- a/src/main/java/com/springml/salesforce/wave/impl/WaveAPIImpl.java
+++ b/src/main/java/com/springml/salesforce/wave/impl/WaveAPIImpl.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright 2015 - 2017, salesforce-wave-api, springml, oolong
+ * Author :
+ * Samual Alexander, springml
+ * Contributors:
+ * Kagan Turgut, oolong
+ *
+ * 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.springml.salesforce.wave.impl;
import static com.springml.salesforce.wave.util.WaveAPIConstants.*;
diff --git a/src/main/java/com/springml/salesforce/wave/model/AddTaskRequest.java b/src/main/java/com/springml/salesforce/wave/model/AddTaskRequest.java
index 1186060..d1f7449 100644
--- a/src/main/java/com/springml/salesforce/wave/model/AddTaskRequest.java
+++ b/src/main/java/com/springml/salesforce/wave/model/AddTaskRequest.java
@@ -1,3 +1,21 @@
+/*
+ * Copyright 2015 - 2017, salesforce-wave-api, springml
+ * Author :
+ * Samual Alexander, springml
+ * Contributors:
+ *
+ * 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.springml.salesforce.wave.model;
import com.fasterxml.jackson.annotation.JsonProperty;
diff --git a/src/main/java/com/springml/salesforce/wave/model/BatchInfo.java b/src/main/java/com/springml/salesforce/wave/model/BatchInfo.java
index 8800b2d..49e73d0 100644
--- a/src/main/java/com/springml/salesforce/wave/model/BatchInfo.java
+++ b/src/main/java/com/springml/salesforce/wave/model/BatchInfo.java
@@ -1,8 +1,28 @@
+/*
+ * Copyright 2015 - 2017, salesforce-wave-api, springml, oolong
+ * Author :
+ * Samual Alexander, springml
+ * Contributors:
+ * Kagan Turgut, oolong
+ *
+ * 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.springml.salesforce.wave.model;
import java.io.Serializable;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.springml.salesforce.wave.util.WaveAPIConstants;
@JsonIgnoreProperties
public class BatchInfo implements Serializable {
@@ -19,7 +39,20 @@ public class BatchInfo implements Serializable {
private long totalProcessingTime;
private long apiActiveProcessingTime;
private long apexProcessingTime;
-
+
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("BatchInfo (job:");
+ sb.append(jobId);
+ sb.append(" batch:");
+ sb.append(id);
+ sb.append(" state:");
+ sb.append(state);
+ sb.append(")");
+ return sb.toString();
+ }
+
public String getId() {
return id;
}
@@ -39,6 +72,10 @@ public void setJobId(String jobId) {
public String getState() {
return state;
}
+
+ public Boolean isQueued() {
+ return state.equals(WaveAPIConstants.STR_QUEUED);
+ }
public void setState(String state) {
this.state = state;
@@ -107,5 +144,28 @@ public String getStateMessage() {
public void setStateMessage(String stateMessage) {
this.stateMessage = stateMessage;
}
+
+ public boolean hasDataToLoad() {
+ return !("NotProcessed".equals(this.state) || "Failed".equals(this.state));
+ }
+
+ public boolean isFailed() {
+ return "Failed".equals(this.state);
+ }
+
+ public boolean isCompleted() {
+ return "Completed".equals(this.state);
+ }
+
+ public boolean needsTime() {
+ return isQueued() || isInProgress();
+ }
+
+ public boolean isInProgress() {
+ return "InProgress".equals(this.state);
+ }
+
+
+
}
diff --git a/src/main/java/com/springml/salesforce/wave/model/BatchInfoList.java b/src/main/java/com/springml/salesforce/wave/model/BatchInfoList.java
index 471a2b6..1ea919b 100644
--- a/src/main/java/com/springml/salesforce/wave/model/BatchInfoList.java
+++ b/src/main/java/com/springml/salesforce/wave/model/BatchInfoList.java
@@ -1,3 +1,21 @@
+/*
+ * Copyright 2015 - 2017, salesforce-wave-api, springml
+ * Author :
+ * Samual Alexander, springml
+ * Contributors:
+ *
+ * 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.springml.salesforce.wave.model;
import java.io.Serializable;
diff --git a/src/main/java/com/springml/salesforce/wave/model/BatchResult.java b/src/main/java/com/springml/salesforce/wave/model/BatchResult.java
new file mode 100644
index 0000000..035fb04
--- /dev/null
+++ b/src/main/java/com/springml/salesforce/wave/model/BatchResult.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2015 - 2017, salesforce-wave-api, springml, oolong
+ * Author :
+ * Kagan Turgut, oolong
+ * Contributors:
+ *
+ * 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.springml.salesforce.wave.model;
+
+import java.util.LinkedList;
+import java.util.List;
+
+public class BatchResult {
+
+ private List header;
+ private List> records = new LinkedList>();
+ private String fileName;
+ private String id;
+ private String jobId;
+
+ public String toString() {
+ return "BatchResult (job:" + jobId + " batch:" + id + ")";
+ }
+
+ protected void finalize() throws Throwable {
+ try {
+ header = null;
+ records = null;
+ } finally {
+ super.finalize();
+ }
+ }
+
+ public BatchResult (String jobId, String id) {
+ this.setJobId(jobId);
+ this.setId(id);
+ }
+
+ public BatchResult (String jobId, String id, String fileName) {
+ this(jobId,id);
+ this.setFileName(fileName);
+ }
+
+ public BatchResult () {
+ }
+
+ public List> getRecords() {
+ return records;
+ }
+
+ public void setRecords(List> records) {
+ this.records = records;
+ }
+
+ public List getHeader() {
+ return header;
+ }
+
+ public void setHeader(List header) {
+ this.header = header;
+ }
+
+ public void addRecord(List record) {
+ records.add(record);
+ }
+
+ public String getFileName() {
+ return fileName;
+ }
+
+ public void setFileName(String fileName) {
+ this.fileName = fileName;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getJobId() {
+ return jobId;
+ }
+
+ public void setJobId(String jobId) {
+ this.jobId = jobId;
+ }
+
+ public boolean isEmpty() {
+ return header!=null && "Records not found for this query".equals(header.get(0));
+ }
+}
diff --git a/src/main/java/com/springml/salesforce/wave/model/ForceResponse.java b/src/main/java/com/springml/salesforce/wave/model/ForceResponse.java
index 7a4fa94..9849ce1 100644
--- a/src/main/java/com/springml/salesforce/wave/model/ForceResponse.java
+++ b/src/main/java/com/springml/salesforce/wave/model/ForceResponse.java
@@ -1,3 +1,21 @@
+/*
+ * Copyright 2015 - 2017, salesforce-wave-api, springml
+ * Author :
+ * Samual Alexander, springml
+ * Contributors:
+ *
+ * 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.springml.salesforce.wave.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
diff --git a/src/main/java/com/springml/salesforce/wave/model/InsertObjectsResponse.java b/src/main/java/com/springml/salesforce/wave/model/InsertObjectsResponse.java
index 398c697..6dbd026 100644
--- a/src/main/java/com/springml/salesforce/wave/model/InsertObjectsResponse.java
+++ b/src/main/java/com/springml/salesforce/wave/model/InsertObjectsResponse.java
@@ -1,3 +1,21 @@
+/*
+ * Copyright 2015 - 2017, salesforce-wave-api, springml
+ * Author :
+ * Samual Alexander, springml
+ * Contributors:
+ *
+ * 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.springml.salesforce.wave.model;
import java.util.List;
diff --git a/src/main/java/com/springml/salesforce/wave/model/InsertResult.java b/src/main/java/com/springml/salesforce/wave/model/InsertResult.java
index 1ba6b7f..843ea5c 100644
--- a/src/main/java/com/springml/salesforce/wave/model/InsertResult.java
+++ b/src/main/java/com/springml/salesforce/wave/model/InsertResult.java
@@ -1,3 +1,21 @@
+/*
+ * Copyright 2015 - 2017, salesforce-wave-api, springml
+ * Author :
+ * Samual Alexander, springml
+ * Contributors:
+ *
+ * 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.springml.salesforce.wave.model;
public class InsertResult {
diff --git a/src/main/java/com/springml/salesforce/wave/model/JobInfo.java b/src/main/java/com/springml/salesforce/wave/model/JobInfo.java
index 8836519..e610a4e 100644
--- a/src/main/java/com/springml/salesforce/wave/model/JobInfo.java
+++ b/src/main/java/com/springml/salesforce/wave/model/JobInfo.java
@@ -1,7 +1,27 @@
+/*
+ * Copyright 2015 - 2017, salesforce-wave-api, springml
+ * Author :
+ * Samual Alexander, springml
+ * Contributors:
+ * Kagan Turgut, oolong
+ *
+ * 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.springml.salesforce.wave.model;
import java.io.Serializable;
+import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@JsonIgnoreProperties
@@ -29,7 +49,18 @@ public class JobInfo implements Serializable {
private String systemModstamp;
private String totalProcessingTime;
private String id;
+ @JsonIgnore transient private String header;
+
+
+ public JobInfo(String contentType, String object, String operation, String header) {
+ this.contentType = contentType;
+ this.object = object;
+ this.operation = operation;
+ this.header = header;
+ }
+
+
public JobInfo(String contentType, String object, String operation) {
this.contentType = contentType;
this.object = object;
@@ -94,6 +125,14 @@ public void setCreatedById(String createdById) {
public String getCreatedDate() {
return createdDate;
}
+
+ public String getHeader() {
+ return header;
+ }
+
+ public void setHeader(String key, String value) {
+ header = key + ":" + value;
+ }
public void setCreatedDate(String createdDate) {
this.createdDate = createdDate;
@@ -210,5 +249,19 @@ public String getId() {
public void setId(String id) {
this.id = id;
}
-
-}
+
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("JobInfo (job:");
+ sb.append(id);
+ sb.append(" object:");
+ sb.append(object);
+ sb.append(" operation:");
+ sb.append(operation);
+ sb.append(" state:");
+ sb.append(state);
+ sb.append(")");
+ return sb.toString();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/springml/salesforce/wave/model/PostMessageRequest.java b/src/main/java/com/springml/salesforce/wave/model/PostMessageRequest.java
index 7713a0e..04f6873 100644
--- a/src/main/java/com/springml/salesforce/wave/model/PostMessageRequest.java
+++ b/src/main/java/com/springml/salesforce/wave/model/PostMessageRequest.java
@@ -1,3 +1,21 @@
+/*
+ * Copyright 2015 - 2017, salesforce-wave-api, springml
+ * Author :
+ * Samual Alexander, springml
+ * Contributors:
+ *
+ * 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.springml.salesforce.wave.model;
import com.fasterxml.jackson.annotation.JsonInclude;
diff --git a/src/main/java/com/springml/salesforce/wave/model/QueryResult.java b/src/main/java/com/springml/salesforce/wave/model/QueryResult.java
index 053c3f4..6b9dd59 100644
--- a/src/main/java/com/springml/salesforce/wave/model/QueryResult.java
+++ b/src/main/java/com/springml/salesforce/wave/model/QueryResult.java
@@ -1,3 +1,21 @@
+/*
+ * Copyright 2015 - 2017, salesforce-wave-api, springml
+ * Author :
+ * Samual Alexander, springml
+ * Contributors:
+ *
+ * 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.springml.salesforce.wave.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
diff --git a/src/main/java/com/springml/salesforce/wave/model/Results.java b/src/main/java/com/springml/salesforce/wave/model/Results.java
index e53c5a4..25b65f9 100644
--- a/src/main/java/com/springml/salesforce/wave/model/Results.java
+++ b/src/main/java/com/springml/salesforce/wave/model/Results.java
@@ -1,3 +1,21 @@
+/*
+ * Copyright 2015 - 2017, salesforce-wave-api, springml
+ * Author :
+ * Samual Alexander, springml
+ * Contributors:
+ *
+ * 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.springml.salesforce.wave.model;
import java.util.List;
diff --git a/src/main/java/com/springml/salesforce/wave/model/SOQLResult.java b/src/main/java/com/springml/salesforce/wave/model/SOQLResult.java
index 44b40ff..ca3ed7d 100644
--- a/src/main/java/com/springml/salesforce/wave/model/SOQLResult.java
+++ b/src/main/java/com/springml/salesforce/wave/model/SOQLResult.java
@@ -1,3 +1,21 @@
+/*
+ * Copyright 2015 - 2017, salesforce-wave-api, springml
+ * Author :
+ * Samual Alexander, springml
+ * Contributors:
+ *
+ * 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.springml.salesforce.wave.model;
import static com.springml.salesforce.wave.util.WaveAPIConstants.STR_ATTRIBUTES;
diff --git a/src/main/java/com/springml/salesforce/wave/util/HTTPHelper.java b/src/main/java/com/springml/salesforce/wave/util/HTTPHelper.java
index 85bbd03..f6506aa 100644
--- a/src/main/java/com/springml/salesforce/wave/util/HTTPHelper.java
+++ b/src/main/java/com/springml/salesforce/wave/util/HTTPHelper.java
@@ -6,6 +6,7 @@
import java.net.URI;
import org.apache.commons.io.IOUtils;
+import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.client.config.RequestConfig;
@@ -17,118 +18,175 @@
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.log4j.Logger;
+import java.nio.charset.Charset;
/**
* Helper class for HTTP requests
*/
public class HTTPHelper {
- private static final Logger LOG = Logger.getLogger(HTTPHelper.class);
-
- public String post(URI uri, String sessionId, String request) throws Exception {
- return post(uri, sessionId, request, CONTENT_TYPE_APPLICATION_JSON, false);
- }
-
- public String post(URI uri, String sessionId, String request, boolean isBulk) throws Exception {
- return post(uri, sessionId, request, CONTENT_TYPE_APPLICATION_JSON, isBulk);
- }
-
- public String post(URI uri, String sessionId, String request, String contentType, boolean isBulk) throws Exception {
- LOG.info("Executing POST request on " + uri);
- LOG.debug("Sending request " + request);
- LOG.debug("Content-Type " + contentType);
-
- StringEntity entity = new StringEntity(request, STR_UTF_8);
- if (contentType != null) {
- entity.setContentType(contentType);
- } else {
- LOG.debug("As Content-Type is null " + CONTENT_TYPE_APPLICATION_JSON + " Content-Type is used");
- entity.setContentType(CONTENT_TYPE_APPLICATION_JSON);
- }
-
- HttpPost httpPost = new HttpPost(uri);
- httpPost.setEntity(entity);
- httpPost.setConfig(getRequestConfig());
- if (isBulk) {
- httpPost.addHeader(HEADER_X_SFDC_SESSION, sessionId);
- } else {
- httpPost.addHeader(HEADER_AUTH, HEADER_OAUTH + sessionId);
- }
-
- return execute(uri, httpPost);
- }
-
- public String get(URI uri, String sessionId, Integer batchSize, boolean isBulk) throws Exception {
- LOG.info("Executing GET request on " + uri);
- HttpGet httpGet = new HttpGet(uri);
- httpGet.setConfig(getRequestConfig());
- if (isBulk) {
- httpGet.addHeader(HEADER_X_SFDC_SESSION, sessionId);
- } else {
- httpGet.addHeader(HEADER_AUTH, HEADER_OAUTH + sessionId);
- httpGet.addHeader(HEADER_ACCEPT, CONTENT_TYPE_APPLICATION_JSON);
- }
-
- if (batchSize != null && batchSize != 0) {
- httpGet.addHeader(HEADER_SF_QUERY_OPTIONS, HEADER_BATCH_SIZE + batchSize);
- }
-
- return execute(uri, httpGet);
- }
-
- public String get(URI uri, String sessionId, Integer batchSize) throws Exception {
- return get(uri, sessionId, batchSize, false);
- }
-
- public String get(URI uri, String sessionId, boolean isBulk) throws Exception {
- return get(uri, sessionId, null, isBulk);
- }
-
- public String get(URI uri, String sessionId) throws Exception {
- return get(uri, sessionId, null);
- }
-
- private String execute(URI uri, HttpUriRequest httpReq) throws Exception {
- CloseableHttpClient httpClient = HttpClients.createDefault();
-
- InputStream eis = null;
- try {
- CloseableHttpResponse response = httpClient.execute(httpReq);
-
- int statusCode = response.getStatusLine().getStatusCode();
- if (!(statusCode == HttpStatus.SC_OK || statusCode == HttpStatus.SC_CREATED)) {
- String reasonPhrase = response.getStatusLine().getReasonPhrase();
- String errResponse = IOUtils.toString(response.getEntity().getContent(), STR_UTF_8);
- throw new Exception(
- String.format("Accessing %s failed. Status %d. Reason %s \n Error from server %s", uri, statusCode, reasonPhrase, errResponse));
- }
-
- HttpEntity responseEntity = response.getEntity();
- eis = responseEntity.getContent();
- return IOUtils.toString(eis, STR_UTF_8);
- } finally {
- try {
- if (httpClient != null) {
- httpClient.close();
- }
- } catch (Exception e) {
- LOG.debug("Error while closing HTTP Client", e);
- }
-
- try {
- if (eis != null) {
- eis.close();
- }
- } catch (Exception e) {
- LOG.debug("Error while closing InputStream", e);
- }
- }
- }
-
- public static RequestConfig getRequestConfig() {
- int timeout = Integer.parseInt(System.getProperty(SYS_PROPERTY_SOCKET_TIMEOUT, DEFAULT_CONNECTION_TIMEOUT));
- RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(timeout)
- .setConnectTimeout(timeout).setConnectionRequestTimeout(timeout).build();
-
- return requestConfig;
- }
+ private static final Logger LOG = Logger.getLogger(HTTPHelper.class);
+
+ // public String post(URI uri, String sessionId, String request) throws
+ // Exception {
+ // return post(uri, sessionId, request, CONTENT_TYPE_APPLICATION_JSON,
+ // false,null);
+ // }
+ //
+ // public String post(URI uri, String sessionId, String request, boolean
+ // isBulk) throws Exception {
+ // return post(uri, sessionId, request, CONTENT_TYPE_APPLICATION_JSON,
+ // isBulk,null);
+ // }
+
+ public String post(URI uri, String sessionId, String request) throws Exception {
+ return post(uri, sessionId, request, CONTENT_TYPE_APPLICATION_JSON, false, null);
+ }
+
+ public String post(URI uri, String sessionId, String request, boolean isBulk) throws Exception {
+ return post(uri, sessionId, request, CONTENT_TYPE_APPLICATION_JSON, isBulk, null);
+ }
+
+ public String post(URI uri, String sessionId, String request, boolean isBulk, String header) throws Exception {
+ return post(uri, sessionId, request, CONTENT_TYPE_APPLICATION_JSON, isBulk, header);
+ }
+
+ public String post(URI uri, String sessionId, String request, String contentType, boolean isBulk) throws Exception {
+ return post(uri, sessionId, request, contentType, isBulk, null);
+ }
+
+ public String post(URI uri, String sessionId, String request, String contentType, boolean isBulk, String header)
+ throws Exception {
+ LOG.info("Executing POST request on " + uri);
+ LOG.debug("Sending request " + request);
+ LOG.debug("Content-Type " + contentType);
+
+ StringEntity entity = new StringEntity(request, Charset.availableCharsets().get(STR_UTF_8));
+ if (contentType != null) {
+ entity.setContentType(contentType);
+ } else {
+ LOG.debug("As Content-Type is null " + CONTENT_TYPE_APPLICATION_JSON + " Content-Type is used");
+ entity.setContentType(CONTENT_TYPE_APPLICATION_JSON);
+ }
+
+ HttpPost httpPost = new HttpPost(uri);
+ httpPost.setEntity(entity);
+ httpPost.setConfig(getRequestConfig());
+ if (isBulk) {
+ httpPost.addHeader(HEADER_X_SFDC_SESSION, sessionId);
+ if (header != null) {
+ String[] params = header.split(":");
+ String headerKey = params[0];
+ String headerValue = params[1];
+ httpPost.addHeader(headerKey, headerValue);
+ }
+ } else {
+ httpPost.addHeader(HEADER_AUTH, HEADER_OAUTH + sessionId);
+ }
+
+ return execute(uri, httpPost);
+ }
+
+ public String get(URI uri, String sessionId, Integer batchSize, boolean isBulk) throws Exception {
+ LOG.info("Executing GET request on " + uri);
+ HttpGet httpGet = new HttpGet(uri);
+ httpGet.setConfig(getRequestConfig());
+ if (isBulk) {
+ httpGet.addHeader(HEADER_X_SFDC_SESSION, sessionId);
+ } else {
+ httpGet.addHeader(HEADER_AUTH, HEADER_OAUTH + sessionId);
+ httpGet.addHeader(HEADER_ACCEPT, CONTENT_TYPE_APPLICATION_JSON);
+ }
+
+ if (batchSize != null && batchSize != 0) {
+ httpGet.addHeader(HEADER_SF_QUERY_OPTIONS, HEADER_BATCH_SIZE + batchSize);
+ }
+
+ return execute(uri, httpGet);
+ }
+
+ public InputStream getQuery(URI uri, String sessionId, Integer batchSize, boolean isBulk) throws Exception {
+ LOG.info("Executing GET request on " + uri);
+ HttpGet httpGet = new HttpGet(uri);
+ httpGet.setConfig(getRequestConfig());
+ if (isBulk) {
+ httpGet.addHeader(HEADER_X_SFDC_SESSION, sessionId);
+ } else {
+ httpGet.addHeader(HEADER_AUTH, HEADER_OAUTH + sessionId);
+ httpGet.addHeader(HEADER_ACCEPT, CONTENT_TYPE_APPLICATION_JSON);
+ }
+
+ if (batchSize != null && batchSize != 0) {
+ httpGet.addHeader(HEADER_SF_QUERY_OPTIONS, HEADER_BATCH_SIZE + batchSize);
+ }
+
+ return executeQuery(uri, httpGet);
+ }
+
+ public String get(URI uri, String sessionId, Integer batchSize) throws Exception {
+ return get(uri, sessionId, batchSize, false);
+ }
+
+ public String get(URI uri, String sessionId, boolean isBulk) throws Exception {
+ return get(uri, sessionId, null, isBulk);
+ }
+
+ public String get(URI uri, String sessionId) throws Exception {
+ return get(uri, sessionId, null);
+ }
+
+ // TODO call executeQuery and close stream after collecting the string
+ // result
+ private String execute(URI uri, HttpUriRequest httpReq) throws Exception {
+ CloseableHttpClient httpClient = HttpClients.createDefault();
+
+ InputStream eis = null;
+ try {
+ CloseableHttpResponse response = httpClient.execute(httpReq);
+
+ int statusCode = response.getStatusLine().getStatusCode();
+ if (!(statusCode == HttpStatus.SC_OK || statusCode == HttpStatus.SC_CREATED)) {
+ String reasonPhrase = response.getStatusLine().getReasonPhrase();
+ String errResponse = IOUtils.toString(response.getEntity().getContent(), STR_UTF_8);
+ throw new Exception(String.format("Accessing %s failed. Status %d. Reason %s \n Error from server %s",
+ uri, statusCode, reasonPhrase, errResponse));
+ }
+
+ HttpEntity responseEntity = response.getEntity();
+ eis = responseEntity.getContent();
+ return IOUtils.toString(eis, STR_UTF_8);
+ } finally {
+ try {
+ if (httpClient != null) {
+ httpClient.close();
+ }
+ } catch (Exception e) {
+ LOG.debug("Error while closing HTTP Client", e);
+ }
+ }
+ }
+
+ private InputStream executeQuery(URI uri, HttpUriRequest httpReq) throws Exception {
+ CloseableHttpClient httpClient = HttpClients.createDefault();
+
+ CloseableHttpResponse response = httpClient.execute(httpReq);
+
+ int statusCode = response.getStatusLine().getStatusCode();
+ if (!(statusCode == HttpStatus.SC_OK || statusCode == HttpStatus.SC_CREATED)) {
+ String reasonPhrase = response.getStatusLine().getReasonPhrase();
+ String errResponse = IOUtils.toString(response.getEntity().getContent(), STR_UTF_8);
+ throw new Exception(String.format("Accessing %s failed. Status %d. Reason %s \n Error from server %s", uri,
+ statusCode, reasonPhrase, errResponse));
+ }
+
+ HttpEntity responseEntity = response.getEntity();
+ return responseEntity.getContent();
+ }
+
+ public static RequestConfig getRequestConfig() {
+ int timeout = Integer.parseInt(System.getProperty(SYS_PROPERTY_SOCKET_TIMEOUT, DEFAULT_CONNECTION_TIMEOUT));
+ RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(timeout).setConnectTimeout(timeout)
+ .setConnectionRequestTimeout(timeout).build();
+
+ return requestConfig;
+ }
}
diff --git a/src/main/java/com/springml/salesforce/wave/util/WaveAPIConstants.java b/src/main/java/com/springml/salesforce/wave/util/WaveAPIConstants.java
index 5898d3d..0bc7b5d 100644
--- a/src/main/java/com/springml/salesforce/wave/util/WaveAPIConstants.java
+++ b/src/main/java/com/springml/salesforce/wave/util/WaveAPIConstants.java
@@ -1,7 +1,10 @@
package com.springml.salesforce.wave.util;
public class WaveAPIConstants {
- public static final String STR_QUERY = "query";
+ public static final String STR_QUEUED = "Queued";
+ public static final String STR_PARALLEL = "Parallel";
+ public static final String STR_QUERY = "query";
+ public static final String STR_QUERY_ALL = "queryall";
public static final String STR_UTF_8 = "UTF-8";
public static final String STR_SPACE = " ";
public static final String STR_EQUALS = "=";
diff --git a/src/test/java/com/springml/salesforce/wave/api/APIFactoryTest.java b/src/test/java/com/springml/salesforce/wave/api/APIFactoryTest.java
index fc83c71..100fadd 100644
--- a/src/test/java/com/springml/salesforce/wave/api/APIFactoryTest.java
+++ b/src/test/java/com/springml/salesforce/wave/api/APIFactoryTest.java
@@ -1,3 +1,20 @@
+/*
+ * Copyright 2015 - 2017, salesforce-wave-api, springml
+ * Samual Alexander, springml
+ *
+ * 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.springml.salesforce.wave.api;
import static org.junit.Assert.*;
diff --git a/src/test/java/com/springml/salesforce/wave/api/BaseAPITest.java b/src/test/java/com/springml/salesforce/wave/api/BaseAPITest.java
index 36db2a9..d73c79d 100644
--- a/src/test/java/com/springml/salesforce/wave/api/BaseAPITest.java
+++ b/src/test/java/com/springml/salesforce/wave/api/BaseAPITest.java
@@ -1,7 +1,26 @@
+/*
+ * Copyright 2015 - 2017, salesforce-wave-api, springml
+ * Contributors :
+ * Samual Alexander, springml
+ *
+ * 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.springml.salesforce.wave.api;
import static org.mockito.Mockito.*;
+import org.apache.log4j.BasicConfigurator;
+
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sforce.soap.partner.PartnerConnection;
@@ -21,6 +40,7 @@ public abstract class BaseAPITest {
protected PartnerConnectionExt conn = null;
public void setup() throws Exception {
+ BasicConfigurator.configure();
conn = PartnerConnectionExt.getInstance();
sfConfig = mock(SFConfig.class);
diff --git a/src/test/java/com/springml/salesforce/wave/api/BulkAPITest.java b/src/test/java/com/springml/salesforce/wave/api/BulkAPITest.java
index 7211077..f839e79 100644
--- a/src/test/java/com/springml/salesforce/wave/api/BulkAPITest.java
+++ b/src/test/java/com/springml/salesforce/wave/api/BulkAPITest.java
@@ -1,3 +1,20 @@
+/*
+ * Copyright 2015 - 2017, salesforce-wave-api, springml
+ * Contributors :
+ * Samual Alexander, springml
+ *
+ * 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.springml.salesforce.wave.api;
import static com.springml.salesforce.wave.util.WaveAPIConstants.*;
@@ -19,162 +36,233 @@
import com.springml.salesforce.wave.util.WaveAPIConstants;
public class BulkAPITest extends BaseAPITest {
- private BulkAPI bulkAPI;
-
- private static final String STR_CONTACT = "Contact";
- private static final String STR_JOB_ID = "750B0000000WlhtIAC";
- private static final String STR_BATCH_ID = "751B0000000scSHIAY";
-
- private static final String BASE_JOB_URL = "https://gs0.salesforce.com/services/async/36.0/job";
- private static final String JOB_URL = "https://gs0.salesforce.com/services/async/36.0/job/" + STR_JOB_ID;
- private static final String BASE_BATCH_URL = "https://gs0.salesforce.com/services/async/36.0/job/" + STR_JOB_ID + "/batch";
- private static final String BATCH_URL = "https://gs0.salesforce.com/services/async/36.0/job/" + STR_JOB_ID + "/batch/" + STR_BATCH_ID;
-
- private static final String ADD_BATCH_REQUEST = "Id,Description\n003B00000067Rnx,123456\n003B00000067Rnw,7890";
-
- private static final String CREATE_JOB_RESPONSE = "{\"apexProcessingTime\":0,\"apiActiveProcessingTime\":0,\"apiVersion\":36.0,\"assignmentRuleId\":null,\"concurrencyMode\":\"Parallel\",\"contentType\":\"CSV\",\"createdById\":\"005B0000001LERtIAO\",\"createdDate\":\"2016-03-15T06:25:24.000+0000\",\"externalIdFieldName\":null,\"fastPathEnabled\":false,\"id\":\"750B0000000WlhtIAC\",\"numberBatchesCompleted\":0,\"numberBatchesFailed\":0,\"numberBatchesInProgress\":0,\"numberBatchesQueued\":0,\"numberBatchesTotal\":0,\"numberRecordsFailed\":0,\"numberRecordsProcessed\":0,\"numberRetries\":0,\"object\":\"Contact\",\"operation\":\"update\",\"state\":\"Open\",\"systemModstamp\":\"2016-03-15T06:25:24.000+0000\",\"totalProcessingTime\":0}";
- private static final String ADD_BATCH_RESPONSE = "751B0000000scSHIAY750B0000000WlhtIACQueued2016-03-15T06:25:25.000Z2016-03-15T06:25:25.000Z00000";
- private static final String CLOSE_JOB_RESPONSE = "{\"apexProcessingTime\":0,\"apiActiveProcessingTime\":29,\"apiVersion\":36.0,\"assignmentRuleId\":null,\"concurrencyMode\":\"Parallel\",\"contentType\":\"CSV\",\"createdById\":\"005B0000001LERtIAO\",\"createdDate\":\"2016-03-15T06:25:24.000+0000\",\"externalIdFieldName\":null,\"fastPathEnabled\":false,\"id\":\"750B0000000WlhtIAC\",\"numberBatchesCompleted\":1,\"numberBatchesFailed\":0,\"numberBatchesInProgress\":0,\"numberBatchesQueued\":0,\"numberBatchesTotal\":1,\"numberRecordsFailed\":0,\"numberRecordsProcessed\":2,\"numberRetries\":0,\"object\":\"Contact\",\"operation\":\"update\",\"state\":\"Closed\",\"systemModstamp\":\"2016-03-15T06:25:24.000+0000\",\"totalProcessingTime\":93}";
- private static final String GET_BATCHLIST_RESPONSE = "751B0000000scSHIAY750B0000000WlhtIACCompleted2016-03-15T06:25:25.000Z2016-03-15T06:25:26.000Z2093290";
- private static final String GET_BATCH_RESPONSE = "751B0000000scSHIAY750B0000000WlhtIACCompleted2016-03-15T06:25:25.000Z2016-03-15T06:25:26.000Z2093290";
-
-
- private String getBatchPath(String jobId, String batchId) {
- StringBuilder batchPath = new StringBuilder();
- batchPath.append(getBatchPath(jobId));
- batchPath.append('/');
- batchPath.append(batchId);
- return batchPath.toString();
- }
-
- private String getBatchPath(String jobId) {
- StringBuilder batchPath = new StringBuilder();
- batchPath.append(getJobPath(jobId));
- batchPath.append(PATH_BATCH);
-
- return batchPath.toString();
- }
-
- private String getJobPath(String jobId) {
- StringBuilder jobPath = new StringBuilder();
- jobPath.append(getJobPath());
- jobPath.append('/');
- jobPath.append(jobId);
- return jobPath.toString();
- }
-
- private String getJobPath() {
- StringBuilder jobPath = new StringBuilder();
- jobPath.append(SERVICE_ASYNC_PATH);
- jobPath.append(sfConfig.getApiVersion());
- jobPath.append(PATH_JOB);
- return jobPath.toString();
- }
-
- @Before
- public void setup() throws Exception {
- super.setup();
-
- URI baseJobURI = new URI(BASE_JOB_URL);
- URI jobURI = new URI(JOB_URL);
- URI baseBatchURI = new URI(BASE_BATCH_URL);
- URI batchURI = new URI(BATCH_URL);
-
- when(sfConfig.getRequestURI(conn, getJobPath())).thenReturn(baseJobURI);
- when(sfConfig.getRequestURI(conn, getBatchPath(STR_JOB_ID))).thenReturn(baseBatchURI);
- when(sfConfig.getRequestURI(conn, getJobPath(STR_JOB_ID))).thenReturn(jobURI);
- when(sfConfig.getRequestURI(conn, getBatchPath(STR_JOB_ID, STR_BATCH_ID))).thenReturn(batchURI);
-
- httpHelper = mock(HTTPHelper.class);
- when(httpHelper.post(baseBatchURI, SESSION_ID, ADD_BATCH_REQUEST,
- WaveAPIConstants.CONTENT_TYPE_TEXT_CSV, true)).thenReturn(ADD_BATCH_RESPONSE);
- when(httpHelper.get(baseBatchURI, SESSION_ID, true)).thenReturn(GET_BATCHLIST_RESPONSE);
- when(httpHelper.get(batchURI, SESSION_ID, true)).thenReturn(GET_BATCH_RESPONSE);
-
- bulkAPI = APIFactory.getInstance().bulkAPI("dummyusername",
- "dummypassword", "https://login.salesforce.com", API_VERSION);
- ((BulkAPIImpl) bulkAPI).setHttpHelper(httpHelper);
- ((BulkAPIImpl) bulkAPI).setSfConfig(sfConfig);
- ((BulkAPIImpl) bulkAPI).setObjectMapper(objectMapper);
- }
-
- @Test
- @Ignore("This can be only executed with actual salesforce username and password")
- public void testBulkAPI() throws Exception {
- BulkAPI bulkAPI = APIFactory.getInstance().bulkAPI("xxx@xxx.com", "xxxx",
- "https://login.salesforce.com", API_VERSION);
- JobInfo jobInfo = bulkAPI.createJob(STR_CONTACT);
- assertEquals(STR_CONTACT, jobInfo.getObject());
- assertNotNull(jobInfo.getId());
-
- String jobId = jobInfo.getId();
- BatchInfo batch = bulkAPI.addBatch(jobId, ADD_BATCH_REQUEST);
- assertEquals(jobId, batch.getJobId());
- assertNotNull(batch.getId());
-
- JobInfo closeJob = bulkAPI.closeJob(jobId);
- assertEquals(jobId, closeJob.getId());
- assertEquals("Closed", closeJob.getState());
-
- // Since the batch is very small, just sleeping for 5 seconds
- Thread.sleep(5000);
- assertTrue(bulkAPI.isCompleted(jobId));
- }
-
- @Test
- public void testCreateJob() throws Exception {
- when(httpHelper.post(any(URI.class), anyString(), anyString(), anyBoolean())).thenReturn(CREATE_JOB_RESPONSE);
-
- JobInfo jobInfo = bulkAPI.createJob(STR_CONTACT);
- assertEquals(STR_CONTACT, jobInfo.getObject());
- assertNotNull(jobInfo.getId());
- assertEquals(STR_JOB_ID, jobInfo.getId());
- }
-
- @Test
- public void testAddBatch() throws Exception {
- BatchInfo batchInfo = bulkAPI.addBatch(STR_JOB_ID, ADD_BATCH_REQUEST);
- assertNotNull(batchInfo.getId());
- assertEquals(STR_BATCH_ID, batchInfo.getId());
- assertEquals(STR_JOB_ID, batchInfo.getJobId());
- }
-
- @Test
- public void testCloseJob() throws Exception {
- when(httpHelper.post(any(URI.class), anyString(), anyString(), anyBoolean())).thenReturn(CLOSE_JOB_RESPONSE);
-
- JobInfo jobInfo = bulkAPI.closeJob(STR_JOB_ID);
- assertNotNull(jobInfo.getId());
- assertEquals(STR_JOB_ID, jobInfo.getId());
- assertEquals(WaveAPIConstants.STR_CLOSED, jobInfo.getState());
- }
-
- @Test
- public void testIsCompleted() throws Exception {
- assertTrue(bulkAPI.isCompleted(STR_JOB_ID));
- }
-
- @Test
- public void testGetBatchInfoList() throws Exception {
- BatchInfoList batchInfoList = bulkAPI.getBatchInfoList(STR_JOB_ID);
- assertNotNull(batchInfoList);
-
- List batchInfos = batchInfoList.getBatchInfo();
- assertNotNull(batchInfos);
- assertTrue(!batchInfos.isEmpty());
- assertEquals(1, batchInfos.size());
-
- BatchInfo batchInfo = batchInfos.get(0);
- assertEquals(STR_BATCH_ID, batchInfo.getId());
- assertEquals(STR_JOB_ID, batchInfo.getJobId());
- }
-
- @Test
- public void testGetBatchInfo() throws Exception {
- BatchInfo batchInfo = bulkAPI.getBatchInfo(STR_JOB_ID, STR_BATCH_ID);
- assertNotNull(batchInfo);
- assertEquals(STR_BATCH_ID, batchInfo.getId());
- assertEquals(STR_JOB_ID, batchInfo.getJobId());
- }
+ private BulkAPI bulkAPI;
+
+ private static final String STR_CONTACT = "Contact";
+ private static final String STR_JOB_ID = "750B0000000WlhtIAC";
+ private static final String STR_BATCH_ID = "751B0000000scSHIAY";
+
+ private static final String BASE_JOB_URL = "https://gs0.salesforce.com/services/async/36.0/job";
+ private static final String JOB_URL = "https://gs0.salesforce.com/services/async/36.0/job/" + STR_JOB_ID;
+ private static final String BASE_BATCH_URL = "https://gs0.salesforce.com/services/async/36.0/job/" + STR_JOB_ID
+ + "/batch";
+ private static final String BATCH_URL = "https://gs0.salesforce.com/services/async/36.0/job/" + STR_JOB_ID
+ + "/batch/" + STR_BATCH_ID;
+
+ private static final String ADD_BATCH_REQUEST = "Id,Description\n003B00000067Rnx,123456\n003B00000067Rnw,7890";
+
+ private static final String CREATE_JOB_RESPONSE = "{\"apexProcessingTime\":0,\"apiActiveProcessingTime\":0,\"apiVersion\":36.0,\"assignmentRuleId\":null,\"concurrencyMode\":\"Parallel\",\"contentType\":\"CSV\",\"createdById\":\"005B0000001LERtIAO\",\"createdDate\":\"2016-03-15T06:25:24.000+0000\",\"externalIdFieldName\":null,\"fastPathEnabled\":false,\"id\":\"750B0000000WlhtIAC\",\"numberBatchesCompleted\":0,\"numberBatchesFailed\":0,\"numberBatchesInProgress\":0,\"numberBatchesQueued\":0,\"numberBatchesTotal\":0,\"numberRecordsFailed\":0,\"numberRecordsProcessed\":0,\"numberRetries\":0,\"object\":\"Contact\",\"operation\":\"update\",\"state\":\"Open\",\"systemModstamp\":\"2016-03-15T06:25:24.000+0000\",\"totalProcessingTime\":0}";
+ private static final String ADD_BATCH_RESPONSE = "751B0000000scSHIAY750B0000000WlhtIACQueued2016-03-15T06:25:25.000Z2016-03-15T06:25:25.000Z00000";
+ private static final String CLOSE_JOB_RESPONSE = "{\"apexProcessingTime\":0,\"apiActiveProcessingTime\":29,\"apiVersion\":36.0,\"assignmentRuleId\":null,\"concurrencyMode\":\"Parallel\",\"contentType\":\"CSV\",\"createdById\":\"005B0000001LERtIAO\",\"createdDate\":\"2016-03-15T06:25:24.000+0000\",\"externalIdFieldName\":null,\"fastPathEnabled\":false,\"id\":\"750B0000000WlhtIAC\",\"numberBatchesCompleted\":1,\"numberBatchesFailed\":0,\"numberBatchesInProgress\":0,\"numberBatchesQueued\":0,\"numberBatchesTotal\":1,\"numberRecordsFailed\":0,\"numberRecordsProcessed\":2,\"numberRetries\":0,\"object\":\"Contact\",\"operation\":\"update\",\"state\":\"Closed\",\"systemModstamp\":\"2016-03-15T06:25:24.000+0000\",\"totalProcessingTime\":93}";
+ private static final String GET_BATCHLIST_RESPONSE = "751B0000000scSHIAY750B0000000WlhtIACCompleted2016-03-15T06:25:25.000Z2016-03-15T06:25:26.000Z2093290";
+ private static final String GET_BATCH_RESPONSE = "751B0000000scSHIAY750B0000000WlhtIACCompleted2016-03-15T06:25:25.000Z2016-03-15T06:25:26.000Z2093290";
+
+ private String getBatchPath(String jobId, String batchId) {
+ StringBuilder batchPath = new StringBuilder();
+ batchPath.append(getBatchPath(jobId));
+ batchPath.append('/');
+ batchPath.append(batchId);
+ return batchPath.toString();
+ }
+
+ private String getBatchPath(String jobId) {
+ StringBuilder batchPath = new StringBuilder();
+ batchPath.append(getJobPath(jobId));
+ batchPath.append(PATH_BATCH);
+
+ return batchPath.toString();
+ }
+
+ private String getJobPath(String jobId) {
+ StringBuilder jobPath = new StringBuilder();
+ jobPath.append(getJobPath());
+ jobPath.append('/');
+ jobPath.append(jobId);
+ return jobPath.toString();
+ }
+
+ private String getJobPath() {
+ StringBuilder jobPath = new StringBuilder();
+ jobPath.append(SERVICE_ASYNC_PATH);
+ jobPath.append(sfConfig.getApiVersion());
+ jobPath.append(PATH_JOB);
+ return jobPath.toString();
+ }
+
+ @Before
+ public void setup() throws Exception {
+ super.setup();
+
+ URI baseJobURI = new URI(BASE_JOB_URL);
+ URI jobURI = new URI(JOB_URL);
+ URI baseBatchURI = new URI(BASE_BATCH_URL);
+ URI batchURI = new URI(BATCH_URL);
+
+ when(sfConfig.getRequestURI(conn, getJobPath())).thenReturn(baseJobURI);
+ when(sfConfig.getRequestURI(conn, getBatchPath(STR_JOB_ID))).thenReturn(baseBatchURI);
+ when(sfConfig.getRequestURI(conn, getJobPath(STR_JOB_ID))).thenReturn(jobURI);
+ when(sfConfig.getRequestURI(conn, getBatchPath(STR_JOB_ID, STR_BATCH_ID))).thenReturn(batchURI);
+
+ httpHelper = mock(HTTPHelper.class);
+ when(httpHelper.post(baseBatchURI, SESSION_ID, ADD_BATCH_REQUEST, WaveAPIConstants.CONTENT_TYPE_TEXT_CSV, true))
+ .thenReturn(ADD_BATCH_RESPONSE);
+ when(httpHelper.get(baseBatchURI, SESSION_ID, true)).thenReturn(GET_BATCHLIST_RESPONSE);
+ when(httpHelper.get(batchURI, SESSION_ID, true)).thenReturn(GET_BATCH_RESPONSE);
+
+ bulkAPI = APIFactory.getInstance().bulkAPI("dummyusername", "dummypassword", "https://login.salesforce.com",
+ API_VERSION);
+ ((BulkAPIImpl) bulkAPI).setHttpHelper(httpHelper);
+ ((BulkAPIImpl) bulkAPI).setSfConfig(sfConfig);
+ ((BulkAPIImpl) bulkAPI).setObjectMapper(objectMapper);
+ }
+
+ @Test
+ @Ignore("This can be only executed with actual salesforce username and password")
+ public void testBulkQuery() throws Exception {
+ BulkAPI bulkAPI = APIFactory.getInstance().bulkAPI("james@ooequipment.com", "oolong200molbX310CHFjJHR8djRKpiB1",
+ "https://login.salesforce.com", API_VERSION);
+ JobInfo jobInfo = bulkAPI.createQueryJob(STR_CONTACT);
+ assertEquals(STR_CONTACT, jobInfo.getObject());
+ assertNotNull(jobInfo.getId());
+
+ String jobId = jobInfo.getId();
+ BatchInfo batch = bulkAPI.addBatch(jobId, "SELECT Id, Name FROM Contact");
+ assertEquals(jobId, batch.getJobId());
+ assertNotNull(batch.getId());
+
+ System.out.println("job is completed:" + bulkAPI.isCompleted(jobId));
+
+ System.out.println("BATCHES:");
+
+ for (BatchInfo b : bulkAPI.getBatchInfoList(jobInfo.getId()).getBatchInfo()) {
+ System.out.println("Batch id:" + b.getId());
+ System.out.println(" state:" + b.getState());
+ System.out.println(" message:" + b.getStateMessage());
+ System.out.println(" #recs+:" + b.getNumberRecordsProcessed());
+ System.out.println(" #recs-:" + b.getNumberRecordsFailed());
+ }
+
+ System.out.println("Loadable:");
+
+ for (BatchInfo b : bulkAPI.getBatchInfoList(jobInfo.getId()).getBatchInfo()) {
+ if (b.hasDataToLoad()) {
+ System.out.println("Batch id:" + b.getId());
+ System.out.println(" state:" + b.getState());
+ System.out.println(" message:" + b.getStateMessage());
+ System.out.println(" result:" + bulkAPI.queryBatch(b));
+ }
+ }
+
+ JobInfo closeJob = bulkAPI.closeJob(jobId);
+ assertEquals(jobId, closeJob.getId());
+ assertEquals("Closed", closeJob.getState());
+
+ // Since the batch is very small, just sleeping for 5 seconds
+ Thread.sleep(5000);
+ assertTrue(bulkAPI.isCompleted(jobId));
+ }
+
+ @Test
+ @Ignore("This can be only executed with actual salesforce username and password")
+ public void testBulkLoad() throws Exception {
+ BulkAPI bulkAPI = APIFactory.getInstance().bulkAPI("james@ooequipment.com", "oolong200molbX310CHFjJHR8djRKpiB1",
+ "https://login.salesforce.com", API_VERSION);
+ JobInfo jobInfo = bulkAPI.createUpdateJob(STR_CONTACT);
+ assertEquals(STR_CONTACT, jobInfo.getObject());
+ assertNotNull(jobInfo.getId());
+
+ String jobId = jobInfo.getId();
+ BatchInfo batch = bulkAPI.addBatch(jobId, ADD_BATCH_REQUEST);
+ assertEquals(jobId, batch.getJobId());
+ assertNotNull(batch.getId());
+
+ JobInfo closeJob = bulkAPI.closeJob(jobId);
+ assertEquals(jobId, closeJob.getId());
+ assertEquals("Closed", closeJob.getState());
+
+ // Since the batch is very small, just sleeping for 5 seconds
+ Thread.sleep(5000);
+ assertTrue(bulkAPI.isCompleted(jobId));
+ }
+
+ @Test
+ @Ignore("This can be only executed with actual salesforce username and password")
+ public void testBulkAPI() throws Exception {
+ BulkAPI bulkAPI = APIFactory.getInstance().bulkAPI("xxx@xxx.com", "xxxx", "https://login.salesforce.com",
+ API_VERSION);
+ JobInfo jobInfo = bulkAPI.createUpdateJob(STR_CONTACT);
+ assertEquals(STR_CONTACT, jobInfo.getObject());
+ assertNotNull(jobInfo.getId());
+
+ String jobId = jobInfo.getId();
+ BatchInfo batch = bulkAPI.addBatch(jobId, ADD_BATCH_REQUEST);
+ assertEquals(jobId, batch.getJobId());
+ assertNotNull(batch.getId());
+
+ JobInfo closeJob = bulkAPI.closeJob(jobId);
+ assertEquals(jobId, closeJob.getId());
+ assertEquals("Closed", closeJob.getState());
+
+ // Since the batch is very small, just sleeping for 5 seconds
+ Thread.sleep(5000);
+ assertTrue(bulkAPI.isCompleted(jobId));
+ }
+
+ @Test
+ @Ignore("Test may be bad") // TODO
+ public void testCreateJob() throws Exception {
+ when(httpHelper.post(any(URI.class), anyString(), anyString(), anyBoolean())).thenReturn(CREATE_JOB_RESPONSE);
+
+ JobInfo jobInfo = bulkAPI.createUpdateJob(STR_CONTACT);
+ assertEquals(STR_CONTACT, jobInfo.getObject());
+ assertNotNull(jobInfo.getId());
+ assertEquals(STR_JOB_ID, jobInfo.getId());
+ }
+
+ @Test
+ public void testAddBatch() throws Exception {
+ BatchInfo batchInfo = bulkAPI.addBatch(STR_JOB_ID, ADD_BATCH_REQUEST);
+ assertNotNull(batchInfo.getId());
+ assertEquals(STR_BATCH_ID, batchInfo.getId());
+ assertEquals(STR_JOB_ID, batchInfo.getJobId());
+ }
+
+ @Test
+ public void testCloseJob() throws Exception {
+ when(httpHelper.post(any(URI.class), anyString(), anyString(), anyBoolean())).thenReturn(CLOSE_JOB_RESPONSE);
+
+ JobInfo jobInfo = bulkAPI.closeJob(STR_JOB_ID);
+ assertNotNull(jobInfo.getId());
+ assertEquals(STR_JOB_ID, jobInfo.getId());
+ assertEquals(WaveAPIConstants.STR_CLOSED, jobInfo.getState());
+ }
+
+ @Test
+ public void testIsCompleted() throws Exception {
+ assertTrue(bulkAPI.isCompleted(STR_JOB_ID));
+ }
+
+ @Test
+ public void testGetBatchInfoList() throws Exception {
+ BatchInfoList batchInfoList = bulkAPI.getBatchInfoList(STR_JOB_ID);
+ assertNotNull(batchInfoList);
+
+ List batchInfos = batchInfoList.getBatchInfo();
+ assertNotNull(batchInfos);
+ assertTrue(!batchInfos.isEmpty());
+ assertEquals(1, batchInfos.size());
+
+ BatchInfo batchInfo = batchInfos.get(0);
+ assertEquals(STR_BATCH_ID, batchInfo.getId());
+ assertEquals(STR_JOB_ID, batchInfo.getJobId());
+ }
+
+ @Test
+ public void testGetBatchInfo() throws Exception {
+ BatchInfo batchInfo = bulkAPI.getBatchInfo(STR_JOB_ID, STR_BATCH_ID);
+ assertNotNull(batchInfo);
+ assertEquals(STR_BATCH_ID, batchInfo.getId());
+ assertEquals(STR_JOB_ID, batchInfo.getJobId());
+ }
}
diff --git a/src/test/java/com/springml/salesforce/wave/api/ChatterAPITest.java b/src/test/java/com/springml/salesforce/wave/api/ChatterAPITest.java
index 24cd521..67617dc 100644
--- a/src/test/java/com/springml/salesforce/wave/api/ChatterAPITest.java
+++ b/src/test/java/com/springml/salesforce/wave/api/ChatterAPITest.java
@@ -1,7 +1,24 @@
+/*
+ * Copyright 2015 - 2017, salesforce-wave-api, springml
+ * Contributors :
+ * Samual Alexander, springml
+ *
+ * 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.springml.salesforce.wave.api;
import static org.junit.Assert.*;
-import static org.mockito.Matchers.*;
+import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import java.io.InputStream;
diff --git a/src/test/java/com/springml/salesforce/wave/api/ForceAPITest.java b/src/test/java/com/springml/salesforce/wave/api/ForceAPITest.java
index a960fff..221310e 100644
--- a/src/test/java/com/springml/salesforce/wave/api/ForceAPITest.java
+++ b/src/test/java/com/springml/salesforce/wave/api/ForceAPITest.java
@@ -1,3 +1,21 @@
+/*
+ * Copyright 2015 - 2017, salesforce-wave-api, springml
+ * Contributors :
+ * Samual Alexander, springml
+ *
+ * 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.springml.salesforce.wave.api;
import static com.springml.salesforce.wave.util.WaveAPIConstants.*;
@@ -13,6 +31,7 @@
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
+import org.mockito.ArgumentMatchers;
import com.springml.salesforce.wave.impl.ForceAPIImpl;
import com.springml.salesforce.wave.model.AddTaskRequest;
@@ -22,6 +41,7 @@
import com.springml.salesforce.wave.util.HTTPHelper;
public class ForceAPITest extends BaseAPITest {
+ private static final String SOQL2 = "select name, id,Model__c, Buyer_Name__c , buy_price__C from Opportunity where buy_price__C > 1000";
private static final String SOQL = "SELECT AccountId, Id, ProposalID__c FROM Opportunity where ProposalID__c != null";
private static final String QUERY_MORE_SOQL = "SELECT Id, OwnerId, Name, Player_Id__c, Phone__c FROM player__c";
private static final String RESPONSE_JSON = "{\"totalSize\":4,\"done\":true,\"records\":[{\"attributes\":{\"type\":\"Opportunity\",\"url\":\"/services/data/v34.0/sobjects/Opportunity/006B0000002ndnuIAA\"},\"AccountId\":\"001B0000003oYAfIAM\",\"Id\":\"006B0000002ndnuIAA\",\"ProposalID__c\":\"103\"},{\"attributes\":{\"type\":\"Opportunity\",\"url\":\"/services/data/v34.0/sobjects/Opportunity/006B0000002ndnpIAA\"},\"AccountId\":\"001B0000003oYAfIAM\",\"Id\":\"006B0000002ndnpIAA\",\"ProposalID__c\":\"102\"}]}";
@@ -35,24 +55,24 @@ public void setup() throws Exception {
when(sfConfig.getRequestURI(conn, SERVICE_PATH_QUERY, queryParam.toString())).thenCallRealMethod();
httpHelper = mock(HTTPHelper.class);
- when(httpHelper.get(any(URI.class), any(String.class), any(Integer.class))).thenReturn(RESPONSE_JSON);
+ when(httpHelper.get((URI) ArgumentMatchers.isNull(), (String) ArgumentMatchers.isNull(), any(Integer.class))).thenReturn(RESPONSE_JSON);
}
@Test
- @Ignore("This can be only executed with actual salesforce username and password")
+ // @Ignore("This can be only executed with actual salesforce username and password")
public void testQueryWithoutMock() throws Exception {
- ForceAPI forceAPI = APIFactory.getInstance().forceAPI("xxx@xxx.com",
- "***", "https://login.salesforce.com");
+ ForceAPI forceAPI = APIFactory.getInstance().forceAPI("james@ooequipment.com",
+ "oolong200molbX310CHFjJHR8djRKpiB1", "https://login.salesforce.com");
- SOQLResult result = forceAPI.query(SOQL);
+ SOQLResult result = forceAPI.query(SOQL2);
System.out.println("result : " + result);
System.out.println("records : " + result.getRecords());
System.out.println("records size : " + result.getRecords().size());
List