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:
042: package org.netbeans.modules.server.ui.manager;
043:
044: import java.awt.CardLayout;
045: import java.awt.Component;
046: import java.awt.Container;
047: import java.awt.Dimension;
048: import java.awt.GridBagConstraints;
049: import java.awt.GridBagLayout;
050: import java.awt.Window;
051: import java.beans.PropertyChangeListener;
052: import java.beans.PropertyChangeEvent;
053: import java.beans.PropertyVetoException;
054: import java.beans.VetoableChangeListener;
055: import java.io.Serializable;
056: import java.util.ArrayList;
057: import java.util.Collections;
058: import java.util.Comparator;
059: import java.util.List;
060: import java.util.logging.Level;
061: import java.util.logging.Logger;
062: import javax.swing.UIManager;
063: import org.netbeans.api.server.ServerInstance;
064: import org.netbeans.modules.server.ServerRegistry;
065: import org.netbeans.modules.server.ui.wizard.AddServerInstanceWizard;
066: import org.netbeans.spi.server.ServerInstanceProvider;
067: import org.openide.nodes.Node;
068: import org.openide.explorer.ExplorerManager;
069: import org.openide.explorer.view.BeanTreeView;
070: import org.openide.nodes.AbstractNode;
071: import org.openide.nodes.ChildFactory;
072: import org.openide.nodes.Children;
073: import org.openide.nodes.FilterNode;
074: import org.openide.util.NbBundle;
075:
076: /**
077: * Servers customizer displays a list of registered server and allows to add,
078: * remove and configure them.
079: *
080: * @author Stepan Herold
081: */
082: public class ServerManagerPanel extends javax.swing.JPanel implements
083: PropertyChangeListener, VetoableChangeListener,
084: ExplorerManager.Provider {
085:
086: private static final String SERVERS_ICON = "org/netbeans/modules/server/ui/resources/servers.png"; // NOI18N
087:
088: private static final Logger LOGGER = Logger
089: .getLogger(ServerManagerPanel.class.getName());
090:
091: private static final Dimension MINIMUM_SIZE = new Dimension(750,
092: 450);
093:
094: //private ServerCategoriesChildren children;
095: private ServersChildren children;
096: private ExplorerManager manager;
097: private ServerInstance initialInstance;
098:
099: /** Creates new form PlatformsCustomizer */
100: public ServerManagerPanel(ServerInstance initialInstance) {
101: initComponents();
102: serverName.setColumns(30);
103: serverType.setColumns(30);
104: // set the preferred width, height is not very important here
105: serversView.setPreferredSize(new Dimension(200, 200));
106: this .initialInstance = initialInstance;
107: setPreferredSize(MINIMUM_SIZE);
108: }
109:
110: public void addNotify() {
111: super .addNotify();
112: expandServers(initialInstance);
113: }
114:
115: public void propertyChange(PropertyChangeEvent evt) {
116: if (ExplorerManager.PROP_SELECTED_NODES.equals(evt
117: .getPropertyName())) {
118: Node[] nodes = (Node[]) evt.getNewValue();
119: if (nodes.length != 1) {
120: selectServer(null);
121: } else {
122: selectServer(nodes[0]);
123: }
124: }
125: }
126:
127: public void vetoableChange(PropertyChangeEvent evt)
128: throws PropertyVetoException {
129: if (ExplorerManager.PROP_SELECTED_NODES.equals(evt
130: .getPropertyName())) {
131: Node[] nodes = (Node[]) evt.getNewValue();
132: if (nodes.length != 1) {
133: throw new PropertyVetoException("Invalid length", evt); //NOI18N
134: }
135: }
136: }
137:
138: public synchronized ExplorerManager getExplorerManager() {
139: if (this .manager == null) {
140: this .manager = new ExplorerManager();
141: this .manager.setRootContext(new ServersNode(Children
142: .create(getChildren(), false)));
143: this .manager.addPropertyChangeListener(this );
144: this .manager.addVetoableChangeListener(this );
145: }
146: return manager;
147: }
148:
149: /** This method is called from within the constructor to
150: * initialize the form.
151: * WARNING: Do NOT modify this code. The content of this method is
152: * always regenerated by the Form Editor.
153: */
154: // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
155: private void initComponents() {
156: java.awt.GridBagConstraints gridBagConstraints;
157:
158: jPanel3 = new javax.swing.JPanel();
159: serversView = new org.openide.explorer.view.BeanTreeView();
160: addButton = new javax.swing.JButton();
161: removeButton = new javax.swing.JButton();
162: cardsPanel = new javax.swing.JPanel();
163: emptyPanel = new javax.swing.JPanel();
164: customizerPanel = new javax.swing.JPanel();
165: jLabel1 = new javax.swing.JLabel();
166: serverName = new javax.swing.JTextField();
167: jLabel2 = new javax.swing.JLabel();
168: serverType = new javax.swing.JTextField();
169: clientPanel = new javax.swing.JPanel();
170: serversLabel = new javax.swing.JLabel();
171:
172: serversView.setBorder(UIManager
173: .getBorder("Nb.ScrollPane.border"));
174: serversView.setPopupAllowed(false);
175: serversView.setPreferredSize(new java.awt.Dimension(220, 400));
176: serversView.setSelectionMode(0);
177:
178: org.openide.awt.Mnemonics.setLocalizedText(addButton, NbBundle
179: .getMessage(ServerManagerPanel.class, "CTL_AddServer")); // NOI18N
180: addButton
181: .addActionListener(new java.awt.event.ActionListener() {
182: public void actionPerformed(
183: java.awt.event.ActionEvent evt) {
184: addServer(evt);
185: }
186: });
187:
188: org.openide.awt.Mnemonics.setLocalizedText(removeButton,
189: NbBundle.getMessage(ServerManagerPanel.class,
190: "CTL_Remove")); // NOI18N
191: removeButton.setEnabled(false);
192: removeButton
193: .addActionListener(new java.awt.event.ActionListener() {
194: public void actionPerformed(
195: java.awt.event.ActionEvent evt) {
196: removeServer(evt);
197: }
198: });
199:
200: cardsPanel.setLayout(new java.awt.CardLayout());
201:
202: emptyPanel.setLayout(new java.awt.GridBagLayout());
203: cardsPanel.add(emptyPanel, "card3");
204:
205: customizerPanel.setLayout(new java.awt.GridBagLayout());
206:
207: jLabel1.setLabelFor(serverName);
208: org.openide.awt.Mnemonics
209: .setLocalizedText(jLabel1, NbBundle.getMessage(
210: ServerManagerPanel.class, "CTL_ServerName")); // NOI18N
211: gridBagConstraints = new java.awt.GridBagConstraints();
212: gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
213: customizerPanel.add(jLabel1, gridBagConstraints);
214: jLabel1.getAccessibleContext().setAccessibleName("null");
215: jLabel1.getAccessibleContext().setAccessibleDescription("null");
216:
217: serverName.setEditable(false);
218: gridBagConstraints = new java.awt.GridBagConstraints();
219: gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
220: gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
221: gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
222: gridBagConstraints.weightx = 1.0;
223: gridBagConstraints.insets = new java.awt.Insets(0, 6, 0, 0);
224: customizerPanel.add(serverName, gridBagConstraints);
225: serverName.getAccessibleContext().setAccessibleName("null");
226: serverName.getAccessibleContext().setAccessibleDescription(
227: "null");
228:
229: jLabel2.setLabelFor(serverType);
230: org.openide.awt.Mnemonics
231: .setLocalizedText(jLabel2, NbBundle.getMessage(
232: ServerManagerPanel.class, "CTL_ServerType")); // NOI18N
233: gridBagConstraints = new java.awt.GridBagConstraints();
234: gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
235: gridBagConstraints.insets = new java.awt.Insets(6, 0, 12, 0);
236: customizerPanel.add(jLabel2, gridBagConstraints);
237: jLabel2.getAccessibleContext().setAccessibleName("null");
238: jLabel2.getAccessibleContext().setAccessibleDescription("null");
239:
240: serverType.setEditable(false);
241: gridBagConstraints = new java.awt.GridBagConstraints();
242: gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
243: gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
244: gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
245: gridBagConstraints.weightx = 1.0;
246: gridBagConstraints.insets = new java.awt.Insets(6, 6, 12, 0);
247: customizerPanel.add(serverType, gridBagConstraints);
248: serverType.getAccessibleContext().setAccessibleName("null");
249: serverType.getAccessibleContext().setAccessibleDescription(
250: "null");
251:
252: clientPanel.setLayout(new java.awt.GridBagLayout());
253: gridBagConstraints = new java.awt.GridBagConstraints();
254: gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
255: gridBagConstraints.gridheight = java.awt.GridBagConstraints.REMAINDER;
256: gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
257: gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
258: gridBagConstraints.weightx = 1.0;
259: gridBagConstraints.weighty = 1.0;
260: customizerPanel.add(clientPanel, gridBagConstraints);
261:
262: cardsPanel.add(customizerPanel, "card2");
263:
264: serversLabel.setLabelFor(serversView);
265: org.openide.awt.Mnemonics.setLocalizedText(serversLabel,
266: org.openide.util.NbBundle.getMessage(
267: ServerManagerPanel.class, "CTL_Servers")); // NOI18N
268:
269: org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(
270: this );
271: this .setLayout(layout);
272: layout
273: .setHorizontalGroup(layout
274: .createParallelGroup(
275: org.jdesktop.layout.GroupLayout.LEADING)
276: .add(
277: layout
278: .createSequentialGroup()
279: .addContainerGap()
280: .add(
281: layout
282: .createParallelGroup(
283: org.jdesktop.layout.GroupLayout.LEADING)
284: .add(
285: serversLabel)
286: .add(
287: layout
288: .createSequentialGroup()
289: .add(
290: layout
291: .createParallelGroup(
292: org.jdesktop.layout.GroupLayout.TRAILING,
293: false)
294: .add(
295: serversView,
296: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE,
297: 0,
298: Short.MAX_VALUE)
299: .add(
300: org.jdesktop.layout.GroupLayout.LEADING,
301: layout
302: .createSequentialGroup()
303: .add(
304: addButton)
305: .addPreferredGap(
306: org.jdesktop.layout.LayoutStyle.RELATED)
307: .add(
308: removeButton)))
309: .addPreferredGap(
310: org.jdesktop.layout.LayoutStyle.UNRELATED)
311: .add(
312: cardsPanel,
313: org.jdesktop.layout.GroupLayout.DEFAULT_SIZE,
314: 267,
315: Short.MAX_VALUE)))
316: .addContainerGap()));
317: layout
318: .setVerticalGroup(layout
319: .createParallelGroup(
320: org.jdesktop.layout.GroupLayout.LEADING)
321: .add(
322: layout
323: .createSequentialGroup()
324: .addContainerGap()
325: .add(serversLabel)
326: .addPreferredGap(
327: org.jdesktop.layout.LayoutStyle.RELATED)
328: .add(
329: layout
330: .createParallelGroup(
331: org.jdesktop.layout.GroupLayout.TRAILING)
332: .add(
333: org.jdesktop.layout.GroupLayout.LEADING,
334: cardsPanel,
335: org.jdesktop.layout.GroupLayout.DEFAULT_SIZE,
336: 271,
337: Short.MAX_VALUE)
338: .add(
339: org.jdesktop.layout.GroupLayout.LEADING,
340: serversView,
341: org.jdesktop.layout.GroupLayout.DEFAULT_SIZE,
342: 271,
343: Short.MAX_VALUE))
344: .addPreferredGap(
345: org.jdesktop.layout.LayoutStyle.RELATED)
346: .add(
347: layout
348: .createParallelGroup(
349: org.jdesktop.layout.GroupLayout.BASELINE)
350: .add(addButton)
351: .add(
352: removeButton))
353: .addContainerGap()));
354:
355: serversView.getAccessibleContext().setAccessibleName("null");
356: serversView.getAccessibleContext().setAccessibleDescription(
357: "null");
358: addButton.getAccessibleContext().setAccessibleName("null");
359: addButton.getAccessibleContext().setAccessibleDescription(
360: "null");
361: removeButton.getAccessibleContext().setAccessibleName("null");
362: removeButton.getAccessibleContext().setAccessibleDescription(
363: "null");
364: serversLabel.getAccessibleContext().setAccessibleName("null");
365: java.util.ResourceBundle bundle = java.util.ResourceBundle
366: .getBundle("org/netbeans/modules/server/ui/manager/Bundle"); // NOI18N
367: serversLabel.getAccessibleContext().setAccessibleDescription(
368: bundle.getString("ACSD_ServerList")); // NOI18N
369:
370: getAccessibleContext().setAccessibleName("null");
371: getAccessibleContext().setAccessibleDescription("null");
372: }// </editor-fold>//GEN-END:initComponents
373:
374: private void removeServer(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_removeServer
375: Node[] nodes = getExplorerManager().getSelectedNodes();
376: //assert nodes.length != 1 : "Illegal number of selected nodes"; // NOI18N
377: LOGGER.log(Level.FINE, "----Remove");
378:
379: if (nodes[0] instanceof ServerNode) {
380: ServerInstance serverInstance = ((ServerNode) nodes[0])
381: .getServerInstance();
382: if (serverInstance.isRemovable()) {
383: LOGGER.log(Level.FINE, "Removing node");
384: serverInstance.remove();
385: LOGGER.log(Level.FINE, "Node removed");
386: LOGGER.log(Level.FINE, "Calling refresh");
387: getChildren().refresh();
388: // new Thread() {
389: //
390: // @Override
391: // public void run() {
392: // try {
393: // Thread.sleep(5000);
394: // } catch (InterruptedException ex) {}
395: // SwingUtilities.invokeLater(new Runnable() {
396: // public void run() {
397: // expandServers(null);
398: // }
399: // });
400:
401: // }
402: //
403: // }.start();
404: //LOGGER.log(Level.FINE, "Refresh called");
405: LOGGER.log(Level.FINE, "Expanding servers");
406: expandServers(null);
407: //LOGGER.log(Level.FINE, "Servers expanded");
408: }
409: }
410: LOGGER.log(Level.FINE, "----Remove finish");
411: }//GEN-LAST:event_removeServer
412:
413: private void addServer(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addServer
414: final ServerInstance instance = AddServerInstanceWizard
415: .showAddServerInstanceWizard();
416: if (instance != null) {
417: getChildren().refresh();
418: // new Thread() {
419: //
420: // @Override
421: // public void run() {
422: // try {
423: // Thread.sleep(5000);
424: // } catch (InterruptedException ex) {}
425: // SwingUtilities.invokeLater(new Runnable() {
426: // public void run() {
427: // expandServers(instance);
428: // }
429: // });
430: //
431: // }
432: //
433: // }.start();
434: expandServers(instance);
435: }
436: }//GEN-LAST:event_addServer
437:
438: private synchronized ServersChildren getChildren() {
439: if (this .children == null) {
440: this .children = new ServersChildren();
441: }
442: return this .children;
443: }
444:
445: private void selectServer(Node aNode) {
446: clientPanel.removeAll();
447:
448: ServerInstance serverInstance = null;
449: if (aNode instanceof ServerNode) {
450: serverInstance = ((ServerNode) aNode).getServerInstance();
451: serverName.setText(serverInstance.getDisplayName());
452: serverType.setText(serverInstance.getServerDisplayName());
453: if (!serverInstance.isRemovable()) {
454: removeButton.setEnabled(false);
455: } else {
456: removeButton.setEnabled(true);
457: }
458: } else {
459: removeButton.setEnabled(false);
460: ((CardLayout) cardsPanel.getLayout()).first(cardsPanel);
461: return;
462: }
463:
464: if (serverInstance.getCustomizer() != null) {
465: Component component = serverInstance.getCustomizer();
466: if (component != null) {
467: addComponent(clientPanel, component);
468: }
469: }
470: // handle the correct window size
471: int height = getHeight();
472: int width = getWidth();
473: // reset the preferred size so that it can be computed during revalidation
474: setPreferredSize(null);
475: revalidate();
476: // now we have the new computed preferred size
477: Dimension prefSize = getPreferredSize();
478: int prefWidth = (int) (prefSize.getWidth() > MINIMUM_SIZE
479: .getWidth() ? prefSize.getWidth() : MINIMUM_SIZE
480: .getWidth());
481: int prefHeight = (int) (prefSize.getHeight() > MINIMUM_SIZE
482: .getHeight() ? prefSize.getHeight() : MINIMUM_SIZE
483: .getHeight());
484: // do we need to resize the manager window?
485: if (prefHeight > height || prefWidth > width) {
486: setPreferredSize(new Dimension(
487: prefWidth > width ? prefWidth : width,
488: prefHeight > height ? prefHeight : height));
489: // repack the parent window
490: for (Container parent = getParent(); parent != null; parent = parent
491: .getParent()) {
492: if (parent instanceof Window) {
493: ((Window) parent).pack();
494: break;
495: }
496: }
497: }
498: CardLayout cl = (CardLayout) cardsPanel.getLayout();
499: cl.last(cardsPanel);
500: }
501:
502: private static void addComponent(Container container,
503: Component component) {
504: GridBagConstraints c = new GridBagConstraints();
505: c.gridx = c.gridy = GridBagConstraints.RELATIVE;
506: c.gridheight = c.gridwidth = GridBagConstraints.REMAINDER;
507: c.fill = GridBagConstraints.BOTH;
508: c.anchor = GridBagConstraints.NORTHWEST;
509: c.weightx = c.weighty = 1.0;
510: ((GridBagLayout) container.getLayout()).setConstraints(
511: component, c);
512: container.add(component);
513: }
514:
515: private void expandServers(ServerInstance servInst) {
516: ExplorerManager mgr = this .getExplorerManager();
517: Node node = mgr.getRootContext();
518: expandAllNodes(serversView, node, mgr, servInst);
519: }
520:
521: private static void expandAllNodes(BeanTreeView btv, Node node,
522: ExplorerManager mgr, ServerInstance servInst) {
523: //btv.expandNode(node);
524:
525: Children ch = node.getChildren();
526: //LOGGER.log(Level.FINE, "children: " + ch);
527:
528: // preselect node for the specified server instance
529: if (servInst != null && ch == Children.LEAF
530: && node instanceof ServerNode) {
531: try {
532: //LOGGER.log(Level.FINE, "preselect server");
533: if (((ServerNode) node).getServerInstance() == servInst) {
534: mgr.setSelectedNodes(new Node[] { node });
535: }
536: } catch (PropertyVetoException e) {
537: //Ignore it
538: e.printStackTrace();
539: }
540: }
541:
542: // preselect first server
543: if (servInst == null && ch == Children.LEAF
544: && mgr.getSelectedNodes().length == 0) {
545: try {
546: //LOGGER.log(Level.FINE, "preselect first");
547: mgr.setSelectedNodes(new Node[] { node });
548: } catch (PropertyVetoException e) {
549: //Ignore it
550: e.printStackTrace();
551: }
552: }
553: Node nodes[] = ch.getNodes(true);
554: //LOGGER.log(Level.FINE, "children nodes: " + nodes.length);
555: for (int i = 0; i < nodes.length; i++) {
556: //LOGGER.log(Level.FINE, "child node: " + nodes[i].getDisplayName());
557: expandAllNodes(btv, nodes[i], mgr, servInst);
558: }
559: }
560:
561: // Variables declaration - do not modify//GEN-BEGIN:variables
562: private javax.swing.JButton addButton;
563: private javax.swing.JPanel cardsPanel;
564: private javax.swing.JPanel clientPanel;
565: private javax.swing.JPanel customizerPanel;
566: private javax.swing.JPanel emptyPanel;
567: private javax.swing.JLabel jLabel1;
568: private javax.swing.JLabel jLabel2;
569: private javax.swing.JPanel jPanel3;
570: private javax.swing.JButton removeButton;
571: private javax.swing.JTextField serverName;
572: private javax.swing.JTextField serverType;
573: private javax.swing.JLabel serversLabel;
574: private org.openide.explorer.view.BeanTreeView serversView;
575:
576: // End of variables declaration//GEN-END:variables
577:
578: private static class ServersNode extends AbstractNode {
579:
580: public ServersNode(Children children) {
581: super (children);
582:
583: setName(""); // NOI18N
584: setDisplayName(NbBundle.getMessage(
585: ServerManagerPanel.class,
586: "Server_Registry_Node_Name"));
587: setShortDescription(NbBundle.getMessage(
588: ServerManagerPanel.class,
589: "Server_Registry_Node_Short_Description"));
590: setIconBaseWithExtension(SERVERS_ICON);
591: }
592:
593: }
594:
595: private static class ServersChildren extends
596: ChildFactory<ServerInstance> {
597:
598: private static final Comparator<ServerInstance> COMPARATOR = new InstanceComparator();
599:
600: public ServersChildren() {
601: super ();
602: }
603:
604: protected final void refresh() {
605: refresh(true);
606: }
607:
608: @Override
609: protected Node createNodeForKey(ServerInstance key) {
610: return new ServerNode(key);
611: }
612:
613: @Override
614: protected boolean createKeys(List<ServerInstance> toPopulate) {
615: List<ServerInstance> fresh = new ArrayList<ServerInstance>();
616: for (ServerInstanceProvider provider : ServerRegistry
617: .getInstance().getProviders()) {
618: fresh.addAll(provider.getInstances());
619: }
620:
621: Collections.sort(fresh, COMPARATOR);
622:
623: toPopulate.addAll(fresh);
624: return true;
625: }
626: }
627:
628: private static class ServerNode extends FilterNode {
629:
630: private final ServerInstance serverInstance;
631:
632: public ServerNode(ServerInstance serverInstance) {
633: super (serverInstance.getBasicNode());
634: this .serverInstance = serverInstance;
635: setChildren(Children.LEAF);
636: }
637:
638: public ServerInstance getServerInstance() {
639: return serverInstance;
640: }
641: }
642:
643: private static class InstanceComparator implements
644: Comparator<ServerInstance>, Serializable {
645:
646: public int compare(ServerInstance o1, ServerInstance o2) {
647: return o1.getDisplayName().compareTo(o2.getDisplayName());
648: }
649:
650: }
651: }
|