1

I'm building a JAX-RS app that consists of a stockroom and a workplace. The stockroom holds a set of Java classes that can be instantiated (via AJAX) to create named instances of those classes in the workplace.

So far I'm able to reference the stockroom and workplace fine by declaring them as "singletons" in the RestEasy application

    singletons.add(StockPlace.getInstance());
    singletons.add(WorkPlace.getInstance());

I'm unable to understand how to understand how the stockroom content classes should be handled. The effect I'm trying to achieve is that when I dynamically create an instance of one of the stockroom classes, that instance can be dynamically accessed via REST commands. I've tried various permutations of:

    classes.add(SomeComponent.class);

I think I'm missing knowledge of how the Java notion of how classes work as factories for making instances, and how both of these relate to what RestEasy calls classes, singletons (singletons ARE classes, yet RestEasy registers them as instances) and resources (instances?).

I suspect I'll wind up needing to dynamically register new instances but can't find a way to do that either. I did find a way to do it given the ServletContext, but am not able to get access to that either. Can someone get me on the right track?

Bradjcox
  • 1,509
  • 1
  • 18
  • 30

3 Answers3

1

Our eventual answer to this question was to bail out of RestEasy and convert to DropWizard. That problem and many others vanished and everything became easy again.

gustavohenke
  • 40,997
  • 14
  • 121
  • 129
Bradjcox
  • 1,509
  • 1
  • 18
  • 30
0

I believe I know what you are after, but I should at least give you a push in the right direction.

You will need to add the annotated RESTEasy class(es) to the registry. Below is the class I used for a recent project. It adds to the singletons (per what you did) but it also adds to the registry.

public class RESTEasyServerApplication extends javax.ws.rs.core.Application
{
    // The RESTEasy registry
    @Autowired
    protected org.jboss.resteasy.spi.Registry registry;

    // The annotated RESTEasy handler classes
    private Set<Object>  singletons = new HashSet<Object>();
    private List<Object> handlers   = new ArrayList<Object>();

    public RESTEasyServerApplication()
    {}

    @Override
    public Set<Object> getSingletons()
    {
        return singletons;
    }

    // Spring injection support
    public void setHandlers( List<Object> handlers )
    {
        for( Object handler : handlers )
        {
            if( registry != null )
            {
                // Save a reference to the handler
                this.handlers.add( handler );

                // Register the handler with RESTEasy
                registry.addSingletonResource( handler );
            }

            singletons.add( handler );
        }
    }

    // Spring injection support
    public List<Object> getHandlers()
    {
        return handlers;
    }
}

I used Spring, and here is the relevant configuration:

<!-- RESTeasy/Spring integration -->
<import resource="classpath:springmvc-resteasy.xml" />

<!-- RESTeasy server application -->
<bean id="application" class="blah.blah.resteasy.RESTEasyServerApplication">
    <property name="handlers">
        <list>
            <!-- Application specific handler classes -->
            <ref bean="sample"/>
        </list>
    </property>
</bean>

Should be easy to modify/add a method to accept a single annotated RESTEasy class and make it work dynamically as required. The registry is defined in the springmvc-resteasy.xml file.

  • I'm reluctant to insert another unknown (Spring) into a situation I'm already confused by. And I don't need dependency injection (yet), since StockPlace already knows the set of classes it holds. It has a Set for that. Also don't understand what setHandlers() is or does. The Application class only has getClasses() and getSingletons(). Do you mean one of those? – Bradjcox Apr 12 '12 at 14:33
  • Sorry, the answer was confusing as I tried to include everything I was doing. I believe all you need to do is: `registry.addSingletonResource( handler );` where handler is your annotated RESTEasy object. – Eric Thorbjornsen Apr 12 '12 at 20:04
  • So how do I find registry if I'm not using Spring. And my content objects aren't singetons; they create many instances on request. And most of all, how do I specify that my instances persist for many requests? I need something like application scope, not request scope, and really don't see how to get it. Without strapping on yet another major technology that I don't yet fully understand. – Bradjcox Apr 12 '12 at 21:31
  • Can you provide some additional information about your environment? Are you using JBoss, Tomcat, something else? You are clearly not using Spring, are you writing EJBs? Hopefully with the additional information, we can nail down where you can grab the registry from. – Eric Thorbjornsen Apr 13 '12 at 16:17
  • Tomcat + RestEasy. No EJBs. But I think I know a solution. I know the Stockroom and Workplace persist across requests (they're singletons). RestEasy won't persist the classes in the Stockroom since they're not singletons. So a solution (not necessarily the best) is to not register them with RestEasy at all and treat them as plain POJOs, managed/routedTo solely by the Workplace. I.e. osint/rest/workplace/configure/part1 routes to workplace, which looks up part1 and calls it's configure method as a POJO. Can you propose a better way (that doesn't involve Spring)? – Bradjcox Apr 13 '12 at 21:30
  • This article should answer your question for the environment you are working in. http://stackoverflow.com/questions/7018041/resteasy-add-a-resource-class-dynamically – Eric Thorbjornsen Apr 14 '12 at 00:39
  • Yeah, that comes close but never explained how to get the ServletContext when you're not in the servlet. Presumably I need to replace the one RestEasy provides, or something. – Bradjcox Apr 14 '12 at 01:43
0

Since I've found no answers that don't involve strapping another whole layer of complexity (Spring) onto RestEasy, the solution I found livable is outlined in the final comment above. That is, don't rely on sending remote messages to instances unless the app is truly stateless (e.g. instances don't persist across messages). Only send remote messages to singletons which do persist across requests. Each such message can identify the desired instance (by String id in my case), and the singleton can forward to the identified instance as an ordinary POJO.

I still don't see why RestEasy unconditionally treats non-Singletons (instances) as ephemeral. Statelessness is not a restriction on REST, only a restriction on when GET methods can be used (idempotent calls). PUT and POST calls are neither stateless nor idempotent.

As I understand this, of course, and feel free to correct me. My focus is getting this app on the air, not exploring every corner of RestEasy, REST, and certainly not Spring.

Bradjcox
  • 1,509
  • 1
  • 18
  • 30