package org.jboss.seam.flex; import java.io.*; import java.lang.reflect.Method; import java.util.concurrent.ConcurrentHashMap; import java.util.Collection; import javax.servlet.*; import javax.servlet.http.*; import flex.messaging.*; import flex.messaging.config.*; import flex.messaging.endpoints.Endpoint; import flex.messaging.log.ServletLogTarget; import flex.messaging.services.RemotingService; import flex.messaging.services.remoting.*; import org.jboss.seam.annotations.Name; import org.jboss.seam.log.LogProvider; import org.jboss.seam.log.Logging; import org.jboss.seam.util.Reflections; import org.jboss.seam.util.Resources; public class MessageBrokerManager { private static final String SEAM_ENDPOINT = "seam-amf"; private static final LogProvider log = Logging.getLogProvider(MessageBrokerManager.class); private static String WAR_CONFIG_PREFIX = "/WEB-INF/flex/"; private static String EAR_CONFIG_PREFIX = "/META-INF/flex/seam-default-"; private flex.messaging.MessageBroker broker; private ServletConfig servletConfig; public void init(ServletConfig servletConfig) throws ServletException { this.servletConfig = servletConfig; // allocate thread local variables createThreadLocals(); try { FlexContext.setThreadLocalObjects(null, null, null, null, null, servletConfig); ServletLogTarget.setServletContext(servletConfig.getServletContext()); FlexConfigurationManager configManager = new SeamFlexConfigurationManager(); MessagingConfiguration config = configManager.getMessagingConfiguration(servletConfig); config.createLogAndTargets(); broker = config.createBroker(servletConfig.getInitParameter("messageBrokerId"), Thread.currentThread().getContextClassLoader()); // Set the servlet config as thread local FlexContext.setThreadLocalObjects(null, null, broker, null, null, servletConfig); setInitServletContext(broker, servletConfig.getServletContext()); // Create endpoints, services, security, and logger on the broker based on configuration config.configureBroker(broker); if (broker.getChannelIds()== null || !broker.getChannelIds().contains(SEAM_ENDPOINT)) { log.info("seam-amf endpoint not found. creating..."); broker.createEndpoint(SEAM_ENDPOINT, "http://{server.name}:{server.port}/{context.root}/messagebroker/seam-amf", "flex.messaging.endpoints.AMFEndpoint"); } //initialize the httpSessionToFlexSessionMap synchronized(HttpFlexSession.mapLock) { if (servletConfig.getServletContext().getAttribute(HttpFlexSession.SESSION_MAP) == null) { servletConfig.getServletContext().setAttribute(HttpFlexSession.SESSION_MAP, new ConcurrentHashMap()); } } broker.start(); configManager.reportTokens(); config.reportUnusedProperties(); // clear the broker and servlet config as this thread is done FlexContext.clearThreadLocalObjects(); } catch (Throwable t){ log.error("MessageBrokerServlet failed to initialize due to runtime exception"); destroy(); throw new ServletException(t); } } private void setInitServletContext(flex.messaging.MessageBroker broker, ServletContext ctx) throws Exception { Method setMethod = flex.messaging.MessageBroker.class. getDeclaredMethod("setInitServletContext", ServletContext.class); setMethod.setAccessible(true); Reflections.invoke(setMethod, broker, ctx); } public void destroy() { if (broker != null) { broker.stop(); // release static thread locals destroyThreadLocals(); } } public void service(HttpServletRequest req, HttpServletResponse res) { log.info("=========== START FLEX REQUEST"); try { broker.initThreadLocals(); FlexContext.setThreadLocalObjects(null, null, broker, req, res, servletConfig); // necessary to create for later HttpFlexSession fs = HttpFlexSession.getFlexSession(req); log.info("flex session is " + fs); Endpoint endpoint = findEndpoint(req, res); log.info("Endpoint: " + endpoint.describeEndpoint()); endpoint.service(req, res); } catch (UnsupportedOperationException ue) { ue.printStackTrace(); sendError(res); } catch (RuntimeException e) { e.printStackTrace(); } finally { FlexContext.clearThreadLocalObjects(); } log.info("=========== END FLEX REQUEST"); } private void sendError(HttpServletResponse res) { if (!res.isCommitted()) { try { res.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); } catch (IOException ignored) { } } } private Endpoint findEndpoint(HttpServletRequest req, HttpServletResponse res) { String contextPath = req.getContextPath(); String pathInfo = req.getPathInfo(); String endpointPath = req.getServletPath(); if (pathInfo != null) { endpointPath = endpointPath + pathInfo; } log.info("flex request for cp=" + contextPath + " ep=" + endpointPath); try { return broker.getEndpoint(endpointPath, contextPath); } catch (MessageException me) { if (!res.isCommitted()) { try { res.sendError(HttpServletResponse.SC_NOT_FOUND); } catch (IOException ignore) { // ignore } } return null; } } // Call ONLY on servlet startup public void createThreadLocals() { // allocate static thread local objects flex.messaging.MessageBroker.createThreadLocalObjects(); FlexContext.createThreadLocalObjects(); flex.messaging.io.SerializationContext.createThreadLocalObjects(); flex.messaging.io.TypeMarshallingContext.createThreadLocalObjects(); } protected void destroyThreadLocals() { // Destroy static thread local objects flex.messaging.MessageBroker.releaseThreadLocalObjects(); FlexContext.releaseThreadLocalObjects(); flex.messaging.io.SerializationContext.releaseThreadLocalObjects(); flex.messaging.io.TypeMarshallingContext.releaseThreadLocalObjects(); } private RemotingService createRemotingService() { RemotingService remotingService = null; remotingService = new RemotingService(); remotingService.setId("remoting-service"); broker.addService(remotingService); log.info("Flex remotingservice not found- creating " + remotingService); return remotingService; } private RemotingService findRemotingService() { return (RemotingService) broker.getServiceByType(RemotingService.class.getName()); } private void registerSeamAdapter(RemotingService remotingService) { if (remotingService.getRegisteredAdapters().get(SeamAdapter.SEAM_ADAPTER_ID) == null) { remotingService.registerAdapter(SeamAdapter.SEAM_ADAPTER_ID,SeamAdapter.class.getName()); } } private Destination createDestination(String destinationName, String componentName) { RemotingService remotingService = findRemotingService(); if (remotingService==null) { remotingService = createRemotingService(); } RemotingDestination destination = (RemotingDestination) remotingService.createDestination(destinationName); destination.setFactory(new FlexSeamFactory(destinationName, componentName)); // configure adapter registerSeamAdapter(remotingService); destination.createAdapter(SeamAdapter.SEAM_ADAPTER_ID); destination.addChannel(SEAM_ENDPOINT); return destination; } public void addDestinations(Collection<Class<?>> destinations) { for (Class<?> annotatedClass: destinations) { log.info("Adding scanned flex desitionation for class " + annotatedClass); FlexRemote fr = annotatedClass.getAnnotation(FlexRemote.class); Name name = annotatedClass.getAnnotation(Name.class); String destinationName = fr.name(); String componentName = name.value(); Destination destination = createDestination(destinationName, componentName); destination.start(); } } }