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.net.URI;
020    import java.net.URISyntaxException;
021    import java.util.Collections;
022    import java.util.HashSet;
023    import java.util.Set;
024    
025    import javax.xml.namespace.QName;
026    
027    import org.apache.geronimo.clustering.wadi.BasicWADISessionManager;
028    import org.apache.geronimo.clustering.wadi.WADISessionManagerConfigInfo;
029    import org.apache.geronimo.common.DeploymentException;
030    import org.apache.geronimo.deployment.DeploymentContext;
031    import org.apache.geronimo.deployment.NamespaceDrivenBuilder;
032    import org.apache.geronimo.deployment.service.EnvironmentBuilder;
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.jetty6.JettyWebAppContext;
040    import org.apache.geronimo.jetty6.cluster.ClusteredSessionHandlerFactory;
041    import org.apache.geronimo.jetty6.cluster.wadi.WADIClusteredPreHandlerFactory;
042    import org.apache.geronimo.kernel.GBeanAlreadyExistsException;
043    import org.apache.geronimo.kernel.GBeanNotFoundException;
044    import org.apache.geronimo.kernel.Jsr77Naming;
045    import org.apache.geronimo.kernel.config.Configuration;
046    import org.apache.geronimo.kernel.repository.Environment;
047    import org.apache.geronimo.naming.deployment.ENCConfigBuilder;
048    import org.apache.geronimo.schema.NamespaceElementConverter;
049    import org.apache.geronimo.schema.SchemaConversionUtils;
050    import org.apache.geronimo.xbeans.geronimo.GerClusteringWadiDocument;
051    import org.apache.geronimo.xbeans.geronimo.GerClusteringWadiType;
052    import org.apache.geronimo.xbeans.geronimo.naming.GerPatternType;
053    import org.apache.xmlbeans.QNameSet;
054    import org.apache.xmlbeans.XmlObject;
055    
056    /**
057     *
058     * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
059     */
060    public class WADIJettyClusteringBuilder implements NamespaceDrivenBuilder {
061        private static final QName CLUSTERING_WADI_QNAME = GerClusteringWadiDocument.type.getDocumentElementName();
062        private static final QNameSet CLUSTERING_WADI_QNAME_SET = QNameSet.singleton(CLUSTERING_WADI_QNAME);
063    
064        static  {
065            SchemaConversionUtils.registerNamespaceConversions(
066                Collections.singletonMap(CLUSTERING_WADI_QNAME.getLocalPart(),
067                new NamespaceElementConverter(CLUSTERING_WADI_QNAME.getNamespaceURI())));
068        }
069        
070        private final int defaultSweepInterval;
071        private final int defaultNumPartitions;
072        private final AbstractNameQuery defaultBackingStrategyFactoryName;
073        private final AbstractNameQuery defaultClusterName;
074        private final Environment defaultEnvironment;
075    
076        public WADIJettyClusteringBuilder(int defaultSweepInterval,
077                int defaultNumPartitions,
078                AbstractNameQuery defaultBackingStrategyFactoryName,
079                AbstractNameQuery defaultClusterName,
080                Environment defaultEnvironment) {
081            if (defaultSweepInterval < 1) {
082                throw new IllegalArgumentException("defaultSweepInterval is lower than 1");
083            } else if (defaultNumPartitions < 1) {
084                throw new IllegalArgumentException("defaultNumPartitions is lower than 1");
085            } else if (null == defaultBackingStrategyFactoryName) {
086                throw new IllegalArgumentException("defaultBackingStrategyFactoryName is required");
087            } else if (null == defaultClusterName) {
088                throw new IllegalArgumentException("defaultClusterName is required");
089            } else if (null == defaultEnvironment) {
090                throw new IllegalArgumentException("defaultEnvironment is required");
091            }
092            this.defaultSweepInterval = defaultSweepInterval;
093            this.defaultNumPartitions = defaultNumPartitions;
094            this.defaultBackingStrategyFactoryName = defaultBackingStrategyFactoryName;
095            this.defaultClusterName = defaultClusterName;
096            this.defaultEnvironment = defaultEnvironment;
097        }
098    
099        public void buildEnvironment(XmlObject container, Environment environment) throws DeploymentException {
100            if (getWadiClusterConfig(container) != null) {
101                EnvironmentBuilder.mergeEnvironments(environment, defaultEnvironment);
102            }
103        }
104    
105        public void build(XmlObject container, DeploymentContext applicationContext, DeploymentContext moduleContext) throws DeploymentException {
106            GerClusteringWadiType clusteringWadiType = getWadiClusterConfig(container);
107            if (clusteringWadiType != null) {
108                GBeanData webModuleData = extractWebModule(moduleContext);
109                try {
110                    AbstractName sessionManagerName = addSessionManager(clusteringWadiType, webModuleData, moduleContext);
111                    addSessionHandlerFactory(moduleContext, webModuleData, sessionManagerName);
112                    addPreHandlerFactory(moduleContext, webModuleData, sessionManagerName);
113                } catch (GBeanAlreadyExistsException e) {
114                    throw new DeploymentException("Duplicate GBean", e);
115                }
116            }
117        }
118    
119        protected GBeanData extractWebModule(DeploymentContext moduleContext) throws DeploymentException {
120            AbstractNameQuery webModuleQuery = createJettyWebAppContextNameQuery(moduleContext);
121            Configuration configuration = moduleContext.getConfiguration();
122            try {
123                return configuration.findGBeanData(webModuleQuery);
124            } catch (GBeanNotFoundException e) {
125                throw new DeploymentException("Could not locate web module gbean in web app configuration", e);
126            }
127        }
128    
129        protected AbstractNameQuery createJettyWebAppContextNameQuery(DeploymentContext moduleContext) {
130            String name = moduleContext.getModuleName().getNameProperty(Jsr77Naming.J2EE_NAME);
131            return new AbstractNameQuery(null,
132                Collections.singletonMap(Jsr77Naming.J2EE_NAME, name),
133                Collections.singleton(JettyWebAppContext.class.getName()));
134        }
135    
136        public QNameSet getSpecQNameSet() {
137            return QNameSet.EMPTY;
138        }
139    
140        public QNameSet getPlanQNameSet() {
141            return CLUSTERING_WADI_QNAME_SET;
142        }
143    
144        protected GerClusteringWadiType getWadiClusterConfig(XmlObject container) throws DeploymentException {
145            XmlObject[] items = container.selectChildren(CLUSTERING_WADI_QNAME_SET);
146            if (items.length > 1) {
147                throw new DeploymentException("Unexpected count of clustering elements in geronimo plan " + items.length + " qnameset: " + CLUSTERING_WADI_QNAME_SET);
148            }
149            if (items.length == 1) {
150                return (GerClusteringWadiType) items[0].copy().changeType(GerClusteringWadiType.type);
151            }
152            return null;
153        }
154    
155        protected AbstractName addSessionManager(GerClusteringWadiType clustering,
156                GBeanData webModuleData,
157                DeploymentContext moduleContext) throws GBeanAlreadyExistsException {
158            AbstractName name = moduleContext.getNaming().createChildName(moduleContext.getModuleName(),
159                    "WADISessionManager", NameFactory.GERONIMO_SERVICE);
160    
161            GBeanData beanData = new GBeanData(name, BasicWADISessionManager.GBEAN_INFO);
162    
163            setConfigInfo(clustering, webModuleData, beanData);
164            setCluster(clustering, beanData);
165            setBackingStrategyFactory(clustering, beanData);
166    
167            moduleContext.addGBean(beanData);
168    
169            return name;
170        }
171        
172        protected void setConfigInfo(GerClusteringWadiType clustering, GBeanData webModuleData, GBeanData beanData) {
173            int sweepInterval = getSweepInterval(clustering);
174            int numPartitions = getNumberOfPartitions(clustering);
175            Integer sessionTimeout = getSessionTimeout(webModuleData);
176            boolean disableReplication = isDisableReplication(clustering);
177            boolean deltaReplication = isDeltaReplication(clustering);
178            
179            String contextPath = (String) webModuleData.getAttribute("contextPath");
180            URI serviceSpaceName;
181            try {
182                serviceSpaceName = new URI(contextPath);
183            } catch (URISyntaxException e) {
184                throw (AssertionError) new AssertionError("contextPath [" + contextPath + "] cannot be parsed as an URI.").initCause(e);
185            }
186            
187            WADISessionManagerConfigInfo configInfo = new WADISessionManagerConfigInfo(serviceSpaceName,
188                    sweepInterval,
189                    numPartitions,
190                    sessionTimeout.intValue(),
191                    disableReplication,
192                    deltaReplication);
193            beanData.setAttribute(BasicWADISessionManager.GBEAN_ATTR_WADI_CONFIG_INFO, configInfo);
194        }
195    
196        protected Integer getSessionTimeout(GBeanData webModuleData) throws AssertionError {
197            Integer sessionTimeout = (Integer) webModuleData.getAttribute(JettyWebAppContext.GBEAN_ATTR_SESSION_TIMEOUT);
198            if (null == sessionTimeout) {
199                throw new AssertionError();
200            }
201            return sessionTimeout;
202        }
203    
204        protected boolean isDeltaReplication(GerClusteringWadiType clustering) {
205            if (clustering.isSetDeltaReplication()) {
206                return clustering.getDeltaReplication();
207            }
208            return false;
209        }
210    
211        protected boolean isDisableReplication(GerClusteringWadiType clustering) {
212            if (clustering.isSetDisableReplication()) {
213                return clustering.getDisableReplication();
214            }
215            return false;
216        }
217    
218        protected int getNumberOfPartitions(GerClusteringWadiType clustering) {
219            if (clustering.isSetNumPartitions()) {
220                return clustering.getNumPartitions().intValue();
221            }
222            return defaultNumPartitions;
223        }
224    
225        protected int getSweepInterval(GerClusteringWadiType clustering) {
226            if (clustering.isSetSweepInterval()) {
227                return clustering.getSweepInterval().intValue();
228            }
229            return defaultSweepInterval;
230        }
231    
232        protected void setCluster(GerClusteringWadiType clustering, GBeanData beanData) {
233            Set patterns = new HashSet();
234            if (clustering.isSetCluster()) {
235                addAbstractNameQueries(patterns, clustering.getCluster().getPatternArray());
236            } else {
237                patterns.add(defaultClusterName);
238            }
239            beanData.setReferencePatterns(BasicWADISessionManager.GBEAN_REF_CLUSTER, patterns);
240        }
241    
242        protected void setBackingStrategyFactory(GerClusteringWadiType clustering, GBeanData beanData) {
243            Set patterns = new HashSet();
244            if (clustering.isSetBackingStrategyFactory()) {
245                addAbstractNameQueries(patterns, clustering.getBackingStrategyFactory().getPatternArray());
246            } else {
247                patterns.add(defaultBackingStrategyFactoryName);
248            }
249            beanData.setReferencePatterns(BasicWADISessionManager.GBEAN_REF_BACKING_STRATEGY_FACTORY, patterns);
250        }
251    
252        protected AbstractName addPreHandlerFactory(DeploymentContext moduleContext,
253                GBeanData webModuleData, AbstractName sessionManagerName) throws GBeanAlreadyExistsException {
254            AbstractName name = moduleContext.getNaming().createChildName(moduleContext.getModuleName(),
255                    "WADIClusteredPreHandlerFactory", NameFactory.GERONIMO_SERVICE);
256    
257            GBeanData beanData = new GBeanData(name, WADIClusteredPreHandlerFactory.GBEAN_INFO);
258            beanData.setReferencePattern(WADIClusteredPreHandlerFactory.GBEAN_REF_WADI_SESSION_MANAGER, sessionManagerName);
259    
260            webModuleData.setReferencePattern(JettyWebAppContext.GBEAN_REF_PRE_HANDLER_FACTORY, name);
261    
262            moduleContext.addGBean(beanData);
263    
264            return name;
265        }
266    
267        protected AbstractName addSessionHandlerFactory(DeploymentContext moduleContext,
268                GBeanData webModuleData, AbstractName sessionManagerName) throws GBeanAlreadyExistsException {
269            AbstractName name = moduleContext.getNaming().createChildName(moduleContext.getModuleName(),
270                    "ClusteredSessionHandlerFactory", NameFactory.GERONIMO_SERVICE);
271    
272            GBeanData beanData = new GBeanData(name, ClusteredSessionHandlerFactory.GBEAN_INFO);
273            beanData.setReferencePattern(ClusteredSessionHandlerFactory.GBEAN_REF_SESSION_MANAGER, sessionManagerName);
274    
275            webModuleData.setReferencePattern(JettyWebAppContext.GBEAN_REF_SESSION_HANDLER_FACTORY, name);
276    
277            moduleContext.addGBean(beanData);
278    
279            return name;
280        }
281    
282        protected void addAbstractNameQueries(Set patterns, GerPatternType[] patternTypes) {
283            for (int i = 0; i < patternTypes.length; i++) {
284                AbstractNameQuery query = ENCConfigBuilder.buildAbstractNameQuery(patternTypes[i], null, null, null);
285                patterns.add(query);
286            }
287        }
288    
289        public static final GBeanInfo GBEAN_INFO;
290    
291        public static final String GBEAN_ATTR_DFT_SWEEP_INTERVAL = "defaultSweepInterval";
292        public static final String GBEAN_ATTR_DFT_NUM_PARTITIONS = "defaultNumPartitions";
293        public static final String GBEAN_ATTR_DFT_BACKING_STRATEGY_FACTORY_NAME = "defaultBackingStrategyFactoryName";
294        public static final String GBEAN_ATTR_DFT_CLUSTER_NAME = "defaultClusterName";
295        public static final String GBEAN_ATTR_DFT_ENVIRONMENT = "defaultEnvironment";
296    
297        static {
298            GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic("WADI Session Manager",
299                    WADIJettyClusteringBuilder.class,
300                    NameFactory.MODULE_BUILDER);
301    
302            infoBuilder.addAttribute(GBEAN_ATTR_DFT_SWEEP_INTERVAL, int.class, true);
303            infoBuilder.addAttribute(GBEAN_ATTR_DFT_NUM_PARTITIONS, int.class, true);
304            infoBuilder.addAttribute(GBEAN_ATTR_DFT_BACKING_STRATEGY_FACTORY_NAME, AbstractNameQuery.class, true);
305            infoBuilder.addAttribute(GBEAN_ATTR_DFT_CLUSTER_NAME, AbstractNameQuery.class, true);
306            infoBuilder.addAttribute(GBEAN_ATTR_DFT_ENVIRONMENT, Environment.class, true);
307    
308            infoBuilder.setConstructor(new String[]{GBEAN_ATTR_DFT_SWEEP_INTERVAL,
309                    GBEAN_ATTR_DFT_NUM_PARTITIONS,
310                    GBEAN_ATTR_DFT_BACKING_STRATEGY_FACTORY_NAME,
311                    GBEAN_ATTR_DFT_CLUSTER_NAME,
312                    GBEAN_ATTR_DFT_ENVIRONMENT});
313    
314            GBEAN_INFO = infoBuilder.getBeanInfo();
315        }
316    
317        public static GBeanInfo getGBeanInfo() {
318            return GBEAN_INFO;
319        }
320    
321    }