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 }