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.IOException;
018import java.io.Reader;
019import java.util.*;
020
021import net.sf.logdistiller.Attributes.Extension;
022import net.sf.logdistiller.util.FormatUtil;
023
024/**
025 * Base class for log type implementation. A log type identifies the log format, which can be customized depending on
026 * parameter's values. When defining a new log type, {@link #newDescription newDescription(Map params)} method has to be
027 * implemented to define and handle log type's parameters.
028 *
029 * @see LogType.Basic
030 * @see LogType.Description
031 * @see LogTypes
032 */
033public abstract class LogType
034{
035    private final String id;
036
037    protected LogType( String id )
038    {
039        this.id = id;
040    }
041
042    /**
043     * Create a new log description customized with parameters.
044     *
045     * @param params the parameters to customize the log type definition
046     */
047    public abstract Description newDescription( Map<String, String> params );
048
049    public String getId()
050    {
051        return id;
052    }
053
054    /**
055     * Basic logtype definition that does not provide any parameters for customization. It always returns the same
056     * Description instance, which must have been set by calling {@link #setDescription}.
057     */
058    public static class Basic
059        extends LogType
060    {
061        private Description description;
062
063        public Basic( String id )
064        {
065            super( id );
066        }
067
068        public void setDescription( Description description )
069        {
070            this.description = description;
071        }
072
073        public Description newDescription( Map<String, String> params )
074        {
075            if ( description == null )
076            {
077                throw new IllegalStateException( "description must be set before basic logtype use" );
078            }
079            return description;
080        }
081    }
082
083    /**
084     * Description of a log format corresponding to a log type. It must be subclassed for every log type to implement
085     * specialized {@link #newFactory(Reader, String)} method.
086     */
087    public static abstract class Description
088    {
089        private final LogType logtype;
090
091        private final List<String> attributeNames;
092
093        /**
094         * Extensions of the log type attributes. Each extension can define multiple extension attributes.
095         * @since 1.1
096         */
097        private Attributes.Extension[] extensions = Attributes.NO_EXTENSIONS;
098
099        /**
100         * Attributes defined by extensions, with corresponding extension index position.
101         * @since 1.1
102         */
103        private Map<String, Integer> extendedAttributes = new HashMap<String, Integer>();
104
105        /**
106         * Create a new LogType description. By convention, the first attribute should be <code>logSource</code> and the
107         * second should be the timestamp (if this notion is relevant for the log type).
108         *
109         * @param logtype
110         * @param attributeNames
111         * @see #getTimestampAttribute()
112         * @see LogEvent#getTimestamp()
113         */
114        public Description( LogType logtype, String[] attributeNames )
115        {
116            this.logtype = logtype;
117            this.attributeNames = Collections.unmodifiableList( Arrays.asList( attributeNames ) );
118        }
119
120        public LogType getLogType()
121        {
122            return logtype;
123        }
124
125        public List<String> getAttributeNames()
126        {
127            return attributeNames;
128        }
129
130        public int getAttributesCount()
131        {
132            return attributeNames.size();
133        }
134
135        public String getAttributeName( int pos )
136        {
137            return attributeNames.get( pos );
138        }
139
140        /** @since 1.1 */
141        public void setExtensions( Attributes.Extension[] extensions )
142        {
143            this.extensions = extensions;
144            for ( int i = extensions.length - 1; i >= 0; i-- )
145            {
146                Attributes.Extension extension = extensions[i];
147                for ( String attribute : extension.getProvides() )
148                {
149                    extendedAttributes.put( attribute, new Integer( i ) );
150                }
151            }
152        }
153
154        /** @since 1.1 */
155        public Attributes.Extension[] getExtensions()
156        {
157            return extensions;
158        }
159
160        /**
161         * Gets the extension index position which defines corresponding attribute.
162         *
163         * @return the extension index, or -1 if not found
164         * @since 1.1
165         */
166        public int getExtensionIndex( String attribute )
167        {
168            Integer index = extendedAttributes.get( attribute );
169            return ( index == null ) ? -1 : index.intValue();
170        }
171
172        /**
173         * Get the attribute that represents the timestamp.
174         *
175         * @return the attribute count, or <code>-1</code> if this logtype does not have a timestamp
176         */
177        public int getTimestampAttribute()
178        {
179            return 1;
180        }
181
182        /**
183         * Get the group definitions specific to this log type that will be added to the generated rules configuration
184         * generated by the GUI.
185         *
186         * @return an XML fragment containing group definitions
187         */
188        public String getDefaultSpecificGroups()
189        {
190            return "";
191        }
192
193        /**
194         * Get the attributes that can be used as a sorting key to get useful event sampling in the last "unknown" group
195         * (separated with a quote when multiple attributes). They will be used as a default sampling rule
196         * configuration.
197         *
198         * @return "attr1[,attr2[,...]]"
199         */
200        public String getDefaultSamplingAttributes()
201        {
202            return "";
203        }
204
205        /**
206         * Find the attribute index corresponding to an attribute name (provided attributes only).
207         *
208         * @param name String the attribute name to search for
209         * @return int the index of the attribute, or -1 if not found
210         * @see #getExtensionIndex(String) to find an extension attribute index
211         */
212        public int getAttributeIndex( String name )
213        {
214            return attributeNames.indexOf( name );
215        }
216
217        public AttributeInfo getAttributeInfo( String name )
218        {
219            int index = getAttributeIndex( name );
220            if ( index > -1 )
221            {
222                return new AttributeInfo( index );
223            }
224            index = getExtensionIndex( name );
225            if ( index < 0 )
226            {
227                throw new IllegalArgumentException( "unknown attribute '" + name + "'. "
228                    + "Provided attributes are: " + FormatUtil.join( ", ", getAttributeNames() )
229                    + ", extended attributes are: " + FormatUtil.join( ", ", extendedAttributes.keySet() ) + "." );
230            }
231            Extension extension = extensions[index];
232            return new AttributeInfo( index, extension.getProvides().indexOf( name ) );
233        }
234
235        /**
236         * Create a new LogEvent factory for a log stream corresponding to this log description.
237         *
238         * @param reader the stream containing to parse
239         * @param logSource a textual description of the stream's source (useful when LogDistiller works on multiple
240         *            simultaneous log sources)
241         */
242        public abstract LogEvent.Factory newFactory( Reader reader, String logSource )
243            throws IOException;
244    }
245
246    public static class AttributeInfo
247    {
248        public final boolean extended;
249
250        public final int index;
251
252        public final int regexpGroup;
253
254        AttributeInfo( int index )
255        {
256            extended = false;
257            this.index = index;
258            regexpGroup = -1;
259        }
260
261        AttributeInfo( int index, int regexpGroup )
262        {
263            extended = true;
264            this.index = index;
265            this.regexpGroup = regexpGroup;
266        }
267    }
268}