001    package net.sf.logdistiller.gui;
002    
003    /*
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *     http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    import java.awt.BorderLayout;
018    import java.awt.Component;
019    import java.awt.Container;
020    import java.awt.Frame;
021    import java.awt.LayoutManager;
022    import java.awt.event.ActionEvent;
023    import java.io.*;
024    import java.util.HashMap;
025    import java.util.List;
026    import java.util.Map;
027    import javax.swing.*;
028    
029    import com.jgoodies.forms.factories.ButtonBarFactory;
030    import com.jgoodies.forms.factories.DefaultComponentFactory;
031    import org.apache.commons.io.IOUtils;
032    import org.apache.commons.lang.StringUtils;
033    
034    import net.sf.logdistiller.LogType;
035    import net.sf.logdistiller.LogTypes;
036    import net.sf.logdistiller.util.FormatUtil;
037    import net.sf.logdistiller.util.PropertiesReplacer;
038    
039    /**
040     * Dialog to create a new rules configuration file: you select the log type and give some basic information (an id, STMP
041     * server, url), and it generates a new rules configuration. Then you just need to refine the rules.
042     */
043    public class NewDialog
044    {
045        private File currentDir;
046    
047        public NewDialog( File directory )
048        {
049            currentDir = directory;
050        }
051    
052        protected JPanel panel = new JPanel();
053    
054        private JTextField tfId = new JTextField( "rules-id", 15 );
055    
056        private JTextField tfDescription = new JTextField( "rules description" );
057    
058        private JComboBox cbLogtype;
059    
060        private JTextField tfSmtp = new JTextField( "smtp.provider.com" );
061    
062        private JTextField tfMailTo = new JTextField( "admin@localhost" );
063    
064        private JTextField tfHttp = new JTextField( "http://mysite.com/logdistiller/logs" );
065    
066        private JButton btSaveAs = new JButton( "save as..." );
067    
068        private JButton btCancel = new JButton( "cancel" );
069    
070        public static JComboBox createCbLogtype( boolean withUndefined )
071        {
072            List logtypes = LogTypes.getAllLogTypes();
073            int len = logtypes.size();
074            String[] logtypeIds = new String[len];
075            for ( int i = 0; i < len; i++ )
076            {
077                logtypeIds[i] = ( (LogType) logtypes.get( i ) ).getId();
078            }
079            JComboBox cb = new JComboBox( logtypeIds );
080            if ( withUndefined )
081            {
082                cb.insertItemAt( "undefined", 0 );
083                cb.setSelectedIndex( 0 );
084            }
085            return cb;
086        }
087    
088        private void initComponents()
089        {
090            cbLogtype = createCbLogtype( false );
091    
092            btSaveAs.addActionListener( SwingAdapter.getActionListener( this, "btSaveAsActionPerformed" ) );
093            btCancel.addActionListener( SwingAdapter.getActionListener( this, "btCancelActionPerformed" ) );
094        }
095    
096        private void addLabel( String label, String id )
097        {
098            panel.add( new JLabel( label ), id );
099        }
100    
101        private void addSeparator( String label, String id )
102        {
103            panel.add( DefaultComponentFactory.getInstance().createSeparator( label ), id );
104        }
105    
106        public LayoutManager createLayout( String layoutId )
107        {
108            return MainPanel.SIMPLE_LAYOUT_CONSTRAINTS_MANAGER.getLayout( layoutId );
109        }
110    
111        public JComponent buildPanel()
112        {
113            initComponents();
114    
115            panel.setBorder( com.jgoodies.forms.factories.Borders.DIALOG_BORDER );
116            panel.setLayout( createLayout( "newDialog" ) );
117    
118            addSeparator( "main parameters", "sepMain" );
119            addLabel( "configuration id:", "lblId" );
120            panel.add( tfId, "tfId" );
121            addLabel( "configuration description:", "lblDescription" );
122            panel.add( tfDescription, "tfDescription" );
123            addLabel( "logtype:", "lblLogtype" );
124            panel.add( cbLogtype, "cbLogtype" );
125    
126            addSeparator( "advanced parameters", "sepOptions" );
127            addLabel( "SMTP host:", "lblSmtp" );
128            panel.add( tfSmtp, "tfSmtp" );
129            addLabel( "mail reports to:", "lblMailTo" );
130            panel.add( tfMailTo, "tfMailTo" );
131            addLabel( "reports publication URL:", "lblHttp" );
132            panel.add( tfHttp, "tfHttp" );
133    
134            Component bbar = ButtonBarFactory.buildRightAlignedBar( new JButton[] { btSaveAs, btCancel } );
135            panel.add( bbar, "bbar" );
136    
137            return panel;
138        }
139    
140        private JDialog createDialog( Component parent )
141        {
142            Frame frame =
143                parent instanceof Frame ? (Frame) parent : (Frame) SwingUtilities.getAncestorOfClass( Frame.class, parent );
144            JDialog dialog = new JDialog( frame, "new classification rules configuration", true );
145    
146            Container contentPane = dialog.getContentPane();
147            contentPane.setLayout( new BorderLayout() );
148            contentPane.add( buildPanel(), BorderLayout.CENTER );
149    
150            dialog.pack();
151            dialog.setLocationRelativeTo( parent );
152            return dialog;
153        }
154    
155        private JDialog dialog;
156    
157        public File showNewConfigurationDialog( Component parent )
158        {
159            dialog = createDialog( parent );
160            dialog.show();
161            dialog.dispose();
162            dialog = null;
163            return configurationFile;
164        }
165    
166        private File configurationFile;
167    
168        public void btSaveAsActionPerformed( ActionEvent ae )
169        {
170            JFileChooser fc = new JFileChooser( currentDir );
171            fc.setFileFilter( new XmlFileFilter() );
172            fc.setSelectedFile( new File( currentDir, tfId.getText() + ".xml" ) );
173            int ret = fc.showSaveDialog( dialog );
174            if ( ret == JFileChooser.APPROVE_OPTION )
175            {
176                saveConfigurationFile( fc.getSelectedFile() );
177                configurationFile = fc.getSelectedFile();
178                if ( dialog != null )
179                {
180                    dialog.setVisible( false );
181                }
182            }
183        }
184    
185        /**
186         * Saves a new rules configuration to a file.
187         *
188         * @param fileTo the file to save to
189         */
190        private void saveConfigurationFile( File fileTo )
191        {
192            try
193            {
194                PrintWriter out = new PrintWriter( new OutputStreamWriter( new FileOutputStream( fileTo ), "utf-8" ) );
195                generateConfiguration( out );
196                out.close();
197            }
198            catch ( FileNotFoundException fnfe )
199            {
200                fnfe.printStackTrace();
201            }
202            catch ( UnsupportedEncodingException uee )
203            {
204                uee.printStackTrace();
205            }
206        }
207    
208        /**
209         * Generate a new configuration stream by filling <code>reference-rules.xml</code> with values taken from the GUI.
210         *
211         * @param out the stream to write to (in UTF-8 encoding)
212         */
213        private void generateConfiguration( PrintWriter out )
214        {
215            LogType logtype = LogTypes.getLogType( (String) cbLogtype.getSelectedItem() );
216            LogType.Description description = logtype.newDescription( new HashMap() );
217    
218            String logeventAttributes = FormatUtil.join( ",", description.getAttributeNames() );
219            int dateAttributeIndex = description.getTimestampAttribute();
220    
221            try
222            {
223                String reference = IOUtils.toString( MainPanel.class.getResourceAsStream( "reference-rules.xml" ), "UTF-8" );
224    
225                Map properties = new HashMap();
226                properties.put( "id", tfId.getText() );
227                properties.put( "description", tfDescription.getText() );
228                properties.put( "logtype", cbLogtype.getSelectedItem() );
229                properties.put( "logtype.attributes", logeventAttributes );
230                properties.put( "mail.to", tfMailTo.getText() );
231                properties.put( "mail.smtp.host", tfSmtp.getText() );
232                properties.put( "logs.url", tfHttp.getText() );
233                properties.put( "logtype.groups", description.getDefaultSpecificGroups() );
234    
235                String skipCondition = // default matching condition for skip group, if no timestamp available
236                    "      <!-- this logtype does not have a timestamp: we can't really skip events with bad date -->\n"
237                        + "      <match attribute=\"logSource\" type=\"equals\"></match>\n"
238                        + "      <!-- if this logtype had a timestamp, the condition would look like the following: -->\n"
239                        + "      <!--match attribute=\"(timestamp attribute?)\" type=\"!contains\">${date}</match!-->";
240                if ( dateAttributeIndex >= 0 )
241                {
242                    skipCondition =
243                        "      <match attribute=\"" + description.getAttributeName( dateAttributeIndex )
244                            + "\" type=\"!contains\">${date}</match>";
245                }
246                properties.put( "skip.condition", skipCondition );
247    
248                // let's compute the sampling.rule property for this LogType
249                String samplingAttributes = description.getDefaultSamplingAttributes();
250                String samplingRule = // default comment when no sampling attributes defined
251                    "\n    <!--plugin type=\"sampling\">\n"
252                    + "      <param name=\"attributes\">most discriminating attribute</param>\n"
253                    + "    </plugin-->";
254                if ( samplingAttributes.length() > 0 )
255                {
256                    // ok, there are sampling attributes
257                    samplingRule =
258                        "\n    <plugin type=\"sampling\">\n"
259                        + "      <param name=\"attributes\">" + samplingAttributes + "</param>\n"
260                        + "    </plugin>";
261                }
262                properties.put( "sampling.rule", samplingRule );
263    
264                PropertiesReplacer repl = new PropertiesReplacer( properties, "#(", ")" );
265    
266                out.print( repl.replaceProperties( reference ) );
267            }
268            catch ( IOException ioe )
269            {
270                ioe.printStackTrace();
271            }
272        }
273    
274        public void btCancelActionPerformed( ActionEvent ae )
275        {
276            configurationFile = null;
277            if ( dialog != null )
278            {
279                dialog.setVisible( false );
280            }
281        }
282    }