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.IOException;
018    import java.io.Reader;
019    import java.util.*;
020    
021    import net.sf.logdistiller.Attributes.Extension;
022    import 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     */
033    public 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 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 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 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();
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 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 (String) 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 ( Iterator iter = extension.getProvides().iterator(); iter.hasNext(); )
148                    {
149                        String attribute = (String)iter.next();
150                        extendedAttributes.put( attribute, new Integer( i ) );
151                    }
152                }
153            }
154    
155            /** @since 1.1 */
156            public Attributes.Extension[] getExtensions()
157            {
158                return extensions;
159            }
160    
161            /**
162             * Gets the extension index position which defines corresponding attribute.
163             *
164             * @return the extension index, or -1 if not found
165             * @since 1.1
166             */
167            public int getExtensionIndex( String attribute )
168            {
169                Integer index = (Integer) extendedAttributes.get( attribute );
170                return ( index == null ) ? -1 : index.intValue();
171            }
172    
173            /**
174             * Get the attribute that represents the timestamp.
175             *
176             * @return the attribute count, or <code>-1</code> if this logtype does not have a timestamp
177             */
178            public int getTimestampAttribute()
179            {
180                return 1;
181            }
182    
183            /**
184             * Get the group definitions specific to this log type that will be added to the generated rules configuration
185             * generated by the GUI.
186             *
187             * @return an XML fragment containing group definitions
188             */
189            public String getDefaultSpecificGroups()
190            {
191                return "";
192            }
193    
194            /**
195             * Get the attributes that can be used as a sorting key to get useful event sampling in the last "unknown" group
196             * (separated with a quote when multiple attributes). They will be used as a default sampling rule
197             * configuration.
198             *
199             * @return "attr1[,attr2[,...]]"
200             */
201            public String getDefaultSamplingAttributes()
202            {
203                return "";
204            }
205    
206            /**
207             * Find the attribute index corresponding to an attribute name (provided attributes only).
208             *
209             * @param name String the attribute name to search for
210             * @return int the index of the attribute, or -1 if not found
211             * @see #getExtensionIndex(String) to find an extension attribute index
212             */
213            public int getAttributeIndex( String name )
214            {
215                return attributeNames.indexOf( name );
216            }
217    
218            public AttributeInfo getAttributeInfo( String name )
219            {
220                int index = getAttributeIndex( name );
221                if ( index > -1 )
222                {
223                    return new AttributeInfo( index );
224                }
225                index = getExtensionIndex( name );
226                if ( index < 0 )
227                {
228                    throw new IllegalArgumentException( "unknown attribute '" + name + "'. "
229                        + "Provided attributes are: " + FormatUtil.join( ", ", getAttributeNames() )
230                        + ", extended attributes are: " + FormatUtil.join( ", ", extendedAttributes.keySet() ) + "." );
231                }
232                Extension extension = extensions[index];
233                return new AttributeInfo( index, extension.getProvides().indexOf( name ) );
234            }
235    
236            /**
237             * Create a new LogEvent factory for a log stream corresponding to this log description.
238             *
239             * @param reader the stream containing to parse
240             * @param logSource a textual description of the stream's source (useful when LogDistiller works on multiple
241             *            simultaneous log sources)
242             */
243            public abstract LogEvent.Factory newFactory( Reader reader, String logSource )
244                throws IOException;
245        }
246    
247        public static class AttributeInfo
248        {
249            public final boolean extended;
250    
251            public final int index;
252    
253            public final int regexpGroup;
254    
255            AttributeInfo( int index )
256            {
257                extended = false;
258                this.index = index;
259                regexpGroup = -1;
260            }
261    
262            AttributeInfo( int index, int regexpGroup )
263            {
264                extended = true;
265                this.index = index;
266                this.regexpGroup = regexpGroup;
267            }
268        }
269    }