Bug 447585 - [any] Exception occurred during compilation unit conversion: ----------------------...
Summary: [any] Exception occurred during compilation unit conversion: ----------------...
Status: CLOSED DUPLICATE of bug 447584
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: EPP Error Reports CLA
QA Contact:
URL:
Whiteboard:
Keywords:
: 445887 (view as bug list)
Depends on:
Blocks:
 
Reported: 2014-10-16 11:01 EDT by EPP Error Reports CLA
Modified: 2015-09-15 14:59 EDT (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description EPP Error Reports CLA 2014-10-16 11:01:42 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


Error Status:

    code:                   4
    plugin:                 org.eclipse.jdt.core_3.10.0.v20140902-0626
    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 com.kusiri.glade.scalarobjectstore.plugin.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.binary.ByteArray;
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.scalarobjectstore.BucketDirectory.NoSuchBucketException;
import com.kusiri.glade.scalarobjectstore.ChangeCommand;
import com.kusiri.glade.scalarobjectstore.ChangeCommand.CommandType;
import com.kusiri.glade.scalarobjectstore.BeanStore.Change;
import com.kusiri.glade.scalarobjectstore.BeanStore.Change.ChangeType;
import com.kusiri.glade.scalarobjectstore.ScalarObjectGet.FetchType;
import com.kusiri.glade.scalarobjectstore.BeanStore;
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;

@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 BeanStore beanStore;

	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.beanStore = new BeanStore(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 = beanStore.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 = beanStore.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.asServlet3Continuation(), 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.isSuspended()) {
					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:            9590917c
    exception class:        java.lang.IllegalArgumentException
    exception message:      -
    number of children:     0
    
    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.ui.SharedASTProvider.getAST(SharedASTProvider.java:128)
    at org.eclipse.jdt.internal.ui.viewsupport.SelectionListenerWithASTManager$PartListenerGroup.calculateASTandInform(SelectionListenerWithASTManager.java:170)
    at org.eclipse.jdt.internal.ui.viewsupport.SelectionListenerWithASTManager$PartListenerGroup$3.run(SelectionListenerWithASTManager.java:155)
    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/committers/confess/0.5/reports/543fddd6e4b0eacad921de87
for the complete error log.


Some general information and guidelines about how to use this bug report:

1. Feel free to move this bug to your own product and components. Please note
   that this bug is only accessible to Eclipse committers. If you move this bug
   please make sure that it's still in the "Security Advisor" group.

2. The bug contents of the fields status, resolution, keywords, and whitelist
   are presented to reporters. If you needs more information, please set the
   keyword "needinfo". This will trigger a specialized dialog asking the user
   to provide further details.

3. Use the following resolutions for the following situations:
   * CLOSED / FIXED: This bug has been fixed. Please provide additional
     information in the whiteboard field.
   * CLOSED / WORKSFORME: Use this resolution if you can't reproduce this issue
     and request further information. Please use the whiteboard text to specify
     more details what a user should provide and how.
   * CLOSED / INVALID: Use this resolution if the reported problem is a
     'user-configuration' problem. Please consider giving hints how to fix
     these issues in the whiteboard field.
   * CLOSED / NOT ECLIPSE: Use this if the problem is caused by another plugin
     not developed at Eclipse.org
   * CLOSED / MOVED: If this bug has been moved else where. Please provide more 
     information (e.g. a link) in the whiteboard field.

4. Please remember that only committers can view and comment on this bug. You
   may, however, manually add the reporting user to the bug's cc list. But keep
   in mind that the report may contains sensitive information.

5. If you are missing a feature, please file a enhancement request here:
   https://bugs.eclipse.org/bugs/enter_bug.cgi?product=Recommenders.Incubator&component=Stacktraces
    
 

Thank you for your assistance.
Your friendly error-reports-inbox.


--
* 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 EPP Error Reports CLA 2014-10-16 11:01:42 EDT
I've looked up the (to date) top-3 most similar bug groups and listed the 
closest bug of each group below. This report may or may not be duplicate of
those (low or similar scores for all entries may indicate that this hasn't
been reported yet):

>     1. Bug 445287: Exception occurred during compilation unit conversion: ----------------------... (err_grp: c2fea5e4) – 1    
>     2. Bug 445887: Exception occurred during compilation unit conversion: ----------------------... (err_grp: 6e4b7cf5) – 1    
>     3. Bug 444292: Invalid ZIP archive: 'some-archive'... (err_grp: e2418191) – 0,4    


If this report actually is a duplicate of those, please mark it as such. This
information helps me to improve the recommendations further for the next issue.

Thank you for your assistance.
Your friendly error-reports-inbox.
Comment 2 EPP Error Reports CLA 2014-10-16 12:58:48 EDT

*** This bug has been marked as a duplicate of bug 447584 ***
Comment 3 EPP Error Reports CLA 2014-10-22 16:28:34 EDT
*** Bug 445887 has been marked as a duplicate of this bug. ***