001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.xbean.finder.archive; 018 019import java.io.IOException; 020import java.io.InputStream; 021import java.util.ArrayList; 022import java.util.Arrays; 023import java.util.Iterator; 024import java.util.List; 025import java.util.NoSuchElementException; 026 027/** 028 * @version $Rev$ $Date$ 029 */ 030public class CompositeArchive implements Archive, AutoCloseable { 031 032 private final List<Archive> archives = new ArrayList<Archive>(); 033 034 public CompositeArchive(Archive... archives) { 035 this(Arrays.asList(archives)); 036 } 037 038 public CompositeArchive(Iterable<Archive> archives) { 039 for (Archive archive : archives) { 040 this.archives.add(archive); 041 } 042 } 043 044 public InputStream getBytecode(String className) throws IOException, ClassNotFoundException { 045 for (Archive archive : archives) { 046 try { 047 return archive.getBytecode(className); 048 } catch (ClassNotFoundException e) { 049 } 050 } 051 052 throw new ClassNotFoundException(className); 053 } 054 055 public Class<?> loadClass(String className) throws ClassNotFoundException { 056 for (Archive archive : archives) { 057 try { 058 return archive.loadClass(className); 059 } catch (ClassNotFoundException e) { 060 } 061 } 062 063 throw new ClassNotFoundException(className); 064 } 065 066 public Iterator<Entry> iterator() { 067 if (archives.size() == 1) return archives.get(0).iterator(); 068 return new CompositeIterator(archives); 069 } 070 071 @Override 072 public void close() throws Exception { 073 archives.stream() 074 .filter(AutoCloseable.class::isInstance) 075 .map(AutoCloseable.class::cast) 076 .forEach(it -> { 077 try { 078 it.close(); 079 } catch (final Exception e) { 080 // no-op 081 } 082 }); 083 } 084 085 private static class CompositeIterator implements Iterator<Entry> { 086 087 private Iterator<Archive> archives; 088 private Iterator<Entry> current; 089 090 private CompositeIterator(Iterable<Archive> archives) { 091 this.archives = archives.iterator(); 092 if (this.archives.hasNext()) { 093 current = this.archives.next().iterator(); 094 } 095 } 096 097 public boolean hasNext() { 098 if (current == null) return false; 099 if (current.hasNext()) return true; 100 101 if (archives.hasNext()) { 102 current = archives.next().iterator(); 103 return hasNext(); 104 } 105 return false; 106 } 107 108 public Entry next() { 109 if (!hasNext()) throw new NoSuchElementException(); 110 111 return current.next(); 112 } 113 114 public void remove() { 115 throw new UnsupportedOperationException(); 116 } 117 } 118}