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 018 package org.apache.geronimo.deployment.cli; 019 020 import java.io.BufferedInputStream; 021 import java.io.File; 022 import java.io.FileInputStream; 023 import java.io.FileNotFoundException; 024 import java.io.IOException; 025 import java.io.InputStream; 026 import java.io.PrintWriter; 027 import java.io.Serializable; 028 import java.util.Properties; 029 import java.util.jar.JarFile; 030 031 import javax.enterprise.deploy.shared.factories.DeploymentFactoryManager; 032 import javax.enterprise.deploy.spi.DeploymentManager; 033 import javax.enterprise.deploy.spi.exceptions.DeploymentManagerCreationException; 034 import javax.enterprise.deploy.spi.factories.DeploymentFactory; 035 036 import org.apache.geronimo.cli.deployer.DeployerCLParser; 037 import org.apache.geronimo.common.DeploymentException; 038 import org.apache.geronimo.deployment.plugin.factories.AuthenticationFailedException; 039 import org.apache.geronimo.deployment.plugin.jmx.JMXDeploymentManager; 040 import org.apache.geronimo.deployment.plugin.jmx.LocalDeploymentManager; 041 import org.apache.geronimo.kernel.Kernel; 042 import org.apache.geronimo.util.SimpleEncryption; 043 044 /** 045 * Supports online connections to the server, via JSR-88, valid only 046 * when the server is online. 047 * 048 * @version $Rev: 549455 $ $Date: 2007-06-21 08:12:27 -0400 (Thu, 21 Jun 2007) $ 049 */ 050 public class ServerConnection { 051 052 private final static String DEFAULT_URI = "deployer:geronimo:jmx"; 053 054 private final DeploymentFactory geronimoDeploymentFactory; 055 056 private DeploymentManager manager; 057 private PrintWriter out; 058 private InputStream in; 059 private SavedAuthentication auth; 060 private boolean logToSysErr; 061 private boolean verboseMessages; 062 063 public ServerConnection(DeployerCLParser parser, PrintWriter out, InputStream in, Kernel kernel, DeploymentFactory geronimoDeploymentFactory) throws DeploymentException { 064 if (null == kernel) { 065 throw new IllegalArgumentException("kernel is required"); 066 } 067 this.geronimoDeploymentFactory = geronimoDeploymentFactory; 068 069 this.out = out; 070 this.in = in; 071 boolean offline = false; 072 073 String uri = parser.getURI(); 074 String driver = parser.getDriver(); 075 String user = parser.getUser(); 076 String password = parser.getPassword(); 077 String host = parser.getHost(); 078 Integer port = parser.getPort(); 079 verboseMessages = parser.isVerbose(); 080 logToSysErr = parser.isSyserr(); 081 offline = parser.isOffline(); 082 083 if ((driver != null) && uri == null) { 084 throw new DeploymentSyntaxException("A custom driver requires a custom URI"); 085 } 086 if (host != null || port != null) { 087 uri = DEFAULT_URI + "://" + (host == null ? "" : host) + (port == null ? "" : ":" + port); 088 } 089 if (offline) { 090 startOfflineDeployer(kernel); 091 manager = new LocalDeploymentManager(kernel); 092 } else { 093 tryToConnect(uri, driver, user, password, true); 094 } 095 if (manager == null) { 096 throw new DeploymentException("Unexpected error; connection failed."); 097 } 098 } 099 100 protected void startOfflineDeployer(Kernel kernel) throws DeploymentException { 101 OfflineDeployerStarter offlineDeployerStarter = new OfflineDeployerStarter(kernel); 102 offlineDeployerStarter.start(); 103 } 104 105 public void close() throws DeploymentException { 106 if (manager != null) { 107 manager.release(); 108 } 109 } 110 111 Serializable getAuthentication() { 112 return auth; 113 } 114 115 String getServerURI() { 116 return auth.uri; 117 } 118 119 private void tryToConnect(String argURI, String driver, String user, String password, boolean authPrompt) throws DeploymentException { 120 DeploymentFactoryManager mgr = DeploymentFactoryManager.getInstance(); 121 if (driver != null) { 122 loadDriver(driver, mgr); 123 } else { 124 mgr.registerDeploymentFactory(geronimoDeploymentFactory); 125 } 126 String useURI = argURI == null ? DEFAULT_URI : argURI; 127 128 if (authPrompt && user == null && password == null) { 129 InputStream in; 130 // First check for .geronimo-deployer on class path (e.g. packaged in deployer.jar) 131 in = ServerConnection.class.getResourceAsStream("/.geronimo-deployer"); 132 // If not there, check in home directory 133 if (in == null) { 134 File authFile = new File(System.getProperty("user.home"), ".geronimo-deployer"); 135 if (authFile.exists() && authFile.canRead()) { 136 try { 137 in = new BufferedInputStream(new FileInputStream(authFile)); 138 } catch (FileNotFoundException e) { 139 // ignore 140 } 141 } 142 } 143 if (in != null) { 144 try { 145 Properties props = new Properties(); 146 props.load(in); 147 String encryped = props.getProperty("login." + useURI); 148 if (encryped != null) { 149 if (encryped.startsWith("{Standard}")) { 150 SavedAuthentication auth = (SavedAuthentication) SimpleEncryption.decrypt(encryped.substring(10)); 151 if (auth.uri.equals(useURI)) { 152 user = auth.user; 153 password = new String(auth.password); 154 } 155 } else if (encryped.startsWith("{Plain}")) { 156 int pos = encryped.indexOf("/"); 157 user = encryped.substring(7, pos); 158 password = encryped.substring(pos + 1); 159 } else { 160 System.out.print(DeployUtils.reformat("Unknown encryption used in saved login file", 4, 72)); 161 } 162 } 163 } catch (IOException e) { 164 System.out.print(DeployUtils.reformat("Unable to read authentication from saved login file: " + e.getMessage(), 4, 72)); 165 } finally { 166 try { 167 in.close(); 168 } catch (IOException e) { 169 // ingore 170 } 171 } 172 } 173 } 174 175 if (authPrompt && !useURI.equals(DEFAULT_URI) && user == null && password == null) { 176 // Non-standard URI, but no authentication information 177 doAuthPromptAndRetry(useURI, user, password); 178 return; 179 } else { // Standard URI with no auth, Non-standard URI with auth, or else this is the 2nd try already 180 try { 181 manager = mgr.getDeploymentManager(useURI, user, password); 182 auth = new SavedAuthentication(useURI, user, password == null ? null : password.toCharArray()); 183 } catch (AuthenticationFailedException e) { // server's there, you just can't talk to it 184 if (authPrompt) { 185 doAuthPromptAndRetry(useURI, user, password); 186 return; 187 } else { 188 throw new DeploymentException("Login Failed"); 189 } 190 } catch (DeploymentManagerCreationException e) { 191 throw new DeploymentException("Unable to connect to server at " + useURI + " -- " + e.getMessage(), e); 192 } 193 } 194 195 if (manager instanceof JMXDeploymentManager) { 196 JMXDeploymentManager deploymentManager = (JMXDeploymentManager) manager; 197 deploymentManager.setLogConfiguration(logToSysErr, verboseMessages); 198 } 199 } 200 201 private void loadDriver(String driver, DeploymentFactoryManager mgr) throws DeploymentException { 202 File file = new File(driver); 203 if (!file.exists() || !file.canRead() || !DeployUtils.isJarFile(file)) { 204 throw new DeploymentSyntaxException("Driver '" + file.getAbsolutePath() + "' is not a readable JAR file"); 205 } 206 String className = null; 207 try { 208 JarFile jar = new JarFile(file); 209 className = jar.getManifest().getMainAttributes().getValue("J2EE-DeploymentFactory-Implementation-Class"); 210 if (className == null) { 211 throw new DeploymentException("The driver JAR " + file.getAbsolutePath() + " does not specify a J2EE-DeploymentFactory-Implementation-Class; cannot load driver."); 212 } 213 jar.close(); 214 DeploymentFactory factory = (DeploymentFactory) Class.forName(className).newInstance(); 215 mgr.registerDeploymentFactory(factory); 216 } catch (DeploymentException e) { 217 throw e; 218 } catch (Exception e) { 219 throw new DeploymentSyntaxException("Unable to load driver class " + className + " from JAR " + file.getAbsolutePath(), e); 220 } 221 } 222 223 private void doAuthPromptAndRetry(String uri, String user, String password) throws DeploymentException { 224 try { 225 InputPrompt prompt = new InputPrompt(in, out); 226 if (user == null) { 227 user = prompt.getInput("Username: "); 228 } 229 if (password == null) { 230 password = prompt.getPassword("Password: "); 231 } 232 } catch (IOException e) { 233 throw new DeploymentException("Unable to prompt for login", e); 234 } 235 tryToConnect(uri, null, user, password, false); 236 } 237 238 public DeploymentManager getDeploymentManager() { 239 return manager; 240 } 241 242 public boolean isGeronimo() { 243 return manager.getClass().getName().startsWith("org.apache.geronimo."); 244 } 245 246 private final static class SavedAuthentication implements Serializable { 247 private String uri; 248 private String user; 249 private char[] password; 250 251 public SavedAuthentication(String uri, String user, char[] password) { 252 this.uri = uri; 253 this.user = user; 254 this.password = password; 255 } 256 } 257 }