001/* 002 * (C) Copyright 2006-2008 Nuxeo SA (http://nuxeo.com/) and others. 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 * Contributors: 017 * bstefanescu 018 * 019 * $Id$ 020 */ 021 022package org.nuxeo.runtime.tomcat.dev; 023 024import java.io.IOException; 025import java.io.InputStream; 026import java.net.URL; 027import java.util.ArrayList; 028import java.util.Enumeration; 029import java.util.List; 030import java.util.NoSuchElementException; 031import java.util.ResourceBundle; 032 033import org.nuxeo.osgi.application.DevMutableClassLoader; 034import org.nuxeo.runtime.tomcat.NuxeoWebappClassLoader; 035 036/** 037 * @author <a href="mailto:[email protected]">Bogdan Stefanescu</a> 038 */ 039 040public class NuxeoDevWebappClassLoader extends NuxeoWebappClassLoader implements DevMutableClassLoader, 041 WebResourcesCacheFlusher { 042 043 /** 044 * @since 9.3 045 */ 046 @Override 047 public void clearPreviousClassLoader() { 048 clear(); 049 } 050 051 /** 052 * @since 9.3 053 */ 054 @Override 055 public void addClassLoader(URL... urls) { 056 createLocalClassLoader(urls); 057 } 058 059 public LocalClassLoader createLocalClassLoader(URL... urls) { 060 LocalClassLoader cl = new LocalURLClassLoader(urls, this); 061 addChildren(cl); 062 return cl; 063 } 064 065 protected DevFrameworkBootstrap bootstrap; 066 067 protected List<LocalClassLoader> children; 068 069 protected volatile LocalClassLoader[] _children; 070 071 public NuxeoDevWebappClassLoader() { 072 super(); 073 this.children = new ArrayList<LocalClassLoader>(); 074 } 075 076 public NuxeoDevWebappClassLoader(ClassLoader parent) { 077 super(parent); 078 this.children = new ArrayList<LocalClassLoader>(); 079 } 080 081 public void setBootstrap(DevFrameworkBootstrap bootstrap) { 082 this.bootstrap = bootstrap; 083 } 084 085 public DevFrameworkBootstrap getBootstrap() { 086 return bootstrap; 087 } 088 089 public synchronized void addChildren(LocalClassLoader loader) { 090 children.add(loader); 091 _children = null; 092 } 093 094 public synchronized void clear() { 095 children.clear(); 096 _children = null; 097 } 098 099 public synchronized void flushWebResources() { 100 resourceEntries.clear(); 101 ResourceBundle.clearCache(this); 102 } 103 104 public LocalClassLoader[] getChildren() { 105 LocalClassLoader[] cls = _children; 106 if (cls == null) { 107 synchronized (this) { 108 _children = children.toArray(new LocalClassLoader[children.size()]); 109 cls = _children; 110 } 111 } 112 return cls; 113 } 114 115 /** 116 * Do not synchronize this method at method level to avoid deadlocks. 117 */ 118 @Override 119 public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { 120 try { 121 synchronized (this) { 122 return super.loadClass(name, resolve); 123 } 124 } catch (ClassNotFoundException e) { 125 for (LocalClassLoader cl : getChildren()) { 126 try { 127 return cl.loadLocalClass(name, resolve); 128 } catch (ClassNotFoundException ee) { 129 // do nothing 130 } 131 } 132 } 133 throw new ClassNotFoundException(name); 134 } 135 136 @Override 137 public URL getResource(String name) { 138 URL url = super.getResource(name); 139 if (url != null) { 140 return url; 141 } 142 for (LocalClassLoader cl : getChildren()) { 143 url = cl.getLocalResource(name); 144 if (url != null) { 145 return url; 146 } 147 } 148 return null; 149 } 150 151 @Override 152 public InputStream getResourceAsStream(String name) { 153 InputStream is = super.getResourceAsStream(name); 154 if (is != null) { 155 return is; 156 } 157 for (LocalClassLoader cl : getChildren()) { 158 try { 159 is = cl.getLocalResourceAsStream(name); 160 } catch (IOException e) { 161 throw new RuntimeException("Cannot read input from " + name, e); 162 } 163 if (is != null) { 164 return is; 165 } 166 } 167 return null; 168 } 169 170 @Override 171 public Enumeration<URL> getResources(String name) throws IOException { 172 CompoundEnumeration<URL> enums = new CompoundEnumeration<URL>(); 173 enums.add(super.getResources(name)); 174 for (LocalClassLoader cl : getChildren()) { 175 enums.add(cl.getLocalResources(name)); 176 } 177 return enums; 178 } 179 180 @Override 181 public void addURL(URL url) { 182 super.addURL(url); 183 } 184 185 public ClassLoader getParentClassLoader() { 186 return parent; 187 } 188 189 @Override 190 public ClassLoader getClassLoader() { 191 return this; 192 } 193 194 protected static class CompoundEnumeration<E> implements Enumeration<E> { 195 196 private final List<Enumeration<E>> enums = new ArrayList<Enumeration<E>>(); 197 198 private int index = 0; 199 200 public CompoundEnumeration() { 201 // nothing to do 202 } 203 204 public CompoundEnumeration(List<Enumeration<E>> enums) { 205 this.enums.addAll(enums); 206 } 207 208 private boolean next() { 209 while (index < enums.size()) { 210 if (enums.get(index) != null && enums.get(index).hasMoreElements()) { 211 return true; 212 } 213 index++; 214 } 215 return false; 216 } 217 218 @Override 219 public boolean hasMoreElements() { 220 return next(); 221 } 222 223 @Override 224 public E nextElement() { 225 if (!next()) { 226 throw new NoSuchElementException(); 227 } 228 return enums.get(index).nextElement(); 229 } 230 231 public void add(Enumeration<E> e) { 232 if (!e.hasMoreElements()) { 233 return; 234 } 235 enums.add(e); 236 } 237 } 238 239}