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) return true; 102 103 if (!stream.hasMoreElements()) return false; 104 105 final JarEntry entry = stream.nextElement(); 106 107 if (entry.isDirectory() || !entry.getName().endsWith(".class")) { 108 return advance(); 109 } 110 111 final String className = entry.getName().replaceFirst(".class$", ""); 112 113 if (className.contains(".")) { 114 return advance(); 115 } 116 117 next = new ClassEntry(entry, className.replace('/', '.')); 118 119 return true; 120 } 121 122 public boolean hasNext() { 123 return advance(); 124 } 125 126 public Entry next() { 127 if (!hasNext()) throw new NoSuchElementException(); 128 Entry entry = next; 129 next = null; 130 return entry; 131 } 132 133 public void remove() { 134 throw new UnsupportedOperationException("remove"); 135 } 136 137 private class ClassEntry implements Entry { 138 private final String name; 139 private final JarEntry entry; 140 141 private ClassEntry(JarEntry entry, String name) { 142 this.name = name; 143 this.entry = entry; 144 } 145 146 public String getName() { 147 return name; 148 } 149 150 public InputStream getBytecode() throws IOException { 151 return jar.getInputStream(entry); 152 } 153 } 154 } 155} 156