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.cling;
20  
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.io.OutputStream;
24  
25  import org.apache.maven.api.annotations.Nullable;
26  import org.apache.maven.api.cli.Invoker;
27  import org.apache.maven.api.cli.InvokerException;
28  import org.apache.maven.api.cli.Parser;
29  import org.apache.maven.api.cli.ParserRequest;
30  import org.apache.maven.api.services.MessageBuilderFactory;
31  import org.apache.maven.cling.invoker.logging.SystemLogger;
32  import org.apache.maven.jline.JLineMessageBuilderFactory;
33  import org.codehaus.plexus.classworlds.ClassWorld;
34  
35  import static java.util.Objects.requireNonNull;
36  
37  /**
38   * The CLI "new-gen".
39   */
40  public abstract class ClingSupport {
41      static final String CORE_CLASS_REALM_ID = "plexus.core";
42  
43      protected final ClassWorld classWorld;
44      protected final boolean classWorldManaged;
45  
46      /**
47       * Ctor that creates "managed" ClassWorld. This constructor is not used in "normal" circumstances.
48       */
49      public ClingSupport() {
50          this(new ClassWorld(CORE_CLASS_REALM_ID, Thread.currentThread().getContextClassLoader()), true);
51      }
52  
53      /**
54       * Ctor to be used when running in ClassWorlds Launcher.
55       */
56      public ClingSupport(ClassWorld classWorld) {
57          this(classWorld, false);
58      }
59  
60      private ClingSupport(ClassWorld classWorld, boolean classWorldManaged) {
61          this.classWorld = requireNonNull(classWorld);
62          this.classWorldManaged = classWorldManaged;
63      }
64  
65      /**
66       * The main entry point.
67       */
68      public int run(
69              String[] args,
70              @Nullable InputStream stdIn,
71              @Nullable OutputStream stdOut,
72              @Nullable OutputStream stdErr,
73              boolean embedded)
74              throws IOException {
75          try (Invoker invoker = createInvoker()) {
76              return invoker.invoke(createParser()
77                      .parseInvocation(createParserRequestBuilder(args)
78                              .stdIn(stdIn)
79                              .stdOut(stdOut)
80                              .stdErr(stdErr)
81                              .embedded(embedded)
82                              .build()));
83          } catch (InvokerException.ExitException e) {
84              return e.getExitCode();
85          } catch (Exception e) {
86              // last resort; as ideally we should get ExitException only
87              new SystemLogger(stdErr).error(e.getMessage(), e);
88              return 1;
89          } finally {
90              if (classWorldManaged) {
91                  classWorld.close();
92              }
93          }
94      }
95  
96      protected MessageBuilderFactory createMessageBuilderFactory() {
97          return new JLineMessageBuilderFactory();
98      }
99  
100     protected abstract Invoker createInvoker();
101 
102     protected abstract Parser createParser();
103 
104     protected abstract ParserRequest.Builder createParserRequestBuilder(String[] args);
105 }