1 /* 2 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 import java.io.File; 25 import java.io.IOException; 26 import java.io.OutputStream; 27 import java.io.UnsupportedEncodingException; 28 import java.nio.file.Files; 29 import java.nio.file.Path; 30 import java.nio.file.Paths; 31 import java.util.ArrayList; 32 import java.util.List; 33 import java.util.Map; 34 import java.util.jar.JarEntry; 35 import java.util.jar.JarOutputStream; 36 import java.lang.module.ModuleDescriptor; 37 import static java.lang.module.ModuleDescriptor.Builder; 38 39 /** 40 * Jigsaw utility methods are part of this class. It exposes methods to 41 * generate module descriptor, compile jigsaw modules, creates modular and 42 * regular jar files and generate service descriptor inside 43 * META-INF folder etc. 44 */ 45 public class JigsawCommon { 46 47 /** 48 * Enum represents all supported module types in JDK9. 49 */ 50 public enum MODULE_TYPE { 51 52 STRICT, AUTO, UN_NAMED; 53 } 54 55 public static final String SPACE = " "; 56 public static final String MODULE_INFO_DESCRIPTOR = "module-info.class"; 57 58 /** 59 * Constructs a Java Command line string based on modular structure 60 * followed by modular client and service. 61 */ 62 public static String[] getJavaCommand(MODULE_TYPE clientModuleType, 63 MODULE_TYPE serviceModuletype, Path clientJarFilePath, 64 Path serviceJarFilePath, String clientModuleName, 65 String mainClass, Map<String, String> vmArgs) throws IOException { 66 67 final StringBuilder command = new StringBuilder(); 68 vmArgs.forEach((key, value) -> command.append(key + value + SPACE)); 69 if (serviceModuletype != MODULE_TYPE.UN_NAMED 70 && clientModuleType != MODULE_TYPE.UN_NAMED) { 71 command.append(SPACE + "-mp" + SPACE); 72 command.append(clientJarFilePath.getParent().toRealPath()); 73 command.append(SPACE + ("-m" + SPACE + clientModuleName + "/") 74 + mainClass); 75 } else if (serviceModuletype == MODULE_TYPE.UN_NAMED 76 && clientModuleType == MODULE_TYPE.UN_NAMED) { 77 command.append(SPACE + "-cp" + SPACE); 78 command.append(clientJarFilePath.toRealPath()); 79 command.append(File.pathSeparator); 80 command.append(serviceJarFilePath.toRealPath()); 81 command.append(SPACE + mainClass); 82 } else { 83 if (serviceModuletype != MODULE_TYPE.UN_NAMED) { 84 command.append(SPACE + "-mp" + SPACE); 85 command.append(serviceJarFilePath.getParent().toRealPath()); 86 } else { 87 command.append(SPACE + "-cp" + SPACE); 88 command.append(serviceJarFilePath.toRealPath()); 89 } 90 if (clientModuleType != MODULE_TYPE.UN_NAMED) { 91 command.append(SPACE + "-mp" + SPACE); 92 command.append(clientJarFilePath.getParent().toRealPath()); 93 command.append(SPACE + ("-m" + SPACE + clientModuleName + "/") 94 + mainClass); 95 } else { 96 command.append(SPACE + "-cp" + SPACE); 97 command.append(clientJarFilePath.toRealPath()); 98 command.append(SPACE + mainClass); 99 } 100 } 101 102 return command.toString().trim().split("[\\s]+"); 103 } 104 105 /** 106 * Compile the source path and generates a regular/modular jar as per need. 107 */ 108 public static boolean compileAndCreateJar(Path codePath, Path compilePath, 109 Path jarFile, ModuleDescriptor moduleDescriptor, 110 boolean addMetaInfServiceDescriptor, 111 String serviceImpl, Path metaServiceDescriptor) throws IOException { 112 113 System.out.println(String.format( 114 "Compiling source code '%s'", codePath)); 115 boolean done = CompilerUtils.compile(codePath, compilePath); 116 System.out.println(String.format( 117 "Compilation completed successfully? %s", done)); 118 if (done) { 119 if (addMetaInfServiceDescriptor) { 120 createMetaInfServiceDescriptor(compilePath, serviceImpl, 121 metaServiceDescriptor); 122 } else { 123 System.out.println( 124 "META-INF service descriptor will not be created"); 125 } 126 127 if (moduleDescriptor != null) { 128 System.out.println(String.format( 129 "Creating Modular jar file '%s'", jarFile)); 130 createModularjar(jarFile, compilePath, 131 moduleDescriptor, Paths.get(".")); 132 } else { 133 System.out.println(String.format( 134 "Creating regular jar file '%s'", jarFile)); 135 JarUtils.createJarFile(jarFile, compilePath); 136 } 137 } 138 139 return done; 140 } 141 142 /** 143 * Generates a modular jar with module descriptor. 144 */ 145 public static void createModularjar(Path jarfile, Path compilePath, 146 ModuleDescriptor moduleDescriptor, Path... file) 147 throws IOException { 148 149 Path parent = jarfile.getParent(); 150 if (parent != null) { 151 Files.createDirectories(parent); 152 } 153 154 List<Path> entries = new ArrayList<>(); 155 for (Path entry : file) { 156 Files.find(compilePath.resolve(entry), Integer.MAX_VALUE, 157 (p, attrs) -> attrs.isRegularFile()) 158 .map(e -> compilePath.relativize(e)) 159 .forEach(entries::add); 160 } 161 try (JarOutputStream jos = new JarOutputStream( 162 Files.newOutputStream(jarfile))) { 163 JarEntry je = new JarEntry(MODULE_INFO_DESCRIPTOR); 164 jos.putNextEntry(je); 165 jdk.internal.module.ModuleInfoWriter.write(moduleDescriptor, jos); 166 jos.closeEntry(); 167 168 for (Path entry : entries) { 169 Path normalized = entry.normalize(); 170 String name = normalized 171 .subpath(0, normalized.getNameCount()) 172 .toString() 173 .replace(File.separatorChar, '/'); 174 175 jos.putNextEntry(new JarEntry(name)); 176 Files.copy(compilePath.resolve(entry), jos); 177 } 178 } 179 } 180 181 /** 182 * Generates a module descriptor for modular service component. 183 */ 184 public static ModuleDescriptor generateServiceModuleDescriptor( 185 MODULE_TYPE serviceModuletype, String moduleName, 186 String servicePkg, String serviceInterface, 187 String serviceImpl, List<String> requiredModules) { 188 189 final Builder builder; 190 if (serviceModuletype == MODULE_TYPE.STRICT) { 191 System.out.println("Generating ServiceModuleDescriptor object"); 192 builder = new Builder(moduleName) 193 .exports(servicePkg) 194 .provides(serviceInterface, serviceImpl); 195 } else { 196 System.out.println("ServiceModuleDescriptor object not required."); 197 return null; 198 } 199 requiredModules.stream().forEach( 200 reqMod -> builder.requires(reqMod)); 201 202 return builder.build(); 203 } 204 205 /** 206 * Generates a module descriptor for modular client component. 207 */ 208 public static ModuleDescriptor generateClientModuleDescriptor( 209 MODULE_TYPE clientModuleType, MODULE_TYPE serviceModuletype, 210 String moduleName, String clientPkg, String serviceInterface, 211 String serviceModuleName, List<String> requiredModules) { 212 213 final Builder builder; 214 if (clientModuleType == MODULE_TYPE.STRICT) { 215 System.out.println("Generating ClientModuleDescriptor object"); 216 builder = new Builder(moduleName) 217 .exports(clientPkg) 218 .uses(serviceInterface); 219 if (serviceModuletype == MODULE_TYPE.STRICT) { 220 builder.requires(serviceModuleName); 221 } 222 } else { 223 System.out.println("ClientModuleDescriptor object not required."); 224 return null; 225 } 226 requiredModules.stream().forEach( 227 reqMod -> builder.requires(reqMod)); 228 229 return builder.build(); 230 } 231 232 /** 233 * Generates service descriptor inside META-INF folder. 234 */ 235 public static void createMetaInfServiceDescriptor(Path serviceCompilePath, 236 String serviceImpl, Path metaServiceDescriptor) 237 throws UnsupportedEncodingException, IOException { 238 239 System.out.println(String.format("Creating META-INF service descriptor" 240 + " for '%s' at path '%s'", serviceImpl, serviceCompilePath)); 241 Path serviceDescriptorFilePath 242 = serviceCompilePath.resolve(metaServiceDescriptor); 243 Path parent = serviceDescriptorFilePath.getParent(); 244 if (parent != null) { 245 Files.createDirectories(parent); 246 } 247 Files.write(serviceDescriptorFilePath, serviceImpl.getBytes("UTF-8")); 248 System.out.println(String.format( 249 "META-INF service descriptor created successfully")); 250 } 251 252 }