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.xdbm.tools;
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.*;
028
029 import javax.swing.BorderFactory;
030 import javax.swing.BoxLayout;
031 import javax.swing.ButtonGroup;
032 import javax.swing.JButton;
033 import javax.swing.JDialog;
034 import javax.swing.JLabel;
035 import javax.swing.JOptionPane;
036 import javax.swing.JPanel;
037 import javax.swing.JRadioButton;
038 import javax.swing.JScrollPane;
039 import javax.swing.JTabbedPane;
040 import javax.swing.JTable;
041 import javax.swing.JTextArea;
042 import javax.swing.JTextField;
043 import javax.swing.border.TitledBorder;
044 import javax.swing.table.DefaultTableModel;
045
046 import org.apache.directory.server.xdbm.Index;
047 import org.apache.directory.server.xdbm.IndexEntry;
048 import org.apache.directory.server.xdbm.ForwardIndexEntry;
049 import org.apache.directory.server.core.entry.ServerEntry;
050 import org.apache.directory.shared.ldap.cursor.Cursor;
051 import org.apache.directory.shared.ldap.util.ExceptionUtils;
052 import org.apache.directory.shared.ldap.NotImplementedException;
053
054 import org.slf4j.Logger;
055 import org.slf4j.LoggerFactory;
056
057
058 /**
059 * A dialog showing index values.
060 *
061 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
062 * @version $Rev: 639279 $
063 */
064 public class IndexDialog<K,O> extends JDialog
065 {
066 private static final Logger LOG = LoggerFactory.getLogger( IndexDialog.class );
067
068 private static final long serialVersionUID = 3689917253680445238L;
069
070 public static final String DEFAULT_CURSOR = "Default";
071 public static final String EQUALITY_CURSOR = "Equality";
072 public static final String GREATER_CURSOR = "Greater";
073 public static final String LESS_CURSOR = "Less";
074 public static final String REGEX_CURSOR = "Regex";
075
076 private Panel mainPnl = new Panel();
077 private JTabbedPane tabbedPane = new JTabbedPane();
078 private JPanel listPnl = new JPanel();
079 private JPanel cursorPnl = new JPanel();
080 private JPanel resultsPnl = new JPanel();
081 private JScrollPane jScrollPane2 = new JScrollPane();
082 private JTable resultsTbl = new JTable();
083 private JPanel buttonPnl = new JPanel();
084 private JButton doneBut = new JButton();
085 private JLabel jLabel1 = new JLabel();
086 private JTextField keyText = new JTextField();
087 private JLabel jLabel2 = new JLabel();
088 private JButton scanBut = new JButton();
089
090 private Index<K,O> index = null;
091
092
093 public IndexDialog( Frame parent, boolean modal, Index<K,O> index )
094 {
095 super( parent, modal );
096 this.index = index;
097 initGUI();
098 }
099
100
101 public IndexDialog( Index<K,O> index )
102 {
103 super();
104 this.index = index;
105 initGUI();
106 }
107
108
109 /**
110 * This method is called from within the constructor to initialize the
111 * form.
112 */
113 private void initGUI()
114 {
115 addWindowListener( new java.awt.event.WindowAdapter()
116 {
117 public void windowClosing( java.awt.event.WindowEvent evt )
118 {
119 closeDialog();
120 }
121 } );
122
123 pack();
124 setTitle( "Index On Attribute '" + index.getAttribute().getName() + "'" );
125 setBounds( new java.awt.Rectangle( 0, 0, 512, 471 ) );
126 getContentPane().add( mainPnl, java.awt.BorderLayout.CENTER );
127 mainPnl.setLayout( new java.awt.BorderLayout() );
128 mainPnl.add( tabbedPane, java.awt.BorderLayout.CENTER );
129 tabbedPane.add( listPnl, "Listing" );
130 listPnl.setLayout( new java.awt.GridBagLayout() );
131
132 RadioButtonListener radioListener = new RadioButtonListener();
133 JRadioButton radioDefault = new JRadioButton( DEFAULT_CURSOR );
134 radioDefault.setActionCommand( DEFAULT_CURSOR );
135 radioDefault.setSelected( true );
136 radioDefault.addActionListener( radioListener );
137
138 JRadioButton radioEquality = new JRadioButton( EQUALITY_CURSOR );
139 radioEquality.setActionCommand( EQUALITY_CURSOR );
140 radioEquality.addActionListener( radioListener );
141
142 JRadioButton radioGreater = new JRadioButton( GREATER_CURSOR );
143 radioGreater.setActionCommand( GREATER_CURSOR );
144 radioGreater.addActionListener( radioListener );
145
146 JRadioButton radioLess = new JRadioButton( LESS_CURSOR );
147 radioLess.setActionCommand( LESS_CURSOR );
148 radioLess.addActionListener( radioListener );
149
150 JRadioButton radioRegex = new JRadioButton( REGEX_CURSOR );
151 radioRegex.setActionCommand( REGEX_CURSOR );
152 radioRegex.addActionListener( radioListener );
153
154 ButtonGroup group = new ButtonGroup();
155 group.add( radioDefault );
156 group.add( radioEquality );
157 group.add( radioGreater );
158 group.add( radioLess );
159 group.add( radioRegex );
160
161 JPanel radioPanel = new JPanel();
162 radioPanel.setLayout( new BoxLayout( radioPanel, BoxLayout.X_AXIS ) );
163 radioPanel.add( radioDefault );
164 radioPanel.add( radioEquality );
165 radioPanel.add( radioGreater );
166 radioPanel.add( radioLess );
167 radioPanel.add( radioRegex );
168
169 listPnl.add( cursorPnl, new java.awt.GridBagConstraints( 0, 0, 1, 1, 1.0, 0.15,
170 java.awt.GridBagConstraints.NORTH, java.awt.GridBagConstraints.BOTH, new java.awt.Insets( 15, 0, 30, 0 ),
171 0, 0 ) );
172 listPnl.add( resultsPnl, new java.awt.GridBagConstraints( 0, 1, 1, 1, 1.0, 0.8,
173 java.awt.GridBagConstraints.CENTER, java.awt.GridBagConstraints.BOTH, new java.awt.Insets( 0, 0, 0, 0 ), 0,
174 0 ) );
175 listPnl.add( buttonPnl, new java.awt.GridBagConstraints( 0, 2, 1, 1, 1.0, 0.05,
176 java.awt.GridBagConstraints.CENTER, java.awt.GridBagConstraints.BOTH, new java.awt.Insets( 0, 0, 0, 0 ), 0,
177 0 ) );
178 cursorPnl.setLayout( new java.awt.GridBagLayout() );
179 cursorPnl.setBorder( javax.swing.BorderFactory.createTitledBorder( javax.swing.BorderFactory.createLineBorder(
180 new java.awt.Color( 153, 153, 153 ), 1 ), "Display Cursor Constraints",
181 javax.swing.border.TitledBorder.LEADING, javax.swing.border.TitledBorder.TOP, new java.awt.Font(
182 "SansSerif", 0, 14 ), new java.awt.Color( 60, 60, 60 ) ) );
183 cursorPnl.add( jLabel1, new java.awt.GridBagConstraints( 0, 1, 1, 1, 0.0, 0.0,
184 java.awt.GridBagConstraints.WEST, java.awt.GridBagConstraints.NONE, new java.awt.Insets( 0, 15, 0, 10 ), 0,
185 0 ) );
186 cursorPnl.add( keyText, new java.awt.GridBagConstraints( 1, 1, 1, 1, 0.4, 0.0,
187 java.awt.GridBagConstraints.WEST, java.awt.GridBagConstraints.BOTH, new java.awt.Insets( 5, 5, 5, 236 ), 0,
188 0 ) );
189 cursorPnl.add( jLabel2, new java.awt.GridBagConstraints( 0, 0, 1, 1, 0.0, 0.0,
190 java.awt.GridBagConstraints.WEST, java.awt.GridBagConstraints.NONE, new java.awt.Insets( 0, 15, 0, 10 ), 0,
191 0 ) );
192 cursorPnl.add( radioPanel,
193 new java.awt.GridBagConstraints( 1, 0, 1, 1, 0.4, 0.0, java.awt.GridBagConstraints.WEST,
194 java.awt.GridBagConstraints.NONE, new java.awt.Insets( 5, 5, 5, 0 ), 0, 0 ) );
195 resultsPnl.setLayout( new java.awt.BorderLayout() );
196 resultsPnl.setBorder( javax.swing.BorderFactory.createTitledBorder( javax.swing.BorderFactory.createLineBorder(
197 new java.awt.Color( 153, 153, 153 ), 1 ), "Scan Results", javax.swing.border.TitledBorder.LEADING,
198 javax.swing.border.TitledBorder.TOP, new java.awt.Font( "SansSerif", 0, 14 ), new java.awt.Color( 60, 60,
199 60 ) ) );
200 resultsPnl.add( jScrollPane2, java.awt.BorderLayout.CENTER );
201 jScrollPane2.getViewport().add( resultsTbl );
202 buttonPnl.setLayout( new java.awt.FlowLayout( java.awt.FlowLayout.CENTER, 15, 5 ) );
203 buttonPnl.add( doneBut );
204 buttonPnl.add( scanBut );
205 doneBut.setText( "Done" );
206 doneBut.addActionListener( new ActionListener()
207 {
208 public void actionPerformed( ActionEvent e )
209 {
210 closeDialog();
211 }
212 } );
213
214 jLabel1.setText( "Key Constraint:" );
215 keyText.setText( "" );
216 keyText.setMinimumSize( new java.awt.Dimension( 130, 20 ) );
217 keyText.setPreferredSize( new java.awt.Dimension( 130, 20 ) );
218 keyText.setMaximumSize( new java.awt.Dimension( 130, 20 ) );
219 keyText.setFont( new java.awt.Font( "SansSerif", java.awt.Font.PLAIN, 14 ) );
220 keyText.setSize( new java.awt.Dimension( 130, 20 ) );
221 jLabel2.setText( "Cursor Type:" );
222
223 scanBut.setText( "Scan" );
224 scanBut.addActionListener( new ActionListener()
225 {
226 @SuppressWarnings("unchecked")
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>> 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> 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> entry = new ForwardIndexEntry<K, O>();
312 entry.setValue( key );
313 list.before( entry );
314 while ( list.next() )
315 {
316 IndexEntry<K,O> 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> entry = new ForwardIndexEntry<K, O>();
328 entry.setValue( key );
329 list.after( entry );
330 while ( list.previous() )
331 {
332 IndexEntry<K,O> 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> 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 = "Error while scanning index " + "on attribute " + index.getAttribute() + " using a " + scanType
394 + " cursor type with a key constraint of '" + key + "':\n" + msg;
395
396 LOG.error( msg, e );
397 JTextArea area = new JTextArea();
398 area.setText( msg );
399 JOptionPane.showMessageDialog( null, area, "Index Scan Error", JOptionPane.ERROR_MESSAGE );
400 return false;
401 }
402
403 return true;
404 }
405
406
407 @SuppressWarnings("unchecked")
408 public static void show( Index<?,ServerEntry> index )
409 {
410 IndexDialog<?,ServerEntry> dialog = new IndexDialog( index );
411 dialog.setVisible( true );
412 }
413 }