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.net.URL;
025 import java.util.ArrayList;
026 import java.util.Collection;
027 import java.util.Set;
028
029 import org.apache.commons.logging.Log;
030 import org.apache.commons.logging.LogFactory;
031 import org.apache.geronimo.farm.config.ClusterInfo;
032 import org.apache.geronimo.farm.config.ExtendedJMXConnectorInfo;
033 import org.apache.geronimo.farm.config.NodeInfo;
034 import org.apache.geronimo.deployment.plugin.remote.FileUploadClient;
035 import org.apache.geronimo.deployment.plugin.remote.FileUploadProgress;
036 import org.apache.geronimo.deployment.plugin.remote.FileUploadServletClient;
037 import org.apache.geronimo.gbean.AbstractName;
038 import org.apache.geronimo.gbean.AbstractNameQuery;
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.ConfigurationData;
043 import org.apache.geronimo.kernel.config.InvalidConfigException;
044 import org.apache.geronimo.kernel.repository.Artifact;
045
046 /**
047 *
048 * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
049 */
050 public class BasicClusterConfigurationStoreClient implements ClusterConfigurationStoreClient {
051 private static final Log log = LogFactory.getLog(BasicClusterConfigurationStoreClient.class);
052
053 private static final String[] METHOD_SIGNATURE_INSTALL =
054 new String[] {ConfigurationData.class.getName(), File.class.getName()};
055 private static final String[] METHOD_SIGNATURE_UNINSTALL = new String[] {Artifact.class.getName()};
056
057 private final AbstractNameQuery clusterConfigurationStoreNameQuery;
058 private final DirectoryPackager packager;
059 private final FileUploadClient fileUploadClient;
060
061 public BasicClusterConfigurationStoreClient(AbstractNameQuery clusterConfigurationStoreNameQuery) {
062 if (null == clusterConfigurationStoreNameQuery) {
063 throw new IllegalArgumentException("clusterConfigurationStoreNameQuery is required");
064 }
065 this.clusterConfigurationStoreNameQuery = clusterConfigurationStoreNameQuery;
066
067 packager = newDirectoryPackager();
068 fileUploadClient = newFileUploadClient();
069 }
070
071 public void install(ClusterInfo clusterInfo, ConfigurationData configurationData)
072 throws IOException, InvalidConfigException {
073 Collection<NodeInfo> nodeInfos = clusterInfo.getNodeInfos();
074
075 Collection<NodeInfo> installedToNodeInfos = new ArrayList<NodeInfo>();
076 for (NodeInfo nodeInfo : nodeInfos) {
077 try {
078 install(nodeInfo, configurationData);
079 installedToNodeInfos.add(nodeInfo);
080 } catch (Exception e) {
081 uninstall(clusterInfo, configurationData.getId(), installedToNodeInfos);
082 if (e instanceof IOException) {
083 throw (IOException) e;
084 } else if (e instanceof InvalidConfigException) {
085 throw (InvalidConfigException) e;
086 }
087 throw (IOException) new IOException("See nested").initCause(e);
088 }
089 }
090 }
091
092 public void uninstall(ClusterInfo clusterInfo, Artifact configId) {
093 uninstall(clusterInfo, configId, clusterInfo.getNodeInfos());
094 }
095
096 protected void uninstall(ClusterInfo clusterInfo, Artifact configId, Collection<NodeInfo> installedToNodeInfos) {
097 for (NodeInfo nodeInfo : installedToNodeInfos) {
098 try {
099 uninstall(nodeInfo, configId);
100 } catch (Exception e) {
101 log.info("Ignoring error while uninstalling [" + configId + "]from [" + nodeInfo + "]", e);
102 }
103 }
104 }
105
106 protected void install(NodeInfo nodeInfo, ConfigurationData configurationData) throws IOException {
107 Kernel kernel = nodeInfo.newKernel();
108
109 AbstractName clusterConfigurationStoreName = searchClusterConfigurationStore(kernel);
110
111 File configurationDataFile = uploadConfiguration(kernel, nodeInfo, configurationData);
112
113 boolean inVMCall = nodeInfo.getConnectorInfo().isLocal();
114 File oldConfigurationDir = null;
115 if (inVMCall) {
116 oldConfigurationDir = configurationData.getConfigurationDir();
117 }
118 Object[] params = new Object[] {configurationData, configurationDataFile};
119 try {
120 kernel.invoke(clusterConfigurationStoreName, "install", params, METHOD_SIGNATURE_INSTALL);
121 } catch (Exception e) {
122 throw (IOException) new IOException("See nested").initCause(e);
123 } finally {
124 if (inVMCall) {
125 configurationData.setConfigurationDir(oldConfigurationDir);
126 }
127 }
128 }
129
130 protected void uninstall(NodeInfo nodeInfo, Artifact configId) throws IOException {
131 Kernel kernel = nodeInfo.newKernel();
132
133 AbstractName clusterConfigurationStoreName = searchClusterConfigurationStore(kernel);
134
135 Object[] params = new Object[] {configId};
136 try {
137 kernel.invoke(clusterConfigurationStoreName, "uninstall", params, METHOD_SIGNATURE_UNINSTALL);
138 } catch (Exception e) {
139 throw (IOException) new IOException("See nested").initCause(e);
140 }
141 }
142
143 protected File uploadConfiguration(Kernel kernel, NodeInfo nodeInfo, ConfigurationData configurationData) throws IOException {
144 File packedConfigurationDir = packager.pack(configurationData.getConfigurationDir());
145
146 if (nodeInfo.getConnectorInfo().isLocal()) {
147 return packedConfigurationDir;
148 }
149
150 URL remoteDeployUploadURL = fileUploadClient.getRemoteDeployUploadURL(kernel);
151
152 ConfigurationUploadProgress configurationUploadProgress = new ConfigurationUploadProgress(configurationData);
153 File[] configurationDataFiles = new File[] {packedConfigurationDir};
154 ExtendedJMXConnectorInfo connectorInfo = nodeInfo.getConnectorInfo();
155 fileUploadClient.uploadFilesToServer(remoteDeployUploadURL,
156 connectorInfo.getUsername(),
157 connectorInfo.getPassword(),
158 configurationDataFiles,
159 configurationUploadProgress);
160
161 if (configurationUploadProgress.failure) {
162 if (null != configurationUploadProgress.exception) {
163 throw (IOException) new IOException("See nested").initCause(configurationUploadProgress.exception);
164 }
165 throw new IOException(configurationUploadProgress.failureMessage);
166 }
167
168 return configurationDataFiles[0];
169 }
170
171 protected DirectoryPackager newDirectoryPackager() {
172 return new ZipDirectoryPackager();
173 }
174
175 protected FileUploadClient newFileUploadClient() {
176 return new FileUploadServletClient();
177 }
178
179 protected AbstractName searchClusterConfigurationStore(Kernel kernel) throws IOException {
180 Set<AbstractName> clusterConfigurationStoreNames = kernel.listGBeans(clusterConfigurationStoreNameQuery);
181 if (1 != clusterConfigurationStoreNames.size()) {
182 throw new IOException("Cannot locate remote store. Found [" + clusterConfigurationStoreNames + "]");
183 }
184 return clusterConfigurationStoreNames.iterator().next();
185 }
186
187 protected class ConfigurationUploadProgress implements FileUploadProgress {
188 private final ConfigurationData configurationData;
189 private boolean failure;
190 private Exception exception;
191 private String failureMessage;
192
193 public ConfigurationUploadProgress(ConfigurationData configurationData) {
194 this.configurationData = configurationData;
195 }
196
197 public void fail(String message) {
198 failure = true;
199 failureMessage = "Upload of configuration [" + configurationData.getId() + "] - [" + message + "]";
200 log.error("Upload of configuration [" + configurationData.getId() + "] - [" + message + "]");
201 }
202
203 public void fail(Exception exception) {
204 failure = true;
205 this.exception = exception;
206 log.error("Upload of configuration [" + configurationData.getId() + "]", exception);
207 }
208
209 public void updateStatus(String message) {
210 log.info("Upload of configuration [" + configurationData.getId() + "] - [" + message + "]");
211 }
212 }
213
214 public static final GBeanInfo GBEAN_INFO;
215
216 public static final String GBEAN_J2EE_TYPE = "ClusterConfigurationStoreClient";
217 public static final String GBEAN_ATTR_CLUSTER_CONF_STORE_NAME_QUERY = "clusterConfigurationStoreNameQuery";
218
219 static {
220 GBeanInfoBuilder builder = GBeanInfoBuilder.createStatic(BasicClusterConfigurationStoreClient.class, GBEAN_J2EE_TYPE);
221
222 builder.addAttribute(GBEAN_ATTR_CLUSTER_CONF_STORE_NAME_QUERY, AbstractNameQuery.class, true);
223
224 builder.addInterface(ClusterConfigurationStoreClient.class);
225
226 builder.setConstructor(new String[]{GBEAN_ATTR_CLUSTER_CONF_STORE_NAME_QUERY});
227
228 GBEAN_INFO = builder.getBeanInfo();
229 }
230
231 public static GBeanInfo getGBeanInfo() {
232 return GBEAN_INFO;
233 }
234
235 }