001    package railo.runtime.tag;
002    
003    import java.io.IOException;
004    
005    import javax.xml.parsers.FactoryConfigurationError;
006    
007    import railo.runtime.converter.ConverterException;
008    import railo.runtime.converter.JSConverter;
009    import railo.runtime.converter.WDDXConverter;
010    import railo.runtime.exp.ApplicationException;
011    import railo.runtime.exp.ExpressionException;
012    import railo.runtime.exp.PageException;
013    import railo.runtime.ext.tag.TagImpl;
014    import railo.runtime.op.Caster;
015    
016    /**
017    * Serializes and de-serializes CFML data structures to the XML-based WDDX format. 
018    *   Generates JavaScript statements to instantiate JavaScript objects equivalent to the contents of a 
019    *   WDDX packet or some CFML data structures.
020    *
021    *
022    *
023    **/
024    public final class Wddx extends TagImpl {
025    
026            /** The value to be processed. */
027            private Object input;
028    
029            /** Specifies the action taken by the cfwddx tag. */
030            private String action;
031    
032            /** The name of the variable to hold the output of the operation. This attribute is required for 
033            **              action = 'WDDX2CFML'. For all other actions, if this attribute is not provided, the result of the 
034            **              WDDX processing is outputted in the HTML stream. */
035            private String output;
036    
037            private boolean validate;
038    
039            /** The name of the top-level JavaScript object created by the deserialization process. The object 
040            **              created is an instance of the WddxRecordset object, explained in WddxRecordset Object. */
041            private String toplevelvariable;
042    
043            /** Indicates whether to output time-zone information when serializing CFML to WDDX. If time-zone 
044            **              information is taken into account, the hour-minute offset, as represented in the ISO8601 format, is 
045            **              calculated in the date-time output. If time-zone information is not taken into account, the local 
046            **              time is output. The default is Yes. */
047            private boolean usetimezoneinfo;
048    
049            private boolean xmlConform;
050    
051            /**
052            * @see javax.servlet.jsp.tagext.Tag#release()
053            */
054            public void release()   {
055                    super.release();
056                    input=null;
057                    action=null;
058                    output=null;
059                    validate=false;
060                    toplevelvariable=null;
061                    usetimezoneinfo=false;
062                    xmlConform=false;
063            }
064            
065    
066            /** set the value input
067            *  The value to be processed.
068            * @param input value to set
069            **/
070            public void setInput(Object input)      {
071                    this.input=input;
072            }
073    
074            /** set the value action
075            *  Specifies the action taken by the cfwddx tag.
076            * @param action value to set
077            **/
078            public void setAction(String action)    {
079                    this.action=action.toLowerCase();
080            }
081    
082            /** set the value output
083            *  The name of the variable to hold the output of the operation. This attribute is required for 
084            *               action = 'WDDX2CFML'. For all other actions, if this attribute is not provided, the result of the 
085            *               WDDX processing is outputted in the HTML stream.
086            * @param output value to set
087            **/
088            public void setOutput(String output)    {
089                    this.output=output;
090            }
091    
092            /** set the value validate
093            *  
094            * @param validate value to set
095            **/
096            public void setValidate(boolean validate)       {
097                    this.validate=validate;
098            }
099    
100            /** set the value toplevelvariable
101            *  The name of the top-level JavaScript object created by the deserialization process. The object 
102            *               created is an instance of the WddxRecordset object, explained in WddxRecordset Object.
103            * @param toplevelvariable value to set
104            **/
105            public void setToplevelvariable(String toplevelvariable)        {
106                    this.toplevelvariable=toplevelvariable;
107            }
108    
109            /** set the value usetimezoneinfo
110            *  Indicates whether to output time-zone information when serializing CFML to WDDX. If time-zone 
111            *               information is taken into account, the hour-minute offset, as represented in the ISO8601 format, is 
112            *               calculated in the date-time output. If time-zone information is not taken into account, the local 
113            *               time is output. The default is Yes.
114            * @param usetimezoneinfo value to set
115            **/
116            public void setUsetimezoneinfo(boolean usetimezoneinfo) {
117                    this.usetimezoneinfo=usetimezoneinfo;
118            }
119            
120            /**
121             * sets if generated code is xml or wddx conform
122             * @param xmlConform
123             */
124            public void setXmlconform(boolean xmlConform)   {
125                    this.xmlConform=xmlConform;
126            }
127    
128    
129            /**
130            * @see javax.servlet.jsp.tagext.Tag#doStartTag()
131            */
132            public int doStartTag() throws PageException    {
133                    try {
134                            doIt();
135                            
136                    } catch (Exception e) {
137                            throw Caster.toPageException(e);
138                    }
139                    return SKIP_BODY;
140            }
141            private void doIt() throws ExpressionException, PageException, ConverterException, IOException, FactoryConfigurationError       {
142            // cfml > wddx
143                    if(action.equals("cfml2wddx")) {
144                            if(output!=null) pageContext.setVariable(output,cfml2wddx(input));
145                            else pageContext.forceWrite(cfml2wddx(input));
146                    }
147                    
148            // wddx > cfml
149                    else if(action.equals("wddx2cfml")) {
150                            if(output==null) throw new ApplicationException("at tag cfwddx the attribute output is required if you set action==wddx2cfml");
151                            pageContext.setVariable(output,wddx2cfml(Caster.toString(input)));
152                    }
153                    
154            // cfml > js
155                    else if(action.equals("cfml2js")) {
156                            if(output!=null) pageContext.setVariable(output,cfml2js(input));
157                            else pageContext.forceWrite(cfml2js(input));
158                    }
159                    
160            // wddx > js
161                    else if(action.equals("wddx2js")) {
162                            if(output!=null) pageContext.setVariable(output,wddx2js(Caster.toString(input)));
163                            else pageContext.forceWrite(wddx2js(Caster.toString(input)));
164                    }
165                    
166                    
167                    else throw new ExpressionException("invalid attribute action for tag cfwddx, attributes are [cfml2wddx, wddx2cfml,cfml2js, wddx2js].");
168    
169            }
170            
171            private String cfml2wddx(Object input) throws ConverterException {
172                    WDDXConverter converter =new WDDXConverter(pageContext.getTimeZone(),xmlConform,true);
173                    if(!usetimezoneinfo)converter.setTimeZone(null);
174                    return converter.serialize(input);
175            }
176            private Object wddx2cfml(String input) throws ConverterException, IOException, FactoryConfigurationError {
177                    WDDXConverter converter =new WDDXConverter(pageContext.getTimeZone(),xmlConform,true);
178                    converter.setTimeZone(pageContext.getTimeZone());
179                    return converter.deserialize(input,validate);
180            }
181            private String cfml2js(Object input) throws ConverterException {
182                    if(toplevelvariable==null)missingTopLevelVariable();
183                    JSConverter converter =new JSConverter();
184                    return converter.serialize(input,toplevelvariable);
185            }
186            private String wddx2js(String input) throws ConverterException, IOException, FactoryConfigurationError {
187                    if(toplevelvariable==null)missingTopLevelVariable();
188                    JSConverter converter =new JSConverter();
189                    return converter.serialize(wddx2cfml(input),toplevelvariable);
190            }
191            
192            
193            private ApplicationException missingTopLevelVariable() {
194                    return new ApplicationException("at tag cfwddx the attribute topLevelVariable is required if you set action equal wddx2js or cfml2js");
195            }
196    
197    
198            /**
199            * @see javax.servlet.jsp.tagext.Tag#doEndTag()
200            */
201            public int doEndTag()   {
202                    return EVAL_PAGE;
203            }
204    }