| 1 | |
package org.webslinger.bsf; |
| 2 | |
|
| 3 | |
import java.util.HashMap; |
| 4 | |
import java.util.Iterator; |
| 5 | |
import java.util.StringTokenizer; |
| 6 | |
import java.util.logging.Logger; |
| 7 | |
import java.util.concurrent.ConcurrentHashMap; |
| 8 | |
import java.security.AccessController; |
| 9 | |
import java.security.PrivilegedActionException; |
| 10 | |
import java.security.PrivilegedExceptionAction; |
| 11 | |
|
| 12 | |
import org.apache.bsf.BSFEngine; |
| 13 | |
import org.apache.bsf.BSFException; |
| 14 | |
import org.apache.bsf.BSFManager; |
| 15 | |
|
| 16 | |
import org.webslinger.vfs.VFSDelegate; |
| 17 | |
|
| 18 | 67 | public abstract class AbstractManager extends BSFManager { |
| 19 | 51 | protected final ConcurrentHashMap<String, String> registeredLanguages = new ConcurrentHashMap<String, String>(); |
| 20 | 51 | protected final ConcurrentHashMap<String, String> languagesByExtension = new ConcurrentHashMap<String, String>(); |
| 21 | |
protected final VFSDelegate<?, Object, ?> vfsDelegate; |
| 22 | |
protected final Logger logger; |
| 23 | 51 | protected final ConcurrentHashMap<String, LanguageEngine> loadedLanguages = new ConcurrentHashMap<String, LanguageEngine>(); |
| 24 | |
|
| 25 | |
protected AbstractManager(VFSDelegate<?, Object, ?> vfsDelegate, Logger logger) throws BSFException { |
| 26 | 51 | super(); |
| 27 | 51 | this.vfsDelegate = vfsDelegate; |
| 28 | 51 | this.logger = logger != null ? logger : Logger.getLogger(getClass().getName()); |
| 29 | 51 | registerBean("vfsDelegate", vfsDelegate); |
| 30 | 51 | } |
| 31 | |
|
| 32 | |
protected void postConstruct() throws BSFException { |
| 33 | 51 | findLanguageEngines(getClass().getClassLoader()); |
| 34 | 51 | findLanguageEngines(Thread.currentThread().getContextClassLoader()); |
| 35 | 51 | } |
| 36 | |
|
| 37 | |
public Logger getLogger() { |
| 38 | 0 | return logger; |
| 39 | |
} |
| 40 | |
|
| 41 | |
public abstract void findLanguageEngines(ClassLoader loader) throws BSFException; |
| 42 | |
|
| 43 | |
public final void registerLanguageEngine(String languageName, String className, String[] extensions) { |
| 44 | 926 | registeredLanguages.put(languageName, className); |
| 45 | 926 | if (extensions != null) { |
| 46 | 1692 | for (int i = 0; i < extensions.length; i++) { |
| 47 | 766 | String extensionLanguages = languagesByExtension.get(extensions[i]); |
| 48 | 766 | extensionLanguages = extensionLanguages == null ? languageName : extensionLanguages + ',' + extensionLanguages; |
| 49 | 766 | languagesByExtension.put(extensions[i], extensionLanguages); |
| 50 | |
} |
| 51 | |
} |
| 52 | 926 | } |
| 53 | |
|
| 54 | |
public String getLanguageFromFilename(String fileName) throws BSFException { |
| 55 | 0 | int dot = fileName.lastIndexOf("."); |
| 56 | 0 | String language = dot != -1 ? getLanguageFromExtensionInternal(fileName.substring(dot + 1)) : null; |
| 57 | 0 | if (language != null) return language; |
| 58 | 0 | throw new BSFException(BSFException.REASON_OTHER_ERROR, |
| 59 | |
"file extension missing: " |
| 60 | |
+ "unable to determine language for '" |
| 61 | |
+ fileName |
| 62 | |
+ "'"); |
| 63 | |
} |
| 64 | |
|
| 65 | |
public String getLanguageFromExtension(String extension) throws BSFException { |
| 66 | 0 | String language = getLanguageFromExtensionInternal(extension); |
| 67 | 0 | if (language != null) return language; |
| 68 | 0 | throw new BSFException(BSFException.REASON_OTHER_ERROR, |
| 69 | |
"file extension unknown: " |
| 70 | |
+ "unable to determine language for '" |
| 71 | |
+ extension |
| 72 | |
+ "'"); |
| 73 | |
} |
| 74 | |
|
| 75 | |
protected String getLanguageFromExtensionInternal(String extension) throws BSFException { |
| 76 | 0 | String langval = languagesByExtension.get(extension), lang = null; |
| 77 | 0 | if (langval == null) return null; |
| 78 | 0 | StringTokenizer st = new StringTokenizer(langval, ","); |
| 79 | 0 | while (st.hasMoreTokens()) { |
| 80 | 0 | String language = st.nextToken(); |
| 81 | |
try { |
| 82 | 0 | Class.forName(registeredLanguages.get(language)); |
| 83 | 0 | return lang; |
| 84 | 0 | } catch (ClassNotFoundException cnfe) { |
| 85 | |
} |
| 86 | 0 | } |
| 87 | 0 | return null; |
| 88 | |
} |
| 89 | |
|
| 90 | |
protected void initializeLanguageEngine(final LanguageEngine engine, final String language) throws BSFException { |
| 91 | |
try { |
| 92 | |
try { |
| 93 | 67 | AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { |
| 94 | |
public Object run() throws Exception { |
| 95 | 67 | engine.initialize(AbstractManager.this, language, declaredBeans); |
| 96 | 67 | return null; |
| 97 | |
} |
| 98 | |
}); |
| 99 | 0 | } catch (PrivilegedActionException e) { |
| 100 | 0 | throw e.getException(); |
| 101 | 67 | } |
| 102 | 0 | } catch (BSFException e) { |
| 103 | 0 | throw e; |
| 104 | 0 | } catch (RuntimeException e) { |
| 105 | 0 | throw e; |
| 106 | 0 | } catch (Error e) { |
| 107 | 0 | throw e; |
| 108 | 0 | } catch (Throwable t) { |
| 109 | 0 | throw (BSFException) new BSFException(BSFException.REASON_OTHER_ERROR, "unable to initialize engine for language: " + language).initCause(t); |
| 110 | 67 | } |
| 111 | 67 | } |
| 112 | |
|
| 113 | |
protected abstract LanguageEngine getLanguageEngineConvertor(String language, BSFEngine engine) throws BSFException; |
| 114 | |
|
| 115 | |
public LanguageEngine loadLanguageEngine(String language) throws BSFException { |
| 116 | |
try { |
| 117 | |
do { |
| 118 | 1467 | LanguageEngine engine = loadedLanguages.get(language); |
| 119 | 1469 | if (engine != null) return engine; |
| 120 | 67 | String className = registeredLanguages.get(language); |
| 121 | 67 | if (className == null) { |
| 122 | 0 | BSFEngine bsfEngine = super.loadScriptingEngine(language); |
| 123 | 0 | if (bsfEngine instanceof LanguageEngine) { |
| 124 | 0 | engine = (LanguageEngine) bsfEngine; |
| 125 | |
} else { |
| 126 | 0 | engine = getLanguageEngineConvertor(language, bsfEngine); |
| 127 | 0 | initializeLanguageEngine(engine, language); |
| 128 | 0 | pcs.addPropertyChangeListener(engine); |
| 129 | |
} |
| 130 | 0 | } else { |
| 131 | 67 | ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); |
| 132 | 67 | if (classLoader == null) classLoader = getClass().getClassLoader(); |
| 133 | 67 | synchronized (this) { |
| 134 | 67 | engine = (LanguageEngine) Class.forName(className, true, classLoader).newInstance(); |
| 135 | 67 | initializeLanguageEngine(engine, language); |
| 136 | 67 | pcs.addPropertyChangeListener(engine); |
| 137 | 67 | } |
| 138 | |
} |
| 139 | 67 | LanguageEngine oldEngine = loadedLanguages.putIfAbsent(language, engine); |
| 140 | 67 | if (oldEngine == null) return engine; |
| 141 | 0 | pcs.removePropertyChangeListener(engine); |
| 142 | 0 | return oldEngine; |
| 143 | |
} while (true); |
| 144 | 0 | } catch (BSFException e) { |
| 145 | 0 | throw e; |
| 146 | 0 | } catch (ClassNotFoundException e) { |
| 147 | 0 | throw (BSFException) new BSFException(BSFException.REASON_OTHER_ERROR, "unable to load language: " + language).initCause(e); |
| 148 | 0 | } catch (IllegalAccessException e) { |
| 149 | 0 | throw (BSFException) new BSFException(BSFException.REASON_OTHER_ERROR, "unable to load language: " + language).initCause(e); |
| 150 | 0 | } catch (InstantiationException e) { |
| 151 | 0 | throw (BSFException) new BSFException(BSFException.REASON_OTHER_ERROR, "unable to load language: " + language).initCause(e); |
| 152 | |
} |
| 153 | |
} |
| 154 | |
|
| 155 | |
public BSFEngine loadScriptingEngine(String language) throws BSFException { |
| 156 | 1469 | return loadLanguageEngine(language); |
| 157 | |
} |
| 158 | |
|
| 159 | |
public void setDebug(String language, boolean debugging) throws BSFException { |
| 160 | 0 | ((LanguageEngine) loadScriptingEngine(language)).setDebug(debugging); |
| 161 | 0 | } |
| 162 | |
|
| 163 | |
public VFSDelegate<?, Object, ?> getVFSDelegate() { |
| 164 | 3050 | return vfsDelegate; |
| 165 | |
} |
| 166 | |
|
| 167 | |
public Object apply(String lang, final String source, final int lineNo, final int columnNo, final Object funcBody, final String[] paramNames, final Object[] arguments) throws BSFException { |
| 168 | 0 | final LanguageEngine engine = (LanguageEngine) loadScriptingEngine(lang); |
| 169 | |
try { |
| 170 | 0 | return AccessController.doPrivileged( |
| 171 | 0 | new PrivilegedExceptionAction<Object>() { |
| 172 | |
public Object run() throws Exception { |
| 173 | 0 | return engine.apply(source, lineNo, columnNo, funcBody, paramNames, arguments); |
| 174 | |
} |
| 175 | |
} |
| 176 | |
); |
| 177 | 0 | } catch (PrivilegedActionException e) { |
| 178 | 0 | throw (BSFException) e.getException(); |
| 179 | |
} |
| 180 | |
} |
| 181 | |
|
| 182 | |
public Object apply(String lang, final String source, final int lineNo, final int columnNo, final Object funcBody, final String[] paramNames, final Object[] arguments, final Class[] types) throws BSFException { |
| 183 | 1467 | final LanguageEngine engine = (LanguageEngine) loadScriptingEngine(lang); |
| 184 | |
try { |
| 185 | 1467 | return AccessController.doPrivileged( |
| 186 | 1466 | new PrivilegedExceptionAction<Object>() { |
| 187 | |
public Object run() throws Exception { |
| 188 | 1472 | return engine.apply(source, lineNo, columnNo, funcBody, paramNames, arguments, types); |
| 189 | |
} |
| 190 | |
} |
| 191 | |
); |
| 192 | 0 | } catch (PrivilegedActionException e) { |
| 193 | 0 | throw (BSFException) e.getException(); |
| 194 | |
} |
| 195 | |
} |
| 196 | |
} |