View Javadoc
1   /*-
2    * #%L
3    * io.earcam.instrumental.lade.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.lade.jpms;
20  
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.lang.module.ModuleDescriptor;
24  import java.lang.module.ModuleFinder;
25  import java.lang.module.ModuleReference;
26  import java.net.URI;
27  import java.net.URL;
28  import java.util.Enumeration;
29  import java.util.HashSet;
30  import java.util.Optional;
31  import java.util.Set;
32  import java.util.stream.Collectors;
33  
34  import io.earcam.instrumental.lade.InMemoryClassLoader;
35  import io.earcam.unexceptional.CheckedFunction;
36  import io.earcam.unexceptional.Closing;
37  import io.earcam.unexceptional.Exceptional;
38  
39  public final class InMemoryModuleFinder implements ModuleFinder {
40  
41  	private static final String MODULE_INFO_CLASS = "module-info.class";
42  	private final InMemoryClassLoader loader;
43  
44  
45  	public InMemoryModuleFinder(InMemoryClassLoader loader)
46  	{
47  		this.loader = loader;
48  	}
49  
50  
51  	@Override
52  	public Optional<ModuleReference> find(String name)
53  	{
54  		return findAll().stream()
55  				.filter(m -> name.equals(m.descriptor().name()))
56  				.findAny();
57  	}
58  
59  
60  	@Override
61  	public Set<ModuleReference> findAll()
62  	{
63  		Enumeration<URL> resources = loader.getResources(MODULE_INFO_CLASS, false);
64  
65  		Set<ModuleReference> references = new HashSet<>();
66  		while(resources.hasMoreElements()) {
67  			URL moduleInfo = resources.nextElement();
68  			ModuleDescriptor descriptor = parseModuleInfoByteCode(moduleInfo);
69  			URI uri = extractBaseUri(moduleInfo);
70  			Set<String> list = resourcesForThisModule(uri);
71  			references.add(new InMemoryModuleReference(descriptor, uri, list));
72  
73  		}
74  		return references;
75  	}
76  
77  
78  	private Set<String> resourcesForThisModule(URI baseUri)
79  	{
80  		return loader.resources()
81  				.map(Object::toString)
82  				.filter(r -> r.startsWith(baseUri.toString()))
83  				.collect(Collectors.toSet());
84  	}
85  
86  
87  	private URI extractBaseUri(URL moduleInfo)
88  	{
89  		String url = moduleInfo.toString();
90  		url = url.substring(0, url.length() - MODULE_INFO_CLASS.length());
91  		return Exceptional.uri(url);
92  	}
93  
94  
95  	private ModuleDescriptor parseModuleInfoByteCode(URL moduleInfo)
96  	{
97  		CheckedFunction<InputStream, ModuleDescriptor, IOException> converter = ModuleDescriptor::read;
98  		return Closing.closeAfterApplying(
99  				URL::openStream,
100 				moduleInfo,
101 				converter);
102 	}
103 }