001: /*
002: * IzPack - Copyright 2001-2008 Julien Ponge, All Rights Reserved.
003: *
004: * http://izpack.org/
005: * http://izpack.codehaus.org/
006: *
007: * Copyright 2002 Johannes Lehtinen
008: *
009: * Licensed under the Apache License, Version 2.0 (the "License");
010: * you may not use this file except in compliance with the License.
011: * You may obtain a copy of the License at
012: *
013: * http://www.apache.org/licenses/LICENSE-2.0
014: *
015: * Unless required by applicable law or agreed to in writing, software
016: * distributed under the License is distributed on an "AS IS" BASIS,
017: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018: * See the License for the specific language governing permissions and
019: * limitations under the License.
020: */
021:
022: package com.izforge.izpack.installer;
023:
024: import java.awt.BorderLayout;
025: import java.awt.Component;
026: import java.awt.GridLayout;
027: import java.awt.Toolkit;
028: import java.io.InputStream;
029: import java.net.Authenticator;
030: import java.net.ConnectException;
031: import java.net.HttpURLConnection;
032: import java.net.InetAddress;
033: import java.net.PasswordAuthentication;
034: import java.net.URL;
035: import java.net.URLConnection;
036: import java.util.Locale;
037:
038: import javax.swing.JDialog;
039: import javax.swing.JLabel;
040: import javax.swing.JOptionPane;
041: import javax.swing.JPanel;
042: import javax.swing.JPasswordField;
043: import javax.swing.JTextField;
044: import javax.swing.UIManager;
045:
046: /**
047: * Dialogs for password authentication and firewall specification, when needed, during web
048: * installation.
049: *
050: * @author Chadwick McHenry
051: * @author <a href="vralev@redhat.com">Vladimir Ralev</a>
052: * @version 1.0
053: */
054: public class WebAccessor {
055:
056: private Thread openerThread = null;
057:
058: private InputStream iStream = null;
059:
060: private Exception exception = null;
061:
062: private Object soloCancelOption = null;
063:
064: private Component parent = null;
065:
066: private JDialog dialog = null;
067:
068: private boolean tryProxy = false;
069:
070: private JPanel passwordPanel = null;
071:
072: private JLabel promptLabel;
073:
074: private JTextField nameField;
075:
076: private JPasswordField passField;
077:
078: private JPanel proxyPanel = null;
079:
080: private JLabel errorLabel;
081:
082: private JTextField hostField;
083:
084: private JTextField portField;
085:
086: private String url;
087:
088: private int contentLength = -1;
089:
090: /**
091: * Not yet Implemented: placeholder for headless installs.
092: *
093: * @throws UnsupportedOperationException
094: */
095: public WebAccessor() {
096: // the class should probably be rearranged to do this.
097: throw new UnsupportedOperationException();
098: }
099:
100: /**
101: * Create a WebAccessor that prompts for proxies and passwords using a JDialog.
102: *
103: * @param parent determines the frame in which the dialog is displayed; if the parentComponent
104: * has no Frame, a default Frame is used
105: */
106: public WebAccessor(Component parent) {
107: this .parent = parent;
108: Locale l = null;
109: if (parent != null)
110: parent.getLocale();
111: soloCancelOption = UIManager.get("OptionPane.cancelButtonText",
112: l);// TODO:
113: // i18n?
114: Authenticator.setDefault(new MyDialogAuthenticator());
115: }
116:
117: /**
118: * Opens a URL connection and returns it's InputStream for the specified URL.
119: *
120: * @param url the url to open the stream to.
121: * @return an input stream ready to read, or null on failure
122: */
123: public InputStream openInputStream(URL url) {
124: setUrl(url.toExternalForm());
125: OPEN_URL: while (true) {
126: startOpening(url); // this starts a thread
127:
128: Thread.yield();
129:
130: // Wait a bit to see if the stream comes up
131: int retry = 28;
132: while (exception == null && iStream == null && retry > 0)
133: try {
134: Thread.sleep(200);
135: retry--;
136: } catch (Exception e) {
137: System.out.println("In openInputStream: " + e);
138: }
139:
140: /* Try to find a proxy if that failed */
141:
142: // success!
143: if (iStream != null)
144: break;
145:
146: // an exception we don't expect setting a proxy to fix
147: if (!tryProxy)
148: break;
149:
150: // else (exception != null)
151: // show proxy dialog until valid values or cancel
152: JPanel panel = getProxyPanel();
153: errorLabel.setText("Unable to connect: "
154: + exception.getMessage());
155: while (true) {
156: int result = JOptionPane.showConfirmDialog(parent,
157: panel, "Proxy Configuration",
158: JOptionPane.OK_CANCEL_OPTION,
159: JOptionPane.QUESTION_MESSAGE);
160: if (result != JOptionPane.OK_OPTION) // canceled
161: break OPEN_URL;
162:
163: String host = null;
164: String port = null;
165:
166: try {
167: InetAddress addr = InetAddress.getByName(hostField
168: .getText());
169: host = addr.getHostName();
170: } catch (Exception x) {
171: errorLabel.setText("Unable to resolve Host");
172: Toolkit.getDefaultToolkit().beep();
173: }
174:
175: try {
176: if (host != null)
177: port = Integer.valueOf(portField.getText())
178: .toString();
179: } catch (NumberFormatException x) {
180: errorLabel.setText("Invalid Port");
181: Toolkit.getDefaultToolkit().beep();
182: }
183:
184: if (host != null && port != null) {
185: // System.err.println ("Setting http proxy: "+ host
186: // +":"+ port);
187: System.getProperties().put("proxySet", "true");
188: System.getProperties().put("proxyHost", host);
189: System.getProperties().put("proxyPort", port);
190: break;
191: }
192: }
193: }
194:
195: if (iStream == null)
196: openerThread.interrupt();
197:
198: return iStream;
199: }
200:
201: private void startOpening(final URL url) {
202: final WebAccessor wa = this ;
203: openerThread = new Thread() {
204: public void run() {
205: iStream = null;
206: try {
207: tryProxy = false;
208:
209: URLConnection connection = url.openConnection();
210:
211: if (connection instanceof HttpURLConnection) {
212: HttpURLConnection htc = (HttpURLConnection) connection;
213: contentLength = htc.getContentLength();
214: }
215:
216: //InputStream iii = echoSocket.getInputStream();
217: InputStream i = connection.getInputStream();
218: iStream = new LoggedInputStream(i, wa); // just to make
219:
220: } catch (ConnectException x) { // could be an incorrect proxy
221: tryProxy = true;
222: exception = x;
223:
224: } catch (Exception x) {
225: // Exceptions that get here are considered cancels or
226: // missing
227: // pages, eg 401 if user finally cancels auth
228: exception = x;
229:
230: } finally {
231: // if dialog is in use, allow it to become visible /before/
232: // closing
233: // it, else on /fast/ connectinos, it may open later and
234: // hang!
235: if (dialog != null) {
236: Thread.yield();
237: dialog.setVisible(false);
238: }
239: }
240: }
241: };
242: openerThread.start();
243: }
244:
245: /**
246: * Only to be called after an initial error has indicated a connection problem
247: */
248: private JPanel getProxyPanel() {
249: if (proxyPanel == null) {
250: proxyPanel = new JPanel(new BorderLayout(5, 5));
251:
252: errorLabel = new JLabel();
253:
254: JPanel fields = new JPanel(new GridLayout(2, 2));
255: String h = (String) System.getProperties().get("proxyHost");
256: String p = (String) System.getProperties().get("proxyPort");
257: hostField = new JTextField(h != null ? h : "");
258: portField = new JTextField(p != null ? p : "");
259: JLabel host = new JLabel("Host: "); // TODO: i18n
260: JLabel port = new JLabel("Port: "); // TODO: i18n
261: fields.add(host);
262: fields.add(hostField);
263: fields.add(port);
264: fields.add(portField);
265:
266: JLabel exampleLabel = new JLabel(
267: "e.g. host=\"gatekeeper.example.com\" port=\"80\"");
268:
269: proxyPanel.add(errorLabel, BorderLayout.NORTH);
270: proxyPanel.add(fields, BorderLayout.CENTER);
271: proxyPanel.add(exampleLabel, BorderLayout.SOUTH);
272: }
273: proxyPanel.validate();
274:
275: return proxyPanel;
276: }
277:
278: private JPanel getPasswordPanel() {
279: if (passwordPanel == null) {
280: passwordPanel = new JPanel(new BorderLayout(5, 5));
281:
282: promptLabel = new JLabel();
283:
284: JPanel fields = new JPanel(new GridLayout(2, 2));
285: nameField = new JTextField();
286: passField = new JPasswordField();
287: JLabel name = new JLabel("Name: "); // TODO: i18n
288: JLabel pass = new JLabel("Password: "); // TODO: i18n
289: fields.add(name);
290: fields.add(nameField);
291: fields.add(pass);
292: fields.add(passField);
293:
294: passwordPanel.add(promptLabel, BorderLayout.NORTH);
295: passwordPanel.add(fields, BorderLayout.CENTER);
296: }
297: passField.setText("");
298:
299: return passwordPanel;
300: }
301:
302: /**
303: * Authenticates via dialog when needed.
304: */
305: private class MyDialogAuthenticator extends Authenticator {
306:
307: public PasswordAuthentication getPasswordAuthentication() {
308: // TODO: i18n
309: JPanel p = getPasswordPanel();
310: String prompt = getRequestingPrompt();
311: InetAddress addr = getRequestingSite();
312: if (addr != null)
313: prompt += " (" + addr.getHostName() + ")";
314: promptLabel.setText(prompt);
315: int result = JOptionPane.showConfirmDialog(parent, p,
316: "Enter Password", JOptionPane.OK_CANCEL_OPTION,
317: JOptionPane.QUESTION_MESSAGE);
318: if (result != JOptionPane.OK_OPTION)
319: return null;
320:
321: return new PasswordAuthentication(nameField.getText(),
322: passField.getPassword());
323: }
324: }
325:
326: public String getUrl() {
327: return url;
328: }
329:
330: public void setUrl(String url) {
331: this .url = url;
332: }
333:
334: public int getContentLength() {
335: return contentLength;
336: }
337: }
|