001package net.sf.logdistiller;
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.io.*;
018import java.util.*;
019
020import org.apache.commons.lang.ArrayUtils;
021import org.jdom.Element;
022
023import net.sf.logdistiller.util.FormatUtil;
024
025/**
026 * A LogDistiller configuration.
027 *
028 * @see LogDistillation
029 * @see net.sf.logdistiller.xml.DOMConfigurator
030 */
031public class LogDistiller
032    implements Serializable
033{
034    private static final long serialVersionUID = 1730313287821721822L;
035
036    private final String id;
037
038    private final String description;
039
040    private LogType logtype;
041
042    /** @since 0.7 */
043    private final Output output;
044
045    private final Category[] categories;
046
047    private final Group[] groups;
048
049    /** @since 0.7 */
050    private final List<String> warnings = new ArrayList<String>();
051
052    private final boolean old;
053
054    public LogDistiller( String id, String description, LogType logtype, Output output, Category[] categories,
055                         Group[] groups, boolean old )
056    {
057        this.id = id;
058        this.description = description;
059        this.logtype = logtype;
060        this.output = output;
061        this.categories = (Category[]) ArrayUtils.clone( categories );
062        this.groups = (Group[]) ArrayUtils.clone( groups );
063        this.old = old;
064        updateRef();
065    }
066
067    public LogDistiller( String id, String description, LogType logtype, Output output, Category[] categories,
068                         Group[] groups )
069    {
070        this( id, description, logtype, output, categories, groups, false );
071    }
072
073    /**
074     * Update the references from internal objects to their parent LogDistiller instance and other referenced object not
075     * initialized at creation time.
076     */
077    public void updateRef()
078    {
079        output.updateRef( this );
080        int len = categories.length;
081        for ( int i = 0; i < len; i++ )
082        {
083            categories[i].updateRef( this );
084        }
085        len = groups.length;
086        for ( int i = 0; i < len; i++ )
087        {
088            groups[i].updateRef( this );
089        }
090    }
091
092    private void readObject( ObjectInputStream in )
093        throws IOException, ClassNotFoundException
094    {
095        in.defaultReadObject();
096        if ( output != null )
097        {
098            // TODO: do better with deserialization of an old instance
099            updateRef();
100        }
101    }
102
103    public String getId()
104    {
105        return id;
106    }
107
108    public String getDescription()
109    {
110        return description;
111    }
112
113    public LogType getLogType()
114    {
115        return logtype;
116    }
117
118    /**
119     * is this LogDistiller read from an old configuration file (DTD older than 1.3)?
120     */
121    public boolean isOld()
122    {
123        return old;
124    }
125
126    /**
127     * To keep old rules configuration files running (without logtype element), create a LogType instance from the type
128     * provided. Parameters from the logtype are extracted from global parameters: every <code>logevent.myParam</code>
129     * global parameter is inserted as <code>myParam</code>.
130     *
131     * @param type String the log type to consider
132     */
133    public void buildCompatibilityLogType( String type )
134    {
135        Map<String, String> logtypeParams = new HashMap<String, String>();
136        Map<String, String> params = output.getParams();
137        for ( Map.Entry<String, String> entry : params.entrySet() )
138        {
139            String key = entry.getKey();
140            if ( key.startsWith( "logevent." ) )
141            {
142                logtypeParams.put( key.substring( 9 ), entry.getValue() );
143            }
144        }
145        String paramAttributes = (String)logtypeParams.get( "attributes" );
146        logtype = new LogDistiller.LogType( type, logtypeParams, new Attributes( paramAttributes, new Attributes.Extension[0] ) );
147    }
148
149    public Output getOutput()
150    {
151        return output;
152    }
153
154    public Category[] getCategories()
155    {
156        return (Category[]) ArrayUtils.clone( categories );
157    }
158
159    public Group[] getGroups()
160    {
161        return (Group[]) ArrayUtils.clone( groups );
162    }
163
164    public List<String> getWarnings()
165    {
166        return Collections.unmodifiableList( warnings );
167    }
168
169    public void addWarning( String msg )
170    {
171        warnings.add( msg );
172    }
173
174    public void checkLogtypeAttributes( net.sf.logdistiller.LogType.Description description )
175    {
176        String attributes = ( logtype.getAttributes() == null ) ? null : logtype.getAttributes().getAttributes();
177        String attributesReference = FormatUtil.join( ",", description.getAttributeNames() );
178
179        if ( attributes == null )
180        {
181            addWarning( "<logtype><attributes> element should contain <provided>" + attributesReference
182                + "</provided>" );
183        }
184        else if ( !attributesReference.equals( attributes ) )
185        {
186            addWarning( "bad value for <logtype><attributes><provided> element, should be " + attributesReference );
187        }
188    }
189
190    public static String getVersion()
191    {
192        Package pkg = LogDistiller.class.getPackage();
193        String version = ( pkg == null ) ? null : pkg.getSpecificationVersion();
194        return ( version == null ) ? "SNAPSHOT" : version;
195    }
196
197    /**
198     * Definition of the log type used for this logdistiller configuration, with its parameters.
199     */
200    public static class LogType
201        implements Serializable
202    {
203        private static final long serialVersionUID = 1486393526172179950L;
204
205        private final String id;
206
207        private final Map<String, String> params;
208
209        /**
210         * @since 1.1
211         */
212        private final Attributes attributes;
213
214        public LogType( String id, Map<String, String> params, Attributes attributes )
215        {
216            this.id = id;
217            this.params = params;
218            this.attributes = attributes;
219        }
220
221        public String getId()
222        {
223            return id;
224        }
225
226        public Map<String, String> getParams()
227        {
228            return params;
229        }
230
231        public String getParam( String name )
232        {
233            return params.get( name );
234        }
235
236        public String getParam( String name, String defaultValue )
237        {
238            String value = getParam( name );
239            return ( value == null ) ? defaultValue : value;
240        }
241
242        /**
243         * @return extensions (not <code>null</code>)
244         *  @since 1.1
245         */
246        public Attributes.Extension[] getExtensions()
247        {
248            return ( attributes == null ) ? Attributes.NO_EXTENSIONS : attributes.getExtensions();
249        }
250
251        /** @since 1.1 */
252        public int getExtensionsCount()
253        {
254            return ( attributes == null ) ? 0 : attributes.getExtensionsCount();
255        }
256
257        /** @since 1.1 */
258        public Attributes getAttributes()
259        {
260            return attributes;
261        }
262    }
263
264    /**
265     * Definition of the global output.
266     *
267     * @since 0.7
268     */
269    public static class Output
270        implements Serializable
271    {
272        private static final long serialVersionUID = 1707510377356801400L;
273
274        private String directory;
275
276        private String content;
277
278        private final String url;
279
280        private String skip;
281
282        private final Map<String, String> params;
283
284        private final Report[] reports;
285
286        private transient LogDistiller logdistiller;
287
288        public Output( String directory, String url, String content, String skip, Map<String, String> params,
289                       Report[] reports )
290        {
291            this.directory = directory;
292            this.url = url;
293            this.content = content;
294            this.skip = skip;
295            this.params = params;
296            this.reports = (Report[]) ArrayUtils.clone( reports );
297        }
298
299        public LogDistiller getLogdistiller()
300        {
301            return logdistiller;
302        }
303
304        private void updateRef( LogDistiller logdistiller )
305        {
306            this.logdistiller = logdistiller;
307            int len = reports.length;
308            for ( int i = 0; i < len; i++ )
309            {
310                reports[i].updateRef( this );
311            }
312        }
313
314        /**
315         * Gets the <code>id</code> that will identify the output reports.
316         *
317         * @return the <code>id</code> param if set, or global logdistiller id.
318         */
319        public String getId()
320        {
321            return getParam( "id", logdistiller.getId() );
322        }
323
324        public Map<String, String> getParams()
325        {
326            return params;
327        }
328
329        public String getParam( String name )
330        {
331            return params.get( name );
332        }
333
334        public String getParam( String name, String defaultValue )
335        {
336            String value = getParam( name );
337            return ( value == null ) ? defaultValue : value;
338        }
339
340        public Report[] getReports()
341        {
342            return (Report[]) ArrayUtils.clone( reports );
343        }
344
345        public void setDirectory( String directory )
346        {
347            this.directory = directory;
348        }
349
350        public String getDirectory()
351        {
352            return directory;
353        }
354
355        public void setContent( String content )
356        {
357            this.content = content;
358        }
359
360        public String getContent()
361        {
362            return content;
363        }
364
365        public String getSkip()
366        {
367            return skip;
368        }
369
370        public void updateCompatibility( File directory, String content, String skip )
371        {
372            this.directory = directory.getAbsolutePath();
373            this.content = content;
374            this.skip = skip;
375        }
376
377        public String getUrl()
378        {
379            return url;
380        }
381
382        public String getUrl( String file )
383        {
384            return ( url == null ) ? null : ( url + '/' + file );
385        }
386    }
387
388    /**
389     * Definition of a report, with its publisher, formant and other params.
390     */
391    public static class Report
392        implements Serializable
393    {
394        private static final long serialVersionUID = 1669156992489095268L;
395
396        private final String publisher;
397
398        private final String format;
399
400        private final Map<String, String> params;
401
402        private transient Output output;
403
404        private transient Group group;
405
406        public Report( String publisher, String format, Map<String, String> params )
407        {
408            this.publisher = publisher;
409            this.format = format;
410            this.params = params;
411        }
412
413        private void updateRef( Output output )
414        {
415            this.output = output;
416            this.group = null;
417        }
418
419        private void updateRef( Group group )
420        {
421            this.group = group;
422            this.output = group.getLogdistiller().getOutput();
423        }
424
425        public Output getOutput()
426        {
427            return output;
428        }
429
430        public Group getGroup()
431        {
432            return group;
433        }
434
435        public Map<String, String> getParams()
436        {
437            return params;
438        }
439
440        public String getFormat()
441        {
442            return format;
443        }
444
445        public String getParam( String name )
446        {
447            return params.get( name );
448        }
449
450        public String getParam( String name, String defaultValue )
451        {
452            String value = getParam( name );
453            return ( value != null ) ? value : output.getParam( publisher + '.' + name, defaultValue );
454        }
455
456        public String getPublisher()
457        {
458            return publisher;
459        }
460    }
461
462    /**
463     * Definition of a group of events: events corresponding to its conditions will be collected in it.
464     */
465    public static class Group
466        implements Serializable
467    {
468        private static final long serialVersionUID = 6647633346412959286L;
469
470        private final String id;
471
472        private final String description;
473
474        private final boolean continueProcessing;
475
476        private final boolean save;
477
478        private final Map<String, String> params;
479
480        private final Condition[] conditions;
481
482        private final Report[] reports;
483
484        private final Category category;
485
486        private final Plugin[] plugins;
487
488        private transient LogDistiller logdistiller;
489
490        public Group( String id, String description, boolean continueProcessing, boolean save,
491                      Map<String, String> params, Condition[] conditions, Report[] reports, Plugin[] plugins,
492                      Category category )
493        {
494            this.id = id;
495            this.description = description;
496            this.continueProcessing = continueProcessing;
497            this.save = save;
498            this.params = params;
499            this.conditions = (Condition[]) ArrayUtils.clone( conditions );
500            this.reports = (Report[]) ArrayUtils.clone( reports );
501            this.plugins = (Plugin[]) ArrayUtils.clone( plugins );
502            this.category = category;
503        }
504
505        private void updateRef( LogDistiller logdistiller )
506        {
507            this.logdistiller = logdistiller;
508            if ( id == null )
509            {
510                // for unknown reason, deserialization of a LogDistillation instance does not fully deserialize
511                // LogDistiller's
512                // instance
513                return;
514            }
515            if ( category != null )
516            {
517                this.category.addGroup( this );
518            }
519            int len = reports.length;
520            for ( int i = 0; i < len; i++ )
521            {
522                reports[i].updateRef( this );
523            }
524            len = plugins.length;
525            for ( int i = 0; i < len; i++ )
526            {
527                plugins[i].updateRef( this );
528            }
529        }
530
531        public LogDistiller getLogdistiller()
532        {
533            return logdistiller;
534        }
535
536        public Map<String, String> getParams()
537        {
538            return params;
539        }
540
541        public String getParam( String name )
542        {
543            return (String) params.get( name );
544        }
545
546        public String getParam( String name, String defaultValue )
547        {
548            String value = getParam( name );
549            return ( value != null ) ? value : logdistiller.getOutput().getParam( name, defaultValue );
550        }
551
552        /**
553         * Check if given LogEvent meet one of the conditions defined.
554         *
555         * @param le LogEvent the LogEvent to check
556         * @return Condition the condition which matched the log event, or <code>null</code>
557         */
558        public Condition accept( LogEvent le )
559        {
560            int count = conditions.length;
561            if ( count == 0 )
562            {
563                // no condition => accepts all log events
564                return Condition.ACCEPT_ALL;
565            }
566            for ( int i = 0; i < count; i++ )
567            {
568                if ( conditions[i].match( le ) )
569                {
570                    return conditions[i];
571                }
572            }
573            return null;
574        }
575
576        public String getId()
577        {
578            return id;
579        }
580
581        public Element dumpConditions( Element parent )
582        {
583            int count = conditions.length;
584            for ( int i = 0; i < count; i++ )
585            {
586                parent.addContent( conditions[i].dump() );
587            }
588            return parent;
589        }
590
591        public String getDescription()
592        {
593            return description;
594        }
595
596        /**
597         * @return boolean in case a LogEvent is added to the current group, must classification be continued further to
598         *         match other groups?
599         */
600        public boolean continueProcessing()
601        {
602            return continueProcessing;
603        }
604
605        public boolean getSave()
606        {
607            return save;
608        }
609
610        public Category getCategory()
611        {
612            return category;
613        }
614
615        public Report[] getReports()
616        {
617            return (Report[]) ArrayUtils.clone( reports );
618        }
619
620        public Plugin[] getPlugins()
621        {
622            return (Plugin[]) ArrayUtils.clone( plugins );
623        }
624    }
625
626    /**
627     * Definition of a category, which will contain groups.
628     */
629    public static class Category
630        implements Serializable
631    {
632        private static final long serialVersionUID = 3036838205912907804L;
633
634        private final String id;
635
636        private final String description;
637
638        private transient LogDistiller logdistiller;
639
640        private transient List<Group> groups;
641
642        public Category( String id, String description )
643        {
644            this.id = id;
645            this.description = description;
646        }
647
648        private void updateRef( LogDistiller logdistiller )
649        {
650            this.logdistiller = logdistiller;
651            this.groups = new ArrayList<Group>();
652        }
653
654        private void addGroup( Group group )
655        {
656            this.groups.add( group );
657        }
658
659        public LogDistiller getLogdistiller()
660        {
661            return logdistiller;
662        }
663
664        public String getId()
665        {
666            return id;
667        }
668
669        public String getDescription()
670        {
671            return description;
672        }
673
674        public List<Group> getGroups()
675        {
676            return groups;
677        }
678    }
679
680    public static class Plugin
681        implements Serializable
682    {
683        private static final long serialVersionUID = 7948111042518186219L;
684
685        private final String type;
686
687        private final Map<String, String> params;
688
689        private final boolean globalReport;
690
691        private final boolean groupReport;
692
693        private transient Group group;
694
695        public Plugin( String type, boolean globalReport, boolean groupReport, Map<String, String> params )
696        {
697            this.type = type;
698            this.params = params;
699            this.globalReport = globalReport;
700            this.groupReport = groupReport;
701        }
702
703        private void updateRef( Group group )
704        {
705            this.group = group;
706        }
707
708        public Group getGroup()
709        {
710            return group;
711        }
712
713        public String getType()
714        {
715            return type;
716        }
717
718        public boolean isGlobalReportEnabled()
719        {
720            return globalReport;
721        }
722
723        public boolean isGroupReportEnabled()
724        {
725            return groupReport;
726        }
727
728        public Map<String, String> getParams()
729        {
730            return params;
731        }
732
733        public String getParam( String name )
734        {
735            return params.get( name );
736        }
737
738        public String getParam( String name, String defaultValue )
739        {
740            String value = getParam( name );
741            return ( value == null ) ? defaultValue : value;
742        }
743    }
744}