View Javadoc
1   package net.sf.logdistiller;
2   
3   /*
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  import java.io.IOException;
18  import java.text.ParseException;
19  import java.util.*;
20  
21  /**
22   * Combines logevents fetched from multiple factories. The resulting factory chooses the next logevent according to the
23   * order provided.
24   */
25  public class FactoryMultiplexer
26      extends LogEvent.Factory
27  {
28      private final Comparator<LogEvent> logeventComparator;
29  
30      private final List<Entry> factories = new ArrayList<Entry>();
31  
32      private boolean initialized = false;
33  
34      private Comparator<Entry> entryComparator;
35  
36      public FactoryMultiplexer( LogType.Description description )
37      {
38          this( description, null );
39      }
40  
41      public FactoryMultiplexer( LogType.Description description, Comparator<LogEvent> logeventComparator )
42      {
43          super( description, "multiplexer" );
44          this.logeventComparator = logeventComparator;
45      }
46  
47      public void addFactory( LogEvent.Factory factory )
48      {
49          if ( initialized )
50          {
51              throw new IllegalStateException( "cannot add a new LogEvent.Factory after reading first event" );
52          }
53          if ( description != factory.getDescription() )
54          {
55              throw new IllegalArgumentException( "cannot add a new LogEvent.Factory with different description" );
56          }
57          factories.add( new Entry( factory ) );
58      }
59  
60      protected LogEvent readNextEvent()
61          throws IOException, ParseException
62      {
63          if ( !initialized )
64          {
65              init();
66          }
67          if ( factories.size() <= 0 )
68          {
69              return null;
70          }
71          Entry entry = factories.get( 0 );
72          LogEvent nextEvent = entry.getEvent();
73          if ( entry.nextEvent() == null )
74          {
75              factories.remove( 0 );
76          }
77          else
78          {
79              sort();
80          }
81          return nextEvent;
82      }
83  
84      /**
85       * Initialize the multiplexer: fetch first event in each factory, remove empty factories, init entry comparator and
86       * sort the factories.
87       *
88       * @throws IOException
89       * @throws ParseException
90       */
91      private void init()
92          throws IOException, ParseException
93      {
94          initialized = true;
95          LogEvent oneEvent = null;
96          // fetch the first LogEvent
97          List<Entry> emptyFactories = new ArrayList<Entry>();
98          for ( Entry entry : factories )
99          {
100             LogEvent event = entry.nextEvent();
101             if ( event == null )
102             {
103                 emptyFactories.add( entry );
104             }
105             else
106             {
107                 oneEvent = event;
108             }
109         }
110         // remove empty factories
111         factories.removeAll( emptyFactories );
112         if ( factories.size() >= 0 )
113         {
114             // init entry comparator
115             if ( logeventComparator != null )
116             {
117                 entryComparator = new EntrySpecificComparator( logeventComparator );
118             }
119             else if ( oneEvent instanceof Comparable<?> )
120             {
121                 entryComparator = new EntryNaturalComparator();
122             }
123             // sort the factories
124             sort();
125         }
126     }
127 
128     /**
129      * Sort the factories, if necessary (a logevent comparator has been provided, or logevent implements Comparable).
130      */
131     private void sort()
132     {
133         if ( entryComparator != null )
134         {
135             Collections.sort( factories, entryComparator );
136         }
137     }
138 
139     private static class Entry
140     {
141         protected LogEvent nextEvent;
142 
143         private final LogEvent.Factory factory;
144 
145         public Entry( LogEvent.Factory factory )
146         {
147             this.factory = factory;
148         }
149 
150         public LogEvent getEvent()
151         {
152             return nextEvent;
153         }
154 
155         public LogEvent nextEvent()
156             throws IOException, ParseException
157         {
158             nextEvent = factory.nextEvent();
159             return nextEvent;
160         }
161     }
162 
163     /**
164      * Comparator for entries with logevents that implement Comparable.
165      */
166     private static class EntryNaturalComparator
167         implements Comparator<Entry>
168     {
169         public int compare( Entry entry1, Entry entry2 )
170         {
171             return ( (Comparable) entry1.getEvent() ).compareTo( entry2.getEvent() );
172         }
173     }
174 
175     /**
176      * Comparator for entries when a specific logevent Comparator is provided.
177      */
178     private static class EntrySpecificComparator
179         implements Comparator<Entry>
180     {
181         private final Comparator<LogEvent> eventComparator;
182 
183         public EntrySpecificComparator( Comparator<LogEvent> eventComparator )
184         {
185             this.eventComparator = eventComparator;
186         }
187 
188         public int compare( Entry entry1, Entry entry2 )
189         {
190             return eventComparator.compare( entry1.getEvent(), entry2.getEvent() );
191         }
192     }
193 }