001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.xbean.kernel.standard; 018 019 import java.util.ArrayList; 020 import java.util.HashMap; 021 import java.util.HashSet; 022 import java.util.Iterator; 023 import java.util.List; 024 import java.util.Map; 025 import java.util.Set; 026 027 import java.util.concurrent.locks.Condition; 028 import java.util.concurrent.locks.Lock; 029 import org.apache.xbean.kernel.Kernel; 030 import org.apache.xbean.kernel.ServiceCondition; 031 import org.apache.xbean.kernel.ServiceName; 032 033 /** 034 * Aggregates a set of ServiceConditions together so the ServiceManager can treat them as a single unit. 035 * 036 * @author Dain Sundstrom 037 * @version $Id$ 038 * @since 2.0 039 */ 040 public class AggregateCondition { 041 private final Kernel kernel; 042 private final ServiceName serviceName; 043 private final ClassLoader classLoader; 044 private final Lock lock; 045 private final Map conditions = new HashMap(); 046 private final Condition satisfiedSignal; 047 private boolean destroyed = false; 048 049 /** 050 * Creates an aggregate condition. 051 * 052 * @param kernel the kernel in which the service is registered 053 * @param serviceName the name of the service 054 * @param classLoader the class loader for the service 055 * @param lock the lock for the service manager 056 * @param conditions the conditions 057 */ 058 public AggregateCondition(Kernel kernel, ServiceName serviceName, ClassLoader classLoader, Lock lock, Set conditions) { 059 this.kernel = kernel; 060 this.serviceName = serviceName; 061 this.classLoader = classLoader; 062 this.lock = lock; 063 satisfiedSignal = lock.newCondition(); 064 065 // add the conditions to the registry 066 if (conditions == null) throw new NullPointerException("conditions is null"); 067 for (Iterator iterator = conditions.iterator(); iterator.hasNext();) { 068 ServiceCondition serviceCondition = (ServiceCondition) iterator.next(); 069 addCondition(serviceCondition); 070 } 071 } 072 073 /** 074 * Gets a snapshot of the current conditions. 075 * 076 * @return a snapshot of the current conditions 077 */ 078 protected Set getConditions() { 079 return new HashSet(conditions.keySet()); 080 } 081 082 /** 083 * Adds a new condition if not already registered. 084 * 085 * @param condition the new condition 086 */ 087 protected final void addCondition(ServiceCondition condition) { 088 if (!conditions.containsKey(condition)) { 089 StandardServiceConditionContext context = new StandardServiceConditionContext(kernel, serviceName, classLoader, lock, satisfiedSignal); 090 condition.initialize(context); 091 conditions.put(condition, context); 092 } 093 } 094 095 /** 096 * Removes a condition from the registry if present. 097 * 098 * @param condition the condition to remove 099 */ 100 protected final void removeCondition(ServiceCondition condition) { 101 if (conditions.remove(condition) != null) { 102 condition.destroy(); 103 } 104 } 105 106 /** 107 * Initializes the conditions. 108 */ 109 public void initialize() { 110 if (destroyed) throw new IllegalStateException("destroyed"); 111 112 for (Iterator iterator = conditions.entrySet().iterator(); iterator.hasNext();) { 113 Map.Entry entry = (Map.Entry) iterator.next(); 114 ServiceCondition condition = (ServiceCondition) entry.getKey(); 115 StandardServiceConditionContext context = (StandardServiceConditionContext) entry.getValue(); 116 condition.initialize(context); 117 } 118 } 119 120 /** 121 * Gets the unsatisfied conditions. 122 * 123 * @return the unstatisfied conditions 124 */ 125 public Set getUnsatisfied() { 126 if (destroyed) throw new IllegalStateException("destroyed"); 127 128 Set unsatisfied = new HashSet(); 129 for (Iterator iterator = conditions.entrySet().iterator(); iterator.hasNext();) { 130 Map.Entry entry = (Map.Entry) iterator.next(); 131 ServiceCondition condition = (ServiceCondition) entry.getKey(); 132 StandardServiceConditionContext context = (StandardServiceConditionContext) entry.getValue(); 133 if (!context.isSatisfied()) { 134 if (condition.isSatisfied()) { 135 // the condition is satisfied 136 // record this fact in the context 137 context.setSatisfied(); 138 } else { 139 unsatisfied.add(condition); 140 } 141 } 142 } 143 144 // notify anyone awaiting satisfaction 145 if (unsatisfied.isEmpty()) { 146 satisfiedSignal.signalAll(); 147 } 148 return unsatisfied; 149 } 150 151 /** 152 * Gets the destroyed status. 153 * 154 * @return true if this AggregateCondition been destroyed; false otherwise 155 */ 156 public boolean isDestroyed() { 157 return destroyed; 158 } 159 160 /** 161 * Destroys all condtions. 162 * 163 * @return a list of the Exceptions or Errors that occured while destroying the conditon objects. 164 */ 165 public List destroy() { 166 List stopErrors = new ArrayList(); 167 if (!destroyed) { 168 destroyed = true; 169 for (Iterator iterator = conditions.keySet().iterator(); iterator.hasNext();) { 170 ServiceCondition condition = (ServiceCondition) iterator.next(); 171 try { 172 condition.destroy(); 173 } catch (RuntimeException stopError) { 174 stopErrors.add(stopError); 175 } catch (Error stopError) { 176 stopErrors.add(stopError); 177 } 178 } 179 // notify anyone awaiting satisfaction 180 satisfiedSignal.signalAll(); 181 } 182 return stopErrors; 183 } 184 185 /** 186 * Causes the current thread to wait until the conditons is satisfied. 187 * 188 * @throws InterruptedException if the thread is interrupted 189 */ 190 public void awaitSatisfaction() throws InterruptedException { 191 while (!destroyed) { 192 if (getUnsatisfied().isEmpty()) { 193 return; 194 } 195 satisfiedSignal.await(); 196 } 197 } 198 }