001
014
015 package com.liferay.util.resiliency.spi.provider;
016
017 import com.liferay.portal.kernel.exception.PortalException;
018 import com.liferay.portal.kernel.log.Log;
019 import com.liferay.portal.kernel.log.LogFactoryUtil;
020 import com.liferay.portal.kernel.resiliency.mpi.MPIHelperUtil;
021 import com.liferay.portal.kernel.resiliency.spi.SPIUtil;
022 import com.liferay.portal.kernel.resiliency.spi.provider.SPIProvider;
023 import com.liferay.portal.kernel.util.CharPool;
024 import com.liferay.portal.kernel.util.ClassUtil;
025 import com.liferay.portal.kernel.util.PortalClassLoaderUtil;
026 import com.liferay.portal.kernel.util.PropsKeys;
027 import com.liferay.portal.kernel.util.PropsUtil;
028 import com.liferay.portal.kernel.util.ReflectionUtil;
029 import com.liferay.portal.kernel.util.StringBundler;
030 import com.liferay.portal.kernel.util.StringPool;
031
032 import java.io.File;
033
034 import java.lang.reflect.Method;
035
036 import java.util.Arrays;
037 import java.util.LinkedHashSet;
038 import java.util.Set;
039 import java.util.concurrent.atomic.AtomicReference;
040
041 import javax.servlet.ServletContext;
042 import javax.servlet.ServletContextEvent;
043 import javax.servlet.ServletContextListener;
044
045
048 public class SPIClassPathContextListener implements ServletContextListener {
049
050 public static volatile String SPI_CLASS_PATH = StringPool.BLANK;
051
052 @Override
053 public void contextDestroyed(ServletContextEvent servletContextEvent) {
054 SPIProvider spiProvider = spiProviderReference.getAndSet(null);
055
056 if (spiProvider != null) {
057 MPIHelperUtil.unregisterSPIProvider(spiProvider);
058 }
059 }
060
061 @Override
062 public void contextInitialized(ServletContextEvent servletContextEvent) {
063 ServletContext servletContext = servletContextEvent.getServletContext();
064
065 String contextPath = servletContext.getRealPath(StringPool.BLANK);
066 String spiEmbeddedLibDirName = servletContext.getInitParameter(
067 "spiEmbeddedLibDir");
068
069 Set<File> jarFiles = new LinkedHashSet<File>();
070
071
072
073 File spiEmbeddedLibDir = new File(contextPath, spiEmbeddedLibDirName);
074
075 addJarFiles(jarFiles, spiEmbeddedLibDir);
076
077
078
079 addJarFiles(
080 jarFiles, PortalClassLoaderUtil.getClassLoader(),
081 PortalException.class.getName());
082
083
084
085 addJarFiles(
086 jarFiles, PortalClassLoaderUtil.getClassLoader(),
087 PropsUtil.get(PropsKeys.JDBC_DEFAULT_DRIVER_CLASS_NAME));
088
089
090
091 addJarFiles(jarFiles, new File(spiEmbeddedLibDir, "ext"));
092
093 StringBundler sb = new StringBundler(jarFiles.size() * 2 + 4);
094
095 for (File file : jarFiles) {
096 sb.append(file.getAbsolutePath());
097 sb.append(File.pathSeparator);
098 }
099
100 sb.append(contextPath);
101 sb.append("/WEB-INF/classes");
102
103 SPI_CLASS_PATH = sb.toString();
104
105 if (_log.isDebugEnabled()) {
106 _log.debug("SPI class path " + SPI_CLASS_PATH);
107 }
108
109 String spiProviderClassName = servletContext.getInitParameter(
110 "spiProviderClassName");
111
112 Thread currentThread = Thread.currentThread();
113
114 ClassLoader contextClassLoader = currentThread.getContextClassLoader();
115
116 try {
117 Class<SPIProvider> spiProviderClass = null;
118
119 if (SPIUtil.isSPI()) {
120 spiProviderClass = (Class<SPIProvider>)loadClassDirectly(
121 contextClassLoader, spiProviderClassName);
122 }
123 else {
124 spiProviderClass =
125 (Class<SPIProvider>)contextClassLoader.loadClass(
126 spiProviderClassName);
127 }
128
129 SPIProvider spiProvider = spiProviderClass.newInstance();
130
131 boolean result = spiProviderReference.compareAndSet(
132 null, spiProvider);
133
134 if (!result) {
135 _log.error(
136 "Duplicate SPI provider " + spiProvider +
137 " is already registered in servlet context " +
138 servletContext.getContextPath());
139 }
140 else {
141 MPIHelperUtil.registerSPIProvider(spiProvider);
142 }
143 }
144 catch (Exception e) {
145 _log.error(
146 "Unable to create SPI provider with name " +
147 spiProviderClassName,
148 e);
149 }
150 }
151
152 protected static Class<?> loadClassDirectly(
153 ClassLoader classLoader, String className)
154 throws Exception {
155
156 synchronized (classLoader) {
157 Method findLoadedClassMethod = ReflectionUtil.getDeclaredMethod(
158 ClassLoader.class, "findLoadedClass", String.class);
159
160 Class<?> clazz = (Class<?>)findLoadedClassMethod.invoke(
161 classLoader, className);
162
163 if (clazz == null) {
164 Method findClassMethod = ReflectionUtil.getDeclaredMethod(
165 ClassLoader.class, "findClass", String.class);
166
167 clazz = (Class<?>)findClassMethod.invoke(
168 classLoader, className);
169 }
170
171 Method resolveClassMethod = ReflectionUtil.getDeclaredMethod(
172 ClassLoader.class, "resolveClass", Class.class);
173
174 resolveClassMethod.invoke(classLoader, clazz);
175
176 return clazz;
177 }
178 }
179
180 protected void addJarFiles(
181 Set<File> jarFiles, ClassLoader classLoader, String className) {
182
183 String path = ClassUtil.getParentPath(classLoader, className);
184
185 int pos = path.lastIndexOf(".jar");
186
187 pos = path.lastIndexOf(CharPool.SLASH, pos);
188
189 path = path.substring(0, pos);
190
191 addJarFiles(jarFiles, new File(path));
192 }
193
194 protected void addJarFiles(Set<File> jarFiles, File dir) {
195 if (!dir.exists() || !dir.isDirectory()) {
196 throw new RuntimeException(
197 "Unable to find directory " + dir.getAbsolutePath());
198 }
199
200 File[] files = dir.listFiles();
201
202 Arrays.sort(files);
203
204 for (File file : files) {
205 String fileName = file.getName();
206
207 if (fileName.endsWith(".jar")) {
208 jarFiles.add(file);
209 }
210 }
211 }
212
213 protected static final AtomicReference<SPIProvider> spiProviderReference =
214 new AtomicReference<SPIProvider>();
215
216 private static Log _log = LogFactoryUtil.getLog(
217 SPIClassPathContextListener.class);
218
219 }