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