[jboss-cvs] jboss-seam/src/remoting/org/jboss/seam/remoting ...
Shane Bryzak
sbryzak at redhat.com
Tue Feb 27 17:15:23 EST 2007
User: sbryzak2
Date: 07/02/27 17:15:23
Added: src/remoting/org/jboss/seam/remoting
BaseRequestHandler.java Call.java CallContext.java
ExecutionHandler.java InterfaceGenerator.java
MarshalUtils.java PollHandler.java Remoting.java
RequestContext.java RequestHandler.java
RequestHandlerFactory.java SubscriptionHandler.java
package-info.java remote.js
Log:
JBSEAM-915
Revision Changes Path
1.1 date: 2007/02/27 22:15:23; author: sbryzak2; state: Exp;jboss-seam/src/remoting/org/jboss/seam/remoting/BaseRequestHandler.java
Index: BaseRequestHandler.java
===================================================================
package org.jboss.seam.remoting;
import javax.servlet.ServletContext;
/**
*
* @author Shane Bryzak
*/
public abstract class BaseRequestHandler implements RequestHandler
{
public void setServletContext(ServletContext context) {}
}
1.1 date: 2007/02/27 22:15:23; author: sbryzak2; state: Exp;jboss-seam/src/remoting/org/jboss/seam/remoting/Call.java
Index: Call.java
===================================================================
package org.jboss.seam.remoting;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.jboss.seam.Component;
import org.jboss.seam.annotations.WebRemote;
import org.jboss.seam.remoting.wrapper.ConversionException;
import org.jboss.seam.remoting.wrapper.ConversionScore;
import org.jboss.seam.remoting.wrapper.Wrapper;
import org.jboss.seam.util.EJB;
/**
*
* @author Shane Bryzak
*/
public class Call
{
private String id;
private String componentName;
private String methodName;
private List<Wrapper> params = new ArrayList<Wrapper> ();
private Object result;
private CallContext context;
private List<String> constraints = null;
/**
* Constructor.
*
* @param componentName String
* @param methodName String
*/
public Call(String id, String componentName, String methodName)
{
this.id = id;
this.componentName = componentName;
this.methodName = methodName;
this.context = new CallContext();
}
/**
* Return the call context.
*
* @return CallContext
*/
public CallContext getContext()
{
return context;
}
/**
* Add a parameter to this call.
*
* @param param BaseWrapper
*/
public void addParameter(Wrapper param)
{
params.add(param);
}
/**
* Returns the result of this call.
*
* @return Wrapper
*/
public Object getResult()
{
return result;
}
/**
* Returns the id of this call.
*
* @return String
*/
public String getId()
{
return id;
}
/**
* Returns the object graph constraints annotated on the method that is called.
*
* @return List The constraints
*/
public List<String> getConstraints()
{
return constraints;
}
/**
* Execute this call
*
* @throws Exception
*/
public void execute()
throws Exception
{
// Find the component we're calling
Component component = Component.forName(componentName);
if (component == null)
throw new RuntimeException("No such component: " + componentName);
// Create an instance of the component
Object instance = Component.getInstance(componentName, true);
Class type = null;
if (component.getType().isSessionBean() &&
component.getBusinessInterfaces().size() > 0)
{
for (Class c : component.getBusinessInterfaces())
{
if (c.isAnnotationPresent(EJB.LOCAL))
{
type = component.getBusinessInterfaces().iterator().next();
break;
}
}
if (type == null)
throw new RuntimeException(String.format(
"Type cannot be determined for component [%s]. Please ensure that it has a local interface.", component));
}
if (type == null)
type = component.getBeanClass();
// Find the method according to the method name and the parameter classes
Method m = findMethod(methodName, type);
if (m == null)
throw new RuntimeException("No compatible method found.");
if (m.getAnnotation(WebRemote.class).exclude().length > 0)
constraints = Arrays.asList(m.getAnnotation(WebRemote.class).exclude());
// Invoke!
result = m.invoke(instance, convertParams(m.getGenericParameterTypes()));
}
/**
* Convert our parameter values to an Object array of the specified target
* types.
*
* @param targetTypes Class[] An array containing the target class types.
* @return Object[] The converted parameter values.
*/
private Object[] convertParams(Type[] targetTypes)
throws ConversionException
{
Object[] paramValues = new Object[targetTypes.length];
for (int i = 0; i < targetTypes.length; i++)
paramValues[i] = params.get(i).convert(targetTypes[i]);
return paramValues;
}
/**
* Find the best matching method within the specified class according to
* the parameter types that were provided to the Call.
*
* @param name String The name of the method.
* @param cls Class The Class to search in.
* @return Method The best matching method.
*/
private Method findMethod(String name, Class cls)
{
Map<Method, Integer> candidates = new HashMap<Method, Integer> ();
for (Method m : cls.getDeclaredMethods()) {
if (m.getAnnotation(WebRemote.class) == null)
continue;
if (name.equals(m.getName()) &&
m.getParameterTypes().length == params.size()) {
int score = 0;
for (int i = 0; i < m.getParameterTypes().length; i++) {
ConversionScore convScore = params.get(i).conversionScore(m.getParameterTypes()[
i]);
if (convScore == ConversionScore.nomatch)
continue;
score += convScore.getScore();
}
candidates.put(m, score);
}
}
Method bestMethod = null;
int bestScore = 0;
for (Method m : candidates.keySet()) {
int thisScore = candidates.get(m).intValue();
if (bestMethod == null || thisScore > bestScore) {
bestMethod = m;
bestScore = thisScore;
}
}
return bestMethod;
}
}
1.1 date: 2007/02/27 22:15:23; author: sbryzak2; state: Exp;jboss-seam/src/remoting/org/jboss/seam/remoting/CallContext.java
Index: CallContext.java
===================================================================
package org.jboss.seam.remoting;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.dom4j.Element;
import org.jboss.seam.remoting.wrapper.Wrapper;
import org.jboss.seam.remoting.wrapper.WrapperFactory;
/**
* Represents the context of an individual call.
*
* @author Shane Bryzak
*/
public class CallContext
{
/**
* Contains references to inbound bean objects identified by their ref.
*/
private Map<String, Wrapper> inRefs = new HashMap<String, Wrapper>();
/**
* Contains references to outbound bean objects identified by their object.
*/
private List<Wrapper> outRefs = new ArrayList<Wrapper>();
/**
*
* @param element Element
* @return Wrapper
*/
public Wrapper createWrapperFromElement(Element element)
{
if ("ref".equals(element.getQualifiedName()))
{
if (inRefs.containsKey(element.attributeValue("id")))
return inRefs.get(element.attributeValue("id"));
else
{
Element value = (Element) element.elements().get(0);
Wrapper w = WrapperFactory.getInstance().createWrapper(value.getQualifiedName());
w.setElement(value);
w.setCallContext(this);
inRefs.put(element.attributeValue("id"), w);
return w;
}
}
else
{
Wrapper w = WrapperFactory.getInstance().createWrapper(element.getQualifiedName());
w.setElement(element);
w.setCallContext(this);
return w;
}
}
/**
*
* @return Wrapper
*/
public Wrapper createWrapperFromObject(Object value, String path)
{
// Not very efficient but has to be done - may implement something better later
for (Wrapper ref : outRefs)
{
if (ref.getValue().equals(value))
return ref;
}
Wrapper w = WrapperFactory.getInstance().getWrapperForObject(value);
w.setCallContext(this);
w.setPath(path);
return w;
}
/**
* Returns the inbound object references
*
* @return Map
*/
public Map<String, Wrapper> getInRefs()
{
return inRefs;
}
/**
* Returns the outbound object references
*
* @return List
*/
public List<Wrapper> getOutRefs()
{
return outRefs;
}
/**
* Add an outbound object reference
*
* @param w Wrapper
*/
public void addOutRef(Wrapper w)
{
if (!outRefs.contains(w))
outRefs.add(w);
}
}
1.1 date: 2007/02/27 22:15:23; author: sbryzak2; state: Exp;jboss-seam/src/remoting/org/jboss/seam/remoting/ExecutionHandler.java
Index: ExecutionHandler.java
===================================================================
package org.jboss.seam.remoting;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.faces.event.PhaseId;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.jboss.seam.log.LogProvider;
import org.jboss.seam.log.Logging;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.jboss.seam.contexts.ContextAdaptor;
import org.jboss.seam.contexts.Lifecycle;
import org.jboss.seam.core.Manager;
import org.jboss.seam.remoting.wrapper.Wrapper;
/**
* Unmarshals the calls from an HttpServletRequest, executes them in order and
* marshals the responses.
*
* @author Shane Bryzak
*/
public class ExecutionHandler extends BaseRequestHandler implements RequestHandler
{
private static final LogProvider log = Logging.getLogProvider(ExecutionHandler.class);
private static final byte[] HEADER_OPEN = "<header>".getBytes();
private static final byte[] HEADER_CLOSE = "</header>".getBytes();
private static final byte[] CONVERSATION_ID_TAG_OPEN = "<conversationId>".getBytes();
private static final byte[] CONVERSATION_ID_TAG_CLOSE = "</conversationId>".getBytes();
private static final byte[] CONTEXT_TAG_OPEN = "<context>".getBytes();
private static final byte[] CONTEXT_TAG_CLOSE = "</context>".getBytes();
private ServletContext servletContext;
@Override
public void setServletContext(ServletContext ctx)
{
this.servletContext = ctx;
}
/**
* The entry point for handling a request.
*
* @param request HttpServletRequest
* @param response HttpServletResponse
* @throws Exception
*/
public void handle(HttpServletRequest request, HttpServletResponse response)
throws Exception
{
try
{
// We're sending an XML response, so set the response content type to text/xml
response.setContentType("text/xml");
// Parse the incoming request as XML
SAXReader xmlReader = new SAXReader();
Document doc = xmlReader.read(request.getInputStream());
Element env = doc.getRootElement();
RequestContext ctx = unmarshalContext(env);
// Reinstate the Seam conversation
HttpSession session = request.getSession(true);
Lifecycle.setPhaseId(PhaseId.INVOKE_APPLICATION);
Lifecycle.setServletRequest(request);
Lifecycle.beginRequest(servletContext, session, request);
Manager.instance().restoreConversation( ctx.getConversationId() );
Lifecycle.resumeConversation(session);
// Extract the calls from the request
List<Call> calls = unmarshalCalls(env);
// Execute each of the calls
for (Call call : calls) {
call.execute();
}
// Store the conversation ID in the outgoing context
ctx.setConversationId( Manager.instance().getCurrentConversationId() );
Manager.instance().endRequest( ContextAdaptor.getSession(session) );
Lifecycle.endRequest();
// Package up the response
marshalResponse(calls, ctx, response.getOutputStream());
}
catch (Exception ex)
{
log.error("Error during remote request", ex);
Lifecycle.endRequest();
}
finally
{
Lifecycle.setServletRequest(null);
Lifecycle.setPhaseId(null);
log.debug("ended request");
}
}
/**
* Unmarshals the context from the request envelope header.
*
* @param env Element
* @return RequestContext
*/
private RequestContext unmarshalContext(Element env)
{
RequestContext ctx = new RequestContext();
Element header = env.element("header");
if (header != null)
{
Element context = header.element("context");
if (context != null)
{
Element convId = context.element("conversationId");
if (convId != null)
ctx.setConversationId(convId.getText());
}
}
return ctx;
}
/**
* Unmarshal the request into a list of Calls.
*
* @param env Element
* @throws Exception
*/
private List<Call> unmarshalCalls(Element env)
throws Exception
{
try {
List<Call> calls = new ArrayList<Call>();
List<Element> callElements = env.element("body").elements("call");
for (Element e : callElements) {
Call call = new Call(e.attributeValue("id"),
e.attributeValue("component"),
e.attributeValue("method"));
// First reconstruct all the references
Element refsNode = e.element("refs");
Iterator iter = refsNode.elementIterator("ref");
while (iter.hasNext())
{
call.getContext().createWrapperFromElement((Element) iter.next());
}
// Now unmarshal the ref values
for (Wrapper w : call.getContext().getInRefs().values())
w.unmarshal();
Element paramsNode = e.element("params");
// Then process the param values
iter = paramsNode.elementIterator("param");
while (iter.hasNext()) {
Element param = (Element) iter.next();
call.addParameter(call.getContext().createWrapperFromElement(
(Element) param.elementIterator().next()));
}
calls.add(call);
}
return calls;
}
catch (Exception ex) {
log.error("Error unmarshalling calls from request", ex);
throw ex;
}
}
/**
* Write the results to the output stream.
*
* @param calls List The list of calls to write
* @param out OutputStream The stream to write to
* @throws IOException
*/
private void marshalResponse(List<Call> calls, RequestContext ctx, OutputStream out)
throws IOException
{
out.write(ENVELOPE_TAG_OPEN);
if (ctx.getConversationId() != null)
{
out.write(HEADER_OPEN);
out.write(CONTEXT_TAG_OPEN);
out.write(CONVERSATION_ID_TAG_OPEN);
out.write(ctx.getConversationId().getBytes());
out.write(CONVERSATION_ID_TAG_CLOSE);
out.write(CONTEXT_TAG_CLOSE);
out.write(HEADER_CLOSE);
}
out.write(BODY_TAG_OPEN);
for (Call call : calls)
{
MarshalUtils.marshalResult(call.getId(), call.getContext(), out,
call.getResult(), call.getConstraints());
}
out.write(BODY_TAG_CLOSE);
out.write(ENVELOPE_TAG_CLOSE);
out.flush();
}
}
1.1 date: 2007/02/27 22:15:23; author: sbryzak2; state: Exp;jboss-seam/src/remoting/org/jboss/seam/remoting/InterfaceGenerator.java
Index: InterfaceGenerator.java
===================================================================
package org.jboss.seam.remoting;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.faces.event.PhaseId;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.jboss.seam.log.LogProvider;
import org.jboss.seam.log.Logging;
import org.jboss.seam.Component;
import org.jboss.seam.ComponentType;
import org.jboss.seam.Seam;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.WebRemote;
import org.jboss.seam.contexts.Lifecycle;
import org.jboss.seam.util.EJB;
import org.jboss.seam.util.Reflections;
/**
* Generates JavaScript interface code.
*
* @author Shane Bryzak
*/
public class InterfaceGenerator extends BaseRequestHandler implements RequestHandler
{
private static final LogProvider log = Logging.getLogProvider(InterfaceGenerator.class);
/**
* Maintain a cache of the accessible fields
*/
private static Map<Class,Set<String>> accessibleProperties = new HashMap<Class,Set<String>>();
/**
* A cache of component interfaces, keyed by component name.
*/
private Map<String,byte[]> interfaceCache = new HashMap<String,byte[]>();
private ServletContext servletContext;
@Override
public void setServletContext(ServletContext ctx)
{
this.servletContext = ctx;
}
/**
*
* @param request HttpServletRequest
* @param response HttpServletResponse
* @throws Exception
*/
public void handle(HttpServletRequest request, HttpServletResponse response)
throws Exception
{
try
{
HttpSession session = request.getSession(true);
Lifecycle.setPhaseId(PhaseId.INVOKE_APPLICATION);
Lifecycle.setServletRequest(request);
Lifecycle.beginRequest(servletContext, session, request);
String[] componentNames = request.getQueryString().split("&");
Component[] components = new Component[componentNames.length];
Set<Type> types = new HashSet<Type>();
for (int i = 0; i < componentNames.length; i++) {
components[i] = Component.forName(componentNames[i]);
if (components[i] == null)
{
try
{
Class c = Reflections.classForName(componentNames[i]);
appendClassSource(response.getOutputStream(), c, types);
}
catch (ClassNotFoundException ex)
{
log.error(String.format("Component not found: [%s]", componentNames[i]));
throw new ServletException("Invalid request - component not found.");
}
}
}
generateComponentInterface(components, response.getOutputStream(), types);
}
finally
{
Lifecycle.setServletRequest(null);
Lifecycle.setPhaseId(null);
}
}
/**
* Generates the JavaScript code required to invoke the methods of a component/s.
*
* @param components Component[] The components to generate javascript for
* @param out OutputStream The OutputStream to write the generated javascript to
* @throws IOException Thrown if there is an error writing to the OutputStream
*/
public void generateComponentInterface(Component[] components, OutputStream out, Set<Type> types)
throws IOException
{
for (Component c : components)
{
if (c != null)
{
if (!interfaceCache.containsKey(c.getName()))
{
synchronized (interfaceCache)
{
if (!interfaceCache.containsKey(c.getName()))
{
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
appendComponentSource(bOut, c, types);
interfaceCache.put(c.getName(), bOut.toByteArray());
}
}
}
out.write(interfaceCache.get(c.getName()));
}
}
}
/**
* A helper method, used internally by InterfaceGenerator and also when
* serializing responses. Returns a list of the property names for the specified
* class which should be included in the generated interface for the type.
*
* @param cls Class
* @return List
*/
public static Set<String> getAccessibleProperties(Class cls)
{
/** @todo This is a hack to get the "real" class - find out if there is
an API method in CGLIB that can be used instead */
if (cls.getName().contains("EnhancerByCGLIB"))
cls = cls.getSuperclass();
if (!accessibleProperties.containsKey(cls))
{
synchronized(accessibleProperties)
{
if (!accessibleProperties.containsKey(cls))
{
Set<String> properties = new HashSet<String>();
Class c = cls;
while (c != null && !c.equals(Object.class))
{
for (Field f : c.getDeclaredFields())
{
if (!Modifier.isTransient(f.getModifiers()) &&
!Modifier.isStatic(f.getModifiers()))
{
String fieldName = f.getName().substring(0, 1).toUpperCase() +
f.getName().substring(1);
String getterName = String.format("get%s", fieldName);
String setterName = String.format("set%s", fieldName);
Method getMethod = null;
Method setMethod = null;
try
{
getMethod = c.getMethod(getterName);
}
catch (SecurityException ex)
{}
catch (NoSuchMethodException ex)
{
// it might be an "is" method...
getterName = String.format("is%s", fieldName);
try
{
getMethod = c.getMethod(getterName);
}
catch (NoSuchMethodException ex2)
{ /* don't care */}
}
try
{
setMethod = c.getMethod(setterName, new Class[] {f.getType()});
}
catch (SecurityException ex)
{}
catch (NoSuchMethodException ex)
{ /* don't care */}
if (Modifier.isPublic(f.getModifiers()) ||
(getMethod != null &&
Modifier.isPublic(getMethod.getModifiers()) ||
(setMethod != null &&
Modifier.isPublic(setMethod.getModifiers()))))
{
properties.add(f.getName());
}
}
}
//
for (Method m : c.getDeclaredMethods())
{
if (m.getName().startsWith("get") || m.getName().startsWith("is"))
{
int startIdx = m.getName().startsWith("get") ? 3 : 2;
try
{
c.getMethod(String.format("set%s",
m.getName().substring(startIdx)), m.getReturnType());
}
catch (NoSuchMethodException ex)
{
continue;
}
String propertyName = String.format("%s%s",
Character.toLowerCase(m.getName().charAt(startIdx)),
m.getName().substring(startIdx + 1));
if (!properties.contains(propertyName))
properties.add(propertyName);
}
}
c = c.getSuperclass();
}
accessibleProperties.put(cls, properties);
}
}
}
return accessibleProperties.get(cls);
}
/**
* Appends component interface code to an outputstream for a specified component.
*
* @param out OutputStream The OutputStream to write to
* @param component Component The component to generate an interface for
* @param types Set A list of types that have already been generated for this
* request. If this component has already been generated (i.e. it is in the list)
* then it won't be generated again
* @throws IOException If there is an error writing to the OutputStream.
*/
private void appendComponentSource(OutputStream out, Component component, Set<Type> types)
throws IOException
{
StringBuilder componentSrc = new StringBuilder();
Class type = null;
if (component.getType().isSessionBean() &&
component.getBusinessInterfaces().size() > 0)
{
for (Class c : component.getBusinessInterfaces())
{
if (c.isAnnotationPresent(EJB.LOCAL))
{
type = component.getBusinessInterfaces().iterator().next();
break;
}
}
if (type == null)
throw new RuntimeException(String.format(
"Type cannot be determined for component [%s]. Please ensure that it has a local interface.", component));
}
else if (component.getType().equals(ComponentType.ENTITY_BEAN))
{
appendTypeSource(out, component.getBeanClass(), types);
return;
}
else if (component.getType().equals(ComponentType.JAVA_BEAN))
{
// Check if any of the methods are annotated with @WebRemote, and if so
// treat it as an "action" component instead of a type component
for (Method m : component.getBeanClass().getDeclaredMethods())
{
if (m.getAnnotation(WebRemote.class) != null)
{
type = component.getBeanClass();
break;
}
}
if (type == null)
{
appendTypeSource(out, component.getBeanClass(), types);
return;
}
}
else
type = component.getBeanClass();
if (types.contains(type))
return;
types.add(type);
componentSrc.append("Seam.Remoting.type.");
componentSrc.append(component.getName());
componentSrc.append(" = function() {\n");
componentSrc.append(" this.__callback = new Object();\n");
for (Method m : type.getDeclaredMethods())
{
if (m.getAnnotation(WebRemote.class) == null)
continue;
// Append the return type to the source block
appendTypeSource(out, m.getGenericReturnType(), types);
componentSrc.append(" Seam.Remoting.type.");
componentSrc.append(component.getName());
componentSrc.append(".prototype.");
componentSrc.append(m.getName());
componentSrc.append(" = function(");
// Insert parameters p0..pN
for (int i = 0; i < m.getGenericParameterTypes().length; i++)
{
appendTypeSource(out, m.getGenericParameterTypes()[i], types);
if (i > 0)
componentSrc.append(", ");
componentSrc.append("p");
componentSrc.append(i);
}
if (m.getGenericParameterTypes().length > 0)
componentSrc.append(", ");
componentSrc.append("callback) {\n");
componentSrc.append(" return Seam.Remoting.execute(this, \"");
componentSrc.append(m.getName());
componentSrc.append("\", [");
for (int i = 0; i < m.getParameterTypes().length; i++)
{
if (i > 0)
componentSrc.append(", ");
componentSrc.append("p");
componentSrc.append(i);
}
componentSrc.append("], callback);\n");
componentSrc.append(" }\n");
}
componentSrc.append("}\n");
// Set the component name
componentSrc.append("Seam.Remoting.type.");
componentSrc.append(component.getName());
componentSrc.append(".__name = \"");
componentSrc.append(component.getName());
componentSrc.append("\";\n\n");
// Register the component
componentSrc.append("Seam.Component.register(Seam.Remoting.type.");
componentSrc.append(component.getName());
componentSrc.append(");\n\n");
out.write(componentSrc.toString().getBytes());
}
/**
* Append Javascript interface code for a specified class to a block of code.
*
* @param source StringBuilder The code block to append to
* @param type Class The type to generate a Javascript interface for
* @param types Set A list of the types already generated (only include each type once).
*/
private void appendTypeSource(OutputStream out, Type type, Set<Type> types)
throws IOException
{
if (type instanceof Class)
{
Class classType = (Class) type;
if (classType.isArray())
{
appendTypeSource(out, classType.getComponentType(), types);
return;
}
if (classType.getName().startsWith("java.") ||
types.contains(type) || classType.isPrimitive())
return;
// Keep track of which types we've already added
types.add(type);
appendClassSource(out, classType, types);
}
else if (type instanceof ParameterizedType)
{
for (Type t : ((ParameterizedType) type).getActualTypeArguments())
appendTypeSource(out, t, types);
}
}
/**
* Appends the interface code for a non-component class to an OutputStream.
*
* @param out OutputStream
* @param classType Class
* @param types Set
* @throws IOException
*/
private void appendClassSource(OutputStream out, Class classType, Set<Type> types)
throws IOException
{
// Don't generate interfaces for enums
if (classType.isEnum())
return;
StringBuilder typeSource = new StringBuilder();
// Determine whether this class is a component; if so, use its name
// otherwise use its class name.
String componentName = Seam.getComponentName(classType);
if (componentName == null)
componentName = classType.getName();
String typeName = componentName.replace('.', '$');
typeSource.append("Seam.Remoting.type.");
typeSource.append(typeName);
typeSource.append(" = function() {\n");
StringBuilder fields = new StringBuilder();
StringBuilder accessors = new StringBuilder();
StringBuilder mutators = new StringBuilder();
Map<String,String> metadata = new HashMap<String,String>();
String getMethodName = null;
String setMethodName = null;
for ( String propertyName : getAccessibleProperties(classType) )
{
Type propertyType = null;
Field f = null;
try
{
f = classType.getDeclaredField(propertyName);
propertyType = f.getGenericType();
}
catch (NoSuchFieldException ex)
{
setMethodName = String.format("set%s%s",
Character.toUpperCase(propertyName.charAt(0)),
propertyName.substring(1));
try
{
getMethodName = String.format("get%s%s",
Character.toUpperCase(propertyName.charAt(0)),
propertyName.substring(1));
propertyType = classType.getMethod(getMethodName).getGenericReturnType();
}
catch (NoSuchMethodException ex2)
{
try
{
getMethodName = String.format("is%s%s",
Character.toUpperCase(propertyName.charAt(0)),
propertyName.substring(1));
propertyType = classType.getMethod(getMethodName).getGenericReturnType();
}
catch (NoSuchMethodException ex3)
{
// ???
continue;
}
}
}
appendTypeSource(out, propertyType, types);
// Include types referenced by generic declarations
if (propertyType instanceof ParameterizedType)
{
for (Type t : ((ParameterizedType) propertyType).getActualTypeArguments())
{
if (t instanceof Class)
appendTypeSource(out, t, types);
}
}
if (f != null)
{
String fieldName = propertyName.substring(0, 1).toUpperCase() +
propertyName.substring(1);
String getterName = String.format("get%s", fieldName);
String setterName = String.format("set%s", fieldName);
try
{
classType.getMethod(getterName);
getMethodName = getterName;
}
catch (SecurityException ex){}
catch (NoSuchMethodException ex)
{
getterName = String.format("is%s", fieldName);
try
{
if (Modifier.isPublic(classType.getMethod(getterName).getModifiers()))
getMethodName = getterName;
}
catch (NoSuchMethodException ex2)
{ /* don't care */}
}
try
{
if (Modifier.isPublic(classType.getMethod(setterName, f.getType()).getModifiers()))
setMethodName = setterName;
}
catch (SecurityException ex) {}
catch (NoSuchMethodException ex) { /* don't care */}
}
// Construct the list of fields.
if (getMethodName != null || setMethodName != null)
{
metadata.put(propertyName, getFieldType(propertyType));
fields.append(" this.");
fields.append(propertyName);
fields.append(" = undefined;\n");
if (getMethodName != null)
{
accessors.append(" Seam.Remoting.type.");
accessors.append(typeName);
accessors.append(".prototype.");
accessors.append(getMethodName);
accessors.append(" = function() { return this.");
accessors.append(propertyName);
accessors.append("; }\n");
}
if (setMethodName != null)
{
mutators.append(" Seam.Remoting.type.");
mutators.append(typeName);
mutators.append(".prototype.");
mutators.append(setMethodName);
mutators.append(" = function(");
mutators.append(propertyName);
mutators.append(") { this.");
mutators.append(propertyName);
mutators.append(" = ");
mutators.append(propertyName);
mutators.append("; }\n");
}
}
}
typeSource.append(fields);
typeSource.append(accessors);
typeSource.append(mutators);
typeSource.append("}\n\n");
// Append the type name
typeSource.append("Seam.Remoting.type.");
typeSource.append(typeName);
typeSource.append(".__name = \"");
typeSource.append(componentName);
typeSource.append("\";\n");
// Append the metadata
typeSource.append("Seam.Remoting.type.");
typeSource.append(typeName);
typeSource.append(".__metadata = [\n");
boolean first = true;
for (String key : metadata.keySet())
{
if (!first)
typeSource.append(",\n");
typeSource.append(" {field: \"");
typeSource.append(key);
typeSource.append("\", type: \"");
typeSource.append(metadata.get(key));
typeSource.append("\"}");
first = false;
}
typeSource.append("];\n\n");
// Register the type under Seam.Component if it is a component, otherwise
// register it under Seam.Remoting
if (classType.isAnnotationPresent(Name.class))
typeSource.append("Seam.Component.register(Seam.Remoting.type.");
else
typeSource.append("Seam.Remoting.registerType(Seam.Remoting.type.");
typeSource.append(typeName);
typeSource.append(");\n\n");
out.write(typeSource.toString().getBytes());
}
/**
* Returns the remoting "type" for a specified class.
*
* @param type Class
* @return String
*/
protected String getFieldType(Type type)
{
if (type.equals(String.class) ||
(type instanceof Class && ( (Class) type).isEnum()) ||
type.equals(BigInteger.class) || type.equals(BigDecimal.class))
return "str";
else if (type.equals(Boolean.class) || type.equals(Boolean.TYPE))
return "bool";
else if (type.equals(Short.class) || type.equals(Short.TYPE) ||
type.equals(Integer.class) || type.equals(Integer.TYPE) ||
type.equals(Long.class) || type.equals(Long.TYPE) ||
type.equals(Float.class) || type.equals(Float.TYPE) ||
type.equals(Double.class) || type.equals(Double.TYPE) ||
type.equals(Byte.class) || type.equals(Byte.TYPE))
return "number";
else if (type instanceof Class)
{
Class cls = (Class) type;
if (Date.class.isAssignableFrom(cls))
return "date";
else if (cls.isArray())
return "bag";
else if (cls.isAssignableFrom(Map.class))
return "map";
else if (cls.isAssignableFrom(Collection.class))
return "bag";
}
else if (type instanceof ParameterizedType)
{
ParameterizedType pt = (ParameterizedType) type;
if (pt.getRawType() instanceof Class && Map.class.isAssignableFrom((Class) pt.getRawType()))
return "map";
else if (pt.getRawType() instanceof Class && Collection.class.isAssignableFrom((Class) pt.getRawType()))
return "bag";
}
return "bean";
}
}
1.1 date: 2007/02/27 22:15:23; author: sbryzak2; state: Exp;jboss-seam/src/remoting/org/jboss/seam/remoting/MarshalUtils.java
Index: MarshalUtils.java
===================================================================
package org.jboss.seam.remoting;
import java.io.OutputStream;
import java.io.IOException;
import org.jboss.seam.remoting.wrapper.BeanWrapper;
import org.jboss.seam.remoting.wrapper.Wrapper;
import java.util.List;
/**
*
*
* @author Shane Bryzak
*/
public class MarshalUtils
{
private static final byte[] RESULT_TAG_OPEN_START = "<result id=\"".getBytes();
private static final byte[] RESULT_TAG_OPEN_END = "\">".getBytes();
private static final byte[] RESULT_TAG_OPEN = "<result>".getBytes();
private static final byte[] RESULT_TAG_CLOSE = "</result>".getBytes();
private static final byte[] VALUE_TAG_OPEN = "<value>".getBytes();
private static final byte[] VALUE_TAG_CLOSE = "</value>".getBytes();
public static void marshalResult(String callId, CallContext ctx, OutputStream out,
Object result, List<String> constraints)
throws IOException
{
if (callId != null)
{
out.write(RESULT_TAG_OPEN_START);
out.write(callId.getBytes());
out.write(RESULT_TAG_OPEN_END);
}
else
out.write(RESULT_TAG_OPEN);
out.write(VALUE_TAG_OPEN);
ctx.createWrapperFromObject(result, "").marshal(out);
out.write(VALUE_TAG_CLOSE);
out.write(RequestHandler.REFS_TAG_OPEN);
// Using a for-loop, because stuff can get added to outRefs as we recurse the object graph
for (int i = 0; i < ctx.getOutRefs().size(); i++)
{
Wrapper wrapper = ctx.getOutRefs().get(i);
out.write(RequestHandler.REF_TAG_OPEN_START);
out.write(Integer.toString(i).getBytes());
out.write(RequestHandler.REF_TAG_OPEN_END);
if (wrapper instanceof BeanWrapper && constraints != null)
((BeanWrapper) wrapper).serialize(out, constraints);
else
wrapper.serialize(out);
out.write(RequestHandler.REF_TAG_CLOSE);
}
out.write(RequestHandler.REFS_TAG_CLOSE);
out.write(RESULT_TAG_CLOSE);
}
}
1.1 date: 2007/02/27 22:15:23; author: sbryzak2; state: Exp;jboss-seam/src/remoting/org/jboss/seam/remoting/PollHandler.java
Index: PollHandler.java
===================================================================
package org.jboss.seam.remoting;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import javax.faces.event.PhaseId;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.ObjectMessage;
import javax.jms.TextMessage;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.jboss.seam.log.LogProvider;
import org.jboss.seam.log.Logging;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.jboss.seam.contexts.Lifecycle;
import org.jboss.seam.remoting.messaging.PollError;
import org.jboss.seam.remoting.messaging.PollRequest;
import org.jboss.seam.remoting.wrapper.Wrapper;
/**
* Handles JMS Message poll requests.
*
* @author Shane Bryzak
*/
public class PollHandler extends BaseRequestHandler implements RequestHandler
{
private static final LogProvider log = Logging.getLogProvider(SubscriptionHandler.class);
private static final byte[] ERRORS_TAG_OPEN_START = "<errors token=\"".getBytes();
private static final byte[] ERRORS_TAG_OPEN_END = "\">".getBytes();
private static final byte[] ERROR_TAG_OPEN_START = "<error code=\"".getBytes();
private static final byte[] ERROR_TAG_OPEN_END = "\">".getBytes();
private static final byte[] ERROR_TAG_CLOSE = "</error>".getBytes();
private static final byte[] MESSAGES_TAG_OPEN_START = "<messages token=\"".getBytes();
private static final byte[] MESSAGES_TAG_OPEN_END = "\">".getBytes();
private static final byte[] MESSAGES_TAG_CLOSE = "</messages>".getBytes();
private static final byte[] MESSAGE_TAG_OPEN_START = "<message type=\"".getBytes();
private static final byte[] MESSAGE_TAG_OPEN_END = "\">".getBytes();
private static final byte[] MESSAGE_TAG_CLOSE = "</message>".getBytes();
private static final byte[] VALUE_TAG_OPEN = "<value>".getBytes();
private static final byte[] VALUE_TAG_CLOSE = "</value>".getBytes();
private ServletContext servletContext;
@Override
public void setServletContext(ServletContext ctx)
{
this.servletContext = ctx;
}
public void handle(HttpServletRequest request, HttpServletResponse response)
throws Exception
{
// We're sending an XML response, so set the response content type to text/xml
response.setContentType("text/xml");
// Parse the incoming request as XML
SAXReader xmlReader = new SAXReader();
Document doc = xmlReader.read(request.getInputStream());
Element env = doc.getRootElement();
List<PollRequest> polls = unmarshalRequests(env);
try
{
HttpSession session = request.getSession(true);
Lifecycle.setPhaseId(PhaseId.INVOKE_APPLICATION);
Lifecycle.setServletRequest(request);
Lifecycle.beginRequest(servletContext, session, request);
for (PollRequest req : polls)
req.poll();
}
finally
{
Lifecycle.endRequest();
Lifecycle.setServletRequest(null);
Lifecycle.setPhaseId(null);
}
// Package up the response
marshalResponse(polls, response.getOutputStream());
}
private List<PollRequest> unmarshalRequests(Element env)
throws Exception
{
try
{
List<PollRequest> requests = new ArrayList<PollRequest>();
List<Element> requestElements = env.element("body").elements("poll");
for (Element e : requestElements)
{
requests.add(new PollRequest(e.attributeValue("token"),
Integer.parseInt(e.attributeValue("timeout"))));
}
return requests;
}
catch (Exception ex)
{
log.error("Error unmarshalling subscriptions from request", ex);
throw ex;
}
}
private void marshalResponse(List<PollRequest> reqs, OutputStream out)
throws IOException
{
out.write(ENVELOPE_TAG_OPEN);
out.write(BODY_TAG_OPEN);
for (PollRequest req : reqs)
{
if (req.getErrors() != null && req.getErrors().size() > 0)
{
out.write(ERRORS_TAG_OPEN_START);
out.write(req.getToken().getBytes());
out.write(ERRORS_TAG_OPEN_END);
for (PollError err : req.getErrors())
{
writeError(err, out);
}
}
else if (req.getMessages() != null && req.getMessages().size() > 0)
{
out.write(MESSAGES_TAG_OPEN_START);
out.write(req.getToken().getBytes());
out.write(MESSAGES_TAG_OPEN_END);
for (Message m : req.getMessages()) {
try {
writeMessage(m, out);
}
catch (JMSException ex) {
}
catch (IOException ex) {
}
}
out.write(MESSAGES_TAG_CLOSE);
}
}
out.write(BODY_TAG_CLOSE);
out.write(ENVELOPE_TAG_CLOSE);
out.flush();
}
private void writeMessage(Message m, OutputStream out)
throws IOException, JMSException
{
out.write(MESSAGE_TAG_OPEN_START);
// We need one of these to maintain a list of outbound references
CallContext ctx = new CallContext();
Object value = null;
if (m instanceof TextMessage)
{
out.write("text".getBytes());
value = ((TextMessage) m).getText();
}
else if (m instanceof ObjectMessage)
{
out.write("object".getBytes());
value = ((ObjectMessage) m).getObject();
}
out.write(MESSAGE_TAG_OPEN_END);
out.write(VALUE_TAG_OPEN);
ctx.createWrapperFromObject(value, "").marshal(out);
out.write(VALUE_TAG_CLOSE);
out.write(REFS_TAG_OPEN);
// Using a for-loop, because stuff can get added to outRefs as we recurse the object graph
for (int i = 0; i < ctx.getOutRefs().size(); i++)
{
Wrapper wrapper = ctx.getOutRefs().get(i);
out.write(REF_TAG_OPEN_START);
out.write(Integer.toString(i).getBytes());
out.write(REF_TAG_OPEN_END);
wrapper.serialize(out);
out.write(REF_TAG_CLOSE);
}
out.write(REFS_TAG_CLOSE);
out.write(MESSAGE_TAG_CLOSE);
}
private void writeError(PollError error, OutputStream out)
throws IOException
{
out.write(ERROR_TAG_OPEN_START);
out.write(error.getCode().getBytes());
out.write(ERROR_TAG_OPEN_END);
out.write(error.getMessage().getBytes());
out.write(ERROR_TAG_CLOSE);
}
}
1.1 date: 2007/02/27 22:15:23; author: sbryzak2; state: Exp;jboss-seam/src/remoting/org/jboss/seam/remoting/Remoting.java
Index: Remoting.java
===================================================================
package org.jboss.seam.remoting;
import static org.jboss.seam.InterceptionType.NEVER;
import static org.jboss.seam.ScopeType.APPLICATION;
import static org.jboss.seam.annotations.Install.BUILT_IN;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.jboss.seam.annotations.Install;
import org.jboss.seam.annotations.Intercept;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.Startup;
import org.jboss.seam.contexts.Lifecycle;
import org.jboss.seam.log.LogProvider;
import org.jboss.seam.log.Logging;
import org.jboss.seam.servlet.AbstractResource;
@Startup
@Scope(APPLICATION)
@Name("org.jboss.seam.remoting.remoting")
@Install(precedence = BUILT_IN)
@Intercept(NEVER)
public class Remoting extends AbstractResource
{
public static final int DEFAULT_POLL_TIMEOUT = 10; // 10 seconds
public static final int DEFAULT_POLL_INTERVAL = 1; // 1 second
private int pollTimeout = DEFAULT_POLL_TIMEOUT;
private int pollInterval = DEFAULT_POLL_INTERVAL;
private boolean debug = false;
/**
* We use a Map for this because a Servlet can serve requests for more than
* one context path.
*/
private Map<String, byte[]> cachedConfig = new HashMap<String, byte[]>();
private static final LogProvider log = Logging.getLogProvider(Remoting.class);
private static final Pattern pathPattern = Pattern.compile("/(.*?)/([^/]+)");
private static final String REMOTING_RESOURCE_PATH = "resource";
@Override
protected String getResourcePath()
{
return "/remoting";
}
private synchronized void initConfig(String contextPath,
HttpSession session, HttpServletRequest request)
{
if (!cachedConfig.containsKey(contextPath))
{
try
{
Lifecycle.beginRequest(getServletContext(), session, request);
StringBuilder sb = new StringBuilder();
sb.append("\nSeam.Remoting.resourcePath = \"");
sb.append(contextPath);
sb.append(request.getServletPath());
sb.append(getResourcePath());
sb.append("\";");
sb.append("\nSeam.Remoting.debug = ");
sb.append(getDebug() ? "true" : "false");
sb.append(";");
sb.append("\nSeam.Remoting.pollInterval = ");
sb.append(getPollInterval());
sb.append(";");
sb.append("\nSeam.Remoting.pollTimeout = ");
sb.append(getPollTimeout());
sb.append(";");
cachedConfig.put(contextPath, sb.toString().getBytes());
}
finally
{
Lifecycle.endRequest(session);
}
}
}
@Override
public void getResource(HttpServletRequest request, HttpServletResponse response)
throws IOException
{
try
{
String pathInfo = request.getPathInfo().substring(getResourcePath().length());
RequestHandler handler = RequestHandlerFactory.getInstance()
.getRequestHandler(pathInfo);
if (handler != null)
{
handler.setServletContext(getServletContext());
handler.handle(request, response);
}
else
{
Matcher m = pathPattern.matcher(pathInfo);
if (m.matches())
{
String path = m.group(1);
String resource = m.group(2);
HttpSession session = request.getSession();
if (REMOTING_RESOURCE_PATH.equals(path))
{
writeResource(resource, response.getOutputStream());
if ("remote.js".equals(resource))
{
appendConfig(response.getOutputStream(), request
.getContextPath(), session, request);
}
}
response.getOutputStream().flush();
}
}
}
catch (Exception ex)
{
log.error("Error", ex);
}
}
/**
* Appends various configuration options to the remoting javascript client
* api.
*
* @param out OutputStream
*/
private void appendConfig(OutputStream out, String contextPath,
HttpSession session, HttpServletRequest request) throws IOException
{
if (!cachedConfig.containsKey(contextPath))
initConfig(contextPath, session, request);
out.write(cachedConfig.get(contextPath));
}
/**
*
* @param resourceName String
* @param out OutputStream
*/
private void writeResource(String resourceName, OutputStream out)
throws IOException
{
// Only allow resource requests for .js files
if (resourceName.endsWith(".js"))
{
InputStream in = this.getClass().getClassLoader().getResourceAsStream(
"org/jboss/seam/remoting/" + resourceName);
if (in != null)
{
byte[] buffer = new byte[1024];
int read = in.read(buffer);
while (read != -1)
{
out.write(buffer, 0, read);
read = in.read(buffer);
}
}
else
log.error(String.format("Resource [%s] not found.", resourceName));
}
}
public int getPollTimeout()
{
return pollTimeout;
}
public void setPollTimeout(int pollTimeout)
{
this.pollTimeout = pollTimeout;
}
public int getPollInterval()
{
return pollInterval;
}
public void setPollInterval(int pollInterval)
{
this.pollInterval = pollInterval;
}
public boolean getDebug()
{
return debug;
}
public void setDebug(boolean debug)
{
this.debug = debug;
}
}
1.1 date: 2007/02/27 22:15:23; author: sbryzak2; state: Exp;jboss-seam/src/remoting/org/jboss/seam/remoting/RequestContext.java
Index: RequestContext.java
===================================================================
package org.jboss.seam.remoting;
/**
*
* @author Shane Bryzak
*/
public class RequestContext
{
private String conversationId;
public String getConversationId()
{
return conversationId;
}
public void setConversationId(String conversationId)
{
this.conversationId = conversationId;
}
}
1.1 date: 2007/02/27 22:15:23; author: sbryzak2; state: Exp;jboss-seam/src/remoting/org/jboss/seam/remoting/RequestHandler.java
Index: RequestHandler.java
===================================================================
package org.jboss.seam.remoting;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
*
* @author Shane Bryzak
*/
public interface RequestHandler
{
static final byte[] ENVELOPE_TAG_OPEN = "<envelope>".getBytes();
static final byte[] ENVELOPE_TAG_CLOSE = "</envelope>".getBytes();
static final byte[] BODY_TAG_OPEN = "<body>".getBytes();
static final byte[] BODY_TAG_CLOSE = "</body>".getBytes();
static final byte[] REFS_TAG_OPEN = "<refs>".getBytes();
static final byte[] REFS_TAG_CLOSE = "</refs>".getBytes();
static final byte[] REF_TAG_OPEN_START = "<ref id=\"".getBytes();
static final byte[] REF_TAG_OPEN_END = "\">".getBytes();
static final byte[] REF_TAG_CLOSE = "</ref>".getBytes();
void handle(HttpServletRequest request, HttpServletResponse response)
throws Exception;
void setServletContext(ServletContext context);
}
1.1 date: 2007/02/27 22:15:23; author: sbryzak2; state: Exp;jboss-seam/src/remoting/org/jboss/seam/remoting/RequestHandlerFactory.java
Index: RequestHandlerFactory.java
===================================================================
package org.jboss.seam.remoting;
import java.util.Map;
import java.util.HashMap;
/**
* Provides request handlers for different request paths.
*
* @author Shane Bryzak
*/
public class RequestHandlerFactory
{
private static final String REQUEST_PATH_EXECUTE = "/execute";
private static final String REQUEST_PATH_SUBSCRIPTION = "/subscription";
private static final String REQUEST_PATH_POLL = "/poll";
private static final String REQUEST_PATH_INTERFACE = "/interface.js";
private static RequestHandlerFactory instance = new RequestHandlerFactory();
private Map<String,RequestHandler> handlers = new HashMap<String,RequestHandler>();
private RequestHandlerFactory()
{
registerHandler(REQUEST_PATH_EXECUTE, new ExecutionHandler());
registerHandler(REQUEST_PATH_SUBSCRIPTION, new SubscriptionHandler());
registerHandler(REQUEST_PATH_POLL, new PollHandler());
registerHandler(REQUEST_PATH_INTERFACE, new InterfaceGenerator());
}
public void registerHandler(String path, RequestHandler handler)
{
handlers.put(path, handler);
}
public RequestHandler getRequestHandler(String path)
{
return handlers.get(path);
}
public static RequestHandlerFactory getInstance()
{
return instance;
}
}
1.1 date: 2007/02/27 22:15:23; author: sbryzak2; state: Exp;jboss-seam/src/remoting/org/jboss/seam/remoting/SubscriptionHandler.java
Index: SubscriptionHandler.java
===================================================================
package org.jboss.seam.remoting;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import javax.faces.event.PhaseId;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.jboss.seam.contexts.Lifecycle;
import org.jboss.seam.core.Manager;
import org.jboss.seam.remoting.messaging.RemoteSubscriber;
import org.jboss.seam.remoting.messaging.SubscriptionRegistry;
import org.jboss.seam.remoting.messaging.SubscriptionRequest;
/**
*
* @author Shane Bryzak
*/
public class SubscriptionHandler extends BaseRequestHandler implements RequestHandler
{
private ServletContext servletContext;
@Override
public void setServletContext(ServletContext ctx)
{
this.servletContext = ctx;
}
/**
* The entry point for handling a request.
*
* @param request HttpServletRequest
* @param response HttpServletResponse
* @throws Exception
*/
public void handle(HttpServletRequest request, HttpServletResponse response)
throws Exception
{
// We're sending an XML response, so set the response content type to text/xml
response.setContentType("text/xml");
// Parse the incoming request as XML
SAXReader xmlReader = new SAXReader();
Document doc = xmlReader.read(request.getInputStream());
Element env = doc.getRootElement();
Element body = env.element("body");
// First handle any new subscriptions
List<SubscriptionRequest> requests = new ArrayList<SubscriptionRequest>();
List<Element> elements = body.elements("subscribe");
for (Element e : elements)
{
requests.add(new SubscriptionRequest(e.attributeValue("topic")));
}
try
{
HttpSession session = request.getSession(true);
Lifecycle.setPhaseId(PhaseId.INVOKE_APPLICATION);
Lifecycle.setServletRequest(request);
Lifecycle.beginRequest(servletContext, session, request);
Manager.instance().initializeTemporaryConversation();
Lifecycle.resumeConversation(session);
for (SubscriptionRequest req : requests)
req.subscribe();
// Then handle any unsubscriptions
List<String> unsubscribeTokens = new ArrayList<String>();
elements = body.elements("unsubscribe");
for (Element e : elements) {
unsubscribeTokens.add(e.attributeValue("token"));
}
for (String token : unsubscribeTokens) {
RemoteSubscriber subscriber = SubscriptionRegistry.instance().
getSubscription(token);
if (subscriber != null)
subscriber.unsubscribe();
}
}
finally
{
Lifecycle.endRequest();
Lifecycle.setServletRequest(null);
Lifecycle.setPhaseId(null);
}
// Package up the response
marshalResponse(requests, response.getOutputStream());
}
private void marshalResponse(List<SubscriptionRequest> requests, OutputStream out)
throws IOException
{
out.write(ENVELOPE_TAG_OPEN);
out.write(BODY_TAG_OPEN);
for (SubscriptionRequest req : requests)
{
req.marshal(out);
}
out.write(BODY_TAG_CLOSE);
out.write(ENVELOPE_TAG_CLOSE);
out.flush();
}
}
1.1 date: 2007/02/27 22:15:23; author: sbryzak2; state: Exp;jboss-seam/src/remoting/org/jboss/seam/remoting/package-info.java
Index: package-info.java
===================================================================
@Namespace(value="http://jboss.com/products/seam/remoting", prefix="org.jboss.seam.remoting")
package org.jboss.seam.remoting;
import org.jboss.seam.annotations.*;
1.1 date: 2007/02/27 22:15:23; author: sbryzak2; state: Exp;jboss-seam/src/remoting/org/jboss/seam/remoting/remote.js
Index: remote.js
===================================================================
// Init base-level objects
var Seam = new Object();
Seam.Remoting = new Object();
Seam.Component = new Object();
Seam.pageContext = new Object();
// Components registered here
Seam.Component.components = new Array();
Seam.Component.instances = new Array();
Seam.Component.newInstance = function(name)
{
for (var i = 0; i < Seam.Component.components.length; i++)
{
if (Seam.Component.components[i].__name == name)
return new Seam.Component.components[i];
}
}
Seam.Component.getInstance = function(name)
{
for (var i = 0; i < Seam.Component.components.length; i++)
{
if (Seam.Component.components[i].__name == name)
{
if (Seam.Component.components[i].__instance == null)
Seam.Component.components[i].__instance = new Seam.Component.components[i]();
return Seam.Component.components[i].__instance;
}
}
return null;
}
Seam.Component.getComponentType = function(obj)
{
for (var i = 0; i < Seam.Component.components.length; i++)
{
if (obj instanceof Seam.Component.components[i])
return Seam.Component.components[i];
}
return null;
}
Seam.Component.getComponentName = function(obj)
{
var componentType = Seam.Component.getComponentType(obj);
return componentType ? componentType.__name : null;
}
Seam.Component.register = function(component)
{
for (var i = 0; i < Seam.Component.components.length; i++)
{
if (Seam.Component.components[i].__name == component.__name)
{
// Replace the existing component with the new one
Seam.Component.components[i] = component;
return;
}
}
Seam.Component.components.push(component);
component.__instance = null;
}
Seam.Component.isRegistered = function(name)
{
for (var i = 0; i < Seam.Component.components.length; i++)
{
if (Seam.Component.components[i].__name == name)
return true;
}
return false;
}
Seam.Component.getMetadata = function(obj)
{
for (var i = 0; i < Seam.Component.components.length; i++)
{
if (obj instanceof Seam.Component.components[i])
return Seam.Component.components[i].__metadata;
}
return null;
}
Seam.Remoting.PATH_EXECUTE = "/execute";
Seam.Remoting.PATH_SUBSCRIPTION = "/subscription";
Seam.Remoting.PATH_POLL = "/poll";
// Type declarations will live in this namespace
Seam.Remoting.type = new Object();
// Types are registered in an array
Seam.Remoting.types = new Array();
Seam.Remoting.debug = false;
Seam.Remoting.debugWindow = null;
Seam.Remoting.setDebug = function(val)
{
Seam.Remoting.debug = val;
}
// Log a message to a popup debug window
Seam.Remoting.log = function(msg)
{
if (!Seam.Remoting.debug)
return;
if (!Seam.Remoting.debugWindow || Seam.Remoting.debugWindow.document == null)
{
var attr = "left=400,top=400,resizable=yes,scrollbars=yes,width=400,height=400";
Seam.Remoting.debugWindow = window.open("", "__seamDebugWindow", attr);
if (Seam.Remoting.debugWindow)
{
Seam.Remoting.debugWindow.document.write("<html><head><title>Seam Debug Window</title></head><body></body></html>");
var bodyTag = Seam.Remoting.debugWindow.document.getElementsByTagName("body").item(0);
bodyTag.style.fontFamily = "arial";
bodyTag.style.fontSize = "8pt";
}
}
if (Seam.Remoting.debugWindow)
{
msg = msg.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
Seam.Remoting.debugWindow.document.write("<pre>" + (new Date()) + ": " + msg + "</pre><br/>");
}
}
Seam.Remoting.__Context = function() {
this.conversationId = null;
Seam.Remoting.__Context.prototype.setConversationId = function(conversationId)
{
this.conversationId = conversationId;
}
Seam.Remoting.__Context.prototype.getConversationId = function()
{
return this.conversationId;
}
}
Seam.Remoting.context = new Seam.Remoting.__Context();
Seam.Remoting.getContext = function()
{
return Seam.Remoting.context;
}
Seam.Remoting.Map = function()
{
this.elements = new Array();
Seam.Remoting.Map.prototype.size = function()
{
return this.elements.length;
}
Seam.Remoting.Map.prototype.isEmpty = function()
{
return this.elements.length == 0;
}
Seam.Remoting.Map.prototype.keySet = function()
{
var keySet = new Array();
for (var i = 0; i < this.elements.length; i++)
keySet[keySet.length] = this.elements[i].key;
return keySet;
}
Seam.Remoting.Map.prototype.values = function()
{
var values = new Array();
for (var i = 0; i < this.elements.length; i++)
values[values.length] = this.elements[i].value;
return values;
}
Seam.Remoting.Map.prototype.get = function(key)
{
for (var i = 0; i < this.elements.length; i++)
{
if (this.elements[i].key == key)
return this.elements[i].value;
}
return null;
}
Seam.Remoting.Map.prototype.put = function(key, value)
{
for (var i = 0; i < this.elements.length; i++)
{
if (this.elements[i].key == key)
{
this.elements[i].value = value;
return;
}
}
this.elements.push({key:key,value:value});
}
Seam.Remoting.Map.prototype.remove = function(key)
{
for (var i = 0; i < this.elements.length; i++)
{
if (this.elements[i].key == key)
this.elements.splice(i, 1);
}
}
Seam.Remoting.Map.prototype.contains = function(key)
{
for (var i = 0; i < this.elements.length; i++)
{
if (this.elements[i].key == key)
return true;
}
return false;
}
}
Seam.Remoting.registerType = function(type)
{
for (var i = 0; i < Seam.Remoting.types.length; i++)
{
if (Seam.Remoting.types[i].__name == type.__name)
{
Seam.Remoting.types[i] = type;
return;
}
}
Seam.Remoting.types.push(type);
}
Seam.Remoting.createType = function(name)
{
for (var i = 0; i < Seam.Remoting.types.length; i++)
{
if (Seam.Remoting.types[i].__name == name)
return new Seam.Remoting.types[i];
}
}
Seam.Remoting.getType = function(obj)
{
for (var i = 0; i < Seam.Remoting.types.length; i++)
{
if (obj instanceof Seam.Remoting.types[i])
return Seam.Remoting.types[i];
}
return null;
}
Seam.Remoting.getTypeName = function(obj)
{
var type = Seam.Remoting.getType(obj);
return type ? type.__name : null;
}
Seam.Remoting.getMetadata = function(obj)
{
for (var i = 0; i < Seam.Remoting.types.length; i++)
{
if (obj instanceof Seam.Remoting.types[i])
return Seam.Remoting.types[i].__metadata;
}
return null;
}
Seam.Remoting.serializeValue = function(value, type, refs)
{
if (value == null)
return "<null/>";
else if (type)
{
switch (type) {
// Boolean
case "bool": return "<bool>" + (value ? "true" : "false") + "</bool>";
// Numerical types
case "number": return "<number>" + value + "</number>";
// Date
case "date": return Seam.Remoting.serializeDate(value);
// Beans
case "bean": return Seam.Remoting.getTypeRef(value, refs);
// Collections
case "bag": return Seam.Remoting.serializeBag(value, refs);
case "map": return Seam.Remoting.serializeMap(value, refs);
default: return "<str>" + encodeURIComponent(value) + "</str>";
}
}
else // We don't know the type.. try to guess
{
switch (typeof(value)) {
case "number":
return "<number>" + value + "</number>";
case "boolean":
return "<bool>" + (value ? "true" : "false") + "</bool>";
case "object":
if (value instanceof Array)
return Seam.Remoting.serializeBag(value, refs);
else if (value instanceof Date)
return Seam.Remoting.serializeDate(value);
else if (value instanceof Seam.Remoting.Map)
return Seam.Remoting.serializeMap(value, refs);
else
return Seam.Remoting.getTypeRef(value, refs);
default:
return "<str>" + encodeURIComponent(value) + "</str>"; // Default to String
}
}
}
Seam.Remoting.serializeBag = function(value, refs)
{
var data = "<bag>";
for (var i = 0; i < value.length; i++)
{
data += "<element>";
data += Seam.Remoting.serializeValue(value[i], null, refs);
data += "</element>";
}
data += "</bag>";
return data;
}
Seam.Remoting.serializeMap = function(value, refs)
{
var data = "<map>";
var keyset = value.keySet();
for (var i = 0; i < keyset.length; i++)
{
data += "<element><k>";
data += Seam.Remoting.serializeValue(keyset[i], null, refs);
data += "</k><v>";
data += Seam.Remoting.serializeValue(value.get(keyset[i]), null, refs);
data += "</v></element>";
}
data += "</map>";
return data;
}
Seam.Remoting.serializeDate = function(value)
{
var zeroPad = function(val, digits) { while (("" + val).length < digits) val = "0" + val; return val; };
var data = "<date>";
data += value.getFullYear();
data += zeroPad(value.getMonth() + 1, 2);
data += zeroPad(value.getDate(), 2);
data += zeroPad(value.getHours(), 2);
data += zeroPad(value.getMinutes(), 2);
data += zeroPad(value.getSeconds(), 2);
data += zeroPad(value.getMilliseconds(), 3);
data += "</date>";
return data;
}
Seam.Remoting.getTypeRef = function(obj, refs)
{
var refId = -1;
for (var i = 0; i < refs.length; i++)
{
if (refs[i] == obj)
{
refId = i;
break;
}
}
if (refId == -1)
{
refId = refs.length;
refs[refId] = obj;
}
return "<ref id=\"" + refId + "\"/>";
}
Seam.Remoting.serializeType = function(obj, refs)
{
var data = "<bean type=\"";
var objType = Seam.Component.getComponentType(obj);
var isComponent = objType != null;
if (!isComponent)
objType = Seam.Remoting.getType(obj);
if (!objType)
{
alert("Unknown Type error.");
return null;
}
data += objType.__name;
data += "\">\n";
var meta = isComponent ? Seam.Component.getMetadata(obj) : Seam.Remoting.getMetadata(obj);
for (var i = 0; i < meta.length; i++)
{
data += "<member name=\"";
data += meta[i].field;
data += "\">";
data += Seam.Remoting.serializeValue(obj[meta[i].field], meta[i].type, refs);
data += "</member>\n";
}
data += "</bean>";
return data;
}
Seam.Remoting.__callId = 0;
Seam.Remoting.createCall = function(component, methodName, params, callback)
{
var callId = "" + Seam.Remoting.__callId++;
if (!callback)
callback = component.__callback[methodName];
var data = "<call component=\"";
data += Seam.Component.getComponentType(component).__name;
data += "\" method=\"";
data += methodName;
data += "\" id=\"";
data += callId;
data += "\">\n";
// Add parameters
data += "<params>";
var refs = new Array();
for (var i = 0; i < params.length; i++)
{
data += "<param>";
data += Seam.Remoting.serializeValue(params[i], null, refs);
data += "</param>";
}
data += "</params>";
// Add refs
data += "<refs>";
for (var i = 0; i < refs.length; i++)
{
data += "<ref id=\"" + i + "\">";
data += Seam.Remoting.serializeType(refs[i], refs);
data += "</ref>";
}
data += "</refs>";
data += "</call>";
return {data: data, id: callId, callback: callback};
}
Seam.Remoting.createHeader = function()
{
var header = "";
header += "<context>";
if (Seam.Remoting.getContext().getConversationId())
{
header += "<conversationId>";
header += Seam.Remoting.getContext().getConversationId();
header += "</conversationId>";
}
header += "</context>";
return header;
}
Seam.Remoting.createEnvelope = function(header, body)
{
var data = "<envelope>";
if (header)
{
data += "<header>";
data += header;
data += "</header>";
}
if (body)
{
data += "<body>";
data += body;
data += "</body>";
}
data += "</envelope>";
return data;
}
Seam.Remoting.pendingCalls = new Seam.Remoting.Map();
Seam.Remoting.inBatch = false;
Seam.Remoting.batchedCalls = new Array();
Seam.Remoting.startBatch = function()
{
Seam.Remoting.inBatch = true;
Seam.Remoting.batchedCalls.length = 0;
}
Seam.Remoting.executeBatch = function()
{
if (!Seam.Remoting.inBatch)
return;
var data = "";
for (var i = 0; i < Seam.Remoting.batchedCalls.length; i++)
{
Seam.Remoting.pendingCalls.put(Seam.Remoting.batchedCalls[i].id, Seam.Remoting.batchedCalls[i]);
data += Seam.Remoting.batchedCalls[i].data;
}
var envelope = Seam.Remoting.createEnvelope(Seam.Remoting.createHeader(), data);
Seam.Remoting.batchAsyncReq = Seam.Remoting.sendAjaxRequest(envelope, Seam.Remoting.PATH_EXECUTE, Seam.Remoting.processResponse, false);
Seam.Remoting.inBatch = false;
}
Seam.Remoting.cancelBatch = function()
{
Seam.Remoting.inBatch = false;
for (var i = 0; i < Seam.Remoting.batchedCalls.length; i++)
Seam.Remoting.pendingCalls.remove(Seam.Remoting.batchedCalls[i].id);
}
Seam.Remoting.cancelCall = function(callId)
{
var call = Seam.Remoting.pendingCalls.get(callId);
Seam.Remoting.pendingCalls.remove(callId);
if (call && call.asyncReq)
{
if (Seam.Remoting.pendingCalls.isEmpty())
Seam.Remoting.hideLoadingMessage();
call.asyncReq.onreadystatechange = function() {};
call.asyncReq.abort();
}
}
Seam.Remoting.execute = function(component, methodName, params, callback)
{
var call = Seam.Remoting.createCall(component, methodName, params, callback);
if (Seam.Remoting.inBatch)
{
Seam.Remoting.batchedCalls[Seam.Remoting.batchedCalls.length] = call;
}
else
{
// Marshal the request
var envelope = Seam.Remoting.createEnvelope(Seam.Remoting.createHeader(), call.data);
Seam.Remoting.pendingCalls.put(call.id, call);
call.asyncReq = Seam.Remoting.sendAjaxRequest(envelope, Seam.Remoting.PATH_EXECUTE, Seam.Remoting.processResponse, false);
}
return call;
}
Seam.Remoting.sendAjaxRequest = function(envelope, path, callback, silent)
{
Seam.Remoting.log("Request packet:\n" + envelope);
if (!silent)
Seam.Remoting.displayLoadingMessage();
var asyncReq;
if (window.XMLHttpRequest)
{
asyncReq = new XMLHttpRequest();
if (asyncReq.overrideMimeType)
asyncReq.overrideMimeType('text/xml');
}
else
asyncReq = new ActiveXObject("Microsoft.XMLHTTP");
asyncReq.onreadystatechange = function() {Seam.Remoting.requestCallback(asyncReq, callback); }
asyncReq.open("POST", Seam.Remoting.resourcePath + path, true);
asyncReq.send(envelope);
return asyncReq;
}
Seam.Remoting.setCallback = function(component, methodName, callback)
{
component.__callback[methodName] = callback;
}
Seam.Remoting.requestCallback = function(req, callback)
{
if (req.readyState == 4)
{
Seam.Remoting.hideLoadingMessage();
if (req.status == 200)
{
Seam.Remoting.log("Response packet:\n" + req.responseText);
if (callback)
callback(req.responseXML);
}
else
alert("There was an error processing your request. Error code: " + req.status);
}
}
Seam.Remoting.processResponse = function(doc)
{
var headerNode;
var bodyNode;
var context = new Seam.Remoting.__Context;
for (var i = 0; i < doc.documentElement.childNodes.length; i++)
{
var node = doc.documentElement.childNodes.item(i);
if (node.tagName == "header")
headerNode = node;
else if (node.tagName == "body")
bodyNode = node;
}
if (headerNode)
{
var contextNode;
for (var i = 0; i < headerNode.childNodes.length; i++)
{
var node = headerNode.childNodes.item(i);
if (node.tagName == "context")
{
contextNode = node;
break;
}
}
if (contextNode)
{
Seam.Remoting.unmarshalContext(contextNode, context);
if (context.getConversationId() && Seam.Remoting.getContext().getConversationId() == null)
Seam.Remoting.getContext().setConversationId(context.getConversationId());
}
}
if (bodyNode)
{
for (var i = 0; i < bodyNode.childNodes.length; i++)
{
var node = bodyNode.childNodes.item(i);
if (node.tagName == "result")
Seam.Remoting.processResult(node, context);
}
}
}
Seam.Remoting.processResult = function(result, context)
{
var callId = result.getAttribute("id");
var call = Seam.Remoting.pendingCalls.get(callId);
Seam.Remoting.pendingCalls.remove(callId);
if (call && call.callback)
{
var valueNode = null;
var refsNode = null;
var children = result.childNodes;
for (var i = 0; i < children.length; i++)
{
var tag = children.item(i).tagName;
if (tag == "value")
valueNode = children.item(i);
else if (tag == "refs")
refsNode = children.item(i);
}
var refs = new Array();
if (refsNode)
Seam.Remoting.unmarshalRefs(refsNode, refs);
var value = Seam.Remoting.unmarshalValue(valueNode.firstChild, refs);
call.callback(value, context);
}
}
Seam.Remoting.unmarshalContext = function(ctxNode, context)
{
for (var i = 0; i < ctxNode.childNodes.length; i++)
{
var tag = ctxNode.childNodes.item(i).tagName;
if (tag == "conversationId")
context.setConversationId(ctxNode.childNodes.item(i).firstChild.nodeValue);
}
}
Seam.Remoting.unmarshalRefs = function(refsNode, refs)
{
var objs = new Array();
// Pass 1 - create the reference objects
for (var i = 0; i < refsNode.childNodes.length; i++)
{
if (refsNode.childNodes.item(i).tagName == "ref")
{
var refNode = refsNode.childNodes.item(i);
var refId = parseInt(refNode.getAttribute("id"));
var valueNode = refNode.firstChild;
if (valueNode.tagName == "bean")
{
var obj = null;
var typeName = valueNode.getAttribute("type");
if (Seam.Component.isRegistered(typeName))
obj = Seam.Component.newInstance(typeName);
else
obj = Seam.Remoting.createType(typeName);
if (obj)
{
refs[refId] = obj;
objs[objs.length] = {obj: obj, node: valueNode};
}
}
}
}
// Pass 2 - populate the object members
for (var i = 0; i < objs.length; i++)
{
for (var j = 0; j < objs[i].node.childNodes.length; j++)
{
var child = objs[i].node.childNodes.item(j);
if (child.tagName == "member")
{
var name = child.getAttribute("name");
objs[i].obj[name] = Seam.Remoting.unmarshalValue(child.firstChild, refs);
}
}
}
}
Seam.Remoting.unmarshalValue = function(element, refs)
{
var tag = element.tagName;
switch (tag)
{
case "bool": return element.firstChild.nodeValue == "true";
case "number":
if (element.firstChild.nodeValue.indexOf(".") == -1)
return parseInt(element.firstChild.nodeValue);
else
return parseFloat(element.firstChild.nodeValue);
case "str":
var data = "";
for (var i = 0; i < element.childNodes.length; i++)
{
if (element.childNodes[i].nodeType == 3) // NODE_TEXT
data += element.childNodes[i].nodeValue;
}
return decodeURIComponent(data);
case "ref": return refs[parseInt(element.getAttribute("id"))];
case "bag":
var value = new Array();
for (var i = 0; i < element.childNodes.length; i++)
{
if (element.childNodes.item(i).tagName == "element")
value[value.length] = Seam.Remoting.unmarshalValue(element.childNodes.item(i).firstChild, refs);
}
return value;
case "map":
var map = new Seam.Remoting.Map();
for (var i = 0; i < element.childNodes.length; i++)
{
var childNode = element.childNodes.item(i);
if (childNode.tagName == "element")
{
var key = null
var value = null;
for (var j = 0; j < childNode.childNodes.length; j++)
{
if (key == null && childNode.childNodes.item(j).tagName == "k")
key = Seam.Remoting.unmarshalValue(childNode.childNodes.item(j).firstChild, refs);
else if (value == null && childNode.childNodes.item(j).tagName == "v")
value = Seam.Remoting.unmarshalValue(childNode.childNodes.item(j).firstChild, refs);
}
if (key != null)
map.put(key, value);
}
}
return map;
case "date": return Seam.Remoting.deserializeDate(element.firstChild.nodeValue);
default: return null;
}
}
Seam.Remoting.deserializeDate = function(val)
{
var dte = new Date();
dte.setFullYear(parseInt(val.substring(0,4), 10));
dte.setMonth(parseInt(val.substring(4,6), 10) - 1);
dte.setDate(parseInt(val.substring(6,8), 10));
dte.setHours(parseInt(val.substring(8,10), 10));
dte.setMinutes(parseInt(val.substring(10,12), 10));
dte.setSeconds(parseInt(val.substring(12,14), 10));
dte.setMilliseconds(parseInt(val.substring(14,17), 10));
return dte;
}
Seam.Remoting.loadingMsgDiv = null;
Seam.Remoting.loadingMessage = "Please wait...";
Seam.Remoting.displayLoadingMessage = function()
{
if (!Seam.Remoting.loadingMsgDiv)
{
Seam.Remoting.loadingMsgDiv = document.createElement('div');
var msgDiv = Seam.Remoting.loadingMsgDiv;
msgDiv.setAttribute('id', 'loadingMsg');
msgDiv.style.position = "absolute";
msgDiv.style.top = "0px";
msgDiv.style.right = "0px";
msgDiv.style.background = "red";
msgDiv.style.color = "white";
msgDiv.style.fontFamily = "Verdana,Helvetica,Arial";
msgDiv.style.fontSize = "small";
msgDiv.style.padding = "2px";
msgDiv.style.border = "1px solid black";
document.body.appendChild(msgDiv);
var text = document.createTextNode(Seam.Remoting.loadingMessage);
msgDiv.appendChild(text);
}
else
{
Seam.Remoting.loadingMsgDiv.innerHTML = Seam.Remoting.loadingMessage;
Seam.Remoting.loadingMsgDiv.style.visibility = 'visible';
}
}
Seam.Remoting.hideLoadingMessage = function()
{
if (Seam.Remoting.loadingMsgDiv)
Seam.Remoting.loadingMsgDiv.style.visibility = 'hidden';
}
/* Messaging API */
Seam.Remoting.pollInterval = 10; // Default poll interval of 10 seconds
Seam.Remoting.pollTimeout = 0; // Default timeout of 0 seconds
Seam.Remoting.polling = false;
Seam.Remoting.setPollInterval = function(interval)
{
Seam.Remoting.pollInterval = interval;
}
Seam.Remoting.setPollTimeout = function(timeout)
{
Seam.Remoting.pollTimeout = timeout;
}
Seam.Remoting.subscriptionRegistry = new Array();
Seam.Remoting.subscribe = function(topicName, callback)
{
for (var i = 0; i < Seam.Remoting.subscriptionRegistry.length; i++)
{
if (Seam.Remoting.subscriptionRegistry[i].topic == topicName)
return;
}
var body = "<subscribe topic=\"" + topicName + "\"/>";
var env = Seam.Remoting.createEnvelope(null, body);
Seam.Remoting.subscriptionRegistry.push({topic:topicName, callback:callback});
Seam.Remoting.sendAjaxRequest(env, Seam.Remoting.PATH_SUBSCRIPTION, Seam.Remoting.subscriptionCallback, false);
}
Seam.Remoting.unsubscribe = function(topicName)
{
var token = null;
for (var i = 0; i < Seam.Remoting.subscriptionRegistry.length; i++)
{
if (Seam.Remoting.subscriptionRegistry[i].topic == topicName)
{
token = Seam.Remoting.subscriptionRegistry[i].token;
Seam.Remoting.subscriptionRegistry.splice(i, 1);
}
}
if (token)
{
var body = "<unsubscribe token=\"" + token + "\"/>";
var env = Seam.Remoting.createEnvelope(null, body);
Seam.Remoting.sendAjaxRequest(env, Seam.Remoting.PATH_SUBSCRIPTION, null, false);
}
}
Seam.Remoting.subscriptionCallback = function(doc)
{
var body = doc.documentElement.firstChild;
for (var i = 0; i < body.childNodes.length; i++)
{
var node = body.childNodes.item(i);
if (node.tagName == "subscription")
{
var topic = node.getAttribute("topic");
var token = node.getAttribute("token");
for (var i = 0; i < Seam.Remoting.subscriptionRegistry.length; i++)
{
if (Seam.Remoting.subscriptionRegistry[i].topic == topic)
{
Seam.Remoting.subscriptionRegistry[i].token = token;
Seam.Remoting.poll();
break;
}
}
}
}
}
Seam.Remoting.pollTimeoutFunction = null;
Seam.Remoting.poll = function()
{
if (Seam.Remoting.polling)
return;
Seam.Remoting.polling = true;
clearTimeout(Seam.Remoting.pollTimeoutFunction);
var body = "";
if (Seam.Remoting.subscriptionRegistry.length == 0)
{
Seam.Remoting.polling = false;
return;
}
for (var i = 0; i < Seam.Remoting.subscriptionRegistry.length; i++)
{
body += "<poll token=\"" + Seam.Remoting.subscriptionRegistry[i].token + "\" ";
body += "timeout=\"" + Seam.Remoting.pollTimeout + "\"/>";
}
var env = Seam.Remoting.createEnvelope(null, body);
Seam.Remoting.sendAjaxRequest(env, Seam.Remoting.PATH_POLL, Seam.Remoting.pollCallback, true);
}
Seam.Remoting.pollCallback = function(doc)
{
Seam.Remoting.polling = false;
var body = doc.documentElement.firstChild;
for (var i = 0; i < body.childNodes.length; i++)
{
var node = body.childNodes.item(i);
if (node.tagName == "messages")
Seam.Remoting.processMessages(node);
else if (node.tagName == "errors")
Seam.Remoting.processPollErrors(node);
}
Seam.Remoting.pollTimeoutFunction = setTimeout("Seam.Remoting.poll()", Math.max(Seam.Remoting.pollInterval * 1000, 1000));
}
Seam.Remoting.processMessages = function(messages)
{
var token = messages.getAttribute("token");
var callback = null;
for (var i = 0; i < Seam.Remoting.subscriptionRegistry.length; i++)
{
if (Seam.Remoting.subscriptionRegistry[i].token == token)
{
callback = Seam.Remoting.subscriptionRegistry[i].callback;
break;
}
}
if (callback != null)
{
var messageNode = null;
var children = messages.childNodes;
for (var i = 0; i < children.length; i++)
{
if (children.item(i).tagName == "message")
{
messageNode = children.item(i);
var messageType = messageNode.getAttribute("type");
var valueNode = null;
var refsNode = null;
for (var j = 0; j < messageNode.childNodes.length; j++)
{
var node = messageNode.childNodes.item(j);
if (node.tagName == "value")
valueNode = node;
else if (node.tagName == "refs")
refsNode = node;
}
var refs = new Array();
if (refsNode)
Seam.Remoting.unmarshalRefs(refsNode, refs);
var value = Seam.Remoting.unmarshalValue(valueNode.firstChild, refs);
callback(Seam.Remoting.createMessage(messageType, value));
}
}
}
}
Seam.Remoting.processErrors = function(errors)
{
var token = errors.getAttribute("token");
// Unsubscribe to the topic
for (var i = 0; i < Seam.Remoting.subscriptionRegistry.length; i++)
{
if (Seam.Remoting.subscriptionRegistry[i].token == token)
{
Seam.Remoting.subscriptionRegistry.splice(i, 1);
break;
}
}
for (var i = 0; i < errors.childNodes.length; i++)
{
if (errors.childNodes.item(i).tagName == "error")
{
var errorNode = errors.childNodes.item(i);
var code = errorNode.getAttribute("code");
var message = errorNode.firstChild.nodeValue;
if (Seam.Remoting.onPollError)
Seam.Remoting.onPollError(code, message);
else
alert("A polling error occurred: " + code + " " + message);
}
}
}
Seam.Remoting.ObjectMessage = function()
{
this.value = null;
Seam.Remoting.ObjectMessage.prototype.getValue = function()
{
return this.value;
}
Seam.Remoting.ObjectMessage.prototype.setValue = function(value)
{
this.value = value;
}
}
Seam.Remoting.TextMessage = function()
{
this.text = null;
Seam.Remoting.TextMessage.prototype.getText = function()
{
return this.text;
}
Seam.Remoting.TextMessage.prototype.setText = function(text)
{
this.text = text;
}
}
Seam.Remoting.createMessage = function(messageType, value)
{
switch (messageType)
{
case "object":
var msg = new Seam.Remoting.ObjectMessage();
msg.setValue(value);
return msg;
case "text":
var msg = new Seam.Remoting.TextMessage();
msg.setText(value);
return msg;
}
return null;
}
More information about the jboss-cvs-commits
mailing list