View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.plugins.jlink;
20  
21  /*
22   * Licensed to the Apache Software Foundation (ASF) under one
23   * or more contributor license agreements.  See the NOTICE file
24   * distributed with this work for additional information
25   * regarding copyright ownership.  The ASF licenses this file
26   * to you under the Apache License, Version 2.0 (the
27   * "License"); you may not use this file except in compliance
28   * with the License.  You may obtain a copy of the License at
29   *
30   *   http://www.apache.org/licenses/LICENSE-2.0
31   *
32   * Unless required by applicable law or agreed to in writing,
33   * software distributed under the License is distributed on an
34   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
35   * KIND, either express or implied.  See the License for the
36   * specific language governing permissions and limitations
37   * under the License.
38   */
39  
40  import java.io.File;
41  import java.io.IOException;
42  import java.io.PrintWriter;
43  import java.io.StringWriter;
44  import java.util.List;
45  import java.util.Optional;
46  import java.util.spi.ToolProvider;
47  
48  import org.apache.maven.plugin.MojoExecutionException;
49  import org.apache.maven.plugin.logging.Log;
50  import org.apache.maven.toolchain.Toolchain;
51  
52  /**
53   * JDK9+ executor for jlink.
54   *
55   * <p>This implementation uses the JDK9+ Toolprovider SPI to find and execute jlink.
56   * This way, no fork needs to be created.</p>
57   */
58  class JLinkExecutor extends AbstractJLinkToolchainExecutor {
59      private final ToolProvider toolProvider;
60  
61      JLinkExecutor(Toolchain toolchain, Log log) {
62          super(toolchain, log);
63          this.toolProvider = getJLinkExecutable();
64      }
65  
66      protected final ToolProvider getJLinkExecutable() {
67          return ToolProvider.findFirst("jlink").orElseThrow(() -> new IllegalStateException("No jlink tool found."));
68      }
69  
70      @Override
71      public int executeJlink(List<String> jlinkArgs) throws MojoExecutionException {
72          if (getToolchain().isPresent()) {
73              return super.executeJlink(jlinkArgs);
74          }
75  
76          if (getLog().isDebugEnabled()) {
77              // no quoted arguments ???
78              getLog().debug(this.toolProvider.name() + " " + jlinkArgs);
79          }
80  
81          try (StringWriter strErr = new StringWriter();
82                  PrintWriter err = new PrintWriter(strErr);
83                  StringWriter strOut = new StringWriter();
84                  PrintWriter out = new PrintWriter(strOut)) {
85              int exitCode = this.toolProvider.run(out, err, jlinkArgs.toArray(new String[0]));
86              out.flush();
87              err.flush();
88  
89              String outAsString = strOut.toString();
90              String output = outAsString.isBlank() ? null : '\n' + outAsString.trim();
91  
92              if (exitCode != 0) {
93                  if (output != null && !output.isBlank()) {
94                      // Reconsider to use WARN / ERROR ?
95                      //  getLog().error( output );
96                      for (String outputLine : output.split("\n")) {
97                          getLog().error(outputLine);
98                      }
99                  }
100 
101                 StringBuilder msg = new StringBuilder("\nExit code: ");
102                 msg.append(exitCode);
103                 String errAsString = strErr.toString();
104                 if (errAsString != null && !errAsString.isBlank()) {
105                     msg.append(" - ").append(errAsString);
106                 }
107                 msg.append('\n');
108                 msg.append("Command line was: ")
109                         .append(this.toolProvider.name())
110                         .append(' ')
111                         .append(jlinkArgs)
112                         .append('\n')
113                         .append('\n');
114 
115                 throw new MojoExecutionException(msg.toString());
116             }
117 
118             if (output != null && !output.isBlank()) {
119                 // getLog().info( output );
120                 for (String outputLine : output.split("\n")) {
121                     getLog().info(outputLine);
122                 }
123             }
124 
125             return exitCode;
126         } catch (IOException e) {
127             throw new MojoExecutionException("Unable to execute jlink command: " + e.getMessage(), e);
128         }
129     }
130 
131     @Override
132     public Optional<File> getJmodsFolder(/* nullable */ File sourceJdkModules) {
133         if (getToolchain().isPresent()) {
134             return super.getJmodsFolder(sourceJdkModules);
135         }
136 
137         if (sourceJdkModules != null && sourceJdkModules.isDirectory()) {
138             return Optional.of(new File(sourceJdkModules, JMODS));
139         }
140 
141         // ToolProvider does not need jmods folder to be set.
142         return Optional.empty();
143     }
144 }