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.text.ParseException; 019import 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 */ 025public class FactoryMultiplexer 026 extends LogEvent.Factory 027{ 028 private final Comparator<LogEvent> logeventComparator; 029 030 private final List<Entry> factories = new ArrayList<Entry>(); 031 032 private boolean initialized = false; 033 034 private Comparator<Entry> entryComparator; 035 036 public FactoryMultiplexer( LogType.Description description ) 037 { 038 this( description, null ); 039 } 040 041 public FactoryMultiplexer( LogType.Description description, Comparator<LogEvent> 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 = 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<Entry> emptyFactories = new ArrayList<Entry>(); 098 for ( Entry entry : factories ) 099 { 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}