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 }