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.invoker.mvn.resident;
20  
21  import java.util.ArrayList;
22  import java.util.concurrent.ConcurrentHashMap;
23  
24  import org.apache.maven.api.cli.InvokerException;
25  import org.apache.maven.api.cli.mvn.MavenInvokerRequest;
26  import org.apache.maven.api.cli.mvn.MavenOptions;
27  import org.apache.maven.api.cli.mvn.resident.ResidentMavenInvoker;
28  import org.apache.maven.cling.invoker.ProtoLookup;
29  import org.apache.maven.cling.invoker.mvn.DefaultMavenInvoker;
30  
31  /**
32   * Local invoker implementation, when Maven CLI is being run. System uses ClassWorld launcher, and class world
33   * instance is passed in via "enhanced" main method. Hence, this class expects fully setup ClassWorld via constructor.
34   */
35  public class DefaultResidentMavenInvoker
36          extends DefaultMavenInvoker<
37                  MavenOptions, MavenInvokerRequest<MavenOptions>, DefaultResidentMavenInvoker.LocalContext>
38          implements ResidentMavenInvoker {
39  
40      public static class LocalContext
41              extends DefaultMavenInvoker.MavenContext<
42                      MavenOptions, MavenInvokerRequest<MavenOptions>, DefaultResidentMavenInvoker.LocalContext> {
43  
44          protected LocalContext(DefaultResidentMavenInvoker invoker, MavenInvokerRequest<MavenOptions> invokerRequest) {
45              super(invoker, invokerRequest);
46          }
47  
48          @Override
49          public void close() throws InvokerException {
50              // we are resident, we do not shut down here
51          }
52  
53          public void shutDown() throws InvokerException {
54              super.close();
55          }
56  
57          public LocalContext copy(MavenInvokerRequest<MavenOptions> invokerRequest) {
58              if (invokerRequest == this.invokerRequest) {
59                  return this;
60              }
61              LocalContext shadow = new LocalContext((DefaultResidentMavenInvoker) invoker, invokerRequest);
62  
63              shadow.logger = logger;
64              shadow.loggerFactory = loggerFactory;
65              shadow.loggerLevel = loggerLevel;
66              shadow.containerCapsule = containerCapsule;
67              shadow.lookup = lookup;
68              shadow.settingsBuilder = settingsBuilder;
69  
70              shadow.interactive = interactive;
71              shadow.localRepositoryPath = localRepositoryPath;
72              shadow.installationSettingsPath = installationSettingsPath;
73              shadow.projectSettingsPath = projectSettingsPath;
74              shadow.userSettingsPath = userSettingsPath;
75              shadow.effectiveSettings = effectiveSettings;
76  
77              shadow.mavenExecutionRequest = mavenExecutionRequest;
78              shadow.eventSpyDispatcher = eventSpyDispatcher;
79              shadow.mavenExecutionRequestPopulator = mavenExecutionRequestPopulator;
80              shadow.toolchainsBuilder = toolchainsBuilder;
81              shadow.modelProcessor = modelProcessor;
82              shadow.maven = maven;
83  
84              return shadow;
85          }
86      }
87  
88      private final ConcurrentHashMap<String, LocalContext> residentContext;
89  
90      public DefaultResidentMavenInvoker(ProtoLookup protoLookup) {
91          super(protoLookup);
92          this.residentContext = new ConcurrentHashMap<>();
93      }
94  
95      @Override
96      public void close() throws InvokerException {
97          ArrayList<InvokerException> exceptions = new ArrayList<>();
98          for (LocalContext context : residentContext.values()) {
99              try {
100                 context.shutDown();
101             } catch (InvokerException e) {
102                 exceptions.add(e);
103             }
104         }
105         if (!exceptions.isEmpty()) {
106             InvokerException exception = new InvokerException("Could not cleanly shut down context pool");
107             exceptions.forEach(exception::addSuppressed);
108             throw exception;
109         }
110     }
111 
112     @Override
113     protected LocalContext createContext(MavenInvokerRequest<MavenOptions> invokerRequest) {
114         return residentContext
115                 .computeIfAbsent(getContextId(invokerRequest), k -> new LocalContext(this, invokerRequest))
116                 .copy(invokerRequest);
117     }
118 
119     protected String getContextId(MavenInvokerRequest<MavenOptions> invokerRequest) {
120         // TODO: in a moment Maven stop pushing user properties to system properties (and maybe something more)
121         // and allow multiple instances per JVM, this may become a pool?
122         return "resident";
123     }
124 
125     @Override
126     protected void container(LocalContext context) throws Exception {
127         if (context.containerCapsule == null) {
128             super.container(context);
129         }
130     }
131 
132     @Override
133     protected void lookup(LocalContext context) throws Exception {
134         if (context.maven == null) {
135             super.lookup(context);
136         }
137     }
138 }