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.farm.deployment;
021    
022    import java.io.File;
023    import java.io.IOException;
024    import java.io.OutputStream;
025    import java.net.MalformedURLException;
026    import java.net.URL;
027    import java.util.ArrayList;
028    import java.util.Collections;
029    import java.util.LinkedHashSet;
030    import java.util.List;
031    import java.util.Set;
032    
033    import org.apache.commons.logging.Log;
034    import org.apache.commons.logging.LogFactory;
035    import org.apache.geronimo.farm.config.ClusterInfo;
036    import org.apache.geronimo.farm.config.NodeInfo;
037    import org.apache.geronimo.gbean.AbstractName;
038    import org.apache.geronimo.gbean.GBeanData;
039    import org.apache.geronimo.gbean.GBeanInfo;
040    import org.apache.geronimo.gbean.GBeanInfoBuilder;
041    import org.apache.geronimo.kernel.Kernel;
042    import org.apache.geronimo.kernel.config.ConfigurationAlreadyExistsException;
043    import org.apache.geronimo.kernel.config.ConfigurationData;
044    import org.apache.geronimo.kernel.config.ConfigurationInfo;
045    import org.apache.geronimo.kernel.config.ConfigurationModuleType;
046    import org.apache.geronimo.kernel.config.ConfigurationStore;
047    import org.apache.geronimo.kernel.config.InvalidConfigException;
048    import org.apache.geronimo.kernel.config.NoSuchConfigException;
049    import org.apache.geronimo.kernel.repository.Artifact;
050    import org.apache.geronimo.kernel.repository.Environment;
051    import org.apache.geronimo.kernel.repository.WritableListableRepository;
052    import org.apache.geronimo.system.configuration.RepositoryConfigurationStore;
053    
054    /**
055     *
056     * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
057     */
058    public class MasterConfigurationStore implements ConfigurationStore {
059        private static final Log log = LogFactory.getLog(MasterConfigurationStore.class);
060        
061        private final ConfigurationStore delegate;
062        private final Environment defaultEnvironment;
063        private final ClusterInfo clusterInfo;
064        private final AbstractName clusterInfoName;
065        private final ClusterConfigurationStoreClient storeDelegate;
066        private final SlaveConfigurationNameBuilder slaveConfigNameBuilder;
067        
068        public MasterConfigurationStore(Kernel kernel,
069                String objectName,
070                AbstractName abstractName,
071                WritableListableRepository repository,
072                Environment defaultEnvironment,
073                ClusterInfo clusterInfo,
074                ClusterConfigurationStoreClient storeDelegate) {
075            if (null == kernel) {
076                throw new IllegalArgumentException("kernel is required");
077            } else if (null == objectName) {
078                throw new IllegalArgumentException("objectName is required");
079            } else if (null == repository) {
080                throw new IllegalArgumentException("repository is required");
081            } else if (null == defaultEnvironment) {
082                throw new IllegalArgumentException("defaultEnvironment is required");
083            } else if (null == clusterInfo) {
084                throw new IllegalArgumentException("clusterInfo is required");
085            } else if (null == storeDelegate) {
086                throw new IllegalArgumentException("storeDelegate is required");
087            }
088            this.defaultEnvironment = defaultEnvironment;
089            this.clusterInfo = clusterInfo;
090            this.storeDelegate = storeDelegate;
091    
092            slaveConfigNameBuilder = newSlaveConfigurationNameBuilder();
093            clusterInfoName = kernel.getAbstractNameFor(clusterInfo);
094            delegate = newConfigurationStore(kernel, objectName, abstractName, repository);
095        }
096    
097        public boolean containsConfiguration(Artifact configId) {
098            if (slaveConfigNameBuilder.isSlaveConfigurationName(configId)) {
099                return false;
100            }
101            return delegate.containsConfiguration(configId);
102        }
103    
104        public File createNewConfigurationDir(Artifact configId) throws ConfigurationAlreadyExistsException {
105            Artifact slaveConfigId = slaveConfigNameBuilder.buildSlaveConfigurationName(configId);
106            return delegate.createNewConfigurationDir(slaveConfigId);
107        }
108    
109        public void exportConfiguration(Artifact configId, OutputStream output) throws IOException, NoSuchConfigException {
110            ensureArtifactForMasterConfiguration(configId);
111            delegate.exportConfiguration(configId, output);
112        }
113    
114        public AbstractName getAbstractName() {
115            return delegate.getAbstractName();
116        }
117    
118        public String getObjectName() {
119            return delegate.getObjectName();
120        }
121    
122        public void install(ConfigurationData configurationData) throws IOException, InvalidConfigException {
123            Environment environment = configurationData.getEnvironment();
124            Artifact actualConfigId = environment.getConfigId();
125            Artifact slaveConfigId = slaveConfigNameBuilder.buildSlaveConfigurationName(actualConfigId);
126            environment.setConfigId(slaveConfigId);
127    
128            storeDelegate.install(clusterInfo, configurationData);
129            installSlaveConfiguration(configurationData);
130    
131            environment.setConfigId(actualConfigId);
132    
133            installMasterConfiguration(configurationData, slaveConfigId);
134        }
135    
136        public boolean isInPlaceConfiguration(Artifact configId) throws NoSuchConfigException, IOException {
137            ensureArtifactForMasterConfiguration(configId);
138            return false;
139        }
140    
141        public List<ConfigurationInfo> listConfigurations() {
142            List<ConfigurationInfo> configurationInfos = delegate.listConfigurations();
143            
144            List<ConfigurationInfo> filteredConfigurationInfos = new ArrayList<ConfigurationInfo>();
145            for (ConfigurationInfo configurationInfo : configurationInfos) {
146                if (!slaveConfigNameBuilder.isSlaveConfigurationName(configurationInfo.getConfigID())) {
147                    filteredConfigurationInfos.add(configurationInfo);
148                }
149            }
150    
151            return filteredConfigurationInfos;
152        }
153    
154        public ConfigurationData loadConfiguration(Artifact configId)
155                throws NoSuchConfigException, IOException, InvalidConfigException {
156            ensureArtifactForMasterConfiguration(configId);
157            return delegate.loadConfiguration(configId);
158        }
159    
160        public Set<URL> resolve(Artifact configId, String moduleName, String path)
161                throws NoSuchConfigException, MalformedURLException {
162            ensureArtifactForMasterConfiguration(configId);
163            return delegate.resolve(configId, moduleName, path);
164        }
165    
166        public void uninstall(Artifact configId) throws NoSuchConfigException, IOException {
167            ensureArtifactForMasterConfiguration(configId);
168            
169            Artifact slaveConfigId = slaveConfigNameBuilder.buildSlaveConfigurationName(configId);
170            storeDelegate.uninstall(clusterInfo, slaveConfigId);
171    
172            try {
173                delegate.uninstall(slaveConfigId);
174            } catch (Exception e) {
175                log.warn("Exception when uninstalling [" + slaveConfigId + "]", e);
176            }
177            delegate.uninstall(configId);
178        }
179    
180        protected void ensureArtifactForMasterConfiguration(Artifact configId) throws NoSuchConfigException {
181            if (slaveConfigNameBuilder.isSlaveConfigurationName(configId)) {
182                throw new NoSuchConfigException(configId);
183            }
184        }
185    
186        protected ConfigurationStore newConfigurationStore(Kernel kernel,
187            String objectName,
188            AbstractName abstractName,
189            WritableListableRepository repository) {
190            return new RepositoryConfigurationStore(kernel, objectName, abstractName, repository);
191        }
192    
193        protected SlaveConfigurationNameBuilder newSlaveConfigurationNameBuilder() {
194            return new BasicSlaveConfigurationNameBuilder();
195        }
196    
197        protected void installMasterConfiguration(ConfigurationData configurationData, Artifact slaveConfigId)
198                throws IOException, InvalidConfigException {
199            ConfigurationData masterConfigurationData = buildMasterConfigurationData(configurationData, slaveConfigId);
200            try {
201                delegate.install(masterConfigurationData);
202            } catch (Exception e) {
203                storeDelegate.uninstall(clusterInfo, slaveConfigId);
204                try {
205                    delegate.uninstall(slaveConfigId);
206                } catch (NoSuchConfigException nestedE) {
207                }
208                if (e instanceof IOException) {
209                    throw (IOException) e;
210                } else if (e instanceof InvalidConfigException) {
211                    throw (InvalidConfigException) e;
212                }
213                throw (IOException) new IOException("See nested").initCause(e);
214            }
215        }
216    
217        protected void installSlaveConfiguration(ConfigurationData configurationData)
218                throws IOException, InvalidConfigException {
219            try {
220                delegate.install(configurationData);
221            } catch (Exception e) {
222                storeDelegate.uninstall(clusterInfo, configurationData.getId());
223                if (e instanceof IOException) {
224                    throw (IOException) e;
225                } else if (e instanceof InvalidConfigException) {
226                    throw (InvalidConfigException) e;
227                }
228                throw (IOException) new IOException("See nested").initCause(e);
229            }
230        }
231    
232        protected ConfigurationData buildMasterConfigurationData(ConfigurationData configurationData,
233            Artifact slaveConfigId) {
234            Environment environment = buildEnvironment(configurationData);
235    
236            Artifact configId = environment.getConfigId();
237            
238            List<GBeanData> gbeans = buildControllerGBeans(configId, slaveConfigId);
239            
240            File configurationDir = delegate.createNewConfigurationDir(configId);
241            
242            return new ConfigurationData(ConfigurationModuleType.CAR,
243                new LinkedHashSet(),
244                gbeans,
245                Collections.EMPTY_MAP,
246                environment,
247                configurationDir,
248                null,
249                configurationData.getNaming()); 
250        }
251    
252        protected Environment buildEnvironment(ConfigurationData configurationData) {
253            Environment environment = new Environment(defaultEnvironment);
254            environment.setConfigId(configurationData.getId());
255            return environment;
256        }
257    
258        protected List<GBeanData> buildControllerGBeans(Artifact configId, Artifact slaveConfigId) {
259            List<GBeanData> gbeans = new ArrayList<GBeanData>();
260            for (NodeInfo nodeInfo : clusterInfo.getNodeInfos()) {
261                GBeanData gbean = buildControllerGBean(configId, nodeInfo, slaveConfigId);
262                gbeans.add(gbean);
263            }
264            return gbeans;
265        }
266    
267        protected GBeanData buildControllerGBean(Artifact configId, NodeInfo nodeInfo, Artifact slaveConfigId) {
268            AbstractName controllerName = buildControllerName(configId, nodeInfo);
269            
270            GBeanData gbean = new GBeanData(controllerName, BasicClusterConfigurationController.GBEAN_INFO);
271            gbean.setAttribute(BasicClusterConfigurationController.GBEAN_ATTR_ARTIFACT, slaveConfigId);
272            gbean.setAttribute(BasicClusterConfigurationController.GBEAN_ATTR_IGNORE_START_CONF_FAIL_UPON_START,
273                Boolean.TRUE);
274            gbean.setAttribute(BasicClusterConfigurationController.GBEAN_ATTR_NODE_NAME, nodeInfo.getName());
275            gbean.setAttribute(BasicClusterConfigurationController.GBEAN_ATTR_START_CONF_UPON_START, Boolean.TRUE);
276            gbean.setReferencePattern(BasicClusterConfigurationController.GBEAN_REF_CLUSTER_INFO, clusterInfoName);
277            return gbean;
278        }
279    
280        protected AbstractName buildControllerName(Artifact configId,
281                NodeInfo nodeInfo) {
282            return new AbstractName(configId, Collections.singletonMap("nodeName", nodeInfo.getName()));
283        }
284    
285        public static final GBeanInfo GBEAN_INFO;
286    
287        public static final String GBEAN_J2EE_TYPE = "ConfigurationStore";
288        public static final String GBEAN_ATTR_KERNEL = "kernel";
289        public static final String GBEAN_ATTR_OBJECT_NAME = "objectName";
290        public static final String GBEAN_ATTR_DEFAULT_ENV = "defaultEnvironment";
291        public static final String GBEAN_REF_REPOSITORY = "Repository";
292        public static final String GBEAN_REF_CLUSTER_INFO = "ClusterInfo";
293        public static final String GBEAN_REF_CLUSTER_CONF_STORE_CLIENT = "ClusterConfigurationStoreClient";
294    
295        static {
296            GBeanInfoBuilder builder = GBeanInfoBuilder.createStatic(MasterConfigurationStore.class, GBEAN_J2EE_TYPE);
297            
298            builder.addAttribute(GBEAN_ATTR_KERNEL, Kernel.class, false);
299            builder.addAttribute(GBEAN_ATTR_OBJECT_NAME, String.class, false);
300            builder.addAttribute("abstractName", AbstractName.class, false);
301            builder.addAttribute(GBEAN_ATTR_DEFAULT_ENV, Environment.class, true, true);
302            
303            builder.addReference(GBEAN_REF_REPOSITORY, WritableListableRepository.class, "Repository");
304            builder.addReference(GBEAN_REF_CLUSTER_INFO, ClusterInfo.class);
305            builder.addReference(GBEAN_REF_CLUSTER_CONF_STORE_CLIENT, ClusterConfigurationStoreClient.class);
306            
307            builder.addInterface(ConfigurationStore.class);
308            
309            builder.setConstructor(new String[]{GBEAN_ATTR_KERNEL,
310                GBEAN_ATTR_OBJECT_NAME,
311                    "abstractName",
312                GBEAN_REF_REPOSITORY,
313                GBEAN_ATTR_DEFAULT_ENV,
314                GBEAN_REF_CLUSTER_INFO,
315                GBEAN_REF_CLUSTER_CONF_STORE_CLIENT});
316            
317            GBEAN_INFO = builder.getBeanInfo();
318        }
319    
320        public static GBeanInfo getGBeanInfo() {
321            return GBEAN_INFO;
322        }
323    
324    }