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.Color;
024    import java.awt.Font;
025    import java.awt.Frame;
026    import java.awt.Panel;
027    import java.awt.event.ActionEvent;
028    import java.awt.event.ActionListener;
029    
030    import javax.swing.BorderFactory;
031    import javax.swing.BoxLayout;
032    import javax.swing.ButtonGroup;
033    import javax.swing.JButton;
034    import javax.swing.JDialog;
035    import javax.swing.JLabel;
036    import javax.swing.JOptionPane;
037    import javax.swing.JPanel;
038    import javax.swing.JRadioButton;
039    import javax.swing.JScrollPane;
040    import javax.swing.JTabbedPane;
041    import javax.swing.JTable;
042    import javax.swing.JTextArea;
043    import javax.swing.JTextField;
044    import javax.swing.border.TitledBorder;
045    import javax.swing.table.DefaultTableModel;
046    
047    import org.apache.directory.server.i18n.I18n;
048    import org.apache.directory.server.xdbm.IndexEntry;
049    import org.apache.directory.server.xdbm.ForwardIndexEntry;
050    import org.apache.directory.server.xdbm.Index;
051    import org.apache.directory.shared.ldap.cursor.Cursor;
052    import org.apache.directory.shared.ldap.util.ExceptionUtils;
053    import org.apache.directory.shared.ldap.NotImplementedException;
054    
055    import org.slf4j.Logger;
056    import org.slf4j.LoggerFactory;
057    
058    
059    /**
060     * A dialog showing index values.
061     *
062     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
063     * @version $Rev: 917312 $
064     */
065    public class IndexDialog<K, O, ID> extends JDialog
066    {
067        private static final Logger LOG = LoggerFactory.getLogger( IndexDialog.class );
068    
069        private static final long serialVersionUID = 3689917253680445238L;
070    
071        public static final String DEFAULT_CURSOR = "Default";
072        public static final String EQUALITY_CURSOR = "Equality";
073        public static final String GREATER_CURSOR = "Greater";
074        public static final String LESS_CURSOR = "Less";
075        public static final String REGEX_CURSOR = "Regex";
076    
077        private Panel mainPnl = new Panel();
078        private JTabbedPane tabbedPane = new JTabbedPane();
079        private JPanel listPnl = new JPanel();
080        private JPanel cursorPnl = new JPanel();
081        private JPanel resultsPnl = new JPanel();
082        private JScrollPane jScrollPane2 = new JScrollPane();
083        private JTable resultsTbl = new JTable();
084        private JPanel buttonPnl = new JPanel();
085        private JButton doneBut = new JButton();
086        private JLabel jLabel1 = new JLabel();
087        private JTextField keyText = new JTextField();
088        private JLabel jLabel2 = new JLabel();
089        private JButton scanBut = new JButton();
090    
091        private Index<K, O, ID> index = null;
092    
093    
094        public IndexDialog( Frame parent, boolean modal, Index<K, O, ID> index )
095        {
096            super( parent, modal );
097            this.index = index;
098            initGUI();
099        }
100    
101    
102        public IndexDialog( Index<K, O, ID> index )
103        {
104            super();
105            this.index = index;
106            initGUI();
107        }
108    
109    
110        /**
111         * This method is called from within the constructor to initialize the
112         * form.
113         */
114        private void initGUI()
115        {
116            addWindowListener( new java.awt.event.WindowAdapter()
117            {
118                public void windowClosing( java.awt.event.WindowEvent evt )
119                {
120                    closeDialog();
121                }
122            } );
123    
124            pack();
125            setTitle( "Index On Attribute '" + index.getAttribute().getName() + "'" );
126            setBounds( new java.awt.Rectangle( 0, 0, 512, 471 ) );
127            getContentPane().add( mainPnl, java.awt.BorderLayout.CENTER );
128            mainPnl.setLayout( new java.awt.BorderLayout() );
129            mainPnl.add( tabbedPane, java.awt.BorderLayout.CENTER );
130            tabbedPane.add( listPnl, "Listing" );
131            listPnl.setLayout( new java.awt.GridBagLayout() );
132    
133            RadioButtonListener radioListener = new RadioButtonListener();
134            JRadioButton radioDefault = new JRadioButton( DEFAULT_CURSOR );
135            radioDefault.setActionCommand( DEFAULT_CURSOR );
136            radioDefault.setSelected( true );
137            radioDefault.addActionListener( radioListener );
138    
139            JRadioButton radioEquality = new JRadioButton( EQUALITY_CURSOR );
140            radioEquality.setActionCommand( EQUALITY_CURSOR );
141            radioEquality.addActionListener( radioListener );
142    
143            JRadioButton radioGreater = new JRadioButton( GREATER_CURSOR );
144            radioGreater.setActionCommand( GREATER_CURSOR );
145            radioGreater.addActionListener( radioListener );
146    
147            JRadioButton radioLess = new JRadioButton( LESS_CURSOR );
148            radioLess.setActionCommand( LESS_CURSOR );
149            radioLess.addActionListener( radioListener );
150    
151            JRadioButton radioRegex = new JRadioButton( REGEX_CURSOR );
152            radioRegex.setActionCommand( REGEX_CURSOR );
153            radioRegex.addActionListener( radioListener );
154    
155            ButtonGroup group = new ButtonGroup();
156            group.add( radioDefault );
157            group.add( radioEquality );
158            group.add( radioGreater );
159            group.add( radioLess );
160            group.add( radioRegex );
161    
162            JPanel radioPanel = new JPanel();
163            radioPanel.setLayout( new BoxLayout( radioPanel, BoxLayout.X_AXIS ) );
164            radioPanel.add( radioDefault );
165            radioPanel.add( radioEquality );
166            radioPanel.add( radioGreater );
167            radioPanel.add( radioLess );
168            radioPanel.add( radioRegex );
169    
170            listPnl.add( cursorPnl, new java.awt.GridBagConstraints( 0, 0, 1, 1, 1.0, 0.15,
171                java.awt.GridBagConstraints.NORTH, java.awt.GridBagConstraints.BOTH, new java.awt.Insets( 15, 0, 30, 0 ),
172                0, 0 ) );
173            listPnl.add( resultsPnl, new java.awt.GridBagConstraints( 0, 1, 1, 1, 1.0, 0.8,
174                java.awt.GridBagConstraints.CENTER, java.awt.GridBagConstraints.BOTH, new java.awt.Insets( 0, 0, 0, 0 ), 0,
175                0 ) );
176            listPnl.add( buttonPnl, new java.awt.GridBagConstraints( 0, 2, 1, 1, 1.0, 0.05,
177                java.awt.GridBagConstraints.CENTER, java.awt.GridBagConstraints.BOTH, new java.awt.Insets( 0, 0, 0, 0 ), 0,
178                0 ) );
179            cursorPnl.setLayout( new java.awt.GridBagLayout() );
180            cursorPnl.setBorder( javax.swing.BorderFactory.createTitledBorder( javax.swing.BorderFactory.createLineBorder(
181                new java.awt.Color( 153, 153, 153 ), 1 ), "Display Cursor Constraints",
182                javax.swing.border.TitledBorder.LEADING, javax.swing.border.TitledBorder.TOP, new java.awt.Font(
183                    "SansSerif", 0, 14 ), new java.awt.Color( 60, 60, 60 ) ) );
184            cursorPnl.add( jLabel1, new java.awt.GridBagConstraints( 0, 1, 1, 1, 0.0, 0.0,
185                java.awt.GridBagConstraints.WEST, java.awt.GridBagConstraints.NONE, new java.awt.Insets( 0, 15, 0, 10 ), 0,
186                0 ) );
187            cursorPnl.add( keyText, new java.awt.GridBagConstraints( 1, 1, 1, 1, 0.4, 0.0,
188                java.awt.GridBagConstraints.WEST, java.awt.GridBagConstraints.BOTH, new java.awt.Insets( 5, 5, 5, 236 ), 0,
189                0 ) );
190            cursorPnl.add( jLabel2, new java.awt.GridBagConstraints( 0, 0, 1, 1, 0.0, 0.0,
191                java.awt.GridBagConstraints.WEST, java.awt.GridBagConstraints.NONE, new java.awt.Insets( 0, 15, 0, 10 ), 0,
192                0 ) );
193            cursorPnl.add( radioPanel,
194                new java.awt.GridBagConstraints( 1, 0, 1, 1, 0.4, 0.0, java.awt.GridBagConstraints.WEST,
195                    java.awt.GridBagConstraints.NONE, new java.awt.Insets( 5, 5, 5, 0 ), 0, 0 ) );
196            resultsPnl.setLayout( new java.awt.BorderLayout() );
197            resultsPnl.setBorder( javax.swing.BorderFactory.createTitledBorder( javax.swing.BorderFactory.createLineBorder(
198                new java.awt.Color( 153, 153, 153 ), 1 ), "Scan Results", javax.swing.border.TitledBorder.LEADING,
199                javax.swing.border.TitledBorder.TOP, new java.awt.Font( "SansSerif", 0, 14 ), new java.awt.Color( 60, 60,
200                    60 ) ) );
201            resultsPnl.add( jScrollPane2, java.awt.BorderLayout.CENTER );
202            jScrollPane2.getViewport().add( resultsTbl );
203            buttonPnl.setLayout( new java.awt.FlowLayout( java.awt.FlowLayout.CENTER, 15, 5 ) );
204            buttonPnl.add( doneBut );
205            buttonPnl.add( scanBut );
206            doneBut.setText( "Done" );
207            doneBut.addActionListener( new ActionListener()
208            {
209                public void actionPerformed( ActionEvent e )
210                {
211                    closeDialog();
212                }
213            } );
214    
215            jLabel1.setText( "Key Constraint:" );
216            keyText.setText( "" );
217            keyText.setMinimumSize( new java.awt.Dimension( 130, 20 ) );
218            keyText.setPreferredSize( new java.awt.Dimension( 130, 20 ) );
219            keyText.setMaximumSize( new java.awt.Dimension( 130, 20 ) );
220            keyText.setFont( new java.awt.Font( "SansSerif", java.awt.Font.PLAIN, 14 ) );
221            keyText.setSize( new java.awt.Dimension( 130, 20 ) );
222            jLabel2.setText( "Cursor Type:" );
223    
224            scanBut.setText( "Scan" );
225            scanBut.addActionListener( new ActionListener()
226            {
227                public void actionPerformed( ActionEvent e )
228                {
229                    //noinspection unchecked
230                    doScan( ( K ) keyText.getText(), selectedCursorType );
231                }
232            } );
233    
234            doScan( null, DEFAULT_CURSOR );
235        }
236    
237        private String selectedCursorType = DEFAULT_CURSOR;
238    
239        class RadioButtonListener implements ActionListener
240        {
241            public void actionPerformed( ActionEvent e )
242            {
243                if ( e.getActionCommand().equals( DEFAULT_CURSOR ) )
244                {
245                    selectedCursorType = DEFAULT_CURSOR;
246                }
247                else if ( e.getActionCommand().equals( EQUALITY_CURSOR ) )
248                {
249                    selectedCursorType = EQUALITY_CURSOR;
250                }
251                else if ( e.getActionCommand().equals( GREATER_CURSOR ) )
252                {
253                    selectedCursorType = GREATER_CURSOR;
254                }
255                else if ( e.getActionCommand().equals( LESS_CURSOR ) )
256                {
257                    selectedCursorType = LESS_CURSOR;
258                }
259                else if ( e.getActionCommand().equals( REGEX_CURSOR ) )
260                {
261                    selectedCursorType = REGEX_CURSOR;
262                }
263            }
264        }
265    
266    
267        private void closeDialog()
268        {
269            setVisible( false );
270            dispose();
271        }
272    
273    
274        public boolean doScan( K key, String scanType )
275        {
276            if ( key == null && !scanType.equals( DEFAULT_CURSOR ) )
277            {
278                JOptionPane.showMessageDialog( null, "Cannot use a " + scanType + " scan type with a null key constraint.",
279                    "Missing Key Constraint", JOptionPane.ERROR_MESSAGE );
280                return false;
281            }
282    
283            Object[] cols = new Object[2];
284            Object[] row;
285            cols[0] = "Keys ( Attribute Value )";
286            cols[1] = "Values ( Entry Id )";
287            DefaultTableModel model = new DefaultTableModel( cols, 0 );
288            int count = 0;
289    
290            try
291            {
292                Cursor<IndexEntry<K, O, ID>> list;
293    
294                if ( scanType.equals( EQUALITY_CURSOR ) )
295                {
296                    list = index.forwardCursor( key );
297                    list.beforeFirst();
298                    while ( list.next() )
299                    {
300                        IndexEntry<K, O, ID> rec = list.get();
301                        row = new Object[2];
302                        row[0] = rec.getValue();
303                        row[1] = rec.getId();
304                        model.addRow( row );
305                        count++;
306                    }
307                }
308                else if ( scanType.equals( GREATER_CURSOR ) )
309                {
310                    list = index.forwardCursor();
311                    ForwardIndexEntry<K, O, ID> entry = new ForwardIndexEntry<K, O, ID>();
312                    entry.setValue( key );
313                    list.before( entry );
314                    while ( list.next() )
315                    {
316                        IndexEntry<K, O, ID> rec = list.get();
317                        row = new Object[2];
318                        row[0] = rec.getValue();
319                        row[1] = rec.getId();
320                        model.addRow( row );
321                        count++;
322                    }
323                }
324                else if ( scanType.equals( LESS_CURSOR ) )
325                {
326                    list = index.forwardCursor();
327                    ForwardIndexEntry<K, O, ID> entry = new ForwardIndexEntry<K, O, ID>();
328                    entry.setValue( key );
329                    list.after( entry );
330                    while ( list.previous() )
331                    {
332                        IndexEntry<K, O, ID> rec = list.get();
333                        row = new Object[2];
334                        row[0] = rec.getValue();
335                        row[1] = rec.getId();
336                        model.addRow( row );
337                        count++;
338                    }
339                }
340                else if ( scanType.equals( REGEX_CURSOR ) )
341                {
342                    //                Pattern regex = StringTools.getRegex( key );
343                    //                int starIndex = key.indexOf( '*' );
344                    //
345                    //                if ( starIndex > 0 )
346                    //                {
347                    //                    String prefix = key.substring( 0, starIndex );
348                    //
349                    //                    if ( log.isDebugEnabled() )
350                    //                        log.debug( "Regex prefix = " + prefix );
351                    //
352                    //                    list = index.listIndices( regex, prefix );
353                    //                }
354                    //                else
355                    //                {
356                    //                    list = index.listIndices( regex );
357                    //                }
358                    throw new NotImplementedException();
359                }
360                else
361                {
362                    list = index.forwardCursor();
363                    while ( list.next() )
364                    {
365                        IndexEntry<K, O, ID> rec = list.get();
366                        row = new Object[2];
367                        row[0] = rec.getValue();
368                        row[1] = rec.getId();
369                        model.addRow( row );
370                        count++;
371                    }
372                }
373    
374                resultsTbl.setModel( model );
375                resultsPnl.setBorder( BorderFactory.createTitledBorder( BorderFactory.createLineBorder( new Color( 153,
376                    153, 153 ), 1 ), "Scan Results: " + count, TitledBorder.LEADING, TitledBorder.TOP, new Font(
377                    "SansSerif", 0, 14 ), new Color( 60, 60, 60 ) ) );
378    
379                if ( isVisible() )
380                {
381                    validate();
382                }
383            }
384            catch ( Exception e )
385            {
386                String msg = ExceptionUtils.getStackTrace( e );
387    
388                if ( msg.length() > 1024 )
389                {
390                    msg = msg.substring( 0, 1024 ) + "\n. . . TRUNCATED . . .";
391                }
392    
393                msg = I18n.err( I18n.ERR_183, index.getAttribute(), scanType, key, msg );
394    
395                LOG.error( msg, e );
396                JTextArea area = new JTextArea();
397                area.setText( msg );
398                JOptionPane.showMessageDialog( null, area, "Index Scan Error", JOptionPane.ERROR_MESSAGE );
399                return false;
400            }
401    
402            return true;
403        }
404    
405    
406        public static void show( Index index )
407        {
408            //noinspection unchecked
409            IndexDialog dialog = new IndexDialog( index );
410            dialog.setVisible( true );
411        }
412    }