001    package hirondelle.web4jtools.logview.parsedview;
002    
003    import hirondelle.web4j.model.Check;
004    import hirondelle.web4j.model.ModelCtorException;
005    import hirondelle.web4j.model.ModelUtil;
006    import static hirondelle.web4j.util.Consts.FAILS;
007    import static hirondelle.web4j.util.Consts.NOT_FOUND;
008    import hirondelle.web4j.security.SafeText;
009    import java.util.Date;
010    import hirondelle.web4j.util.Util;
011    import hirondelle.web4jtools.logview.simpleview.LogFor;
012    import java.util.logging.Level;
013    
014    /** 
015    *  Model Object for the criteria used for viewing parsed log records.
016    *  
017    * <P>This class is immutable, and makes defensive copies.
018    */
019    public final class ParsedCriteria {
020    
021      /**
022      * Full constructor.
023      *
024      * @param aLogFor either application log or server log (required).
025      * @param aLevel minimum JDK Logger Level (required); any record at this level or higher will be displayed.
026      * @param aMinDate minimum Date for log message (cannot come after <tt>aMaxDate</tt>).
027      * @param aMaxDate maximum Date for log messages.
028      * @param aLoggerStartsWith logger/package name starts with this text.
029      * @param aMethodName name of the method emitting the log message.
030      * @param aLogMessageContains log message must contain this text.
031      * @param aReverseOrder doesn't filter records, but rather sorts them in reverse order, placing most recent first.
032      */
033      public ParsedCriteria(
034       SafeText aLogFor,
035       SafeText aLevel, 
036       Date aMinDate, 
037       Date aMaxDate, 
038       SafeText aLoggerStartsWith, 
039       SafeText aMethodName,
040       SafeText aLogMessageContains,
041       Boolean aReverseOrder
042      ) throws ModelCtorException {
043        fLogFor = Util.textHasContent(aLogFor) ? LogFor.valueOf(aLogFor.getRawString()) : null;
044        fLevel = Util.textHasContent(aLevel) ? Level.parse(aLevel.getRawString()) : null;
045        fMinDate = aMinDate == null ? null : aMinDate.getTime();
046        fMaxDate = aMaxDate == null ? null : aMaxDate.getTime();
047        fLoggerStartsWith = aLoggerStartsWith;
048        fMethodName = aMethodName;
049        fLogMessageContains = aLogMessageContains;
050        fReverseOrder = Util.nullMeansFalse(aReverseOrder);
051        validateState();
052      }
053      
054      /** 
055      * Return an instance having <tt>FINEST</tt> level for application logs.
056      * (No other criteria.)
057      */
058      public static ParsedCriteria forDowntimeListing() {
059        try {
060          return new ParsedCriteria(SafeText.from(LogFor.Application.name()), SafeText.from(Level.FINEST.getName()), null, null, null, null, null, null);
061        }
062        catch(ModelCtorException ex){
063          throw new RuntimeException(ex);
064        }
065      }
066      
067      /** 
068      * Return an instance having <tt>FINEST</tt> level for the given log.
069      * (No other criteria.)
070      */
071      public static ParsedCriteria forStats(String aLogFor) throws ModelCtorException {
072        return new ParsedCriteria(SafeText.from(aLogFor), SafeText.from(Level.FINEST.getName()), null, null, null, null, null, null);
073      }
074      
075      public LogFor getLogFor() { return fLogFor; }
076      Level getLevel() { return fLevel; }  
077      Date getMinDate() { return new Date(fMinDate); }  
078      Date getMaxDate() { return new Date(fMaxDate); }  
079      SafeText getLoggerStartsWith() { return fLoggerStartsWith; }
080      SafeText getMethodName() { return fMethodName; }
081      SafeText getLogMessageContains() { return fLogMessageContains; }
082      public Boolean getReverseOrder() { return fReverseOrder; }
083      
084      /**
085      * Return <tt>true</tt> only if the given logger record passes these criteria.
086      */
087      public boolean passes(LoggerRecord aRecord) {
088        boolean result = true;
089        if( aRecord.getLevel().intValue() < fLevel.intValue() ) {
090          result = FAILS; 
091        }
092        if( fMinDate != null  ) {
093          if ( aRecord.getDate().getTime() < fMinDate ) {
094            result = FAILS;
095          }
096        }
097        if( fMaxDate != null  ) {
098          if ( aRecord.getDate().getTime() > fMaxDate ) {
099            result = FAILS;
100          }
101        }
102        if ( Util.textHasContent(fLoggerStartsWith) ) {
103          if ( ! aRecord.getLogger().getRawString().startsWith(fLoggerStartsWith.getRawString()) ) {
104            result = FAILS;
105          }
106        }
107        if ( Util.textHasContent(fLogMessageContains) ) {
108          if ( NOT_FOUND == aRecord.getMessage().getRawString().indexOf(fLogMessageContains.getRawString()) ) {
109            result = FAILS;
110          }
111        }
112        if ( Util.textHasContent(fMethodName) ) {
113          if ( ! aRecord.getMethod().getRawString().equalsIgnoreCase(fMethodName.getRawString()) ) {
114            result = FAILS;
115          }
116        }
117        return result;
118      }
119      
120      @Override public String toString(){
121        return ModelUtil.toStringFor(this);
122      }
123      
124      @Override public boolean equals(Object aThat){
125        Boolean result = ModelUtil.quickEquals(this, aThat);
126        if ( result == null ) {
127          ParsedCriteria that = (ParsedCriteria)aThat;
128          result = ModelUtil.equalsFor(this.getSignificantFields(), that.getSignificantFields());
129        }
130        return result;
131      }
132      
133      @Override public int hashCode(){
134        if ( fHashCode == 0 ) {
135          fHashCode = ModelUtil.hashCodeFor(getSignificantFields());
136        }
137        return fHashCode;
138      }
139    
140      // PRIVATE //
141      private final LogFor fLogFor;
142      private final Level fLevel;
143      private final Long fMinDate;
144      private final Long fMaxDate;
145      private final SafeText fLoggerStartsWith;
146      private final SafeText fMethodName;
147      private final SafeText fLogMessageContains;
148      private final Boolean fReverseOrder;
149      private int fHashCode;
150    
151      private void validateState() throws ModelCtorException {
152        ModelCtorException ex = new ModelCtorException();
153        
154        if( FAILS == Check.required(fLogFor) ) {
155          ex.add("Log For is required.");
156        }
157        if ( FAILS == Check.required(fLevel) ) {
158          ex.add("Level is required.");
159        }
160        if ( fMinDate != null && fMaxDate != null  ) {
161          if( fMinDate > fMaxDate ) {
162            ex.add("Min Date/Time must come before Max Date/Time");
163          }
164        }
165    
166        if ( ! ex.isEmpty() ) throw ex;
167      }
168      
169      private Object[] getSignificantFields(){
170        return new Object[] {fLogFor, fLevel, fMinDate, fMaxDate, fLoggerStartsWith, fMethodName, fLogMessageContains, fReverseOrder};
171      }
172    }