Well, I guess I really am starting to learn a bit more about Tomcat. It is possible to remove the singleton loader and put it back in the application code. I was just trying to do something slick with a single loader. But your answer and the previous one have shown me the error of my way. now I see the light! :-)
David Delbecq <[EMAIL PROTECTED]> wrote: THAT is really *not* recommended. Short answer, you go the wrong way in your design. And adding your web-inf/classes to your common classloader will completly break the tomcat behaviour (presence of same classes at 2 levels, some instances are done at one level, some other at another level, and you will have codes like 'instanceof' fail even if class names & packages are same, because 2 sides of check use a different classloader) Long answer, from tomcat docs, about classloader: Bootstrap | System | Common / \ Catalina Shared / \ Webapp1 Webapp2 (Other servlet engine have probably similar structure, separing server level from webapp level and isolating webapps) Webapp2 classloader can load class from webapp2, Shared, Common, System, Bootstrap. This does not go 2 ways, it's a one way road. What you are trying to do is, from Common classloader to load a class inside Webapp2 classloader. Question, how do you expect you singleton loader in common to be able to know which webapp to use and locate it's classloader? 1) Mixing common and webapp level is really *not* a recommended design, i suggest you put your singleton loader inside your webapp's WEB-INF/classes folder. 2) If it's not possible, your singleton classes themselves should be also within common/lib so your singleton loader can see them. 3) If (and only if) what you want to do is actually a factory that reside in common/lib and create instances of object in WEB-INF/lib, and, more over, if and only if, you do this in a Thread that process a client request, you can use Thread.currentThread().getContextClassLoader() because early in the client Http request tomcat set it to classloader of webapp that will process request. One important thing to know in this later scenario is that your singletonloader must *not* keep references to those created instances (that why i spoke about factory not singleton). This is because keeping at common level a reference to an object loaded at webapp level will prevent this webapp's classloader to be garbage collected at redeployed and with it all static instances, which end quickly to visible memory leaks (out of permgen) You scenario, looking at your code, seems to me could be (2), considering you load singletons during context listener event, and that you use server wide constant to tell what to load. It's not webapp specific and as such should not concern webapps. Last but not least, it seems your aimed architecture it to load a set of 'called at initialization' classes in each webapp you deploy. This is strange, as deciding we need a specific service at webapp startup, loaded from classes in webapp, is generally a webapp specific job. It should be done at webapp level, probably using a ServletContextListener configured in web.xml. (http://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/servlet/ServletContextListener.html) Mike Peremsky a écrit : > The class that is trying to load the singleton (SingletonLoader) is in a > common JAR located at /common/lib/mvpservlet.jar > > The Singletons that I am trying to load can be from ANY app and are in the > WEB-INF/classes folder of whichever application is trying to use the > SingletonLoader. > > > Filip Hanik - Dev Lists wrote: > that work around is probably not what you want. You've just disabled the > ability to reload your app correctly. > Try using another classloader, maybe the > Thread.currentThread().getContextClassLoader() > > where are you storing the class that is trying to load the singleton? it > should be in your webapp as well. > > Filip > > Mike Peremsky wrote: > >> I have resolved this issue, but am wondering if the way I did it is the >> "correct" way to resolve this issue. >> >> I modified the catalina.properties file entry common.loader by adding the >> path to the applications WEB-INF/classes directory, this seems to have >> resolved the issue with finding the class. >> >> >> common.loader=${catalina.home}/common/classes,,${catalina.home}/webapps/myExternalApp/WEB-INF/classes >> >> >> >> I also had to fix a bug in the retrieval of the method (I read the API docs >> incorrectly) >> >> private static final Object OBJECT_ARG_LIST[] = new Object[0]; >> private static final Class CLASS_ARG_LIST[] = new Class[0]; >> >> Method method = singletonClassObj.getMethod(GET_INSTANCE_METHOD, >> CLASS_ARG_LIST); >> method.invoke(null, OBJECT_ARG_LIST); >> >> >> >> Mike Peremsky wrote: >> I tried the modification you suggested (with the correct method name on the >> end) but still with the same results. I also printed out a debug message >> just to see what class loader was being used (not that I know what to do >> with it :-P ) >> >> log.debug("this class loader: " + >> this.getClass().getClassLoader().getClass().getName()); >> Class singletongClassObj = >> this.getClass().getClassLoader().loadClass(singletonClassName); >> >> The class loader for the SingletonLoader is: >> org.apache.catalina.loader.StandardClassLoader. >> >> The classes that it is looking for are located in the >> >> /apache-tomcat-5.5.23/webapps/myExternalApp/WEB-INF/classes directory. >> >> >> >> >> Filip Hanik - Dev Lists wrote: >> did you try >> >> Class singletongClassObj = >> this.getClass().getClassLoader().loadName(singletonClassName); >> >> Filip >> >> >> Mike Peremsky wrote: >> >> >>> I think this may be a class loader issue, but am not sure as I have never >>> really worked with them before. I am putting together a JAR file that >>> contains a set of classes to be used throughout a suite of applications. I >>> have a class called SingletonLoader that was working when it was within the >>> main application, but when I broke out the reusable classes into a separate >>> jar file and modified the contextInitialized() method to dynamically load >>> the classes it is failing to fid the classes. The contextInitialized() >>> method is properly reading the class names from the property file (e.g. >>> SINGLETON_LOADER_CLASSES=com.externalApp.singleton.Countries,com.externalApp.singleton.SecurityQuestions) >>> and looping through them, but I always get the following error message >>> when the line >>> >>> Class singletongClassObj = Class.forName(singletonClassName); >>> >>> is executed: >>> >>> Unable to load singleton: com.externalApp.singleton.Countries >>> java.lang.ClassNotFoundException: com.externalApp.singleton.Countries >>> >>> ALL of the singleton classes to be loaded implement the Singleton interface >>> (which has nothing in it, it is just used to denote a class that MUST >>> specify a "public static anyReturnVal getInstance()" method. >>> >>> public class SingletonLoader implements ServletContextListener, >>> SystemConsts { >>> /** >>> * Logger for this class >>> */ >>> private static final Logger log = Logger.getLogger(SingletonLoader.class); >>> private static final String SINGLETON_LOADER_CLASSES >>> = "SINGLETON_LOADER_CLASSES"; >>> private static final String DELIMITER = ","; >>> // This is the method defined >>> private static final String GET_INSTANCE_METHOD = "getInstance"; >>> private static final Object ARG_LIST[] = new Object[0]; >>> >>> /** >>> * Constructs a new SingletonLoader object. >>> */ >>> public SingletonLoader() { >>> } >>> >>> /** >>> * Notification that the web application is ready to process requests. >>> * >>> * Initializes all of the singletons so they are ready for immediate use >>> * after the containet server starts. >>> * >>> * @param sce This is the event object for notifications about changes to the >>> * servlet context of a web application. >>> * >>> */ >>> public void contextInitialized(ServletContextEvent sce) { >>> >>> log.debug("contextInitialized: BEGIN"); >>> String singletons = ExtProperties.getProperty(SYS_PROPS, >>> SINGLETON_LOADER_CLASSES); >>> >>> if (!StringUtils.isNullOrZeroLen(singletons)) { >>> DelimitedString ds = new DelimitedString(singletons, DELIMITER); >>> int max = ds.size(); >>> String singletonClassName = null; >>> >>> for (int ndx=0; ndx < max; ndx++) { >>> try { >>> singletonClassName = ds.getEntry(ndx); >>> log.debug("Get singletonClassName: " + singletonClassName); >>> // Get the singleton class to load >>> Class singletongClassObj = Class.forName(singletonClassName); >>> log.debug("singletongClassObj: " + singletongClassObj); >>> Method method = singletongClassObj.getMethod(GET_INSTANCE_METHOD, >>> singletongClassObj); >>> method.invoke(null, ARG_LIST); >>> >>> } catch (Exception e) { >>> log.error("Unable to load singleton: " + singletonClassName, e); >>> } >>> } >>> } >>> log.debug("contextInitialized: END"); >>> } >>> >>> /** >>> * Notification that the servlet context is about to be shut down. >>> * >>> * @param sce the ServletContextEvent >>> */ >>> public void contextDestroyed(ServletContextEvent sce) { >>> } >>> } >>> >>> Example of the Countries singleton >>> >>> >>> public class Countries implements DbConsts, Singleton { >>> private static Logger log = Logger.getLogger(Countries.class); >>> >>> >>> >>> /** Creates a new instance of Countries */ >>> private Countries() { >>> refreshData(); >>> } >>> >>> /** >>> * Returns the single instance of this class. >>> * >>> * @return the instance of this class. >>> */ >>> public static Countries getInstance() { >>> if (instance == null) { >>> synchronized (Countries.class) { >>> if (instance == null) { >>> instance = new Countries(); >>> } >>> } >>> } >>> return instance; >>> } >>> >>> >>> } >>> >>> >>> --------------------------------- >>> Be a better Globetrotter. Get better travel answers from someone who knows. >>> Yahoo! Answers - Check it out. >>> >>> ------------------------------------------------------------------------ >>> >>> No virus found in this incoming message. >>> Checked by AVG Free Edition. >>> Version: 7.5.467 / Virus Database: 269.7.1/805 - Release Date: 5/15/2007 >>> 10:47 AM >>> >>> >>> >> --------------------------------------------------------------------- >> To start a new topic, e-mail: users@tomcat.apache.org >> To unsubscribe, e-mail: [EMAIL PROTECTED] >> For additional commands, e-mail: [EMAIL PROTECTED] >> >> >> >> >> >> --------------------------------- >> Luggage? GPS? Comic books? >> Check out fitting gifts for grads at Yahoo! Search. >> >> >> --------------------------------- >> Give spam the boot. Take control with tough spam protection >> in the all-new Yahoo! Mail Beta. >> >> ------------------------------------------------------------------------ >> >> No virus found in this incoming message. >> Checked by AVG Free Edition. >> Version: 7.5.467 / Virus Database: 269.7.6/814 - Release Date: 5/21/2007 >> 2:01 PM >> >> > > > --------------------------------------------------------------------- > To start a new topic, e-mail: users@tomcat.apache.org > To unsubscribe, e-mail: [EMAIL PROTECTED] > For additional commands, e-mail: [EMAIL PROTECTED] > > > > > --------------------------------- > Take the Internet to Go: Yahoo!Go puts the Internet in your pocket: mail, > news, photos & more. > --------------------------------------------------------------------- To start a new topic, e-mail: users@tomcat.apache.org To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] --------------------------------- No need to miss a message. Get email on-the-go with Yahoo! Mail for Mobile. Get started.