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            @Override
052            public void release()   {
053                    super.release();
054                    input=null;
055                    action=null;
056                    output=null;
057                    validate=false;
058                    toplevelvariable=null;
059                    usetimezoneinfo=false;
060                    xmlConform=false;
061            }
062            
063    
064            /** set the value input
065            *  The value to be processed.
066            * @param input value to set
067            **/
068            public void setInput(Object input)      {
069                    this.input=input;
070            }
071    
072            /** set the value action
073            *  Specifies the action taken by the cfwddx tag.
074            * @param action value to set
075            **/
076            public void setAction(String action)    {
077                    this.action=action.toLowerCase();
078            }
079    
080            /** set the value output
081            *  The name of the variable to hold the output of the operation. This attribute is required for 
082            *               action = 'WDDX2CFML'. For all other actions, if this attribute is not provided, the result of the 
083            *               WDDX processing is outputted in the HTML stream.
084            * @param output value to set
085            **/
086            public void setOutput(String output)    {
087                    this.output=output;
088            }
089    
090            /** set the value validate
091            *  
092            * @param validate value to set
093            **/
094            public void setValidate(boolean validate)       {
095                    this.validate=validate;
096            }
097    
098            /** set the value toplevelvariable
099            *  The name of the top-level JavaScript object created by the deserialization process. The object 
100            *               created is an instance of the WddxRecordset object, explained in WddxRecordset Object.
101            * @param toplevelvariable value to set
102            **/
103            public void setToplevelvariable(String toplevelvariable)        {
104                    this.toplevelvariable=toplevelvariable;
105            }
106    
107            /** set the value usetimezoneinfo
108            *  Indicates whether to output time-zone information when serializing CFML to WDDX. If time-zone 
109            *               information is taken into account, the hour-minute offset, as represented in the ISO8601 format, is 
110            *               calculated in the date-time output. If time-zone information is not taken into account, the local 
111            *               time is output. The default is Yes.
112            * @param usetimezoneinfo value to set
113            **/
114            public void setUsetimezoneinfo(boolean usetimezoneinfo) {
115                    this.usetimezoneinfo=usetimezoneinfo;
116            }
117            
118            /**
119             * sets if generated code is xml or wddx conform
120             * @param xmlConform
121             */
122            public void setXmlconform(boolean xmlConform)   {
123                    this.xmlConform=xmlConform;
124            }
125    
126    
127            @Override
128            public int doStartTag() throws PageException    {
129                    try {
130                            doIt();
131                            
132                    } catch (Exception e) {
133                            throw Caster.toPageException(e);
134                    }
135                    return SKIP_BODY;
136            }
137            private void doIt() throws ExpressionException, PageException, ConverterException, IOException, FactoryConfigurationError       {
138            // cfml > wddx
139                    if(action.equals("cfml2wddx")) {
140                            if(output!=null) pageContext.setVariable(output,cfml2wddx(input));
141                            else pageContext.forceWrite(cfml2wddx(input));
142                    }
143                    
144            // wddx > cfml
145                    else if(action.equals("wddx2cfml")) {
146                            if(output==null) throw new ApplicationException("at tag cfwddx the attribute output is required if you set action==wddx2cfml");
147                            pageContext.setVariable(output,wddx2cfml(Caster.toString(input)));
148                    }
149                    
150            // cfml > js
151                    else if(action.equals("cfml2js")) {
152                            if(output!=null) pageContext.setVariable(output,cfml2js(input));
153                            else pageContext.forceWrite(cfml2js(input));
154                    }
155                    
156            // wddx > js
157                    else if(action.equals("wddx2js")) {
158                            if(output!=null) pageContext.setVariable(output,wddx2js(Caster.toString(input)));
159                            else pageContext.forceWrite(wddx2js(Caster.toString(input)));
160                    }
161                    
162                    
163                    else throw new ExpressionException("invalid attribute action for tag cfwddx, attributes are [cfml2wddx, wddx2cfml,cfml2js, wddx2js].");
164    
165            }
166            
167            private String cfml2wddx(Object input) throws ConverterException {
168                    WDDXConverter converter =new WDDXConverter(pageContext.getTimeZone(),xmlConform,true);
169                    if(!usetimezoneinfo)converter.setTimeZone(null);
170                    return converter.serialize(input);
171            }
172            private Object wddx2cfml(String input) throws ConverterException, IOException, FactoryConfigurationError {
173                    WDDXConverter converter =new WDDXConverter(pageContext.getTimeZone(),xmlConform,true);
174                    converter.setTimeZone(pageContext.getTimeZone());
175                    return converter.deserialize(input,validate);
176            }
177            private String cfml2js(Object input) throws ConverterException {
178                    if(toplevelvariable==null)missingTopLevelVariable();
179                    JSConverter converter =new JSConverter();
180                    return converter.serialize(input,toplevelvariable);
181            }
182            private String wddx2js(String input) throws ConverterException, IOException, FactoryConfigurationError {
183                    if(toplevelvariable==null)missingTopLevelVariable();
184                    JSConverter converter =new JSConverter();
185                    return converter.serialize(wddx2cfml(input),toplevelvariable);
186            }
187            
188            
189            private ApplicationException missingTopLevelVariable() {
190                    return new ApplicationException("at tag cfwddx the attribute topLevelVariable is required if you set action equal wddx2js or cfml2js");
191            }
192    
193    
194            @Override
195            public int doEndTag()   {
196                    return EVAL_PAGE;
197            }
198    }