ModuleInfo.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 java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.nio.file.Path;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.SortedSet;
import java.util.jar.JarInputStream;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.WillClose;
import javax.annotation.WillNotClose;

/**
 *
 */
public interface ModuleInfo extends Serializable {

	/**
	 * @return a new {@link ModuleInfoBuilder}.
	 */
	public static ModuleInfoBuilder moduleInfo()
	{
		return new DefaultModuleInfo();
	}


	/**
	 * <p>
	 * Read a {@code module-info.class}
	 * </p>
	 *
	 * @param bytecode the binary for {@code module-info.class}
	 * @return a {@link io.earcam.instrumental.module.jpms.ModuleInfo} object.
	 */
	public static ModuleInfo read(byte[] bytecode)
	{
		return BytecodeReader.read(bytecode);
	}


	/**
	 * <p>
	 * Read a {@code module-info.class}. The InputStream will not be closed, allowing
	 * use coding inspecting {@link JarInputStream} entries.
	 * </p>
	 *
	 * @param bytecode the {@link InputStream}, which at current point contains {@code module-info.class}
	 * @return a {@link io.earcam.instrumental.module.jpms.ModuleInfo} object.
	 * 
	 * @throws java.io.IOException if any.
	 */
	public static ModuleInfo read(@WillNotClose InputStream bytecode) throws IOException
	{
		return BytecodeReader.read(bytecode);
	}


	/**
	 * Extracts a {@code module-info} from a JAR (zip or directory-as-exploded-JAR)
	 * 
	 * @param jar path to the JAR
	 * @return a {@link ModuleInfo} instance, possibly {@link SYNTHETIC},
	 * or {@link Optional#empty()} if no module-info can be derived.
	 * @throws IOException
	 * 
	 * @see {@link #read(byte[])} to just read a {@code module-info.class} file
	 */
	public static Optional<ModuleInfo> extract(Path jar) throws IOException
	{
		return ModuleInfoExtractor.extract(jar);
	}


	/**
	 * Extracts a {@code module-info} from a {@link JarInputStream}.
	 * 
	 * @param jar the JAR input stream.
	 * @return a {@link ModuleInfo} instance, possibly {@link SYNTHETIC},
	 * or {@link Optional#empty()} if no module-info can be derived.
	 * @throws IOException
	 */
	public static Optional<ModuleInfo> extract(@WillClose JarInputStream jar) throws IOException
	{
		return ModuleInfoExtractor.extract(jar);
	}


	/**
	 * @return the module's name.
	 */
	public abstract @Nonnull String name();


	/**
	 * @return the module's version.
	 */
	public abstract @Nullable String version();


	/**
	 * @return the module's access flags.
	 */
	public abstract int access();


	/**
	 * @return the module's modifiers.
	 */
	public default Set<ModuleModifier> modifiers()
	{
		return Access.modifiers(ModuleModifier.class, access());
	}


	/**
	 * @return the module's packages.
	 */
	public abstract SortedSet<CharSequence> packages();


	/**
	 * @return the module's <b>uses</b>.
	 */
	public abstract SortedSet<String> uses();


	/**
	 * @return the module's <b>provides</b>.
	 */
	public abstract Map<String, String[]> provides();


	/**
	 * @return the module's main-class to launch.
	 */
	public abstract String mainClass();


	/**
	 * @return the module's <b>requires</b>.
	 */
	public abstract Set<Require> requires();


	/**
	 * @return the module's <b>exports</b>.
	 */
	public abstract Set<Export> exports();


	/**
	 * @return the module's <b>opens</b>.
	 */
	public abstract Set<Export> opens();


	/**
	 * @return convert this model to bytecode.
	 */
	public abstract byte[] toBytecode();


	/**
	 * @return a mutable version of this model.
	 */
	public abstract ModuleInfoBuilder deconstruct();
}