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