package org.jboss.resteasy.test.cdi.injection.resource; import org.jboss.resteasy.spi.ResteasyProviderFactory; import org.jboss.resteasy.test.cdi.util.Constants; import org.jboss.resteasy.test.cdi.util.Counter; import org.jboss.resteasy.test.cdi.util.CounterBinding; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.ejb.EJB; import javax.enterprise.context.ApplicationScoped; import javax.enterprise.context.Dependent; import javax.enterprise.context.RequestScoped; import javax.enterprise.context.SessionScoped; import javax.enterprise.inject.Instance; import javax.enterprise.inject.New; import javax.enterprise.inject.spi.Bean; import javax.enterprise.inject.spi.BeanManager; import javax.inject.Inject; import javax.jms.DeliveryMode; import javax.jms.JMSException; import javax.jms.MessageConsumer; import javax.jms.MessageProducer; import javax.jms.Queue; import javax.jms.Session; import javax.jms.TextMessage; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Context; import javax.ws.rs.core.GenericEntity; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import java.lang.annotation.Annotation; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Logger; @Path("/") @RequestScoped public class CDIInjectionBookResource { public static final String BOOK_READER = "BookReader"; public static final String BOOK_WRITER = "BookWriter"; public static final String BOOK_RESOURCE = "BookResource"; public static final String BOOK_READER_DEPENDENT = "BookReaderDependent"; public static final String BOOK_WRITER_DEPENDENT = "BookWriterDependent"; public static final String BOOK_RESOURCE_DEPENDENT = "BookResourceDependent"; public static final String BOOK_READER_STATEFUL = "BookReaderStateless"; public static final String BOOK_WRITER_STATEFUL = "BookWriterStateless"; public static final String BOOK_RESOURCE_STATEFUL = "BookResourceStateless"; public static final String BOOK_RESOURCE_STATEFUL2 = "BookResourceStateless2"; public static final String COUNTER = "counter"; public static final String COLLECTION = "collection"; public static final String BOOK_BAG = "bookBag"; public static final String NEW_BEAN_APPLICATION_SCOPED = "newBeanApplicationScoped"; public static final String NEW_BEAN_DEPENDENT_SCOPED = "newBeanDependentScoped"; public static final String STEREOTYPED_APPLICATION_SCOPED = "stereotypedApplicationScoped"; public static final String STEREOTYPED_DEPENDENT_SCOPED = "stereotypedDependentScoped"; private static HashMap<String, Object> store; private static AtomicInteger constructCounter = new AtomicInteger(); private static AtomicInteger destroyCounter = new AtomicInteger(); private static CountDownLatch latch = new CountDownLatch(2); @Inject @CDIInjectionResourceBinding @PersistenceContext(unitName = "test") EntityManager em; private HashSet<CDIInjectionBook> set = new HashSet<CDIInjectionBook>(); @Inject private BeanManager beanManager; @Inject private int secret; // used to determine identity @Inject private CDIInjectionDependentScoped dependent; // dependent scoped managed bean @Inject @CounterBinding private Counter counter; // application scoped singleton: injected as Weld proxy @EJB private CDIInjectionBookCollection collection; // application scoped singleton: injected as EJB proxy // @Note: stateful and stateful2 are two very different objects. // stateful is an EJB proxy and stateful2 is a Weld proxy. @EJB private CDIInjectionStatefulEJB stateful; // dependent scoped SLSB @Inject private CDIInjectionStatefulEJB stateful2; // dependent scoped SLSB @Inject private CDIInjectionBookBagLocal bookBag; // session scoped SFSB @Inject @CDIInjectionResourceBinding private Session session; @Inject @CDIInjectionResourceBinding private Queue bookQueue; @Inject private CDIInjectionNewBean newBean1; @Inject @New private CDIInjectionNewBean newBean2; @Inject private CDIInjectionStereotypedApplicationScope stereotypeApplicationScoped; @Inject private CDIInjectionStereotypedDependentScope stereotypedRequestScoped; private Logger log; public static HashMap<String, Object> getStore() { return store; } public static void setStore(HashMap<String, Object> store) { CDIInjectionBookResource.store = store; } public HashSet<CDIInjectionBook> getSet() { return set; } public void setSet(HashSet<CDIInjectionBook> set) { this.set = set; } @PreDestroy public void preDestroy() { destroyCounter.incrementAndGet(); log.info("preDestroy(): destroyCounter: " + destroyCounter.get()); } @PostConstruct public void postConstruct() { constructCounter.incrementAndGet(); log.info("postConstruct(): constructCounter: " + constructCounter.get()); } public CountDownLatch getCountDownLatch() { log.info("latch.getCount(): " + latch.getCount()); return latch; } @Inject public void init(Instance<Logger> logInstance) { this.log = logInstance.get(); } @GET @Path("verifyScopes") @Produces(MediaType.TEXT_PLAIN) public Response verifyScopes() { log.info("entering verifyScopes()"); ResteasyProviderFactory factory = ResteasyProviderFactory.getInstance(); CDIInjectionBookReader reader = CDIInjectionBookReader.class.cast(factory.getMessageBodyReader(CDIInjectionBook.class, null, null, Constants.MEDIA_TYPE_TEST_XML_TYPE)); CDIInjectionBookWriter writer = CDIInjectionBookWriter.class.cast(factory.getMessageBodyWriter(CDIInjectionBook.class, null, null, Constants.MEDIA_TYPE_TEST_XML_TYPE)); if (store == null) { log.info("Counter scope: " + getScope(Counter.class)); log.info("BookCollection scope: " + getScope(CDIInjectionBookCollection.class)); log.info("BookResource scope: " + getScope(CDIInjectionBookResource.class)); log.info("BookReader scope: " + getScope(CDIInjectionBookReader.class)); log.info("BookWriter scope: " + getScope(CDIInjectionBookWriter.class)); log.info("UnscopedResource scope: " + getScope(CDIInjectionUnscopedResource.class)); log.info("DependentScoped scope: " + getScope(CDIInjectionDependentScoped.class)); log.info("StatelessEJB scope: " + getScope(CDIInjectionStatefulEJB.class)); log.info("BookBagLocal scope: " + getScope(CDIInjectionBookBagLocal.class)); log.info("NewBean scope: " + getScope(CDIInjectionNewBean.class)); log.info("stereotypeApplicationScoped: " + getScope(CDIInjectionStereotypedApplicationScope.class)); log.info("stereotypeRequestScoped: " + getScope(CDIInjectionStereotypedDependentScope.class)); store = new HashMap<String, Object>(); store.put(BOOK_READER, reader); store.put(BOOK_WRITER, writer); store.put(BOOK_RESOURCE, this); store.put(BOOK_READER_DEPENDENT, reader.getDependent()); store.put(BOOK_WRITER_DEPENDENT, writer.getDependent()); store.put(BOOK_RESOURCE_DEPENDENT, dependent); store.put(BOOK_READER_STATEFUL, reader.getStateful()); store.put(BOOK_WRITER_STATEFUL, writer.getStateful()); store.put(BOOK_RESOURCE_STATEFUL, stateful); store.put(BOOK_RESOURCE_STATEFUL2, stateful2); store.put(COUNTER, counter); store.put(COLLECTION, collection); store.put(BOOK_BAG, bookBag); store.put(NEW_BEAN_APPLICATION_SCOPED, newBean1); store.put(NEW_BEAN_DEPENDENT_SCOPED, newBean2); store.put(STEREOTYPED_APPLICATION_SCOPED, stereotypeApplicationScoped); store.put(STEREOTYPED_DEPENDENT_SCOPED, stereotypedRequestScoped); return Response.ok().build(); } if (isApplicationScoped(Counter.class) && isApplicationScoped(CDIInjectionBookCollection.class) && isApplicationScoped(CDIInjectionBookReader.class) && isApplicationScoped(CDIInjectionBookWriter.class) && isRequestScoped(CDIInjectionBookResource.class) && isDependentScoped(CDIInjectionDependentScoped.class) && isDependentScoped(CDIInjectionStatefulEJB.class) && isRequestScoped(CDIInjectionUnscopedResource.class) && isSessionScoped(CDIInjectionBookBagLocal.class) && isApplicationScoped(CDIInjectionNewBean.class) && isApplicationScoped(CDIInjectionStereotypedApplicationScope.class) && isDependentScoped(CDIInjectionStereotypedDependentScope.class) && store.get(BOOK_READER) == reader && store.get(BOOK_WRITER) == writer && store.get(BOOK_RESOURCE) != this && store.get(BOOK_READER_DEPENDENT) == reader.getDependent() && store.get(BOOK_WRITER_DEPENDENT) == writer.getDependent() && store.get(BOOK_RESOURCE_DEPENDENT) != dependent && store.get(BOOK_READER_STATEFUL).equals(reader.getStateful()) && store.get(BOOK_WRITER_STATEFUL).equals(writer.getStateful()) && !store.get(BOOK_RESOURCE_STATEFUL).equals(stateful) && !store.get(BOOK_RESOURCE_STATEFUL2).equals(stateful2) && store.get(COUNTER).equals(counter) && store.get(COLLECTION).equals(collection) && store.get(BOOK_BAG).equals(bookBag) && store.get(NEW_BEAN_APPLICATION_SCOPED).equals(newBean1) && !store.get(NEW_BEAN_DEPENDENT_SCOPED).equals(newBean2) && !newBean1.equals(newBean2) && store.get(STEREOTYPED_APPLICATION_SCOPED).equals(stereotypeApplicationScoped) && !store.get(STEREOTYPED_DEPENDENT_SCOPED).equals(stereotypedRequestScoped) ) { return Response.ok().build(); } else { return Response.serverError().build(); } } @POST @Path("empty") public void empty() { collection.empty(); } @POST @Path("create") @Consumes("application/test+xml") @Produces(MediaType.TEXT_PLAIN) public Response createBook(CDIInjectionBook book) { log.info("entering createBook()"); int id = counter.getNext(); book.setId(id); collection.addBook(book); log.info("stored: " + id + "->" + book); return Response.ok(id).build(); } @GET @Produces(MediaType.APPLICATION_XML) @Path("books") public Collection<CDIInjectionBook> listAllMembers() { log.info("entering listAllMembers()"); log.info("this.theSecret(): " + this.theSecret()); Collection<CDIInjectionBook> books = collection.getBooks(); log.info("listAllMembers(): " + books); return books; } @GET @Path("book/{id:[0-9][0-9]*}") @Produces("application/test+xml") public CDIInjectionBook lookupBookById(@PathParam("id") int id) { log.info("entering lookupBookById(" + id + ")"); log.info("books: " + collection.getBooks()); CDIInjectionBook book = collection.getBook(id); if (book == null) { throw new WebApplicationException(Response.Status.NOT_FOUND); } return book; } @POST @Path("entityManager") public Response testEntityManager() { log.info("entering testEntityManager()"); CDIInjectionBook book1 = collection.getBook(Counter.INITIAL_VALUE); CDIInjectionBook book2 = em.find(CDIInjectionBook.class, Counter.INITIAL_VALUE); return book1.equals(book2) ? Response.ok().build() : Response.serverError().build(); } @POST @Path("session/add") public Response sessionAdd(@Context HttpServletRequest request, CDIInjectionBook book) { log.info("entering sessionAdd()"); log.info("new session: " + request.getSession().isNew()); bookBag.addBook(book); return Response.ok().build(); } @GET @Path("session/get") @Produces(MediaType.APPLICATION_XML) public Collection<CDIInjectionBook> sessionGetBag(@Context HttpServletRequest request) { log.info("entering sessionGetBag()"); log.info("new session: " + request.getSession().isNew()); Collection<CDIInjectionBook> books = bookBag.getContents(); log.info("sessionGetBag(): " + books); request.getSession().invalidate(); return books; } @POST @Path("session/test") public Response sessionTest(@Context HttpServletRequest request) { log.info("entering sessionTest()"); log.info("new session: " + request.getSession().isNew()); Collection<CDIInjectionBook> contents = bookBag.getContents(); log.info("bookBag: " + contents); if (request.getSession().isNew() && contents.isEmpty()) { return Response.ok().build(); } else { return Response.serverError().build(); } } @GET @Path("mdb/get") @Produces(MediaType.APPLICATION_XML) public GenericEntity<Collection<CDIInjectionBook>> mdbGetBag() { log.info("entering mdbGetBag()"); Collection<CDIInjectionBook> books = bookBag.getContents(); log.info("sessionGetBag(): " + books); return new GenericEntity<Collection<CDIInjectionBook>>(books) { }; } @GET @Path("getCounters") public String getCounters() { return Integer.toString(constructCounter.get()) + ":" + Integer.toString(destroyCounter.get()) + ":"; } @GET @Path("disposer") public Response testDisposer() { log.info("entering testDisposer()"); return CDIInjectionResourceProducer.isDisposed() ? Response.ok().build() : Response.serverError().build(); } @POST @Path("produceMessage") @Consumes("application/test+xml") @Produces(MediaType.TEXT_PLAIN) public Response produceBookMessage(CDIInjectionBook book) { log.info("entering produceBookMessage()"); try { log.info("queue: " + bookQueue); log.info("ResourceProducer scope: " + getScope(CDIInjectionResourceProducer.class)); log.info("queue scope: " + getScope(Queue.class)); MessageProducer producer = session.createProducer(bookQueue); TextMessage message = session.createTextMessage(book.getName()); producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); producer.send(message); log.info("sent: " + message.getText()); return Response.ok().build(); } catch (JMSException e) { log.info(String.format("Stacktrace: %s", (Object[]) e.getStackTrace())); return Response.serverError().entity("JMS error: " + e.getMessage()).build(); } } @GET @Path("queue/consumeMessage") @Produces(MediaType.TEXT_PLAIN) public Response consumeBookMessageFromQueue() { log.info("entering consumeBookMessageFromQueue() xxx"); log.info("getting consumer"); try { MessageConsumer consumer = session.createConsumer(bookQueue); log.info("got consumer"); TextMessage message = (TextMessage) consumer.receiveNoWait(); log.info("message: " + message); if (message == null) { return Response.serverError().build(); } log.info("message text: " + message.getText()); return Response.ok(message.getText()).build(); } catch (JMSException e) { return Response.serverError().entity("JMS error: " + e.getMessage()).build(); } } @GET @Path("mdb/consumeMessage") @Produces(MediaType.TEXT_PLAIN) public Response consumeBookMessageFromMDB() throws InterruptedException { log.info("entering consumeBookMessageFromMDB()"); getCountDownLatch().await(5000, TimeUnit.MILLISECONDS); // Wait until BookMDB has stored book in BookCollection. CDIInjectionBookCollection collection = getBookCollection(); log.info("consumeBookMessageFromMDB(): collection.size(): " + collection.getBooks().size()); if (collection.getBooks().size() == 1) { String name = collection.getBooks().iterator().next().getName(); log.info("got book name: " + name); return Response.ok(name).build(); } else { return Response.serverError().entity("Collection size: " + collection.getBooks().size()).build(); } } @GET @Produces(MediaType.APPLICATION_XML) @Path("mdb/books") public Collection<CDIInjectionBook> getBooksMDB() throws InterruptedException { log.info("entering getBooksMDB()"); log.info("getBooksMDB(): waiting on latch"); latch.await(); log.info("this.theSecret(): " + this.theSecret()); Collection<CDIInjectionBook> books = collection.getBooks(); log.info("getBooksMDB(): " + books); return books; } CDIInjectionBookCollection getBookCollection() { log.info("entering getBookCollection()"); return collection; } Counter getCounter() { log.info("returning: " + counter); return counter; } boolean isApplicationScoped(Class<?> c) { return testScope(c, ApplicationScoped.class); } boolean isDependentScoped(Class<?> c) { return testScope(c, Dependent.class); } boolean isRequestScoped(Class<?> c) { return testScope(c, RequestScoped.class); } boolean isSessionScoped(Class<?> c) { return testScope(c, SessionScoped.class); } boolean testScope(Class<?> c, Class<?> scopeClass) { Class<? extends Annotation> annotation = getScope(c); if (annotation == null) { return false; } return annotation.isAssignableFrom(scopeClass); } Class<? extends Annotation> getScope(Class<?> c) { Set<Bean<?>> beans = beanManager.getBeans(c); Iterator<Bean<?>> it = beans.iterator(); if (it.hasNext()) { Bean<?> bean = beans.iterator().next(); return bean.getScope(); } return null; } public boolean theSame(CDIInjectionBookResource that) { return this.secret == that.secret; } public int theSecret() { return secret; } }