DefaultArchive.java
/*-
* #%L
* io.earcam.instrumental.archive
* %%
* Copyright (C) 2018 earcam
* %%
* SPDX-License-Identifier: (BSD-3-Clause OR EPL-1.0 OR Apache-2.0 OR MIT)
*
* You <b>must</b> choose to accept, in full - any individual or combination of
* the following licenses:
* <ul>
* <li><a href="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</a></li>
* <li><a href="https://www.eclipse.org/legal/epl-v10.html">EPL-1.0</a></li>
* <li><a href="https://www.apache.org/licenses/LICENSE-2.0">Apache-2.0</a></li>
* <li><a href="https://opensource.org/licenses/MIT">MIT</a></li>
* </ul>
* #L%
*/
package io.earcam.instrumental.archive;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.nio.file.Path;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import javax.annotation.WillClose;
import io.earcam.unexceptional.Closing;
import io.earcam.unexceptional.Exceptional;
import io.earcam.utilitarian.io.file.RecursiveFiles;
/**
* <p>
* Default implementation of {@link Archive}.
* </p>
*
*/
class DefaultArchive implements Archive {
private final Optional<Manifest> manifest;
private final List<ArchiveResource> contents;
DefaultArchive(Optional<Manifest> manifest, List<ArchiveResource> contents)
{
this.manifest = manifest;
this.contents = contents;
}
@Override
public Optional<Manifest> manifest()
{
return manifest;
}
@Override
public List<ArchiveResource> contents()
{
return contents;
}
@Override
public <R> R to(Function<Archive, R> transformer)
{
return transformer.apply(this);
}
@Override
public void to(@WillClose OutputStream os)
{
JarOutputStream out = manifest()
.map(m -> Exceptional.apply(JarOutputStream::new, os, m))
.orElseGet(() -> Exceptional.apply(JarOutputStream::new, os));
Closing.closeAfterAccepting(out, o -> contents()
.stream()
.forEach(e -> addEntry(e, o)));
}
private void addEntry(ArchiveResource resource, JarOutputStream target)
{
JarEntry entry = new JarEntry(resource.name());
if(resource.knownSize() != -1) {
entry.setSize(resource.knownSize());
}
Exceptional.accept(target::putNextEntry, entry);
resource.write(target);
}
@Override
public Path explodeTo(Path directory, boolean merge)
{
if(!merge && directory.toFile().exists()) {
Exceptional.accept(RecursiveFiles::delete, directory);
}
directory.toFile().mkdirs();
Path metaInf = directory.resolve("META-INF");
metaInf.toFile().mkdirs();
manifest()
.ifPresent(m -> Exceptional.run(() -> m.write(new FileOutputStream(metaInf.resolve("MANIFEST.MF").toFile()))));
contents().forEach(r -> {
Path resource = directory.resolve(r.name());
File dir = resource.getParent().toFile();
dir.mkdirs();
Closing.closeAfterAccepting(FileOutputStream::new, resource.toFile(), r::write);
});
return directory;
}
}