001    package net.sf.logdistiller.ant;
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.text.*;
019    import java.util.*;
020    import java.util.zip.*;
021    import javax.xml.parsers.*;
022    
023    import org.apache.tools.ant.*;
024    import org.apache.tools.ant.types.*;
025    import org.xml.sax.*;
026    
027    import net.sf.logdistiller.*;
028    import net.sf.logdistiller.util.*;
029    import net.sf.logdistiller.xml.*;
030    
031    /**
032     * Ant task to configure and launch a log distillation.
033     *
034     * <pre>
035     * &lt;logdistiller conf=&quot;&lt;i&gt;[xml configuration file]&lt;/i&gt;&quot; publish=&quot;&lt;i&gt;[all|file,mail,...]&lt;/i&gt;&quot; compressed=&quot;&lt;i&gt;[no|gzip|zip]&lt;/i&gt;&quot;&gt;
036     *  [&lt;&lt;a href=&quot;AntProperty.html&quot;&gt;property&lt;/a&gt; .../&gt;]*
037     *  &lt;fileset ...&gt;
038     * lt;/logdistiller&gt;
039     * </pre>
040     */
041    public class LogDistillerTask
042        extends Task
043    {
044        private File conf;
045    
046        private boolean mail = true;
047    
048        private boolean mailConfigured = false;
049    
050        private List publish;
051    
052        private boolean publishConfigured = false;
053    
054        private Map properties = new HashMap();
055    
056        private AntLogEvent logevent;
057    
058        private AntLogDistillation logdistillation;
059    
060        private List filesets = new ArrayList();
061    
062        /** @since 0.8 */
063        private String compressed = "no";
064    
065        public LogDistillerTask()
066        {
067        }
068    
069        public void setConf( File conf )
070        {
071            this.conf = conf;
072        }
073    
074        public void setMail( boolean mail )
075        {
076            this.mail = mail;
077            mailConfigured = true;
078        }
079    
080        public void setPublish( String publish )
081        {
082            publishConfigured = true;
083            publish = publish.trim();
084            if ( publish.equals( "all" ) )
085            {
086                this.publish = null;
087            }
088            else
089            {
090                this.publish = new ArrayList();
091                while ( publish.length() > 0 )
092                {
093                    int index = publish.indexOf( ',' );
094                    if ( index > -1 )
095                    {
096                        this.publish.add( publish.substring( 0, index ).trim() );
097                        publish = publish.substring( index + 1 );
098                    }
099                    else
100                    {
101                        this.publish.add( publish );
102                        publish = "";
103                    }
104                }
105            }
106        }
107    
108        public void addConfiguredProperty( AntProperty property )
109        {
110            properties.put( property.getName(), property.getValue() );
111        }
112    
113        public void setCompressed( Compressed attr )
114        {
115            this.compressed = attr.getValue();
116        }
117    
118        /**
119         * @deprecated since LogDistiller 0.7, replaced by logtype element in rules configuration
120         */
121        public AntLogEvent createLogevent()
122        {
123            logevent = new AntLogEvent( getProject() );
124            return logevent;
125        }
126    
127        /**
128         * @deprecated since LogDistiller 0.7, replaced by output element in rules configuration
129         */
130        public AntLogDistillation createLogdistillation()
131        {
132            logdistillation = new AntLogDistillation();
133            return logdistillation;
134        }
135    
136        public void addFileSet( FileSet fs )
137        {
138            filesets.add( fs );
139        }
140    
141        public void execute()
142            throws BuildException
143        {
144            log( "LogDistiller " + LogDistiller.getVersion() );
145            LogDistiller ld = readLogDistiller();
146            compatibilityUpdate( ld );
147    
148            if ( LogTypes.getLogType( ld.getLogType().getId() ) == null )
149            {
150                throw new BuildException( "Could not find logtype '" + ld.getLogType().getId() + "': available values are "
151                    + LogTypes.listAllLogTypeIds() );
152            }
153    
154            LogDistillation distillation = new LogDistillation( ld );
155    
156            LogEvent.Factory factory = initLogEventFactory( distillation.getLogTypeDescription() );
157    
158            log( "content: " + ld.getOutput().getContent() + ", output directory: " + ld.getOutput().getDirectory() );
159    
160            String step = null;
161            try
162            {
163                step = "beginning logdistillation";
164                distillation.begin();
165    
166                step = "reading a log event";
167                int count = 0;
168                LogEvent le;
169                while ( ( le = factory.nextEvent() ) != null )
170                {
171                    count++;
172                    distillation.processLogEvent( le );
173                }
174    
175                step = "ending logdistillation";
176                distillation.end();
177                log( "logevents distilled: " + count + ", time elapsed: "
178                    + FormatUtil.formatPeriod( distillation.getEndTime() - distillation.getBeginTime() ) );
179    
180                step = "publishing logdistillation reports";
181                int reports = new PublishHelper( distillation, publish ).publish();
182                log( "reports published: " + reports );
183            }
184            catch ( IOException ioe )
185            {
186                throw new BuildException( "I/O error when " + step + ": " + ioe.getMessage(), ioe );
187            }
188            catch ( Publisher.PublishException ppe )
189            {
190                throw new BuildException( "Error when " + step + ": " + ppe.getMessage(), ppe );
191            }
192            catch ( ParseException pe )
193            {
194                throw new BuildException( "Parsing error when " + step + ": " + pe.getMessage(), pe );
195            }
196        }
197    
198        /**
199         * Make all that's possible to update latest LogDistiller model to maintain compatibility with older versions, since
200         * some elements have moved from Ant task to LogDistiller model.
201         *
202         * @param ld LogDistiller
203         */
204        private void compatibilityUpdate( LogDistiller ld )
205        {
206            if ( logevent != null )
207            {
208                if ( ld.isOld() )
209                {
210                    String warning =
211                        "element 'logevent' is deprecated in Ant logdistiller task, please use element 'logtype' "
212                            + "from " + LogDistillerEntityResolver.LATEST_DTD + " in your rules file";
213                    log( "WARNING: " + warning, Project.MSG_WARN );
214                    ld.addWarning( warning );
215                    ld.buildCompatibilityLogType( logevent.getLogtype() );
216                }
217                else
218                {
219                    String warning =
220                        "element 'logevent' is deprecated in Ant logdistiller task now that you use element "
221                            + "'logtype' from " + LogDistillerEntityResolver.LATEST_DTD
222                            + " in your rules file: ignored (please remove)";
223                    log( "WARNING : " + warning, Project.MSG_WARN );
224                    ld.addWarning( warning );
225                }
226            }
227    
228            if ( logdistillation != null )
229            {
230                if ( ld.isOld() )
231                {
232                    String warning =
233                        "element 'logdistillation' is deprecated in Ant logdistiller task, please use element "
234                            + "'output' from " + LogDistillerEntityResolver.LATEST_DTD + " in your rules file";
235                    log( "WARNING: " + warning, Project.MSG_WARN );
236                    ld.addWarning( warning );
237                    String skipgroups = logdistillation.getSkipgroups();
238                    int pos = skipgroups.indexOf( ',' );
239                    if ( pos >= 0 )
240                    {
241                        skipgroups = skipgroups.substring( 0, pos ).trim();
242                        warning =
243                            "attribute skipgroups in logdistillation element cannot refer any more to multiple groups: "
244                                + "please create a category. Only group '" + skipgroups + "' has been kept.";
245                    }
246                    ld.getOutput().updateCompatibility( logdistillation.getDestdir(), logdistillation.getContent(),
247                                                        skipgroups );
248                }
249                else
250                {
251                    String warning =
252                        "element 'logdistillation' is deprecated in Ant logdistiller task now that you use element "
253                            + "'output' from " + LogDistillerEntityResolver.LATEST_DTD
254                            + " in your rules file: ignored (please remove)";
255                    log( "WARNING: " + warning, Project.MSG_WARN );
256                    ld.addWarning( warning );
257                }
258            }
259    
260            if ( mailConfigured )
261            {
262                if ( !publishConfigured )
263                {
264                    setPublish( mail ? "file,mail" : "file" );
265                }
266                else
267                {
268                    String warning =
269                        "attribute 'mail' is deprecated in Ant logdistiller task now that you use attribute "
270                            + "'publish': attribute ignored (please remove)";
271                    log( "WARNING: " + warning, Project.MSG_WARN );
272                    ld.addWarning( warning );
273                }
274            }
275        }
276    
277        private LogDistiller readLogDistiller()
278        {
279            DOMConfigurator domConfigurator = new DOMConfigurator( properties );
280            try
281            {
282                log( "reading configuration " + conf );
283                return domConfigurator.read( conf );
284            }
285            catch ( IllegalArgumentException iae )
286            {
287                throw new BuildException( "error in configuration: " + iae.getMessage(), iae );
288            }
289            catch ( SAXException saxe )
290            {
291                throw new BuildException( "parsing error in logdistiller XML configuration file " + conf + ": "
292                    + saxe.getMessage(), saxe );
293            }
294            catch ( IOException ioe )
295            {
296                throw new BuildException( "error while reading file " + conf + ": " + ioe.getMessage(), ioe );
297            }
298            catch ( ParserConfigurationException pce )
299            {
300                throw new BuildException( "error with XML parser configuration:" + pce.getMessage(), pce );
301            }
302        }
303    
304        private FactoryMultiplexer initLogEventFactory( LogType.Description description )
305        {
306            // construct a log event multiplexer with each file added in the fileset
307            FactoryMultiplexer multiplexer = new FactoryMultiplexer( description );
308            try
309            {
310                int count = 0;
311                Iterator iter = filesets.iterator();
312                while ( iter.hasNext() )
313                {
314                    FileSet fs = (FileSet) iter.next();
315                    DirectoryScanner ds = fs.getDirectoryScanner( getProject() );
316                    String[] srcFiles = ds.getIncludedFiles();
317                    int len = srcFiles.length;
318                    for ( int i = 0; i < len; i++ )
319                    {
320                        count += addFile( new File( ds.getBasedir(), srcFiles[i] ), description, multiplexer );
321                    }
322                }
323                log( "parsing " + count + " log files" );
324            }
325            catch ( IOException ioe )
326            {
327                throw new BuildException( "error while opening log file: " + ioe.getMessage(), ioe );
328            }
329            return multiplexer;
330        }
331    
332        private int addFile( File file, LogType.Description description, FactoryMultiplexer multiplexer )
333            throws IOException
334        {
335            int count = 0;
336            log( "parsing " + file.getPath() );
337            if ( "no".equals( compressed ) )
338            {
339                Reader reader = new InputStreamReader( new FileInputStream( file ) );
340                String logSource = file.toURL().toString();
341                multiplexer.addFactory( description.newFactory( reader, logSource ) );
342                count++;
343            }
344            else if ( "gzip".equals( compressed ) )
345            {
346                Reader reader = new InputStreamReader( new GZIPInputStream( new FileInputStream( file ) ) );
347                String logSource = "gzip:" + file.toURL().toString();
348                multiplexer.addFactory( description.newFactory( reader, logSource ) );
349                count++;
350            }
351            else if ( "compress".equals( compressed ) )
352            {
353                Reader reader = new InputStreamReader( new UncompressInputStream( new FileInputStream( file ) ) );
354                String logSource = "compress:" + file.toURL().toString();
355                multiplexer.addFactory( description.newFactory( reader, logSource ) );
356                count++;
357            }
358            else
359            { // zip
360                ZipFile zip = new ZipFile( file );
361                Enumeration iter = zip.entries();
362                while ( iter.hasMoreElements() )
363                {
364                    ZipEntry entry = (ZipEntry) iter.nextElement();
365                    if ( !entry.isDirectory() )
366                    {
367                        log( "   " + entry.getName() );
368                        Reader reader = new InputStreamReader( zip.getInputStream( entry ) );
369                        String logSource = "zip:" + file.toURL() + "!" + entry.getName();
370                        multiplexer.addFactory( description.newFactory( reader, logSource ) );
371                        count++;
372                    }
373                }
374            }
375            return count;
376        }
377    
378        public static class Compressed
379            extends EnumeratedAttribute
380        {
381            public String[] getValues()
382            {
383                return new String[] { "no", "gzip", "zip", "compress" };
384            }
385        }
386    }