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 }