Package railo.runtime.converter

Source Code of railo.runtime.converter.WDDXConverter

package railo.runtime.converter;

import java.io.IOException;
import java.io.StringReader;
import java.io.Writer;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;

import javax.xml.parsers.FactoryConfigurationError;

import org.apache.xerces.parsers.DOMParser;
import org.w3c.dom.CharacterData;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import railo.commons.date.TimeZoneConstants;
import railo.commons.lang.NumberUtil;
import railo.runtime.Component;
import railo.runtime.ComponentScope;
import railo.runtime.ComponentWrap;
import railo.runtime.PageContext;
import railo.runtime.coder.Base64Coder;
import railo.runtime.coder.CoderException;
import railo.runtime.component.Property;
import railo.runtime.engine.ThreadLocalPageContext;
import railo.runtime.exp.ExpressionException;
import railo.runtime.exp.PageException;
import railo.runtime.op.Caster;
import railo.runtime.op.Decision;
import railo.runtime.op.date.DateCaster;
import railo.runtime.orm.ORMUtil;
import railo.runtime.text.xml.XMLUtil;
import railo.runtime.type.Array;
import railo.runtime.type.ArrayImpl;
import railo.runtime.type.Collection;
import railo.runtime.type.Collection.Key;
import railo.runtime.type.KeyImpl;
import railo.runtime.type.Query;
import railo.runtime.type.QueryImpl;
import railo.runtime.type.Struct;
import railo.runtime.type.StructImpl;
import railo.runtime.type.UDF;
import railo.runtime.type.cfc.ComponentAccess;
import railo.runtime.type.dt.DateTime;
import railo.runtime.type.dt.DateTimeImpl;
import railo.runtime.type.util.CollectionUtil;
import railo.runtime.type.util.ComponentUtil;
import railo.runtime.type.util.KeyConstants;

/**
* class to serialize and desirilize WDDX Packes
*/
public final class WDDXConverter extends ConverterSupport {
  private static final Collection.Key REMOTING_FETCH = KeyImpl.intern("remotingFetch");
 
  private int deep=1;
  private boolean xmlConform;
  private char _;
  private TimeZone timeZone;
  private boolean ignoreRemotingFetch=true;
    //private PageContext pcx;

  /**
   * constructor of the class
   * @param timeZone
   * @param xmlConform define if generated xml conform output or wddx conform output (wddx is not xml conform)
   */
  public WDDXConverter(TimeZone timeZone, boolean xmlConform,boolean ignoreRemotingFetch) {
    this.xmlConform=xmlConform;
    _=(xmlConform)?'"':'\'';
    this.timeZone=timeZone;
    this.ignoreRemotingFetch=ignoreRemotingFetch;
  }
 
  /**
   * defines timezone info will
   * @param timeZone
   */
  public void setTimeZone(TimeZone timeZone) {
    this.timeZone=timeZone;
  }

  /**
   * serialize a Date
   * @param date Date to serialize
   * @return serialized date
   * @throws ConverterException
   */
  private String _serializeDate(Date date) {
    return _serializeDateTime(new DateTimeImpl(date));
  }
  /**
   * serialize a DateTime
   * @param dateTime DateTime to serialize
   * @return serialized dateTime
   * @throws ConverterException
   */
  private String _serializeDateTime(DateTime dateTime) {
    //try {
     

      String strDate = new railo.runtime.format.DateFormat(Locale.US).format(dateTime,"yyyy-m-d",TimeZoneConstants.UTC);
      String strTime = new railo.runtime.format.TimeFormat(Locale.US).format(dateTime,"H:m:s",TimeZoneConstants.UTC);
     
      return goIn()+"<dateTime>"+
        strDate+
        "T"+strTime+
        "+0:0"+
        "</dateTime>";
     
    /*}
    catch (PageException e) {
      throw new ConverterException(e);
    }*/
  }
 
  private String _serializeBinary(byte[] binary) {
    return new StringBuilder("<binary length='")
    .append(binary.length)
    .append("'>")
    .append(Base64Coder.encode(binary))
    .append("</binary>").toString();
  }

  /**
   * @param dateTime
   * @return returns the time zone info
   */
  private String getTimeZoneInfo(DateTime dateTime) {
    timeZone=ThreadLocalPageContext.getTimeZone(timeZone);
    //if(timeZone==null) return "";
   
    int minutes=timeZone.getOffset(dateTime.getTime())/1000/60;
    String operator=(minutes>=0)?"+":"-";
    if(operator.equals("-"))minutes=minutes-(minutes+minutes);
    int hours=minutes/60;
    minutes=minutes%60;
   
    return operator+hours+":"+minutes;

   
  }

  /**
   * serialize a Array
   * @param array Array to serialize
   * @param done
   * @return serialized array
   * @throws ConverterException
   */
  private String _serializeArray(Array array, Set<Object> done) throws ConverterException {
    return _serializeList(array.toList(),done);
  }
 
  /**
   * serialize a List (as Array)
   * @param list List to serialize
   * @param done
   * @return serialized list
   * @throws ConverterException
   */
  private String _serializeList(List list, Set<Object> done) throws ConverterException {
    StringBuffer sb=new StringBuffer(goIn()+"<array length="+_+list.size()+_+">");
       
    ListIterator it=list.listIterator();
    while(it.hasNext()) {
      sb.append(_serialize(it.next(),done));
    }
   
    sb.append(goIn()+"</array>");
    return sb.toString();
  }

  /**
   * serialize a Component
   * @param component Component to serialize
   * @param done
   * @return serialized component
   * @throws ConverterException
   */
  private String _serializeComponent(Component component, Set<Object> done) throws ConverterException {
    StringBuffer sb=new StringBuffer();
    ComponentAccess ca;
    try {
      component=new ComponentWrap(Component.ACCESS_PRIVATE, ca=ComponentUtil.toComponentAccess(component));
    } catch (ExpressionException e1) {
      throw toConverterException(e1);
    }
    boolean isPeristent=ca.isPersistent();
   
   
        deep++;
        Object member;
        Iterator<Key> it = component.keyIterator();
        Collection.Key key;
        while(it.hasNext()) {
          key=Caster.toKey(it.next(),null);
          member = component.get(key,null);
          if(member instanceof UDF) continue;
          sb.append(goIn()+"<var scope=\"this\" name="+_+key.toString()+_+">");
            sb.append(_serialize(member,done));
            sb.append(goIn()+"</var>");
        }

        Property p;
        Boolean remotingFetch;
      Struct props = ignoreRemotingFetch?null:ComponentUtil.getPropertiesAsStruct(ca,false);
        ComponentScope scope = ca.getComponentScope();
        it=scope.keyIterator();
        while(it.hasNext()) {
          key=Caster.toKey(it.next(),null);
          if(!ignoreRemotingFetch) {
            p=(Property) props.get(key,null);
              if(p!=null) {
                remotingFetch=Caster.toBoolean(p.getDynamicAttributes().get(REMOTING_FETCH,null),null);
                if(remotingFetch==null){
              if(isPeristent  && ORMUtil.isRelated(p)) continue;
            }
            else if(!remotingFetch.booleanValue()) continue;
              }
        }
         
          member = scope.get(key,null);
          if(member instanceof UDF || key.equals(KeyConstants._this)) continue;
            sb.append(goIn()+"<var scope=\"variables\" name="+_+key.toString()+_+">");
            sb.append(_serialize(member,done));
            sb.append(goIn()+"</var>");
        }
       
       
        deep--;
        try {
      //return goIn()+"<struct>"+sb+"</struct>";
      return goIn()+"<component md5=\""+ComponentUtil.md5(component)+"\" name=\""+component.getAbsName()+"\">"+sb+"</component>";
    }
    catch (Exception e) {
      throw toConverterException(e);
    }
  }

  /**
   * serialize a Struct
   * @param struct Struct to serialize
   * @param done
   * @return serialized struct
   * @throws ConverterException
   */
  private String _serializeStruct(Struct struct, Set<Object> done) throws ConverterException {
        StringBuffer sb=new StringBuffer(goIn()+"<struct>");
       
        Iterator<Key> it = struct.keyIterator();

        deep++;
        while(it.hasNext()) {
            Key key = it.next();
            sb.append(goIn()+"<var name="+_+key.toString()+_+">");
            sb.append(_serialize(struct.get(key,null),done));
            sb.append(goIn()+"</var>");
        }
        deep--;
       
        sb.append(goIn()+"</struct>");
        return sb.toString();
  }

  /**
   * serialize a Map (as Struct)
   * @param map Map to serialize
   * @param done
   * @return serialized map
   * @throws ConverterException
   */
  private String _serializeMap(Map map, Set<Object> done) throws ConverterException {
    StringBuffer sb=new StringBuffer(goIn()+"<struct>");
   
    Iterator it=map.keySet().iterator();

    deep++;
    while(it.hasNext()) {
      Object key=it.next();
      sb.append(goIn()+"<var name="+_+key.toString()+_+">");
      sb.append(_serialize(map.get(key),done));
      sb.append(goIn()+"</var>");
    }
    deep--;
   
    sb.append(goIn()+"</struct>");
    return sb.toString();
  }

  /**
   * serialize a Query
   * @param query Query to serialize
   * @param done
   * @return serialized query
   * @throws ConverterException
   */
  private String _serializeQuery(Query query, Set<Object> done) throws ConverterException {
   
    Collection.Key[] keys = CollectionUtil.keys(query);
    StringBuffer sb=new StringBuffer(goIn()+"<recordset rowCount="+_+query.getRecordcount()+_+" fieldNames="+_+railo.runtime.type.util.ListUtil.arrayToList(keys,",")+_+" type="+_+"coldfusion.sql.QueryTable"+_+">");
   
 
    deep++;
    int len=query.getRecordcount();
    for(int i=0;i<keys.length;i++) {
      sb.append(goIn()+"<field name="+_+keys[i].getString()+_+">");
        for(int y=1;y<=len;y++) {
          try {
            sb.append(_serialize(query.getAt(keys[i],y),done));
          } catch (PageException e) {
            sb.append(_serialize(e.getMessage(),done));
          }
        }
     
      sb.append(goIn()+"</field>");
    }
    deep--;
   
    sb.append(goIn()+"</recordset>");
    return sb.toString();
  }
 
  /**
   * serialize a Object to his xml Format represenation
   * @param object Object to serialize
   * @param done
   * @return serialized Object
   * @throws ConverterException
   */
  private String _serialize(Object object, Set<Object> done) throws ConverterException {
    String rtn;
    deep++;
    // NULL
    if(object==null) {
      rtn= goIn()+"<null/>";
      deep--;
      return rtn;
    }
    // String
    if(object instanceof String) {
      rtn= goIn()+"<string>"+XMLUtil.escapeXMLString(object.toString())+"</string>";
      deep--;
      return rtn;
    }
    // Number
    if(object instanceof Number) {
      rtn= goIn()+"<number>"+((Number)object).doubleValue()+"</number>";
      deep--;
      return rtn;
    }
    // Boolean
    if(object instanceof Boolean) {
      rtn= goIn()+"<boolean value="+_+((Boolean)object).booleanValue()+_+"/>";
      deep--;
      return rtn;
    }
    // DateTime
    if(object instanceof DateTime) {
      rtn= _serializeDateTime((DateTime)object);
      deep--;
      return rtn;
    }
    // Date
    if(object instanceof Date) {
      rtn= _serializeDate((Date)object);
      deep--;
      return rtn;
    }
    // Date
    if(Decision.isCastableToBinary(object, false)) {
      rtn= _serializeBinary(Caster.toBinary(object,null));
      deep--;
      return rtn;
    }

    Object raw = LazyConverter.toRaw(object);
    if(done.contains(raw)){
      rtn= goIn()+"<null/>";
      deep--;
      return rtn;
    }
   
    done.add(raw);
    try {
      // Component
      if(object instanceof Component) {
        rtn= _serializeComponent((Component)object,done);
        deep--;
        return rtn;
      }
      // Struct
      if(object instanceof Struct) {
        rtn= _serializeStruct((Struct)object,done);
        deep--;
        return rtn;
      }
      // Map
      if(object instanceof Map) {
        rtn= _serializeMap((Map)object,done);
        deep--;
        return rtn;
      }
      // Array
      if(object instanceof Array) {
        rtn= _serializeArray((Array)object,done);
        deep--;
        return rtn;
      }
      // List
      if(object instanceof List) {
        rtn= _serializeList((List)object,done);
        deep--;
        return rtn;
      }
      // Query
      if(object instanceof Query) {
        rtn= _serializeQuery((Query)object,done);
        deep--;
        return rtn;
      }
    }
    finally{
      done.remove(raw);
    }
    // Others
    rtn="<struct type="+_+"L"+object.getClass().getName()+";"+_+"></struct>";
    deep--;
    return rtn;
  }

  @Override
  public void writeOut(PageContext pc, Object source, Writer writer) throws ConverterException, IOException {
    writer.write(serialize(source));
    writer.flush();
  }
 
  /**
   * serialize a Object to his xml Format represenation and create a valid wddx representation
   * @param object Object to serialize
   * @return serialized wddx package
   * @throws ConverterException
   */
  public String serialize(Object object) throws ConverterException {
    deep=0;
   
    StringBuffer sb=new StringBuffer()
    if(xmlConform)sb.append("<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>")
    sb.append("<wddxPacket version="+_+"1.0"+_+">")
    deep++;
    sb.append(goIn()+"<header/>");
    sb.append(goIn()+"<data>");
    sb.append(_serialize(object,new HashSet<Object>()));
    sb.append(goIn()+"</data>");
    deep--;
    sb.append("</wddxPacket>");
    return sb.toString();
  }
 

  /**
   * deserialize a WDDX Package (XML String Representation) to a runtime object
   * @param strWddx
   * @param validate
   * @return Object represent WDDX Package
   * @throws ConverterException
   * @throws IOException
   * @throws FactoryConfigurationError
   */
  public Object deserialize(String strWddx, boolean validate) throws ConverterException, IOException, FactoryConfigurationError {
    try {
      DOMParser parser = new DOMParser();
      if(validate) parser.setEntityResolver(new WDDXEntityResolver());
     
            parser.parse(new InputSource(new StringReader(strWddx)));
            Document doc=parser.getDocument();
       
        // WDDX Package
        NodeList docChldren = doc.getChildNodes();
        Node wddxPacket=doc;
        int len = docChldren.getLength();
        for(int i = 0; i < len; i++) {
          Node node=docChldren.item(i);
          if(node.getNodeName().equalsIgnoreCase("wddxPacket")) {
            wddxPacket=node;
            break;
          }
        }

      NodeList nl = wddxPacket.getChildNodes();
      int n = nl.getLength();

     
      for(int i = 0; i < n; i++) {
        Node data = nl.item(i);
        if(data.getNodeName().equals("data")) {
          NodeList list=data.getChildNodes();
          len=list.getLength();
          for(int y=0;y<len;y++) {
            Node node=list.item(y);
            if(node instanceof Element)
              return _deserialize((Element)node);
           
          }
        }
      }
     
      throw new IllegalArgumentException("Invalid WDDX Format: node 'data' not found in WDD packet");

    }
    catch(org.xml.sax.SAXException sxe) {
      throw new IllegalArgumentException("XML Error: " + sxe.toString());
    }
  }
 
 
 
  /**
   * deserialize a WDDX Package (XML Element) to a runtime object
   * @param element
   * @return deserialized Element
   * @throws ConverterException
   */
  private Object _deserialize(Element element) throws ConverterException {
    String nodeName=element.getNodeName().toLowerCase();
   
    // NULL
    if(nodeName.equals("null")) {
      return null;
    }
    // String
    else if(nodeName.equals("string")) {
      return _deserializeString(element);
      /*Node data=element.getFirstChild();
      if(data==null) return "";
     
      String value=data.getNodeValue();
     
      if(value==null) return "";
      return XMLUtil.unescapeXMLString(value);*/
    }
    // Number
    else if(nodeName.equals("number")) {
      try {
        Node data=element.getFirstChild();
        if(data==null) return new Double(0);
        return Caster.toDouble(data.getNodeValue());
      } catch (Exception e) {
        throw toConverterException(e);
      }
    }
    // Boolean
    else if(nodeName.equals("boolean")) {
      try {
        return Caster.toBoolean(element.getAttribute("value"));
      } catch (PageException e) {
        throw toConverterException(e);
       
      }
    }
    // Array
    else if(nodeName.equals("array")) {
      return _deserializeArray(element);
    }
    // Component
    else if(nodeName.equals("component")) {
      return  _deserializeComponent(element);
    }
    // Struct
    else if(nodeName.equals("struct")) {
      return  _deserializeStruct(element);
    }
    // Query
    else if(nodeName.equals("recordset")) {
      return  _deserializeQuery(element);
    }
    // DateTime
    else if(nodeName.equalsIgnoreCase("dateTime")) {
      try {
        return DateCaster.toDateAdvanced(element.getFirstChild().getNodeValue(),timeZone);
      }
            catch (Exception e) {
        throw toConverterException(e);
      }
    }
    // Query
    else if(nodeName.equals("binary")) {
      return  _deserializeBinary(element);
    }
    else
      throw new ConverterException("can't deserialize Element of type ["+nodeName+"] to a Object representation");
   
  }

  private Object _deserializeString(Element element) {
    NodeList childList = element.getChildNodes();
    int len = childList.getLength();
    StringBuffer sb=new StringBuffer();
    Node data;
    String str;
    for(int i=0;i<len;i++) {
      data=childList.item(i);
      if(data==null)continue;
     
      //<char code="0a"/>
      if("char".equals(data.getNodeName())) {
        str=((Element)data).getAttribute("code");
        sb.append((char)NumberUtil.hexToInt(str, 10));
      }
      else {
        sb.append(str=data.getNodeValue());
      }
    }
    return sb.toString();
    //return XMLUtil.unescapeXMLString(sb.toString());
  }

  /**
   * Desirialize a Query Object
   * @param recordset Query Object as XML Element
   * @return Query Object
   * @throws ConverterException
   */
  private Object _deserializeQuery(Element recordset) throws ConverterException {
    try {
      // create Query Object
      Query query=new QueryImpl(
          railo.runtime.type.util.ListUtil.listToArray(
              recordset.getAttribute("fieldNames"),','
          )
        ,Caster.toIntValue(recordset.getAttribute("rowCount")),"query"
      );
     
      NodeList list = recordset.getChildNodes();
      int len=list.getLength();
      for(int i=0;i<len;i++) {
        Node node=list.item(i);
        if(node instanceof Element) {
          _deserializeQueryField(query,(Element) node);
        }     
      }
      return query;
    }
    catch(PageException e) {
      throw toConverterException(e);
    }
   
  }
 


  private Object _deserializeBinary(Element el) throws ConverterException {
    Node node = el.getFirstChild();
    if(node instanceof CharacterData) {
      String data=((CharacterData)node).getData();
      try {
        return Base64Coder.decode(data);
      } catch (CoderException e) {
        throw new ConverterException(e.getMessage());
      }
    }
    throw new ConverterException("cannot convert serialized binary back to binary data");
  }

  /**
   * deserilize a single Field of a query WDDX Object
   * @param query
   * @param field
   * @throws ConverterException
   * @throws PageException
   */
  private void _deserializeQueryField(Query query,Element field) throws PageException, ConverterException {
    String name=field.getAttribute("name");
    NodeList list = field.getChildNodes();
    int len=list.getLength();
    int count=0;
    for(int i=0;i<len;i++) {
      Node node=list.item(i);
      if(node instanceof Element) {
        query.setAt(KeyImpl.init(name),++count,_deserialize((Element) node));
      }     
    }
   
  }
 
  /**
   * Desirialize a Component Object
   * @param elComp Component Object as XML Element
   * @return Component Object
   * @throws ConverterException
   * @throws ConverterException
   */
  private Object _deserializeComponent(Element elComp) throws ConverterException {
//    String type=elStruct.getAttribute("type");
    String name=elComp.getAttribute("name");
    String md5=elComp.getAttribute("md5");
   
    // TLPC
    PageContext pc = ThreadLocalPageContext.get();
   
    // Load comp
    ComponentAccess comp=null;
    try {
      comp = ComponentUtil.toComponentAccess(pc.loadComponent(name));
      if(!ComponentUtil.md5(comp).equals(md5)){
        throw new ConverterException("component ["+name+"] in this enviroment has not the same interface as the component to load, it is possible that one off the components has Functions added dynamicly.");
      }
    }
    catch (ConverterException e) {
      throw e;
    }
    catch (Exception e) {
      throw new ConverterException(e.getMessage());
    }
   
   
    NodeList list=elComp.getChildNodes();
    ComponentScope scope = comp.getComponentScope();
    int len=list.getLength();
    String scopeName;
    Element var,value;
    Collection.Key key;
    for(int i=0;i<len;i++) {
            Node node=list.item(i);
      if(node instanceof Element) {
        var=(Element)node;
        value=getChildElement((Element)node);
        scopeName=var.getAttribute("scope");
        if(value!=null) {
          key=Caster.toKey(var.getAttribute("name"),null);
          if(key==null) continue;
          if("variables".equalsIgnoreCase(scopeName))
            scope.setEL(key,_deserialize(value));
          else
            comp.setEL(key,_deserialize(value));
        }
            }
    }
        return comp;
  }

  /**
   * Desirialize a Struct Object
   * @param elStruct Struct Object as XML Element
   * @return Struct Object
   * @throws ConverterException
   */
  private Object _deserializeStruct(Element elStruct) throws ConverterException {
    String type=elStruct.getAttribute("type");
    Struct struct=new StructImpl();
       
    NodeList list=elStruct.getChildNodes();
    int len=list.getLength();
    for(int i=0;i<len;i++) {
            //print.ln(i);
           
      Node node=list.item(i);
      if(node instanceof Element) {
        Element var=(Element)node;
        Element value=getChildElement((Element)node);
        if(value!=null) {
          struct.setEL(var.getAttribute("name"),_deserialize(value));
         
        }
            }
    }
        if(struct.size()==0 && type!=null && type.length()>0) {
            return "";
        }       
    return struct;
  }

  /**
   * Desirialize a Struct Object
   * @param el Struct Object as XML Element
   * @return Struct Object
   * @throws ConverterException
   */
  private Array _deserializeArray(Element el) throws ConverterException {
    Array array=new ArrayImpl();
   
    NodeList list=el.getChildNodes();
    int len=list.getLength();
    for(int i=0;i<len;i++) {
      Node node=list.item(i);
      if(node instanceof Element)
        try {
          array.append(_deserialize((Element)node));
        } catch (PageException e) {
          throw toConverterException(e);
        }
     
    }
    return array;
  }

  /**
   * return fitst child Element of a Element, if there are no child Elements return null
   * @param parent parent node
   * @return child Element
   */
  private Element getChildElement(Element parent) {
    NodeList list=parent.getChildNodes();
    int len=list.getLength();
    for(int i=0;i<len;i++) {
      Node node=list.item(i);
      if(node instanceof Element) {
        return (Element)node;
      }     
    }
    return null;
  }
 
 
  /**
   * @return return current blockquote
   */
  private String goIn() {
    //StringBuffer rtn=new StringBuffer(deep);
    //for(int i=0;i<deep;i++) rtn.append('\t');
    //return rtn.toString();
    return "";
  }

    @Override
    public boolean equals(Object obj) {
        return timeZone.equals(obj);
    }
}
TOP

Related Classes of railo.runtime.converter.WDDXConverter

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.