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.net.URL; 022import java.util.Enumeration; 023import java.util.Iterator; 024import java.util.List; 025import java.util.NoSuchElementException; 026import java.util.jar.JarEntry; 027import java.util.jar.JarFile; 028import java.util.zip.ZipEntry; 029 030/** 031 * @version $Rev$ $Date$ 032 */ 033public class JarArchive implements Archive { 034 035 private final ClassLoader loader; 036 private final URL url; 037 private List<String> list; 038 private final JarFile jar; 039 040 public JarArchive(ClassLoader loader, URL url) { 041// if (!"jar".equals(url.getProtocol())) throw new IllegalArgumentException("not a jar url: " + url); 042 043 try { 044 this.loader = loader; 045 this.url = url; 046 URL u = url; 047 048 String jarPath = url.getFile(); 049 if (jarPath.contains("!")) { 050 jarPath = jarPath.substring(0, jarPath.indexOf("!")); 051 u = new URL(jarPath); 052 } 053 jar = new JarFile(FileArchive.decode(u.getFile())); // no more an url 054 } catch (IOException e) { 055 throw new IllegalStateException(e); 056 } 057 } 058 059 public URL getUrl() { 060 return url; 061 } 062 063 public InputStream getBytecode(String className) throws IOException, ClassNotFoundException { 064 int pos = className.indexOf("<"); 065 if (pos > -1) { 066 className = className.substring(0, pos); 067 } 068 pos = className.indexOf(">"); 069 if (pos > -1) { 070 className = className.substring(0, pos); 071 } 072 if (!className.endsWith(".class")) { 073 className = className.replace('.', '/') + ".class"; 074 } 075 076 ZipEntry entry = jar.getEntry(className); 077 if (entry == null) throw new ClassNotFoundException(className); 078 079 return jar.getInputStream(entry); 080 } 081 082 083 public Class<?> loadClass(String className) throws ClassNotFoundException { 084 return loader.loadClass(className); 085 } 086 087 public Iterator<Entry> iterator() { 088 return new JarIterator(); 089 } 090 091 private class JarIterator implements Iterator<Entry> { 092 093 private final Enumeration<JarEntry> stream; 094 private Entry next; 095 096 private JarIterator() { 097 stream = jar.entries(); 098 } 099 100 private boolean advance() { 101 if (next != null) { 102 return true; 103 } 104 while (stream.hasMoreElements()) { 105 final JarEntry entry = stream.nextElement(); 106 final String entryName = entry.getName(); 107 if (entry.isDirectory() || !entryName.endsWith(".class")) { 108 continue; 109 } 110 111 String className = entryName; 112 if (entryName.endsWith(".class")) { 113 className = className.substring(0, className.length() - 6); 114 } 115 if (className.contains(".")) { 116 continue; 117 } 118 119 next = new ClassEntry(entry, className.replace('/', '.')); 120 return true; 121 } 122 return false; 123 } 124 125 public boolean hasNext() { 126 return advance(); 127 } 128 129 public Entry next() { 130 if (!hasNext()) throw new NoSuchElementException(); 131 Entry entry = next; 132 next = null; 133 return entry; 134 } 135 136 public void remove() { 137 throw new UnsupportedOperationException("remove"); 138 } 139 140 private class ClassEntry implements Entry { 141 private final String name; 142 private final JarEntry entry; 143 144 private ClassEntry(JarEntry entry, String name) { 145 this.name = name; 146 this.entry = entry; 147 } 148 149 public String getName() { 150 return name; 151 } 152 153 public InputStream getBytecode() throws IOException { 154 return jar.getInputStream(entry); 155 } 156 } 157 } 158} 159