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: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
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 LinkedHashSet getStartedChildren() {
090            LinkedHashSet childrenStatuses = new LinkedHashSet();
091            getStartedChildrenInternal(childrenStatuses);
092    
093            LinkedHashSet childrenIds = new LinkedHashSet(childrenStatuses.size());
094            for (Iterator iterator = childrenStatuses.iterator(); iterator.hasNext();) {
095                ConfigurationStatus configurationStatus = (ConfigurationStatus) iterator.next();
096                childrenIds.add(configurationStatus.configurationId);
097            }
098    
099            return childrenIds;
100        }
101    
102        private void getStartedChildrenInternal(LinkedHashSet childrenStatuses) {
103            // if we aren't started, there is nothing to do
104            if (!started) {
105                return;
106            }
107    
108            // visit all children
109            for (Iterator iterator = startChildren.iterator(); iterator.hasNext();) {
110                ConfigurationStatus child = (ConfigurationStatus) iterator.next();
111                if (child.isStarted() && !child.configurationId.equals(configurationId)) {
112                    child.getStartedChildrenInternal(childrenStatuses);
113                }
114            }
115            childrenStatuses.add(this);
116        }
117    
118        public boolean isLoaded() {
119            return loaded;
120        }
121    
122        public boolean isStarted() {
123            return started;
124        }
125    
126        public boolean isUserLoaded() {
127            return userLoaded;
128        }
129    
130        public boolean isUserStarted() {
131            return userStarted;
132        }
133    
134    
135        public void upgrade(Artifact newId, Set newLoadParents, Set newStartParents) {
136            this.configurationId = newId;
137    
138            //
139            // remove links from the current parents to me
140            //
141            for (Iterator iterator = loadParents.iterator(); iterator.hasNext();) {
142                ConfigurationStatus loadParent = (ConfigurationStatus) iterator.next();
143                loadParent.loadChildren.remove(this);
144            }
145            loadParents.clear();
146    
147            for (Iterator iterator = startParents.iterator(); iterator.hasNext();) {
148                ConfigurationStatus startParent = (ConfigurationStatus) iterator.next();
149                startParent.startChildren.remove(this);
150            }
151            startChildren.clear();
152    
153            //
154            // connect to to the new parents
155            //
156            this.loadParents.addAll(newLoadParents);
157            this.startParents.addAll(newStartParents);
158    
159            for (Iterator iterator = loadParents.iterator(); iterator.hasNext();) {
160                ConfigurationStatus loadParent = (ConfigurationStatus) iterator.next();
161                loadParent.loadChildren.add(this);
162            }
163    
164            for (Iterator iterator = startParents.iterator(); iterator.hasNext();) {
165                ConfigurationStatus startParent = (ConfigurationStatus) iterator.next();
166                startParent.startChildren.add(this);
167            }
168        }
169    
170        public LinkedHashSet load() {
171            LinkedHashSet loadList = new LinkedHashSet();
172            loadInternal(loadList);
173            userLoaded = true;
174            return loadList;
175        }
176    
177        private void loadInternal(LinkedHashSet loadList) {
178            // visit all unloaded parents
179            for (Iterator iterator = loadParents.iterator(); iterator.hasNext();) {
180                ConfigurationStatus parent = (ConfigurationStatus) iterator.next();
181                if (!parent.isLoaded()) {
182                    parent.loadInternal(loadList);
183                }
184            }
185    
186            if (!loaded) {
187                loadList.add(configurationId);
188                loaded = true;
189            }
190        }
191    
192    
193        public LinkedHashSet start() {
194            if (!loaded) {
195                throw new IllegalStateException(configurationId + " is not loaded");
196            }
197            LinkedHashSet startList = new LinkedHashSet();
198            startInternal(startList);
199            userLoaded = true;
200            userStarted = true;
201            return startList;
202        }
203    
204        private void startInternal(LinkedHashSet startList) {
205            // visit all stopped parents
206            for (Iterator iterator = startParents.iterator(); iterator.hasNext();) {
207                ConfigurationStatus parent = (ConfigurationStatus) iterator.next();
208                if (!parent.isStarted()) {
209                    parent.startInternal(startList);
210                }
211            }
212    
213            if (!started) {
214                startList.add(configurationId);
215                started = true;
216            }
217        }
218    
219        /**
220         * Stop this configuration and its children (if it's running) or do nothing
221         * (if it's not running).
222         */
223        public LinkedHashSet stop(boolean gc) {
224            LinkedHashSet stopStatuses = new LinkedHashSet();
225            stopInternal(stopStatuses, gc);
226    
227            LinkedHashSet stopIds = new LinkedHashSet(stopStatuses.size());
228            for (Iterator iterator = stopStatuses.iterator(); iterator.hasNext();) {
229                ConfigurationStatus configurationStatus = (ConfigurationStatus) iterator.next();
230                stopIds.add(configurationStatus.configurationId);
231            }
232    
233            return stopIds;
234        }
235    
236        private void stopInternal(LinkedHashSet stopList, boolean gc) {
237            // if we aren't started, there is nothing to do
238            if (!started) {
239                return;
240            }
241    
242            // visit all children
243            for (Iterator iterator = startChildren.iterator(); iterator.hasNext();) {
244                ConfigurationStatus child = (ConfigurationStatus) iterator.next();
245                if (child.isStarted()) {
246                    child.stopInternal(stopList, gc);
247                }
248            }
249    
250            // mark this node as stoped, and add this node to the stop list
251            if (started) {
252                started = false;
253                userStarted = false;
254                stopList.add(this);
255    
256                // if we are garbage collecting, visit parents
257                if (gc) {
258                    // visit all non-user started parents that haven't already been visited
259                    for (Iterator iterator = startParents.iterator(); iterator.hasNext();) {
260                        ConfigurationStatus parent = (ConfigurationStatus) iterator.next();
261                        if (!parent.isUserStarted() && stopList.containsAll(parent.startChildren)) {
262                            parent.stopInternal(stopList, gc);
263                        }
264                    }
265                }
266            }
267        }
268    
269        public LinkedHashSet restart() {
270            if (!started) {
271                throw new IllegalStateException(configurationId + " is not started");
272            }
273    
274            LinkedHashSet restartStatuses = new LinkedHashSet();
275            restartInternal(restartStatuses);
276    
277            LinkedHashSet restartIds = new LinkedHashSet(restartStatuses.size());
278            for (Iterator iterator = restartStatuses.iterator(); iterator.hasNext();) {
279                ConfigurationStatus configurationStatus = (ConfigurationStatus) iterator.next();
280                restartIds.add(configurationStatus.configurationId);
281            }
282    
283            userLoaded = true;
284            userStarted = true;
285            return restartIds;
286        }
287    
288        private void restartInternal(LinkedHashSet restartList) {
289            // if we aren't started, there is nothing to do
290            if (!started) {
291                return;
292            }
293    
294            // visit all children
295            for (Iterator iterator = startChildren.iterator(); iterator.hasNext();) {
296                ConfigurationStatus child = (ConfigurationStatus) iterator.next();
297                if (child.isStarted()) {
298                    child.restartInternal(restartList);
299                }
300            }
301    
302            // add this node to the restart list
303            restartList.add(this);
304        }
305    
306        /**
307         * Unload the configuration and all its children (if it's loaded), or do
308         * nothing (if it's not loaded).
309         */
310        public LinkedHashSet unload(boolean gc) {
311    
312            LinkedHashSet unloadStatuses = new LinkedHashSet();
313            unloadInternal(unloadStatuses, gc);
314    
315            LinkedHashSet unloadIds = new LinkedHashSet(unloadStatuses.size());
316            for (Iterator iterator = unloadStatuses.iterator(); iterator.hasNext();) {
317                ConfigurationStatus configurationStatus = (ConfigurationStatus) iterator.next();
318                unloadIds.add(configurationStatus.configurationId);
319            }
320    
321            return unloadIds;
322        }
323    
324        private void unloadInternal(LinkedHashSet unloadList, boolean gc) {
325            // if we aren't loaded, there is nothing to do
326            if (!loaded) {
327                return;
328            }
329    
330            // visit all loaded children
331            for (Iterator iterator = loadChildren.iterator(); iterator.hasNext();) {
332                ConfigurationStatus child = (ConfigurationStatus) iterator.next();
333                if (child.isLoaded()) {
334                    child.unloadInternal(unloadList, gc);
335                }
336            }
337    
338            // mark this node as unloaded, and add this node to the unload list
339            if (loaded) {
340                started = false;
341                userStarted = false;
342                loaded = false;
343                userLoaded = false;
344                unloadList.add(this);
345    
346                // if we are garbage collecting, visit parents
347                if (gc) {
348                    // visit all non-user loaded parents
349                    for (Iterator iterator = loadParents.iterator(); iterator.hasNext();) {
350                        ConfigurationStatus parent = (ConfigurationStatus) iterator.next();
351                        if (!parent.isUserLoaded() && unloadList.containsAll(parent.loadChildren)) {
352                            parent.unloadInternal(unloadList, gc);
353                        }
354                    }
355                }
356            }
357        }
358    
359        public LinkedHashSet reload() {
360            if (!loaded) {
361                throw new IllegalStateException(configurationId + " is not loaded");
362            }
363    
364            LinkedHashSet reloadStatuses = new LinkedHashSet();
365            reloadInternal(reloadStatuses);
366    
367            LinkedHashSet reloadIds = new LinkedHashSet(reloadStatuses.size());
368            for (Iterator iterator = reloadStatuses.iterator(); iterator.hasNext();) {
369                ConfigurationStatus configurationStatus = (ConfigurationStatus) iterator.next();
370                reloadIds.add(configurationStatus.configurationId);
371            }
372    
373            userLoaded = true;
374            return reloadIds;
375        }
376    
377        private void reloadInternal(LinkedHashSet reloadList) {
378            // if we aren't loaded, there is nothing to do
379            if (!loaded) {
380                return;
381            }
382    
383            // visit all children
384            for (Iterator iterator = loadChildren.iterator(); iterator.hasNext();) {
385                ConfigurationStatus child = (ConfigurationStatus) iterator.next();
386                if (child.isLoaded()) {
387                    child.reloadInternal(reloadList);
388                }
389            }
390    
391            // add this node to the reload list
392            reloadList.add(this);
393        }
394    
395        public String toString() {
396            String load;
397            if (userLoaded) {
398                load = "user-loaded";
399            } else if (loaded) {
400                load = "loaded";
401            } else {
402                load = "not-loaded";
403            }
404            String start;
405            if (userLoaded) {
406                start = "user-started";
407            } else if (loaded) {
408                start = "started";
409            } else {
410                start = "not-started";
411            }
412            return "[" + configurationId + " " + load + " " + start + "]";
413        }
414    }