001 /* 002 * Copyright (C) 2006-2007 the original author or authors. 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 package org.codehaus.gmaven.runtime.loader.realm; 018 019 import org.codehaus.gmaven.feature.Provider; 020 import org.codehaus.plexus.classworlds.ClassWorld; 021 import org.codehaus.plexus.classworlds.ClassWorldException; 022 import org.codehaus.plexus.classworlds.realm.ClassRealm; 023 import org.codehaus.plexus.classworlds.realm.NoSuchRealmException; 024 import org.codehaus.plexus.classworlds.strategy.ParentFirstStrategy; 025 import org.codehaus.plexus.classworlds.strategy.Strategy; 026 import org.slf4j.Logger; 027 import org.slf4j.LoggerFactory; 028 029 import java.io.ByteArrayOutputStream; 030 import java.io.PrintStream; 031 import java.lang.reflect.Field; 032 import java.net.URL; 033 import java.util.HashMap; 034 import java.util.Map; 035 036 /** 037 * The default {@link RealmManager} component. 038 * 039 * @plexus.component role="org.codehaus.gmaven.runtime.loader.realm.RealmManager" 040 * 041 * @version $Id: DefaultRealmManager.java 83 2009-12-11 11:01:28Z user57 $ 042 * @author <a href="mailto:jason@planet57.com">Jason Dillon</a> 043 */ 044 public class DefaultRealmManager 045 implements RealmManager 046 { 047 private final Logger log = LoggerFactory.getLogger(getClass()); 048 049 private ClassWorld classWorld = new ClassWorld(); 050 051 private Map providerRealms = new HashMap(); 052 053 public ClassRealm createProviderRealm(final String key, final URL[] classPath, final ClassLoader parent) throws ClassWorldException { 054 assert key != null; 055 assert classPath != null; 056 assert parent != null; 057 058 String id = Provider.class.getName() + "[" + key + "]"; 059 060 log.debug("Creating provider realm: {}", id); 061 062 ClassRealm realm = classWorld.newRealm(id, parent); 063 setupRealm(realm, classPath); 064 065 providerRealms.put(key, realm); 066 067 return realm; 068 } 069 070 private int uniqueCounter = 0; 071 072 private synchronized String uniqueId() { 073 return System.currentTimeMillis() + ":" + (uniqueCounter++); 074 } 075 076 public ClassRealm createComponentRealm(final Provider provider, final URL[] classPath) throws ClassWorldException { 077 assert provider != null; 078 assert classPath != null; 079 080 String id = provider.getClass().getName() + "#component[" + uniqueId() + "]"; 081 082 log.debug("Creating component realm: {}", id); 083 084 ClassRealm providerRealm = (ClassRealm)providerRealms.get(provider.key()); 085 086 if (providerRealm == null) { 087 throw new Error("No realm for provider: " + provider); 088 } 089 090 log.debug(" Provider realm: {}", providerRealm.getId()); 091 092 ClassRealm realm = providerRealm.createChildRealm(id); 093 setupRealm(realm, classPath); 094 095 return realm; 096 } 097 098 public void releaseComponentRealm(final ClassRealm realm) throws NoSuchRealmException { 099 assert realm != null; 100 101 log.debug("Releasing component realm: {}", realm.getId()); 102 103 classWorld.disposeRealm(realm.getId()); 104 } 105 106 private void setupRealm(final ClassRealm realm, final URL[] classPath) { 107 assert realm != null; 108 assert classPath != null; 109 110 // HACK: Force the realm to use parent-first, instead of the default self-first 111 setStrategy(realm, new ParentFirstStrategy(realm)); 112 113 for (int i=0; i<classPath.length; i++) { 114 realm.addURL(classPath[i]); 115 116 log.debug(" {}", classPath[i]); 117 } 118 119 if (log.isTraceEnabled()) { 120 ByteArrayOutputStream buff = new ByteArrayOutputStream(); 121 realm.display(new PrintStream(buff, true)); 122 log.trace("Realm configuration:\n" + new String(buff.toByteArray())); 123 } 124 } 125 126 /** 127 * There is no public API to set/change a realms strategy, so we use some reflection muck to set the private field. 128 */ 129 private void setStrategy(final ClassRealm realm, final Strategy strategy) { 130 assert realm != null; 131 assert strategy != null; 132 133 try { 134 Field field = realm.getClass().getDeclaredField("strategy"); 135 136 try { 137 field.set(realm, strategy); 138 } 139 catch (IllegalAccessException ignore) { 140 // try again 141 field.setAccessible(true); 142 143 try { 144 field.set(realm, strategy); 145 } 146 catch (IllegalAccessException e) { 147 throw new IllegalAccessError(e.getMessage()); 148 } 149 } 150 } 151 catch (NoSuchFieldException e) { 152 throw new Error(e); 153 } 154 } 155 }