SourceForge.net Logo
Main Overview Wiki Issues Forum Build Fisheye
Issue Details (XML | Word | Printable)

Key: CMP-515
Type: Bug Bug
Status: Closed Closed
Resolution: Fixed
Priority: Major Major
Assignee: Shay Banon
Reporter: Michael Lossos
Votes: 0
Watchers: 0
Operations

If you were logged in you would be able to see more operations.
Compass

IllegalAccessError from ExistingSpringTxCompassHelper when using Eclipse RCP

Created: 23/Jan/08 01:43 AM   Updated: 23/Jan/08 07:19 AM
Component/s: Compass::Core
Affects Version/s: 1.2 GA, 2.0 M1
Fix Version/s: 1.2.2, 2.0 M1

Environment:
Eclipse RCP
Spring 2.0.7 bundled as its own plugin
Compass 1.2 bundled as its own plugin, though the problem also exists in 2.0M1 as of 2008-01-22


 Description  « Hide
ExistingSpringTxCompassHelper causes an IllegalAccessError when Compass is running in an Eclipse RCP application that uses Spring.

Eclipse RCP uses separate class loaders (BundleClassLoader) for each plugin. When Compass is bundled as a separate plugin from Spring (this is necessary when the main Eclipse RCP app uses Spring), Compass cannot use a protected access method as is done in ExistingSpringTxCompassHelper, because the Spring object is loaded by another class loader, and you cannot trick separate class loaders into thinking you're part of the same package as a class loaded in another, even when using the same package name..

package org.springframework.transaction.support; // ---------- This trick won't work for Eclipse RCP bundles

public class ExistingSpringTxCompassHelper {

public static boolean isExistingTransaction(PlatformTransactionManager transactionManager) {
if (transactionManager == null) { return false; }
AbstractPlatformTransactionManager absTxManager = (AbstractPlatformTransactionManager) transactionManager;
Object transaction = absTxManager.doGetTransaction(); // ----------------- This will throw an IllegalAccessError
return absTxManager.isExistingTransaction(transaction);
}
}

The workaround for now is to extend Compass's SpringSyncTransactionFactory and rewrite the isWithinExistingTransaction method. The correct fix is might be to make the doGetTransaction method public in Spring, though the Spring and Compass teams will know better than I.

Exception is:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'compass' defined in class path resource [xxxxxxxxxx.spring.xml]: Invocation of init method failed; nested exception is java.lang.IllegalAccessError: tried to access method org.springframework.transaction.support.AbstractPlatformTransactionManager.doGetTransaction()Ljava/lang/Object; from class org.springframework.transaction.support.ExistingSpringTxCompassHelper
Caused by: java.lang.IllegalAccessError: tried to access method org.springframework.transaction.support.AbstractPlatformTransactionManager.doGetTransaction()Ljava/lang/Object; from class org.springframework.transaction.support.ExistingSpringTxCompassHelper
at org.springframework.transaction.support.ExistingSpringTxCompassHelper.isExistingTransaction(ExistingSpringTxCompassHelper.java:31)
at org.compass.spring.transaction.SpringSyncTransactionFactory.isWithinExistingTransaction(SpringSyncTransactionFactory.java:64)
at org.compass.core.transaction.AbstractTransactionFactory.tryJoinExistingTransaction(AbstractTransactionFactory.java:59)
at org.compass.core.impl.DefaultCompassSession.<init>(DefaultCompassSession.java:94)
at org.compass.core.impl.DefaultCompass.openSession(DefaultCompass.java:186)
at org.compass.core.impl.DefaultCompass.openSession(DefaultCompass.java:170)
at org.compass.core.CompassTemplate.execute(CompassTemplate.java:132)
at org.compass.core.CompassTemplate.execute(CompassTemplate.java:119)
at org.compass.core.impl.DefaultCompass$TransactionalSearchEngineIndexManager.verifyIndex(DefaultCompass.java:291)
at org.compass.core.lucene.engine.manager.ScheduledLuceneSearchEngineIndexManager.verifyIndex(ScheduledLuceneSearchEngineIndexManager.java:98)
at org.compass.core.impl.DefaultCompass.<init>(DefaultCompass.java:147)
at org.compass.core.impl.DefaultCompass.<init>(DefaultCompass.java:102)
at org.compass.core.impl.DefaultCompass.<init>(DefaultCompass.java:95)
at org.compass.core.config.CompassConfiguration.buildCompass(CompassConfiguration.java:192)
at org.compass.spring.LocalCompassBean.newCompass(LocalCompassBean.java:336)
at org.compass.spring.LocalCompassBean.afterPropertiesSet(LocalCompassBean.java:326)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1198)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1167)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:427)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:249)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:155)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:246)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:160)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:285)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:352)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:122)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:76)
at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:153)
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:106)
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:76)
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:363)
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:176)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:504)
at org.eclipse.equinox.launcher.Main.basicRun(Main.java:443)
at org.eclipse.equinox.launcher.Main.run(Main.java:1169)
at org.eclipse.equinox.launcher.Main.main(Main.java:1144)



 All   Comments   Change History      Sort Order: Ascending order - Click to sort in descending order
Michael Lossos added a comment - 23/Jan/08 02:15 AM
The fix to Compass might be this simple:

// SpringSyncTransactionFactory

@Override
protected boolean isWithinExistingTransaction( InternalCompassSession session )
throws CompassException { return TransactionSynchronizationManager.isActualTransactionActive(); }

Someone more familiar with Spring internals should be able to determine if that's a suitable replacement for the ExistingSpringTxCompassHelper. It seems to work for me (with Spring managing Hibernate transactions).


Shay Banon added a comment - 23/Jan/08 06:54 AM
Yea, the new Spring method make sense. It was not available in Spring 1.2, but Spring 2.0 has been around for a long time now, and I think we can default to it.

Michael Lossos added a comment - 23/Jan/08 07:19 AM
Great, thanks!