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.jetty6.cluster.wadi.builder;
018    
019    import java.util.Collections;
020    import java.util.HashSet;
021    import java.util.Set;
022    
023    import javax.xml.namespace.QName;
024    
025    import org.apache.geronimo.clustering.wadi.BasicWADISessionManager;
026    import org.apache.geronimo.clustering.wadi.WADISessionManagerConfigInfo;
027    import org.apache.geronimo.common.DeploymentException;
028    import org.apache.geronimo.deployment.DeploymentContext;
029    import org.apache.geronimo.deployment.NamespaceDrivenBuilder;
030    import org.apache.geronimo.deployment.service.EnvironmentBuilder;
031    import org.apache.geronimo.gbean.AbstractName;
032    import org.apache.geronimo.gbean.AbstractNameQuery;
033    import org.apache.geronimo.gbean.GBeanData;
034    import org.apache.geronimo.gbean.GBeanInfo;
035    import org.apache.geronimo.gbean.GBeanInfoBuilder;
036    import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
037    import org.apache.geronimo.jetty6.JettyWebAppContext;
038    import org.apache.geronimo.jetty6.cluster.ClusteredSessionHandlerFactory;
039    import org.apache.geronimo.jetty6.cluster.wadi.WADIClusteredPreHandlerFactory;
040    import org.apache.geronimo.kernel.GBeanAlreadyExistsException;
041    import org.apache.geronimo.kernel.GBeanNotFoundException;
042    import org.apache.geronimo.kernel.config.Configuration;
043    import org.apache.geronimo.kernel.repository.Environment;
044    import org.apache.geronimo.naming.deployment.ENCConfigBuilder;
045    import org.apache.geronimo.schema.NamespaceElementConverter;
046    import org.apache.geronimo.schema.SchemaConversionUtils;
047    import org.apache.geronimo.xbeans.geronimo.GerClusteringWadiDocument;
048    import org.apache.geronimo.xbeans.geronimo.GerClusteringWadiType;
049    import org.apache.geronimo.xbeans.geronimo.naming.GerPatternType;
050    import org.apache.xmlbeans.QNameSet;
051    import org.apache.xmlbeans.XmlObject;
052    
053    /**
054     *
055     * @version $Rev$ $Date$
056     */
057    public class WADIJettyClusteringBuilder implements NamespaceDrivenBuilder {
058        private static final QName CLUSTERING_WADI_QNAME = GerClusteringWadiDocument.type.getDocumentElementName();
059        private static final QNameSet CLUSTERING_WADI_QNAME_SET = QNameSet.singleton(CLUSTERING_WADI_QNAME);
060    
061        private final int defaultSweepInterval;
062        private final int defaultNumPartitions;
063        private final AbstractNameQuery defaultBackingStrategyFactoryName;
064        private final AbstractNameQuery defaultClusterName;
065        private final Environment defaultEnvironment;
066    
067        public WADIJettyClusteringBuilder(int defaultSweepInterval,
068                int defaultNumPartitions,
069                AbstractNameQuery defaultBackingStrategyFactoryName,
070                AbstractNameQuery defaultClusterName,
071                Environment defaultEnvironment) {
072            this.defaultSweepInterval = defaultSweepInterval;
073            this.defaultNumPartitions = defaultNumPartitions;
074            this.defaultBackingStrategyFactoryName = defaultBackingStrategyFactoryName;
075            this.defaultClusterName = defaultClusterName;
076            this.defaultEnvironment = defaultEnvironment;
077            
078            SchemaConversionUtils.registerNamespaceConversions(
079                Collections.singletonMap(CLUSTERING_WADI_QNAME.getLocalPart(),
080                new NamespaceElementConverter(CLUSTERING_WADI_QNAME.getNamespaceURI())));
081        }
082    
083        public void buildEnvironment(XmlObject container, Environment environment) throws DeploymentException {
084            if (getWadiClusterConfig(container) != null) {
085                EnvironmentBuilder.mergeEnvironments(environment, defaultEnvironment);
086            }
087        }
088    
089        public void build(XmlObject container, DeploymentContext applicationContext, DeploymentContext moduleContext) throws DeploymentException {
090            GerClusteringWadiType clusteringWadiType = getWadiClusterConfig(container);
091            if (clusteringWadiType != null) {
092                GBeanData webModuleData = extractWebModule(moduleContext);
093                try {
094                    AbstractName sessionManagerName = addSessionManager(clusteringWadiType, webModuleData, moduleContext);
095                    addSessionHandlerFactory(moduleContext, webModuleData, sessionManagerName);
096                    addPreHandlerFactory(moduleContext, webModuleData, sessionManagerName);
097                } catch (GBeanAlreadyExistsException e) {
098                    throw new DeploymentException("Duplicate GBean", e);
099                }
100            }
101        }
102    
103        private GBeanData extractWebModule(DeploymentContext moduleContext) throws DeploymentException {
104            Configuration configuration = moduleContext.getConfiguration();
105            AbstractNameQuery webModuleQuery = new AbstractNameQuery(configuration.getId(), Collections.EMPTY_MAP, Collections.singleton(JettyWebAppContext.class.getName()));
106            try {
107                return configuration.findGBeanData(webModuleQuery);
108            } catch (GBeanNotFoundException e) {
109                throw new DeploymentException("Could not locate web module gbean in web app configuration", e);
110            }
111        }
112    
113        public QNameSet getSpecQNameSet() {
114            return QNameSet.EMPTY;
115        }
116    
117        public QNameSet getPlanQNameSet() {
118            return CLUSTERING_WADI_QNAME_SET;
119        }
120    
121        private GerClusteringWadiType getWadiClusterConfig(XmlObject container) throws DeploymentException {
122            XmlObject[] items = container.selectChildren(CLUSTERING_WADI_QNAME_SET);
123            if (items.length > 1) {
124                throw new DeploymentException("Unexpected count of clustering elements in geronimo plan " + items.length + " qnameset: " + CLUSTERING_WADI_QNAME_SET);
125            }
126            if (items.length == 1) {
127                return (GerClusteringWadiType) items[0].copy().changeType(GerClusteringWadiType.type);
128            }
129            return null;
130        }
131    
132        private AbstractName addSessionManager(GerClusteringWadiType clustering,
133                GBeanData webModuleData,
134                DeploymentContext moduleContext) throws GBeanAlreadyExistsException {
135            AbstractName name = moduleContext.getNaming().createChildName(moduleContext.getModuleName(),
136                    "WADISessionManager", NameFactory.GERONIMO_SERVICE);
137    
138            GBeanData beanData = new GBeanData(name, BasicWADISessionManager.GBEAN_INFO);
139    
140            setConfigInfo(clustering, webModuleData, beanData);
141            setCluster(clustering, beanData);
142            setBackingStrategyFactory(clustering, beanData);
143    
144            moduleContext.addGBean(beanData);
145    
146            return name;
147        }
148        
149        private void setConfigInfo(GerClusteringWadiType clustering, GBeanData webModuleData, GBeanData beanData) {
150            int sweepInterval = defaultSweepInterval;
151            if (clustering.isSetSweepInterval()) {
152                sweepInterval = clustering.getSweepInterval().intValue();
153            }
154            int numPartitions = defaultNumPartitions;
155            if (clustering.isSetNumPartitions()) {
156                numPartitions = clustering.getNumPartitions().intValue();
157            }
158            Integer sessionTimeout = (Integer) webModuleData.getAttribute(JettyWebAppContext.GBEAN_ATTR_SESSION_TIMEOUT);
159            if (null == sessionTimeout) {
160                throw new AssertionError();
161            }
162            
163            WADISessionManagerConfigInfo configInfo = new WADISessionManagerConfigInfo(
164                    beanData.getAbstractName().toURI(),
165                    sweepInterval,
166                    numPartitions,
167                    sessionTimeout.intValue());
168            beanData.setAttribute(BasicWADISessionManager.GBEAN_ATTR_WADI_CONFIG_INFO, configInfo);
169        }
170    
171        private void setCluster(GerClusteringWadiType clustering, GBeanData beanData) {
172            Set patterns = new HashSet();
173            if (clustering.isSetCluster()) {
174                addAbstractNameQueries(patterns, clustering.getCluster().getPatternArray());
175            } else {
176                patterns.add(defaultClusterName);
177            }
178            beanData.setReferencePatterns(BasicWADISessionManager.GBEAN_REF_CLUSTER, patterns);
179        }
180    
181        private void setBackingStrategyFactory(GerClusteringWadiType clustering, GBeanData beanData) {
182            Set patterns = new HashSet();
183            if (clustering.isSetBackingStrategyFactory()) {
184                addAbstractNameQueries(patterns, clustering.getBackingStrategyFactory().getPatternArray());
185            } else {
186                patterns.add(defaultBackingStrategyFactoryName);
187            }
188            beanData.setReferencePatterns(BasicWADISessionManager.GBEAN_REF_BACKING_STRATEGY_FACTORY, patterns);
189        }
190    
191        private AbstractName addPreHandlerFactory(DeploymentContext moduleContext,
192                GBeanData webModuleData, AbstractName sessionManagerName) throws GBeanAlreadyExistsException {
193            AbstractName name = moduleContext.getNaming().createChildName(moduleContext.getModuleName(),
194                    "WADIClusteredPreHandlerFactory", NameFactory.GERONIMO_SERVICE);
195    
196            GBeanData beanData = new GBeanData(name, WADIClusteredPreHandlerFactory.GBEAN_INFO);
197            beanData.setReferencePattern(WADIClusteredPreHandlerFactory.GBEAN_REF_WADI_SESSION_MANAGER, sessionManagerName);
198    
199            webModuleData.setReferencePattern(JettyWebAppContext.GBEAN_REF_PRE_HANDLER_FACTORY, name);
200    
201            moduleContext.addGBean(beanData);
202    
203            return name;
204        }
205    
206        private AbstractName addSessionHandlerFactory(DeploymentContext moduleContext,
207                GBeanData webModuleData, AbstractName sessionManagerName) throws GBeanAlreadyExistsException {
208            AbstractName name = moduleContext.getNaming().createChildName(moduleContext.getModuleName(),
209                    "ClusteredSessionHandlerFactory", NameFactory.GERONIMO_SERVICE);
210    
211            GBeanData beanData = new GBeanData(name, ClusteredSessionHandlerFactory.GBEAN_INFO);
212            beanData.setReferencePattern(ClusteredSessionHandlerFactory.GBEAN_REF_SESSION_MANAGER, sessionManagerName);
213    
214            webModuleData.setReferencePattern(JettyWebAppContext.GBEAN_REF_SESSION_HANDLER_FACTORY, name);
215    
216            moduleContext.addGBean(beanData);
217    
218            return name;
219        }
220    
221        private void addAbstractNameQueries(Set patterns, GerPatternType[] patternTypes) {
222            for (int i = 0; i < patternTypes.length; i++) {
223                AbstractNameQuery query = ENCConfigBuilder.buildAbstractNameQuery(patternTypes[i], null, null, null);
224                patterns.add(query);
225            }
226        }
227    
228        public static final GBeanInfo GBEAN_INFO;
229    
230        public static final String GBEAN_ATTR_DFT_SWEEP_INTERVAL = "defaultSweepInterval";
231        public static final String GBEAN_ATTR_DFT_NUM_PARTITIONS = "defaultNumPartitions";
232        public static final String GBEAN_ATTR_DFT_BACKING_STRATEGY_FACTORY_NAME = "defaultBackingStrategyFactoryName";
233        public static final String GBEAN_ATTR_DFT_CLUSTER_NAME = "defaultClusterName";
234        public static final String GBEAN_ATTR_DFT_ENVIRONMENT = "defaultEnvironment";
235    
236        static {
237            GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic("WADI Session Manager",
238                    WADIJettyClusteringBuilder.class,
239                    NameFactory.MODULE_BUILDER);
240    
241            infoBuilder.addAttribute(GBEAN_ATTR_DFT_SWEEP_INTERVAL, int.class, true);
242            infoBuilder.addAttribute(GBEAN_ATTR_DFT_NUM_PARTITIONS, int.class, true);
243            infoBuilder.addAttribute(GBEAN_ATTR_DFT_BACKING_STRATEGY_FACTORY_NAME, AbstractNameQuery.class, true);
244            infoBuilder.addAttribute(GBEAN_ATTR_DFT_CLUSTER_NAME, AbstractNameQuery.class, true);
245            infoBuilder.addAttribute(GBEAN_ATTR_DFT_ENVIRONMENT, Environment.class, true);
246    
247            infoBuilder.setConstructor(new String[]{GBEAN_ATTR_DFT_SWEEP_INTERVAL,
248                    GBEAN_ATTR_DFT_NUM_PARTITIONS,
249                    GBEAN_ATTR_DFT_BACKING_STRATEGY_FACTORY_NAME,
250                    GBEAN_ATTR_DFT_CLUSTER_NAME,
251                    GBEAN_ATTR_DFT_ENVIRONMENT});
252    
253            GBEAN_INFO = infoBuilder.getBeanInfo();
254        }
255    
256        public static GBeanInfo getGBeanInfo() {
257            return GBEAN_INFO;
258        }
259    
260    }