Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,13 @@
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.openstack4j.api.exceptions.ConnectionException;
import org.openstack4j.core.transport.HttpMethod;
import org.openstack4j.core.transport.HttpRequest;
import org.openstack4j.core.transport.ObjectMapperSingleton;
import org.openstack4j.core.transport.functions.EndpointURIFromRequestFunction;
import org.openstack4j.openstack.common.FileEntity;

import com.google.common.net.MediaType;

/**
* HttpCommand is responsible for executing the actual request driven by the
Expand Down Expand Up @@ -89,10 +93,15 @@ public CloseableHttpResponse execute() throws Exception {
EntityBuilder builder = null;

if (request.getEntity() != null) {
if (InputStream.class.isAssignableFrom(request.getEntity().getClass())) {
InputStreamEntity ise = new InputStreamEntity((InputStream) request.getEntity(),
ContentType.create(request.getContentType()));
((HttpEntityEnclosingRequestBase) clientReq).setEntity(ise);
if (request.getFileUploadProgressListener() != null && request.getMethod() == HttpMethod.PUT
&& request.getPath().startsWith("/images/") && request.getPath().endsWith("/file")) {
FileEntity fe = new FileEntity((InputStream) request.getEntity(), request.getContentType(),
request.getBufferSize(), request.getFileUploadProgressListener());
((HttpEntityEnclosingRequestBase) clientReq).setEntity(fe);
} else if (InputStream.class.isAssignableFrom(request.getEntity().getClass())) {
InputStreamEntity ise = new InputStreamEntity((InputStream) request.getEntity(),
ContentType.create(request.getContentType()));
((HttpEntityEnclosingRequestBase) clientReq).setEntity(ise);
} else {
builder = EntityBuilder.create().setContentType(ContentType.create(request.getContentType(), "UTF-8"))
.setText(ObjectMapperSingleton.getContext(request.getEntity().getClass()).writer()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,16 @@
import org.openstack4j.model.common.Payload;
import org.openstack4j.model.common.Payloads;
import org.openstack4j.model.image.v2.*;
import org.openstack4j.openstack.image.v2.domain.GlanceImage;
import org.testng.annotations.Test;

import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;

import org.openstack4j.openstack.common.FileUploadProgressListener;

/**
* @author emjburns
*/
Expand Down Expand Up @@ -249,7 +252,14 @@ public void UploadImage() throws IOException {
String imageId = "4b434528-032b-4467-946c-b5880ce15c06";
InputStream s = new ByteArrayInputStream(BINARY_IMAGE_DATA.getBytes(StandardCharsets.UTF_8));
Payload<InputStream> payload = Payloads.create(s);
ActionResponse upload = osv3().imagesV2().upload(imageId, payload, null);
org.openstack4j.model.image.v2.Image image = new GlanceImage();
image.setId(imageId);

int imageSize = BINARY_IMAGE_DATA.getBytes(StandardCharsets.UTF_8).length;
assertTrue(imageSize > 0);
FileUploadProgressListener listener = new ImageUploadProgressListener(imageId, imageSize);

ActionResponse upload = osv3().imagesV2().upload(imageId, payload, image, 4096, listener);
assertTrue(upload.isSuccess());
}

Expand All @@ -272,4 +282,30 @@ public void DownloadImage() throws IOException {
protected Service service() {
return Service.IMAGE;
}

public class ImageUploadProgressListener implements FileUploadProgressListener
{
private long totalByte;
private String imageId;

public ImageUploadProgressListener(String imageId,
long totalByte)
{
this.imageId = imageId;
this.totalByte = totalByte;
}

@Override
public void updateTransferedByte(long transferedByte)
{
assertEquals(imageId, "4b434528-032b-4467-946c-b5880ce15c06");
assertTrue(transferedByte <= totalByte);
}

@Override
public long getFileSize()
{
return totalByte;
}
}
}
6 changes: 6 additions & 0 deletions core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,12 @@
<artifactId>testng</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.12</version>
</dependency>
</dependencies>
<reporting>
<plugins>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.openstack4j.model.image.v2.Image;
import org.openstack4j.model.image.v2.ImageUpdate;
import org.openstack4j.model.image.v2.Member;
import org.openstack4j.openstack.common.FileUploadProgressListener;

/**
* OpenStack (Glance) Image V2 support
Expand Down Expand Up @@ -154,6 +155,9 @@ public interface ImageService extends RestService {
* Uploads binary image data
*/
ActionResponse upload(String imageId, Payload<?> payload, @Nullable Image image);

ActionResponse upload(String imageId, Payload<?> payload, @Nullable Image image, int bufferSize,
FileUploadProgressListener listener);

/**
* Downloads binary image data
Expand Down
29 changes: 29 additions & 0 deletions core/src/main/java/org/openstack4j/core/transport/HttpRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import org.openstack4j.core.transport.functions.EndpointURIFromRequestFunction;
import org.openstack4j.model.ModelEntity;
import org.openstack4j.model.common.Payload;
import org.openstack4j.openstack.common.FileUploadProgressListener;

/**
* A Request Delegate which aids in building the request that is compatible with the OpenStack Rest API. The request is used to encoding as well as keeping reference to
Expand All @@ -34,6 +35,8 @@ public class HttpRequest<R> {
String contentType = ClientConstants.CONTENT_TYPE_JSON;
HttpMethod method = HttpMethod.GET;
String json;
private FileUploadProgressListener fileUploadProgressListener;
private int bufferSize;
private Config config;
private Map<String, List<Object>> queryParams;
private Function<String, String> endpointFunc;
Expand Down Expand Up @@ -175,7 +178,23 @@ public RequestBuilder<R> toBuilder() {
public Config getConfig() {
return config != null ? config: Config.DEFAULT;
}

public void setFileUploadProgressListener(FileUploadProgressListener fileUploadProgressListener) {
this.fileUploadProgressListener = fileUploadProgressListener;
}

public FileUploadProgressListener getFileUploadProgressListener() {
return this.fileUploadProgressListener;
}

public void setBufferSize(int bufferSize) {
this.bufferSize = bufferSize;
}

public int getBufferSize() {
return this.bufferSize;
}

/**
* Append query parameters into the url.
*/
Expand Down Expand Up @@ -344,6 +363,16 @@ public RequestBuilder<R> header(String name, Object value) {
return this;
}

public RequestBuilder<R> fileUploadProgressListener(FileUploadProgressListener fileUploadProgressListener) {
request.setFileUploadProgressListener(fileUploadProgressListener);
return this;
}

public RequestBuilder<R> bufferSize(int bufferSize) {
request.setBufferSize(bufferSize);
return this;
}

/**
* The endpoint Service Type
*
Expand Down
119 changes: 119 additions & 0 deletions core/src/main/java/org/openstack4j/openstack/common/FileEntity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package org.openstack4j.openstack.common;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.apache.http.entity.AbstractHttpEntity;

/**
* TODO add description.
*
* <p>
* Class responsibility:
* </p>
*/

public class FileEntity extends AbstractHttpEntity implements Cloneable
{
protected InputStream is;
private FileUploadProgressListener listener;
private long transferredByte;
private int bufferSize;

private final long SLEEP_TIME = 3;

public FileEntity(InputStream is, String contentType, int bufferSize, FileUploadProgressListener listener)
{
super();
if (is == null)
{
throw new IllegalArgumentException("File may not be null");
}
this.is = is;
this.transferredByte = 0;
this.listener = listener;

if (bufferSize <= 0)
{
// 1MB
bufferSize = 1048576;
} else
{
this.bufferSize = bufferSize;
}

setContentType(contentType);
}

public boolean isRepeatable()
{
return true;
}

public long getContentLength()
{
if (listener != null)
{
return listener.getFileSize();
}

try
{
if (is instanceof FileInputStream)
{
return ((FileInputStream) is).getChannel().size();
}
} catch (IOException e)
{
return 0;
}
return 0;
}

public InputStream getContent() throws IOException
{
return is;
}

public void writeTo(final OutputStream outstream) throws IOException
{
if (outstream == null)
{
throw new IllegalArgumentException("Output stream may not be null");
}

try
{
byte[] buffer = new byte[bufferSize];
int w;
while ((w = is.read(buffer)) != -1)
{
outstream.write(buffer, 0, w);
this.transferredByte += w;
listener.updateTransferedByte(transferredByte);
Thread.sleep(SLEEP_TIME);
}
outstream.flush();
} catch (InterruptedException e)
{
throw new RuntimeException(e.getMessage());
// throw e;
} finally
{
is.close();
}
}

public boolean isStreaming()
{
return false;
}

@Override
public Object clone() throws CloneNotSupportedException
{
return super.clone();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.openstack4j.openstack.common;

public interface FileUploadProgressListener
{
void updateTransferedByte(long transferedByte);

long getFileSize();
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.openstack4j.model.image.v2.Image;
import org.openstack4j.model.image.v2.ImageUpdate;
import org.openstack4j.model.image.v2.Member;
import org.openstack4j.openstack.common.FileUploadProgressListener;
import org.openstack4j.openstack.image.v2.domain.CachedGlanceImage.CachedImages;
import org.openstack4j.openstack.image.v2.domain.GlanceImage;
import org.openstack4j.openstack.image.v2.domain.GlanceImageUpdate;
Expand Down Expand Up @@ -161,6 +162,20 @@ public ActionResponse upload(String imageId, Payload<?> payload, @Nullable Image
checkNotNull(payload);
return put(ActionResponse.class, uri("/images/%s/file", imageId)).header(HEADER_CONTENT_TYPE, CONTENT_TYPE_OCTECT_STREAM).entity(payload).execute();
}

/**
* {@inheritDoc}
*/
@Override
public ActionResponse upload(String imageId, Payload<?> payload, @Nullable Image image, int bufferSize,
FileUploadProgressListener listener)
{
checkNotNull(imageId);
checkNotNull(payload);
return put(ActionResponse.class, uri("/images/%s/file", imageId))
.header(HEADER_CONTENT_TYPE, CONTENT_TYPE_OCTECT_STREAM).entity(payload)
.fileUploadProgressListener(listener).bufferSize(bufferSize).execute();
}

/**
* {@inheritDoc}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import org.openstack4j.model.identity.AuthVersion;
import org.openstack4j.model.identity.v2.Access;
import org.openstack4j.model.identity.v3.Service;
import org.openstack4j.openstack.common.FileUploadProgressListener;

import static org.openstack4j.core.transport.ClientConstants.HEADER_USER_AGENT;
import static org.openstack4j.core.transport.ClientConstants.USER_AGENT;
Expand Down Expand Up @@ -229,6 +230,18 @@ public Invocation<R> headers(Map<String, ?> headers) {
return this;
}

public Invocation<R> fileUploadProgressListener(FileUploadProgressListener fileUploadProgressListener)
{
req.fileUploadProgressListener(fileUploadProgressListener);
return this;
}

public Invocation<R> bufferSize(int bufferSize)
{
req.bufferSize(bufferSize);
return this;
}

public Invocation<R> header(String name, Object value) {
req.header(name, value);
return this;
Expand Down