Package org.jboss.seam.remoting.model

Source Code of org.jboss.seam.remoting.model.ModelHandler

package org.jboss.seam.remoting.model;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.StringReader;
import java.lang.reflect.Array;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.enterprise.context.Conversation;
import javax.enterprise.inject.spi.BeanManager;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.jboss.logging.Logger;
import org.jboss.seam.remoting.AbstractRequestHandler;
import org.jboss.seam.remoting.Call;
import org.jboss.seam.remoting.MarshalUtils;
import org.jboss.seam.remoting.RequestContext;
import org.jboss.seam.remoting.RequestHandler;
import org.jboss.seam.remoting.wrapper.BagWrapper;
import org.jboss.seam.remoting.wrapper.BeanWrapper;
import org.jboss.seam.remoting.wrapper.MapWrapper;
import org.jboss.seam.remoting.wrapper.Wrapper;

/**
* Handles incoming model fetch/apply requests
* @author Shane Bryzak
*/
public class ModelHandler extends AbstractRequestHandler implements RequestHandler
{
   private static final Logger log = Logger.getLogger(ModelHandler.class);
  
   @Inject BeanManager beanManager;
   @Inject ModelRegistry registry;
   @Inject Conversation conversation;
  
   public void handle(HttpServletRequest request, HttpServletResponse response)
         throws Exception
   {
      response.setContentType("text/xml");

      ByteArrayOutputStream out = new ByteArrayOutputStream();

      byte[] buffer = new byte[256];
      int read = request.getInputStream().read(buffer);
      while (read != -1)
      {
         out.write(buffer, 0, read);
         read = request.getInputStream().read(buffer);
      }

      String requestData = new String(out.toByteArray());
      log.debug("Processing model request: " + requestData);

      SAXReader xmlReader = new SAXReader();
      Document doc = xmlReader.read(new StringReader(requestData));
      final Element env = doc.getRootElement();
      final RequestContext ctx = new RequestContext(env.element("header"));
     
      try
      {
         activateConversationContext(request, ctx.getConversationId());
  
         Element modelElement = env.element("body").element("model");
         String operation = modelElement.attributeValue("operation");
          
         if ("expand".equals(operation))
         {
            processExpandRequest(modelElement, ctx, response.getOutputStream())
         }
         else
         {
            Model model = null;
            if ("fetch".equals(operation))
            {
               model = processFetchRequest(modelElement);
            }
            else if ("apply".equals(operation))
            {
               model = processApplyRequest(modelElement);
            }
     
            if (model.getAction() != null && model.getAction().getException() != null)
            {
               response.getOutputStream().write(ENVELOPE_TAG_OPEN);
               response.getOutputStream().write(BODY_TAG_OPEN);        
               MarshalUtils.marshalException(model.getAction().getException(),
                     model.getAction().getContext(), response.getOutputStream());
               response.getOutputStream().write(BODY_TAG_CLOSE);
               response.getOutputStream().write(ENVELOPE_TAG_CLOSE);
               response.getOutputStream().flush();
               return;
            }
           
            model.evaluate();
           
            ctx.setConversationId(conversation.isTransient() ? null : conversation.getId());
            marshalResponse(model, ctx, response.getOutputStream());
         }
      }
      finally
      {
         deactivateConversationContext(request);
      }
   }
  
   @SuppressWarnings({ "unchecked" })
   private Model processFetchRequest(Element modelElement)
      throws Exception
   {
      Model model = registry.createModel();
     
      if (modelElement.elements("action").size() > 0)
      {        
         unmarshalAction(modelElement.element("action"), model);
      }
     
      for (Element beanElement : (List<Element>) modelElement.elements("bean"))
      {
         Element beanNameElement = beanElement.element("name");
         Element beanQualifierElement = beanElement.element("qualifier");
         Element beanPropertyElement = beanElement.element("property");
        
         model.addBean(beanElement.attributeValue("alias"),
               beanNameElement.getTextTrim(),
               beanQualifierElement != null ? beanQualifierElement.getTextTrim() : null,
               beanPropertyElement != null ? beanPropertyElement.getTextTrim() : null);
      }
     
      // TODO Unmarshal expressions - don't support this until security implications investigated
      //for (Element exprElement : (List<Element>) modelElement.elements("expression"))
      //{
        
      //}
     
      if (model.getAction() != null)
      {
         model.getAction().execute();                             
      }
     
      return model;
   }
  
   @SuppressWarnings("unchecked")
   private void unmarshalAction(Element actionElement, Model model)
   {
      Element targetElement = actionElement.element("target");
      Element qualifiersElement = actionElement.element("qualifiers");
      Element methodElement = actionElement.element("method");
      Element paramsElement = actionElement.element("params");
      Element refsElement = actionElement.element("refs");
     
      model.setAction(new Call(beanManager, targetElement.getTextTrim(),
           qualifiersElement != null ? qualifiersElement.getTextTrim() : null,
           methodElement != null ? methodElement.getTextTrim() : null));                       

      if (refsElement != null)
      {
         for (Element refElement : (List<Element>) refsElement.elements("ref"))
         {
            model.getAction().getContext().createWrapperFromElement(refElement);
         }

         for (Wrapper w : model.getAction().getContext().getInRefs().values())
         {
            w.unmarshal();
         }
      }

      if (paramsElement != null)
      {
         for (Element paramElement : (List<Element>) paramsElement.elements("param"))
         {
            model.getAction().addParameter(model.getAction().getContext().createWrapperFromElement(
                  (Element) paramElement.elements().get(0)));
         }
      }     
   }
  
   @SuppressWarnings({ "unchecked", "unused" })
   private Model processApplyRequest(Element modelElement)
      throws Exception
   {
      Model model = registry.getModel(modelElement.attributeValue("id"));
      model.setAction(null);
     
      // We clone the outRefs to the inRefs so that the context can locate
      // already-loaded refs when unmarshalling
      for (int i = 0; i < model.getCallContext().getOutRefs().size(); i++)
      {
         model.getCallContext().getInRefs().put("" + i, model.getCallContext().getOutRefs().get(i));
      }
                 
      Element refsElement = modelElement.element("refs");
      if (refsElement != null)
      {
         List<Wrapper> newRefs = new ArrayList<Wrapper>();
        
         for (Element ref : (List<Element>) refsElement.elements("ref"))
         {
            newRefs.add(model.getCallContext().createWrapperFromElement(ref));
         }
        
         // Unmarshal any new ref values
         for (Wrapper w : newRefs)
         {
            w.unmarshal();
         }
      }
     
      Element delta = modelElement.element("delta");
      if (delta != null)
      {
         List<Element> changesets = delta.elements("changeset");
         for (Element changeset : changesets)
         {
            int refId = Integer.parseInt(changeset.attributeValue("refid"));
           
            if (changeset.elements("member").size() > 0)
            {
               Wrapper target = model.getCallContext().getOutRefs().get(refId);
               if (!(target instanceof BeanWrapper))
               {
                  throw new IllegalStateException("Changeset for refId [" +
                        refId + "] does not reference a valid bean object");                    
               }
              
               for (Element member : (List<Element>) changeset.elements("member"))
               {
                  String name = member.attributeValue("name");
                 
                  Wrapper source = model.getCallContext().createWrapperFromElement(
                        (Element) member.elementIterator().next());
                                                     
                  if (source instanceof BagWrapper)
                  {                 
                     Object targetBag = ((BeanWrapper) target).getBeanProperty(name);
                     if (targetBag == null)
                     {
                        ((BeanWrapper) target).setBeanProperty(name, source);
                     }
                     else
                     {
                        Type t = ((BeanWrapper) target).getBeanPropertyType(name);
                        if (!cloneBagContents(source.convert(t), ((Wrapper) targetBag).getValue()))
                        {
                           ((BeanWrapper) target).setBeanProperty(name, source);
                        }
                     }
                  }
                  else if (source instanceof MapWrapper)
                  {                    
                     Object targetMap = ((BeanWrapper) target).getBeanProperty(name);
                     if (!Map.class.isAssignableFrom(targetMap.getClass()))
                     {
                        throw new IllegalStateException("Cannot assign Map value " +
                              "to non Map property [" + target.getClass().getName() +
                              "." + name + "]");
                     }
                    
                     if (targetMap == null)
                     {
                        ((BeanWrapper) target).setBeanProperty(name, source);
                     }
                     else
                     {                       
                        Type t = ((BeanWrapper) target).getBeanPropertyType(name);                       
                        cloneMapContents((Map<Object,Object>) source.convert(t),
                              (Map<Object,Object>) targetMap);
                     }
                  }                 
                  else
                  {                                         
                     ((BeanWrapper) target).setBeanProperty(name, source);
                  }
               }
            }
           
            if (changeset.elements("bag").size() > 0)
            {
               Wrapper target = model.getCallContext().getOutRefs().get(refId);              
               Wrapper source = model.getCallContext().createWrapperFromElement(
                     (Element) changeset.element("bag"));
               cloneBagContents(source.convert(target.getValue().getClass()),
                     target.getValue());
            }           
            else if (changeset.elements("map").size() > 0)
            {
               Wrapper target = model.getCallContext().getOutRefs().get(refId);
               Wrapper source = model.getCallContext().createWrapperFromElement(
                     (Element) changeset.element("map"));
               cloneMapContents((Map<Object,Object>) source.convert(target.getValue().getClass()),
                     (Map<Object,Object>) target.getValue());
            }
         }
      }
     
      if (modelElement.elements("action").size() > 0)
      {        
         unmarshalAction(modelElement.element("action"), model);
      }     
     
      if (model.getAction() != null)
      {
         model.getAction().execute();                             
      }   
     
      return model;
   }
  
   private void processExpandRequest(Element modelElement, RequestContext ctx, OutputStream out)
      throws Exception
   {
      Model model = registry.getModel(modelElement.attributeValue("id"));
      model.setAction(null);
   
      Element refElement = modelElement.element("ref");
      if (refElement == null)
      {
         throw new IllegalStateException("Invalid request state - no object ref found");
      }
     
      int refId = Integer.parseInt(refElement.attributeValue("id"));
      Wrapper target = model.getCallContext().getOutRefs().get(refId);
     
      int newRefIdx = model.getCallContext().getOutRefs().size();
     
      Element memberElement = refElement.element("member");
      String memberName = memberElement.attributeValue("name");
     
      Wrapper value = ((BeanWrapper) target).getBeanProperty(memberName);
      if (value instanceof BagWrapper)
      {
         ((BagWrapper) value).setLoadLazy(true);
      }
   
      out.write(ENVELOPE_TAG_OPEN);

      out.write(HEADER_OPEN);
      out.write(CONTEXT_TAG_OPEN);
      if (ctx.getConversationId() != null)
      {
         out.write(CONVERSATION_ID_TAG_OPEN);
         out.write(ctx.getConversationId().getBytes());
         out.write(CONVERSATION_ID_TAG_CLOSE);
      }
      out.write(CALL_ID_TAG_OPEN);
      out.write(ctx.getCallId().toString().getBytes());
      out.write(CALL_ID_TAG_CLOSE);
      out.write(CONTEXT_TAG_CLOSE);
      out.write(HEADER_CLOSE);

      out.write(BODY_TAG_OPEN);

      MarshalUtils.marshalModelExpand(model, value, out, newRefIdx);     

      out.write(BODY_TAG_CLOSE);
      out.write(ENVELOPE_TAG_CLOSE);
      out.flush()
   }
  
   /**
    * Clones the contents of the specified source bag into the specified target
    * bag. If the contents can be cloned, this method returns true, otherwise it
    * returns false.
    * 
    * @param sourceBag
    * @param targetBag
    * @return
    */
   @SuppressWarnings("unchecked")
   private boolean cloneBagContents(Object sourceBag, Object targetBag)
   {
      Class<?> cls = sourceBag.getClass();
      if (cls.isArray())
      {
         int sourceLen = Array.getLength(sourceBag);
         int targetLen = Array.getLength(targetBag);
         if (targetLen != sourceLen) return false;
         for (int i = 0; i < sourceLen; i++)
         {
            Array.set(targetBag, i, Array.get(sourceBag, i));
         }
         return true;
      }
      else if (List.class.isAssignableFrom(cls))
      {
         List<Object> sourceList = (List<Object>) sourceBag;
         List<Object> targetList = (List<Object>) targetBag;
        
         targetList.clear();
        
         for (int i = 0; i < sourceList.size(); i++)
         {
            if (targetList.size() < i + 1)
            {
               targetList.add(i, sourceList.get(i))
            }
            else if (targetList.get(i) != sourceList.get(i))
            {
               targetList.set(i, sourceList.get(i));
            }
         }
         return true;       
      }
      else if (Set.class.isAssignableFrom(cls))
      {
         Set<Object> sourceSet = (Set<Object>) sourceBag;
         Set<Object> targetSet = (Set<Object>) targetBag;
        
         for (Object e : sourceSet)
         {
            if (!targetSet.contains(e))
            {
               targetSet.add(e);
            }
         }
        
         for (Object e : targetSet)
         {
            if (!sourceSet.contains(e))
            {
               targetSet.remove(e);
            }
         }        
         return true;
      }
     
      return false;
   }
  
   /**
    * Clones the contents of one Map into another
    *
    * @param sourceMap
    * @param targetMap
    */
   private void cloneMapContents(Map<Object,Object> sourceMap, Map<Object,Object> targetMap)
   {
      for (Object key : sourceMap.keySet())
      {
         if (!targetMap.containsKey(key))
         {
            targetMap.put(key, sourceMap.get(key));
         }
      }
     
      for (Object key : targetMap.keySet())
      {
         if (!sourceMap.containsKey(key))
         {
            targetMap.remove(key);
         }
      }     
   }
  
   private void marshalResponse(Model model, RequestContext ctx,
         OutputStream out) throws IOException
   {
      out.write(ENVELOPE_TAG_OPEN);

      out.write(HEADER_OPEN);
      out.write(CONTEXT_TAG_OPEN);
      if (ctx.getConversationId() != null)
      {
         out.write(CONVERSATION_ID_TAG_OPEN);
         out.write(ctx.getConversationId().getBytes());
         out.write(CONVERSATION_ID_TAG_CLOSE);
      }
      out.write(CALL_ID_TAG_OPEN);
      out.write(ctx.getCallId().toString().getBytes());
      out.write(CALL_ID_TAG_CLOSE);
      out.write(CONTEXT_TAG_CLOSE);
      out.write(HEADER_CLOSE);

      out.write(BODY_TAG_OPEN);

      MarshalUtils.marshalModel(model, out);

      out.write(BODY_TAG_CLOSE);
      out.write(ENVELOPE_TAG_CLOSE);
      out.flush();
   }  
}
TOP

Related Classes of org.jboss.seam.remoting.model.ModelHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.