001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.j2ee.websphere6.ui.wizard;
042:
043: import java.io.BufferedReader;
044: import java.io.File;
045: import java.io.FileInputStream;
046: import java.io.IOException;
047: import java.io.InputStreamReader;
048: import java.util.*;
049: import java.awt.*;
050: import java.awt.event.*;
051: import java.util.logging.Level;
052: import java.util.logging.Logger;
053: import javax.swing.*;
054: import javax.swing.event.*;
055: import javax.swing.filechooser.*;
056:
057: import org.openide.*;
058: import org.openide.util.*;
059:
060: /**
061: * The first panel of the custom wizard used to register new server instance.
062: * User is required to enter the local server's installation directory at this
063: * phase.
064: *
065: * @author Kirill Sorokin
066: * @author Arathi
067: */
068: public class ServerLocationPanel extends JPanel implements
069: WizardDescriptor.Panel {
070:
071: private static final Logger LOGGER = Logger
072: .getLogger(ServerLocationPanel.class.getName());
073:
074: /**
075: * Since the WizardDescriptor does not expose the property name for the
076: * error message label, we have to keep it here also
077: */
078: private final static String PROP_ERROR_MESSAGE = "WizardPanel_errorMessage"; // NOI18N
079:
080: /**
081: * The parent wizard descriptor handle
082: */
083: private transient WizardDescriptor wizardDescriptor;
084:
085: /**
086: * The parent instantiaing iterator handle
087: */
088: private transient WSInstantiatingIterator instantiatingIterator;
089:
090: /**
091: * Creates a new instance of the ServerLocationPanel. It initializes all the
092: * GUI components that appear on the panel.
093: *
094: * @param steps the names of the steps in the wizard
095: * @param index index of this panel in the wizard
096: * @param listener a listener that will propagate the chage event higher in
097: * the hierarchy
098: * @param instantiatingIterator the parent instantiating iterator
099: */
100: public ServerLocationPanel(String[] steps, int index,
101: ChangeListener listener,
102: WSInstantiatingIterator instantiatingIterator) {
103: // save the instantiating iterator
104: this .instantiatingIterator = instantiatingIterator;
105:
106: // set the required properties, so that the panel appear correct in
107: // the steps
108: putClientProperty("WizardPanel_contentData", steps); // NOI18N
109: putClientProperty("WizardPanel_contentSelectedIndex", // NOI18N
110: Integer.valueOf(index));
111:
112: // register the supplied listener
113: addChangeListener(listener);
114:
115: // set the panel's name
116: setName(steps[index]);
117:
118: // init the GUI
119: init();
120: }
121:
122: /**
123: * Returns the named help article associated with this panel
124: *
125: * @return the associated help article
126: */
127: public HelpCtx getHelp() {
128: return new HelpCtx("j2eeplugins_registering_app_" + // NOI18N
129: "server_websphere"); // NOI18N
130: }
131:
132: /**
133: * Gets the panel's AWT Component object, in our case it coincides with this
134: * object
135: *
136: * @return this
137: */
138: public Component getComponent() {
139: return this ;
140: }
141:
142: /**
143: * Checks whether the data input is valid
144: *
145: * @return true if the entered installation directory is valid, false
146: * otherwise
147: */
148: public boolean isValid() {
149: // clear the error message
150: wizardDescriptor.putProperty(PROP_ERROR_MESSAGE, "");
151:
152: // check for the validity of the entered installation directory
153: // if it's invalid, return false
154: if (!isValidServerRoot(locationField.getText())) {
155: wizardDescriptor.putProperty(PROP_ERROR_MESSAGE, NbBundle
156: .getMessage(ServerLocationPanel.class,
157: "ERR_INVALID_SERVER_ROOT")); // NOI18N
158: return false;
159: }
160:
161: // set the server root in the parent instantiating iterator
162: instantiatingIterator.setServerRoot(locationField.getText());
163:
164: // everything seems ok
165: return true;
166: }
167:
168: ////////////////////////////////////////////////////////////////////////////
169: // JPanel section
170: ////////////////////////////////////////////////////////////////////////////
171: private JButton locationBrowseButton;
172: private JLabel locationLabel;
173: private JTextField locationField;
174: private JPanel formattingPanel;
175:
176: /**
177: * Inits the GUI components
178: */
179: private void init() {
180: // we use the GridBagLayout so we need the GridBagConstraints to
181: // properly place the components
182: GridBagConstraints gridBagConstraints;
183:
184: // initialize the components
185: locationLabel = new JLabel();
186: locationField = new JTextField();
187: locationBrowseButton = new JButton();
188: formattingPanel = new JPanel();
189:
190: // set the desired layout
191: setLayout(new GridBagLayout());
192:
193: // add server installation directory field label
194: locationLabel.setText(NbBundle.getMessage(
195: ServerLocationPanel.class, "LBL_SERVER_LOCATION")); // NOI18N
196: locationLabel.setDisplayedMnemonic(NbBundle.getMessage(
197: ServerLocationPanel.class, "MNE_SERVER_LOCATION")
198: .charAt(0));
199: locationLabel.setLabelFor(locationField);
200: gridBagConstraints = new GridBagConstraints();
201: gridBagConstraints.gridx = 0;
202: gridBagConstraints.gridy = 0;
203: gridBagConstraints.anchor = GridBagConstraints.EAST;
204: add(locationLabel, gridBagConstraints);
205:
206: // add server installation directory field
207: locationField.addKeyListener(new LocationKeyListener());
208: if (System.getProperty("websphere.home") == null
209: || System.getProperty("websphere.home").equals("")) {
210: String home = System.getProperty("user.home");
211: if (home != null) {
212: try {
213: File f = new File(home + File.separator
214: + ".WASRegistry");
215: BufferedReader reader = new BufferedReader(
216: new InputStreamReader(
217: new FileInputStream(f)));
218: try {
219: String string;
220: while ((string = reader.readLine()) != null) {
221: if (string.length() > 1
222: && new File(string).exists()) {
223: System.setProperty("websphere.home",
224: string);
225: }
226: }
227: } finally {
228: reader.close();
229: }
230: } catch (IOException e) {
231: LOGGER.log(Level.FINE, null, e);
232: }
233: }
234: }
235:
236: if (System.getProperty("websphere.home") != null) { // NOI18N
237: locationField.setText(System.getProperty("websphere.home")); // NOI18N
238: }
239: gridBagConstraints = new GridBagConstraints();
240: gridBagConstraints.gridx = 1;
241: gridBagConstraints.gridy = 0;
242: gridBagConstraints.fill = GridBagConstraints.HORIZONTAL;
243: gridBagConstraints.weightx = 1.0;
244: gridBagConstraints.insets = new Insets(0, 10, 0, 10);
245: locationField
246: .getAccessibleContext()
247: .setAccessibleName(
248: java.util.ResourceBundle
249: .getBundle(
250: "org/netbeans/modules/j2ee/websphere6/ui/wizard/Bundle")
251: .getString("TTL_Location"));
252: locationField
253: .getAccessibleContext()
254: .setAccessibleDescription(
255: java.util.ResourceBundle
256: .getBundle(
257: "org/netbeans/modules/j2ee/websphere6/ui/wizard/Bundle")
258: .getString("MSG_Location"));
259:
260: add(locationField, gridBagConstraints);
261:
262: // add server installation directory field browse button
263: locationBrowseButton.setText(NbBundle.getMessage(
264: ServerLocationPanel.class, "LBL_BROWSE_BUTTON")); // NOI18N
265: locationBrowseButton.setMnemonic(KeyEvent.VK_O);
266: locationBrowseButton.setDisplayedMnemonicIndex(2);
267: locationBrowseButton
268: .addActionListener(new BrowseActionListener());
269: gridBagConstraints = new GridBagConstraints();
270: gridBagConstraints.gridx = 2;
271: gridBagConstraints.gridy = 0;
272: gridBagConstraints.anchor = GridBagConstraints.WEST;
273: locationBrowseButton
274: .getAccessibleContext()
275: .setAccessibleName(
276: java.util.ResourceBundle
277: .getBundle(
278: "org/netbeans/modules/j2ee/websphere6/ui/wizard/Bundle")
279: .getString("TTL_Browse"));
280: locationBrowseButton
281: .getAccessibleContext()
282: .setAccessibleDescription(
283: java.util.ResourceBundle
284: .getBundle(
285: "org/netbeans/modules/j2ee/websphere6/ui/wizard/Bundle")
286: .getString("MSG_Browse"));
287:
288: add(locationBrowseButton, gridBagConstraints);
289:
290: // add the empty panel, that will take up all the remaining space
291: gridBagConstraints = new GridBagConstraints();
292: gridBagConstraints.gridx = 0;
293: gridBagConstraints.gridy = 1;
294: gridBagConstraints.gridwidth = GridBagConstraints.REMAINDER;
295: gridBagConstraints.weighty = 1.0;
296: add(formattingPanel, gridBagConstraints);
297: getAccessibleContext()
298: .setAccessibleDescription(
299: java.util.ResourceBundle
300: .getBundle(
301: "org/netbeans/modules/j2ee/websphere6/ui/wizard/Bundle")
302: .getString(
303: "MSG_ServerLocationPanelDescription"));
304: }
305:
306: /**
307: * An instance of the fileschooser that is used for locating the server
308: * installation directory
309: */
310: private JFileChooser fileChooser = new JFileChooser();
311:
312: /**
313: * Shows the filechooser set to currently selected directory or to the
314: * default system root if the directory is invalid
315: */
316: private void showFileChooser() {
317: // set the chooser's properties
318: fileChooser.setFileFilter(new DirectoryFileFilter());
319: fileChooser.setMultiSelectionEnabled(false);
320: fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
321:
322: // set the current directory
323: File currentLocation = new File(locationField.getText());
324: if (currentLocation.exists() && currentLocation.isDirectory()) {
325: fileChooser.setCurrentDirectory(currentLocation
326: .getParentFile());
327: fileChooser.setSelectedFile(currentLocation);
328: }
329:
330: // wait for the user to choose the directory and if he clicked the OK
331: // button store the selected directory in the server location field
332: if (fileChooser.showOpenDialog(SwingUtilities
333: .getWindowAncestor(this )) == JFileChooser.APPROVE_OPTION) {
334: locationField.setText(fileChooser.getSelectedFile()
335: .getPath());
336: fireChangeEvent();
337: }
338: }
339:
340: /**
341: * Checks whether the supplied directory is the valid server installation
342: * directory.
343: *
344: * @return true if the supplied directory is valid, false otherwise
345: */
346: private static boolean isValidServerRoot(String path) {
347: // set the child directories/files that should be present and validate
348: // the directory as the server's installation one
349:
350: // This is for WAS 6.1
351: String dbDir = "derby";
352: String jsr88Jar = "plugins/com.ibm.ws.runtime_6.1.0.jar";
353:
354: // This is for WAS 6.0
355: if ((new File(path + File.separator + "cloudscape").exists())) {
356: dbDir = "cloudscape";
357: jsr88Jar = "lib/wjmxapp.jar";
358: }
359:
360: String[] children = { "bin", // NOI18N
361: dbDir, // NOI18N
362: "profiles", // NOI18N
363: "properties/wsadmin.properties", // NOI18N
364: "lib/j2ee.jar", // NOI18N
365: jsr88Jar // NOI18N
366: };
367: return hasChildren(path, children);
368: }
369:
370: /**
371: * Checks whether the supplied directory has the required children
372: *
373: * @return true if the directory contains all the children, false otherwise
374: */
375: private static boolean hasChildren(String parent, String[] children) {
376: // if parent is null, it cannot contain any children
377: if (parent == null) {
378: return false;
379: }
380:
381: // if the children array is null, then the condition is fullfilled
382: if (children == null) {
383: return true;
384: }
385:
386: // for each child check whether it is contained and if it is not,
387: // return false
388: for (int i = 0; i < children.length; i++) {
389: if (!(new File(parent + File.separator + children[i])
390: .exists())) {
391: return false;
392: }
393: }
394:
395: // all is good
396: return true;
397: }
398:
399: ////////////////////////////////////////////////////////////////////////////
400: // Settings section
401: ////////////////////////////////////////////////////////////////////////////
402: /**
403: * Reads the supplied setting. The only one that can arrive this way is the
404: * WizardDescriptor, thus we only convert the incoming object and save
405: *
406: * @param object the incoming setting (WizardDescriptor)
407: */
408: public void readSettings(Object object) {
409: this .wizardDescriptor = (WizardDescriptor) object;
410: }
411:
412: /**
413: * Stores the supplied setting. I don't know the purpose of this method
414: * thus we do not implement it
415: */
416: public void storeSettings(Object object) {
417: }
418:
419: ////////////////////////////////////////////////////////////////////////////
420: // Listeners section
421: ////////////////////////////////////////////////////////////////////////////
422: /**
423: * The registrered listeners vector
424: */
425: private Vector listeners = new Vector();
426:
427: /**
428: * Removes a registered listener
429: *
430: * @param listener the listener to be removed
431: */
432: public void removeChangeListener(ChangeListener listener) {
433: if (listeners != null) {
434: synchronized (listeners) {
435: listeners.remove(listener);
436: }
437: }
438: }
439:
440: /**
441: * Adds a listener
442: *
443: * @param listener the listener to be added
444: */
445: public void addChangeListener(ChangeListener listener) {
446: synchronized (listeners) {
447: listeners.add(listener);
448: }
449: }
450:
451: /**
452: * Fires a change event originating from this panel
453: */
454: private void fireChangeEvent() {
455: ChangeEvent event = new ChangeEvent(this );
456: fireChangeEvent(event);
457: }
458:
459: /**
460: * Fires a custom change event
461: *
462: * @param event the event
463: */
464: private void fireChangeEvent(ChangeEvent event) {
465: Vector targetListeners;
466: synchronized (listeners) {
467: targetListeners = (Vector) listeners.clone();
468: }
469:
470: for (int i = 0; i < targetListeners.size(); i++) {
471: ChangeListener listener = (ChangeListener) targetListeners
472: .elementAt(i);
473: listener.stateChanged(event);
474: }
475: }
476:
477: ////////////////////////////////////////////////////////////////////////////
478: // Inner Classes
479: ////////////////////////////////////////////////////////////////////////////
480: /**
481: * Simple key listener that delegates the event to its parent's listeners
482: *
483: * @author Kirill Sorokin
484: */
485: private class LocationKeyListener extends KeyAdapter {
486: /**
487: * This method is called when a user presses a key on the keyboard
488: */
489: public void keyTyped(KeyEvent event) {
490: fireChangeEvent();
491: }
492:
493: /**
494: * This method is called when a user releases a key on the keyboard
495: */
496: public void keyReleased(KeyEvent event) {
497: fireChangeEvent();
498: }
499: }
500:
501: /**
502: * Simple listener that reacts on the user's clicking the Browse button
503: *
504: * @author Kirill Sorokin
505: */
506: private class BrowseActionListener implements ActionListener {
507: /**
508: * this methos is called when a user clicks Browse and show the file
509: * chooser dialog in response
510: */
511: public void actionPerformed(ActionEvent event) {
512: showFileChooser();
513: }
514: }
515:
516: /**
517: * An extension of the FileFilter class that is setup to accept only
518: * directories.
519: *
520: * @author Kirill Sorokin
521: */
522: private static class DirectoryFileFilter extends FileFilter {
523: /**
524: * This method is called when it is needed to decide whether a chosen
525: * file meets the filter's requirements
526: *
527: * @return true if the file meets the requirements, false otherwise
528: */
529: public boolean accept(File file) {
530: // if the file exists and it's a directory - accept it
531: if (file.exists() && file.isDirectory()) {
532: return true;
533: }
534:
535: // in all other cases - refuse
536: return false;
537: }
538:
539: /**
540: * Returns the description of file group described by this filter
541: *
542: * @return group name
543: */
544: public String getDescription() {
545: return NbBundle.getMessage(ServerLocationPanel.class,
546: "DIRECTORIES_FILTER_NAME"); // NOI18N
547: }
548: }
549: }
|