View Javadoc

1   /*
2    * Copyright (C) 2012 Atlassian
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package com.atlassian.jira.rest.client.internal.async;
17  
18  import com.atlassian.event.api.EventPublisher;
19  import com.atlassian.httpclient.apache.httpcomponents.DefaultHttpClientFactory;
20  import com.atlassian.httpclient.api.HttpClient;
21  import com.atlassian.httpclient.api.factory.HttpClientOptions;
22  import com.atlassian.jira.rest.client.api.AuthenticationHandler;
23  import com.atlassian.sal.api.ApplicationProperties;
24  import com.atlassian.sal.api.UrlMode;
25  import com.atlassian.sal.api.executor.ThreadLocalContextManager;
26  import org.slf4j.Logger;
27  import org.slf4j.LoggerFactory;
28  
29  import javax.annotation.Nonnull;
30  import java.io.File;
31  import java.io.IOException;
32  import java.io.InputStream;
33  import java.net.URI;
34  import java.util.Date;
35  import java.util.Properties;
36  
37  /**
38   * Factory for asynchronous http clients.
39   *
40   * @since v2.0
41   */
42  public class AsynchronousHttpClientFactory {
43  
44      @SuppressWarnings("unchecked")
45      public DisposableHttpClient createClient(final URI serverUri, final AuthenticationHandler authenticationHandler) {
46          final HttpClientOptions options = new HttpClientOptions();
47  
48          final DefaultHttpClientFactory defaultHttpClientFactory = new DefaultHttpClientFactory(new NoOpEventPublisher(),
49                  new RestClientApplicationProperties(serverUri),
50                  new ThreadLocalContextManager() {
51                      @Override
52                      public Object getThreadLocalContext() {
53                          return null;
54                      }
55  
56                      @Override
57                      public void setThreadLocalContext(Object context) {
58                      }
59  
60                      @Override
61                      public void clearThreadLocalContext() {
62                      }
63                  });
64  
65          final HttpClient httpClient = defaultHttpClientFactory.create(options);
66  
67          return new AtlassianHttpClientDecorator(httpClient, authenticationHandler) {
68              @Override
69              public void destroy() throws Exception {
70                  defaultHttpClientFactory.dispose(httpClient);
71              }
72          };
73      }
74  
75      public DisposableHttpClient createClient(final HttpClient client) {
76          return new AtlassianHttpClientDecorator(client, null) {
77  
78              @Override
79              public void destroy() throws Exception {
80                  // This should never be implemented. This is simply creation of a wrapper
81                  // for AtlassianHttpClient which is extended by a destroy method.
82                  // Destroy method should never be called for AtlassianHttpClient coming from
83                  // a client! Imagine you create a RestClient, pass your own HttpClient there
84                  // and it gets destroy.
85              }
86          };
87      }
88  
89      private static class NoOpEventPublisher implements EventPublisher {
90          @Override
91          public void publish(Object o) {
92          }
93  
94          @Override
95          public void register(Object o) {
96          }
97  
98          @Override
99          public void unregister(Object o) {
100         }
101 
102         @Override
103         public void unregisterAll() {
104         }
105     }
106 
107     /**
108      * These properties are used to present JRJC as a User-Agent during http requests.
109      */
110     @SuppressWarnings("deprecation")
111     private static class RestClientApplicationProperties implements ApplicationProperties {
112 
113         private final String baseUrl;
114 
115         private RestClientApplicationProperties(URI jiraURI) {
116             this.baseUrl = jiraURI.getPath();
117         }
118 
119         @Override
120         public String getBaseUrl() {
121             return baseUrl;
122         }
123 
124         /**
125          * We'll always have an absolute URL as a client.
126          */
127         @Nonnull
128         @Override
129         public String getBaseUrl(UrlMode urlMode) {
130             return baseUrl;
131         }
132 
133         @Nonnull
134         @Override
135         public String getDisplayName() {
136             return "Atlassian JIRA Rest Java Client";
137         }
138 
139         @Nonnull
140         @Override
141         public String getPlatformId() {
142             return ApplicationProperties.PLATFORM_JIRA;
143         }
144 
145         @Nonnull
146         @Override
147         public String getVersion() {
148             return MavenUtils.getVersion("com.atlassian.jira", "jira-rest-java-com.atlassian.jira.rest.client");
149         }
150 
151         @Nonnull
152         @Override
153         public Date getBuildDate() {
154             // TODO implement using MavenUtils, JRJC-123
155             throw new UnsupportedOperationException();
156         }
157 
158         @Nonnull
159         @Override
160         public String getBuildNumber() {
161             // TODO implement using MavenUtils, JRJC-123
162             return String.valueOf(0);
163         }
164 
165         @Override
166         public File getHomeDirectory() {
167             return new File(".");
168         }
169 
170         @Override
171         public String getPropertyValue(final String s) {
172             throw new UnsupportedOperationException("Not implemented");
173         }
174     }
175 
176     private static final class MavenUtils {
177         private static final Logger logger = LoggerFactory.getLogger(MavenUtils.class);
178 
179         private static final String UNKNOWN_VERSION = "unknown";
180 
181         static String getVersion(String groupId, String artifactId) {
182             final Properties props = new Properties();
183             InputStream resourceAsStream = null;
184             try {
185                 resourceAsStream = MavenUtils.class.getResourceAsStream(String
186                         .format("/META-INF/maven/%s/%s/pom.properties", groupId, artifactId));
187                 props.load(resourceAsStream);
188                 return props.getProperty("version", UNKNOWN_VERSION);
189             } catch (Exception e) {
190                 logger.debug("Could not find version for maven artifact {}:{}", groupId, artifactId);
191                 logger.debug("Got the following exception", e);
192                 return UNKNOWN_VERSION;
193             } finally {
194                 if (resourceAsStream != null) {
195                     try {
196                         resourceAsStream.close();
197                     } catch (IOException ioe) {
198                         // ignore
199                     }
200                 }
201             }
202         }
203     }
204 
205 }