feat(manager-api): add extended description and image to Api
MODIFY
gateway/engine/core/src/main/java/io/apiman/gateway/engine/impl/InMemoryRateLimiterComponent.java
gateway/engine/core/src/main/java/io/apiman/gateway/engine/impl/InMemoryRateLimiterComponent.java
@@ -47,6 +47,8 @@ public class InMemoryRateLimiterComponent implements IRateLimiterComponent {
@Override
public void accept(String bucketId, RateBucketPeriod period, long limit, long increment, IAsyncResultHandler<RateLimitResponse> handler) {
RateLimiterBucket bucket;
+ RateLimitResponse response = new RateLimitResponse();
+ int reset = 0;
synchronized (buckets) {
bucket = buckets.get(bucketId);
if (bucket == null) {
@@ -54,8 +56,6 @@ public class InMemoryRateLimiterComponent implements IRateLimiterComponent {
buckets.put(bucketId, bucket);
}
bucket.resetIfNecessary(period);
-
- RateLimitResponse response = new RateLimitResponse();
if (bucket.getCount() > limit) {
response.setAccepted(false);
} else {
@@ -63,11 +63,11 @@ public class InMemoryRateLimiterComponent implements IRateLimiterComponent {
bucket.setCount(bucket.getCount() + increment);
bucket.setLast(System.currentTimeMillis());
}
- int reset = (int) (bucket.getResetMillis(period) / 1000L);
+ reset = (int) (bucket.getResetMillis(period) / 1000L);
+ }
response.setReset(reset);
response.setRemaining(limit - bucket.getCount());
- handler.handle(AsyncResultImpl.<RateLimitResponse>create(response));
- }
+ handler.handle(AsyncResultImpl.create(response));
}
}

MODIFY
manager/api/beans/src/main/java/io/apiman/manager/api/beans/apis/NewApiBean.java
manager/api/beans/src/main/java/io/apiman/manager/api/beans/apis/NewApiBean.java
@@ -39,6 +39,7 @@ public class NewApiBean implements Serializable {
@JsonIgnore
@BlobReference
private String image;
+ private String extendedDescription;
private String initialVersion;
@@ -240,4 +241,13 @@ public class NewApiBean implements Serializable {
this.image = image;
return this;
}
+
+ public String getExtendedDescription() {
+ return extendedDescription;
+ }
+
+ public NewApiBean setExtendedDescription(String extendedDescription) {
+ this.extendedDescription = extendedDescription;
+ return this;
+ }
}

MODIFY
manager/api/beans/src/main/java/io/apiman/manager/api/beans/apis/NewApiVersionBean.java
manager/api/beans/src/main/java/io/apiman/manager/api/beans/apis/NewApiVersionBean.java
@@ -44,6 +44,7 @@ public class NewApiVersionBean implements Serializable {
private Set<ApiPlanBean> plans;
private String definitionUrl;
private ApiDefinitionType definitionType;
+ private String extendedDescription;
/**
* Constructor.
@@ -215,4 +216,12 @@ public class NewApiVersionBean implements Serializable {
*/
public void setDisableKeysStrip(Boolean disableKeysStrip) { this.disableKeysStrip = disableKeysStrip; }
+ public String getExtendedDescription() {
+ return extendedDescription;
+ }
+
+ public NewApiVersionBean setExtendedDescription(String extendedDescription) {
+ this.extendedDescription = extendedDescription;
+ return this;
+ }
}

MODIFY
manager/api/beans/src/main/java/io/apiman/manager/api/beans/apis/UpdateApiVersionBean.java
manager/api/beans/src/main/java/io/apiman/manager/api/beans/apis/UpdateApiVersionBean.java
@@ -43,6 +43,7 @@ public class UpdateApiVersionBean implements Serializable {
private Boolean publicAPI;
private Boolean disableKeysStrip;
private Set<ApiPlanBean> plans;
+ private String extendedDescription;
/**
* Constructor.
@@ -172,6 +173,15 @@ public class UpdateApiVersionBean implements Serializable {
*/
public void setDisableKeysStrip(Boolean disableKeysStrip) { this.disableKeysStrip = disableKeysStrip; }
+ public String getExtendedDescription() {
+ return extendedDescription;
+ }
+
+ public UpdateApiVersionBean setExtendedDescription(String extendedDescription) {
+ this.extendedDescription = extendedDescription;
+ return this;
+ }
+
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/

MODIFY
manager/api/beans/src/main/java/io/apiman/manager/api/beans/clients/ClientBean.java
manager/api/beans/src/main/java/io/apiman/manager/api/beans/clients/ClientBean.java
@@ -65,7 +65,7 @@ public class ClientBean implements Serializable, Cloneable {
private String name;
@Column(name = "image_file_ref", updatable = true, nullable = true) // Reference to file storage (we'll ship with DB blob)
@BlobReference
- private String imageFileRef;
+ private String image;
@Column(updatable=true, nullable=true, length=512)
private String description;
@Column(name = "created_by", updatable=false, nullable=false)
@@ -161,11 +161,11 @@ public class ClientBean implements Serializable, Cloneable {
}
public String getImage() {
- return imageFileRef;
+ return image;
}
- public ClientBean setImageFileRef(String imageFileRef) {
- this.imageFileRef = imageFileRef;
+ public ClientBean setImage(String image) {
+ this.image = image;
return this;
}

MODIFY
manager/api/beans/src/main/java/io/apiman/manager/api/beans/clients/NewClientBean.java
manager/api/beans/src/main/java/io/apiman/manager/api/beans/clients/NewClientBean.java
*/
package io.apiman.manager.api.beans.clients;
+import io.apiman.manager.api.beans.download.BlobReference;
+
import java.io.Serializable;
+import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
@@ -33,6 +36,9 @@ public class NewClientBean implements Serializable {
private String name;
private String description;
private String initialVersion;
+ @JsonIgnore
+ @BlobReference
+ private String image;
/**
* Constructor.
@@ -82,6 +88,15 @@ public class NewClientBean implements Serializable {
this.initialVersion = initialVersion;
}
+ public String getImage() {
+ return image;
+ }
+
+ public NewClientBean setImage(String image) {
+ this.image = image;
+ return this;
+ }
+
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/

MODIFY
manager/api/beans/src/main/java/io/apiman/manager/api/beans/clients/UpdateClientBean.java
manager/api/beans/src/main/java/io/apiman/manager/api/beans/clients/UpdateClientBean.java
*/
package io.apiman.manager.api.beans.clients;
+import io.apiman.manager.api.beans.download.BlobReference;
+
import java.io.Serializable;
+import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
@@ -31,6 +34,9 @@ public class UpdateClientBean implements Serializable {
private static final long serialVersionUID = 5549391329361400489L;
private String description;
+ @JsonIgnore
+ @BlobReference
+ private String image;
/**
* Constructor.
@@ -52,6 +58,15 @@ public class UpdateClientBean implements Serializable {
this.description = description;
}
+ public String getImage() {
+ return image;
+ }
+
+ public UpdateClientBean setImage(String image) {
+ this.image = image;
+ return this;
+ }
+
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/

MODIFY
manager/api/beans/src/main/java/io/apiman/manager/api/beans/summary/ApiVersionSummaryBean.java
manager/api/beans/src/main/java/io/apiman/manager/api/beans/summary/ApiVersionSummaryBean.java
@@ -34,6 +34,7 @@ public class ApiVersionSummaryBean implements Serializable {
private String id;
private String name;
private String description;
+ private String extendedDescription;
private ApiStatus status;
private String version;
private boolean publicAPI;
@@ -165,6 +166,24 @@ public class ApiVersionSummaryBean implements Serializable {
this.exposeInPortal = exposeInPortal;
}
+ public String getExtendedDescription() {
+ return extendedDescription;
+ }
+
+ public ApiVersionSummaryBean setExtendedDescription(String extendedDescription) {
+ this.extendedDescription = extendedDescription;
+ return this;
+ }
+
+ public boolean isExposeInPortal() {
+ return exposeInPortal;
+ }
+
+ public ApiVersionSummaryBean setExposeInPortal(boolean exposeInPortal) {
+ this.exposeInPortal = exposeInPortal;
+ return this;
+ }
+
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/

MODIFY
manager/api/beans/src/main/java/io/apiman/manager/api/beans/summary/ClientSummaryBean.java
manager/api/beans/src/main/java/io/apiman/manager/api/beans/summary/ClientSummaryBean.java
@@ -36,7 +36,7 @@ public class ClientSummaryBean implements Serializable {
private String organizationId;
private String organizationName;
@BlobReference
- private String imageFileRef;
+ private String image;
private String id;
private String name;
private String description;
@@ -139,12 +139,12 @@ public class ClientSummaryBean implements Serializable {
return serialVersionUID;
}
- public String getImageFileRef() {
- return imageFileRef;
+ public String getImage() {
+ return image;
}
public ClientSummaryBean setImage(String imageFileRef) {
- this.imageFileRef = imageFileRef;
+ this.image = imageFileRef;
return this;
}

MODIFY
manager/api/jpa/src/main/java/io/apiman/manager/api/jpa/JpaStorage.java
manager/api/jpa/src/main/java/io/apiman/manager/api/jpa/JpaStorage.java
@@ -1039,6 +1039,7 @@ public class JpaStorage extends AbstractJpaStorage implements IStorage, IStorage
summary.setName(bean.getName());
summary.setDescription(bean.getDescription());
summary.setCreatedOn(bean.getCreatedOn());
+ summary.setImage(bean.getImage());
OrganizationBean org = bean.getOrganization();
summary.setOrganizationId(org.getId());
summary.setOrganizationName(org.getName());
@@ -1141,6 +1142,7 @@ public class JpaStorage extends AbstractJpaStorage implements IStorage, IStorage
svsb.setStatus(apiVersion.getStatus());
svsb.setPublicAPI(apiVersion.isPublicAPI());
svsb.setExposeInPortal(apiVersion.isExposeInPortal());
+ svsb.setExtendedDescription(apiVersion.getExtendedDescription());
rval.add(svsb);
}
return rval;

MODIFY
manager/api/rest-impl/src/main/java/io/apiman/manager/api/rest/impl/OrganizationResourceImpl.java
manager/api/rest-impl/src/main/java/io/apiman/manager/api/rest/impl/OrganizationResourceImpl.java
@@ -253,6 +253,25 @@ public class OrganizationResourceImpl implements IOrganizationResource, DataAcce
return clientService.createClient(organizationId, bean);
}
+ @Override
+ public ClientBean createClient(String organizationId, MultipartFormDataInput multipartInput)
+ throws OrganizationNotFoundException, ClientAlreadyExistsException, NotAuthorizedException, InvalidNameException, IOException {
+ securityContext.checkPermissions(PermissionType.clientEdit, organizationId);
+
+ Preconditions.checkArgument(multipartInput.getParts().size() != 2, "Expected 'client' and 'image'");
+
+ // Try to do image first as it is probably more likely to fail.
+ MultipartUploadHolder image = MultipartHelper.getRequiredImage(multipartInput, "image");
+ String blobRef = blobStore.storeBlob(image.getFilename(), image.getMediaType().toString(), image.getFileBackedOutputStream());
+
+ // Simply convert to NewApiBean and store reference.
+ InputPart clientPart = MultipartHelper.getRequiredPart(multipartInput, "client", MediaType.APPLICATION_JSON_TYPE);
+ // TODO(msavy): probably better to have a separate DTO than for imageref @JsonIgnore?
+ NewClientBean clientBean = clientPart.getBody(NewClientBean.class, null);
+ clientBean.setImage(blobRef);
+ return clientService.createClient(organizationId, clientBean);
+ }
+
@Override
public ClientBean getClient(String organizationId, String clientId)
throws ClientNotFoundException, NotAuthorizedException {
@@ -269,6 +288,25 @@ public class OrganizationResourceImpl implements IOrganizationResource, DataAcce
clientService.updateClient(organizationId, clientId, bean);
}
+ @Override
+ public void updateClient(String organizationId, String clientId, MultipartFormDataInput multipartInput)
+ throws OrganizationNotFoundException, ClientAlreadyExistsException, NotAuthorizedException, InvalidNameException, IOException {
+ securityContext.checkPermissions(PermissionType.clientEdit, organizationId);
+
+ Preconditions.checkArgument(multipartInput.getParts().size() != 2, "Expected 'client' and 'image'");
+ // Try to do image first as it is probably more likely to fail.
+ MultipartUploadHolder image = MultipartHelper.getRequiredImage(multipartInput, "image");
+ String blobRef = blobStore.storeBlob(image.getFilename(), image.getMediaType().toString(), image.getFileBackedOutputStream());
+
+ InputPart clientPart = MultipartHelper.getRequiredPart(multipartInput, "client", MediaType.APPLICATION_JSON_TYPE);
+ UpdateClientBean bean = clientPart.getBody(UpdateClientBean.class, null);
+ bean.setImage(blobRef);
+
+ LOGGER.debug("Attempting to update client {0} in org {1} with {2}", clientId, organizationId, bean);
+ clientService.updateClient(organizationId, clientId, bean);
+ }
+
+
@Override
public void deleteClient(String organizationId, String clientId)
throws OrganizationNotFoundException, NotAuthorizedException, EntityStillActiveException {

MODIFY
manager/api/rest-impl/src/main/java/io/apiman/manager/api/rest/impl/util/MultipartHelper.java
manager/api/rest-impl/src/main/java/io/apiman/manager/api/rest/impl/util/MultipartHelper.java
@@ -11,6 +11,7 @@ import java.util.StringJoiner;
import javax.ws.rs.core.MediaType;
import com.google.common.io.FileBackedOutputStream;
+import org.apache.commons.io.IOUtils;
import org.jboss.resteasy.plugins.providers.multipart.InputPart;
import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput;
import org.jetbrains.annotations.NotNull;
@@ -73,16 +74,18 @@ public class MultipartHelper {
}
}
} catch (IOException ioe) {
+ IOUtils.closeQuietly(os);
throw new UncheckedIOException(ioe);
}
}
- public class MultipartUploadHolder {
- private String filename;
- private FileBackedOutputStream fileBackedOutputStream;
- private MediaType mediaType;
+ public static final class MultipartUploadHolder {
+ private final String filename;
+ private final FileBackedOutputStream fileBackedOutputStream;
+ private final MediaType mediaType;
- public MultipartUploadHolder(String filename, FileBackedOutputStream fileBackedOutputStream, MediaType mediaType) {
+ public MultipartUploadHolder(final String filename, final FileBackedOutputStream fileBackedOutputStream,
+ final MediaType mediaType) {
this.filename = filename;
this.fileBackedOutputStream = fileBackedOutputStream;
this.mediaType = mediaType;

MODIFY
manager/api/rest-impl/src/main/java/io/apiman/manager/api/rest/interceptors/BlobResourceInterceptorProvider.java
manager/api/rest-impl/src/main/java/io/apiman/manager/api/rest/interceptors/BlobResourceInterceptorProvider.java
@@ -69,14 +69,14 @@ public class BlobResourceInterceptorProvider implements WriterInterceptor {
for (Field blobRef : blobRefs) {
blobRef.setAccessible(true);
String existingValue = (String) blobRef.get(entity);
- if (existingValue != null) {
+ if (existingValue == null || existingValue.isBlank()) {
+ LOGGER.debug("Null or blank @BlobRef {0}@{1}", blobRef.getName(), entity.getClass().getCanonicalName());
+ } else {
String resolvedRef = UriBuilder.fromResource(IBlobResource.class).path(existingValue).build()
.toString();
LOGGER.debug("Rewriting response POJO field annotated with resolved @BlobReference: {0} -> {1}",
existingValue, resolvedRef);
blobRef.set(entity, resolvedRef);
- } else {
- LOGGER.debug("Null @BlobRef {0}@{1}", blobRef.getName(), entity.getClass().getCanonicalName());
}
}
}

MODIFY
manager/api/rest-impl/src/main/java/io/apiman/manager/api/service/ApiService.java
manager/api/rest-impl/src/main/java/io/apiman/manager/api/service/ApiService.java
@@ -167,7 +167,9 @@ public class ApiService implements DataAccessUtilMixin {
}
}
storage.deleteApi(api);
+ if (api.getImage() != null) {
blobStore.remove(api.getImage());
+ }
LOGGER.debug("Deleted API: {0}", api.getName()); //$NON-NLS-1$
});
}
@@ -210,6 +212,7 @@ public class ApiService implements DataAccessUtilMixin {
newApiVersion.setVersion(bean.getInitialVersion());
newApiVersion.setDefinitionUrl(bean.getDefinitionUrl());
newApiVersion.setDefinitionType(bean.getDefinitionType());
+ newApiVersion.setExtendedDescription(bean.getExtendedDescription());
createApiVersionInternal(newApiVersion, newApi, gateway);
}
@@ -294,8 +297,6 @@ public class ApiService implements DataAccessUtilMixin {
return createApiVersionInternal(bean, api, gateway);
});
- //storage.flush();
-
if (bean.isClone() && bean.getCloneVersion() != null) {
try {
ApiVersionBean cloneSource = getApiVersion(organizationId, apiId, bean.getCloneVersion());
@@ -324,10 +325,12 @@ public class ApiService implements DataAccessUtilMixin {
updatedApi.setPublicAPI(cloneSource.isPublicAPI());
}
if (bean.getParsePayload() == null) {
- updatedApi.setParsePayload(bean.getParsePayload());
+ updatedApi.setParsePayload(cloneSource.isParsePayload());
+ }
+ if (bean.getExtendedDescription() == null) {
+ updatedApi.setExtendedDescription(cloneSource.getExtendedDescription());
}
newVersion = updateApiVersion(newVersion, updatedApi);
- //storage.flush();
if (bean.getDefinitionUrl() == null) {
// Clone the API definition document
@@ -388,6 +391,7 @@ public class ApiService implements DataAccessUtilMixin {
newVersion.setEndpointType(bean.getEndpointType());
newVersion.setEndpointContentType(bean.getEndpointContentType());
newVersion.setDefinitionUrl(bean.getDefinitionUrl());
+ newVersion.setExtendedDescription(bean.getExtendedDescription());
if (bean.getPublicAPI() != null) {
newVersion.setPublicAPI(bean.getPublicAPI());
}

MODIFY
manager/api/rest-impl/src/main/java/io/apiman/manager/api/service/ClientAppService.java
manager/api/rest-impl/src/main/java/io/apiman/manager/api/service/ClientAppService.java
@@ -15,7 +15,6 @@ import io.apiman.manager.api.beans.clients.UpdateClientBean;
import io.apiman.manager.api.beans.contracts.NewContractBean;
import io.apiman.manager.api.beans.events.ApimanEventHeaders;
import io.apiman.manager.api.beans.events.ClientVersionStatusEvent;
-import io.apiman.manager.api.beans.idm.PermissionType;
import io.apiman.manager.api.beans.orgs.OrganizationBean;
import io.apiman.manager.api.beans.policies.NewPolicyBean;
import io.apiman.manager.api.beans.policies.PolicyBean;
@@ -29,6 +28,7 @@ import io.apiman.manager.api.beans.summary.ClientVersionSummaryBean;
import io.apiman.manager.api.beans.summary.ContractSummaryBean;
import io.apiman.manager.api.beans.summary.PolicySummaryBean;
import io.apiman.manager.api.core.IApiKeyGenerator;
+import io.apiman.manager.api.core.IBlobStore;
import io.apiman.manager.api.core.IStorage;
import io.apiman.manager.api.core.IStorageQuery;
import io.apiman.manager.api.core.exceptions.StorageException;
@@ -84,6 +84,7 @@ public class ClientAppService implements DataAccessUtilMixin {
private PolicyService policyService;
private IApiKeyGenerator apiKeyGenerator;
private EventService eventService;
+ private IBlobStore blobstore;
@Inject
public ClientAppService(
@@ -94,7 +95,8 @@ public class ClientAppService implements DataAccessUtilMixin {
ContractService contractService,
PolicyService policyService,
IApiKeyGenerator apiKeyGenerator,
- EventService eventService
+ EventService eventService,
+ IBlobStore blobstore
) {
this.storage = storage;
this.query = query;
@@ -104,6 +106,7 @@ public class ClientAppService implements DataAccessUtilMixin {
this.policyService = policyService;
this.apiKeyGenerator = apiKeyGenerator;
this.eventService = eventService;
+ this.blobstore = blobstore;
}
public ClientAppService() {
@@ -121,6 +124,7 @@ public class ClientAppService implements DataAccessUtilMixin {
newClient.setDescription(bean.getDescription());
newClient.setCreatedBy(securityContext.getCurrentUser());
newClient.setCreatedOn(new Date());
+ newClient.setImage(bean.getImage());
tryAction(() -> {
// Store/persist the new client
@@ -141,14 +145,14 @@ public class ClientAppService implements DataAccessUtilMixin {
}
});
- LOGGER.debug(String.format("Created client %s: %s", newClient.getName(), newClient)); //$NON-NLS-1$
+ LOGGER.debug("Created client {0}: {1}", newClient.getName(), newClient); //$NON-NLS-1$
return newClient;
}
public ClientBean getClient(String organizationId, String clientId)
throws ClientNotFoundException, NotAuthorizedException {
ClientBean clientBean = tryAction(() -> getClientFromStorage(organizationId, clientId));
- LOGGER.debug(String.format("Got client %s: %s", clientBean.getName(), clientBean)); //$NON-NLS-1$
+ LOGGER.debug("Got client {0}: {1}", clientBean.getName(), clientBean); //$NON-NLS-1$
return clientBean;
}
@@ -170,6 +174,9 @@ public class ClientAppService implements DataAccessUtilMixin {
}
storage.deleteClient(client);
+ if (client.getImage() != null) {
+ blobstore.remove(client.getImage());
+ }
LOGGER.debug("Deleted ClientApp: {0}", client.getName()); //$NON-NLS-1$
});
}
@@ -189,10 +196,14 @@ public class ClientAppService implements DataAccessUtilMixin {
auditData.addChange("description", clientForUpdate.getDescription(), bean.getDescription()); //$NON-NLS-1$
clientForUpdate.setDescription(bean.getDescription());
}
+ if (AuditUtils.valueChanged(clientForUpdate.getImage(), bean.getImage())) {
+ auditData.addChange("image", clientForUpdate.getImage(), bean.getImage()); //$NON-NLS-1$
+ clientForUpdate.setImage(bean.getImage());
+ }
storage.updateClient(clientForUpdate);
storage.createAuditEntry(AuditUtils.clientUpdated(clientForUpdate, auditData, securityContext));
- LOGGER.debug(String.format("Updated client %s: %s", clientForUpdate.getName(), clientForUpdate)); //$NON-NLS-1$
+ LOGGER.debug("Updated client {0}: {1}", clientForUpdate.getName(), clientForUpdate); //$NON-NLS-1$
});
}
@@ -273,7 +284,7 @@ public class ClientAppService implements DataAccessUtilMixin {
tryAction(() -> storage.updateClientVersion(clientVersion));
- LOGGER.debug(String.format("Updated an API Key for client %s version %s", clientVersion.getClient().getName(), clientVersion)); //$NON-NLS-1$
+ LOGGER.debug("Updated an API Key for client {0} version {1}", clientVersion.getClient().getName(), clientVersion); //$NON-NLS-1$
ApiKeyBean rval = new ApiKeyBean();
rval.setApiKey(newApiKey);
return rval;
@@ -307,7 +318,7 @@ public class ClientAppService implements DataAccessUtilMixin {
storage.createClientVersion(newVersion);
storage.createAuditEntry(AuditUtils.clientVersionCreated(newVersion, securityContext));
- LOGGER.debug(String.format("Created new client version %s: %s", newVersion.getClient().getName(), newVersion)); //$NON-NLS-1$
+ LOGGER.debug("Created new client version {0}: {1}", newVersion.getClient().getName(), newVersion); //$NON-NLS-1$
return newVersion;
}
@@ -329,7 +340,7 @@ public class ClientAppService implements DataAccessUtilMixin {
protected ClientVersionBean getClientVersionInternal(String organizationId, String clientId, String version)
throws ClientVersionNotFoundException {
ClientVersionBean clientVersion = tryAction(() -> getClientVersionFromStorage(organizationId, clientId, version));
- LOGGER.debug(String.format("Got new client version %s: %s", clientVersion.getClient().getName(), clientVersion)); //$NON-NLS-1$
+ LOGGER.debug("Got new client version {0}: {1}", clientVersion.getClient().getName(), clientVersion); //$NON-NLS-1$
return clientVersion;
}

MODIFY
manager/api/rest/src/main/java/io/apiman/manager/api/rest/IOrganizationResource.java
manager/api/rest/src/main/java/io/apiman/manager/api/rest/IOrganizationResource.java
@@ -98,7 +98,6 @@ import io.apiman.manager.api.rest.exceptions.UserNotFoundException;
import java.io.IOException;
import java.util.List;
-import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
@@ -253,6 +252,14 @@ public interface IOrganizationResource {
NewClientBean bean) throws OrganizationNotFoundException, ClientAlreadyExistsException,
NotAuthorizedException, InvalidNameException;
+ @POST
+ @Path("{organizationId}/clients")
+ @Consumes(MediaType.MULTIPART_FORM_DATA)
+ @Produces(MediaType.APPLICATION_JSON)
+ public ClientBean createClient(@PathParam("organizationId") String organizationId, @NotNull MultipartFormDataInput multipartInput)
+ throws OrganizationNotFoundException, ClientAlreadyExistsException, NotAuthorizedException, InvalidNameException, IOException;
+
+
/**
* Use this endpoint to retrieve information about a single Client by ID. Note
* that this only returns information about the Client, not about any particular
@@ -331,6 +338,14 @@ public interface IOrganizationResource {
@PathParam("clientId") String clientId, UpdateClientBean bean)
throws ClientNotFoundException, NotAuthorizedException;
+ @PUT
+ @Path("{organizationId}/clients/{clientId}")
+ @Consumes(MediaType.MULTIPART_FORM_DATA)
+ @Produces(MediaType.APPLICATION_JSON)
+ public void updateClient(@PathParam("organizationId") String organizationId,
+ @PathParam("clientId") String clientId, @NotNull MultipartFormDataInput multipartInput)
+ throws OrganizationNotFoundException, ClientAlreadyExistsException, NotAuthorizedException,
+ InvalidNameException, IOException;
/**
* Use this endpoint to create a new version of the Client.
* @summary Create Client Version
@@ -837,7 +852,7 @@ public interface IOrganizationResource {
@Path("{organizationId}/apis")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
- public ApiBean createApi(@PathParam("organizationId") String organizationId, @Valid @NotNull NewApiBean bean)
+ public ApiBean createApi(@PathParam("organizationId") String organizationId, @NotNull NewApiBean bean)
throws OrganizationNotFoundException, ApiAlreadyExistsException, NotAuthorizedException,
InvalidNameException;
@@ -845,7 +860,7 @@ public interface IOrganizationResource {
@Path("{organizationId}/apis")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.APPLICATION_JSON)
- public ApiBean createApi(@PathParam("organizationId") String organizationId, @Valid @NotNull @MultipartForm MultipartFormDataInput multipartInput)
+ public ApiBean createApi(@PathParam("organizationId") String organizationId, @NotNull MultipartFormDataInput multipartInput)
throws OrganizationNotFoundException, ApiAlreadyExistsException, NotAuthorizedException, InvalidNameException, IOException;
/**

feat(manager-api): add extended description and image to Api