ModuleInfoExtractor.java
/*-
* #%L
* io.earcam.instrumental.module.jpms
* %%
* 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.module.jpms;
import static io.earcam.instrumental.module.jpms.Constants.HEADER_AUTOMATIC_MODULE_NAME;
import static io.earcam.instrumental.module.jpms.Constants.META_INF_SERVICES;
import static io.earcam.instrumental.module.jpms.ModuleModifier.SYNTHETIC;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Optional;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.jar.Manifest;
import javax.annotation.WillClose;
import io.earcam.utilitarian.io.ExplodedJarInputStream;
import io.earcam.utilitarian.io.IoStreams;
final class ModuleInfoExtractor {
private ModuleInfoExtractor()
{}
static Optional<ModuleInfo> extract(Path jar) throws IOException
{
return extract(ExplodedJarInputStream.jarInputStreamFrom(jar));
}
static Optional<ModuleInfo> extract(@WillClose JarInputStream jar) throws IOException
{
try(JarInputStream jin = jar) {
String autoName = null;
boolean hasAutoName = false;
Manifest manifest = jin.getManifest();
if(manifest != null) {
autoName = manifest.getMainAttributes().getValue(HEADER_AUTOMATIC_MODULE_NAME);
hasAutoName = (autoName != null);
}
ModuleInfoBuilder builder = ModuleInfo.moduleInfo()
.withAccess(SYNTHETIC.access());
JarEntry entry;
while((entry = jin.getNextJarEntry()) != null) {
if(!entry.isDirectory()) {
if("module-info.class".equals(entry.getName())) {
return Optional.of(ModuleInfo.read(IoStreams.readAllBytes(jin)));
}
if(hasAutoName) {
processEntryForAutomaticModule(builder, jin, entry);
}
}
}
return (hasAutoName) ? Optional.of(builder.named(autoName).construct()) : Optional.empty();
}
}
private static void processEntryForAutomaticModule(ModuleInfoBuilder builder, JarInputStream jin, JarEntry entry)
{
if(entry.getName().endsWith(".class")) {
int end = entry.getName().lastIndexOf('/');
if(end != -1) {
builder.exporting(entry.getName().substring(0, end).replace('/', '.'));
}
} else if(entry.getName().startsWith(META_INF_SERVICES)) {
String service = entry.getName().substring(META_INF_SERVICES.length());
String[] implementations = new String(IoStreams.readAllBytes(jin), UTF_8).split("\r?\n");
builder.providing(service, implementations);
}
}
}