001    /*
002     *  Licensed to the Apache Software Foundation (ASF) under one
003     *  or more contributor license agreements.  See the NOTICE file
004     *  distributed with this work for additional information
005     *  regarding copyright ownership.  The ASF licenses this file
006     *  to you under the Apache License, Version 2.0 (the
007     *  "License"); you may not use this file except in compliance
008     *  with the License.  You may obtain a copy of the License at
009     *  
010     *    http://www.apache.org/licenses/LICENSE-2.0
011     *  
012     *  Unless required by applicable law or agreed to in writing,
013     *  software distributed under the License is distributed on an
014     *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     *  KIND, either express or implied.  See the License for the
016     *  specific language governing permissions and limitations
017     *  under the License. 
018     *  
019     */
020    package org.apache.directory.server.core.partition.impl.btree.gui;
021    
022    
023    import java.awt.BorderLayout;
024    import java.awt.Dimension;
025    import java.awt.Toolkit;
026    import java.awt.Window;
027    import java.awt.event.ActionEvent;
028    import java.awt.event.ActionListener;
029    import java.io.File;
030    import java.io.FileNotFoundException;
031    import java.io.FileReader;
032    import java.util.HashMap;
033    import java.util.Iterator;
034    import java.util.Map;
035    import java.util.Stack;
036    
037    import javax.naming.NamingException;
038    import javax.naming.directory.SearchControls;
039    import javax.swing.JFileChooser;
040    import javax.swing.JFrame;
041    import javax.swing.JLabel;
042    import javax.swing.JMenu;
043    import javax.swing.JMenuBar;
044    import javax.swing.JMenuItem;
045    import javax.swing.JOptionPane;
046    import javax.swing.JPanel;
047    import javax.swing.JScrollPane;
048    import javax.swing.JSeparator;
049    import javax.swing.JSplitPane;
050    import javax.swing.JTabbedPane;
051    import javax.swing.JTable;
052    import javax.swing.JTextArea;
053    import javax.swing.JTree;
054    import javax.swing.event.TreeSelectionEvent;
055    import javax.swing.event.TreeSelectionListener;
056    import javax.swing.table.DefaultTableModel;
057    import javax.swing.tree.DefaultTreeModel;
058    import javax.swing.tree.TreeModel;
059    import javax.swing.tree.TreeNode;
060    import javax.swing.tree.TreePath;
061    
062    import org.apache.directory.server.core.interceptor.context.AddOperationContext;
063    import org.apache.directory.server.core.partition.impl.btree.BTreePartition;
064    import org.apache.directory.server.i18n.I18n;
065    import org.apache.directory.server.xdbm.Index;
066    import org.apache.directory.server.xdbm.IndexCursor;
067    import org.apache.directory.server.xdbm.IndexEntry;
068    import org.apache.directory.shared.ldap.entry.DefaultServerEntry;
069    import org.apache.directory.shared.ldap.entry.ServerEntry;
070    import org.apache.directory.shared.ldap.filter.ExprNode;
071    import org.apache.directory.shared.ldap.filter.FilterParser;
072    import org.apache.directory.shared.ldap.ldif.LdifEntry;
073    import org.apache.directory.shared.ldap.ldif.LdifReader;
074    import org.apache.directory.shared.ldap.message.AliasDerefMode;
075    import org.apache.directory.shared.ldap.name.DN;
076    import org.apache.directory.shared.ldap.schema.SchemaManager;
077    import org.apache.directory.shared.ldap.util.StringTools;
078    import org.slf4j.Logger;
079    import org.slf4j.LoggerFactory;
080    
081    
082    /**
083     * The frame for the database.
084     * 
085     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
086     * @version $Rev: 927404 $
087     */
088    public class PartitionFrame extends JFrame
089    {
090        private static final Logger LOG = LoggerFactory.getLogger( PartitionFrame.class );
091    
092        private static final long serialVersionUID = 4049353102291513657L;
093    
094        // Swing Stuff
095        private JLabel statusBar = new JLabel( "Ready" );
096        private JPanel mainPnl = new JPanel();
097        private JSplitPane splitPane = new JSplitPane();
098        private JTabbedPane tabbedPane = new JTabbedPane();
099        private JPanel entryPnl = new JPanel();
100        private JPanel idxPnl = new JPanel();
101        private JScrollPane treePane = new JScrollPane();
102        private JTree tree = new JTree();
103        private JScrollPane entryPane = new JScrollPane();
104        private JTable entryTbl = new JTable();
105        private JScrollPane idxPane = new JScrollPane();
106        private JTable idxTbl = new JTable();
107        private JMenu searchMenu = new JMenu();
108        private JMenuItem annotate = new JMenuItem();
109        private JMenuItem run = new JMenuItem();
110        private JMenuItem debug = new JMenuItem();
111        private JMenu indices = new JMenu();
112    
113        // Non Swing Stuff
114        private BTreePartition<Long> partition;
115        private boolean doCleanUp;
116        private Map<Long, EntryNode> nodes;
117        private EntryNode root;
118    
119        /** A handle on the global schemaManager */
120        private SchemaManager schemaManager;
121    
122    
123        /**
124         * Creates new form JFrame
125         * 
126         * @param db the partition to view
127         * @throws NamingException if there are problems accessing the partition
128         */
129        public PartitionFrame( BTreePartition<Long> db, SchemaManager schemaManager ) throws Exception
130        {
131            partition = db;
132            this.schemaManager = schemaManager;
133    
134            initialize();
135            buildIndicesMenu( partition );
136            pack();
137            load();
138        }
139    
140    
141        /**
142         * This method is called from within the constructor to initialize the form
143         *
144         * @throws NamingException on partition access errors
145         */
146        private void initialize() throws Exception
147        {
148            mainPnl.setBorder( null );
149            mainPnl.setLayout( new java.awt.BorderLayout() );
150            mainPnl.add( splitPane, java.awt.BorderLayout.CENTER );
151            splitPane.add( tabbedPane, javax.swing.JSplitPane.RIGHT );
152            splitPane.add( treePane, javax.swing.JSplitPane.LEFT );
153            tabbedPane.add( entryPnl, "Entry Attributes" );
154            tabbedPane.add( idxPnl, "Entry Indices" );
155    
156            entryPnl.setLayout( new java.awt.BorderLayout() );
157            entryPnl.add( entryPane, java.awt.BorderLayout.CENTER );
158    
159            idxPnl.setLayout( new java.awt.BorderLayout() );
160            idxPnl.add( idxPane, java.awt.BorderLayout.CENTER );
161    
162            getContentPane().setLayout( new java.awt.BorderLayout() );
163            JPanel content = new JPanel();
164            content.setPreferredSize( new java.awt.Dimension( 798, 461 ) );
165            content.setLayout( new java.awt.BorderLayout() );
166            content.setBorder( javax.swing.BorderFactory.createEtchedBorder() );
167            content.add( mainPnl, java.awt.BorderLayout.NORTH );
168            getContentPane().add( content, BorderLayout.CENTER );
169            // set title
170            setTitle( "Partition: " + this.partition.getSuffixDn().getName() );
171            // add status bar
172            getContentPane().add( statusBar, BorderLayout.SOUTH );
173            // add menu bar
174            JMenuBar menuBar = new JMenuBar();
175    
176            // --------------------------------------------------------------------
177            // 'Backend' Menu
178            // --------------------------------------------------------------------
179    
180            JMenu backendMenu = new JMenu( "Backend" );
181            backendMenu.setText( "Partition" );
182            backendMenu.setBackground( new java.awt.Color( 205, 205, 205 ) );
183            backendMenu.setMnemonic( 'B' );
184    
185            // create Import menu item
186            JMenuItem add = new JMenuItem( "Add" );
187            backendMenu.add( add );
188            add.setMnemonic( 'A' );
189            add.setBackground( new java.awt.Color( 205, 205, 205 ) );
190            add.addActionListener( new ActionListener()
191            {
192                public void actionPerformed( ActionEvent e )
193                {
194                    doAddDialog();
195                }
196            } );
197    
198            // create Import menu item
199            JMenuItem importItem = new JMenuItem( "Import" );
200            backendMenu.add( importItem );
201            importItem.setMnemonic( 'I' );
202            importItem.setBackground( new java.awt.Color( 205, 205, 205 ) );
203            importItem.addActionListener( new ActionListener()
204            {
205                public void actionPerformed( ActionEvent e )
206                {
207                    doImport();
208                }
209            } );
210    
211            // create Exit menu item
212            JMenuItem exit = new JMenuItem( "Exit" );
213            backendMenu.add( exit );
214            exit.setMnemonic( 'E' );
215            exit.setBackground( new java.awt.Color( 205, 205, 205 ) );
216            exit.addActionListener( new ActionListener()
217            {
218                public void actionPerformed( ActionEvent e )
219                {
220                    try
221                    {
222                        exitForm();
223                    }
224                    catch ( Exception e1 )
225                    {
226                        e1.printStackTrace();
227                    }
228                }
229            } );
230    
231            // create About menu item
232            JMenu helpMenu = new JMenu( "Help" );
233            helpMenu.setMnemonic( 'H' );
234            JMenuItem about = new JMenuItem( "About" );
235            about.setMnemonic( 'A' );
236            about.setBackground( new java.awt.Color( 205, 205, 205 ) );
237            about.addActionListener( new ActionListener()
238            {
239                public void actionPerformed( ActionEvent e )
240                {
241                    AboutDialog aboutDialog = new AboutDialog( PartitionFrame.this, true );
242                    PartitionFrame.this.centerOnScreen( aboutDialog );
243                    aboutDialog.setVisible( true );
244                }
245            } );
246            helpMenu.setBackground( new java.awt.Color( 205, 205, 205 ) );
247            helpMenu.add( about );
248    
249            // create Save menu item
250            // create Print menu item
251            menuBar.setBackground( new java.awt.Color( 196, 197, 203 ) );
252            menuBar.add( backendMenu );
253            menuBar.add( searchMenu );
254            menuBar.add( indices );
255            menuBar.add( helpMenu );
256            // sets menu bar
257            setJMenuBar( menuBar );
258            setBounds( new java.awt.Rectangle( 0, 0, 802, 515 ) );
259            setSize( new java.awt.Dimension( 802, 515 ) );
260            setResizable( true );
261    
262            addWindowListener( new java.awt.event.WindowAdapter()
263            {
264                public void windowClosing( java.awt.event.WindowEvent evt )
265                {
266                    try
267                    {
268                        exitForm();
269                    }
270                    catch ( Exception e )
271                    {
272                        e.printStackTrace();
273                    }
274                }
275            } );
276    
277            treePane.getViewport().add( tree );
278            tree.setBounds( new java.awt.Rectangle( 6, 184, 82, 80 ) );
279            tree.setShowsRootHandles( true );
280            tree.setToolTipText( "DB DIT" );
281            tree.setScrollsOnExpand( true );
282            tree.getSelectionModel().addTreeSelectionListener( new TreeSelectionListener()
283            {
284                public void valueChanged( TreeSelectionEvent e )
285                {
286                    TreePath path = e.getNewLeadSelectionPath();
287    
288                    if ( path == null )
289                    {
290                        return;
291                    }
292    
293                    Object last = path.getLastPathComponent();
294                    try
295                    {
296                        if ( last instanceof EntryNode )
297                        {
298                            displayEntry( ( ( EntryNode ) last ).getEntryId(), ( ( EntryNode ) last ).getLdapEntry() );
299                        }
300                    }
301                    catch ( Exception ex )
302                    {
303                        ex.printStackTrace();
304                    }
305                }
306            } );
307    
308            entryPane.getViewport().add( entryTbl );
309            entryTbl.setBounds( new java.awt.Rectangle( 321, 103, 32, 32 ) );
310    
311            idxPane.getViewport().add( idxTbl );
312            idxTbl.setBounds( new java.awt.Rectangle( 429, 134, 32, 32 ) );
313    
314            treePane.setSize( new java.awt.Dimension( 285, 435 ) );
315            treePane.setPreferredSize( new java.awt.Dimension( 285, 403 ) );
316            searchMenu.setText( "Search" );
317            searchMenu.setBackground( new java.awt.Color( 205, 205, 205 ) );
318            searchMenu.add( run );
319            searchMenu.add( debug );
320            searchMenu.add( annotate );
321    
322            ActionListener searchHandler = new ActionListener()
323            {
324                public void actionPerformed( ActionEvent an_event )
325                {
326                    LOG.debug( "action command = {}", an_event.getActionCommand() );
327    
328                    try
329                    {
330                        doFilterDialog( an_event.getActionCommand() );
331                    }
332                    catch ( Exception e )
333                    {
334                        e.printStackTrace();
335                    }
336                }
337            };
338    
339            annotate.setText( FilterDialog.ANNOTATE_MODE );
340            annotate.setActionCommand( FilterDialog.ANNOTATE_MODE );
341            annotate.setBackground( new java.awt.Color( 205, 205, 205 ) );
342            annotate.addActionListener( searchHandler );
343    
344            run.setText( FilterDialog.RUN_MODE );
345            run.setActionCommand( FilterDialog.RUN_MODE );
346            run.setBackground( new java.awt.Color( 205, 205, 205 ) );
347            run.addActionListener( searchHandler );
348    
349            debug.setText( FilterDialog.DEBUG_MODE );
350            debug.setActionCommand( FilterDialog.DEBUG_MODE );
351            debug.setBackground( new java.awt.Color( 205, 205, 205 ) );
352            debug.addActionListener( searchHandler );
353    
354            indices.setText( "Indices" );
355            indices.setBackground( new java.awt.Color( 205, 205, 205 ) );
356        }
357    
358    
359        private void centerOnScreen( Window window )
360        {
361            Dimension frameSize = window.getSize();
362            Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
363    
364            frameSize.height = ( ( frameSize.height > screenSize.height ) ? screenSize.height : frameSize.height );
365            frameSize.width = ( ( frameSize.width > screenSize.width ) ? screenSize.width : frameSize.width );
366            window.setLocation( ( screenSize.width - frameSize.width ) / 2, ( screenSize.height - frameSize.height ) / 2 );
367        }
368    
369    
370        /**
371         * Displays a entry addition dialog.
372         */
373        public void doAddDialog()
374        {
375            try
376            {
377                TreePath path = tree.getSelectionModel().getSelectionPath();
378                String parentDn = partition.getSuffixDn().getName();
379    
380                if ( null != path )
381                {
382                    Object last = path.getLastPathComponent();
383    
384                    if ( last instanceof EntryNode )
385                    {
386                        parentDn = ( ( EntryNode ) last ).getEntryDn();
387                    }
388                }
389    
390                if ( null == parentDn )
391                {
392                    JOptionPane.showMessageDialog( this, "Must select a parent entry to add a child to!" );
393                    return;
394                }
395    
396                AddEntryDialog dialog = new AddEntryDialog( this, false, schemaManager );
397                dialog.setParentDn( parentDn );
398    
399                centerOnScreen( dialog );
400                dialog.setEnabled( true );
401                dialog.setVisible( true );
402            }
403            catch ( Exception e )
404            {
405                e.printStackTrace();
406            }
407        }
408    
409    
410        /**
411         * Gets the DN of the DIT node selected in the tree view.
412         * 
413         * @return the DN of the selected tree node or the root Dn of the tree if 
414         * nothing has been selected yet.
415         * @throws NamingException on partition access errors
416         */
417        public String getSelectedDn() throws Exception
418        {
419            TreePath path = tree.getSelectionModel().getSelectionPath();
420    
421            if ( null == path )
422            {
423                return partition.getSuffixDn().getName();
424            }
425    
426            Object last = path.getLastPathComponent();
427            String base = null;
428    
429            if ( last instanceof EntryNode )
430            {
431                try
432                {
433                    base = ( ( EntryNode ) last ).getEntryDn();
434                }
435                catch ( NamingException e )
436                {
437                    e.printStackTrace();
438                }
439            }
440            else
441            {
442                base = partition.getSuffixDn().getName();
443            }
444    
445            return base;
446        }
447    
448    
449        public void doImport()
450        {
451            FileReader in;
452            JFileChooser chooser = new JFileChooser();
453            int choice = chooser.showOpenDialog( this );
454            File selected = chooser.getSelectedFile();
455    
456            if ( JFileChooser.APPROVE_OPTION != choice )
457            {
458                return;
459            }
460    
461            try
462            {
463                in = new FileReader( selected );
464    
465                for ( LdifEntry entry : new LdifReader( in ) )
466                {
467                    String updn = entry.getDn().getName();
468    
469                    DN ndn = new DN( StringTools.deepTrimToLower( updn ) );
470    
471                    ServerEntry attrs = new DefaultServerEntry( schemaManager, entry.getEntry() );
472    
473                    if ( null == partition.getEntryId( ndn.getNormName() ) )
474                    {
475                        partition.add( new AddOperationContext( null, attrs ) );
476                        load();
477                    }
478                }
479            }
480            catch ( NamingException e )
481            {
482                // @todo display popup with error here!
483                e.printStackTrace();
484            }
485            catch ( FileNotFoundException e )
486            {
487                // @todo display popup with error here!
488                e.printStackTrace();
489            }
490            catch ( Exception e )
491            {
492                // @todo display popup with error here!
493                e.printStackTrace();
494            }
495        }
496    
497    
498        /**
499         * Exit the Application
500         */
501        private void exitForm() throws Exception
502        {
503            setEnabled( false );
504            setVisible( false );
505            dispose();
506    
507            if ( doCleanUp && partition != null )
508            {
509                try
510                {
511                    partition.sync();
512                    partition.destroy();
513                }
514                catch ( NamingException e )
515                {
516                    e.printStackTrace();
517                }
518    
519                System.exit( 0 );
520            }
521        }
522    
523    
524        public void doRunDebugAnnotate( FilterDialog dialog, String mode )
525        {
526            try
527            {
528                if ( mode.equals( FilterDialog.RUN_MODE ) )
529                {
530                    doRun( dialog.getFilter(), dialog.getScope(), dialog.getBase(), dialog.getLimit() );
531                }
532                else if ( mode.equals( FilterDialog.DEBUG_MODE ) )
533                {
534                    doDebug( dialog.getFilter(), dialog.getScope(), dialog.getBase(), dialog.getLimit() );
535                }
536                else if ( mode.equals( FilterDialog.ANNOTATE_MODE ) )
537                {
538                    if ( doAnnotate( dialog.getFilter() ) )
539                    {
540                        // continue
541                    }
542                    else
543                    {
544                        // We failed don't loose users filter buf
545                        // allow user to make edits.
546                        return;
547                    }
548    
549                    LOG.debug( "call to annotate" );
550                }
551                else
552                {
553                    throw new RuntimeException( I18n.err( I18n.ERR_730 ) );
554                }
555            }
556            catch ( Exception e )
557            {
558                // @todo show error popup here!
559                e.printStackTrace();
560            }
561        }
562    
563    
564        public void doFilterDialog( final String mode ) throws Exception
565        {
566            final FilterDialog dialog = new FilterDialog( mode, this, true );
567    
568            if ( tree.getSelectionModel().getSelectionPath() != null )
569            {
570                dialog.setBase( getSelectedDn() );
571            }
572            else
573            {
574                dialog.setBase( partition.getSuffixDn().getName() );
575            }
576    
577            dialog.addActionListener( new ActionListener()
578            {
579                public void actionPerformed( ActionEvent an_event )
580                {
581                    String cmd = an_event.getActionCommand();
582    
583                    if ( cmd.equals( FilterDialog.SEARCH_CMD ) )
584                    {
585                        doRunDebugAnnotate( dialog, mode );
586                    }
587                    else if ( cmd.equals( FilterDialog.CANCEL_CMD ) )
588                    {
589                        // Do nothing! Just exit dialog.
590                    }
591                    else
592                    {
593                        throw new RuntimeException( I18n.err( I18n.ERR_731, cmd ) );
594                    }
595    
596                    dialog.setVisible( false );
597                    dialog.dispose();
598                }
599            } );
600    
601            //Center the frame on screen
602            dialog.setSize( 456, 256 );
603            centerOnScreen( dialog );
604            dialog.setEnabled( true );
605            dialog.setVisible( true );
606        }
607    
608    
609        public boolean doRun( String filter, String scope, String base, String limit ) throws Exception
610        {
611            if ( LOG.isDebugEnabled() )
612            {
613                LOG.debug( "Search attempt using filter '" + filter + "' " + "with scope '" + scope
614                    + "' and a return limit of '" + limit + "'" );
615            }
616    
617            ExprNode root;
618    
619            try
620            {
621                root = FilterParser.parse( filter );
622            }
623            catch ( Exception e )
624            {
625                e.printStackTrace();
626                JTextArea text = new JTextArea();
627                String msg = e.getLocalizedMessage();
628    
629                if ( msg.length() > 1024 )
630                {
631                    msg = msg.substring( 0, 1024 ) + "\n. . . truncated . . .";
632                }
633    
634                text.setText( msg );
635                text.setEnabled( false );
636                JOptionPane.showMessageDialog( null, text, "Syntax Error", JOptionPane.ERROR_MESSAGE );
637                return false;
638            }
639    
640            SearchControls ctls = new SearchControls();
641    
642            if ( scope.equals( FilterDialog.BASE_SCOPE ) )
643            {
644                ctls.setSearchScope( SearchControls.OBJECT_SCOPE );
645            }
646            else if ( scope.equals( FilterDialog.SINGLE_SCOPE ) )
647            {
648                ctls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
649            }
650            else if ( scope.equals( FilterDialog.SUBTREE_SCOPE ) )
651            {
652                ctls.setSearchScope( SearchControls.SUBTREE_SCOPE );
653            }
654            else
655            {
656                throw new RuntimeException( "Unexpected scope parameter: " + scope );
657            }
658    
659            int limitMax = Integer.MAX_VALUE;
660            if ( !limit.equals( FilterDialog.UNLIMITED ) )
661            {
662                limitMax = Integer.parseInt( limit );
663            }
664    
665            IndexCursor<Long, ServerEntry, Long> cursor = partition.getSearchEngine().cursor( new DN( base ),
666                AliasDerefMode.DEREF_ALWAYS, root, ctls );
667            String[] cols = new String[2];
668            cols[0] = "id";
669            cols[1] = "dn";
670            DefaultTableModel tableModel = new DefaultTableModel( cols, 0 );
671            Object[] row = new Object[2];
672            int count = 0;
673            while ( cursor.next() && count < limitMax )
674            {
675                IndexEntry rec = ( IndexEntry ) cursor.get();
676                row[0] = rec.getId();
677                row[1] = partition.getEntryDn( ( Long ) row[0] );
678                tableModel.addRow( row );
679                count++;
680            }
681    
682            SearchResultDialog results = new SearchResultDialog( this, false );
683            StringBuffer buf = new StringBuffer();
684            buf.append( "base: " );
685            buf.append( base );
686            buf.append( "\n" );
687            buf.append( "scope: " );
688            buf.append( scope );
689            buf.append( "\n" );
690            buf.append( "limit: " );
691            buf.append( limit );
692            buf.append( "\n" );
693            buf.append( "total: " );
694            buf.append( count );
695            buf.append( "\n" );
696            buf.append( "filter:\n" );
697            buf.append( filter );
698            buf.append( "\n" );
699            results.setFilter( buf.toString() );
700    
701            TreeNode astRoot = new ASTNode( null, root );
702            TreeModel treeModel = new DefaultTreeModel( astRoot, true );
703            results.setTreeModel( treeModel );
704            results.setTableModel( tableModel );
705            centerOnScreen( results );
706            results.setVisible( true );
707            return true;
708        }
709    
710    
711        public void doDebug( String filter, String scope, String base, String limit )
712        {
713            if ( LOG.isDebugEnabled() )
714            {
715                LOG.debug( "debug attempt using base '" + base + "' filter '" + filter + "' " + "with scope '" + scope
716                    + "' and a return limit of '" + limit + "'" );
717            }
718    
719            LOG.warn( "NOT IMPLMENTED YET" );
720        }
721    
722    
723        public void selectTreeNode( Long id )
724        {
725            Stack<TreeNode> stack = new Stack<TreeNode>();
726            Object[] comps;
727            TreeNode parent = nodes.get( id );
728    
729            while ( parent != null && ( parent != parent.getParent() ) )
730            {
731                stack.push( parent );
732                parent = parent.getParent();
733            }
734    
735            if ( stack.size() == 0 )
736            {
737                comps = new Object[1];
738                comps[0] = root;
739            }
740            else
741            {
742                comps = new Object[stack.size()];
743            }
744    
745            for ( int ii = 0; stack.size() > 0 && ii < comps.length; ii++ )
746            {
747                comps[ii] = stack.pop();
748            }
749    
750            TreePath path = new TreePath( comps );
751            tree.scrollPathToVisible( path );
752            tree.getSelectionModel().setSelectionPath( path );
753            tree.validate();
754        }
755    
756    
757        public boolean doAnnotate( String filter ) throws Exception
758        {
759            ExprNode root;
760    
761            try
762            {
763                root = FilterParser.parse( filter );
764            }
765            catch ( Exception e )
766            {
767                JTextArea text = new JTextArea();
768                String msg = e.getLocalizedMessage();
769    
770                if ( msg.length() > 1024 )
771                {
772                    msg = msg.substring( 0, 1024 ) + "\n. . . truncated . . .";
773                }
774    
775                text.setText( msg );
776                text.setEnabled( false );
777                JOptionPane.showMessageDialog( null, text, "Syntax Error", JOptionPane.ERROR_MESSAGE );
778                return false;
779            }
780    
781            AnnotatedFilterTreeDialog treeDialog = new AnnotatedFilterTreeDialog( PartitionFrame.this, false );
782            treeDialog.setFilter( filter );
783    
784            partition.getSearchEngine().getOptimizer().annotate( root );
785            TreeNode astRoot = new ASTNode( null, root );
786            TreeModel model = new DefaultTreeModel( astRoot, true );
787            treeDialog.setModel( model );
788            treeDialog.setVisible( true );
789            return true;
790        }
791    
792    
793        /**
794         * Shows a dialog to display and scan indices.
795         * 
796         * @param idxAttr the name of the index or its attribute
797         * @throws Exception if the indices cannot be accessed
798         */
799        public void showIndexDialog( String idxAttr ) throws Exception
800        {
801            Index index;
802            boolean isSystem = partition.hasSystemIndexOn( idxAttr );
803    
804            if ( isSystem )
805            {
806                index = partition.getSystemIndex( idxAttr );
807            }
808            else
809            {
810                index = partition.getUserIndex( idxAttr );
811            }
812    
813            if ( index != null )
814            {
815                IndexDialog dialog = new IndexDialog( this, false, index );
816                centerOnScreen( dialog );
817                dialog.setEnabled( true );
818                dialog.setVisible( true );
819            }
820        }
821    
822    
823        public void buildIndicesMenu( BTreePartition partition )
824        {
825            JMenuItem item;
826    
827            ActionListener listener = new ActionListener()
828            {
829                public void actionPerformed( ActionEvent event )
830                {
831                    try
832                    {
833                        showIndexDialog( event.getActionCommand() );
834                    }
835                    catch ( Exception e )
836                    {
837                        e.printStackTrace();
838                    }
839                }
840            };
841    
842            Iterator list = partition.getSystemIndices();
843            while ( list.hasNext() )
844            {
845                String idx = ( String ) list.next();
846                item = new JMenuItem();
847                item.setBackground( new java.awt.Color( 205, 205, 205 ) );
848                indices.add( item );
849                item.setText( idx );
850                item.setActionCommand( idx );
851                item.addActionListener( listener );
852            }
853    
854            indices.add( new JSeparator() );
855            list = partition.getUserIndices();
856            while ( list.hasNext() )
857            {
858                String idx = ( String ) list.next();
859                item = new JMenuItem();
860                item.setBackground( new java.awt.Color( 205, 205, 205 ) );
861                indices.add( item );
862                item.setText( idx );
863                item.setActionCommand( idx );
864                item.addActionListener( listener );
865            }
866        }
867    
868    
869        void displayEntry( Long id, ServerEntry entry ) throws Exception
870        {
871            String dn = partition.getEntryUpdn( id );
872            AttributesTableModel model = new AttributesTableModel( entry, id, dn, false );
873            entryTbl.setModel( model );
874    
875            // TODO use utility method to getIndices below
876            //        model = new AttributesTableModel( partition.getIndices( id ), id, dn, false );
877            //        idxTbl.setModel( model );
878            //
879            //        validate();
880        }
881    
882    
883        private void load() throws Exception
884        {
885            // boolean doFiltered = false;
886            nodes = new HashMap<Long, EntryNode>();
887    
888            ServerEntry suffix = partition.lookup( partition.getEntryId( partition.getSuffixDn().getNormName() ) );
889            Long id = partition.getEntryId( partition.getSuffixDn().getName() );
890            root = new EntryNode( id, null, partition, suffix, nodes );
891    
892            /*
893             int option = JOptionPane.showConfirmDialog( null,
894             "Would you like to filter leaf nodes on load?", "Use Filter?",
895             JOptionPane.OK_CANCEL_OPTION );
896             doFiltered = option == JOptionPane.OK_OPTION;
897    
898             if(doFiltered) {
899             SearchEngine engine = new SearchEngine();
900             final FilterDialog dialog =
901             new FilterDialog(FilterDialog.LOAD_MODE, this, true);
902             dialog.addActionListener(new ActionListener() {
903             public void actionPerformed(ActionEvent e) {
904             dialog.setVisible(false);
905             dialog.dispose();
906             }
907             });
908    
909             dialog.setBase(database.getSuffixDn().toString());
910             dialog.setScope(FilterDialog.SUBTREE_SCOPE);
911    
912             //Center the frame on screen
913             dialog.setSize(456, 256);
914             this.centerOnScreen( dialog );
915             dialog.setEnabled(true);
916             dialog.setVisible(true);
917    
918             FilterParser parser = new FilterParserImpl();
919             parser.enableLogging(logger);
920             ExprNode exprNode = parser.parse(dialog.getFilter());
921    
922             int scope = -1;
923             String scopeStr = dialog.getScope();
924             if(scopeStr == FilterDialog.BASE_SCOPE) {
925             scope = Backend.BASE_SCOPE;
926             } else if(scopeStr == FilterDialog.SINGLE_SCOPE) {
927             scope = Backend.SINGLE_SCOPE;
928             } else if(scopeStr == FilterDialog.SUBTREE_SCOPE) {
929             scope = Backend.SUBTREE_SCOPE;
930             } else {
931             throw new RuntimeException("Unrecognized scope");
932             }
933    
934             exprNode =
935             engine.addScopeNode(exprNode, dialog.getBase(), scope);
936             root = new EntryNode(null, database,
937             database.getSuffixEntry(), nodes, exprNode, engine);
938             } else {
939             root = new EntryNode(null, database,
940             database.getSuffixEntry(), nodes);
941             }
942             */
943    
944            DefaultTreeModel model = new DefaultTreeModel( root );
945            tree.setModel( model );
946    
947            if ( isVisible() )
948            {
949                tree.validate();
950            }
951        }
952    
953    
954        public void setDoCleanUp( boolean doCleanUp )
955        {
956            this.doCleanUp = doCleanUp;
957        }
958    }