001    /**
002     *
003     *  Licensed to the Apache Software Foundation (ASF) under one or more
004     *  contributor license agreements.  See the NOTICE file distributed with
005     *  this work for additional information regarding copyright ownership.
006     *  The ASF licenses this file to You under the Apache License, Version 2.0
007     *  (the "License"); you may not use this file except in compliance with
008     *  the License.  You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     *  Unless required by applicable law or agreed to in writing, software
013     *  distributed under the License is distributed on an "AS IS" BASIS,
014     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     *  See the License for the specific language governing permissions and
016     *  limitations under the License.
017     */
018    package org.apache.geronimo.clustering.wadi.jetty;
019    
020    import java.util.Collections;
021    import java.util.HashSet;
022    import java.util.Set;
023    
024    import javax.xml.namespace.QName;
025    
026    import org.apache.geronimo.clustering.wadi.BasicWADISessionManager;
027    import org.apache.geronimo.clustering.wadi.WADISessionManagerConfigInfo;
028    import org.apache.geronimo.common.DeploymentException;
029    import org.apache.geronimo.deployment.DeploymentContext;
030    import org.apache.geronimo.deployment.NamespaceDrivenBuilder;
031    import org.apache.geronimo.deployment.service.EnvironmentBuilder;
032    import org.apache.geronimo.deployment.xmlbeans.XmlBeansUtil;
033    import org.apache.geronimo.gbean.AbstractName;
034    import org.apache.geronimo.gbean.AbstractNameQuery;
035    import org.apache.geronimo.gbean.GBeanData;
036    import org.apache.geronimo.gbean.GBeanInfo;
037    import org.apache.geronimo.gbean.GBeanInfoBuilder;
038    import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
039    import org.apache.geronimo.jetty.JettyWebAppContext;
040    import org.apache.geronimo.jetty.cluster.ClusteredWebApplicationHandlerFactory;
041    import org.apache.geronimo.jetty.cluster.wadi.WADIClusteredHandleInterceptor;
042    import org.apache.geronimo.kernel.GBeanAlreadyExistsException;
043    import org.apache.geronimo.kernel.GBeanNotFoundException;
044    import org.apache.geronimo.kernel.config.Configuration;
045    import org.apache.geronimo.kernel.repository.Environment;
046    import org.apache.geronimo.naming.deployment.ENCConfigBuilder;
047    import org.apache.geronimo.schema.NamespaceElementConverter;
048    import org.apache.geronimo.schema.SchemaConversionUtils;
049    import org.apache.geronimo.xbeans.geronimo.GerClusteringWadiDocument;
050    import org.apache.geronimo.xbeans.geronimo.GerClusteringWadiType;
051    import org.apache.geronimo.xbeans.geronimo.naming.GerPatternType;
052    import org.apache.xmlbeans.QNameSet;
053    import org.apache.xmlbeans.XmlObject;
054    
055    /**
056     *
057     * @version $Rev$ $Date$
058     */
059    public class WADIJettyClusteringBuilder implements NamespaceDrivenBuilder {
060        private static final QName CLUSTERING_WADI_QNAME = GerClusteringWadiDocument.type.getDocumentElementName();
061        private static final QNameSet CLUSTERING_WADI_QNAME_SET = QNameSet.singleton(CLUSTERING_WADI_QNAME);
062    
063        private final int defaultSweepInterval;
064        private final int defaultNumPartitions;
065        private final AbstractNameQuery defaultRepManagerFactoryName;
066        private final AbstractNameQuery defaultRepStorageFactoryName;
067        private final AbstractNameQuery defaultBackingStrategyFactoryName;
068        private final AbstractNameQuery defaultDispatcherHolderName;
069        private final Environment defaultEnvironment;
070    
071        public WADIJettyClusteringBuilder(int defaultSweepInterval,
072                int defaultNumPartitions,
073                AbstractNameQuery defaultRepManagerFactoryName,
074                AbstractNameQuery defaultRepStorageFactoryName,
075                AbstractNameQuery defaultBackingStrategyFactoryName,
076                AbstractNameQuery defaultDispatcherHolderName,
077                Environment defaultEnvironment) {
078            this.defaultSweepInterval = defaultSweepInterval;
079            this.defaultNumPartitions = defaultNumPartitions;
080            this.defaultRepManagerFactoryName = defaultRepManagerFactoryName;
081            this.defaultRepStorageFactoryName = defaultRepStorageFactoryName;
082            this.defaultBackingStrategyFactoryName = defaultBackingStrategyFactoryName;
083            this.defaultDispatcherHolderName = defaultDispatcherHolderName;
084            this.defaultEnvironment = defaultEnvironment;
085            SchemaConversionUtils.registerNamespaceConversions(Collections.singletonMap(CLUSTERING_WADI_QNAME.getLocalPart(), new NamespaceElementConverter(CLUSTERING_WADI_QNAME.getNamespaceURI())));
086        }
087    
088        public void buildEnvironment(XmlObject container, Environment environment) throws DeploymentException {
089            if (getWadiClusterConfig(container) != null) {
090                EnvironmentBuilder.mergeEnvironments(environment, defaultEnvironment);
091            }
092        }
093    
094        public void build(XmlObject container, DeploymentContext applicationContext, DeploymentContext moduleContext) throws DeploymentException {
095            GerClusteringWadiType clusteringWadiType = getWadiClusterConfig(container);
096            if (clusteringWadiType != null) {
097                GBeanData webModuleData = extractWebModule(moduleContext);
098                try {
099                    AbstractName sessionManagerName = addSessionManager(clusteringWadiType, webModuleData, moduleContext);
100                    addHandlerFactory(moduleContext, webModuleData, sessionManagerName);
101                    addInterceptor(moduleContext, webModuleData, sessionManagerName);
102                } catch (GBeanAlreadyExistsException e) {
103                    throw new DeploymentException("Duplicate GBean", e);
104                }
105            }
106        }
107    
108        private GBeanData extractWebModule(DeploymentContext moduleContext) throws DeploymentException {
109            Configuration configuration = moduleContext.getConfiguration();
110            AbstractNameQuery webModuleQuery = new AbstractNameQuery(configuration.getId(), Collections.EMPTY_MAP, Collections.singleton(JettyWebAppContext.class.getName()));
111            try {
112                return configuration.findGBeanData(webModuleQuery);
113            } catch (GBeanNotFoundException e) {
114                throw new DeploymentException("Could not locate web module gbean in web app configuration", e);
115            }
116        }
117    
118        public String getNamespace() {
119            XmlBeansUtil.registerSubstitutionGroupElements(org.apache.geronimo.xbeans.geronimo.j2ee.GerClusteringDocument.type.getDocumentElementName(), CLUSTERING_WADI_QNAME_SET);
120            return CLUSTERING_WADI_QNAME.getNamespaceURI();
121        }
122    
123        private GerClusteringWadiType getWadiClusterConfig(XmlObject container) throws DeploymentException {
124            XmlObject[] items = container.selectChildren(CLUSTERING_WADI_QNAME_SET);
125            if (items.length > 1) {
126                throw new DeploymentException("Unexpected count of clustering elements in geronimo plan " + items.length + " qnameset: " + CLUSTERING_WADI_QNAME_SET);
127            }
128            if (items.length == 1) {
129                return (GerClusteringWadiType) items[0].copy().changeType(GerClusteringWadiType.type);
130            }
131            return null;
132        }
133    
134        private AbstractName addSessionManager(GerClusteringWadiType clustering, GBeanData webModuleData, 
135                DeploymentContext moduleContext) throws GBeanAlreadyExistsException {
136            AbstractName name = moduleContext.getNaming().createChildName(moduleContext.getModuleName(),
137                    "WADISessionManager", NameFactory.GERONIMO_SERVICE);
138    
139            GBeanData beanData = new GBeanData(name, BasicWADISessionManager.GBEAN_INFO);
140            
141            setConfigInfo(clustering, webModuleData, beanData);
142            setReplicationManagerFactory(clustering, beanData);
143            setReplicaStorageFactory(clustering, beanData);
144            setBackingStrategyFactory(clustering, beanData);
145            setDispatcher(clustering, beanData);
146    
147            moduleContext.addGBean(beanData);
148    
149            return name;
150        }
151    
152        private void setConfigInfo(GerClusteringWadiType clustering, GBeanData webModuleData, GBeanData beanData) {
153            int sweepInterval = defaultSweepInterval;
154            if (clustering.isSetSweepInterval()) {
155                sweepInterval = clustering.getSweepInterval().intValue();
156            }
157            int numPartitions = defaultNumPartitions;
158            if (clustering.isSetNumPartitions()) {
159                numPartitions = clustering.getNumPartitions().intValue();
160            }
161            Integer sessionTimeout = (Integer) webModuleData.getAttribute(JettyWebAppContext.GBEAN_ATTR_SESSION_TIMEOUT);
162            if (null == sessionTimeout) {
163                throw new AssertionError();
164            }
165            
166            WADISessionManagerConfigInfo configInfo = new WADISessionManagerConfigInfo(
167                    beanData.getAbstractName().toURI(),
168                    sweepInterval,
169                    numPartitions,
170                    sessionTimeout.intValue());
171            beanData.setAttribute(BasicWADISessionManager.GBEAN_ATTR_WADI_CONFIG_INFO, configInfo);
172        }
173    
174        private void setDispatcher(GerClusteringWadiType clustering, GBeanData beanData) {
175            Set patterns = new HashSet();
176            if (clustering.isSetDispatcher()) {
177                addAbstractNameQueries(patterns, clustering.getDispatcher().getPatternArray());
178            } else {
179                patterns.add(defaultDispatcherHolderName);
180            }
181            beanData.setReferencePatterns(BasicWADISessionManager.GBEAN_REF_DISPATCHER_HOLDER, patterns);
182        }
183    
184        private void setBackingStrategyFactory(GerClusteringWadiType clustering, GBeanData beanData) {
185            Set patterns = new HashSet();
186            if (clustering.isSetBackingStrategyFactory()) {
187                addAbstractNameQueries(patterns, clustering.getBackingStrategyFactory().getPatternArray());
188            } else {
189                patterns.add(defaultBackingStrategyFactoryName);
190            }
191            beanData.setReferencePatterns(BasicWADISessionManager.GBEAN_REF_BACKING_STRATEGY_FACTORY, patterns);
192        }
193    
194        private void setReplicaStorageFactory(GerClusteringWadiType clustering, GBeanData beanData) {
195            Set patterns = new HashSet();
196            if (clustering.isSetReplicaStorageFactory()) {
197                addAbstractNameQueries(patterns, clustering.getReplicaStorageFactory().getPatternArray());
198            } else {
199                patterns.add(defaultRepStorageFactoryName);
200            }
201            beanData.setReferencePatterns(BasicWADISessionManager.GBEAN_REF_REPLICA_STORAGE_FACTORY, patterns);
202        }
203    
204        private void setReplicationManagerFactory(GerClusteringWadiType clustering, GBeanData beanData) {
205            Set patterns = new HashSet();
206            if (clustering.isSetReplicationManagerFactory()) {
207                addAbstractNameQueries(patterns, clustering.getReplicationManagerFactory().getPatternArray());
208            } else {
209                patterns.add(defaultRepManagerFactoryName);
210            }
211            beanData.setReferencePatterns(BasicWADISessionManager.GBEAN_REF_REPLICATION_MANAGER_FACTORY, patterns);
212        }
213    
214        private AbstractName addHandlerFactory(DeploymentContext moduleContext,
215                GBeanData webModuleData, AbstractName sessionManagerName) throws GBeanAlreadyExistsException {
216            AbstractName name = moduleContext.getNaming().createChildName(moduleContext.getModuleName(),
217                    "ClusteredWebApplicationHandlerFactory", NameFactory.GERONIMO_SERVICE);
218    
219            GBeanData beanData = new GBeanData(name, ClusteredWebApplicationHandlerFactory.GBEAN_INFO);
220            beanData.setReferencePattern(ClusteredWebApplicationHandlerFactory.GBEAN_REF_SESSION_MANAGER, sessionManagerName);
221    
222            webModuleData.setReferencePattern(JettyWebAppContext.GBEAN_REF_WEB_APPLICATION_HANDLER_FACTORY, name);
223    
224            moduleContext.addGBean(beanData);
225    
226            return name;
227        }
228    
229        private AbstractName addInterceptor(DeploymentContext moduleContext,
230                GBeanData webModuleData, AbstractName sessionManagerName) throws GBeanAlreadyExistsException {
231            AbstractName name = moduleContext.getNaming().createChildName(moduleContext.getModuleName(),
232                    "WADIClusteredHandleInterceptor", NameFactory.GERONIMO_SERVICE);
233    
234            GBeanData beanData = new GBeanData(name, WADIClusteredHandleInterceptor.GBEAN_INFO);
235            beanData.setReferencePattern(WADIClusteredHandleInterceptor.GBEAN_REF_WADI_SESSION_MANAGER, sessionManagerName);
236    
237            webModuleData.setReferencePattern(JettyWebAppContext.GBEAN_REF_HANDLE_INTERCEPTOR, name);
238    
239            moduleContext.addGBean(beanData);
240    
241            return name;
242        }
243    
244        private void addAbstractNameQueries(Set patterns, GerPatternType[] patternTypes) {
245            for (int i = 0; i < patternTypes.length; i++) {
246                AbstractNameQuery query = ENCConfigBuilder.buildAbstractNameQuery(patternTypes[i], null, null, null);
247                patterns.add(query);
248            }
249        }
250    
251        public static final GBeanInfo GBEAN_INFO;
252    
253        public static final String GBEAN_ATTR_DFT_SWEEP_INTERVAL = "defaultSweepInterval";
254        public static final String GBEAN_ATTR_DFT_NUM_PARTITIONS = "defaultNumPartitions";
255        public static final String GBEAN_ATTR_DFT_REP_MANAGER_FACTORY_NAME = "defaultReplicationManagerFactoryName";
256        public static final String GBEAN_ATTR_DFT_REP_STORAGE_FACTORY_NAME = "defaultReplicaStorageFactoryName";
257        public static final String GBEAN_ATTR_DFT_BACKING_STRATEGY_FACTORY_NAME = "defaultBackingStrategyFactoryName";
258        public static final String GBEAN_ATTR_DFT_DISPATCHER_HOLDER_NAME = "defaultDispatcherHolderName";
259        public static final String GBEAN_ATTR_DFT_ENVIRONMENT = "defaultEnvironment";
260    
261        static {
262            GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic("WADI Session Manager",
263                    WADIJettyClusteringBuilder.class,
264                    NameFactory.MODULE_BUILDER);
265    
266            infoBuilder.addAttribute(GBEAN_ATTR_DFT_SWEEP_INTERVAL, int.class, true);
267            infoBuilder.addAttribute(GBEAN_ATTR_DFT_NUM_PARTITIONS, int.class, true);
268            infoBuilder.addAttribute(GBEAN_ATTR_DFT_REP_MANAGER_FACTORY_NAME, AbstractNameQuery.class, true);
269            infoBuilder.addAttribute(GBEAN_ATTR_DFT_REP_STORAGE_FACTORY_NAME, AbstractNameQuery.class, true);
270            infoBuilder.addAttribute(GBEAN_ATTR_DFT_BACKING_STRATEGY_FACTORY_NAME, AbstractNameQuery.class, true);
271            infoBuilder.addAttribute(GBEAN_ATTR_DFT_DISPATCHER_HOLDER_NAME, AbstractNameQuery.class, true);
272            infoBuilder.addAttribute(GBEAN_ATTR_DFT_ENVIRONMENT, Environment.class, true);
273    
274            infoBuilder.setConstructor(new String[]{GBEAN_ATTR_DFT_SWEEP_INTERVAL,
275                    GBEAN_ATTR_DFT_NUM_PARTITIONS,
276                    GBEAN_ATTR_DFT_REP_MANAGER_FACTORY_NAME,
277                    GBEAN_ATTR_DFT_REP_STORAGE_FACTORY_NAME,
278                    GBEAN_ATTR_DFT_BACKING_STRATEGY_FACTORY_NAME,
279                    GBEAN_ATTR_DFT_DISPATCHER_HOLDER_NAME,
280                    GBEAN_ATTR_DFT_ENVIRONMENT});
281    
282            GBEAN_INFO = infoBuilder.getBeanInfo();
283        }
284    
285        public static GBeanInfo getGBeanInfo() {
286            return GBEAN_INFO;
287        }
288    
289    }