Skip to content

Commit 0e64cea

Browse files
authored
Merge pull request #1 from Crim/sp/refactor
Sp/refactor
2 parents 693d6e9 + c9898e1 commit 0e64cea

File tree

51 files changed

+1222
-864
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1222
-864
lines changed

src/main/java/com/darksci/pardot/api/Configuration.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ public class Configuration {
1010
private final String password;
1111
private final String userKey;
1212

13+
/**
14+
* Optionally you can re-use an existing known good api key.
15+
*/
16+
private String apiKey = null;
17+
1318
// Optional Proxy Configuration
1419
private String proxyHost = null;
1520
private int proxyPort = 0;
@@ -107,6 +112,14 @@ public void setPardotApiVersion(final String pardotApiVersion) {
107112
this.pardotApiVersion = pardotApiVersion;
108113
}
109114

115+
public String getApiKey() {
116+
return apiKey;
117+
}
118+
119+
public void setApiKey(final String apiKey) {
120+
this.apiKey = apiKey;
121+
}
122+
110123
@Override
111124
public String toString() {
112125
final StringBuilder stringBuilder = new StringBuilder("Configuration{")
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.darksci.pardot.api;
2+
3+
/**
4+
* Represents when a request is invalid.
5+
*/
6+
public class InvalidRequestException extends RuntimeException {
7+
private final int errorCode;
8+
9+
public InvalidRequestException(final String message, final int errorCode) {
10+
super(message);
11+
this.errorCode = errorCode;
12+
}
13+
14+
public InvalidRequestException(final String message, final Throwable cause) {
15+
super(message, cause);
16+
this.errorCode = -1;
17+
}
18+
}
Lines changed: 282 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,291 @@
11
package com.darksci.pardot.api;
22

3+
import com.darksci.pardot.api.parser.ErrorResponseParser;
4+
import com.darksci.pardot.api.parser.ResponseParser;
5+
import com.darksci.pardot.api.parser.account.AccountReadResponseParser;
6+
import com.darksci.pardot.api.parser.campaign.CampaignQueryResponseParser;
7+
import com.darksci.pardot.api.parser.campaign.CampaignReadResponseParser;
8+
import com.darksci.pardot.api.parser.email.EmailReadResponseParser;
9+
import com.darksci.pardot.api.parser.email.EmailStatsResponseParser;
10+
import com.darksci.pardot.api.parser.login.LoginResponseParser;
11+
import com.darksci.pardot.api.parser.user.UserAbilitiesParser;
12+
import com.darksci.pardot.api.parser.user.UserQueryResponseParser;
13+
import com.darksci.pardot.api.parser.user.UserReadResponseParser;
14+
import com.darksci.pardot.api.request.Request;
15+
import com.darksci.pardot.api.request.account.AccountReadRequest;
16+
import com.darksci.pardot.api.request.campaign.CampaignCreateRequest;
17+
import com.darksci.pardot.api.request.campaign.CampaignQueryRequest;
18+
import com.darksci.pardot.api.request.campaign.CampaignReadRequest;
19+
import com.darksci.pardot.api.request.campaign.CampaignUpdateRequest;
20+
import com.darksci.pardot.api.request.email.EmailReadRequest;
21+
import com.darksci.pardot.api.request.email.EmailSendListRequest;
22+
import com.darksci.pardot.api.request.email.EmailSendOneToOneRequest;
23+
import com.darksci.pardot.api.request.email.EmailStatsRequest;
24+
import com.darksci.pardot.api.request.login.LoginRequest;
25+
import com.darksci.pardot.api.request.user.UserAbilitiesRequest;
26+
import com.darksci.pardot.api.request.user.UserQueryRequest;
27+
import com.darksci.pardot.api.request.user.UserReadRequest;
28+
import com.darksci.pardot.api.response.ErrorResponse;
29+
import com.darksci.pardot.api.response.account.Account;
30+
import com.darksci.pardot.api.response.campaign.Campaign;
31+
import com.darksci.pardot.api.response.campaign.CampaignQueryResponse;
32+
import com.darksci.pardot.api.response.email.Email;
33+
import com.darksci.pardot.api.response.email.EmailStatsResponse;
34+
import com.darksci.pardot.api.response.login.LoginResponse;
35+
import com.darksci.pardot.api.response.user.User;
36+
import com.darksci.pardot.api.response.user.UserAbilitiesResponse;
37+
import com.darksci.pardot.api.response.user.UserQueryResponse;
38+
import com.darksci.pardot.api.rest.HttpClientRestClient;
39+
import com.darksci.pardot.api.rest.RestClient;
40+
import com.darksci.pardot.api.rest.RestResponse;
341
import org.slf4j.Logger;
442
import org.slf4j.LoggerFactory;
543

44+
import java.io.IOException;
45+
646
/**
7-
* WIP.
47+
* Interface for Pardot's API.
848
*/
949
public class PardotClient {
1050
private static final Logger logger = LoggerFactory.getLogger(PardotClient.class);
11-
}
51+
52+
/**
53+
* Our API Configuration.
54+
*/
55+
private final Configuration configuration;
56+
57+
/**
58+
* Underlying RestClient to use.
59+
*/
60+
private final RestClient restClient;
61+
62+
/**
63+
* Internal State flag.
64+
*/
65+
private boolean isInitialized = false;
66+
67+
/**
68+
* Default Constructor.
69+
* @param configuration Pardot Api Configuration.
70+
*/
71+
public PardotClient(final Configuration configuration) {
72+
this.configuration = configuration;
73+
this.restClient = new HttpClientRestClient();
74+
}
75+
76+
/**
77+
* Constructor for injecting a RestClient implementation.
78+
* Typically only used in testing.
79+
* @param configuration Pardot Api Configuration.
80+
* @param restClient RestClient implementation to use.
81+
*/
82+
public PardotClient(final Configuration configuration, final RestClient restClient) {
83+
this.configuration = configuration;
84+
this.restClient = restClient;
85+
}
86+
87+
private <T> T submitRequest(final Request request, ResponseParser<T> responseParser) throws IOException {
88+
// Ugly hack,
89+
// avoid doing login check if we're doing a login request.
90+
if (!(request instanceof LoginRequest)) {
91+
// Check for auth token
92+
checkLogin();
93+
}
94+
95+
// Submit request
96+
final RestResponse restResponse = getRestClient().submitRequest(request);
97+
98+
// If we have a valid response
99+
logger.info("Response: {}", restResponse);
100+
101+
// Check for invalid http status codes
102+
if (restResponse.getHttpCode() >= 200 && restResponse.getHttpCode() < 300) {
103+
// High level check for error response
104+
if (restResponse.getResponseStr().contains("<rsp stat=\"fail\"")) {
105+
// Parse error response
106+
final ErrorResponse error = new ErrorResponseParser().parseResponse(restResponse.getResponseStr());
107+
108+
// throw exception
109+
throw new InvalidRequestException(error.getMessage(), error.getCode());
110+
}
111+
return responseParser.parseResponse(restResponse.getResponseStr());
112+
}
113+
// Otherwise throw an exception.
114+
throw new InvalidRequestException("Invalid http response code from server: " + restResponse.getHttpCode(), restResponse.getHttpCode());
115+
}
116+
117+
/**
118+
* @return Return Pardot API Configuration.
119+
*/
120+
public Configuration getConfiguration() {
121+
return configuration;
122+
}
123+
124+
/**
125+
* Package protected for access in tests.
126+
* @return Rest Client.
127+
*/
128+
RestClient getRestClient() {
129+
// If we haven't initialized.
130+
if (!isInitialized) {
131+
// Call Init.
132+
restClient.init(getConfiguration());
133+
134+
// Flip state flag
135+
isInitialized = true;
136+
}
137+
138+
// return our rest client.
139+
return restClient;
140+
}
141+
142+
/**
143+
* Check to see if we're already logged in and have an API key.
144+
* If no existing API key is found, this will attempt to authenticate and
145+
* get a new API key.
146+
*/
147+
private void checkLogin() throws IOException {
148+
if (configuration.getApiKey() != null) {
149+
return;
150+
}
151+
// Otherwise attempt to authenticate.
152+
final LoginResponse response = login(new LoginRequest()
153+
.withEmail(configuration.getEmail())
154+
.withPassword(configuration.getPassword())
155+
);
156+
157+
// If we have an API key.
158+
if (response.getApiKey() != null) {
159+
// Set it.
160+
getConfiguration().setApiKey(response.getApiKey());
161+
}
162+
}
163+
164+
/**
165+
* Make login request
166+
* @return LoginResponse returned from server.
167+
*/
168+
public LoginResponse login(LoginRequest request) throws IOException {
169+
return submitRequest(request, new LoginResponseParser());
170+
}
171+
172+
/**
173+
* Make API request to read the account of the currently authenticated user.
174+
* @param request Request definition.
175+
* @return Parsed api response.
176+
* @throws IOException on parse errors.
177+
*/
178+
public Account accountRead(final AccountReadRequest request) throws IOException {
179+
return submitRequest(request, new AccountReadResponseParser());
180+
}
181+
182+
/**
183+
* Make API request to query one or more users.
184+
* @param request Request definition.
185+
* @return Parsed user query response.
186+
* @throws IOException on parse errors.
187+
*/
188+
public UserQueryResponse.Result userQuery(final UserQueryRequest request) throws IOException {
189+
return submitRequest(request, new UserQueryResponseParser());
190+
}
191+
192+
/**
193+
* Make API request to read the abilities of the currently authenticated user.
194+
* @param request Request definition.
195+
* @return Parsed api response.
196+
* @throws IOException on parse errors.
197+
*/
198+
public UserAbilitiesResponse.Result userAbilities(final UserAbilitiesRequest request) throws IOException {
199+
return submitRequest(request, new UserAbilitiesParser());
200+
}
201+
202+
/**
203+
* Make API request to read a specific user.
204+
* @param request Request definition.
205+
* @return Parsed api response.
206+
* @throws IOException on parse errors.
207+
*/
208+
public User userRead(final UserReadRequest request) throws IOException {
209+
return submitRequest(request, new UserReadResponseParser());
210+
}
211+
212+
/**
213+
* Make API request to query for one or more campaigns.
214+
* @param request Request definition.
215+
* @return Parsed api response.
216+
* @throws IOException on parse errors.
217+
*/
218+
public CampaignQueryResponse.Result campaignQuery(final CampaignQueryRequest request) throws IOException {
219+
return submitRequest(request, new CampaignQueryResponseParser());
220+
}
221+
222+
/**
223+
* Make API request to read a specific campaign.
224+
* @param request Request definition.
225+
* @return Parsed api response.
226+
* @throws IOException on parse errors.
227+
*/
228+
public Campaign campaignRead(final CampaignReadRequest request) throws IOException {
229+
return submitRequest(request, new CampaignReadResponseParser());
230+
}
231+
232+
/**
233+
* Make API request to create a new Campaign.
234+
* @param request Request definition.
235+
* @return Parsed api response.
236+
* @throws IOException on parse errors.
237+
*/
238+
public Campaign campaignCreate(final CampaignCreateRequest request) throws IOException {
239+
return submitRequest(request, new CampaignReadResponseParser());
240+
}
241+
242+
/**
243+
* Make API request to update an existing Campaign.
244+
* @param request Request definition.
245+
* @return Parsed api response.
246+
* @throws IOException on parse errors.
247+
*/
248+
public Campaign campaignUpdate(final CampaignUpdateRequest request) throws IOException {
249+
return submitRequest(request, new CampaignReadResponseParser());
250+
}
251+
252+
/**
253+
* Make API request to read a specific Email.
254+
* @param request Request definition.
255+
* @return Parsed api response.
256+
* @throws IOException on parse errors.
257+
*/
258+
public Email emailRead(final EmailReadRequest request) throws IOException {
259+
return submitRequest(request, new EmailReadResponseParser());
260+
}
261+
262+
/**
263+
* Make API request to retrieve stats about a List Email Send.
264+
* @param request Request definition.
265+
* @return Parsed api response.
266+
* @throws IOException on parse errors.
267+
*/
268+
public EmailStatsResponse.Stats emailStats(final EmailStatsRequest request) throws IOException {
269+
return submitRequest(request, new EmailStatsResponseParser());
270+
}
271+
272+
/**
273+
* Make API request to send a 1-to-1 prospect email.
274+
* @param request Request definition.
275+
* @return Parsed api response.
276+
* @throws IOException on parse errors.
277+
*/
278+
public Email emailSendOneToOne(final EmailSendOneToOneRequest request) throws IOException {
279+
return submitRequest(request, new EmailReadResponseParser());
280+
}
281+
282+
/**
283+
* Make API request to send a list email.
284+
* @param request Request definition.
285+
* @return Parsed api response.
286+
* @throws IOException on parse errors.
287+
*/
288+
public Email emailSendList(final EmailSendListRequest request) throws IOException {
289+
return submitRequest(request, new EmailReadResponseParser());
290+
}
291+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.darksci.pardot.api.parser;
2+
3+
import com.darksci.pardot.api.response.ErrorResponse;
4+
5+
import java.io.IOException;
6+
7+
/**
8+
* Parses Error Responses.
9+
*/
10+
public class ErrorResponseParser implements ResponseParser<ErrorResponse> {
11+
12+
/**
13+
* Parses response.
14+
* @param responseStr String representation.
15+
* @return Parsed response.
16+
*/
17+
public ErrorResponse parseResponse(final String responseStr) throws IOException {
18+
return JacksonFactory
19+
.newInstance()
20+
.readValue(responseStr, ErrorResponse.class);
21+
}
22+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.darksci.pardot.api.parser;
2+
3+
import com.fasterxml.jackson.databind.DeserializationFeature;
4+
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
5+
import com.fasterxml.jackson.dataformat.xml.JacksonXmlModule;
6+
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
7+
import com.fasterxml.jackson.datatype.joda.JodaModule;
8+
9+
import java.text.SimpleDateFormat;
10+
11+
/**
12+
* Creates properly configured Jackson XML Mapper instances.
13+
*/
14+
public class JacksonFactory {
15+
16+
/**
17+
* Creates properly configured Jackson XML Mapper instances.
18+
* @return XmlMapper instance.
19+
*/
20+
public static XmlMapper newInstance() {
21+
// Create new mapper
22+
final JacksonXmlModule module = new JacksonXmlModule();
23+
module.setDefaultUseWrapper(false);
24+
XmlMapper mapper = new XmlMapper(module);
25+
26+
// Configure it
27+
mapper
28+
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
29+
.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE)
30+
.registerModule(new JodaModule())
31+
.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
32+
33+
return mapper;
34+
}
35+
}

0 commit comments

Comments
 (0)