001package 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
017import java.io.*;
018import java.util.Collections;
019import java.util.HashMap;
020import java.util.Map;
021import java.util.regex.Pattern;
022
023import 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 */
030public 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<String, Class<? extends Function>> FUNCTIONS;
083        static
084        {
085            Map<String, Class<? extends Function>> map = new HashMap<String, Class<? extends Function>>();
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<? extends Function> functionClass = FUNCTIONS.get( type );
097            if ( functionClass == null )
098            {
099                throw new IllegalArgumentException( "function type not supported '" + type + "'" );
100            }
101            try
102            {
103                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}