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.eclipse.aether.internal.impl;
20  
21  import javax.inject.Inject;
22  import javax.inject.Named;
23  import javax.inject.Singleton;
24  
25  import java.util.ArrayList;
26  import java.util.Map;
27  import java.util.concurrent.ConcurrentHashMap;
28  import java.util.concurrent.CopyOnWriteArrayList;
29  import java.util.concurrent.atomic.AtomicBoolean;
30  
31  import org.eclipse.aether.MultiRuntimeException;
32  import org.eclipse.aether.RepositorySystemSession.CloseableSession;
33  import org.eclipse.aether.impl.RepositorySystemLifecycle;
34  
35  import static java.util.Objects.requireNonNull;
36  
37  /**
38   *
39   */
40  @Singleton
41  @Named
42  public class DefaultRepositorySystemLifecycle implements RepositorySystemLifecycle {
43      private final AtomicBoolean shutdown;
44  
45      private final CopyOnWriteArrayList<Runnable> onSystemEndedHandlers;
46  
47      private final ConcurrentHashMap<String, CopyOnWriteArrayList<Runnable>> onSessionEndedHandlers;
48  
49      @Inject
50      public DefaultRepositorySystemLifecycle() {
51          this.shutdown = new AtomicBoolean(false);
52          this.onSystemEndedHandlers = new CopyOnWriteArrayList<>();
53          this.onSessionEndedHandlers = new ConcurrentHashMap<>();
54      }
55  
56      @Override
57      public void systemEnded() {
58          final ArrayList<Exception> exceptions = new ArrayList<>();
59          if (shutdown.compareAndSet(false, true)) {
60              for (Map.Entry<String, CopyOnWriteArrayList<Runnable>> sessionEndedHandlers :
61                      onSessionEndedHandlers.entrySet()) {
62                  IllegalStateException sessionNotClosed =
63                          new IllegalStateException("Session " + sessionEndedHandlers.getKey() + " not closed");
64                  exceptions.add(sessionNotClosed);
65                  for (Runnable onCloseHandler : sessionEndedHandlers.getValue()) {
66                      try {
67                          onCloseHandler.run();
68                      } catch (Exception e) {
69                          sessionNotClosed.addSuppressed(e);
70                      }
71                  }
72              }
73              for (Runnable onCloseHandler : onSystemEndedHandlers) {
74                  try {
75                      onCloseHandler.run();
76                  } catch (Exception e) {
77                      exceptions.add(e);
78                  }
79              }
80              MultiRuntimeException.mayThrow("system on-close handler failures", exceptions);
81          }
82      }
83  
84      @Override
85      public void addOnSystemEndedHandler(Runnable handler) {
86          requireNonNull(handler, "handler cannot be null");
87          requireNotShutdown();
88          onSystemEndedHandlers.add(0, handler);
89      }
90  
91      @Override
92      public void sessionStarted(CloseableSession session) {
93          requireNonNull(session, "session cannot be null");
94          requireNotShutdown();
95          String sessionId = session.sessionId();
96          onSessionEndedHandlers.compute(sessionId, (k, v) -> {
97              if (v != null) {
98                  throw new IllegalStateException("session instance already registered");
99              }
100             return new CopyOnWriteArrayList<>();
101         });
102     }
103 
104     @Override
105     public void sessionEnded(CloseableSession session) {
106         requireNonNull(session, "session cannot be null");
107         requireNotShutdown();
108         String sessionId = session.sessionId();
109         ArrayList<Runnable> handlers = new ArrayList<>();
110         onSessionEndedHandlers.compute(sessionId, (k, v) -> {
111             if (v == null) {
112                 throw new IllegalStateException("session instance not registered");
113             }
114             handlers.addAll(v);
115             return null;
116         });
117 
118         ArrayList<Exception> exceptions = new ArrayList<>();
119         for (Runnable handler : handlers) {
120             try {
121                 handler.run();
122             } catch (Exception e) {
123                 exceptions.add(e);
124             }
125         }
126         MultiRuntimeException.mayThrow("sessionEnded handler issue(s)", exceptions);
127     }
128 
129     @Override
130     public void addOnSessionEndedHandle(CloseableSession session, Runnable handler) {
131         requireNonNull(session, "session cannot be null");
132         requireNonNull(handler, "handler cannot be null");
133         requireNotShutdown();
134         String sessionId = session.sessionId();
135         onSessionEndedHandlers.compute(sessionId, (k, v) -> {
136             if (v == null) {
137                 throw new IllegalStateException("session instance not registered");
138             }
139             v.add(handler);
140             return v;
141         });
142     }
143 
144     private void requireNotShutdown() {
145         if (shutdown.get()) {
146             throw new IllegalStateException("repository system is already shut down");
147         }
148     }
149 }