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