001    package 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    
017    import java.io.*;
018    import java.util.*;
019    
020    import org.apache.commons.lang.ArrayUtils;
021    import org.jdom.Element;
022    
023    import net.sf.logdistiller.util.FormatUtil;
024    
025    /**
026     * A LogDistiller configuration.
027     *
028     * @see LogDistillation
029     * @see net.sf.logdistiller.xml.DOMConfigurator
030     */
031    public 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 warnings = new ArrayList();
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 logtypeParams = new HashMap();
136            Map params = output.getParams();
137            Iterator iter = params.entrySet().iterator();
138            while ( iter.hasNext() )
139            {
140                Map.Entry entry = (Map.Entry) iter.next();
141                String key = (String) entry.getKey();
142                if ( key.startsWith( "logevent." ) )
143                {
144                    logtypeParams.put( key.substring( 9 ), entry.getValue() );
145                }
146            }
147            String paramAttributes = (String)logtypeParams.get( "attributes" );
148            logtype = new LogDistiller.LogType( type, logtypeParams, new Attributes( paramAttributes, new Attributes.Extension[0] ) );
149        }
150    
151        public Output getOutput()
152        {
153            return output;
154        }
155    
156        public Category[] getCategories()
157        {
158            return (Category[]) ArrayUtils.clone( categories );
159        }
160    
161        public Group[] getGroups()
162        {
163            return (Group[]) ArrayUtils.clone( groups );
164        }
165    
166        public List getWarnings()
167        {
168            return Collections.unmodifiableList( warnings );
169        }
170    
171        public void addWarning( String msg )
172        {
173            warnings.add( msg );
174        }
175    
176        public void checkLogtypeAttributes( net.sf.logdistiller.LogType.Description description )
177        {
178            String attributes = ( logtype.getAttributes() == null ) ? null : logtype.getAttributes().getAttributes();
179            String attributesReference = FormatUtil.join( ",", description.getAttributeNames() );
180    
181            if ( attributes == null )
182            {
183                addWarning( "<logtype><attributes> element should contain <provided>" + attributesReference
184                    + "</provided>" );
185            }
186            else if ( !attributesReference.equals( attributes ) )
187            {
188                addWarning( "bad value for <logtype><attributes><provided> element, should be " + attributesReference );
189            }
190        }
191    
192        public static String getVersion()
193        {
194            Package pkg = LogDistiller.class.getPackage();
195            String version = ( pkg == null ) ? null : pkg.getSpecificationVersion();
196            return ( version == null ) ? "SNAPSHOT" : version;
197        }
198    
199        /**
200         * Definition of the log type used for this logdistiller configuration, with its parameters.
201         */
202        public static class LogType
203            implements Serializable
204        {
205            private static final long serialVersionUID = 1486393526172179950L;
206    
207            private final String id;
208    
209            private final Map params;
210    
211            /**
212             * @since 1.1
213             */
214            private final Attributes attributes;
215    
216            public LogType( String id, Map params, Attributes attributes )
217            {
218                this.id = id;
219                this.params = params;
220                this.attributes = attributes;
221            }
222    
223            public String getId()
224            {
225                return id;
226            }
227    
228            public Map getParams()
229            {
230                return params;
231            }
232    
233            public String getParam( String name )
234            {
235                return (String) params.get( name );
236            }
237    
238            public String getParam( String name, String defaultValue )
239            {
240                String value = getParam( name );
241                return ( value == null ) ? defaultValue : value;
242            }
243    
244            /**
245             * @return extensions (not <code>null</code>)
246             *  @since 1.1
247             */
248            public Attributes.Extension[] getExtensions()
249            {
250                return ( attributes == null ) ? Attributes.NO_EXTENSIONS : attributes.getExtensions();
251            }
252    
253            /** @since 1.1 */
254            public int getExtensionsCount()
255            {
256                return ( attributes == null ) ? 0 : attributes.getExtensionsCount();
257            }
258    
259            /** @since 1.1 */
260            public Attributes getAttributes()
261            {
262                return attributes;
263            }
264        }
265    
266        /**
267         * Definition of the global output.
268         *
269         * @since 0.7
270         */
271        public static class Output
272            implements Serializable
273        {
274            private static final long serialVersionUID = 1707510377356801400L;
275    
276            private String directory;
277    
278            private String content;
279    
280            private final String url;
281    
282            private String skip;
283    
284            private final Map params;
285    
286            private final Report[] reports;
287    
288            private transient LogDistiller logdistiller;
289    
290            public Output( String directory, String url, String content, String skip, Map params, Report[] reports )
291            {
292                this.directory = directory;
293                this.url = url;
294                this.content = content;
295                this.skip = skip;
296                this.params = params;
297                this.reports = (Report[]) ArrayUtils.clone( reports );
298            }
299    
300            public LogDistiller getLogdistiller()
301            {
302                return logdistiller;
303            }
304    
305            private void updateRef( LogDistiller logdistiller )
306            {
307                this.logdistiller = logdistiller;
308                int len = reports.length;
309                for ( int i = 0; i < len; i++ )
310                {
311                    reports[i].updateRef( this );
312                }
313            }
314    
315            /**
316             * Gets the <code>id</code> that will identify the output reports.
317             *
318             * @return the <code>id</code> param if set, or global logdistiller id.
319             */
320            public String getId()
321            {
322                return getParam( "id", logdistiller.getId() );
323            }
324    
325            public Map getParams()
326            {
327                return params;
328            }
329    
330            public String getParam( String name )
331            {
332                return (String) params.get( name );
333            }
334    
335            public String getParam( String name, String defaultValue )
336            {
337                String value = getParam( name );
338                return ( value == null ) ? defaultValue : value;
339            }
340    
341            public Report[] getReports()
342            {
343                return (Report[]) ArrayUtils.clone( reports );
344            }
345    
346            public void setDirectory( String directory )
347            {
348                this.directory = directory;
349            }
350    
351            public String getDirectory()
352            {
353                return directory;
354            }
355    
356            public void setContent( String content )
357            {
358                this.content = content;
359            }
360    
361            public String getContent()
362            {
363                return content;
364            }
365    
366            public String getSkip()
367            {
368                return skip;
369            }
370    
371            public void updateCompatibility( File directory, String content, String skip )
372            {
373                this.directory = directory.getAbsolutePath();
374                this.content = content;
375                this.skip = skip;
376            }
377    
378            public String getUrl()
379            {
380                return url;
381            }
382    
383            public String getUrl( String file )
384            {
385                return ( url == null ) ? null : ( url + '/' + file );
386            }
387        }
388    
389        /**
390         * Definition of a report, with its publisher, formant and other params.
391         */
392        public static class Report
393            implements Serializable
394        {
395            private static final long serialVersionUID = 1669156992489095268L;
396    
397            private final String publisher;
398    
399            private final String format;
400    
401            private final Map params;
402    
403            private transient Output output;
404    
405            private transient Group group;
406    
407            public Report( String publisher, String format, Map params )
408            {
409                this.publisher = publisher;
410                this.format = format;
411                this.params = params;
412            }
413    
414            private void updateRef( Output output )
415            {
416                this.output = output;
417                this.group = null;
418            }
419    
420            private void updateRef( Group group )
421            {
422                this.group = group;
423                this.output = group.getLogdistiller().getOutput();
424            }
425    
426            public Output getOutput()
427            {
428                return output;
429            }
430    
431            public Group getGroup()
432            {
433                return group;
434            }
435    
436            public Map getParams()
437            {
438                return params;
439            }
440    
441            public String getFormat()
442            {
443                return format;
444            }
445    
446            public String getParam( String name )
447            {
448                return (String) params.get( name );
449            }
450    
451            public String getParam( String name, String defaultValue )
452            {
453                String value = getParam( name );
454                return ( value != null ) ? value : output.getParam( publisher + '.' + name, defaultValue );
455            }
456    
457            public String getPublisher()
458            {
459                return publisher;
460            }
461        }
462    
463        /**
464         * Definition of a group of events: events corresponding to its conditions will be collected in it.
465         */
466        public static class Group
467            implements Serializable
468        {
469            private static final long serialVersionUID = 6647633346412959286L;
470    
471            private final String id;
472    
473            private final String description;
474    
475            private final boolean continueProcessing;
476    
477            private final boolean save;
478    
479            private final Map params;
480    
481            private final Condition[] conditions;
482    
483            private final Report[] reports;
484    
485            private final Category category;
486    
487            private final Plugin[] plugins;
488    
489            private transient LogDistiller logdistiller;
490    
491            public Group( String id, String description, boolean continueProcessing, boolean save, Map params,
492                          Condition[] conditions, Report[] reports, Plugin[] plugins, 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 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 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();
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 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 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 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 getParams()
729            {
730                return params;
731            }
732    
733            public String getParam( String name )
734            {
735                return (String) 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    }