public void uploadApplication(
     String appName, ApplicationArchive archive, UploadStatusCallback callback)
     throws IOException {
   Assert.notNull(appName, "AppName must not be null");
   Assert.notNull(archive, "Archive must not be null");
   if (callback == null) {
     callback = UploadStatusCallback.NONE;
   }
   CloudResources knownRemoteResources = getKnownRemoteResources(archive);
   callback.onCheckResources();
   callback.onMatchedFileNames(knownRemoteResources.getFilenames());
   UploadApplicationPayload payload = new UploadApplicationPayload(archive, knownRemoteResources);
   callback.onProcessMatchedResources(payload.getTotalUncompressedSize());
   HttpEntity<?> entity = generatePartialResourceRequest(payload, knownRemoteResources);
   String url = getUrl("apps/{appName}/application");
   try {
     getRestTemplate().put(url, entity, appName);
   } catch (HttpServerErrorException hsee) {
     if (HttpStatus.INTERNAL_SERVER_ERROR.equals(hsee.getStatusCode())) {
       // this is for supporting legacy Micro Cloud Foundry 1.1 and older
       uploadAppUsingLegacyApi(url, entity, appName);
     } else {
       throw hsee;
     }
   }
 }
 private HttpEntity<MultiValueMap<String, ?>> generatePartialResourceRequest(
     UploadApplicationPayload application, CloudResources knownRemoteResources)
     throws IOException {
   MultiValueMap<String, Object> body = new LinkedMultiValueMap<String, Object>(2);
   if (application.getNumEntries() > 0) {
     // If the entire app contents are cached, send nothing
     body.add("application", application);
   }
   ObjectMapper mapper = new ObjectMapper();
   String knownRemoteResourcesPayload = mapper.writeValueAsString(knownRemoteResources);
   body.add("resources", knownRemoteResourcesPayload);
   HttpHeaders headers = new HttpHeaders();
   headers.setContentType(MediaType.MULTIPART_FORM_DATA);
   return new HttpEntity<MultiValueMap<String, ?>>(body, headers);
 }