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.text.ParseException;
019    import java.util.*;
020    
021    /**
022     * Combines logevents fetched from multiple factories. The resulting factory chooses the next logevent according to the
023     * order provided.
024     */
025    public class FactoryMultiplexer
026        extends LogEvent.Factory
027    {
028        private final Comparator logeventComparator;
029    
030        private final List factories = new ArrayList();
031    
032        private boolean initialized = false;
033    
034        private Comparator entryComparator;
035    
036        public FactoryMultiplexer( LogType.Description description )
037        {
038            this( description, null );
039        }
040    
041        public FactoryMultiplexer( LogType.Description description, Comparator logeventComparator )
042        {
043            super( description, "multiplexer" );
044            this.logeventComparator = logeventComparator;
045        }
046    
047        public void addFactory( LogEvent.Factory factory )
048        {
049            if ( initialized )
050            {
051                throw new IllegalStateException( "cannot add a new LogEvent.Factory after reading first event" );
052            }
053            if ( description != factory.getDescription() )
054            {
055                throw new IllegalArgumentException( "cannot add a new LogEvent.Factory with different description" );
056            }
057            factories.add( new Entry( factory ) );
058        }
059    
060        protected LogEvent readNextEvent()
061            throws IOException, ParseException
062        {
063            if ( !initialized )
064            {
065                init();
066            }
067            if ( factories.size() <= 0 )
068            {
069                return null;
070            }
071            Entry entry = (Entry) factories.get( 0 );
072            LogEvent nextEvent = entry.getEvent();
073            if ( entry.nextEvent() == null )
074            {
075                factories.remove( 0 );
076            }
077            else
078            {
079                sort();
080            }
081            return nextEvent;
082        }
083    
084        /**
085         * Initialize the multiplexer: fetch first event in each factory, remove empty factories, init entry comparator and
086         * sort the factories.
087         *
088         * @throws IOException
089         * @throws ParseException
090         */
091        private void init()
092            throws IOException, ParseException
093        {
094            initialized = true;
095            LogEvent oneEvent = null;
096            // fetch the first LogEvent
097            List emptyFactories = new ArrayList();
098            Iterator iter = factories.iterator();
099            while ( iter.hasNext() )
100            {
101                Entry entry = (Entry) iter.next();
102                LogEvent event = entry.nextEvent();
103                if ( event == null )
104                {
105                    emptyFactories.add( entry );
106                }
107                else
108                {
109                    oneEvent = event;
110                }
111            }
112            // remove empty factories
113            factories.removeAll( emptyFactories );
114            if ( factories.size() >= 0 )
115            {
116                // init entry comparator
117                if ( logeventComparator != null )
118                {
119                    entryComparator = new EntrySpecificComparator( logeventComparator );
120                }
121                else if ( oneEvent instanceof Comparable )
122                {
123                    entryComparator = new EntryNaturalComparator();
124                }
125                // sort the factories
126                sort();
127            }
128        }
129    
130        /**
131         * Sort the factories, if necessary (a logevent comparator has been provided, or logevent implements Comparable).
132         */
133        private void sort()
134        {
135            if ( entryComparator != null )
136            {
137                Collections.sort( factories, entryComparator );
138            }
139        }
140    
141        private static class Entry
142        {
143            protected LogEvent nextEvent;
144    
145            private final LogEvent.Factory factory;
146    
147            public Entry( LogEvent.Factory factory )
148            {
149                this.factory = factory;
150            }
151    
152            public LogEvent getEvent()
153            {
154                return nextEvent;
155            }
156    
157            public LogEvent nextEvent()
158                throws IOException, ParseException
159            {
160                nextEvent = factory.nextEvent();
161                return nextEvent;
162            }
163        }
164    
165        /**
166         * Comparator for entries with logevents that implement Comparable.
167         */
168        private static class EntryNaturalComparator
169            implements Comparator
170        {
171            public int compare( Object object1, Object object2 )
172            {
173                Entry entry1 = (Entry) object1;
174                Entry entry2 = (Entry) object2;
175                return ( (Comparable) entry1.getEvent() ).compareTo( entry2.getEvent() );
176            }
177        }
178    
179        /**
180         * Comparator for entries when a specific logevent Comparator is provided.
181         */
182        private static class EntrySpecificComparator
183            implements Comparator
184        {
185            private final Comparator eventComparator;
186    
187            public EntrySpecificComparator( Comparator eventComparator )
188            {
189                this.eventComparator = eventComparator;
190            }
191    
192            public int compare( Object object1, Object object2 )
193            {
194                Entry entry1 = (Entry) object1;
195                Entry entry2 = (Entry) object2;
196                return eventComparator.compare( entry1.getEvent(), entry2.getEvent() );
197            }
198        }
199    }