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.Collections;
019    import java.util.HashMap;
020    import java.util.Map;
021    import java.util.regex.Pattern;
022    
023    import org.jdom.Element;
024    
025    /**
026     * Match of an attribute of a LogEvent. Match type can be either <code>contains</code>, <code>equals</code>,
027     * <code>startsWith</code>, <code>endsWith</code> or <code>regexp</code>, and can be negated by preceding type with
028     * <code>!</code>.
029     */
030    public class Match
031        implements Serializable
032    {
033        private static final long serialVersionUID = -1809458932445222708L;
034    
035        private final String attribute;
036    
037        private final boolean not;
038    
039        private final Function function;
040    
041        private transient LogType.AttributeInfo attributeInfo;
042    
043        public Match( String attribute, String type, String reference )
044        {
045            this.attribute = attribute;
046            this.not = type.startsWith( "!" );
047            if ( not )
048            {
049                type = type.substring( 1 );
050            }
051            this.function = Match.Function.getInstance( type, reference );
052        }
053    
054        public boolean match( LogEvent le )
055        {
056            // initialize attributeInfo if necessary
057            if ( attributeInfo == null )
058            {
059                LogType.Description description = le.getFactory().getDescription();
060                attributeInfo = description.getAttributeInfo( attribute );
061            }
062    
063            String value = le.getValue( attributeInfo );
064            boolean result = function.checkValue( value );
065            return ( not ? !result : result );
066        }
067    
068        public Element dump()
069        {
070            Element elmt = new Element( "match" );
071            elmt.setAttribute( "attribute", attribute );
072            elmt.setAttribute( "type", ( not ? "!" : "" ) + function.getId() );
073            elmt.setText( function.reference );
074            return elmt;
075        }
076    
077        private static abstract class Function
078            implements Serializable
079        {
080            private static final long serialVersionUID = 1072441995042764838L;
081    
082            public final static Map FUNCTIONS;
083            static
084            {
085                Map map = new HashMap();
086                map.put( Contains.ID, Contains.class );
087                map.put( Equals.ID, Equals.class );
088                map.put( StartsWith.ID, StartsWith.class );
089                map.put( EndsWith.ID, EndsWith.class );
090                map.put( Regexp.ID, Regexp.class );
091                FUNCTIONS = Collections.unmodifiableMap( map );
092            }
093    
094            public static Function getInstance( String type, String reference )
095            {
096                Class functionClass = (Class) FUNCTIONS.get( type );
097                if ( functionClass == null )
098                {
099                    throw new IllegalArgumentException( "function type not supported '" + type + "'" );
100                }
101                try
102                {
103                    Function function = (Function) functionClass.newInstance();
104                    function.setReference( reference );
105                    return function;
106                }
107                catch ( IllegalAccessException iae )
108                {
109                    // can't happen
110                    throw new RuntimeException( "an impossible condition has arrived...", iae );
111                }
112                catch ( InstantiationException ie )
113                {
114                    // can't happen
115                    throw new RuntimeException( "an impossible condition has arrived...", ie );
116                }
117            }
118    
119            protected String reference;
120    
121            public void setReference( String reference )
122            {
123                this.reference = reference;
124            }
125    
126            public abstract String getId();
127    
128            /**
129             * check if the given value matches the reference.
130             *
131             * @param value String the value to compare to reference
132             * @return boolean
133             */
134            public abstract boolean checkValue( String value );
135        }
136    
137        protected static class Contains
138            extends Function
139        {
140            private static final long serialVersionUID = 4613611844726287358L;
141    
142            public static final String ID = "contains";
143    
144            public String getId()
145            {
146                return ID;
147            }
148    
149            public boolean checkValue( String value )
150            {
151                return ( value.indexOf( reference ) >= 0 );
152            }
153        }
154    
155        protected static class Equals
156            extends Function
157        {
158            private static final long serialVersionUID = -6539918940865536415L;
159    
160            public static final String ID = "equals";
161    
162            public String getId()
163            {
164                return ID;
165            }
166    
167            public boolean checkValue( String value )
168            {
169                return reference.equals( value );
170            }
171        }
172    
173        protected static class StartsWith
174            extends Function
175        {
176            private static final long serialVersionUID = 5014914695776363132L;
177    
178            public static final String ID = "startsWith";
179    
180            public String getId()
181            {
182                return ID;
183            }
184    
185            public boolean checkValue( String value )
186            {
187                return value.startsWith( reference );
188            }
189        }
190    
191        protected static class EndsWith
192            extends Function
193        {
194            private static final long serialVersionUID = 1819477635452601804L;
195    
196            public static final String ID = "endsWith";
197    
198            public String getId()
199            {
200                return ID;
201            }
202    
203            public boolean checkValue( String value )
204            {
205                return value.endsWith( reference );
206            }
207        }
208    
209        protected static class Regexp
210            extends Function
211        {
212            private static final long serialVersionUID = -2067188055591690252L;
213    
214            public static final String ID = "regexp";
215    
216            public String getId()
217            {
218                return ID;
219            }
220    
221            private transient Pattern pattern;
222    
223            public void setReference( String reference )
224            {
225                super.setReference( reference );
226                updatePattern();
227            }
228    
229            private void updatePattern()
230            {
231                pattern = Pattern.compile( reference );
232            }
233    
234            private void readObject( ObjectInputStream in )
235                throws IOException, ClassNotFoundException
236            {
237                in.defaultReadObject();
238                updatePattern();
239            }
240    
241            public boolean checkValue( String value )
242            {
243                return pattern.matcher( value ).find();
244            }
245        }
246    }