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.server.spring.configuration;
018    
019    import java.util.ArrayList;
020    import java.util.Iterator;
021    import java.util.List;
022    import java.util.Map;
023    import java.util.Set;
024    import java.util.HashSet;
025    import java.util.Collections;
026    
027    import org.apache.xbean.kernel.AbstractServiceFactory;
028    import org.apache.xbean.kernel.ServiceCondition;
029    import org.apache.xbean.kernel.ServiceConditionContext;
030    import org.apache.xbean.kernel.ServiceContext;
031    import org.apache.xbean.kernel.ServiceFactory;
032    import org.apache.xbean.kernel.ServiceName;
033    import org.springframework.context.support.AbstractXmlApplicationContext;
034    
035    /**
036     * SpringConfigurationServiceFactory is manages the creation and destruction of a SpringConfiguration.
037     *
038     * @author Dain Sundstrom
039     * @version $Id$
040     * @since 2.0
041     */
042    public class SpringConfigurationServiceFactory extends AbstractServiceFactory {
043        private final AbstractXmlApplicationContext applicationContext;
044        private final ConfigurationStopCondition configurationStopCondition;
045        private SpringConfiguration springConfiguration;
046    
047        /**
048         * Creates a SpringConfigurationServiceFactory that wraps the specified application context.
049         * @param applicationContext the application context for this configuration
050         */
051        public SpringConfigurationServiceFactory(AbstractXmlApplicationContext applicationContext) {
052            this.applicationContext = applicationContext;
053            configurationStopCondition = new ConfigurationStopCondition();
054            addStopCondition(configurationStopCondition);
055        }
056    
057        /**
058         * Gets the unique id if this configuration.
059         * @return the unique id if this configuration
060         */
061        public String getId() {
062            return applicationContext.getDisplayName();
063        }
064    
065        /**
066         * Gets the application context wrapped by this configuration.  Use caution when modifiying this context as it can
067         * effect the running state of services.
068         * @return the application context wrapped by this configuration
069         */
070        public AbstractXmlApplicationContext getApplicationContext() {
071            return applicationContext;
072        }
073    
074        /**
075         * {@inheritDoc}
076         */
077        public Class[] getTypes() {
078            return new Class[]{SpringConfiguration.class};
079        }
080    
081        /**
082         * SpringConfigurationServiceFactory is restartable so this method always returns true.
083         * @return true
084         */
085        public boolean isRestartable() {
086            return false;
087        }
088    
089        /**
090         * Gets the ServiceNames of the services defined in the application context if the configuration has been started,
091         * otherwise this method returns an empty set.
092         *
093         * @return the ServiceNames of the services defined in the application context if the configuration has been started
094         */
095        public Set getOwnedServices() {
096            if (springConfiguration != null) {
097                return new HashSet(springConfiguration.getServiceFactories().keySet());
098            }
099            return Collections.EMPTY_SET;
100        }
101    
102        /**
103         * {@inheritDoc}
104         */
105        public Object createService(ServiceContext serviceContext) throws Exception {
106            springConfiguration = new SpringConfiguration(applicationContext, serviceContext.getKernel());
107    
108            // add owned service stop conditions
109            Set ownedServices = springConfiguration.getServiceFactories().keySet();
110            for (Iterator iterator = springConfiguration.getServiceFactories().entrySet().iterator(); iterator.hasNext();) {
111                Map.Entry entry = (Map.Entry) iterator.next();
112                ServiceName serviceName = (ServiceName) entry.getKey();
113                ServiceFactory serviceFactory = (ServiceFactory) entry.getValue();
114                if (ownedServices.contains(serviceName)) {
115                    serviceFactory.addStopCondition(configurationStopCondition.createOwnedServiceStopCondition());
116                }
117            }
118    
119            return springConfiguration;
120        }
121    
122        /**
123         * {@inheritDoc}
124         */
125        public void destroyService(ServiceContext serviceContext) {
126            if (springConfiguration != null) {
127                springConfiguration.destroy();
128                springConfiguration = null;
129            }
130            applicationContext.close();
131        }
132    
133        /**
134         * {@inheritDoc}
135         */
136        public ClassLoader getClassLoader() {
137            return SpringConfiguration.getClassLoader(applicationContext);
138        }
139        
140        private static class ConfigurationStopCondition implements ServiceCondition {
141            private final List ownedServiceConditions = new ArrayList();
142    
143            public synchronized void initialize(ServiceConditionContext context) {
144                for (Iterator iterator = ownedServiceConditions.iterator(); iterator.hasNext();) {
145                    OwnedServiceCondition ownedServiceCondition = (OwnedServiceCondition) iterator.next();
146                    ownedServiceCondition.setSatisfied();
147                }
148            }
149    
150            public boolean isSatisfied() {
151                return true;
152            }
153    
154            public synchronized void destroy() {
155                for (Iterator iterator = ownedServiceConditions.iterator(); iterator.hasNext();) {
156                    OwnedServiceCondition ownedServiceCondition = (OwnedServiceCondition) iterator.next();
157                    ownedServiceCondition.setSatisfied();
158                }
159            }
160    
161            public ServiceCondition createOwnedServiceStopCondition() {
162                ServiceCondition ownedServiceCondition = new OwnedServiceCondition();
163                ownedServiceConditions.add(ownedServiceCondition);
164                return ownedServiceCondition;
165            }
166    
167            private static class OwnedServiceCondition implements ServiceCondition {
168                private boolean satisfied = false;
169                private ServiceConditionContext context;
170    
171                public synchronized void initialize(ServiceConditionContext context) {
172                    this.context = context;
173                }
174    
175                public synchronized boolean isSatisfied() {
176                    return satisfied;
177                }
178    
179                private void setSatisfied() {
180                    this.satisfied = true;
181                    if (context != null) {
182                        context.setSatisfied();
183                    }
184                }
185    
186                public synchronized void destroy() {
187                    context = null;
188                }
189            }
190        }
191    }