buildframework/helium/sf/java/metadata/src/com/nokia/helium/metadata/ant/types/sbs/SBSLogHandler.java
changeset 628 7c4a911dc066
equal deleted inserted replaced
588:c7c26511138f 628:7c4a911dc066
       
     1 /*
       
     2  * Copyright (c) 2007-2008 Nokia Corporation and/or its subsidiary(-ies).
       
     3  * All rights reserved.
       
     4  * This component and the accompanying materials are made available
       
     5  * under the terms of the License "Eclipse Public License v1.0"
       
     6  * which accompanies this distribution, and is available
       
     7  * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8  *
       
     9  * Initial Contributors:
       
    10  * Nokia Corporation - initial contribution.
       
    11  *
       
    12  * Contributors:
       
    13  *
       
    14  * Description:  
       
    15  *
       
    16  */
       
    17 package com.nokia.helium.metadata.ant.types.sbs;
       
    18 
       
    19 import java.io.File;
       
    20 import java.io.IOException;
       
    21 import java.util.ArrayList;
       
    22 import java.util.Hashtable;
       
    23 import java.util.List;
       
    24 import java.util.regex.Matcher;
       
    25 import java.util.regex.Pattern;
       
    26 
       
    27 import javax.xml.parsers.ParserConfigurationException;
       
    28 import javax.xml.parsers.SAXParser;
       
    29 import javax.xml.parsers.SAXParserFactory;
       
    30 
       
    31 import org.xml.sax.Attributes;
       
    32 import org.xml.sax.Locator;
       
    33 import org.xml.sax.SAXException;
       
    34 import org.xml.sax.SAXParseException;
       
    35 import org.xml.sax.helpers.DefaultHandler;
       
    36 
       
    37 import com.nokia.helium.metadata.ant.types.SeverityEnum;
       
    38 
       
    39 /**
       
    40  * This class implements the parsing of a SBS log file.
       
    41  * Information will be pushed using an SBSLogEvents.
       
    42  *
       
    43  */
       
    44 public class SBSLogHandler extends DefaultHandler {
       
    45     private static final int UNCATEGORIZED_MAP_LIMIT = 10000;
       
    46     private static final String BLDINF_COMPONENT = "/bld.inf";
       
    47     private File file;
       
    48     private SBSLogEvents eventHandler;
       
    49     private boolean record;
       
    50     private StringBuffer text = new StringBuffer();
       
    51     private Locator locator; 
       
    52     private String recipeStatus = "ok";
       
    53     private String currentComponent;
       
    54     private boolean inWhatLog;
       
    55     private long deep;
       
    56     private StringBuffer mainSectionText = new StringBuffer();
       
    57     private List<SpecialPattern> specialPatterns = new ArrayList<SpecialPattern>();
       
    58     private UncategorizedItemMap uncategorizedItemMap = new UncategorizedItemMap();
       
    59 
       
    60     
       
    61     class SpecialPattern {
       
    62         private Pattern regexPattern;
       
    63         private int groupPosition;
       
    64 
       
    65         public SpecialPattern(String exp, int pos) {
       
    66             regexPattern = Pattern.compile(exp);
       
    67             groupPosition = pos;
       
    68         }
       
    69         
       
    70         public Pattern getRegexPattern() {
       
    71             return regexPattern;
       
    72         }
       
    73         
       
    74         public int getGroupPosition() {
       
    75             return groupPosition;
       
    76         }
       
    77     }
       
    78     
       
    79     class UncategorizedItemMap extends Hashtable<String, List<UncategorizedItem>> {
       
    80         
       
    81         private static final long serialVersionUID = 1L;
       
    82 
       
    83         public void put(String key, UncategorizedItem item) {
       
    84             if (this.containsKey(key)) {
       
    85                 this.get(key).add(item);
       
    86             } else {
       
    87                 this.put(key, new ArrayList<UncategorizedItem>());
       
    88                 this.get(key).add(item);                
       
    89             }
       
    90         }
       
    91     }
       
    92     
       
    93     class UncategorizedItem {
       
    94         private SeverityEnum.Severity priotity;
       
    95         private String text;
       
    96         private int lineNumber;
       
    97         
       
    98         public UncategorizedItem(String text, int lineNumber, SeverityEnum.Severity priotity) {
       
    99             this.text = text;
       
   100             this.lineNumber = lineNumber;
       
   101             this.priotity = priotity;
       
   102         }
       
   103 
       
   104         public SeverityEnum.Severity getPriotity() {
       
   105             return priotity;
       
   106         }
       
   107 
       
   108         public String getText() {
       
   109             return text;
       
   110         }
       
   111 
       
   112         public int getLineNumber() {
       
   113             return lineNumber;
       
   114         }
       
   115     }
       
   116     
       
   117     /**
       
   118      * Construct an SBSLogHandler, defining a SBSLogEvents object
       
   119      * to receive parsing notifications. The file will be used
       
   120      * by the categorization handler.
       
   121      * 
       
   122      * @param event
       
   123      * @param file
       
   124      */
       
   125     public SBSLogHandler(SBSLogEvents event, File file) {
       
   126         this.file = file;
       
   127         this.eventHandler = event;
       
   128         currentComponent = event.getDefaultComponentName();
       
   129         specialPatterns.add(new SpecialPattern("(make.exe|make): \\*\\*\\* No rule to make target.*needed by `(.*)'.*", 2));
       
   130         specialPatterns.add(new SpecialPattern("(make.exe|make): \\*\\*\\* \\[(.*)\\].*", 2));
       
   131     }
       
   132 
       
   133     /**
       
   134      * This method will cleanup the path of a bld.inf to extract
       
   135      * a component name.
       
   136      * e.g: I:/root/layer/package/group/bld.inf
       
   137      * will return root/layer/package/group
       
   138      * 
       
   139      * @param text
       
   140      * @return
       
   141      */
       
   142     protected String removeDriveAndBldInf(String text) {
       
   143         // Some light linux support
       
   144         if (text.endsWith(BLDINF_COMPONENT)) {
       
   145             text = text.substring(0, text.length() - BLDINF_COMPONENT.length());
       
   146         }
       
   147         if (this.eventHandler.getEpocroot() == null) {
       
   148             return text.replaceFirst("^([a-zA-Z]:)?/", "");
       
   149         } else {
       
   150             text = this.eventHandler.getEpocroot().toURI().relativize((new File(text)).toURI()).getPath();
       
   151             if (text.endsWith("/")) {
       
   152                 text = text.substring(0, text.length() - 1);
       
   153             }
       
   154             return text;
       
   155         }
       
   156     }
       
   157 
       
   158     /**
       
   159      * Get the component based on the Attributes list.
       
   160      * If not found it will fallback to the default
       
   161      * component name defined by the eventHandler.
       
   162      * 
       
   163      * @param attributes XML tag SAX attributes list.
       
   164      * @return a String representing the component name
       
   165      */
       
   166     public String getComponent(Attributes attributes) {
       
   167         String component = attributes.getValue("", "bldinf");
       
   168         if (component == null || component.length() == 0) {
       
   169             return eventHandler.getDefaultComponentName();
       
   170         }
       
   171         return removeDriveAndBldInf(component);
       
   172     }
       
   173 
       
   174     /**
       
   175      * {@inheritDoc}
       
   176      */
       
   177     @Override
       
   178     public void setDocumentLocator(Locator locator) {
       
   179         this.locator = locator;
       
   180         super.setDocumentLocator(locator);
       
   181     }
       
   182 
       
   183     /**
       
   184      * {@inheritDoc}
       
   185      */
       
   186     @Override
       
   187     public void endElement(String uri, String localName, String qName)
       
   188         throws SAXException {
       
   189         // one level deeper
       
   190         deep--;
       
   191         if (qName.equals("error") || qName.equals("warning") || qName.equals("info")) {
       
   192             record = false;
       
   193             String line = text.toString();
       
   194             if (!line.trim().equals("")) {
       
   195                 //log.info(qName + " - " + line);
       
   196                 eventHandler.add(SeverityEnum.Severity.valueOf(qName.toUpperCase()), text.toString(), locator.getLineNumber());
       
   197             }
       
   198         } else if (qName.equals("recipe")) {
       
   199             record = false;
       
   200             int count = 0;
       
   201             for (String line : text.toString().split("\n")) {
       
   202                 if (eventHandler.check(currentComponent, line, locator.getLineNumber()) == SeverityEnum.Severity.ERROR) {
       
   203                     count++;
       
   204                 }
       
   205             }
       
   206             if (count == 0 && recipeStatus.equalsIgnoreCase("failed")) {
       
   207                 eventHandler.add(SeverityEnum.Severity.ERROR, currentComponent, "ERROR: recipe exit status is failed.", locator.getLineNumber());
       
   208             }
       
   209             recipeStatus = "ok";
       
   210             text.setLength(0);
       
   211         } else if (qName.equalsIgnoreCase("whatlog") ) {
       
   212             record = false;
       
   213             for (String line : text.toString().split("\n")) {
       
   214                 line = line.trim().replace("\"", "");
       
   215                 if (line.length() > 0) {
       
   216                     this.eventHandler.addWhatEntry(currentComponent, line, locator.getLineNumber());
       
   217                 }
       
   218             }
       
   219             text.setLength(0);
       
   220             inWhatLog = false;
       
   221         } else if (inWhatLog && qName.equalsIgnoreCase("member")) {
       
   222             String line = text.toString().trim().replace("\"", "");
       
   223             this.eventHandler.addWhatEntry(currentComponent, line, locator.getLineNumber());
       
   224             record = false;
       
   225             text.setLength(0);
       
   226         } else if (qName.equalsIgnoreCase("clean")) {
       
   227             record = false;
       
   228             for (String line : text.toString().split("\n")) {
       
   229                 line = line.trim().replace("\"", "");
       
   230                 if (line.length() > 0) {
       
   231                     if (uncategorizedItemMap.containsKey(line)) {
       
   232                         for (UncategorizedItem item : uncategorizedItemMap.get(line)) {
       
   233                             this.eventHandler.add(item.getPriotity(), currentComponent, item.getText(), item.getLineNumber());
       
   234                         }
       
   235                         uncategorizedItemMap.remove(line);
       
   236                     }
       
   237                 }
       
   238             }
       
   239             text.setLength(0);
       
   240         }
       
   241         if (deep == 1) {
       
   242             mainSectionText.setLength(0);
       
   243         }
       
   244         super.endElement(uri, localName, qName);
       
   245     }
       
   246 
       
   247     /**
       
   248      * {@inheritDoc}
       
   249      */
       
   250     @Override
       
   251     public void fatalError(SAXParseException e) throws SAXException {
       
   252         // Reporting an XML parsing error.
       
   253         eventHandler.add(SeverityEnum.Severity.ERROR, e.getMessage(), e.getLineNumber());
       
   254         super.fatalError(e);
       
   255     }
       
   256 
       
   257     /**
       
   258      * {@inheritDoc}
       
   259      */
       
   260     @Override
       
   261     public void error(SAXParseException e) throws SAXException {
       
   262         // Reporting an XML parsing error.
       
   263         eventHandler.add(SeverityEnum.Severity.ERROR, e.getMessage(), e.getLineNumber());
       
   264         super.error(e);
       
   265     }
       
   266     
       
   267     /**
       
   268      * {@inheritDoc}
       
   269      */
       
   270     @Override
       
   271     public void startElement(String uri, String localName, String qName,
       
   272             Attributes attributes) throws SAXException {
       
   273         // one level deeper
       
   274         deep++;
       
   275         if (deep == 2) {
       
   276             for (String line : mainSectionText.toString().split("\n")) {
       
   277                 for (SpecialPattern sp : specialPatterns) {
       
   278                     Matcher matcher = sp.getRegexPattern().matcher(line);
       
   279                     if (matcher.matches()) {
       
   280                         uncategorizedItemMap.put(matcher.group(sp.getGroupPosition()), new UncategorizedItem(line, locator.getLineNumber(), SeverityEnum.Severity.ERROR));
       
   281                     }
       
   282                 }
       
   283                 // record external log messages (such as from emake)
       
   284                 eventHandler.check(line, locator.getLineNumber());
       
   285             }
       
   286             if (uncategorizedItemMap.size() > UNCATEGORIZED_MAP_LIMIT) {
       
   287                 emptyUncategorizedItemMap();
       
   288             }
       
   289             mainSectionText.setLength(0);
       
   290         }
       
   291         if (qName.equalsIgnoreCase("buildlog")) {
       
   292             mainSectionText.setLength(0);
       
   293         } else if (qName.equals("error") || qName.equals("warning") || qName.equals("info")) {
       
   294             record = true;
       
   295             text.setLength(0);
       
   296         } else if (qName.equals("recipe")) {
       
   297             record = true;
       
   298             text.setLength(0);
       
   299             currentComponent = getComponent(attributes);
       
   300             this.eventHandler.declareComponent(currentComponent);
       
   301         } else if (qName.equalsIgnoreCase("time")) {
       
   302             //currentComponent
       
   303             String elapsed = attributes.getValue("", "elapsed");
       
   304             if (elapsed != null) {
       
   305                 try {
       
   306                     this.eventHandler.addElapsedTime(currentComponent, Double.valueOf(elapsed).doubleValue());
       
   307                 } catch (NumberFormatException ex) {
       
   308                     ex = null; // ignoring the error.
       
   309                 }
       
   310             }
       
   311             //elapsedTime = Float.valueOf(getAttribute("elapsed", streamReader)).floatValue();
       
   312         } else if (qName.equalsIgnoreCase("status") ) {
       
   313             String exit = attributes.getValue("", "exit");
       
   314             recipeStatus = (exit != null) ? exit : "ok";
       
   315         } else if (qName.equalsIgnoreCase("whatlog") ) {
       
   316             record = true;
       
   317             inWhatLog = true;
       
   318             text.setLength(0);
       
   319             currentComponent = getComponent(attributes);
       
   320             this.eventHandler.declareComponent(currentComponent);
       
   321         } else if (inWhatLog && qName.equalsIgnoreCase("export")) {
       
   322             String filename = attributes.getValue("", "destination");
       
   323             eventHandler.addWhatEntry(currentComponent, filename, locator.getLineNumber());
       
   324         } else if (inWhatLog && qName.equalsIgnoreCase("member")) {
       
   325             record = true;
       
   326             text.setLength(0);
       
   327         } else if (qName.equalsIgnoreCase("clean")) {
       
   328             record = true;
       
   329             currentComponent = getComponent(attributes);
       
   330             this.eventHandler.declareComponent(currentComponent);
       
   331             text.setLength(0);
       
   332         }
       
   333         super.startElement(uri, localName, qName, attributes);
       
   334     }
       
   335     
       
   336     /**
       
   337      * {@inheritDoc}
       
   338      */
       
   339     @Override
       
   340     public void characters(char[] ch, int start, int length)
       
   341         throws SAXException {
       
   342         if (record) {
       
   343             text.append(ch, start, length);
       
   344         }
       
   345         if (deep == 1) {
       
   346             mainSectionText.append(ch, start, length);            
       
   347         }
       
   348         super.characters(ch, start, length);
       
   349     }
       
   350 
       
   351 
       
   352     private void emptyUncategorizedItemMap() throws SAXException {
       
   353         if (uncategorizedItemMap.size() > 0) {
       
   354             try {
       
   355                 SAXParserFactory saxFactory = SAXParserFactory.newInstance();
       
   356                 SAXParser parser = saxFactory.newSAXParser();
       
   357                 parser.parse(file, new CategorizationHandler(this));
       
   358             } catch (ParserConfigurationException e) {
       
   359                 throw new SAXException(e.getMessage(), e);
       
   360             } catch (IOException e) {
       
   361                 throw new SAXException(e.getMessage(), e);
       
   362             }
       
   363         }        
       
   364     }
       
   365     
       
   366     /**
       
   367      * {@inheritDoc}
       
   368      */
       
   369     @Override
       
   370     public void endDocument() throws SAXException {
       
   371         // Remaining changes
       
   372         
       
   373         // Let's try categorization handler first
       
   374         emptyUncategorizedItemMap();
       
   375         
       
   376         // Last resorts
       
   377         for (String key : uncategorizedItemMap.keySet()) {
       
   378             for (UncategorizedItem item : uncategorizedItemMap.get(key)) {
       
   379                 this.eventHandler.add(item.getPriotity(), this.eventHandler.getDefaultComponentName(), item.getText(), item.getLineNumber());
       
   380             }
       
   381         }
       
   382         super.endDocument();
       
   383     }
       
   384 
       
   385     /**
       
   386      * Get the EventHandler.
       
   387      * @return
       
   388      */
       
   389     public SBSLogEvents getEventHandler() {
       
   390         return eventHandler;
       
   391     }    
       
   392 
       
   393     /**
       
   394      * Get the uncategorized items map.
       
   395      * @return a map of uncategorized items.
       
   396      */
       
   397     public UncategorizedItemMap getUncategorizedItemMap() {
       
   398         return uncategorizedItemMap;
       
   399     }
       
   400 }