001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements.  See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership.  The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the
007     * "License"); you may not use this file except in compliance
008     * with 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,
013     * software distributed under the License is distributed on an
014     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     * KIND, either express or implied.  See the License for the
016     * specific language governing permissions and limitations
017     * under the License.
018     */
019    
020    package org.apache.geronimo.tomcat.cluster.wadi.builder;
021    
022    import java.net.URI;
023    import java.net.URISyntaxException;
024    import java.util.ArrayList;
025    import java.util.Collections;
026    import java.util.HashSet;
027    import java.util.Iterator;
028    import java.util.List;
029    import java.util.Set;
030    
031    import javax.xml.namespace.QName;
032    
033    import org.apache.geronimo.clustering.wadi.BasicWADISessionManager;
034    import org.apache.geronimo.clustering.wadi.WADISessionManagerConfigInfo;
035    import org.apache.geronimo.common.DeploymentException;
036    import org.apache.geronimo.deployment.DeploymentContext;
037    import org.apache.geronimo.deployment.NamespaceDrivenBuilder;
038    import org.apache.geronimo.deployment.service.EnvironmentBuilder;
039    import org.apache.geronimo.gbean.AbstractName;
040    import org.apache.geronimo.gbean.AbstractNameQuery;
041    import org.apache.geronimo.gbean.GBeanData;
042    import org.apache.geronimo.gbean.GBeanInfo;
043    import org.apache.geronimo.gbean.GBeanInfoBuilder;
044    import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
045    import org.apache.geronimo.kernel.GBeanAlreadyExistsException;
046    import org.apache.geronimo.kernel.GBeanNotFoundException;
047    import org.apache.geronimo.kernel.Jsr77Naming;
048    import org.apache.geronimo.kernel.config.Configuration;
049    import org.apache.geronimo.kernel.repository.Artifact;
050    import org.apache.geronimo.kernel.repository.Dependency;
051    import org.apache.geronimo.kernel.repository.Environment;
052    import org.apache.geronimo.naming.deployment.ENCConfigBuilder;
053    import org.apache.geronimo.schema.SchemaConversionUtils;
054    import org.apache.geronimo.tomcat.TomcatWebAppContext;
055    import org.apache.geronimo.tomcat.cluster.ClusteredManagerRetriever;
056    import org.apache.geronimo.tomcat.cluster.wadi.WADIClusteredValveRetriever;
057    import org.apache.geronimo.xbeans.geronimo.GerTomcatClusteringWadiDocument;
058    import org.apache.geronimo.xbeans.geronimo.GerTomcatClusteringWadiType;
059    import org.apache.geronimo.xbeans.geronimo.naming.GerPatternType;
060    import org.apache.xmlbeans.QNameSet;
061    import org.apache.xmlbeans.XmlObject;
062    
063    /**
064     *
065     * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
066     */
067    public class WADITomcatClusteringBuilder implements NamespaceDrivenBuilder {
068        private static final QName CLUSTERING_WADI_QNAME = GerTomcatClusteringWadiDocument.type.getDocumentElementName();
069        private static final QNameSet CLUSTERING_WADI_QNAME_SET = QNameSet.singleton(CLUSTERING_WADI_QNAME);
070    
071        static {
072            SchemaConversionUtils.registerNamespaceConversions(
073                Collections.singletonMap(CLUSTERING_WADI_QNAME.getLocalPart(),
074                new TomcatClusteringWADIConverter()));
075        }
076        
077        private final int defaultSweepInterval;
078        private final int defaultSessionTimeout;
079        private final int defaultNumPartitions;
080        private final AbstractNameQuery defaultBackingStrategyFactoryName;
081        private final AbstractNameQuery defaultClusterName;
082        private final Artifact artifactToRemoveFromEnvironment;
083        private final Environment defaultEnvironment;
084    
085        public WADITomcatClusteringBuilder(int defaultSweepInterval,
086                int defaultSessionTimeout,
087                int defaultNumPartitions,
088                AbstractNameQuery defaultBackingStrategyFactoryName,
089                AbstractNameQuery defaultClusterName,
090                            Artifact artifactToRemoveFromEnvironment,
091                Environment defaultEnvironment) {
092            if (defaultSweepInterval < 1) {
093                throw new IllegalArgumentException("defaultSweepInterval is lower than 1");
094            } else if (defaultSessionTimeout < 1) {
095                throw new IllegalArgumentException("defaultSessionTimeout is lower than 1");
096            } else if (defaultNumPartitions < 1) {
097                throw new IllegalArgumentException("defaultNumPartitions is lower than 1");
098            } else if (null == defaultBackingStrategyFactoryName) {
099                throw new IllegalArgumentException("defaultBackingStrategyFactoryName is required");
100            } else if (null == defaultClusterName) {
101                throw new IllegalArgumentException("defaultClusterName is required");
102            } else if (null == artifactToRemoveFromEnvironment) {
103                throw new IllegalArgumentException("artifactToRemoveFromEnvironment is required");
104            } else if (null == defaultEnvironment) {
105                throw new IllegalArgumentException("defaultEnvironment is required");
106            }
107            this.defaultSweepInterval = defaultSweepInterval;
108            this.defaultSessionTimeout = defaultSessionTimeout;
109            this.defaultNumPartitions = defaultNumPartitions;
110            this.defaultBackingStrategyFactoryName = defaultBackingStrategyFactoryName;
111            this.defaultClusterName = defaultClusterName;
112            this.artifactToRemoveFromEnvironment = artifactToRemoveFromEnvironment;
113            this.defaultEnvironment = defaultEnvironment;
114        }
115    
116        public void buildEnvironment(XmlObject container, Environment environment) throws DeploymentException {
117            if (getWadiClusterConfig(container) != null) {
118                filterDependencies(environment);
119                EnvironmentBuilder.mergeEnvironments(environment, defaultEnvironment);
120            }
121        }
122    
123        public void build(XmlObject container, DeploymentContext applicationContext, DeploymentContext moduleContext)
124                throws DeploymentException {
125            GerTomcatClusteringWadiType clusteringWadiType = getWadiClusterConfig(container);
126            if (clusteringWadiType != null) {
127                GBeanData webModuleData = extractWebModule(moduleContext);
128                try {
129                    AbstractName sessionManagerName = addSessionManager(clusteringWadiType, webModuleData, moduleContext);
130                    addClusteredManagerRetriever(moduleContext, webModuleData, sessionManagerName);
131                    addClusteredValveRetriever(moduleContext, webModuleData, sessionManagerName);
132                } catch (GBeanAlreadyExistsException e) {
133                    throw new DeploymentException("Duplicate GBean", e);
134                }
135            }
136        }
137    
138        protected void filterDependencies(Environment environment) {
139            List<Dependency> dependencies = environment.getDependencies();
140            dependencies = new ArrayList<Dependency>(dependencies);
141            for (Iterator<Dependency> iterator = dependencies.iterator(); iterator.hasNext();) {
142                Dependency dependency = iterator.next();
143                Artifact dependencyArtifact = dependency.getArtifact();
144                if (artifactToRemoveFromEnvironment.matches(dependencyArtifact)) {
145                    iterator.remove();
146                }
147            }
148            environment.setDependencies(dependencies);
149        }
150    
151        protected GBeanData extractWebModule(DeploymentContext moduleContext) throws DeploymentException {
152            AbstractNameQuery webModuleQuery = createTomcatWebAppContextNameQuery(moduleContext);
153            Configuration configuration = moduleContext.getConfiguration();
154            try {
155                return configuration.findGBeanData(webModuleQuery);
156            } catch (GBeanNotFoundException e) {
157                throw new DeploymentException("Could not locate web module gbean in web app configuration", e);
158            }
159        }
160    
161        protected AbstractNameQuery createTomcatWebAppContextNameQuery(DeploymentContext moduleContext) {
162            String name = moduleContext.getModuleName().getNameProperty(Jsr77Naming.J2EE_NAME);
163            return new AbstractNameQuery(null,
164                Collections.singletonMap(Jsr77Naming.J2EE_NAME, name),
165                Collections.singleton(TomcatWebAppContext.class.getName()));
166        }
167    
168        public QNameSet getSpecQNameSet() {
169            return QNameSet.EMPTY;
170        }
171    
172        public QNameSet getPlanQNameSet() {
173            return CLUSTERING_WADI_QNAME_SET;
174        }
175    
176        protected GerTomcatClusteringWadiType getWadiClusterConfig(XmlObject container) throws DeploymentException {
177            XmlObject[] items = container.selectChildren(CLUSTERING_WADI_QNAME_SET);
178            if (items.length > 1) {
179                throw new DeploymentException("Unexpected count of clustering elements in geronimo plan " + items.length
180                        + " qnameset: " + CLUSTERING_WADI_QNAME_SET);
181            }
182            if (items.length == 1) {
183                return (GerTomcatClusteringWadiType) items[0].copy().changeType(GerTomcatClusteringWadiType.type);
184            }
185            return null;
186        }
187    
188        protected AbstractName addSessionManager(GerTomcatClusteringWadiType clustering,
189                GBeanData webModuleData,
190                DeploymentContext moduleContext) throws GBeanAlreadyExistsException {
191            AbstractName name = newGBeanName(moduleContext, "WADISessionManager");
192    
193            GBeanData beanData = new GBeanData(name, BasicWADISessionManager.GBEAN_INFO);
194    
195            setConfigInfo(clustering, webModuleData, beanData);
196            setCluster(clustering, beanData);
197            setBackingStrategyFactory(clustering, beanData);
198    
199            addGBean(moduleContext, beanData);
200    
201            return name;
202        }
203    
204        protected void setConfigInfo(GerTomcatClusteringWadiType clustering, GBeanData webModuleData, GBeanData beanData) {
205            int sweepInterval = getSweepInterval(clustering);
206            int numPartitions = getNumberOfPartitions(clustering);
207            Integer sessionTimeout = getSessionTimeout(webModuleData);
208            boolean disableReplication = isDisableReplication(clustering);
209            boolean deltaReplication = isDeltaReplication(clustering);
210            
211            String contextPath = (String) webModuleData.getAttribute("contextPath");
212            URI serviceSpaceName;
213            try {
214                serviceSpaceName = new URI(contextPath);
215            } catch (URISyntaxException e) {
216                AssertionError error = new AssertionError("contextPath [" + contextPath + "] cannot be parsed as an URI.");
217                throw (AssertionError) error.initCause(e);
218            }
219            
220            WADISessionManagerConfigInfo configInfo = new WADISessionManagerConfigInfo(serviceSpaceName,
221                    sweepInterval,
222                    numPartitions,
223                    sessionTimeout.intValue(),
224                    disableReplication,
225                    deltaReplication);
226            beanData.setAttribute(BasicWADISessionManager.GBEAN_ATTR_WADI_CONFIG_INFO, configInfo);
227        }
228    
229        protected Integer getSessionTimeout(GBeanData webModuleData) throws AssertionError {
230            return defaultSessionTimeout;
231        }
232    
233        protected boolean isDeltaReplication(GerTomcatClusteringWadiType clustering) {
234            if (clustering.isSetDeltaReplication()) {
235                return clustering.getDeltaReplication();
236            }
237            return false;
238        }
239    
240        protected boolean isDisableReplication(GerTomcatClusteringWadiType clustering) {
241            if (clustering.isSetDisableReplication()) {
242                return clustering.getDisableReplication();
243            }
244            return false;
245        }
246    
247        protected int getNumberOfPartitions(GerTomcatClusteringWadiType clustering) {
248            if (clustering.isSetNumPartitions()) {
249                return clustering.getNumPartitions().intValue();
250            }
251            return defaultNumPartitions;
252        }
253    
254        protected int getSweepInterval(GerTomcatClusteringWadiType clustering) {
255            if (clustering.isSetSweepInterval()) {
256                return clustering.getSweepInterval().intValue();
257            }
258            return defaultSweepInterval;
259        }
260    
261        protected void setCluster(GerTomcatClusteringWadiType clustering, GBeanData beanData) {
262            Set patterns = new HashSet();
263            if (clustering.isSetCluster()) {
264                addAbstractNameQueries(patterns, clustering.getCluster());
265            } else {
266                patterns.add(defaultClusterName);
267            }
268            beanData.setReferencePatterns(BasicWADISessionManager.GBEAN_REF_CLUSTER, patterns);
269        }
270    
271        protected void setBackingStrategyFactory(GerTomcatClusteringWadiType clustering, GBeanData beanData) {
272            Set patterns = new HashSet();
273            if (clustering.isSetBackingStrategyFactory()) {
274                addAbstractNameQueries(patterns, clustering.getBackingStrategyFactory());
275            } else {
276                patterns.add(defaultBackingStrategyFactoryName);
277            }
278            beanData.setReferencePatterns(BasicWADISessionManager.GBEAN_REF_BACKING_STRATEGY_FACTORY, patterns);
279        }
280    
281        protected AbstractName addClusteredValveRetriever(DeploymentContext moduleContext,
282                GBeanData webModuleData,
283                AbstractName sessionManagerName) throws GBeanAlreadyExistsException {
284            AbstractName name = newGBeanName(moduleContext, "WADIClusteredValveRetriever");
285    
286            GBeanData beanData = new GBeanData(name, WADIClusteredValveRetriever.GBEAN_INFO);
287            beanData.setReferencePattern(WADIClusteredValveRetriever.GBEAN_REF_WADI_SESSION_MANAGER, sessionManagerName);
288    
289            webModuleData.setReferencePattern(TomcatWebAppContext.GBEAN_REF_CLUSTERED_VALVE_RETRIEVER, name);
290    
291            addGBean(moduleContext, beanData);
292    
293            return name;
294        }
295    
296        protected AbstractName addClusteredManagerRetriever(DeploymentContext moduleContext,
297                GBeanData webModuleData,
298                AbstractName sessionManagerName) throws GBeanAlreadyExistsException {
299            AbstractName name = newGBeanName(moduleContext, "ClusteredManagerRetriever");
300    
301            GBeanData beanData = new GBeanData(name, ClusteredManagerRetriever.GBEAN_INFO);
302            beanData.setReferencePattern(ClusteredManagerRetriever.GBEAN_REF_SESSION_MANAGER, sessionManagerName);
303    
304            webModuleData.setReferencePattern(TomcatWebAppContext.GBEAN_REF_MANAGER_RETRIEVER, name);
305    
306            addGBean(moduleContext, beanData);
307    
308            return name;
309        }
310        
311        protected void addGBean(DeploymentContext moduleContext, GBeanData beanData) throws GBeanAlreadyExistsException {
312            moduleContext.addGBean(beanData);
313        }
314    
315        protected AbstractName newGBeanName(DeploymentContext moduleContext, String name) {
316            return moduleContext.getNaming().createChildName(moduleContext.getModuleName(),
317                    name,
318                    NameFactory.GERONIMO_SERVICE);
319        }
320    
321        protected void addAbstractNameQueries(Set patterns, GerPatternType patternType) {
322            AbstractNameQuery query = ENCConfigBuilder.buildAbstractNameQuery(patternType, null, null, null);
323            patterns.add(query);
324        }
325    
326        public static final GBeanInfo GBEAN_INFO;
327    
328        public static final String GBEAN_ATTR_DFT_SWEEP_INTERVAL = "defaultSweepInterval";
329        public static final String GBEAN_ATTR_DFT_SESSION_TIMEOUT = "defaultSessionTimeout";
330        public static final String GBEAN_ATTR_DFT_NUM_PARTITIONS = "defaultNumPartitions";
331        public static final String GBEAN_ATTR_DFT_BACKING_STRATEGY_FACTORY_NAME = "defaultBackingStrategyFactoryName";
332        public static final String GBEAN_ATTR_DFT_CLUSTER_NAME = "defaultClusterName";
333        public static final String GBEAN_ATTR_ARTIFACT_TO_REMOVE = "artifactToRemoveFromEnvironment";
334        public static final String GBEAN_ATTR_DFT_ENVIRONMENT = "defaultEnvironment";
335    
336        static {
337            GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic("WADI Session Manager",
338                    WADITomcatClusteringBuilder.class,
339                    NameFactory.MODULE_BUILDER);
340    
341            infoBuilder.addAttribute(GBEAN_ATTR_DFT_SWEEP_INTERVAL, int.class, true);
342            infoBuilder.addAttribute(GBEAN_ATTR_DFT_SESSION_TIMEOUT, int.class, true);
343            infoBuilder.addAttribute(GBEAN_ATTR_DFT_NUM_PARTITIONS, int.class, true);
344            infoBuilder.addAttribute(GBEAN_ATTR_DFT_BACKING_STRATEGY_FACTORY_NAME, AbstractNameQuery.class, true);
345            infoBuilder.addAttribute(GBEAN_ATTR_DFT_CLUSTER_NAME, AbstractNameQuery.class, true);
346            infoBuilder.addAttribute(GBEAN_ATTR_ARTIFACT_TO_REMOVE, Artifact.class, true);
347            infoBuilder.addAttribute(GBEAN_ATTR_DFT_ENVIRONMENT, Environment.class, true);
348    
349            infoBuilder.setConstructor(new String[]{GBEAN_ATTR_DFT_SWEEP_INTERVAL,
350                    GBEAN_ATTR_DFT_SESSION_TIMEOUT,
351                    GBEAN_ATTR_DFT_NUM_PARTITIONS,
352                    GBEAN_ATTR_DFT_BACKING_STRATEGY_FACTORY_NAME,
353                    GBEAN_ATTR_DFT_CLUSTER_NAME,
354                                    GBEAN_ATTR_ARTIFACT_TO_REMOVE,
355                    GBEAN_ATTR_DFT_ENVIRONMENT});
356    
357            GBEAN_INFO = infoBuilder.getBeanInfo();
358        }
359    
360        public static GBeanInfo getGBeanInfo() {
361            return GBEAN_INFO;
362        }
363    
364    }