private void readClasses(
	                         final MultiProcessor executor,
	                         final Map<String, ByteClass> byteClasses,
	                         final List<Pair<ZipEntry, byte[]>> fileEntries
	                         ) throws
	                         ZipException,
	                         IOException,
	                         InterruptedException,
	                         ExecutionException,
	                         MojoFailureException
	                         {
		final List<Future<ByteClass>> classBuffer = newArrayList();
		final List<Future<Pair<ZipEntry, byte[]>>> fileBuffer = newArrayList();

		final ZipFile zipInput = new ZipFile(input);
		final Enumeration<? extends ZipEntry> zipEntries = zipInput.entries();
		while (zipEntries.hasMoreElements()) {
			final ZipEntry zipEntry = zipEntries.nextElement();
			if (ByteClass.isClass(zipEntry.getName())) {
				classBuffer.add(executor.submit(
					new Callable<ByteClass>()
						{
							@Override
							public ByteClass call() throws Exception {
								return new ByteClass(zipEntry.getName(), zipInput.getInputStream(zipEntry));
							}
						}
					));
			} else {
				fileBuffer.add(executor.submit(
					new Callable<Pair<ZipEntry, byte[]>>()
						{
							@Override
							public Pair<ZipEntry, byte[]> call() throws Exception {
								return new ImmutablePair<ZipEntry, byte[]>(
									new ZipEntry(zipEntry),
									ByteStreams.toByteArray(zipInput.getInputStream(zipEntry))
									);
							}
						}
					));
			}
		}

		for (final Future<Pair<ZipEntry, byte[]>> file : fileBuffer) {
			fileEntries.add(file.get());
		}
		for (final Future<ByteClass> clazzFuture : classBuffer) {
			ByteClass clazz = clazzFuture.get();
			clazz = byteClasses.put(clazz.getToken(), clazz);
			if (clazz != null)
				throw new MojoFailureException(String.format(
					"Duplicate class definition %s - %s",
					clazz,
					clazzFuture.get()
					));
		}

		zipInput.close();
	}