Wicket
  1. Wicket
  2. WICKET-4385

Mounting pages using application instance is broken

    Details

    • Type: Bug Bug
    • Status: Resolved
    • Priority: Major Major
    • Resolution: Won't Fix
    • Affects Version/s: 1.5.4
    • Fix Version/s: None
    • Component/s: None
    • Labels:

      Description

      We mount some pages dynamically, using different thread than wicket filter. Our extension tracks service registry and once it finds something it calls application instance to mount new page. To don't use ThreadLocals we keep application assigned to private field. It worked well with Wicket 1.4.x.

      public final class PageMounterTracker extends ServiceTracker {
      
          private final WebApplication application;
      
          @Override
          public final Object addingService(ServiceReference reference) {
              PageMounter mounter = (PageMounter) super.addingService(reference);
      
              List<MountPointInfo> infos = mounter.getMountPoints();
              for (MountPointInfo info : infos) {
                  application.unmount(info.getPath());
                  application.mountPage(info.getPath(), info.getPage());
              }
              return mounter;
          }
      
          @Override
          public final void removedService(ServiceReference reference, Object mounter) {
              PageMounter pageMounter = (PageMounter) mounter;
              List<MountPointInfo> infos = pageMounter.getMountPoints();
              for (MountPointInfo info : infos) {
                  application.unmount(info.getPath());
              }
      
              super.removedService(reference, pageMounter);
          }
      }
      
      ERROR: Bundle org.ops4j.pax.wicket.service [72] EventDispatcher: Error during dispatch. (org.apache.wicket.WicketRuntimeException: There is no application attached to current thread Karaf Shell Console Thread)
      org.apache.wicket.WicketRuntimeException: There is no application attached to current thread Karaf Shell Console Thread
      	at org.apache.wicket.Application.get(Application.java:230)
      	at org.apache.wicket.request.mapper.AbstractComponentMapper.getContext(AbstractComponentMapper.java:46)
      	at org.apache.wicket.request.mapper.PageInstanceMapper.matches(PageInstanceMapper.java:163)
      	at org.apache.wicket.request.mapper.PageInstanceMapper.mapRequest(PageInstanceMapper.java:62)
      	at org.apache.wicket.request.mapper.CompoundRequestMapper.unmount(CompoundRequestMapper.java:194)
      	at org.apache.wicket.protocol.http.WebApplication.unmount(WebApplication.java:377)
      	at org.ops4j.pax.wicket.internal.PageMounterTracker.removedService(PageMounterTracker.java:91)
      	at org.osgi.util.tracker.ServiceTracker$Tracked.customizerRemoved(ServiceTracker.java:922)
      	at org.osgi.util.tracker.AbstractTracked.untrack(AbstractTracked.java:351)
      	at org.osgi.util.tracker.ServiceTracker$Tracked.serviceChanged(ServiceTracker.java:865)
      	at org.apache.felix.framework.util.EventDispatcher.invokeServiceListenerCallback(EventDispatcher.java:871)
      	at org.apache.felix.framework.util.EventDispatcher.fireEventImmediately(EventDispatcher.java:733)
      	at org.apache.felix.framework.util.EventDispatcher.fireServiceEvent(EventDispatcher.java:662)
      	at org.apache.felix.framework.Felix.fireServiceEvent(Felix.java:3772)
      	at org.apache.felix.framework.Felix.access$000(Felix.java:80)
      	at org.apache.felix.framework.Felix$2.serviceChanged(Felix.java:729)
      	at org.apache.felix.framework.ServiceRegistry.unregisterService(ServiceRegistry.java:135)
      	at org.apache.felix.framework.ServiceRegistrationImpl.unregister(ServiceRegistrationImpl.java:129)
      	at org.ops4j.pax.wicket.util.DefaultPageMounter.dispose(DefaultPageMounter.java:84)
      	at org.ops4j.pax.wicket.internal.BundleDelegatingPageMounter.stop(BundleDelegatingPageMounter.java:68)
      	at org.ops4j.pax.wicket.internal.extender.BundleDelegatingExtensionTracker.removeServicesForServiceReference(BundleDelegatingExtensionTracker.java:107)
      	at org.ops4j.pax.wicket.internal.extender.BundleDelegatingExtensionTracker.removedService(BundleDelegatingExtensionTracker.java:86)
      	at org.osgi.util.tracker.ServiceTracker$Tracked.customizerRemoved(ServiceTracker.java:922)
      	at org.osgi.util.tracker.AbstractTracked.untrack(AbstractTracked.java:351)
      	at org.osgi.util.tracker.ServiceTracker$Tracked.serviceChanged(ServiceTracker.java:865)
      	at org.apache.felix.framework.util.EventDispatcher.invokeServiceListenerCallback(EventDispatcher.java:871)
      	at org.apache.felix.framework.util.EventDispatcher.fireEventImmediately(EventDispatcher.java:733)
      	at org.apache.felix.framework.util.EventDispatcher.fireServiceEvent(EventDispatcher.java:662)
      	at org.apache.felix.framework.Felix.fireServiceEvent(Felix.java:3772)
      	at org.apache.felix.framework.Felix.access$000(Felix.java:80)
      	at org.apache.felix.framework.Felix$2.serviceChanged(Felix.java:729)
      	at org.apache.felix.framework.ServiceRegistry.unregisterService(ServiceRegistry.java:135)
      	at org.apache.felix.framework.ServiceRegistrationImpl.unregister(ServiceRegistrationImpl.java:129)
      	at org.ops4j.pax.wicket.util.DefaultWebApplicationFactory.dispose(DefaultWebApplicationFactory.java:79)
      	at org.ops4j.pax.wicket.internal.injection.ApplicationDecorator.stop(ApplicationDecorator.java:76)
      	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.apache.aries.blueprint.utils.ReflectionUtils.invoke(ReflectionUtils.java:226)
      	at org.apache.aries.blueprint.container.BeanRecipe.invoke(BeanRecipe.java:824)
      	at org.apache.aries.blueprint.container.BeanRecipe.destroy(BeanRecipe.java:741)
      	at org.apache.aries.blueprint.container.BlueprintRepository.destroy(BlueprintRepository.java:295)
      	at org.apache.aries.blueprint.container.BlueprintContainerImpl.destroyComponents(BlueprintContainerImpl.java:681)
      	at org.apache.aries.blueprint.container.BlueprintContainerImpl.namespaceHandlerUnregistered(BlueprintContainerImpl.java:868)
      	at org.apache.aries.blueprint.namespace.NamespaceHandlerRegistryImpl$NamespaceHandlerSetImpl.unregisterHandler(NamespaceHandlerRegistryImpl.java:365)
      	at org.apache.aries.blueprint.namespace.NamespaceHandlerRegistryImpl.unregisterHandler(NamespaceHandlerRegistryImpl.java:149)
      	at org.apache.aries.blueprint.namespace.NamespaceHandlerRegistryImpl.removedService(NamespaceHandlerRegistryImpl.java:119)
      	at org.osgi.util.tracker.ServiceTracker$Tracked.customizerRemoved(ServiceTracker.java:922)
      	at org.osgi.util.tracker.AbstractTracked.untrack(AbstractTracked.java:351)
      	at org.osgi.util.tracker.ServiceTracker$Tracked.serviceChanged(ServiceTracker.java:865)
      	at org.apache.felix.framework.util.EventDispatcher.invokeServiceListenerCallback(EventDispatcher.java:871)
      	at org.apache.felix.framework.util.EventDispatcher.fireEventImmediately(EventDispatcher.java:733)
      	at org.apache.felix.framework.util.EventDispatcher.fireServiceEvent(EventDispatcher.java:662)
      	at org.apache.felix.framework.Felix.fireServiceEvent(Felix.java:3772)
      	at org.apache.felix.framework.Felix.access$000(Felix.java:80)
      	at org.apache.felix.framework.Felix$2.serviceChanged(Felix.java:729)
      	at org.apache.felix.framework.ServiceRegistry.unregisterService(ServiceRegistry.java:135)
      	at org.apache.felix.framework.ServiceRegistrationImpl.unregister(ServiceRegistrationImpl.java:129)
      	at org.apache.aries.blueprint.container.ServiceRecipe.unregister(ServiceRecipe.java:201)
      	at org.apache.aries.blueprint.container.BlueprintContainerImpl.unregisterServices(BlueprintContainerImpl.java:673)
      	at org.apache.aries.blueprint.container.BlueprintContainerImpl.destroy(BlueprintContainerImpl.java:822)
      	at org.apache.aries.blueprint.container.BlueprintExtender.destroyContext(BlueprintExtender.java:250)
      	at org.apache.aries.blueprint.container.BlueprintExtender.bundleChanged(BlueprintExtender.java:242)
      	at org.apache.aries.blueprint.container.BlueprintExtender$BlueprintBundleTrackerCustomizer.modifiedBundle(BlueprintExtender.java:431)
      	at org.osgi.util.tracker.BundleTracker$Tracked.customizerModified(BundleTracker.java:453)
      	at org.osgi.util.tracker.AbstractTracked.track(AbstractTracked.java:237)
      	at org.osgi.util.tracker.BundleTracker$Tracked.bundleChanged(BundleTracker.java:413)
      	at org.apache.felix.framework.util.EventDispatcher.invokeBundleListenerCallback(EventDispatcher.java:807)
      	at org.apache.felix.framework.util.EventDispatcher.fireEventImmediately(EventDispatcher.java:729)
      	at org.apache.felix.framework.util.EventDispatcher.fireBundleEvent(EventDispatcher.java:610)
      	at org.apache.felix.framework.Felix.fireBundleEvent(Felix.java:3761)
      	at org.apache.felix.framework.Felix.stopBundle(Felix.java:2206)
      	at org.apache.felix.framework.Felix.updateBundle(Felix.java:1955)
      	at org.apache.felix.framework.BundleImpl.update(BundleImpl.java:936)
      	at org.apache.felix.framework.BundleImpl.update(BundleImpl.java:923)
      	at org.apache.karaf.shell.osgi.UpdateBundle.doExecute(UpdateBundle.java:37)
      	at org.apache.karaf.shell.osgi.BundleCommand.doExecute(BundleCommand.java:42)
      	at org.apache.karaf.shell.console.OsgiCommandSupport.execute(OsgiCommandSupport.java:38)
      	at org.apache.felix.gogo.commands.basic.AbstractCommand.execute(AbstractCommand.java:35)
      	at org.apache.felix.gogo.runtime.CommandProxy.execute(CommandProxy.java:78)
      	at org.apache.felix.gogo.runtime.Closure.executeCmd(Closure.java:474)
      	at org.apache.felix.gogo.runtime.Closure.executeStatement(Closure.java:400)
      	at org.apache.felix.gogo.runtime.Pipe.run(Pipe.java:108)
      	at org.apache.felix.gogo.runtime.Closure.execute(Closure.java:183)
      	at org.apache.felix.gogo.runtime.Closure.execute(Closure.java:120)
      	at org.apache.felix.gogo.runtime.CommandSessionImpl.execute(CommandSessionImpl.java:89)
      	at org.apache.karaf.shell.console.jline.Console.run(Console.java:221)
      	at java.lang.Thread.run(Thread.java:680)
      

        Activity

        Hide
        Martin Grigorov added a comment -

        As discussed in IRC (Lukasz, Igor, Martin) we agreed to keep it as it is now.
        In non-request threads the user application should care to set the needed objects in the the ThreadContext.

        Show
        Martin Grigorov added a comment - As discussed in IRC (Lukasz, Igor, Martin) we agreed to keep it as it is now. In non-request threads the user application should care to set the needed objects in the the ThreadContext.
        Hide
        Łukasz Dywicki added a comment -

        As a side note workaround with ThreadContext works.

        Show
        Łukasz Dywicki added a comment - As a side note workaround with ThreadContext works.
        Hide
        Łukasz Dywicki added a comment -

        Martin, the ThreadContext is an workaround. Previously with 1.4 we did not do any hacks with it and I belive we still should not. We already have an instance of Application and we call methods from public interface. The problem is that AbstractComponentMapper expects to run in same thread as application which is not always true - as in our case. We mount pages from different thread. Possible solution is to pass application instance to component mapper instead of using Application.get().

        Show
        Łukasz Dywicki added a comment - Martin, the ThreadContext is an workaround. Previously with 1.4 we did not do any hacks with it and I belive we still should not. We already have an instance of Application and we call methods from public interface. The problem is that AbstractComponentMapper expects to run in same thread as application which is not always true - as in our case. We mount pages from different thread. Possible solution is to pass application instance to component mapper instead of using Application.get().
        Hide
        Martin Grigorov added a comment -

        Not sure how 1.4 supported this. There is no special code that exports "this" as a ThreadLocal.
        To use the Application from a non-request thread you need to export it as ThreadLocal.
        Use ThreadContext.setApplication(app) and revert that in a "finally".

        Show
        Martin Grigorov added a comment - Not sure how 1.4 supported this. There is no special code that exports "this" as a ThreadLocal. To use the Application from a non-request thread you need to export it as ThreadLocal. Use ThreadContext.setApplication(app) and revert that in a "finally".

          People

          • Assignee:
            Unassigned
            Reporter:
            Łukasz Dywicki
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development