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 }