Bug 445287 - Exception occurred during compilation unit conversion: ----------------------... (err_grp: c2fea5e4)
Summary: Exception occurred during compilation unit conversion: ----------------------...
Status: CLOSED DUPLICATE of bug 445057
Alias: None
Product: z_Archived
Classification: Eclipse Foundation
Component: Recommenders (show other bugs)
Version: unspecified   Edit
Hardware: All All
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: Marcel Bruch CLA
QA Contact:
URL:
Whiteboard:
Keywords:
: 445228 447584 (view as bug list)
Depends on:
Blocks:
 
Reported: 2014-09-28 13:36 EDT by Marcel Bruch CLA
Modified: 2015-09-15 14:53 EDT (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Marcel Bruch CLA 2014-09-28 13:36:53 EDT
Hello committers,

we received a new error report for Eclipse 4.4.1.M20140925-0400.


General Information:
    anonymous-id:         01c9fb23-7e0d-4f0b-8ada-af4b42b9d715
    eclipse-build-id:     4.4.1.M20140925-0400
    eclipse-product:      org.eclipse.epp.package.standard.product
    operating system:     Linux 3.13.0 (x86_64) - gtk
    java-runtime-version: 1.7.0_67-b01

The following plug-ins were present on the execution stack (*):
    1. org.eclipse.core.jobs_3.6.0.v20140424-0053
    2. org.eclipse.core.runtime_3.10.0.v20140318-2214
    3. org.eclipse.jdt.core_3.10.0.v20140902-0626
    4. org.eclipse.jdt_3.10.0.v20140925-0400
    5. org.eclipse.jdt.ui_3.10.1.v20140817-1500
    6. org.eclipse.ui_3.106.0.v20140812-1751


Error Status:
    code:                   4
    message:                Exception occurred during compilation unit conversion:
----------------------------------- SOURCE BEGIN -------------------------------------
package com.importio.api;

import static org.elasticsearch.index.query.FilterBuilders.andFilter;
import static org.elasticsearch.index.query.FilterBuilders.termFilter;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.security.DigestOutputStream;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.zip.Deflater;
import java.util.zip.GZIPOutputStream;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Cleanup;
import lombok.Data;
import lombok.Delegate;
import lombok.Getter;
import lombok.Setter;
import lombok.val;
import lombok.experimental.FieldDefaults;
import lombok.extern.slf4j.Slf4j;

import org.eclipse.jetty.server.AsyncContinuation;
import org.elasticsearch.index.query.FilterBuilder;

import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.BaseEncoding;
import com.google.common.io.ByteStreams;
import com.google.common.util.concurrent.AsyncFunction;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.importio.data.Attachment;
import com.importio.s3.URLSigner;
import com.importio.s3.URLSigner.Builder;
import com.importio.servlet.ImportioServlet;
import com.importio.servlet.ImportioServlet.BadParameterException;
import com.kusiri.glade.auth.data.User;
import com.kusiri.glade.auth.exceptions.NotAuthorizedException;
import com.kusiri.glade.downloader.DownloadService;
import com.kusiri.glade.downloader.data.HeaderEntry;
import com.kusiri.glade.downloader.data.Request;
import com.kusiri.glade.downloader.data.Response;
import com.kusiri.glade.objectstore.ObjectStore.Change;
import com.kusiri.glade.objectstore.ObjectStore.Change.ChangeType;
import com.kusiri.glade.objectstore.impl.ObjectStoreImpl;
import com.kusiri.glade.scalarobjectstore.BucketDirectory.NoSuchBucketException;
import com.kusiri.glade.scalarobjectstore.ChangeCommand;
import com.kusiri.glade.scalarobjectstore.ChangeCommand.CommandType;
import com.kusiri.glade.scalarobjectstore.ScalarObjectGet.FetchType;
import com.kusiri.glade.scalarobjectstore.ScalarObjectGetByGuid;
import com.kusiri.glade.scalarobjectstore.ScalarObjectStore;
import com.kusiri.glade.scalarobjectstore.ScalarObjectStore.Format;
import com.kusiri.glade.scalarobjectstore.bucket.Bucket;
import com.kusiri.glade.scalarobjectstore.bucket.Bucket.BucketField;
import com.kusiri.glade.scalarobjectstore.bucket.Bucket.NoSuchBucketFieldException;
import com.kusiri.glade.scalarobjectstore.bucket.BucketACL.UserACL;
import com.kusiri.glade.scalarobjectstore.bucket.StoredBean;
import com.kusiri.glade.scalarobjectstore.plugin.AbstractPlugin;
import com.kusiri.glade.scalarobjectstore.search.elasticsearch.ESResponse;
import com.kusiri.glade.scalarobjectstore.search.elasticsearch.ObjectSearchPlugin;
import com.kusiri.glade.serialization.AttachmentInfo;
import com.kusiri.glade.serialization.ByteArray;

@FieldDefaults(level = AccessLevel.PRIVATE)
@Slf4j
public class AttachmentPlugin extends AbstractPlugin implements AttachmentService {

	public static final String TEST_BUCKET = "importio-tests";

	final String[] passedThrough = new String[] { "If-Modified-Since", "If-Unmodified-Since", "If-Match", "If-None-Match" };
	final String MD5_HEADER = "Content-MD5";

	/**
	 * The CDN service to use to store the data
	 */
	@Getter(AccessLevel.PROTECTED)
	final DownloadService downloadService;
	
	@Getter(AccessLevel.PROTECTED)
	final URLSigner urlSigner;

	@Setter
	String s3BucketName;

	@Setter
	int maximumSize = 25 * 1 << 20;

	@Getter(AccessLevel.PROTECTED)
	final ObjectStoreImpl objectStore;

	final ObjectSearchPlugin objectSearchPlugin;

	final Bucket<?> attachmentBucket;

	final long expires = System.currentTimeMillis() + 2 * TimeUnit.MILLISECONDS.convert(365, TimeUnit.DAYS);

	final ListeningExecutorService uploadExecutor;

	public AttachmentPlugin(ObjectSearchPlugin objectSearchPlugin, DownloadService downloadService, ScalarObjectStore scalarObjectStore, ExecutorService uploadExecutor, ExecutorService executor, URLSigner urlSigner) throws NoSuchBucketException {
		super(scalarObjectStore, executor);
		this.objectSearchPlugin = objectSearchPlugin;
		this.objectStore = new ObjectStoreImpl(getStore());
		this.downloadService = downloadService;
		this.urlSigner = urlSigner;
		this.uploadExecutor = MoreExecutors.listeningDecorator(uploadExecutor);
		this.attachmentBucket = scalarObjectStore.getBucketDirectory().getBucket(Attachment.class);
	}

	/**
	 * When GET on the bucket with a GUID
	 * 
	 * @throws NoSuchObjectException
	 * @throws BadParameterException
	 */
	@Override
	protected void doGet(final User user, final Bucket<?> bucket, final UUID guid, String extraPath, final AsyncContinuation continuation) throws BadParameterException {
		doRead("GET", user, bucket, guid, extraPath, continuation);
	}

	/**
	 * When HEAD on the bucket with a GUID
	 */
	@Override
	protected void doHead(User user, Bucket<?> bucket, UUID guid, String extraPath, AsyncContinuation continuation) throws BadParameterException {
		doRead("HEAD", user, bucket, guid, extraPath, continuation);
	}
	
	private void doRead(final String method, final User user, final Bucket<?> bucket, final UUID guid, String extraPath, final AsyncContinuation continuation)
			throws BadParameterException {
		String[] split = extraPath.split("/");

		if (split.length != 2) {
			throw new BadParameterException("Bad URL");
		}

		String name = split[0];

		if ("_history".equals(split[1]) && "GET".equals(method)) {
			getHistory(user, bucket, guid, name, continuation);
			return;
		}

		final UUID attachmentGuid;
		try {
			attachmentGuid = UUID.fromString(split[1]);
		} catch (Exception e) {
			throw new BadParameterException("Bad attachmentGuid");
		}

		getAttachment(method, user, bucket, guid, name, attachmentGuid, continuation);
	}

	/**
	 * When POST on the bucket
	 * 
	 * @throws IOException
	 * @throws BadParameterException
	 * @throws NotAuthorizedException
	 */
	@Override
	protected void doPut(final User user, final Bucket<?> bucket, final UUID guid, final String extra, final AsyncContinuation continuation) throws IOException, BadParameterException, NotAuthorizedException {
		ListenableFuture<Attachment> future = makeAttachment(user, bucket, guid, continuation, extra);
		ImportioServlet.hook(future, continuation, getExecutor());
	}

	public ListenableFuture<Attachment> sudoMakeAttachment(final User user, final Bucket<?> bucket, final UUID guid, final AsyncContinuation continuation, final String field) throws NotAuthorizedException, BadParameterException, IOException {
		return _makeAttachment(user, bucket, guid, continuation, field, true);
	}
	
	public ListenableFuture<Attachment> makeAttachment(final User user, final Bucket<?> bucket, final UUID guid, final AsyncContinuation continuation, final String field) throws NotAuthorizedException, BadParameterException, IOException {
		return _makeAttachment(user, bucket, guid, continuation, field, false);
	}

	private ListenableFuture<Attachment> _makeAttachment(final User user, final Bucket<?> bucket, final UUID guid, final AsyncContinuation continuation, final String field, final boolean sudo) throws NotAuthorizedException, BadParameterException, IOException {
		final BucketField bucketField = checkUpload(bucket, field, user, continuation);

		ListenableFuture<?> aclFuture = sudo ? Futures.immediateFuture(null) : checkAcl(user, bucket, guid, field, sudo);

		ListenableFuture<Attachment> result;

		if (bucketField.getField().getAttachmentInfo().isGzip()) {
			if (gzipUpload(continuation)) {
				result = _upload(user, bucketField, guid, getMD5(continuation), getContentLength(continuation), continuation.getRequest().getInputStream(), getIp(continuation), null, aclFuture, sudo, 0);
			} else {
				final Integer contentLength = getContentLength(continuation);
				result = nonGZippedUpload(aclFuture, user, bucketField, guid, continuation, continuation.getRequest().getInputStream(), contentLength, sudo);
			}
		} else {
			result = _upload(user, bucketField, guid, getMD5(continuation), getContentLength(continuation), continuation.getRequest().getInputStream(), getIp(continuation), null, aclFuture, sudo, 0);
		}

		return result;
	}

	/**
	 * A low level access to the attachment 'service'. Allows usage of a request, in which the input has started being read, say for other data.
	 * 
	 * @param user
	 * @param bucket
	 * @param guid
	 * @param continuation
	 * @param stream
	 * @param offset
	 * @param field
	 * @param sudo
	 * @return
	 * @throws NotAuthorizedException
	 * @throws BadParameterException
	 * @throws IOException
	 */
	public ListenableFuture<Attachment> makeAttachmentUsingStream(final User user, final Bucket<?> bucket, final UUID guid, final AsyncContinuation continuation, InputStream stream, int offset, final String field, final boolean sudo) throws NotAuthorizedException, BadParameterException, IOException {
		final BucketField bucketField = checkUpload(bucket, field, user, continuation);

		ListenableFuture<?> aclFuture = sudo ? Futures.immediateFuture(null) : checkAcl(user, bucket, guid, field, sudo);

		ListenableFuture<Attachment> result;

		if (bucketField.getField().getAttachmentInfo().isGzip()) {
			if (gzipUpload(continuation)) {
				//TODO:- do we?
				throw new UnsupportedOperationException("gzip not supported");
			} else {
				int contentLength = getContentLength(continuation) - offset;
				result = nonGZippedUpload(aclFuture, user, bucketField, guid, continuation, stream, contentLength, sudo);
			}
		} else {
			result = _upload(user, bucketField, guid, null, getContentLength(continuation), stream, getIp(continuation), null, aclFuture, sudo, offset);
		}

		return result;
	}

	
	BucketField checkUpload(final Bucket<?> bucket, final String field, final User user, final AsyncContinuation continuation) throws NotAuthorizedException, BadParameterException {
		
		// Check user credentials
		if (user == User.ANONYMOUS) {
			throw new NotAuthorizedException(user);
		}

		final Integer contentLength = getContentLength(continuation);

		final BucketField bucketField = checkBucketField(bucket, field);

		String contentType = ((HttpServletRequest) continuation.getRequest()).getContentType();
		if (contentType == null || !checkContentType(bucketField, contentType)) {
			throw new ImportioServlet.BadParameterException("Please upload " + bucketField.getField().getAttachmentInfo().getMime());
		}

		if (contentLength <= 0) {
			throw new ImportioServlet.BadParameterException("No file size specified");
		}

		if (contentLength > maximumSize) {
			throw new ImportioServlet.BadParameterException("File too large");
		}

		return bucketField;
	}

	protected int getContentLength(final AsyncContinuation continuation) {
		val httpRequest = (HttpServletRequest) continuation.getRequest();
		if(httpRequest.getHeader("Content-Length") != null) {
			int length;
			try {
				length = Integer.parseInt(httpRequest.getHeader("Content-Length"));
			} catch (Exception e) {
				return continuation.getRequest().getContentLength();
			}
			return length;
		} else {
			return continuation.getRequest().getContentLength();
		}
	}

	/**
	 * Return the MD5 hash from the request header, could be NULL
	 * 
	 * @param continuation
	 * @return
	 */
	protected String getMD5(final AsyncContinuation continuation) {
		val httpRequest = (HttpServletRequest) continuation.getRequest();
		val md5Hash = httpRequest.getHeader(MD5_HEADER);
		return md5Hash;
	}

	@Data
	@AllArgsConstructor
	private class TempFile {
		File file;
		String hash;
	}
	

	
	private <X> ListenableFuture<Attachment> nonGZippedUpload(final ListenableFuture<X> aclFuture, final User user, final BucketField bucketField, final UUID guid, final AsyncContinuation continuation, final InputStream input, final Integer contentLength, final boolean sudo) throws IOException {

		// put the upload in a temporary file on the server

		final File temp = File.createTempFile("upload", "gz");
		ListenableFuture<TempFile> f = transform(aclFuture, new AsyncFunction<X, TempFile>() {

			@Override
			public ListenableFuture<TempFile> apply(X arg0) throws Exception {
				return uploadExecutor.submit(new Callable<TempFile>() {
					
					@SuppressWarnings("resource")
					@Override
					public TempFile call() throws Exception {
						val digest = MessageDigest.getInstance("MD5");
						@Cleanup final GZIPOutputStream gzipOutputStream = new GZIPOutputStream(new DigestOutputStream(new BufferedOutputStream(new FileOutputStream(temp)), digest)) {
							{
								def.setLevel(Deflater.BEST_SPEED);
							}
						};
						if(contentLength != null) {
							@Cleanup val out = new ExpectedLengthOutputStream(contentLength.intValue(), gzipOutputStream);
							ByteStreams.copy(input, out);
							out.close();
						} else {
							ByteStreams.copy(input, gzipOutputStream);
							gzipOutputStream.close();
						}
						val digestBytes = digest.digest();
						val hash = BaseEncoding.base64().encode(digestBytes);
						return new TempFile(temp, hash);
					}
				});
			}
		});
		
		ListenableFuture<Attachment> result = transform(f, new AsyncFunction<TempFile, Attachment>() {

			@SuppressWarnings("resource")
			@Override
			public ListenableFuture<Attachment> apply(TempFile gzipped) throws Exception {
				return _upload(user, bucketField, guid, gzipped.hash, (int) gzipped.file.length(), new BufferedInputStream(new FileInputStream(gzipped.file)), getIp(continuation), null, Futures.immediateFuture(null), sudo, 0);
			}
		});

		result.addListener(new Runnable() {

			@Override
			public void run() {
				temp.delete();
			}
		}, MoreExecutors.sameThreadExecutor());
		return result;
	}

	private boolean gzipUpload(final AsyncContinuation continuation) {
		return "gzip".equalsIgnoreCase(((HttpServletRequest) continuation.getRequest()).getHeader("Content-Encoding"));
	}

	/**
	 * @param user
	 * @param bucketField
	 * @param guid
	 * @param hash
	 * @param contentLength
	 * @param inputStream
	 * @param ip address
	 * @param info 
	 * @return
	 */
	public ListenableFuture<Attachment> upload(final User user, final BucketField bucketField, final UUID guid, final String hash, final Integer contentLength, final InputStream inputStream, final ByteArray ip, final Map<String, Object> info) {
		ListenableFuture<StoredBean<Object>> checkedFuture = checkAcl(user, bucketField.getBucket(), guid, bucketField.getField().getFieldName(), false);
		return _upload(user, bucketField, guid, hash, contentLength, inputStream, ip, info, checkedFuture, false, 0);
	}
	
	public ListenableFuture<Attachment> sudoUpload(final User user, final BucketField bucketField, final UUID guid, final String hash, final Integer contentLength, final InputStream inputStream, final ByteArray ip, final Map<String, Object> info) {
		return _upload(user, bucketField, guid, hash, contentLength, inputStream, ip, info, Futures.immediateFuture(null), true, 0);
	}

	private <X> ListenableFuture<Attachment> _upload(final User user, final BucketField bucketField, final UUID guid, final String hash, final Integer contentLength, final InputStream inputStream, final ByteArray ip, final Map<String, Object> info,
			ListenableFuture<X> aclFuture, final boolean sudo, final int lengthOffset) {
		ListenableFuture<Attachment> future = transform(aclFuture, new AsyncFunction<X, Attachment>() {

			@Override
			public ListenableFuture<Attachment> apply(X bytes) throws Exception {

				final UUID attachmentGuid = UUID.randomUUID();

				// Upload to CDN
				final Builder builder = getPUTBuilder(guid, attachmentGuid, bucketField);
				final AttachmentInfo attachmentInfo = bucketField.getField().getAttachmentInfo();
				builder.setContentType(attachmentInfo.getMime()).setHash(hash);
				Request request = new Request(builder.build());
				
				request.setMethod("PUT");
				val headers = ImmutableList.<HeaderEntry> builder();
				{
					if (attachmentInfo.isGzip()) {
						headers.add(new HeaderEntry("Content-Encoding", "gzip"));
					}
					if (hash != null) {
						log.debug("will use the following hash for this attachment:- {}", hash);
						headers.add(new HeaderEntry(MD5_HEADER, hash));
					}
					headers.add(new HeaderEntry("Content-Type", attachmentInfo.getMime()));
					val actualContentLength = contentLength.intValue() - lengthOffset;
					headers.add(new HeaderEntry("Content-Length", Integer.toString(actualContentLength)));
					headers.addAll(getHeaders());
				}
				request.setHeaders(headers.build());
				request.setInputStream(inputStream);
				return transform(downloadService.download(request), new AsyncFunction<Response, Attachment>() {

					@Override
					public ListenableFuture<Attachment> apply(Response ok) throws Exception {

						if (ok.getStatus() != 200 && ok.getStatus() != 201) {
							throw new RuntimeException("Failed to upload: " + getJsonUtils().toJson(ok));
						}

						val data = objectStore.diffObject(Attachment.class, attachmentGuid);
						final Attachment attachment = data.bean();
						attachment.setBucketGuid(bucketField.getBucket().getGuid());
						attachment.setObjectGuid(guid);
						attachment.setField(bucketField.getField().getFieldName());
						attachment.setSize(contentLength);
						attachment.setInfo(info);

						ListenableFuture<Boolean> storeFuture = objectStore.change(new Change<Attachment>(user, ip).setSudo(true).setType(ChangeType.POST).setData(data).setNewOwnerGuid(user.getGuid()));
						return transform(storeFuture, new AsyncFunction<Boolean, Attachment>() {

							@Override
							public ListenableFuture<Attachment> apply(Boolean b) throws Exception {
								ImmutableMap.Builder<String, Object> values = ImmutableMap.builder();
								values.put(bucketField.getField().getFieldName(), data.guid());
								if (attachmentInfo.getDateField() != null) {
									// it would be nice if this could match up with the attachment date, but that currently isn't easy to do
									// and would require further API changes
									values.put(attachmentInfo.getDateField(), System.currentTimeMillis());
								}
								ChangeCommand command = new ChangeCommand(user, ip).setSudo(sudo).setGuid(guid).setCommandType(CommandType.PATCH).setBucketAlias(bucketField.getBucket()).setValues(values.build());
								return transform(getStore().change(Format.NONE, command), new Function<ByteArray, Attachment>() {
									@Override
									public Attachment apply(ByteArray result) {
										return attachment;
									}
								});
							}
						});
					}
				});
			}

		});
		return future;
	}

	private <K> ListenableFuture<StoredBean<K>> checkAcl(final User user, final Bucket<?> bucket, final UUID guid, final String field, final boolean sudo) {
		// we want to return a 404 ASAP
		ListenableFuture<StoredBean<K>> aclFuture = getStore().getByGuid(user, new ScalarObjectGetByGuid(bucket, guid, null, FetchType.ONLY_META, null).setSudo(sudo));

		ListenableFuture<StoredBean<K>> checkedFuture = transform(aclFuture, new AsyncFunction<StoredBean<K>, StoredBean<K>>() {

			@Override
			public ListenableFuture<StoredBean<K>> apply(StoredBean<K> o) throws Exception {

				UserACL userACL = bucket.getAcl().getUserAcl(user);
				if ( ! sudo && !userACL.canUpdate(o.ownerGuid(), Collections.singleton(field))) {
					return Futures.immediateFailedFuture(new NotAuthorizedException(user));
				}

				return Futures.immediateFuture(o);
			}
		});
		return checkedFuture;
	}

	protected List<HeaderEntry> getHeaders() {
		return Collections.emptyList();
	}

	private boolean checkContentType(BucketField field, String contentType) {
		return contentType.startsWith(field.getField().getAttachmentInfo().getMime());
	}

	private String getKey(BucketField bucketField, final UUID guid, UUID attachmentGuid) {
		String file = bucketField.getBucket().getGuid() + "/" + guid.toString().replace('-', '/') + "/" + bucketField.getField().getFieldName() + "/" + attachmentGuid.toString().replace('-', '/') + "."
				+ bucketField.getField().getAttachmentInfo().getExtension();
		return file;
	}
	
	public ListenableFuture<Response> copyAttachments(final Bucket<?> bucket, final UUID fromGuid, final UUID toGuid, final String name, final UUID attachmentGuid) throws BadParameterException {

		final BucketField bucketField = checkBucketField(bucket, name);

		final String oldKey = getKey(bucketField, fromGuid, attachmentGuid);
		Builder builder = urlSigner.makeBuilder("PUT", s3BucketName, getKey(bucketField, toGuid, attachmentGuid), null).setSource(s3BucketName, oldKey);
		Request request = new Request(builder.build());
		request.setMethod("PUT");
		request.setHeaders(Collections.singletonList(new HeaderEntry("x-amz-copy-source", builder.getSource())));
		return downloadService.download(request);
	}
	
	public void getAttachment(final String method, final User user, final Bucket<?> bucket, final UUID guid, final String name, final UUID attachmentGuid, final AsyncContinuation continuation) throws BadParameterException {
		final HttpServletRequest httpServletRequest = (HttpServletRequest) continuation.getRequest();

		final BucketField bucketField = checkBucketField(bucket, name);

		if (bucketField.getField().getAttachmentInfo().isGzip()) {
			final String encoding = httpServletRequest.getHeader("Accept-Encoding");
			if (encoding == null || !encoding.toLowerCase().contains("gzip")) {
				throw new BadParameterException("Must accept gzipped encoding");
			}
		}

		ListenableFuture<Boolean> aclFuture = bucket.getAcl().getUserAcl(user).canRead(getStore(), guid);

		ListenableFuture<Boolean> result = transform(aclFuture, new AsyncFunction<Boolean, Boolean>() {
			@Override
			public ListenableFuture<Boolean> apply(Boolean ok) throws NotAuthorizedException {

				if (!ok) {
					throw new NotAuthorizedException(user);
				}

				Builder builder = getReadBuilder(method, guid, attachmentGuid, bucketField);

				List<HeaderEntry> headers = new ArrayList<>(passedThrough.length);

				for (String passThrough : passedThrough) {
					String value = httpServletRequest.getHeader(passThrough);
					if (value != null) {
						headers.add(new HeaderEntry(passThrough, value));
					}
				}

				final AttachmentInfo attachmentInfo = bucketField.getField().getAttachmentInfo();
				if (attachmentInfo.isGzip()) {
					headers.add(new HeaderEntry("Accept-Encoding", "gzip"));
				}

				final URL url = builder.build();
				Request request = new Request(url);
				request.setMethod(method);
				request.setHeaders(headers);

				final String substring = httpServletRequest.getRequestURL().subSequence(0, 8).toString();
				if (substring.equalsIgnoreCase("https://")) {
					// see
					// https://developers.google.com/speed/docs/best-practices/caching
					((HttpServletResponse) continuation.getResponse()).addHeader("Cache-control", "public");
				}

				((HttpServletResponse) continuation.getResponse()).addDateHeader("Expires", expires);
				// TODO: Upgrade to latest Jetty, which allows you to set this in web.xml
				((HttpServletResponse) continuation.getResponse()).addHeader("Access-Control-Expose-Headers", "Content-Length");

				// TODO: this should only happen on success
				if (attachmentInfo.isInline()) {
					// Make this a download disposition
					((HttpServletResponse) continuation.getResponse()).addHeader("Content-Disposition", "attachment; filename=\"" + attachmentGuid.toString() + "." + attachmentInfo.getExtension() + "\"");
				}

				return downloadService.proxy(request, continuation, true);
			}
		});
		//OK - the future, which uses a proxy request above, will complete the continuation,
		//unless it has an error, in which case, handle it below
		Futures.addCallback(result, new FutureCallback<Boolean>() {
			@Override public void onFailure(Throwable error) {
				ImportioServlet.onException(continuation, error);
			}
			@Override
			public void onSuccess(Boolean ok) {
				//Do nothing everything is good
			}
		}, uploadExecutor);
	}

	protected void getHistory(final User user, final Bucket<?> bucket, final UUID guid, final String name, final AsyncContinuation continuation) throws BadParameterException {

		final BucketField bucketField = checkBucketField(bucket, name);

		ListenableFuture<Boolean> aclFuture = bucket.getAcl().getUserAcl(user).canRead(getStore(), guid);

		ListenableFuture<ESResponse> future = transform(aclFuture, new AsyncFunction<Boolean, ESResponse>() {
			@Override
			public ListenableFuture<ESResponse> apply(Boolean ok) throws Exception {
				if (!ok) {
					throw new NotAuthorizedException(user);
				}
				FilterBuilder filter = andFilter(termFilter("objectGuid", guid.toString()), termFilter("bucketGuid", bucket.getGuid()), termFilter("field", bucketField.getField().getFieldName()));
				return objectSearchPlugin.doSearch(user, attachmentBucket, continuation, null, Collections.singletonList(filter), Arrays.asList("size", "info"));
			}
		});

		hook(future, new ImportioServlet.ImportIoCallback<ESResponse>() {
			@Override
			public void onSuccess(ESResponse o) {
				// do nothing!
				log.trace("Download complete");
			}

			@Override
			public void onFailure(Throwable t) {
				if (!continuation.isComplete()) {
					super.onFailure(t);
				}
			}

		}, continuation);
	}

	protected BucketField checkBucketField(final Bucket<?> bucket, String extraPath) throws BadParameterException {
		final BucketField bucketField;
		try {
			bucketField = bucket.getBucketField(extraPath);
		} catch (NoSuchBucketFieldException e) {
			throw new ImportioServlet.BadParameterException("No such field");
		}
		if (!bucketField.getField().isAttachment()) {
			throw new ImportioServlet.BadParameterException("Not an attachment");
		}
		return bucketField;
	}


	@Override
	protected boolean mustHaveReadPermissionOnBucket() {
		return false;
	}

	@Override
	protected List<String> getApplicableBuckets() {
		return null;
	}

	public Builder getGETBuilder(final UUID guid, final UUID attachmentGuid, final BucketField bucketField) {
		return getReadBuilder("GET", guid, attachmentGuid, bucketField);
	}
	
	public Builder getHEADBuilder(final UUID guid, final UUID attachmentGuid, final BucketField bucketField) {
		return getReadBuilder("HEAD", guid, attachmentGuid, bucketField);
	}
	
	public Builder getReadBuilder(final String method, final UUID guid, final UUID attachmentGuid, final BucketField bucketField) {
		return urlSigner.makeBuilder(method, s3BucketName, getKey(bucketField, guid, attachmentGuid), null);
	}

	public Builder getPUTBuilder(final UUID guid, final UUID attachmentGuid, final BucketField bucketField) {
		final AttachmentInfo attachmentInfo = bucketField.getField().getAttachmentInfo();
		final Builder builder = urlSigner.makeBuilder("PUT", s3BucketName, getKey(bucketField, guid, attachmentGuid), null)
				.setContentType(attachmentInfo.getMime());
		if (attachmentInfo.isGzip()) {
			builder.setParameter("Content-Encoding", "gzip");
		}
		return builder;
	}

	@Override
	public String getName() {
		return "attachment";
	}
	
	
	private interface ExcludedDelegateMethods {
		public void write(int b) throws IOException;
		public void write(byte[] b, int off, int len) throws IOException;
		public void close() throws IOException;
	}

	class ExpectedLengthOutputStream extends OutputStream {
		
		int expectedLength;
		int length;
		@Delegate(types=OutputStream.class, excludes=ExcludedDelegateMethods.class)
		OutputStream stream;
		
		public ExpectedLengthOutputStream(int max, OutputStream out) {
			this.expectedLength = max;
			stream = new FilterOutputStream(out);
		}
		
		@Override
		public void write(byte[] b, int off, int len) throws IOException {
			if(length + len > expectedLength) throw new IOException("file is larger than expected (sofar "+(length+len)+" vs expected "+expectedLength+")");
			length += len;
			stream.write(b, off, len);
		}
		
		@Override
		public void write(int b) throws IOException {
			if(length + 1 > expectedLength) throw new IOException("file is larger than expected (sofar "+(length+1)+" vs expected "+expectedLength+")");
			length++;
			stream.write(b);
		}
		
		@Override
		public void close() throws IOException {
			stream.close();
			if(length != expectedLength) throw new IOException("file is not expected size (actual "+length+" vs expected "+expectedLength+")");
		}

		
	}

}

----------------------------------- SOURCE END -------------------------------------
    fingerprint:            c2fea5e4
    exception class:        java.lang.IllegalArgumentException
    exception message:      -
    number of children:     0

Topmost Stacktrace:
 java.lang.IllegalArgumentException: null
    at org.eclipse.jdt.core.dom.ASTNode.setSourceRange(ASTNode.java:2845)
    at org.eclipse.jdt.core.dom.ASTConverter.setTypeAnnotationsAndSourceRangeOnArray(ASTConverter.java:3420)
    at org.eclipse.jdt.core.dom.ASTConverter.convertToArray(ASTConverter.java:3166)
    at org.eclipse.jdt.core.dom.ASTConverter.convertType(ASTConverter.java:3628)
    at org.eclipse.jdt.core.dom.ASTConverter.convert(ASTConverter.java:921)
    at org.eclipse.jdt.core.dom.ASTConverter.convert(ASTConverter.java:550)
    at org.eclipse.jdt.core.dom.ASTConverter.buildBodyDeclarations(ASTConverter.java:195)
    at org.eclipse.jdt.core.dom.ASTConverter.convert(ASTConverter.java:2958)
    at org.eclipse.jdt.core.dom.ASTConverter.buildBodyDeclarations(ASTConverter.java:200)
    at org.eclipse.jdt.core.dom.ASTConverter.convert(ASTConverter.java:2958)
    at org.eclipse.jdt.core.dom.ASTConverter.convert(ASTConverter.java:1374)
    at org.eclipse.jdt.core.dom.CompilationUnitResolver.convert(CompilationUnitResolver.java:292)
    at org.eclipse.jdt.core.dom.ASTParser.internalCreateAST(ASTParser.java:1209)
    at org.eclipse.jdt.core.dom.ASTParser.createAST(ASTParser.java:809)
    at org.eclipse.jdt.internal.ui.javaeditor.ASTProvider$1.run(ASTProvider.java:544)
    at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
    at org.eclipse.jdt.internal.ui.javaeditor.ASTProvider.createAST(ASTProvider.java:537)
    at org.eclipse.jdt.internal.ui.javaeditor.ASTProvider.getAST(ASTProvider.java:480)
    at org.eclipse.jdt.internal.ui.javaeditor.ASTProvider.getAST(ASTProvider.java:470)
    at org.eclipse.jdt.ui.SharedASTProvider.getAST(SharedASTProvider.java:128)
    at org.eclipse.jdt.ui.OverrideIndicatorLabelDecorator.getOverrideIndicators(OverrideIndicatorLabelDecorator.java:161)
    at org.eclipse.jdt.ui.OverrideIndicatorLabelDecorator.computeAdornmentFlags(OverrideIndicatorLabelDecorator.java:136)
    at org.eclipse.jdt.ui.OverrideIndicatorLabelDecorator.decorate(OverrideIndicatorLabelDecorator.java:273)
    at org.eclipse.ui.internal.decorators.LightweightDecoratorDefinition.decorate(LightweightDecoratorDefinition.java:273)
    at org.eclipse.ui.internal.decorators.LightweightDecoratorManager$LightweightRunnable.run(LightweightDecoratorManager.java:83)
    at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
    at org.eclipse.ui.internal.decorators.LightweightDecoratorManager.decorate(LightweightDecoratorManager.java:367)
    at org.eclipse.ui.internal.decorators.LightweightDecoratorManager.getDecorations(LightweightDecoratorManager.java:349)
    at org.eclipse.ui.internal.decorators.DecorationScheduler$1.ensureResultCached(DecorationScheduler.java:372)
    at org.eclipse.ui.internal.decorators.DecorationScheduler$1.run(DecorationScheduler.java:332)
    at org.eclipse.core.internal.jobs.Worker.run(Worker.java:54)
    

Messages, stacktraces, and nested status objects may be shortened. Please visit 
http://dev.eclipse.org/recommenders/reports/54284736e4b05b1f99e71bcf
for the complete error log.

The list of all reported error reports belonging to this error group can be
fetched from http://dev.eclipse.org/recommenders/states/54284736e4b05b1f99e71bd0/reports

The Error Log Reporter presents the current processing state of this error to 
new reporters. This state can be updated by modifying the values of this bug.
To update the error log database call the link below after each change made to
this bug report: http://dev.eclipse.org/recommenders/states/54284736e4b05b1f99e71bd0/sync


Thank you for caring.
Your friendly error reports bot.


--
* Note: The list of present bundles and their respective versions was
  calculated by package naming heuristics. This may or may not reflect reality.
Comment 1 Marcel Bruch CLA 2014-10-02 15:41:24 EDT
*** Bug 445228 has been marked as a duplicate of this bug. ***
Comment 2 Marcel Bruch CLA 2014-10-16 08:50:48 EDT

*** This bug has been marked as a duplicate of bug 445057 ***
Comment 3 EPP Error Reports CLA 2014-10-16 13:10:27 EDT
*** Bug 447584 has been marked as a duplicate of this bug. ***