001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.eclipse.aether.internal.impl; 020 021import javax.inject.Inject; 022import javax.inject.Named; 023import javax.inject.Singleton; 024 025import java.util.ArrayList; 026import java.util.Map; 027import java.util.concurrent.ConcurrentHashMap; 028import java.util.concurrent.CopyOnWriteArrayList; 029import java.util.concurrent.atomic.AtomicBoolean; 030 031import org.eclipse.aether.MultiRuntimeException; 032import org.eclipse.aether.RepositorySystemSession.CloseableSession; 033import org.eclipse.aether.impl.RepositorySystemLifecycle; 034 035import static java.util.Objects.requireNonNull; 036 037/** 038 * 039 */ 040@Singleton 041@Named 042public class DefaultRepositorySystemLifecycle implements RepositorySystemLifecycle { 043 private final AtomicBoolean shutdown; 044 045 private final CopyOnWriteArrayList<Runnable> onSystemEndedHandlers; 046 047 private final ConcurrentHashMap<String, CopyOnWriteArrayList<Runnable>> onSessionEndedHandlers; 048 049 @Inject 050 public DefaultRepositorySystemLifecycle() { 051 this.shutdown = new AtomicBoolean(false); 052 this.onSystemEndedHandlers = new CopyOnWriteArrayList<>(); 053 this.onSessionEndedHandlers = new ConcurrentHashMap<>(); 054 } 055 056 @Override 057 public void systemEnded() { 058 final ArrayList<Exception> exceptions = new ArrayList<>(); 059 if (shutdown.compareAndSet(false, true)) { 060 for (Map.Entry<String, CopyOnWriteArrayList<Runnable>> sessionEndedHandlers : 061 onSessionEndedHandlers.entrySet()) { 062 IllegalStateException sessionNotClosed = 063 new IllegalStateException("Session " + sessionEndedHandlers.getKey() + " not closed"); 064 exceptions.add(sessionNotClosed); 065 for (Runnable onCloseHandler : sessionEndedHandlers.getValue()) { 066 try { 067 onCloseHandler.run(); 068 } catch (Exception e) { 069 sessionNotClosed.addSuppressed(e); 070 } 071 } 072 } 073 for (Runnable onCloseHandler : onSystemEndedHandlers) { 074 try { 075 onCloseHandler.run(); 076 } catch (Exception e) { 077 exceptions.add(e); 078 } 079 } 080 MultiRuntimeException.mayThrow("system on-close handler failures", exceptions); 081 } 082 } 083 084 @Override 085 public void addOnSystemEndedHandler(Runnable handler) { 086 requireNonNull(handler, "handler cannot be null"); 087 requireNotShutdown(); 088 onSystemEndedHandlers.add(0, handler); 089 } 090 091 @Override 092 public void sessionStarted(CloseableSession session) { 093 requireNonNull(session, "session cannot be null"); 094 requireNotShutdown(); 095 String sessionId = session.sessionId(); 096 onSessionEndedHandlers.compute(sessionId, (k, v) -> { 097 if (v != null) { 098 throw new IllegalStateException("session instance already registered"); 099 } 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}