Commit 1d7db5f915d99f1842ce2e9d0f6e4d133954c7a5

Authored by bernard
1 parent f211190c

Safer URI building.

  1 +package pl.com.it_crowd.youtrack.api;
  2 +
  3 +import java.net.URI;
  4 +import java.net.URISyntaxException;
  5 +
  6 +public class URIUtils {
  7 +// -------------------------- STATIC METHODS --------------------------
  8 +
  9 + public static URI buildURI(URI base, String path)
  10 + {
  11 + return buildURI(base, path, null);
  12 + }
  13 +
  14 + public static URI buildURI(URI base, String path, String query)
  15 + {
  16 + try {
  17 + return new URI(base.getScheme(), base.getHost(), base.getPath().replaceAll("/+$", "") + path, query, null);
  18 + } catch (URISyntaxException e) {
  19 + throw new RuntimeException(e);
  20 + }
  21 + }
  22 +}
1 package pl.com.it_crowd.youtrack.api; 1 package pl.com.it_crowd.youtrack.api;
2 2
  3 +import org.apache.commons.logging.Log;
  4 +import org.apache.commons.logging.LogFactory;
3 import org.apache.http.Header; 5 import org.apache.http.Header;
4 import org.apache.http.HttpEntity; 6 import org.apache.http.HttpEntity;
5 import org.apache.http.HttpHeaders; 7 import org.apache.http.HttpHeaders;
@@ -17,7 +19,6 @@ import org.apache.http.client.methods.HttpGet; @@ -17,7 +19,6 @@ import org.apache.http.client.methods.HttpGet;
17 import org.apache.http.client.methods.HttpPost; 19 import org.apache.http.client.methods.HttpPost;
18 import org.apache.http.client.methods.HttpPut; 20 import org.apache.http.client.methods.HttpPut;
19 import org.apache.http.client.methods.HttpUriRequest; 21 import org.apache.http.client.methods.HttpUriRequest;
20 -import org.apache.http.client.utils.URIBuilder;  
21 import org.apache.http.conn.ClientConnectionManager; 22 import org.apache.http.conn.ClientConnectionManager;
22 import org.apache.http.conn.scheme.Scheme; 23 import org.apache.http.conn.scheme.Scheme;
23 import org.apache.http.conn.scheme.SchemeRegistry; 24 import org.apache.http.conn.scheme.SchemeRegistry;
@@ -60,6 +61,8 @@ import java.util.List; @@ -60,6 +61,8 @@ import java.util.List;
60 import java.util.regex.Matcher; 61 import java.util.regex.Matcher;
61 import java.util.regex.Pattern; 62 import java.util.regex.Pattern;
62 63
  64 +import static pl.com.it_crowd.youtrack.api.URIUtils.buildURI;
  65 +
63 public class YoutrackAPI { 66 public class YoutrackAPI {
64 // ------------------------------ FIELDS ------------------------------ 67 // ------------------------------ FIELDS ------------------------------
65 68
@@ -67,10 +70,14 @@ public class YoutrackAPI { @@ -67,10 +70,14 @@ public class YoutrackAPI {
67 70
68 private final static QName Issue_QNAME = new QName("", "issue"); 71 private final static QName Issue_QNAME = new QName("", "issue");
69 72
  73 + private static Log LOG = LogFactory.getLog(YoutrackAPI.class);
  74 +
70 private HttpClient httpClient; 75 private HttpClient httpClient;
71 76
72 private String serviceLocation; 77 private String serviceLocation;
73 78
  79 + private URI serviceLocationURI;
  80 +
74 // -------------------------- STATIC METHODS -------------------------- 81 // -------------------------- STATIC METHODS --------------------------
75 82
76 private static HttpClient getDefaultHttpClient() 83 private static HttpClient getDefaultHttpClient()
@@ -134,7 +141,15 @@ public class YoutrackAPI { @@ -134,7 +141,15 @@ public class YoutrackAPI {
134 141
135 public YoutrackAPI(String serviceLocation, HttpClient httpClient) 142 public YoutrackAPI(String serviceLocation, HttpClient httpClient)
136 { 143 {
  144 + if (serviceLocation == null) {
  145 + throw new IllegalArgumentException("serviceLocation cannot be null");
  146 + }
137 this.serviceLocation = serviceLocation; 147 this.serviceLocation = serviceLocation;
  148 + try {
  149 + serviceLocationURI = new URI(this.serviceLocation);
  150 + } catch (URISyntaxException e) {
  151 + throw new RuntimeException(e);
  152 + }
138 this.httpClient = httpClient == null ? getDefaultHttpClient() : httpClient; 153 this.httpClient = httpClient == null ? getDefaultHttpClient() : httpClient;
139 } 154 }
140 155
@@ -170,7 +185,7 @@ public class YoutrackAPI { @@ -170,7 +185,7 @@ public class YoutrackAPI {
170 185
171 public void command(String issueId, String command, String comment, String group, Boolean disableNotifications, String runAs) throws IOException 186 public void command(String issueId, String command, String comment, String group, Boolean disableNotifications, String runAs) throws IOException
172 { 187 {
173 - final HttpPost request = new HttpPost(serviceLocation + "/rest/issue/" + issueId + "/execute"); 188 + final HttpPost request = new HttpPost(buildURI(serviceLocationURI, "/rest/issue/" + issueId + "/execute"));
174 final List<BasicNameValuePair> parameters = new ArrayList<BasicNameValuePair>(); 189 final List<BasicNameValuePair> parameters = new ArrayList<BasicNameValuePair>();
175 parameters.add(new BasicNameValuePair("command", command)); 190 parameters.add(new BasicNameValuePair("command", command));
176 if (!isBlank(comment)) { 191 if (!isBlank(comment)) {
@@ -202,14 +217,8 @@ public class YoutrackAPI { @@ -202,14 +217,8 @@ public class YoutrackAPI {
202 */ 217 */
203 public String createIssue(String project, String summary, String description) throws IOException 218 public String createIssue(String project, String summary, String description) throws IOException
204 { 219 {
205 - final URI uri;  
206 - try {  
207 - uri = new URIBuilder(serviceLocation + "/rest/issue").build();  
208 - } catch (URISyntaxException e) {  
209 - throw new RuntimeException(e);  
210 - }  
211 - final HttpPut request = createPutRequest(uri, new BasicNameValuePair("project", project), new BasicNameValuePair("summary", summary),  
212 - new BasicNameValuePair("description", description)); 220 + final HttpPut request = createPutRequest(buildURI(serviceLocationURI, "/rest/issue"), new BasicNameValuePair("project", project),
  221 + new BasicNameValuePair("summary", summary), new BasicNameValuePair("description", description));
213 final HttpResponse response = httpClient.execute(request); 222 final HttpResponse response = httpClient.execute(request);
214 final StatusLine statusLine = response.getStatusLine(); 223 final StatusLine statusLine = response.getStatusLine();
215 final HttpEntity entity = response.getEntity(); 224 final HttpEntity entity = response.getEntity();
@@ -230,24 +239,12 @@ public class YoutrackAPI { @@ -230,24 +239,12 @@ public class YoutrackAPI {
230 239
231 public void deleteIssue(String issueId) throws IOException 240 public void deleteIssue(String issueId) throws IOException
232 { 241 {
233 - final URI uri;  
234 - try {  
235 - uri = new URIBuilder(serviceLocation + "/rest/issue/" + issueId).build();  
236 - } catch (URISyntaxException e) {  
237 - throw new RuntimeException(e);  
238 - }  
239 - execute(new HttpDelete(uri)); 242 + execute(new HttpDelete(buildURI(serviceLocationURI, "/rest/issue/" + issueId)));
240 } 243 }
241 244
242 public AssigneeList getAssignees(String project) throws IOException, JAXBException 245 public AssigneeList getAssignees(String project) throws IOException, JAXBException
243 { 246 {
244 - final URI uri;  
245 - try {  
246 - uri = new URIBuilder(serviceLocation + "/rest/admin/project/" + project + "/assignee").build();  
247 - } catch (URISyntaxException e) {  
248 - throw new RuntimeException(e);  
249 - }  
250 - final String responseString = execute(new HttpGet(uri)); 247 + final String responseString = execute(new HttpGet(buildURI(serviceLocationURI, "/rest/admin/project/" + project + "/assignee")));
251 final Object result = YoutrackUnmarshaller.unmarshall(responseString); 248 final Object result = YoutrackUnmarshaller.unmarshall(responseString);
252 if (result instanceof AssigneeList) { 249 if (result instanceof AssigneeList) {
253 return (AssigneeList) result; 250 return (AssigneeList) result;
@@ -258,13 +255,7 @@ public class YoutrackAPI { @@ -258,13 +255,7 @@ public class YoutrackAPI {
258 255
259 public Enumeration getBundle(String customField) throws IOException, JAXBException 256 public Enumeration getBundle(String customField) throws IOException, JAXBException
260 { 257 {
261 - final URI uri;  
262 - try {  
263 - uri = new URIBuilder(serviceLocation + "/rest/admin/customfield/bundle/" + customField).build();  
264 - } catch (URISyntaxException e) {  
265 - throw new RuntimeException(e);  
266 - }  
267 - final Object result = YoutrackUnmarshaller.unmarshall(execute(new HttpGet(uri))); 258 + final Object result = YoutrackUnmarshaller.unmarshall(execute(new HttpGet(buildURI(serviceLocationURI, "/rest/admin/customfield/bundle/" + customField))));
268 if (result instanceof Enumeration) { 259 if (result instanceof Enumeration) {
269 return (Enumeration) result; 260 return (Enumeration) result;
270 } else if (result instanceof JAXBElement) { 261 } else if (result instanceof JAXBElement) {
@@ -281,13 +272,7 @@ public class YoutrackAPI { @@ -281,13 +272,7 @@ public class YoutrackAPI {
281 272
282 public List<User> getIndividualAssignees(String project) throws IOException, JAXBException 273 public List<User> getIndividualAssignees(String project) throws IOException, JAXBException
283 { 274 {
284 - final URI uri;  
285 - try {  
286 - uri = new URIBuilder(serviceLocation + "/rest/admin/project/" + project + "/assignee/individual").build();  
287 - } catch (URISyntaxException e) {  
288 - throw new RuntimeException(e);  
289 - }  
290 - final String responseString = execute(new HttpGet(uri)); 275 + final String responseString = execute(new HttpGet(buildURI(serviceLocationURI, "/rest/admin/project/" + project + "/assignee/individual")));
291 final Object result = YoutrackUnmarshaller.unmarshall(responseString); 276 final Object result = YoutrackUnmarshaller.unmarshall(responseString);
292 if (result instanceof UserRefs) { 277 if (result instanceof UserRefs) {
293 return ((UserRefs) result).getUsers(); 278 return ((UserRefs) result).getUsers();
@@ -298,15 +283,9 @@ public class YoutrackAPI { @@ -298,15 +283,9 @@ public class YoutrackAPI {
298 283
299 public IssueWrapper getIssue(String issueId) throws IOException, JAXBException 284 public IssueWrapper getIssue(String issueId) throws IOException, JAXBException
300 { 285 {
301 - final URI uri;  
302 - try {  
303 - uri = new URIBuilder(serviceLocation + "/rest/issue/" + issueId).build();  
304 - } catch (URISyntaxException e) {  
305 - throw new RuntimeException(e);  
306 - }  
307 final String responseString; 286 final String responseString;
308 try { 287 try {
309 - responseString = execute(new HttpGet(uri)); 288 + responseString = execute(new HttpGet(buildURI(serviceLocationURI, "/rest/issue/" + issueId)));
310 } catch (YoutrackErrorException e) { 289 } catch (YoutrackErrorException e) {
311 if (e.getStatusCode() == HttpStatus.SC_NOT_FOUND) { 290 if (e.getStatusCode() == HttpStatus.SC_NOT_FOUND) {
312 throw new NoResultFoundException(e.getMessage(), e); 291 throw new NoResultFoundException(e.getMessage(), e);
@@ -331,15 +310,15 @@ public class YoutrackAPI { @@ -331,15 +310,15 @@ public class YoutrackAPI {
331 310
332 public void login(String username, String password) throws IOException, JAXBException 311 public void login(String username, String password) throws IOException, JAXBException
333 { 312 {
334 - final HttpPost request = new HttpPost(serviceLocation + "/rest/user/login"); 313 + final HttpPost request = new HttpPost(buildURI(serviceLocationURI, "/rest/user/login"));
335 request.setEntity(new UrlEncodedFormEntity(Arrays.asList(new BasicNameValuePair("login", username), new BasicNameValuePair("password", password)))); 314 request.setEntity(new UrlEncodedFormEntity(Arrays.asList(new BasicNameValuePair("login", username), new BasicNameValuePair("password", password))));
336 execute(request); 315 execute(request);
337 } 316 }
338 317
339 public List<IssueWrapper> searchIssuesByProject(String project, Object filter) throws JAXBException, IOException 318 public List<IssueWrapper> searchIssuesByProject(String project, Object filter) throws JAXBException, IOException
340 { 319 {
341 - final String url = serviceLocation + "/rest/issue/byproject/" + project + "?filter=" + (filter == null ? "" : filter);  
342 - final Object result = YoutrackUnmarshaller.unmarshall(execute(new HttpGet(url))); 320 + final Object result = YoutrackUnmarshaller.unmarshall(
  321 + execute(new HttpGet(buildURI(serviceLocationURI, "/rest/issue/byproject/" + project, "filter=" + (filter == null ? "" : filter)))));
343 if (!(result instanceof Issues)) { 322 if (!(result instanceof Issues)) {
344 throw new YoutrackAPIException("Unmarshalling problem. Expected Issues, received: " + result.getClass() + " " + result); 323 throw new YoutrackAPIException("Unmarshalling problem. Expected Issues, received: " + result.getClass() + " " + result);
345 } 324 }
@@ -353,13 +332,7 @@ public class YoutrackAPI { @@ -353,13 +332,7 @@ public class YoutrackAPI {
353 332
354 public void updateIssue(String issueId, String summary, String description) throws IOException 333 public void updateIssue(String issueId, String summary, String description) throws IOException
355 { 334 {
356 - final URI uri;  
357 - try {  
358 - uri = new URIBuilder(serviceLocation + "/rest/issue/" + issueId).build();  
359 - } catch (URISyntaxException e) {  
360 - throw new RuntimeException(e);  
361 - }  
362 - final HttpPost request = createPostRequest(uri, new BasicNameValuePair(Fields.summary.name(), summary), 335 + final HttpPost request = createPostRequest(buildURI(serviceLocationURI, "/rest/issue/" + issueId), new BasicNameValuePair(Fields.summary.name(), summary),
363 new BasicNameValuePair(Fields.description.name(), description)); 336 new BasicNameValuePair(Fields.description.name(), description));
364 final HttpResponse response = httpClient.execute(request); 337 final HttpResponse response = httpClient.execute(request);
365 final StatusLine statusLine = response.getStatusLine(); 338 final StatusLine statusLine = response.getStatusLine();
@@ -389,7 +362,7 @@ public class YoutrackAPI { @@ -389,7 +362,7 @@ public class YoutrackAPI {
389 final String error = ErrorUnmarshaller.unmarshal(responseText); 362 final String error = ErrorUnmarshaller.unmarshal(responseText);
390 throw new YoutrackErrorException(error, statusLine.getStatusCode()); 363 throw new YoutrackErrorException(error, statusLine.getStatusCode());
391 } catch (JAXBException e) { 364 } catch (JAXBException e) {
392 - // TODO we should log on debug level the JAXBException 365 + LOG.error("Cannot unmarshal following response text:\n" + responseText, e);
393 throw new HttpResponseException(statusLine.getStatusCode(), responseText); 366 throw new HttpResponseException(statusLine.getStatusCode(), responseText);
394 } 367 }
395 } 368 }
  1 +package pl.com.it_crowd.youtrack.api.rest;
  2 +
  3 +import org.junit.Test;
  4 +import pl.com.it_crowd.youtrack.api.Filter;
  5 +import pl.com.it_crowd.youtrack.api.URIUtils;
  6 +import pl.com.it_crowd.youtrack.api.defaults.StateValues;
  7 +
  8 +import java.net.URI;
  9 +import java.net.URISyntaxException;
  10 +
  11 +import static org.junit.Assert.assertEquals;
  12 +
  13 +public class URIUtilsTest {
  14 +// -------------------------- OTHER METHODS --------------------------
  15 +
  16 + @Test
  17 + public void buildURI() throws URISyntaxException
  18 + {
  19 +// Given
  20 + final URI base = new URI("http://localhost:8080/youtrack/");
  21 + final String pathA = "/rest/admin/bundle/QA note types";
  22 + final String queryA = "q=" + Filter.stateFilter(StateValues.NotWontFix).maxResults(20);
  23 +
  24 +// When
  25 + final URI uriA = URIUtils.buildURI(base, pathA);
  26 + final URI uriB = URIUtils.buildURI(base, pathA, queryA);
  27 +
  28 +// Then
  29 + assertEquals("http://localhost/youtrack/rest/admin/bundle/QA%20note%20types", uriA.toString());
  30 + assertEquals("http://localhost/youtrack/rest/admin/bundle/QA%20note%20types?q=state:-%257BWon%2527t+fix%257D&max=20", uriB.toString());
  31 + }
  32 +}
Please register or login to post a comment