View Javadoc
1   /*-
2    * #%L
3    * io.earcam.instrumental.archive.jpms
4    * %%
5    * Copyright (C) 2018 earcam
6    * %%
7    * SPDX-License-Identifier: (BSD-3-Clause OR EPL-1.0 OR Apache-2.0 OR MIT)
8    * 
9    * You <b>must</b> choose to accept, in full - any individual or combination of 
10   * the following licenses:
11   * <ul>
12   * 	<li><a href="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</a></li>
13   * 	<li><a href="https://www.eclipse.org/legal/epl-v10.html">EPL-1.0</a></li>
14   * 	<li><a href="https://www.apache.org/licenses/LICENSE-2.0">Apache-2.0</a></li>
15   * 	<li><a href="https://opensource.org/licenses/MIT">MIT</a></li>
16   * </ul>
17   * #L%
18   */
19  package io.earcam.instrumental.archive.jpms.auto;
20  
21  import java.io.IOException;
22  import java.nio.file.Path;
23  import java.util.Arrays;
24  import java.util.HashSet;
25  import java.util.Iterator;
26  import java.util.List;
27  import java.util.Set;
28  import java.util.function.Function;
29  
30  import io.earcam.instrumental.archive.jpms.PackageModuleMapper;
31  import io.earcam.instrumental.module.jpms.Export;
32  import io.earcam.instrumental.module.jpms.ModuleInfo;
33  import io.earcam.utilitarian.charstar.CharSequences;
34  
35  /**
36   * <p>
37   * An abstract base for PackageModuleMapper.
38   * </p>
39   */
40  public abstract class AbstractPackageModuleMapper implements PackageModuleMapper {
41  
42  	/**
43  	 * <p>
44  	 * The modules observed by this {@link PackageModuleMapper}.
45  	 * </p>
46  	 *
47  	 * @return the list of {@link ModuleInfo}s resolved by the package-module-mapper
48  	 */
49  	protected abstract List<ModuleInfo> modules();
50  
51  
52  	@Override
53  	public Set<ModuleInfo> moduleRequiredFor(CharSequence moduleName, Iterator<? extends CharSequence> requiredPackages)
54  	{
55  		return mapAvailableModules(moduleName, requiredPackages, ModuleInfo::exports);
56  	}
57  
58  
59  	Set<ModuleInfo> mapAvailableModules(CharSequence moduleName, Iterator<? extends CharSequence> requiredPackages,
60  			Function<ModuleInfo, Set<Export>> exportMode)
61  	{
62  		Set<ModuleInfo> mods = new HashSet<>();
63  		while(requiredPackages.hasNext()) {
64  			mapAvailableModules(moduleName, exportMode, requiredPackages, mods);
65  		}
66  		return mods;
67  	}
68  
69  
70  	void mapAvailableModules(CharSequence moduleName, Function<ModuleInfo, Set<Export>> exportMode, Iterator<? extends CharSequence> packages,
71  			Set<ModuleInfo> modules)
72  	{
73  		CharSequence paquet = packages.next();
74  		modules().stream().filter(m -> exportMode.apply(m).stream()
75  				.filter(x -> x.modules().length == 0 || Arrays.asList(x.modules()).contains(moduleName.toString()))
76  				.map(Export::paquet)
77  				.anyMatch(p -> CharSequences.same(p, paquet)))
78  				.findFirst().ifPresent(m -> {
79  					modules.add(m);
80  					packages.remove();
81  				});
82  	}
83  
84  
85  	@Override
86  	public Set<ModuleInfo> moduleOpenedFor(CharSequence moduleName, Iterator<? extends CharSequence> requiredPackages)
87  	{
88  		return mapAvailableModules(moduleName, requiredPackages, ModuleInfo::opens);
89  	}
90  
91  
92  	/**
93  	 * <p>
94  	 * Extracts ModuleInfo for the given JAR.
95  	 * </p>
96  	 * <ul>
97  	 * <li>If the {@literal #HEADER_AUTOMATIC_MODULE_NAME} header
98  	 * is encountered, then a {@link SYNTHETIC} module is generated exporting all packages</li>
99  	 * <li>Header values {@code Add-Exports} and {@code Add-Opens} are ignored (<i>though methods exposed to
100 	 * subclasses</i>)</li>
101 	 * </ul>
102 	 *
103 	 * @param path a {@link Path} to a JAR (zip file or exploded directory).
104 	 * @return a {@link ModuleInfo} instance, possibly {@link SYNTHETIC},
105 	 * or {@code null} if no module-info can be derived.
106 	 * 
107 	 * @throws java.io.IOException if thrown by the underlying.
108 	 */
109 	protected ModuleInfo moduleInfoFrom(Path path) throws IOException
110 	{
111 		return ModuleInfo.extract(path).orElse(null);
112 	}
113 }