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 }