package org.jboss.resteasy.cdi.injection.reverse;
import java.util.HashMap;
import java.util.logging.Logger;
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.ejb.Stateful;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import org.jboss.resteasy.cdi.injection.Book;
import org.jboss.resteasy.cdi.injection.BookResource;
import org.jboss.resteasy.cdi.util.Utilities;
/**
*
* @author <a href="ron.sigal@jboss.com">Ron Sigal</a>
* @version $Revision: 1.1 $
*
* Copyright May 30, 2012
*/
@Stateful
@RequestScoped
public class EJBHolder implements EJBHolderRemote, EJBHolderLocal
{
public static final String SLE = "sle";
public static final String SFDE = "sfde";
public static final String SFRE = "sfre";
public static final String SFAE = "sfae";
public static final String SLI = "sli";
public static final String SFDI = "sfdi";
public static final String SFRI = "sfri";
public static final String SFAI = "sfai";
public static final String SLI_SECRET = "sliSecret";
public static final String SFDI_SECRET = "sfdiSecret";
public static final String SFRI_SECRET = "sfriSecret";
public static final String SFAI_SECRET = "sfaiSecret";
private static HashMap<String,Object> store = new HashMap<String,Object>();
@Inject private Logger log;
@Inject private Utilities utilities;
@Inject int secret;
@EJB private StatelessEJBwithJaxRsComponentsInterface sle;
@EJB private StatefulDependentScopedEJBwithJaxRsComponentsInterface sfde;
@EJB private StatefulRequestScopedEJBwithJaxRsComponentsInterface sfre;
@EJB private StatefulApplicationScopedEJBwithJaxRsComponentsInterface sfae;
@Inject private StatelessEJBwithJaxRsComponentsInterface sli;
@Inject private StatefulDependentScopedEJBwithJaxRsComponentsInterface sfdi;
@Inject private StatefulRequestScopedEJBwithJaxRsComponentsInterface sfri;
@Inject private StatefulApplicationScopedEJBwithJaxRsComponentsInterface sfai;
@Inject private BookResource resource;
@PostConstruct
public void postConstruct()
{
log.info(this + " secret: " + secret);
}
@Override
public boolean testScopes()
{
log.info("");
log.info("entering EJBHolder.testScopes()");
log.info("resource scope: " + utilities.getScope(BookResource.class));
log.info("EJBHolder scope: " + utilities.getScope(EJBHolder.class));
log.info("EJBHolderLocal scope: " + utilities.getScope(EJBHolderLocal.class));
log.info("EJBHolderRemote scope: " + utilities.getScope(EJBHolderRemote.class));
log.info("StatelessEJBwithJaxRsComponents scope: " + utilities.getScope(StatelessEJBwithJaxRsComponents.class));
log.info("StatelessEJBwithJaxRsComponentsInterface scope: " + utilities.getScope(StatelessEJBwithJaxRsComponentsInterface.class));
log.info("StatefulDependentScopedEJBwithJaxRsComponents scope: " + utilities.getScope(StatefulDependentScopedEJBwithJaxRsComponents.class));
log.info("StatefulDependentScopedEJBwithJaxRsComponentsInterface scope: " + utilities.getScope(StatefulDependentScopedEJBwithJaxRsComponentsInterface.class));
log.info("StatefulRequestScopedEJBwithJaxRsComponents scope: " + utilities.getScope(StatefulRequestScopedEJBwithJaxRsComponents.class));
log.info("StatefulRequestScopedEJBwithJaxRsComponentsInterface scope: " + utilities.getScope(StatefulRequestScopedEJBwithJaxRsComponentsInterface.class));
log.info("StatefulApplicationScopedEJBwithJaxRsComponents scope: " + utilities.getScope(StatefulApplicationScopedEJBwithJaxRsComponents.class));
log.info("StatefulApplicationScopedEJBwithJaxRsComponentsInterface scope: " + utilities.getScope(StatefulApplicationScopedEJBwithJaxRsComponentsInterface.class));
return utilities.isDependentScoped(StatelessEJBwithJaxRsComponentsInterface.class) &&
utilities.isDependentScoped(StatefulDependentScopedEJBwithJaxRsComponentsInterface.class) &&
utilities.isRequestScoped(StatefulRequestScopedEJBwithJaxRsComponentsInterface.class) &&
utilities.isApplicationScoped(StatefulApplicationScopedEJBwithJaxRsComponentsInterface.class);
}
@Override
public void setup()
{
log.info("");
log.info("entering EJBHolder.setup()");
resource.getSet().add(new Book("Disappearing Book"));
store.put("sle", sle);
store.put("sfde", sfde);
store.put("sfre", sfre);
store.put("sfae", sfae);
store.put("sli", sli);
store.put("sfdi", sfdi);
store.put("sfri", sfri);
store.put("sfai", sfai);
store.put("sli.secret", sli.theSecret());
store.put("sfdi.secret", sfdi.theSecret());
store.put("sfri.secret", sfri.theSecret());
store.put("sfai.secret", sfai.theSecret());
sleSetup();
sfdeSetup();
sfreSetup();
sfaeSetup();
sliSetup();
sfdiSetup();
sfriSetup();
sfaiSetup();
}
@Override
public boolean test()
{
log.info("");
log.info("entering EJBHolder.test()");
boolean result = true;
result &= resource.getSet().isEmpty();
// @TODO inject singleton
// @TODO inject by setter method
result &= store.get("sle").equals(sle); // EJB spec 3.4.7.1
result &= !store.get("sfde").equals(sfde); // EJB spec 3.4.7.2, 16.2.1
result &= !store.get("sfre").equals(sfre); // EJB spec 3.4.7.2, 16.2.1
result &= !store.get("sfae").equals(sfae); // EJB spec 3.4.7.2, 16.2.1
//
result &= !(store.get("sle") == sle); // EJB spec 16.2.1
result &= !(store.get("sfde") == sfde); // EJB spec 16.2.1
result &= !(store.get("sfre") == sfre); // EJB spec 16.2.1
result &= !(store.get("sfae") == sfae); // EJB spec 16.2.1
// Unlike the EJB spec, the CDI spec does not explicitly specify the semantics of the equality or inequality
// of injected objects. In fact, it explicitly forbids calling the java.lang.Object.equals() function on injected
// objects [CDI spec, section 5.4.2]. It does specify that the first reference to an injectible object in a given
// context should result in a new contextual reference or a new contextual instance [CDI spec, section 6.5.3],
// but it doesn't seem to specify the precise semantics of "new". In the weld reference implementation,
// there seem to be three variations, at least with respect to injected EJBs:
//
// 1. It could be a new proxy for an existing object, or
// 2. a new proxy for a new object, or
// 3. a reused proxy for a new object.
//
// In this test, we find that
//
// 1. An SLSB (which necessarily has dependent pseudo-scope) is treated according to case 1.
// 2. An SFSB with dependent scope is treated according to case 2.
// 3. An SFSB with request scope is treated according to case 3.
//
// This behavior seems to be consistent with the semantics of EJBs:
//
// 1. All instances of a given SLSB class are considered equal, and SLSB target objects are reused (case 1).
// 2. All instances of a given SFSB class are considered unequal, and SFSBs are always recreated (cases 2 and 3).
//
// For this test, we consider inequality, in cases where we expect a new object in a new scope, to mean
//
// 1. a new proxy for SLSBs, and
// 2. a new target object for SFSBs.
//
// N.B. If an SLSB is reused, and it is a contextual object (i.e., created by CDI), then, though some fields might
// remain the same, all fields annotated with @Inject should be processed accordingly.
//
log.info("sli: == stored sli: " + (sli == store.get("sli")));
log.info("sfdi: == stored sfdi: " + (sfdi == store.get("sfdi")));
log.info("sfri: == stored sfri: " + (sfri == store.get("sfri")));
log.info("sfai: == stored sfai: " + (sfai == store.get("sfai")));
log.info("sli.secret: == stored sli.secret: " + (sli.theSecret() == Integer.class.cast(store.get("sli.secret"))));
log.info("sfdi.secret: == stored sfdi.secret: " + (sfdi.theSecret() == Integer.class.cast(store.get("sfdi.secret"))));
log.info("sfri.secret: == stored sfri.secret: " + (sfri.theSecret() == Integer.class.cast(store.get("sfri.secret"))));
log.info("sfai.secret: == stored sfai.secret: " + (sfai.theSecret() == Integer.class.cast(store.get("sfai.secret"))));
result &= (sli != store.get("sli"));
result &= (sfdi.theSecret() != Integer.class.cast(store.get("sfdi.secret")));
result &= (sfri.theSecret() != Integer.class.cast(store.get("sfri.secret")));
// The CDI spec requires that a single application scoped object of a given class should exist for the
// lifetime of the application. It seems reasonable to expect
//
// 1. that a proxy for that object obtained by @Inject should be reused throughout the lifetime of the application, and
// 2. that the target of that proxy should remain the same throughout the lifetime of the application.
result &= (sfai == store.get("sfai") && sfai.theSecret() == Integer.class.cast(store.get("sfai.secret")));
result &= sleTest();
result &= sfdeTest();
result &= sfreTest();
result &= sfaeTest();
result &= sliTest();
result &= sfdiTest();
result &= sfriTest();
result &= sfaiTest();
return result;
}
@Override
public void sleSetup()
{
sle.setUp(SLE);
}
@Override
public boolean sleTest()
{
return sle.test(SLE);
}
@Override
public void sfdeSetup()
{
sfde.setUp(SFDE);
}
@Override
public boolean sfdeTest()
{
return sfde.test(SFDE);
}
@Override
public void sfreSetup()
{
sfre.setUp(SFRE);
}
@Override
public boolean sfreTest()
{
return sfre.test(SFRE);
}
@Override
public void sfaeSetup()
{
sfae.setUp(SFAE);
}
@Override
public boolean sfaeTest()
{
return sfae.test(SFAE);
}
@Override
public void sliSetup()
{
sli.setUp(SLI);
}
@Override
public boolean sliTest()
{
return sli.test(SLI);
}
@Override
public void sfdiSetup()
{
sfdi.setUp(SFDI);
}
@Override
public boolean sfdiTest()
{
return sfdi.test(SFDI);
}
@Override
public void sfriSetup()
{
sfri.setUp(SFRI);
}
@Override
public boolean sfriTest()
{
return sfri.test(SFRI);
}
@Override
public void sfaiSetup()
{
sfai.setUp(SFAI);
}
@Override
public boolean sfaiTest()
{
return sfai.test(SFAI);
}
@Override
public boolean theSame(EJBHolderLocal that)
{
log.info("this secret: " + secret);
log.info("that secret: " + that.theSecret());
return this.secret == that.theSecret();
}
@Override
public int theSecret()
{
return secret;
}
}