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.geronimo.kernel.config;
018    
019    import java.util.LinkedHashSet;
020    import java.util.Iterator;
021    import java.util.Set;
022    
023    import org.apache.geronimo.kernel.repository.Artifact;
024    
025    /**
026     * @version $Rev: 476049 $ $Date: 2006-11-16 23:35:17 -0500 (Thu, 16 Nov 2006) $
027     */
028    public class ConfigurationStatus {
029        private Artifact configurationId;
030        private final Set loadParents = new LinkedHashSet();
031        private final Set startParents = new LinkedHashSet();
032        private final LinkedHashSet loadChildren = new LinkedHashSet();
033        private final LinkedHashSet startChildren = new LinkedHashSet();
034        private boolean loaded = false;
035        private boolean started = false;
036        private boolean userLoaded = false;
037        private boolean userStarted = false;
038    
039        public ConfigurationStatus(Artifact configId, Set loadParents, Set startParents) {
040            if (configId == null) throw new NullPointerException("configId is null");
041            if (loadParents == null) throw new NullPointerException("loadParents is null");
042            if (startParents == null) throw new NullPointerException("startParents is null");
043            if (!loadParents.containsAll(startParents)) {
044                throw new IllegalArgumentException("loadParents must contain all startParents");
045            }
046            this.configurationId = configId;
047            this.loadParents.addAll(loadParents);
048            this.startParents.addAll(startParents);
049    
050            for (Iterator iterator = loadParents.iterator(); iterator.hasNext();) {
051                ConfigurationStatus loadParent = (ConfigurationStatus) iterator.next();
052                loadParent.loadChildren.add(this);
053            }
054    
055            for (Iterator iterator = startParents.iterator(); iterator.hasNext();) {
056                ConfigurationStatus startParent = (ConfigurationStatus) iterator.next();
057                startParent.startChildren.add(this);
058            }
059        }
060    
061        public void destroy() {
062            if (started) {
063                throw new IllegalStateException("Configuration " + configurationId + " is still running");
064            }
065            if (loaded) {
066                throw new IllegalStateException("Configuration " + configurationId + " is still loaded");
067            }
068            if (loadChildren.size() > 0 || startChildren.size() > 0) {
069                throw new IllegalStateException("Configuration " + configurationId + " still has children");
070            }
071    
072            for (Iterator iterator = loadParents.iterator(); iterator.hasNext();) {
073                ConfigurationStatus loadParent = (ConfigurationStatus) iterator.next();
074                loadParent.loadChildren.remove(this);
075            }
076            loadParents.clear();
077    
078            for (Iterator iterator = startParents.iterator(); iterator.hasNext();) {
079                ConfigurationStatus startParent = (ConfigurationStatus) iterator.next();
080                startParent.startChildren.remove(this);
081            }
082            startChildren.clear();
083        }
084    
085        public Artifact getConfigurationId() {
086            return configurationId;
087        }
088    
089        public boolean isLoaded() {
090            return loaded;
091        }
092    
093        public boolean isStarted() {
094            return started;
095        }
096    
097        public boolean isUserLoaded() {
098            return userLoaded;
099        }
100    
101        public boolean isUserStarted() {
102            return userStarted;
103        }
104    
105    
106        public void upgrade(Artifact newId, Set newLoadParents, Set newStartParents) {
107            this.configurationId = newId;
108    
109            //
110            // remove links from the current parents to me
111            //
112            for (Iterator iterator = loadParents.iterator(); iterator.hasNext();) {
113                ConfigurationStatus loadParent = (ConfigurationStatus) iterator.next();
114                loadParent.loadChildren.remove(this);
115            }
116            loadParents.clear();
117    
118            for (Iterator iterator = startParents.iterator(); iterator.hasNext();) {
119                ConfigurationStatus startParent = (ConfigurationStatus) iterator.next();
120                startParent.startChildren.remove(this);
121            }
122            startChildren.clear();
123    
124            //
125            // connect to to the new parents
126            //
127            this.loadParents.addAll(newLoadParents);
128            this.startParents.addAll(newStartParents);
129    
130            for (Iterator iterator = loadParents.iterator(); iterator.hasNext();) {
131                ConfigurationStatus loadParent = (ConfigurationStatus) iterator.next();
132                loadParent.loadChildren.add(this);
133            }
134    
135            for (Iterator iterator = startParents.iterator(); iterator.hasNext();) {
136                ConfigurationStatus startParent = (ConfigurationStatus) iterator.next();
137                startParent.startChildren.add(this);
138            }
139        }
140    
141        public LinkedHashSet load() {
142            LinkedHashSet loadList = new LinkedHashSet();
143            loadInternal(loadList);
144            userLoaded = true;
145            return loadList;
146        }
147    
148        private void loadInternal(LinkedHashSet loadList) {
149            // visit all unloaded parents
150            for (Iterator iterator = loadParents.iterator(); iterator.hasNext();) {
151                ConfigurationStatus parent = (ConfigurationStatus) iterator.next();
152                if (!parent.isLoaded()) {
153                    parent.loadInternal(loadList);
154                }
155            }
156    
157            if (!loaded) {
158                loadList.add(configurationId);
159                loaded = true;
160            }
161        }
162    
163    
164        public LinkedHashSet start() {
165            if (!loaded) {
166                throw new IllegalStateException(configurationId + " is not loaded");
167            }
168            LinkedHashSet startList = new LinkedHashSet();
169            startInternal(startList);
170            userLoaded = true;
171            userStarted = true;
172            return startList;
173        }
174    
175        private void startInternal(LinkedHashSet startList) {
176            // visit all stopped parents
177            for (Iterator iterator = startParents.iterator(); iterator.hasNext();) {
178                ConfigurationStatus parent = (ConfigurationStatus) iterator.next();
179                if (!parent.isStarted()) {
180                    parent.startInternal(startList);
181                }
182            }
183    
184            if (!started) {
185                startList.add(configurationId);
186                started = true;
187            }
188        }
189    
190        /**
191         * Stop this configuration and its children (if it's running) or do nothing
192         * (if it's not running).
193         */
194        public LinkedHashSet stop(boolean gc) {
195            LinkedHashSet stopStatuses = new LinkedHashSet();
196            stopInternal(stopStatuses, gc);
197    
198            LinkedHashSet stopIds = new LinkedHashSet(stopStatuses.size());
199            for (Iterator iterator = stopStatuses.iterator(); iterator.hasNext();) {
200                ConfigurationStatus configurationStatus = (ConfigurationStatus) iterator.next();
201                stopIds.add(configurationStatus.configurationId);
202            }
203    
204            return stopIds;
205        }
206    
207        private void stopInternal(LinkedHashSet stopList, boolean gc) {
208            // if we aren't started, there is nothing to do
209            if (!started) {
210                return;
211            }
212    
213            // visit all children
214            for (Iterator iterator = startChildren.iterator(); iterator.hasNext();) {
215                ConfigurationStatus child = (ConfigurationStatus) iterator.next();
216                if (child.isStarted()) {
217                    child.stopInternal(stopList, gc);
218                }
219            }
220    
221            // mark this node as stoped, and add this node to the stop list
222            if (started) {
223                started = false;
224                userStarted = false;
225                stopList.add(this);
226    
227                // if we are garbage collecting, visit parents
228                if (gc) {
229                    // visit all non-user started parents that haven't already been visited
230                    for (Iterator iterator = startParents.iterator(); iterator.hasNext();) {
231                        ConfigurationStatus parent = (ConfigurationStatus) iterator.next();
232                        if (!parent.isUserStarted() && stopList.containsAll(parent.startChildren)) {
233                            parent.stopInternal(stopList, gc);
234                        }
235                    }
236                }
237            }
238        }
239    
240        public LinkedHashSet restart() {
241            if (!started) {
242                throw new IllegalStateException(configurationId + " is not started");
243            }
244    
245            LinkedHashSet restartStatuses = new LinkedHashSet();
246            restartInternal(restartStatuses);
247    
248            LinkedHashSet restartIds = new LinkedHashSet(restartStatuses.size());
249            for (Iterator iterator = restartStatuses.iterator(); iterator.hasNext();) {
250                ConfigurationStatus configurationStatus = (ConfigurationStatus) iterator.next();
251                restartIds.add(configurationStatus.configurationId);
252            }
253    
254            userLoaded = true;
255            userStarted = true;
256            return restartIds;
257        }
258    
259        private void restartInternal(LinkedHashSet restartList) {
260            // if we aren't started, there is nothing to do
261            if (!started) {
262                return;
263            }
264    
265            // visit all children
266            for (Iterator iterator = startChildren.iterator(); iterator.hasNext();) {
267                ConfigurationStatus child = (ConfigurationStatus) iterator.next();
268                if (child.isStarted()) {
269                    child.restartInternal(restartList);
270                }
271            }
272    
273            // add this node to the restart list
274            restartList.add(this);
275        }
276    
277        /**
278         * Unload the configuration and all its children (if it's loaded), or do
279         * nothing (if it's not loaded).
280         */
281        public LinkedHashSet unload(boolean gc) {
282    
283            LinkedHashSet unloadStatuses = new LinkedHashSet();
284            unloadInternal(unloadStatuses, gc);
285    
286            LinkedHashSet unloadIds = new LinkedHashSet(unloadStatuses.size());
287            for (Iterator iterator = unloadStatuses.iterator(); iterator.hasNext();) {
288                ConfigurationStatus configurationStatus = (ConfigurationStatus) iterator.next();
289                unloadIds.add(configurationStatus.configurationId);
290            }
291    
292            return unloadIds;
293        }
294    
295        private void unloadInternal(LinkedHashSet unloadList, boolean gc) {
296            // if we aren't loaded, there is nothing to do
297            if (!loaded) {
298                return;
299            }
300    
301            // visit all loaded children
302            for (Iterator iterator = loadChildren.iterator(); iterator.hasNext();) {
303                ConfigurationStatus child = (ConfigurationStatus) iterator.next();
304                if (child.isLoaded()) {
305                    child.unloadInternal(unloadList, gc);
306                }
307            }
308    
309            // mark this node as unloaded, and add this node to the unload list
310            if (loaded) {
311                started = false;
312                userStarted = false;
313                loaded = false;
314                userLoaded = false;
315                unloadList.add(this);
316    
317                // if we are garbage collecting, visit parents
318                if (gc) {
319                    // visit all non-user loaded parents
320                    for (Iterator iterator = loadParents.iterator(); iterator.hasNext();) {
321                        ConfigurationStatus parent = (ConfigurationStatus) iterator.next();
322                        if (!parent.isUserLoaded() && unloadList.containsAll(parent.loadChildren)) {
323                            parent.unloadInternal(unloadList, gc);
324                        }
325                    }
326                }
327            }
328        }
329    
330        public LinkedHashSet reload() {
331            if (!loaded) {
332                throw new IllegalStateException(configurationId + " is not loaded");
333            }
334    
335            LinkedHashSet reloadStatuses = new LinkedHashSet();
336            reloadInternal(reloadStatuses);
337    
338            LinkedHashSet reloadIds = new LinkedHashSet(reloadStatuses.size());
339            for (Iterator iterator = reloadStatuses.iterator(); iterator.hasNext();) {
340                ConfigurationStatus configurationStatus = (ConfigurationStatus) iterator.next();
341                reloadIds.add(configurationStatus.configurationId);
342            }
343    
344            userLoaded = true;
345            return reloadIds;
346        }
347    
348        private void reloadInternal(LinkedHashSet reloadList) {
349            // if we aren't loaded, there is nothing to do
350            if (!loaded) {
351                return;
352            }
353    
354            // visit all children
355            for (Iterator iterator = loadChildren.iterator(); iterator.hasNext();) {
356                ConfigurationStatus child = (ConfigurationStatus) iterator.next();
357                if (child.isLoaded()) {
358                    child.reloadInternal(reloadList);
359                }
360            }
361    
362            // add this node to the reload list
363            reloadList.add(this);
364        }
365    
366        public String toString() {
367            String load;
368            if (userLoaded) {
369                load = "user-loaded";
370            } else if (loaded) {
371                load = "loaded";
372            } else {
373                load = "not-loaded";
374            }
375            String start;
376            if (userLoaded) {
377                start = "user-started";
378            } else if (loaded) {
379                start = "started";
380            } else {
381                start = "not-started";
382            }
383            return "[" + configurationId + " " + load + " " + start + "]";
384        }
385    }