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 }