mirror of https://github.com/apache/jclouds.git
added support for ning http client
This commit is contained in:
parent
5d68b3e820
commit
6c26047e6a
|
@ -353,7 +353,7 @@ public abstract class BaseJettyTest {
|
|||
protected boolean redirectEveryTwentyRequests(HttpServletRequest request,
|
||||
HttpServletResponse response) throws IOException {
|
||||
if (cycle.incrementAndGet() % 20 == 0) {
|
||||
response.sendRedirect("http://localhost:" + (testPort + 1));
|
||||
response.sendRedirect("http://localhost:" + (testPort + 1) + "/");
|
||||
((Request) request).setHandled(true);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
# use glob syntax.
|
||||
syntax: glob
|
||||
target
|
||||
.settings
|
||||
.classpath
|
||||
.project
|
||||
jclouds-apachehc.iml
|
||||
jclouds-apachehc.ipr
|
||||
jclouds-apachehc.iws
|
|
@ -0,0 +1,54 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
|
||||
Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
|
||||
====================================================================
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
====================================================================
|
||||
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>jclouds-extensions-project</artifactId>
|
||||
<groupId>org.jclouds</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>jclouds-ning</artifactId>
|
||||
<name>jclouds Ning Http Client</name>
|
||||
<packaging>jar</packaging>
|
||||
<description>Ning Http client</description>
|
||||
|
||||
<scm>
|
||||
<connection>scm:svn:http://jclouds.googlecode.com/svn/trunk</connection>
|
||||
<developerConnection>scm:svn:https://jclouds.googlecode.com/svn/trunk</developerConnection>
|
||||
<url>http://jclouds.googlecode.com/svn/trunk</url>
|
||||
</scm>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.ning</groupId>
|
||||
<artifactId>async-http-client</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mortbay.jetty</groupId>
|
||||
<artifactId>jetty</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,215 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
|
||||
package org.jclouds.http.ning;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.inject.Singleton;
|
||||
import javax.ws.rs.HttpMethod;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import com.google.common.io.Closeables;
|
||||
import com.google.common.util.concurrent.AbstractFuture;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.ning.http.client.*;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import com.ning.http.collection.Pair;
|
||||
import org.jclouds.http.*;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import org.jclouds.http.handlers.DelegatingErrorHandler;
|
||||
import org.jclouds.http.handlers.DelegatingRetryHandler;
|
||||
import org.jclouds.http.payloads.ByteArrayPayload;
|
||||
import org.jclouds.http.payloads.FilePayload;
|
||||
import org.jclouds.http.payloads.InputStreamPayload;
|
||||
import org.jclouds.http.payloads.StringPayload;
|
||||
import org.jclouds.util.Utils;
|
||||
|
||||
/**
|
||||
* Todo Write me
|
||||
*
|
||||
* @author Sam Tunnicliffe
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class NingHttpCommandExecutorService implements HttpCommandExecutorService {
|
||||
|
||||
public static final String USER_AGENT = "jclouds/1.0 ning http/1.0.0";
|
||||
|
||||
private final AsyncHttpClient client;
|
||||
private final ConvertToNingRequest convertToNingRequest;
|
||||
private final ConvertToJCloudsResponse convertToJCloudsResponse;
|
||||
private final DelegatingRetryHandler retryHandler;
|
||||
private final DelegatingErrorHandler errorHandler;
|
||||
|
||||
@Inject
|
||||
public NingHttpCommandExecutorService(AsyncHttpClient client,
|
||||
ConvertToNingRequest convertToNingRequest,
|
||||
ConvertToJCloudsResponse convertToJCloudsResponse,
|
||||
DelegatingRetryHandler retryHandler,
|
||||
DelegatingErrorHandler errorHandler) {
|
||||
this.client = client;
|
||||
this.convertToNingRequest = convertToNingRequest;
|
||||
this.convertToJCloudsResponse = convertToJCloudsResponse;
|
||||
this.retryHandler = retryHandler;
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<HttpResponse> submit(HttpCommand command) {
|
||||
try {
|
||||
for(;;) {
|
||||
Future<Response> responseF = client.executeRequest(convertToNingRequest.apply(command.getRequest()));
|
||||
final HttpResponse httpResponse = convertToJCloudsResponse.apply(responseF.get());
|
||||
int statusCode = httpResponse.getStatusCode();
|
||||
if (statusCode >= 300) {
|
||||
if (retryHandler.shouldRetryRequest(command, httpResponse)) {
|
||||
continue;
|
||||
} else {
|
||||
errorHandler.handleError(command, httpResponse);
|
||||
return wrapAsFuture(httpResponse);
|
||||
}
|
||||
} else {
|
||||
return wrapAsFuture(httpResponse);
|
||||
}
|
||||
}
|
||||
|
||||
} catch(IOException e) {
|
||||
throw Throwables.propagate(e);
|
||||
} catch(InterruptedException e) {
|
||||
throw Throwables.propagate(e);
|
||||
} catch(ExecutionException e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
}
|
||||
|
||||
private ListenableFuture<HttpResponse> wrapAsFuture(final HttpResponse httpResponse) {
|
||||
return Futures.makeListenable(new AbstractFuture<HttpResponse>() {
|
||||
@Override
|
||||
public HttpResponse get() throws InterruptedException, ExecutionException {
|
||||
return httpResponse;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Singleton
|
||||
public static class ConvertToNingRequest implements Function<HttpRequest, Request> {
|
||||
|
||||
public Request apply(HttpRequest request) {
|
||||
|
||||
for (HttpRequestFilter filter : request.getFilters()) {
|
||||
filter.filter(request);
|
||||
}
|
||||
|
||||
AsyncHttpClient client = new AsyncHttpClient();
|
||||
AsyncHttpClient.BoundRequestBuilder nativeRequestBuilder;
|
||||
String endpoint = request.getEndpoint().toASCIIString();
|
||||
|
||||
if (request.getMethod().equals(HttpMethod.HEAD)) {
|
||||
nativeRequestBuilder = client.prepareHead(endpoint);
|
||||
} else if (request.getMethod().equals(HttpMethod.GET)) {
|
||||
nativeRequestBuilder = client.prepareGet(endpoint);
|
||||
} else if (request.getMethod().equals(HttpMethod.DELETE)) {
|
||||
nativeRequestBuilder = client.prepareDelete(endpoint);
|
||||
} else if (request.getMethod().equals(HttpMethod.PUT)) {
|
||||
nativeRequestBuilder = client.preparePut(endpoint);
|
||||
} else if (request.getMethod().equals(HttpMethod.POST)) {
|
||||
nativeRequestBuilder = client.preparePost(endpoint);
|
||||
} else {
|
||||
throw new UnsupportedOperationException(request.getMethod());
|
||||
}
|
||||
Payload payload = request.getPayload();
|
||||
if(payload != null) {
|
||||
//changeRequestContentToBytes(request);
|
||||
setPayload(nativeRequestBuilder, payload);
|
||||
} else {
|
||||
nativeRequestBuilder.addHeader(HttpHeaders.CONTENT_LENGTH, "0");
|
||||
}
|
||||
|
||||
nativeRequestBuilder.addHeader(HttpHeaders.USER_AGENT, USER_AGENT);
|
||||
for (String header : request.getHeaders().keySet()) {
|
||||
for (String value : request.getHeaders().get(header)) {
|
||||
nativeRequestBuilder.addHeader(header, value);
|
||||
}
|
||||
}
|
||||
|
||||
return nativeRequestBuilder.build();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void changeRequestContentToBytes(HttpRequest request) {
|
||||
Payload content = request.getPayload();
|
||||
if (content == null || content instanceof ByteArrayPayload) {
|
||||
//just return
|
||||
} else if (content instanceof StringPayload) {
|
||||
String string = ((StringPayload) content).getRawContent();
|
||||
request.setPayload(string.getBytes());
|
||||
} else if (content instanceof InputStreamPayload || content instanceof FilePayload) {
|
||||
InputStream i = content.getContent();
|
||||
try {
|
||||
try {
|
||||
request.setPayload(ByteStreams.toByteArray(i));
|
||||
} catch (IOException e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
} finally {
|
||||
Closeables.closeQuietly(i);
|
||||
}
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Content not supported " + content.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
void setPayload(AsyncHttpClient.BoundRequestBuilder requestBuilder, Payload payload) {
|
||||
try {
|
||||
requestBuilder.setBody(ByteStreams.toByteArray(payload.getContent()));
|
||||
} catch(IOException e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Singleton
|
||||
public static class ConvertToJCloudsResponse implements Function<Response, HttpResponse> {
|
||||
public HttpResponse apply(Response nativeResponse) {
|
||||
HttpResponse response = new HttpResponse();
|
||||
response.setStatusCode(nativeResponse.getStatusCode());
|
||||
for (Pair<String, String> header : nativeResponse.getHeaders()) {
|
||||
response.getHeaders().put(header.getFirst(), header.getSecond());
|
||||
}
|
||||
try {
|
||||
String responseBody = nativeResponse.getResponseBody();
|
||||
if(responseBody != null) {
|
||||
response.setContent(Utils.toInputStream(responseBody));
|
||||
}
|
||||
} catch(IOException e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,151 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.http.ning.config;
|
||||
|
||||
import com.google.inject.Provides;
|
||||
import com.ning.http.client.AsyncHttpClient;
|
||||
import com.ning.http.client.AsyncHttpClientConfig;
|
||||
import org.jclouds.http.HttpCommandExecutorService;
|
||||
import org.jclouds.http.TransformingHttpCommandExecutorService;
|
||||
import org.jclouds.http.TransformingHttpCommandExecutorServiceImpl;
|
||||
import org.jclouds.http.ning.NingHttpCommandExecutorService;
|
||||
import org.jclouds.http.config.ConfiguresHttpCommandExecutorService;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Scopes;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
/**
|
||||
* Configures {@link NingHttpCommandExecutorService}.
|
||||
*
|
||||
* Note that this uses threads
|
||||
*
|
||||
* @author Sam Tunnicliffe
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@ConfiguresHttpCommandExecutorService
|
||||
public class NingHttpCommandExecutorServiceModule extends AbstractModule {
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
bindClient();
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
AsyncHttpClient provideNingClient() {
|
||||
AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().
|
||||
setFollowRedirects(true).
|
||||
build();
|
||||
return new AsyncHttpClient(config);
|
||||
}
|
||||
//
|
||||
// @Singleton
|
||||
// @Provides
|
||||
// HttpParams newBasicHttpParams(HttpUtils utils) {
|
||||
// BasicHttpParams params = new BasicHttpParams();
|
||||
//
|
||||
// params.setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024)
|
||||
// .setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, true)
|
||||
// .setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true).setParameter(
|
||||
// CoreProtocolPNames.ORIGIN_SERVER, "jclouds/1.0");
|
||||
//
|
||||
// if (utils.getConnectionTimeout() > 0) {
|
||||
// params.setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, utils
|
||||
// .getConnectionTimeout());
|
||||
// }
|
||||
//
|
||||
// if (utils.getSocketOpenTimeout() > 0) {
|
||||
// params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, utils.getSocketOpenTimeout());
|
||||
// }
|
||||
//
|
||||
// if (utils.getMaxConnections() > 0)
|
||||
// ConnManagerParams.setMaxTotalConnections(params, utils.getMaxConnections());
|
||||
//
|
||||
// if (utils.getMaxConnectionsPerHost() > 0) {
|
||||
// ConnPerRoute connectionsPerRoute = new ConnPerRouteBean(utils.getMaxConnectionsPerHost());
|
||||
// ConnManagerParams.setMaxConnectionsPerRoute(params, connectionsPerRoute);
|
||||
// }
|
||||
// HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
|
||||
// return params;
|
||||
// }
|
||||
//
|
||||
// @Singleton
|
||||
// @Provides
|
||||
// X509HostnameVerifier newHostnameVerifier(HttpUtils utils) {
|
||||
// return utils.relaxHostname() ? SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER
|
||||
// : SSLSocketFactory.STRICT_HOSTNAME_VERIFIER;
|
||||
// }
|
||||
//
|
||||
// @Singleton
|
||||
// @Provides
|
||||
// ClientConnectionManager newClientConnectionManager(HttpParams params,
|
||||
// X509HostnameVerifier verifier, Closer closer) throws NoSuchAlgorithmException,
|
||||
// KeyManagementException {
|
||||
//
|
||||
// SchemeRegistry schemeRegistry = new SchemeRegistry();
|
||||
//
|
||||
// Scheme http = new Scheme("http", PlainSocketFactory.getSocketFactory(), 80);
|
||||
// SSLContext context = SSLContext.getInstance("TLS");
|
||||
//
|
||||
// context.init(null, null, null);
|
||||
// SSLSocketFactory sf = new SSLSocketFactory(context);
|
||||
// sf.setHostnameVerifier(verifier);
|
||||
//
|
||||
// Scheme https = new Scheme("https", sf, 443);
|
||||
//
|
||||
// SchemeRegistry sr = new SchemeRegistry();
|
||||
// sr.register(http);
|
||||
// sr.register(https);
|
||||
//
|
||||
// schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
|
||||
// schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
|
||||
// final ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
|
||||
// closer.addToClose(new Closeable() {
|
||||
// @Override
|
||||
// public void close() throws IOException {
|
||||
// cm.shutdown();
|
||||
// }
|
||||
// });
|
||||
// return cm;
|
||||
// }
|
||||
//
|
||||
// @Provides
|
||||
// @Singleton
|
||||
// HttpClient newDefaultHttpClient(HttpUtils utils, BasicHttpParams params,
|
||||
// ClientConnectionManager cm) {
|
||||
// DefaultHttpClient client = new DefaultHttpClient(cm, params);
|
||||
// if (utils.useSystemProxies()) {
|
||||
// ProxySelectorRoutePlanner routePlanner = new ProxySelectorRoutePlanner(client
|
||||
// .getConnectionManager().getSchemeRegistry(), ProxySelector.getDefault());
|
||||
// client.setRoutePlanner(routePlanner);
|
||||
// }
|
||||
// return client;
|
||||
// }
|
||||
|
||||
protected void bindClient() {
|
||||
bind(HttpCommandExecutorService.class).to(NingHttpCommandExecutorService.class).in(
|
||||
Scopes.SINGLETON);
|
||||
|
||||
bind(TransformingHttpCommandExecutorService.class).to(
|
||||
TransformingHttpCommandExecutorServiceImpl.class).in(Scopes.SINGLETON);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.http.ning;
|
||||
|
||||
import static org.jclouds.Constants.PROPERTY_IO_WORKER_THREADS;
|
||||
import static org.jclouds.Constants.*;
|
||||
import static org.jclouds.Constants.PROPERTY_MAX_CONNECTIONS_PER_HOST;
|
||||
import static org.jclouds.Constants.PROPERTY_USER_THREADS;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import org.jclouds.http.BaseHttpCommandExecutorServiceIntegrationTest;
|
||||
import org.jclouds.http.ning.config.NingHttpCommandExecutorServiceModule;
|
||||
import org.jclouds.http.options.GetOptions;
|
||||
import org.testng.annotations.BeforeTest;
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.inject.Module;
|
||||
|
||||
/**
|
||||
* Tests the functionality of the {@link ApacheHCHttpCommandExecutorService}
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test
|
||||
public class NingHttpCommandExecutorServiceTest extends BaseHttpCommandExecutorServiceIntegrationTest {
|
||||
static {
|
||||
System.setProperty("http.conn-manager.timeout", 1000 + "");
|
||||
}
|
||||
|
||||
protected Module createConnectionModule() {
|
||||
return new NingHttpCommandExecutorServiceModule();
|
||||
}
|
||||
|
||||
protected void addConnectionProperties(Properties props) {
|
||||
props.setProperty(PROPERTY_MAX_CONNECTIONS_PER_CONTEXT, 20 + "");
|
||||
props.setProperty(PROPERTY_MAX_CONNECTIONS_PER_HOST, 0 + "");
|
||||
props.setProperty(PROPERTY_CONNECTION_TIMEOUT, 100 + "");
|
||||
props.setProperty(PROPERTY_SO_TIMEOUT, 100 + "");
|
||||
props.setProperty(PROPERTY_IO_WORKER_THREADS, 3 + "");
|
||||
props.setProperty(PROPERTY_USER_THREADS, 0 + "");
|
||||
}
|
||||
|
||||
@Test(invocationCount = 1, timeOut = 50000)
|
||||
public void testSpaceInUri() throws MalformedURLException, ExecutionException,
|
||||
InterruptedException, TimeoutException {
|
||||
assertEquals(client.synch("sp ace").trim(), XML);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testGetBigFile() throws MalformedURLException, ExecutionException, InterruptedException, TimeoutException {
|
||||
//don't run it
|
||||
}
|
||||
}
|
|
@ -99,6 +99,10 @@
|
|||
<id>clojars.org</id>
|
||||
<url>http://clojars.org/repo</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>ning.http.client</id>
|
||||
<url>http://oss.sonatype.org/service/local/repositories/snapshots/content</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<distributionManagement>
|
||||
|
|
Loading…
Reference in New Issue