// [B] Now we need to create the final re-assembled object
// -> the allocObjectItem checks for the bucket policy PutObject permissions
Tuple<SObject, SObjectItem> tupleObjectItem = allocObjectItem(bucket, key, meta, null, request.getCannedAccess());
Tuple<SHost, String> tupleBucketHost = getBucketStorageHost(bucket);
S3BucketAdapter bucketAdapter = getStorageHostBucketAdapter(tupleBucketHost.getFirst());
String itemFileName = tupleObjectItem.getSecond().getStoredPath();
// -> Amazon defines that we must return a 200 response immediately to the client, but
// -> we don't know the version header until we hit here
httpResp.setStatus(200);
httpResp.setContentType("text/xml; charset=UTF-8");
String version = tupleObjectItem.getSecond().getVersion();
if (null != version) httpResp.addHeader( "x-amz-version-id", version );
httpResp.flushBuffer();
// [C] Re-assemble the object from its uploaded file parts
try {
// explicit transaction control to avoid holding transaction during long file concatenation process
PersistContext.commitTransaction();
Tuple<String, Long> result = bucketAdapter.concatentateObjects( tupleBucketHost.getSecond(), bucket.getName(), itemFileName, ServiceProvider.getInstance().getMultipartDir(), parts, os );
response.setETag(result.getFirst());
response.setLastModified(DateHelper.toCalendar( tupleObjectItem.getSecond().getLastModifiedTime()));
SObjectItemDao itemDao = new SObjectItemDao();
SObjectItem item = itemDao.get( tupleObjectItem.getSecond().getId());