This commit is contained in:
msyu
2024-10-23 11:17:42 +03:00
commit ab5c944862
380 changed files with 55823 additions and 0 deletions
@@ -0,0 +1,26 @@
<cfcomponent output="false">
<cfscript>
this.name = "taffy_ParentAppExample";//same name as parent folder application.cfc
this.applicationTimeout = createTimeSpan(0,2,0,0);
this.sessionManagement = false;
this.setClientCookies = false;
this.scriptProtect = false;
</cfscript>
<cffunction name="onApplicationStart" returnType="boolean" output="false">
<cfinclude template="mixin/appInit.cfm" />
<cfreturn true />
</cffunction>
<cffunction name="onRequestStart" returnType="boolean" output="false">
<cfargument name="thePage" type="string" required="true" />
<cfif structKeyExists(url, "reinit")>
<cfset onApplicationStart() />
</cfif>
<cfreturn true />
</cffunction>
</cfcomponent>
@@ -0,0 +1,6 @@
RewriteEngine On
#if we've already been rewritten to use index.cfm/* format, don't make a circular request
RewriteRule index\.cfm/* - [L]
RewriteRule ^(.*)$ index.cfm/$1
@@ -0,0 +1,16 @@
component extends="taffy.core.api" {
this.name = "taffy_ParentAppExample";//same name as api folder application.cfc
variables.framework = {};
variables.framework.beanFactory = "";
function onApplicationStart(){
include "../mixin/appInit.cfm";
variables.framework.beanFactory = application.beanFactory;
return super.onApplicationStart();
}
}
@@ -0,0 +1,6 @@
<!---
DO NOT DELETE THIS FILE
===============================
This file is necessary for Taffy to work, but should be blank.
All requests funnel through it, but are handled by framework internal functionality.
--->
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="fakeData" class="taffy.examples.shared.fakeData" />
<bean id="fooCollection" class="taffy.examples.ParentApplication.model.fooCollection">
<property name="fakeData">
<ref bean="fakeData" />
</property>
</bean>
</beans>
@@ -0,0 +1,5 @@
<h1>Parent Application</h1>
<p>Hi there. I'm the parent application. Want to see what's under the hood?</p>
<cfdump var="#application#">
@@ -0,0 +1,2 @@
<cfset application.beanFactory = createObject("component", "coldspring.beans.DefaultXMLBeanFactory") />
<cfset application.beanFactory.loadBeans('/taffy/examples/ParentApplication/config/coldspring.xml') />
@@ -0,0 +1,13 @@
<cfcomponent extends="taffy.core.resource" taffy_uri="/foo">
<cffunction name="get" access="public" output="false">
<cfreturn representationOf(variables.fakeData.getData()).withStatus(200) />
</cffunction>
<!--- this will be called by the bean factory's autowire functionality --->
<cffunction name="setFakeData" access="public" output="false" returnType="void">
<cfargument name="fakeDataObj" type="any" required="true" hint="Shared FakeData object" />
<cfset variables.fakeData = arguments.fakeDataObj />
</cffunction>
</cfcomponent>
+6
View File
@@ -0,0 +1,6 @@
RewriteEngine On
#if we've already been rewritten to use index.cfm/* format, don't make a circular request
RewriteRule index\.cfm/* - [L]
RewriteRule ^(.*)$ index.cfm/$1
+30
View File
@@ -0,0 +1,30 @@
<cfcomponent extends="taffy.core.api">
<cfscript>
this.name = hash(getCurrentTemplatePath());
this.mappings["/resources"] = listDeleteAt(cgi.script_name, listLen(cgi.script_name, "/"), "/") & "/resources";
variables.framework = {};
variables.framework.debugKey = "debug";
variables.framework.reloadKey = "reload";
variables.framework.reloadPassword = "true";
variables.framework.serializer = "taffy.core.nativeJsonSerializer";
variables.framework.returnExceptionsAsJson = true;
function onApplicationStart(){
return super.onApplicationStart();
}
function onRequestStart(TARGETPATH){
return super.onRequestStart(TARGETPATH);
}
// this function is called after the request has been parsed and all request details are known
function onTaffyRequest(verb, cfc, requestArguments, mimeExt){
// this would be a good place for you to check API key validity and other non-resource-specific validation
return true;
}
</cfscript>
</cfcomponent>
+6
View File
@@ -0,0 +1,6 @@
<!---
DO NOT DELETE THIS FILE
===============================
This file is necessary for Taffy to work, but should be blank.
All requests funnel through it, but are handled by framework internal functionality.
--->
@@ -0,0 +1,24 @@
<cfcomponent extends="taffy.core.resource" taffy_uri="/artist/{artistId}/art/{artId}">
<cfset variables.dummyData = StructNew() />
<cfset variables.dummyData.whatever = true />
<cfset variables.dummyData.phone = encode.string(5558675309) />
<cfset variables.dummyData.phoneNumeric = 5558675309 />
<cffunction name="get" access="public" output="false">
<cfreturn representationOf(variables.dummyData).withStatus(200) />
</cffunction>
<cffunction name="post" access="public" output="false">
<cfreturn representationOf(variables.dummyData).withStatus(200) />
</cffunction>
<cffunction name="put" access="public" output="false">
<cfreturn representationOf(variables.dummyData).withStatus(200) />
</cffunction>
<cffunction name="delete" access="public" output="false">
<cfreturn representationOf(variables.dummyData).withStatus(200) />
</cffunction>
</cfcomponent>
@@ -0,0 +1,84 @@
<cfcomponent extends="taffy.core.resource" taffy:uri="/artist/{id}" hint="some hint about this resource">
<cffunction name="get" access="public" output="false">
<cfargument name="id" type="numeric" required="true" />
<cfset var q = ""/>
<cfset var col = "" />
<cfset var rtn = StructNew() />
<cfquery name="q" datasource="cfartgallery">
select * from artists where artistId = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.id#" />
</cfquery>
<cfif q.recordCount gt 0>
<cfloop list="#q.ColumnList#" index="col">
<cfset rtn[col] = q[col][1] />
</cfloop>
<cfreturn representationOf(rtn).withStatus(200) />
<cfelse>
<cfreturn noData().withStatus(404) />
</cfif>
</cffunction>
<cffunction name="put" access="public" output="false">
<cfargument name="id" type="numeric" required="true" />
<cfargument name="firstname" type="string" required="false" default="" />
<cfargument name="lastname" type="string" required="false" default="" />
<cfargument name="address" type="string" required="false" default="" hint="some hint about this parameter" />
<cfargument name="city" type="string" required="false" default="" />
<cfargument name="state" type="string" required="false" default="" />
<cfargument name="postalcode" type="string" required="false" default="" />
<cfargument name="email" type="string" required="false" default="" />
<cfargument name="phone" type="string" required="false" default="" />
<cfargument name="fax" type="string" required="false" default="" />
<cfargument name="thepassword" type="string" required="false" default="" />
<cfset var q = "" />
<cfquery name="q" datasource="cfartgallery">
update artists
set artistid=artistid
<cfif len(arguments.firstname)>
,firstname = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.firstname#" />
</cfif>
<cfif len(arguments.lastname)>
,lastname = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.lastname#" />
</cfif>
<cfif len(arguments.address)>
,address = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.address#" />
</cfif>
<cfif len(arguments.city)>
,city = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.city#" />
</cfif>
<cfif len(arguments.state)>
,state = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.state#" />
</cfif>
<cfif len(arguments.postalcode)>
,postalcode = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.postalcode#" />
</cfif>
<cfif len(arguments.email)>
,email = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.email#" />
</cfif>
<cfif len(arguments.phone)>
,phone = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.phone#" />
</cfif>
<cfif len(arguments.fax)>
,fax = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.fax#" />
</cfif>
<cfif len(arguments.thepassword)>
,thepassword = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.thepassword#" />
</cfif>
where artistid = <cfqueryparam cfsqltype="cf_sql_numeric" value="#arguments.id#" />
</cfquery>
<cfreturn noData().withStatus(200) />
</cffunction>
<cffunction name="delete" access="public" output="false">
<cfargument name="id" type="numeric" required="true" />
<cfset var q = "" />
<cfquery name="q" datasource="cfartgallery">
delete from artists where artistid = <cfqueryparam cfsqltype="cf_sql_numeric" value="#arguments.id#" />
</cfquery>
<cfreturn noData().withStatus(200) />
</cffunction>
<cffunction name="someInternalMethod" hint="you should not see this documentation...">
</cffunction>
</cfcomponent>
@@ -0,0 +1,15 @@
<cfcomponent extends="taffy.core.resource" taffy:uri="/artist/{artistId}/art" hint="Collection of art data">
<cfset variables.dummyData = StructNew() />
<cfset variables.dummyData.whatever = true />
<cffunction name="get" access="public" output="false" hint="Get some collection of art data">
<cfargument name="artistId" type="numeric" required="true" />
<cfreturn representationOf(variables.dummyData).withStatus(200) />
</cffunction>
<cffunction name="post" access="public" output="false" hint="Insert a new art record">
<cfreturn representationOf(variables.dummyData).withStatus(200) />
</cffunction>
</cfcomponent>
@@ -0,0 +1,59 @@
<cfcomponent extends="taffy.core.resource" taffy_uri="/artists">
<cffunction name="get" access="public" output="false">
<cfset var q = "" />
<cfquery name="q" datasource="cfartgallery">
select * from artists
</cfquery>
<cfreturn representationOf(q).withStatus(200) />
</cffunction>
<cffunction name="post" access="public" output="false">
<cfargument name="firstname" type="string" required="false" default="" />
<cfargument name="lastname" type="string" required="false" default="" />
<cfargument name="address" type="string" required="false" default="" />
<cfargument name="city" type="string" required="false" default="" />
<cfargument name="state" type="string" required="false" default="" />
<cfargument name="postalcode" type="string" required="false" default="" />
<cfargument name="email" type="string" required="false" default="" />
<cfargument name="phone" type="string" required="false" default="" />
<cfargument name="fax" type="string" required="false" default="" />
<cfargument name="thepassword" type="string" required="false" default="" />
<cfset var q = "" />
<cfquery name="q" datasource="cfartgallery">
insert into artists (firstname,lastname,address,city,state,postalcode,email,phone,fax,thepassword)
values (
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.firstname#" />,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.lastname#" />,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.address#" />,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.city#" />,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.state#" />,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.postalcode#" />,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.email#" />,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.phone#" />,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.fax#" />,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.thepassword#" />
)
</cfquery>
<cfquery name="q" datasource="cfartgallery">
select * from artists
where
firstname = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.firstname#" />
and lastname = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.lastname#" />
and address = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.address#" />
and city = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.city#" />
and state = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.state#" />
and postalcode = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.postalcode#" />
and email = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.email#" />
and phone = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.phone#" />
and fax = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.fax#" />
and thepassword = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.thepassword#" />
</cfquery>
<cfreturn representationOf(q).withStatus(200) />
</cffunction>
<!---
The DELETE and PUT verbs are not implemented, so those actions are not permitted.
--->
</cfcomponent>
@@ -0,0 +1,18 @@
<cfcomponent extends="taffy.core.api">
<cfscript>
this.name = hash(getCurrentTemplatePath());
variables.framework = {};
variables.framework.exceptionLogAdapter = "taffy.bonus.LogToBugLogHQ";
variables.framework.exceptionLogAdapterConfig = StructNew();
variables.framework.exceptionLogAdapterConfig.bugLogListener = "bugLog.listeners.bugLogListenerWS";
variables.framework.exceptionLogAdapterConfig.bugEmailRecipients = "you@yourdomain.com";
variables.framework.exceptionLogAdapterConfig.bugEmailSender = "errors@yourdomain.com";
variables.framework.exceptionLogAdapterConfig.hostname = "Taffy_DEV_Examples";
variables.framework.exceptionLogAdapterConfig.apikey = "";
</cfscript>
</cfcomponent>
@@ -0,0 +1,7 @@
<cfcomponent extends="taffy.core.resource" taffy_uri="/foo">
<cffunction name="get" access="public" output="false">
<cfthrow message="this is the message" detail="this is the detail" />
</cffunction>
</cfcomponent>
+17
View File
@@ -0,0 +1,17 @@
<cfcomponent extends="taffy.core.api">
<cfscript>
this.name = hash(getCurrentTemplatePath());
variables.framework = {};
function onApplicationStart(){
application.beanFactory = createObject("component", "di1.ioc").init( "/taffy/examples/api_DI1/model" );
variables.framework.beanFactory = application.beanFactory;
return super.onApplicationStart();
}
</cfscript>
</cfcomponent>
View File
+7
View File
@@ -0,0 +1,7 @@
<cfcomponent extends="taffy.core.resource" taffy:uri="/foo">
<cffunction name="get">
<cfreturn representationOf("hi").withStatus(200) />
</cffunction>
</cfcomponent>
@@ -0,0 +1,10 @@
<cfcomponent extends="taffy.core.api">
<cfscript>
this.name = hash(getCurrentTemplatePath());
variables.framework = {};
variables.framework.exceptionLogAdapter = "taffy.bonus.LogToHoth";
variables.framework.exceptionLogAdapterConfig = "taffy.examples.api_hoth.resources.HothConfig";
</cfscript>
</cfcomponent>
@@ -0,0 +1 @@
Hoth: The files within this directory contain the complete details for each unique exception.
@@ -0,0 +1 @@
Hoth: The files within this directory contain the details about the volume of errors for each unique exception.
+6
View File
@@ -0,0 +1,6 @@
<!---
DO NOT DELETE THIS FILE
===============================
This file is necessary for Taffy to work, but should be blank.
All requests funnel through it, but are handled by framework internal functionality.
--->
@@ -0,0 +1,57 @@
component
implements = 'Hoth.object.iHothConfig'
extends = 'Hoth.object.CoreConfig'
accessors = 'true'
{
/** What is the name of your application? */
property
name='applicationName'
default='Taffy Tests';
/** How many seconds should we lock file operations?
For most operations this is exclusive to a unique exception. */
property
name='timeToLock'
default='4';
/** Where would you like Hoth to save exception data?
This folder should be empty. */
property
name='logPath'
default='/taffy/examples/api_hoth/hoth/exceptions';
// ------------------------------------------------------------------------------
/** Would you like new exceptions to be emailed to you? */
property
name='EmailNewExceptions'
default='true';
/** What address(es) should receive these e-mails? */
property
name='EmailNewExceptionsTo'
default='you@yourdomain.com';
/** What address would you like these emails sent from? */
property
name='EmailNewExceptionsFrom'
default='hoth-error-report@yourdomain.com';
/** Would you like the raw JSON attached to the e-mail? */
property
name='EmailNewExceptionsFile'
default='true';
// ------------------------------------------------------------------------------
/**
The mapping where you would like Hoth to write it's log files.
Without this setting, Hoth will write log files to the same directory
Hoth is located within. This is not recomended as your will have content
mixed into your Hoth code.
**/
setGlobalDatabasePath(path='/taffy/examples/api_hoth/hoth/logs/');
//make the log path be evaluated as relative
variables.logPathIsRelative = true;
}
@@ -0,0 +1,7 @@
<cfcomponent extends="taffy.core.resource" taffy_uri="/foo">
<cffunction name="get" access="public" output="false">
<cfthrow message="this is the message" detail="this is the detail" />
</cffunction>
</cfcomponent>
@@ -0,0 +1,17 @@
<cfcomponent extends="taffy.core.api">
<cfscript>
this.name = hash(getCurrentTemplatePath());
variables.framework = {};
variables.framework.exceptionLogAdapter = "taffy.bonus.LogToEmail";
variables.framework.exceptionLogAdapterConfig = StructNew();
variables.framework.exceptionLogAdapterConfig.emailFrom = "api-error@yourdomain.com";
variables.framework.exceptionLogAdapterConfig.emailTo = "you@yourdomain.com";
variables.framework.exceptionLogAdapterConfig.emailSubj = "Exception Trapped in API";
variables.framework.exceptionLogAdapterConfig.emailType = "html";
</cfscript>
</cfcomponent>
@@ -0,0 +1,10 @@
<cfcomponent extends="taffy.core.resource" taffy_uri="/foo">
<cffunction name="get" access="public" output="false">
<cfset local.exception = {} />
<cfset local.exception.message = "testing log to email from resource saveLog()" />
<cfset saveLog(local.exception) />
<cfreturn noData().withStatus(200, "Log Saved") />
</cffunction>
</cfcomponent>
@@ -0,0 +1,6 @@
RewriteEngine On
#if we've already been rewritten to use index.cfm/* format, don't make a circular request
RewriteRule index\.cfm/* - [L]
RewriteRule ^(.*)$ index.cfm/$1
@@ -0,0 +1,16 @@
<cfcomponent extends="taffy.core.api">
<cfscript>
this.name = hash(getCurrentTemplatePath());
variables.framework = {};
variables.framework.serializer = "taffy.bonus.AnythingToXmlRepresentation";
function onApplicationStart(){
application.anythingToXml = createObject("component", "anythingtoxml.AnythingToXML").init();
return super.onApplicationStart();
}
</cfscript>
</cfcomponent>
@@ -0,0 +1,69 @@
<cfcomponent displayname="AnythingToXML" namespace="AnythingToXML" output="no">
<!--- Anything To XML by Daniel Gaspar <daniel.gaspar@gmail.com> 5/1/2008 --->
<!---
Copyright 2008 Daniel Gaspar Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or
agreed to in writing, software distributed under the License is distributed on an "AS IS"
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
for the specific language governing permissions and limitations under the License.
--->
<cffunction name="init" access="public" output="no" returntype="any">
<cfargument name="Include_Type_Hinting" type="numeric" required="no" default="1" />
<cfset variables.TabUtils = createObject('component', 'TabUtils').init() />
<cfset variables.XMLutils = createObject('component', 'XMLutils').init() />
<cfset variables.StructToXML = createObject('component','StructToXML').init(arguments.Include_Type_Hinting,XMLutils,TabUtils) />
<cfset variables.QueryToXML = createObject('component','QueryToXML').init(arguments.Include_Type_Hinting,XMLutils,TabUtils) />
<cfset variables.ArrayToXML = createObject('component','ArrayToXML').init(arguments.Include_Type_Hinting,XMLutils,TabUtils) />
<cfset variables.ObjectToXML = createObject('component','ObjectToXML').init(arguments.Include_Type_Hinting,XMLutils,TabUtils) />
<cfset variables.Include_Type_Hinting = arguments.Include_Type_Hinting />
<cfset variables.StructToXML.setAnythingToXML(this) />
<cfset variables.QueryToXML.setAnythingToXML(this) />
<cfset variables.ArrayToXML.setAnythingToXML(this) />
<cfset variables.ObjectToXML.setAnythingToXML(this) />
<cfreturn this>
</cffunction>
<cffunction name="ToXML" access="public" output="no" returntype="string" hint="This function converts simple types, arrays, queries, structures, objects with properties, or any combination of these to XML">
<cfargument name="ThisItem" type="any" required="yes" hint="simple type, array, query, structure, object with properties, or any combination of previous">
<cfargument name="NodeName" type="string" required="no" default="XML_ELEMENT" hint="name of a node">
<cfargument name="AttributeList" type="string" required="no" default="" hint="List of Column Names/Struct Keys that should become Attributes of the XML Node" />
<cfset var returnstring = "">
<!---initalize cfc if it is not --->
<cfif not structkeyexists(variables, "TabUtils") >
<cfset init() />
</cfif>
<!--- If this is the 1st time add XML encoding. Comment this out for Debugging --->
<cfif variables.TabUtils.tabs eq 0 >
<!---cfcontent type="text/xml; charset=utf-8">--->
<cfset returnstring = '<?xml version="1.0" encoding="utf-8"?>' />
</cfif>
<!--- Decide how to create the XML --->
<cfif isSimpleValue(ThisItem) >
<cfset returnstring = returnstring & "#variables.TabUtils.printtabs()#<#variables.XMLutils.NodeNameCheck(arguments.NodeName)#><![CDATA[#trim(ThisItem)#]]></#variables.XMLutils.NodeNameCheck(arguments.NodeName)#>" />
<cfelseif isArray(ThisItem)>
<cfset returnstring = returnstring & variables.ArrayToXML.ArrayToXML(arguments.ThisItem,arguments.NodeName,arguments.AttributeList)>
<cfelseif isQuery(ThisItem)>
<cfset returnstring = returnstring & variables.QueryToXML.QueryToXML(arguments.ThisItem,arguments.NodeName,arguments.AttributeList)>
<cfelseif structkeyexists(getMetaData(ThisItem), "properties") >
<cfset returnstring = returnstring & variables.ObjectToXML.ObjectToXML(arguments.ThisItem,arguments.NodeName,arguments.AttributeList)>
<cfelseif isStruct(ThisItem)>
<cfset returnstring = returnstring & variables.StructToXML.StructToXML(arguments.ThisItem,arguments.NodeName,arguments.AttributeList)>
<cfelseif IsCustomFunction(ThisItem)>
<!--- ignore --->
<cfelse>
<cfset returnstring = returnstring & "#variables.TabUtils.printtabs()#<ERROR>Unable to Convert this element to XML</ERROR>" />
<!---<cfdump var="#arguments.ThisItem#" /><cfabort />--->
</cfif>
<cfreturn returnstring>
</cffunction>
</cfcomponent>
@@ -0,0 +1,74 @@
<cfcomponent namespace="ArrayToXML" displayname="ArrayToXML" output="no" >
<!--- Array to XML by Daniel Gaspar <daniel.gaspar@gmail.com> 5/1/2008 --->
<!---
Copyright 2008 Daniel Gaspar Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or
agreed to in writing, software distributed under the License is distributed on an "AS IS"
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
for the specific language governing permissions and limitations under the License.
--->
<cffunction name="init" access="public" output="no" returntype="any">
<cfargument name="Include_Type_Hinting" type="numeric" required="no" default="1" />
<cfargument name="XMLutils" type="any" required="yes" />
<cfargument name="TabUtils" type="any" required="yes" />
<cfset variables.Include_Type_Hinting = arguments.Include_Type_Hinting />
<cfset variables.XMLutils = arguments.XMLutils />
<cfset variables.TabUtils = arguments.TabUtils />
<cfreturn this>
</cffunction>
<cffunction name="setAnythingToXML" access="public" output="no" returntype="void">
<cfargument name="AnythingToXML" type="any" required="yes" />
<cfset variables.AnythingToXML = arguments.AnythingToXML />
</cffunction>
<cffunction name="ArrayToXML" access="public" output="no" returntype="string" >
<cfargument name="TheseItems" type="array" required="yes">
<cfargument name="rootNodeName" type="string" required="no" default="">
<cfargument name="AttributeList" type="string" required="no" default="">
<cfset var xmlString = "" />
<cfset var i = 1 />
<cfprocessingdirective suppresswhitespace="yes">
<cfsetting enablecfoutputonly="yes">
<cfsavecontent variable="xmlString" >
<cfoutput>#variables.TabUtils.printtabs()#<#variables.XMLutils.getNodePlural(arguments.rootNodeName)# <cfif variables.Include_Type_Hinting eq 1>CF_TYPE='array'</cfif>></cfoutput>
<cfoutput>#createXML(arguments.TheseItems,arguments.rootNodeName,arguments.AttributeList)#</cfoutput>
<cfoutput>#variables.TabUtils.printtabs()#</#variables.XMLutils.getNodePlural(arguments.rootNodeName)#></cfoutput>
</cfsavecontent>
</cfprocessingdirective>
<cfreturn xmlString />
</cffunction>
<cffunction name="createXML" access="public" output="no" returntype="string">
<cfargument name="thisArray" type="Array" required="yes">
<cfargument name="rootNodeName" type="string" required="no" default="">
<cfargument name="AttributeList" type="string" required="no" default="">
<cfset var thisSize = thisArray.size() />
<cfset var xmlString = "" />
<cfset var i = 1 />
<cfset var CurrentNode = '' />
<cfset variables.TabUtils.addtab() />
<cfprocessingdirective suppresswhitespace="yes">
<cfsetting enablecfoutputonly="yes">
<cfsavecontent variable="xmlString" >
<cfloop from="1" to="#thisSize#" index="i" >
<cfif IsSimpleValue(thisArray[i])>
<cfset CurrentNode = variables.XMLutils.NodeNameCheck(rootNodeName) />
<cfoutput>#variables.TabUtils.printtabs()#<#CurrentNode#><![CDATA[#trim(thisArray[i])#]]></#CurrentNode#></cfoutput>
<cfelse>
<!--- Yay for Recursion!--->
<cfoutput>#variables.AnythingToXML.ToXML(thisArray[i],arguments.rootNodeName,arguments.AttributeList)#</cfoutput>
</cfif>
</cfloop>
</cfsavecontent>
</cfprocessingdirective>
<cfset variables.TabUtils.removetab() />
<cfreturn xmlString />
</cffunction>
</cfcomponent>
@@ -0,0 +1,121 @@
<cfcomponent namespace="ObjectToXML" displayname="ObjectToXML" output="no" >
<!--- Object to XML by Daniel Gaspar <daniel.gaspar@gmail.com> 5/1/2008
Thanks to Brian Rinaldi for getting the function introspection working. --->
<!---
Copyright 2008 Daniel Gaspar Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or
agreed to in writing, software distributed under the License is distributed on an "AS IS"
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
for the specific language governing permissions and limitations under the License.
--->
<cffunction name="init" access="public" output="no" returntype="any">
<cfargument name="Include_Type_Hinting" type="numeric" required="no" default="1" />
<cfargument name="XMLutils" type="any" required="yes" />
<cfargument name="TabUtils" type="any" required="yes" />
<cfset variables.Include_Type_Hinting = arguments.Include_Type_Hinting />
<cfset variables.XMLutils = arguments.XMLutils />
<cfset variables.TabUtils = arguments.TabUtils />
<cfreturn this>
</cffunction>
<cffunction name="setAnythingToXML" access="public" output="no" returntype="void">
<cfargument name="AnythingToXML" type="any" required="yes" />
<cfset variables.AnythingToXML = arguments.AnythingToXML />
</cffunction>
<cffunction name="ObjectToXML" access="public" output="no" returntype="string" >
<cfargument name="ThisObj" type="any" required="yes">
<cfargument name="rootNodeName" type="string" required="no" default="">
<cfargument name="AttributeList" type="string" required="no" default="">
<cfset var xmlString = "" />
<cfset var i = 1 />
<cfset var AttributeCollection = getMetaData(arguments.ThisObj).properties />
<cfsetting enablecfoutputonly="yes">
<cfprocessingdirective suppresswhitespace="yes">
<cfsavecontent variable="xmlString" >
<cfoutput>#variables.TabUtils.printtabs()#</cfoutput>
<cfoutput><#addNodeAttributes(arguments.rootNodeName,AttributeCollection,arguments.ThisObj,arguments.AttributeList)# <cfif variables.Include_Type_Hinting eq 1>CF_TYPE='object'</cfif>></cfoutput>
<cfoutput>#createXML(arguments.ThisObj,arguments.rootNodeName,arguments.AttributeList)#</cfoutput>
<cfoutput>#variables.TabUtils.printtabs()#</#variables.XMLutils.NodeNameCheck(arguments.rootNodeName)#></cfoutput>
</cfsavecontent>
</cfprocessingdirective>
<cfreturn xmlString />
</cffunction>
<cffunction name="createXML" access="public" output="no" returntype="string">
<cfargument name="ThisObj" type="any" required="yes">
<cfargument name="rootNodeName" type="string" required="no" default="">
<cfargument name="AttributeList" type="string" required="no" default="">
<cfset var aProperties = getMetaData(ThisObj).properties />
<cfset var aMethods = getMetaData(ThisObj).functions />
<cfset var methodName = "" />
<cfset var tmp = "" />
<cfset var thisSize = ArrayLen(aProperties) />
<cfset var xmlString = "" />
<cfset var i = 1 />
<cfset var CurrentNode = '' />
<cfset variables.TabUtils.addtab() />
<cfsetting enablecfoutputonly="yes">
<cfprocessingdirective suppresswhitespace="yes">
<cfsavecontent variable="xmlString" >
<cfloop from="1" to="#thisSize#" index="i" >
<cfset methodName = "get" & aProperties[i].name />
<cfif structkeyexists(ThisObj, aProperties[i].name)>
<cfif IsSimpleValue(evaluate("ThisObj." & aProperties[i].name))>
<cfif not ListFindNoCase(arguments.AttributeList,aProperties[i].name)>
<cfset CurrentNode = variables.XMLutils.NodeNameCheck(aProperties[i].name) />
<cfoutput>#variables.TabUtils.printtabs()#</cfoutput>
<cfoutput><#CurrentNode#><![CDATA[#trim(evaluate("ThisObj." & aProperties[i].name))#]]></#CurrentNode#></cfoutput>
</cfif>
<cfelse>
<!--- Yay for Recursion!--->
<cfoutput>#variables.AnythingToXML.ToXML(ThisObj[aProperties[i].name], aProperties[i].name,arguments.AttributeList)#</cfoutput>
</cfif>
<cfelse>
<cfif isdefined("ThisObj." & methodName) >
<cfinvoke component="#ThisObj#" method="#methodName#" returnvariable="tmp" />
<cfif IsSimpleValue(tmp)>
<cfif not ListFindNoCase(arguments.AttributeList,aProperties[i].name)>
<cfset CurrentNode = variables.XMLutils.NodeNameCheck(aProperties[i].name) />
<cfoutput>#variables.TabUtils.printtabs()#</cfoutput>
<cfoutput><#CurrentNode#><![CDATA[#trim(tmp)#]]></#CurrentNode#></cfoutput>
</cfif>
<cfelse>
<!--- Yay for Recursion!--->
<cfoutput>#variables.AnythingToXML.ToXML(tmp, aProperties[i].name,arguments.AttributeList)#</cfoutput>
</cfif>
</cfif>
</cfif>
</cfloop>
</cfsavecontent>
</cfprocessingdirective>
<cfset variables.TabUtils.removetab() />
<cfreturn xmlString />
</cffunction>
<cffunction name="addNodeAttributes" access="public" output="no" returntype="string" >
<cfargument name="thisNode" required="yes" type="string" hint="Name of XML the Tag" />
<cfargument name="thisKeyList" required="yes" type="string" hint="List of Column names, Struct Keys, object properties" />
<cfargument name="thisElement" required="yes" type="any" hint="a Query or a Struct" />
<cfargument name="thisAttributeList" required="yes" type="string" hint="List of Column Names/Struct Keys that should become Attributes of the XML Node" />
<cfset var returnString = variables.XMLutils.NodeNameCheck(arguments.thisNode) />
<cfset var i = 1 />
<cfloop from="1" to="#arraylen(arguments.thisKeyList)#" index="j">
<cfloop from="1" to="#ListLen(arguments.thisAttributeList)#" index="i">
<cfif ListFindNoCase(arguments.thisKeyList[j].name, ListGetAt(arguments.thisAttributeList,i), ',' )>
<cfset returnString = returnString & ' ' & lCase(ListGetAt(arguments.thisAttributeList,i)) & '="' />
<cfset returnString = returnString & xmlformat(evaluate("arguments.thisElement." & ListGetAt(arguments.thisAttributeList,i))) & '"' />
</cfif>
</cfloop>
</cfloop>
<cfreturn returnString />
</cffunction>
</cfcomponent>
@@ -0,0 +1,102 @@
<cfcomponent namespace="QueryToXML" displayname="QueryToXML" output="no" >
<!--- Query to XML by Daniel Gaspar <daniel.gaspar@gmail.com> 5/1/2008 --->
<!---
Copyright 2008 Daniel Gaspar Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or
agreed to in writing, software distributed under the License is distributed on an "AS IS"
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
for the specific language governing permissions and limitations under the License.
--->
<cffunction name="init" access="public" output="no" returntype="any">
<cfargument name="Include_Type_Hinting" type="numeric" required="no" default="1" />
<cfargument name="XMLutils" type="any" required="yes" />
<cfargument name="TabUtils" type="any" required="yes" />
<cfset variables.Include_Type_Hinting = arguments.Include_Type_Hinting />
<cfset variables.XMLutils = arguments.XMLutils />
<cfset variables.TabUtils = arguments.TabUtils />
<cfreturn this>
</cffunction>
<cffunction name="setAnythingToXML" access="public" output="no" returntype="void">
<cfargument name="AnythingToXML" type="any" required="yes" />
<cfset variables.AnythingToXML = arguments.AnythingToXML />
</cffunction>
<cffunction name="QueryToXML" access="public" output="no" returntype="string" >
<cfargument name="ThisQuery" type="Query" required="yes">
<cfargument name="rootNodeName" type="string" required="no" default="">
<cfargument name="AttributeList" type="string" required="no" default="">
<cfset var xmlString = "" />
<cfset var i = 1 />
<cfsetting enablecfoutputonly="yes">
<cfprocessingdirective suppresswhitespace="yes">
<cfsavecontent variable="xmlString" >
<cfoutput>#variables.TabUtils.printtabs()#<#variables.XMLutils.getNodePlural(arguments.rootNodeName)#></cfoutput>
<cfset variables.TabUtils.addtab() />
<cfloop query="arguments.ThisQuery" >
<cfoutput>#variables.TabUtils.printtabs()#</cfoutput>
<cfoutput><#addNodeAttributes(arguments.rootNodeName,arguments.ThisQuery.columnlist,arguments.ThisQuery,arguments.AttributeList)# <cfif variables.Include_Type_Hinting eq 1>CF_TYPE='query'</cfif>></cfoutput>
<cfoutput>#createXML(arguments.ThisQuery,arguments.rootNodeName,arguments.AttributeList)#</cfoutput>
<cfoutput>#variables.TabUtils.printtabs()#</#variables.XMLutils.NodeNameCheck(arguments.rootNodeName)#></cfoutput>
</cfloop>
<cfset variables.TabUtils.removetab() />
<cfoutput>#variables.TabUtils.printtabs()#</#variables.XMLutils.getNodePlural(arguments.rootNodeName)#></cfoutput>
</cfsavecontent>
</cfprocessingdirective>
<cfreturn xmlString />
</cffunction>
<cffunction name="createXML" access="public" output="no" returntype="string">
<cfargument name="thisQuery" type="Query" required="yes">
<cfargument name="rootNodeName" type="string" required="no" default="">
<cfargument name="AttributeList" type="string" required="no" default="">
<cfset var aColumns = ListToArray(thisQuery.columnList) />
<cfset var thisSize = aColumns.size() />
<cfset var xmlString = "" />
<cfset var CurrentNode = '' />
<cfset var i = 1 />
<cfset variables.TabUtils.addtab() />
<cfsetting enablecfoutputonly="yes">
<cfprocessingdirective suppresswhitespace="yes">
<cfsavecontent variable="xmlString" >
<cfloop from="1" to="#thisSize#" index="i" >
<cfif IsSimpleValue(evaluate("thisQuery." & aColumns[i]))>
<cfif not ListFindNoCase(arguments.AttributeList,aColumns[i])>
<cfset CurrentNode= variables.XMLutils.NodeNameCheck(aColumns[i]) />
<cfoutput>#variables.TabUtils.printtabs()#<#CurrentNode#><![CDATA[#trim(evaluate("thisQuery." & aColumns[i]))#]]></#CurrentNode#></cfoutput>
</cfif>
<cfelse>
<!--- Yay for Recursion!--->
<cfoutput>#variables.AnythingToXML.ToXML(evaluate("thisQuery." & aColumns[i]), aColumns[i],arguments.AttributeList)#</cfoutput>
</cfif>
</cfloop>
</cfsavecontent>
</cfprocessingdirective>
<cfset variables.TabUtils.removetab() />
<cfreturn xmlString />
</cffunction>
<cffunction name="addNodeAttributes" access="public" output="no" returntype="string" >
<cfargument name="thisNode" required="yes" type="string" hint="Name of XML the Tag" />
<cfargument name="thisKeyList" required="yes" type="string" hint="List of Column names, Struct Keys, object properties" />
<cfargument name="thisElement" required="yes" type="any" hint="a Query or a Struct" />
<cfargument name="thisAttributeList" required="yes" type="string" hint="List of Column Names/Struct Keys that should become Attributes of the XML Node" />
<cfset var returnString = variables.XMLutils.NodeNameCheck(arguments.thisNode) />
<cfset var i = 1 />
<cfloop from="1" to="#ListLen(arguments.thisAttributeList)#" index="i">
<cfif ListFindNoCase(arguments.thisKeyList, ListGetAt(arguments.thisAttributeList,i), ',' )>
<cfset returnString = returnString & ' ' & lCase(ListGetAt(arguments.thisAttributeList,i)) & '="' />
<cfset returnString = returnString & xmlformat(trim(evaluate("arguments.thisElement." & ListGetAt(arguments.thisAttributeList,i)))) & '"' />
</cfif>
</cfloop>
<cfreturn returnString />
</cffunction>
</cfcomponent>
@@ -0,0 +1,95 @@
<cfcomponent namespace="StructToXML" displayname="StructToXML" output="no" >
<!--- Structure to XML by Daniel Gaspar <daniel.gaspar@gmail.com> 5/1/2008 --->
Copyright 2008 Daniel Gaspar Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or
agreed to in writing, software distributed under the License is distributed on an "AS IS"
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
for the specific language governing permissions and limitations under the License.
--->
<cffunction name="init" access="public" output="no" returntype="any">
<cfargument name="Include_Type_Hinting" type="numeric" required="no" default="1" />
<cfargument name="XMLutils" type="any" required="yes" />
<cfargument name="TabUtils" type="any" required="yes" />
<cfset variables.Include_Type_Hinting = arguments.Include_Type_Hinting />
<cfset variables.XMLutils = arguments.XMLutils />
<cfset variables.TabUtils = arguments.TabUtils />
<cfreturn this>
</cffunction>
<cffunction name="setAnythingToXML" access="public" output="no" returntype="void">
<cfargument name="AnythingToXML" type="any" required="yes" />
<cfset variables.AnythingToXML = arguments.AnythingToXML />
</cffunction>
<cffunction name="StructToXML" access="public" output="no" returntype="string" >
<cfargument name="ThisStruct" type="struct" required="yes">
<cfargument name="rootNodeName" type="string" required="no">
<cfargument name="AttributeList" type="string" required="no" default="">
<cfset var xmlString = "" />
<cfset var i = 1 />
<cfsetting enablecfoutputonly="yes">
<cfprocessingdirective suppresswhitespace="yes">
<cfsavecontent variable="xmlString" >
<cfoutput>#variables.TabUtils.printtabs()#</cfoutput>
<cfoutput><#addNodeAttributes(arguments.rootNodeName,StructKeyList(arguments.ThisStruct),arguments.ThisStruct,arguments.AttributeList)# <cfif variables.Include_Type_Hinting eq 1>CF_TYPE='struct'</cfif>></cfoutput>
<cfoutput>#createXML(arguments.ThisStruct,arguments.rootNodeName,arguments.AttributeList)#</cfoutput>
<cfoutput>#variables.TabUtils.printtabs()#</#variables.XMLutils.NodeNameCheck(arguments.rootNodeName)#></cfoutput>
</cfsavecontent>
</cfprocessingdirective>
<cfreturn xmlString />
</cffunction>
<cffunction name="createXML" access="public" output="no" returntype="string">
<cfargument name="thisStruct" type="struct" required="yes">
<cfargument name="rootNodeName" type="string" required="no" default="">
<cfargument name="AttributeList" type="string" required="no" default="">
<cfset var aKeys = ListToArray(StructKeyList(arguments.thisStruct)) />
<cfset var thisStructSize = StructCount(arguments.thisStruct) />
<cfset var xmlString = "" />
<cfset var i = 1 />
<cfset var CurrentNode = '' />
<cfset variables.TabUtils.addtab() />
<cfsetting enablecfoutputonly="yes">
<cfprocessingdirective suppresswhitespace="yes">
<cfsavecontent variable="xmlString" >
<cfloop from="1" to="#thisStructSize#" index="i" >
<cfif IsSimpleValue(thisStruct[aKeys[i]])>
<cfif not ListFindNoCase(arguments.AttributeList,aKeys[i])>
<cfset CurrentNode= variables.XMLutils.NodeNameCheck(aKeys[i]) />
<cfoutput>#variables.TabUtils.printtabs()#<#CurrentNode#><![CDATA[#trim(thisStruct[aKeys[i]])#]]></#CurrentNode#></cfoutput>
</cfif>
<cfelse>
<!--- Yay for Recursion!--->
<cfoutput>#variables.AnythingToXML.ToXML(thisStruct[aKeys[i]],aKeys[i],arguments.AttributeList)#</cfoutput>
</cfif>
</cfloop>
</cfsavecontent>
</cfprocessingdirective>
<cfset variables.TabUtils.removetab() />
<cfreturn xmlString />
</cffunction>
<cffunction name="addNodeAttributes" access="public" output="no" returntype="string" >
<cfargument name="thisNode" required="yes" type="string" hint="Name of XML the Tag" />
<cfargument name="thisKeyList" required="yes" type="string" hint="List of Column names, Struct Keys, object properties" />
<cfargument name="thisElement" required="yes" type="any" hint="a Query or a Struct" />
<cfargument name="thisAttributeList" required="yes" type="string" hint="List of Column Names/Struct Keys that should become Attributes of the XML Node" />
<cfset var returnString = variables.XMLutils.NodeNameCheck(arguments.thisNode) />
<cfset var i = 1 />
<cfloop from="1" to="#ListLen(arguments.thisAttributeList)#" index="i">
<cfif ListFindNoCase(arguments.thisKeyList, ListGetAt(arguments.thisAttributeList,i), ',' )>
<cfset returnString = returnString & ' ' & lCase(ListGetAt(arguments.thisAttributeList,i)) & '="' />
<cfset returnString = returnString & xmlformat(arguments.thisElement[ListGetAt(arguments.thisAttributeList,i)]) & '"' />
</cfif>
</cfloop>
<cfreturn returnString />
</cffunction>
</cfcomponent>
@@ -0,0 +1,55 @@
<cfcomponent displayname="TabUtils" namespace="TabUtils" output="no">
<!--- Tab Utilities by Daniel Gaspar <daniel.gaspar@gmail.com> 5/1/2008 --->
<!--- Keeps track of tabs 'n prints them -Dg--->
<!---
Copyright 2008 Daniel Gaspar Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or
agreed to in writing, software distributed under the License is distributed on an "AS IS"
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
for the specific language governing permissions and limitations under the License.
--->
<cfproperty name="tabs" default="0" type="numeric" />
<cffunction name="init" access="public" output="no" returntype="any">
<cfargument name="tabs" type="numeric" required="no" default="0" />
<cfset this.tabs = arguments.tabs />
<cfreturn this>
</cffunction>
<cffunction name="setTabs" access="public" output="no" returntype="any">
<cfargument name="tabs" type="numeric" required="no" default="#this.tabs#" />
<cfset this.tabs = arguments.tabs />
</cffunction>
<cffunction name="addtab" access="public" output="no" returntype="void">
<cfargument name="num" type="numeric" required="no" default="1" />
<cfset this.tabs = this.tabs + arguments.num />
</cffunction>
<cffunction name="removetab" access="public" output="no" returntype="void">
<cfargument name="num" type="numeric" required="no" default="1" />
<cfset this.tabs = this.tabs - arguments.num />
</cffunction>
<cffunction name="printtabs" access="public" output="no" returntype="string" >
<cfargument name="tabs" type="numeric" required="no" default="#this.tabs#" />
<cfset var returnstring = "" />
<cfset var i = 1 />
<!---<cfif this.tabs gt 0 > --->
<cfprocessingdirective suppresswhitespace="yes">
<cfsetting enablecfoutputonly="yes">
<cfsavecontent variable="returnstring" >
<cfoutput>#chr(10)#</cfoutput>
<cfloop from="1" to="#arguments.tabs#" index="i" >
<cfoutput>#chr(09)#</cfoutput>
</cfloop>
</cfsavecontent>
</cfprocessingdirective>
<!---</cfif>--->
<cfreturn returnstring>
</cffunction>
</cfcomponent>
@@ -0,0 +1,79 @@
<cfcomponent displayname="XMLutils" namespace="XMLutils" output="no">
<!--- XML Utility functions by Daniel Gaspar <daniel.gaspar@gmail.com> 5/1/2008 --->
<!--- Global functionality for XML creation: deciding on plural node names -Dg--->
<!---
Copyright 2008 Daniel Gaspar Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or
agreed to in writing, software distributed under the License is distributed on an "AS IS"
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
for the specific language governing permissions and limitations under the License.
--->
<cffunction name="init" access="public" output="no" returntype="any">
<cfreturn this>
</cffunction>
<cffunction name="getNodePlural" access="public" output="no" >
<cfargument name="ThisNode" type="string" required="yes" />
<cfset var Plural = "" />
<cfif PluralExceptions(ThisNode) neq "" >
<cfset plural = PluralExceptions(ThisNode)>
<cfelseif right(ThisNode,2) eq 'ey'>
<cfset plural = left(ThisNode,(len(ThisNode)-2)) & "IES" />
<cfelseif right(ThisNode,1) eq 'y'>
<cfset plural = left(ThisNode,(len(ThisNode)-1)) & "IES" />
<cfelseif right(ThisNode,1) eq 's'>
<cfset plural = ThisNode & "ES" />
<cfelse>
<cfset Plural = ThisNode & "S" />
</cfif>
<cfreturn NodeNameCheck(Plural) />
</cffunction>
<cffunction name="PluralExceptions" access="private" output="no" >
<cfargument name="ThisNode" type="string" required="yes" />
<cfset var Plural = "" />
<!--- 1st pass at naming. --->
<cfswitch expression="#ucase(arguments.ThisNode)#">
<cfcase value="SURVEY">
<cfset Plural = "SURVEYS" />
</cfcase>
<cfcase value="METADATA">
<cfset Plural = "METADATA" />
</cfcase>
<cfdefaultcase>
<cfset Plural = "" />
</cfdefaultcase>
</cfswitch>
<cfreturn ucase(Plural) />
</cffunction>
<cffunction name="NodeNameCheck" access="public" output="no" >
<cfargument name="ThisNode" type="string" required="yes" />
<cfset var rename = "" />
<!--- For adding hacks/ renaming nodes. --->
<!---
A trick here is that you could let things get missnamed in the plural exceptions list,
then fix them here if you need to.
For example:
"related_images" plural is "related_imageses" the sub-node of this is "related_image" which plural is "related_images"
We'd need to let "related_images" get missnamed then fix both afterwards so that we can filter properly.
--->
<cfswitch expression="#ucase(arguments.ThisNode)#">
<cfcase value="IMAGESES">
<cfset rename = "IMAGES" />
</cfcase>
<cfcase value="IMAGES">
<cfset rename = "IMAGE" />
</cfcase>
<cfdefaultcase>
<cfset rename = arguments.ThisNode />
</cfdefaultcase>
</cfswitch>
<cfreturn ucase(rename) />
</cffunction>
</cfcomponent>
@@ -0,0 +1,6 @@
<!---
DO NOT DELETE THIS FILE
===============================
This file is necessary for Taffy to work, but should be blank.
All requests funnel through it, but are handled by framework internal functionality.
--->
@@ -0,0 +1,14 @@
<cfcomponent extends="taffy.core.resource" taffy_uri="/artist/{artistId}/art">
<cfset variables.dummyData = StructNew() />
<cfset variables.dummyData.whatever = true />
<cffunction name="get" access="public" output="false">
<cfreturn representationOf(variables.dummyData).withStatus(200) />
</cffunction>
<cffunction name="post" access="public" output="false">
<cfreturn representationOf(variables.dummyData).withStatus(200) />
</cffunction>
</cfcomponent>
@@ -0,0 +1,22 @@
<cfcomponent extends="taffy.core.resource" taffy_uri="/artist/{artistId}/art/{artId}">
<cfset variables.dummyData = StructNew() />
<cfset variables.dummyData.whatever = true />
<cffunction name="get" access="public" output="false">
<cfreturn representationOf(variables.dummyData).withStatus(200) />
</cffunction>
<cffunction name="post" access="public" output="false">
<cfreturn representationOf(variables.dummyData).withStatus(200) />
</cffunction>
<cffunction name="put" access="public" output="false">
<cfreturn representationOf(variables.dummyData).withStatus(200) />
</cffunction>
<cffunction name="delete" access="public" output="false">
<cfreturn representationOf(variables.dummyData).withStatus(200) />
</cffunction>
</cfcomponent>
@@ -0,0 +1,59 @@
<cfcomponent extends="taffy.core.resource" taffy_uri="/artists">
<cffunction name="get" access="public" output="false">
<cfset var q = "" />
<cfquery name="q" datasource="cfartgallery" cachedwithin="#createTimeSpan(0,0,0,1)#">
select * from artists
</cfquery>
<cfreturn representationOf(q).withStatus(200).withHeaders({"x-powered-by" = "Taffy 1.0"}) />
</cffunction>
<cffunction name="post" access="public" output="false">
<cfargument name="firstname" type="string" required="false" default="" />
<cfargument name="lastname" type="string" required="false" default="" />
<cfargument name="address" type="string" required="false" default="" />
<cfargument name="city" type="string" required="false" default="" />
<cfargument name="state" type="string" required="false" default="" />
<cfargument name="postalcode" type="string" required="false" default="" />
<cfargument name="email" type="string" required="false" default="" />
<cfargument name="phone" type="string" required="false" default="" />
<cfargument name="fax" type="string" required="false" default="" />
<cfargument name="thepassword" type="string" required="false" default="" />
<cfset var q = "" />
<cfquery name="q" datasource="cfartgallery">
insert into artists (firstname,lastname,address,city,state,postalcode,email,phone,fax,thepassword)
values (
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.firstname#" />,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.lastname#" />,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.address#" />,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.city#" />,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.state#" />,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.postalcode#" />,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.email#" />,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.phone#" />,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.fax#" />,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.thepassword#" />
)
</cfquery>
<cfquery name="q" datasource="cfartgallery">
select * from artists
where
firstname = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.firstname#" />
and lastname = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.lastname#" />
and address = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.address#" />
and city = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.city#" />
and state = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.state#" />
and postalcode = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.postalcode#" />
and email = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.email#" />
and phone = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.phone#" />
and fax = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.fax#" />
and thepassword = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.thepassword#" />
</cfquery>
<cfreturn representationOf(q).withStatus(200) />
</cffunction>
<!---
The DELETE and PUT verbs are not implemented, so those actions are not permitted.
--->
</cfcomponent>
@@ -0,0 +1,72 @@
<cfcomponent extends="taffy.core.resource" taffy_uri="/artist/{id}">
<cffunction name="get" access="public" output="false">
<cfargument name="id" type="numeric" required="true" />
<cfset var q = ""/>
<cfquery name="q" datasource="cfartgallery">
select * from artists where artistId = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.id#" />
</cfquery>
<cfreturn representationOf(q).withStatus(200) />
</cffunction>
<cffunction name="put" access="public" output="false">
<cfargument name="id" type="numeric" required="true" />
<cfargument name="firstname" type="string" required="false" default="" />
<cfargument name="lastname" type="string" required="false" default="" />
<cfargument name="address" type="string" required="false" default="" />
<cfargument name="city" type="string" required="false" default="" />
<cfargument name="state" type="string" required="false" default="" />
<cfargument name="postalcode" type="string" required="false" default="" />
<cfargument name="email" type="string" required="false" default="" />
<cfargument name="phone" type="string" required="false" default="" />
<cfargument name="fax" type="string" required="false" default="" />
<cfargument name="thepassword" type="string" required="false" default="" />
<cfset var q = "" />
<cfquery name="q" datasource="cfartgallery">
update artists
set artistid=artistid
<cfif len(arguments.firstname)>
,firstname = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.firstname#" />
</cfif>
<cfif len(arguments.lastname)>
,lastname = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.lastname#" />
</cfif>
<cfif len(arguments.address)>
,address = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.address#" />
</cfif>
<cfif len(arguments.city)>
,city = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.city#" />
</cfif>
<cfif len(arguments.state)>
,state = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.state#" />
</cfif>
<cfif len(arguments.postalcode)>
,postalcode = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.postalcode#" />
</cfif>
<cfif len(arguments.email)>
,email = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.email#" />
</cfif>
<cfif len(arguments.phone)>
,phone = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.phone#" />
</cfif>
<cfif len(arguments.fax)>
,fax = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.fax#" />
</cfif>
<cfif len(arguments.thepassword)>
,thepassword = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.thepassword#" />
</cfif>
where artistid = <cfqueryparam cfsqltype="cf_sql_numeric" value="#arguments.id#" />
</cfquery>
<cfreturn noData().withStatus(200) />
</cffunction>
<cffunction name="delete" access="public" output="false">
<cfargument name="id" type="numeric" required="true" />
<cfset var q = "" />
<cfquery name="q" datasource="cfartgallery">
delete from artists where artistid = <cfqueryparam cfsqltype="cf_sql_numeric" value="#arguments.id#" />
</cfquery>
<cfreturn noData().withStatus(200) />
</cffunction>
</cfcomponent>
@@ -0,0 +1,28 @@
<cfcomponent extends="taffy.core.api">
<cfscript>
this.name = hash(getCurrentTemplatePath());
variables.framework = {};
variables.framework.debugKey = "debug";
variables.framework.reloadKey = "reload";
variables.framework.reloadPassword = "true";
variables.framework.serializer = "taffy.core.nativeJsonSerializer";
variables.framework.returnExceptionsAsJson = true;
function onApplicationStart(){
return super.onApplicationStart();
}
function onRequestStart(TARGETPATH){
return super.onRequestStart(TARGETPATH);
}
// this function is called after the request has been parsed and all request details are known
function onTaffyRequest(verb, cfc, requestArguments, mimeExt){
// this would be a good place for you to check API key validity and other non-resource-specific validation
return true;
}
</cfscript>
</cfcomponent>
+6
View File
@@ -0,0 +1,6 @@
<!---
DO NOT DELETE THIS FILE
===============================
This file is necessary for Taffy to work, but should be blank.
All requests funnel through it, but are handled by framework internal functionality.
--->
@@ -0,0 +1,17 @@
<cfcomponent extends="taffy.core.resource" taffy:uri="/date" hint="Collection of dates">
<cffunction name="get" access="public" output="false" hint="Get some collection of dates">
<cfset var qry = queryNew("id,foo", "integer,date") />
<cfset var i = 0 />
<cfloop from="1" to="15" index="i">
<cfset tmp = queryAddRow(qry) />
<cfset tmp = querySetCell(qry, "id", i) />
<cfset tmp = querySetCell(qry, "foo", dateadd("s",RandRange(1, 5000),now())) />
</cfloop>
<cfreturn representationOf(queryToArray(qry)).withStatus(200) />
</cffunction>
</cfcomponent>
@@ -0,0 +1,27 @@
<cfcomponent extends="taffy.core.resource" taffy:uri="/dateCalback" hint="Collection of dates">
<cffunction name="formatDate" access="private" output="false" hint="Format dates in ISO 8601 format">
<cfargument name="row" type="any" required="yes" />
<cfif isDate(row.foo)>
<cfset row.foo = dateFormat(row.foo,'yyyy-mm-dd')&'T'&timeFormat(row.foo, 'HH:mm:ss.lZ')>
</cfif>
<cfreturn row>
</cffunction>
<cffunction name="get" access="public" output="false" hint="Get some collection of dates">
<cfset var qry = queryNew("id,foo", "integer,date") />
<cfset var i = 0 />
<cfloop from="1" to="15" index="i">
<cfset tmp = queryAddRow(qry) />
<cfset tmp = querySetCell(qry, "id", i) />
<cfset tmp = querySetCell(qry, "foo", dateadd("s",RandRange(1, 5000),now())) />
</cfloop>
<cfreturn representationOf(queryToArray(qry,formatDate)).withStatus(200) />
</cffunction>
</cfcomponent>
@@ -0,0 +1,23 @@
<cfcomponent extends="taffy.core.api">
<cfscript>
this.name = hash(getCurrentTemplatePath());
variables.framework = {};
variables.framework.debugKey = "debug";
variables.framework.reloadKey = "reload";
variables.framework.reloadPassword = "true";
variables.framework.serializer = "taffy.core.nativeJsonSerializer";
function onApplicationStart(){
application.beanFactory = createObject("component", "coldspring.beans.DefaultXMLBeanFactory");
application.beanFactory.loadBeans('/taffy/examples/api_coldspring/config/coldspring.xml');
//note that we're modifying variables.framework here, after the application variable has been set
variables.framework.beanFactory = application.beanFactory;
return super.onApplicationStart();
}
</cfscript>
</cfcomponent>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans default-autowire="byName">
<bean id="fakeData" class="taffy.examples.shared.fakeData" />
<bean id="artfartCollection" class="taffy.examples.api_coldspring.stuff.artfartCollection" />
</beans>
@@ -0,0 +1,6 @@
<!---
DO NOT DELETE THIS FILE
===============================
This file is necessary for Taffy to work, but should be blank.
All requests funnel through it, but are handled by framework internal functionality.
--->
@@ -0,0 +1,13 @@
<cfcomponent extends="taffy.core.resource" taffy_uri="/artfarts">
<cffunction name="get" access="public" output="false">
<cfreturn representationOf(variables.fakeData.getData()).withStatus(200) />
</cffunction>
<!--- this will be called by the bean factory's autowire functionality --->
<cffunction name="setFakeData" access="public" output="false" returnType="void">
<cfargument name="fakeDataObj" type="any" required="true" hint="Shared FakeData object" />
<cfset variables.fakeData = arguments.fakeDataObj />
</cffunction>
</cfcomponent>
@@ -0,0 +1,39 @@
<cfcomponent extends="taffy.core.api">
<cfscript>
this.name = hash(getCurrentTemplatePath());
// In the interest of compatibility, we'll write this out long-form so it works on CF8
variables.framework = structNew();
variables.framework.debugKey = "debug";
variables.framework.reloadKey = "reload";
variables.framework.reloadPassword = "true";
variables.framework.serializer = "taffy.core.nativeJsonSerializer";
variables.framework.dashboardKey = "dashboard";
variables.framework.disableDashboard = false;
variables.framework.unhandledPaths = "/flex2gateway";
variables.framework.allowCrossDomain = false;
variables.framework.globalHeaders = structNew();
variables.framework.globalHeaders["X-MY-HEADER"] = "my header value";
//variables.framework.beanFactory = "";
/* If you have CF9+, the above could be written as:
variables.framework {
debugKey = "debug",
reloadKey = "reload",
reloadPassword = "true",
serializer = "taffy.core.nativeJsonSerializer",
dashboardKey = "dashboard",
disableDashboard = false,
unhandledPaths = "/flex2gateway",
allowCrossDomain = false,
globalHeaders = {
"X-MY-HEADER" = "my header value"
}
}
*/
</cfscript>
</cfcomponent>
@@ -0,0 +1,6 @@
<!---
DO NOT DELETE THIS FILE
===============================
This file is necessary for Taffy to work, but should be blank.
All requests funnel through it, but are handled by framework internal functionality.
--->
@@ -0,0 +1,15 @@
<cfcomponent extends="taffy.core.resource" taffy:uri="/artist/{artistId}/art" hint="Collection of art data">
<cfset variables.dummyData = StructNew() />
<cfset variables.dummyData.whatever = true />
<cffunction name="get" access="public" output="false" hint="Get some collection of art data">
<cfargument name="artistId" type="numeric" required="true" />
<cfreturn representationOf(variables.dummyData).withStatus(200) />
</cffunction>
<cffunction name="post" access="public" output="false" hint="Insert a new art record">
<cfreturn representationOf(variables.dummyData).withStatus(200) />
</cffunction>
</cfcomponent>
@@ -0,0 +1,22 @@
<cfcomponent extends="taffy.core.resource" taffy_uri="/artist/{artistId}/art/{artId}">
<cfset variables.dummyData = StructNew() />
<cfset variables.dummyData.whatever = true />
<cffunction name="get" access="public" output="false">
<cfreturn representationOf(variables.dummyData).withStatus(200) />
</cffunction>
<cffunction name="post" access="public" output="false">
<cfreturn representationOf(variables.dummyData).withStatus(200) />
</cffunction>
<cffunction name="put" access="public" output="false">
<cfreturn representationOf(variables.dummyData).withStatus(200) />
</cffunction>
<cffunction name="delete" access="public" output="false">
<cfreturn representationOf(variables.dummyData).withStatus(200) />
</cffunction>
</cfcomponent>
@@ -0,0 +1,59 @@
<cfcomponent extends="taffy.core.resource" taffy_uri="/artists">
<cffunction name="get" access="public" output="false">
<cfset var q = "" />
<cfquery name="q" datasource="cfartgallery">
select * from artists
</cfquery>
<cfreturn representationOf(q).withStatus(200) />
</cffunction>
<cffunction name="post" access="public" output="false">
<cfargument name="firstname" type="string" required="false" default="" />
<cfargument name="lastname" type="string" required="false" default="" />
<cfargument name="address" type="string" required="false" default="" />
<cfargument name="city" type="string" required="false" default="" />
<cfargument name="state" type="string" required="false" default="" />
<cfargument name="postalcode" type="string" required="false" default="" />
<cfargument name="email" type="string" required="false" default="" />
<cfargument name="phone" type="string" required="false" default="" />
<cfargument name="fax" type="string" required="false" default="" />
<cfargument name="thepassword" type="string" required="false" default="" />
<cfset var q = "" />
<cfquery name="q" datasource="cfartgallery">
insert into artists (firstname,lastname,address,city,state,postalcode,email,phone,fax,thepassword)
values (
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.firstname#" />,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.lastname#" />,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.address#" />,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.city#" />,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.state#" />,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.postalcode#" />,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.email#" />,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.phone#" />,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.fax#" />,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.thepassword#" />
)
</cfquery>
<cfquery name="q" datasource="cfartgallery">
select * from artists
where
firstname = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.firstname#" />
and lastname = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.lastname#" />
and address = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.address#" />
and city = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.city#" />
and state = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.state#" />
and postalcode = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.postalcode#" />
and email = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.email#" />
and phone = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.phone#" />
and fax = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.fax#" />
and thepassword = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.thepassword#" />
</cfquery>
<cfreturn representationOf(q).withStatus(200) />
</cffunction>
<!---
The DELETE and PUT verbs are not implemented, so those actions are not permitted.
--->
</cfcomponent>
@@ -0,0 +1,81 @@
<cfcomponent extends="taffy.core.resource" taffy:uri="/artist/{id}" hint="some hint about this resource">
<cffunction name="get" access="public" output="false">
<cfargument name="id" type="numeric" required="true" />
<cfset var q = ""/>
<cfset var col = "" />
<cfset var rtn = StructNew() />
<cfquery name="q" datasource="cfartgallery">
select * from artists where artistId = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.id#" />
</cfquery>
<cfif q.recordCount gt 0>
<cfloop list="#q.ColumnList#" index="col">
<cfset rtn[col] = q[col][1] />
</cfloop>
<cfreturn representationOf(rtn).withStatus(200) />
<cfelse>
<cfreturn noData().withStatus(404) />
</cfif>
</cffunction>
<cffunction name="put" access="public" output="false">
<cfargument name="id" type="numeric" required="true" />
<cfargument name="firstname" type="string" required="false" default="" />
<cfargument name="lastname" type="string" required="false" default="" />
<cfargument name="address" type="string" required="false" default="" hint="some hint about this parameter" />
<cfargument name="city" type="string" required="false" default="" />
<cfargument name="state" type="string" required="false" default="" />
<cfargument name="postalcode" type="string" required="false" default="" />
<cfargument name="email" type="string" required="false" default="" />
<cfargument name="phone" type="string" required="false" default="" />
<cfargument name="fax" type="string" required="false" default="" />
<cfargument name="thepassword" type="string" required="false" default="" />
<cfset var q = "" />
<cfquery name="q" datasource="cfartgallery">
update artists
set artistid=artistid
<cfif len(arguments.firstname)>
,firstname = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.firstname#" />
</cfif>
<cfif len(arguments.lastname)>
,lastname = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.lastname#" />
</cfif>
<cfif len(arguments.address)>
,address = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.address#" />
</cfif>
<cfif len(arguments.city)>
,city = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.city#" />
</cfif>
<cfif len(arguments.state)>
,state = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.state#" />
</cfif>
<cfif len(arguments.postalcode)>
,postalcode = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.postalcode#" />
</cfif>
<cfif len(arguments.email)>
,email = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.email#" />
</cfif>
<cfif len(arguments.phone)>
,phone = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.phone#" />
</cfif>
<cfif len(arguments.fax)>
,fax = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.fax#" />
</cfif>
<cfif len(arguments.thepassword)>
,thepassword = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.thepassword#" />
</cfif>
where artistid = <cfqueryparam cfsqltype="cf_sql_numeric" value="#arguments.id#" />
</cfquery>
<cfreturn noData().withStatus(200) />
</cffunction>
<cffunction name="delete" access="public" output="false">
<cfargument name="id" type="numeric" required="true" />
<cfset var q = "" />
<cfquery name="q" datasource="cfartgallery">
delete from artists where artistid = <cfqueryparam cfsqltype="cf_sql_numeric" value="#arguments.id#" />
</cfquery>
<cfreturn noData().withStatus(200) />
</cffunction>
</cfcomponent>
@@ -0,0 +1,2 @@
<cfcomponent extends="taffy.core.api">
</cfcomponent>
+6
View File
@@ -0,0 +1,6 @@
RewriteEngine On
#if we've already been rewritten to use index.cfm/* format, don't make a circular request
RewriteRule ^(index\.cfm[/.]?+|images/.*) - [L]
RewriteRule ^(.*)$ index.cfm/$1
+19
View File
@@ -0,0 +1,19 @@
<cfcomponent extends="taffy.core.api">
<cfscript>
this.name = hash(getCurrentTemplatePath());
variables.framework = {};
variables.framework.debugKey = "debug";
variables.framework.reloadKey = "reload";
variables.framework.reloadPassword = "true";
variables.framework.serializer = "taffy.core.nativeJsonSerializer";
function onApplicationStart(){
application.lastReset = now();
return super.onApplicationStart();
}
</cfscript>
</cfcomponent>
Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

+6
View File
@@ -0,0 +1,6 @@
<!---
DO NOT DELETE THIS FILE
===============================
This file is necessary for Taffy to work, but should be blank.
All requests funnel through it, but are handled by framework internal functionality.
--->
@@ -0,0 +1,13 @@
<cfcomponent extends="taffy.core.resource" taffy:uri="/pdf/mew">
<cffunction name="get">
<cfset var local = structNew() />
<cfdocument format="PDF" name="local.pdf">
<h1>Mew mew mew mew</h1>
<img src="/taffy/examples/api_img/images/Kitten_cups.jpg"/><br/>
<img src="/taffy/examples/api_img/images/PETA_sea_kitten.jpg" />
</cfdocument>
<cfreturn streamBinary(local.pdf).withStatus(200).withMime("application/pdf") />
</cffunction>
</cfcomponent>
@@ -0,0 +1,12 @@
<cfcomponent extends="Taffy.core.resource" taffy_uri="/kitten/random">
<cfdirectory action="list" directory="#expandPath('./images')#" name="variables.images" />
<cfset variables.fileTypes = { jpg="image/jpeg", jpeg="image/jpeg", gif="image/gif", png="image/png", bmp="image/bmp" } />
<cffunction name="get" access="public" output="false">
<cfset var row = randRange(1,variables.images.recordCount) />
<cfset var file = variables.images.directory[row] & "/" & variables.images.name[row] />
<cfreturn streamFile(file).withStatus(200).withMime(fileTypes[listLast(variables.images.name[row], '.')]) />
</cffunction>
</cfcomponent>
@@ -0,0 +1,41 @@
<cfcomponent extends="Taffy.core.resource" taffy_uri="/placekitten/{width}/{height}">
<cfdirectory action="list" directory="#expandPath('./images')#" name="variables.images" />
<cfset variables.fileTypes = { jpg="image/jpeg", jpeg="image/jpeg", gif="image/gif", png="image/png", bmp="image/bmp" } />
<cffunction name="get" access="public" output="false">
<cfargument name="width" />
<cfargument name="height" />
<cfset var img = '' />
<!--- pick a file --->
<cfset var row = randRange(1,variables.images.recordCount) />
<cfset var file = variables.images.directory[row] & "/" & variables.images.name[row] />
<cfset var fileType = listLast(variables.images.name[row], '.') />
<!--- resize it on the fly to fit the requested dimensions, scaling as necessary --->
<cfif arguments.width gt arguments.height>
<cfimage action="resize" source="#file#" name="img" height="" width="#arguments.width#" />
<cfset imageCrop(img, 0, 0, arguments.width, arguments.height) />
<cfelseif arguments.width lt arguments.height>
<cfimage action="resize" source="#file#" name="img" height="#arguments.height#" width="" />
<cfset imageCrop(img, 0, 0, arguments.width, arguments.height) />
<cfelse>
<cfimage action="read" name="img" source="#file#" />
<cfset w = imageGetWidth(img) />
<cfset h = imageGetHeight(img) />
<cfif w gt h>
<cfimage action="resize" source="#file#" name="img" height="#arguments.height#" width="" />
<cfelseif h gt w>
<cfimage action="resize" source="#file#" name="img" height="" width="#arguments.width#" />
<cfelse>
<cfimage action="resize" source="#file#" name="img" height="#arguments.height#" width="#arguments.width#" />
</cfif>
<cfset imageCrop(img, 0, 0, arguments.width, arguments.height) />
</cfif>
<cfreturn streamImage(img).withStatus(200).withMime(fileTypes[fileType]) />
</cffunction>
</cfcomponent>
+6
View File
@@ -0,0 +1,6 @@
RewriteEngine On
#if we've already been rewritten to use index.cfm/* format, don't make a circular request
RewriteRule index\.cfm/* - [L]
RewriteRule ^(.*)$ index.cfm/$1
@@ -0,0 +1,10 @@
<cfcomponent extends="taffy.core.api">
<cfscript>
this.name = hash(getCurrentTemplatePath());
variables.framework = {};
variables.framework.serializer = "JsonUtilSerializer";
</cfscript>
</cfcomponent>
+6
View File
@@ -0,0 +1,6 @@
<!---
DO NOT DELETE THIS FILE
===============================
This file is necessary for Taffy to work, but should be blank.
All requests funnel through it, but are handled by framework internal functionality.
--->
@@ -0,0 +1,553 @@
<!---
Copyright 2009 Nathan Mische
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
--->
<cfcomponent displayname="JSONUtil" output="false">
<cfset this.deserialzeJSON = deserializeFromJSON />
<cfset this.serializeJSON = serializeToJSON />
<cfset this.deserialize = deserializeFromJSON />
<cfset this.serialize = serializeToJSON />
<cffunction name="init" output="false">
<cfreturn this />
</cffunction>
<cffunction
name="deserializeFromJSON"
access="public"
returntype="any"
output="false"
hint="Converts a JSON (JavaScript Object Notation) string data representation into CFML data, such as a CFML structure or array.">
<cfargument
name="JSONVar"
type="string"
required="true"
hint="A string that contains a valid JSON construct, or variable that represents one." />
<cfargument
name="strictMapping"
type="boolean"
required="false"
default="true"
hint="A Boolean value that specifies whether to convert the JSON strictly, as follows:
<ul>
<li><code>true:</code> (Default) Convert the JSON string to ColdFusion data types that correspond directly to the JSON data types.</li>
<li><code>false:</code> Determine if the JSON string contains representations of ColdFusion queries, and if so, convert them to queries.</li>
</ul>" />
<!--- DECLARE VARIABLES --->
<cfset var ar = ArrayNew(1) />
<cfset var st = StructNew() />
<cfset var dataType = "" />
<cfset var inQuotes = false />
<cfset var startPos = 1 />
<cfset var nestingLevel = 0 />
<cfset var dataSize = 0 />
<cfset var i = 1 />
<cfset var skipIncrement = false />
<cfset var j = 0 />
<cfset var char = "" />
<cfset var dataStr = "" />
<cfset var structVal = "" />
<cfset var structKey = "" />
<cfset var colonPos = "" />
<cfset var qRows = 0 />
<cfset var qCols = "" />
<cfset var qCol = "" />
<cfset var qData = "" />
<cfset var curCharIndex = "" />
<cfset var curChar = "" />
<cfset var result = "" />
<cfset var unescapeVals = "\\,\"",\/,\b,\t,\n,\f,\r" />
<cfset var unescapeToVals = "\,"",/,#Chr(8)#,#Chr(9)#,#Chr(10)#,#Chr(12)#,#Chr(13)#" />
<cfset var unescapeVals2 = '\,",/,b,t,n,f,r' />
<cfset var unescapetoVals2 = '\,",/,#Chr(8)#,#Chr(9)#,#Chr(10)#,#Chr(12)#,#Chr(13)#' />
<cfset var dJSONString = "" />
<cfset var _data = Trim(arguments.JSONVar) />
<!--- NUMBER --->
<cfif IsNumeric(_data)>
<cfreturn Val(_data) />
<!--- NULL --->
<cfelseif _data EQ "null">
<cfreturn "null" />
<!--- BOOLEAN --->
<cfelseif ListFindNoCase("true,false", _data)>
<cfreturn _data />
<!--- EMPTY STRING --->
<cfelseif _data EQ "''" OR _data EQ '""'>
<cfreturn "" />
<!--- STRING --->
<cfelseif ReFind('^"[^\\"]*(?:\\.[^\\"]*)*"$', _data) EQ 1 OR ReFind("^'[^\\']*(?:\\.[^\\']*)*'$", _data) EQ 1>
<cfset _data = mid(_data, 2, Len(_data)-2) />
<!--- If there are any \b, \t, \n, \f, and \r, do extra processing
(required because ReplaceList() won't work with those) --->
<cfif Find("\b", _data) OR Find("\t", _data) OR Find("\n", _data) OR Find("\f", _data) OR Find("\r", _data)>
<cfset curCharIndex = 0 />
<cfset curChar = ""/>
<cfset dJSONString = ArrayNew(1) />
<cfloop condition="true">
<cfset curCharIndex = curCharIndex + 1 />
<cfif curCharIndex GT len(_data)>
<cfbreak />
<cfelse>
<cfset curChar = mid(_data, curCharIndex, 1) />
<cfif curChar EQ "\">
<cfset curCharIndex = curCharIndex + 1 />
<cfset curChar = mid(_data, curCharIndex,1) />
<cfset pos = listFind(unescapeVals2, curChar) />
<cfif pos>
<cfset ArrayAppend(dJSONString,ListGetAt(unescapetoVals2, pos)) />
<cfelse>
<cfset ArrayAppend(dJSONString,"\" & curChar) />
</cfif>
<cfelse>
<cfset ArrayAppend(dJSONString,curChar) />
</cfif>
</cfif>
</cfloop>
<cfreturn ArrayToList(dJSONString,"") />
<cfelse>
<cfreturn ReplaceList(_data, unescapeVals, unescapeToVals) />
</cfif>
<!--- ARRAY, STRUCT, OR QUERY --->
<cfelseif ( Left(_data, 1) EQ "[" AND Right(_data, 1) EQ "]" )
OR ( Left(_data, 1) EQ "{" AND Right(_data, 1) EQ "}" )>
<!--- Store the data type we're dealing with --->
<cfif Left(_data, 1) EQ "[" AND Right(_data, 1) EQ "]">
<cfset dataType = "array" />
<cfelseif ReFindNoCase('^\{"ROWCOUNT":[0-9]+,"COLUMNS":\[("[^"]+",?)+\],"DATA":\{("[^"]+":\[[^]]*\],?)+\}\}$', _data, 0) EQ 1 AND NOT arguments.strictMapping>
<cfset dataType = "queryByColumns" />
<cfelseif ReFindNoCase('^\{"COLUMNS":\[("[^"]+",?)+\],"DATA":\[(\[[^]]*\],?)+\]\}$', _data, 0) EQ 1 AND NOT arguments.strictMapping>
<cfset dataType = "query" />
<cfelse>
<cfset dataType = "struct" />
</cfif>
<!--- Remove the brackets --->
<cfset _data = Trim( Mid(_data, 2, Len(_data)-2) ) />
<!--- Deal with empty array/struct --->
<cfif Len(_data) EQ 0>
<cfif dataType EQ "array">
<cfreturn ar />
<cfelse>
<cfreturn st />
</cfif>
</cfif>
<!--- Loop through the string characters --->
<cfset dataSize = Len(_data) + 1 />
<cfloop condition="#i# LTE #dataSize#">
<cfset skipIncrement = false />
<!--- Save current character --->
<cfset char = Mid(_data, i, 1) />
<!--- If char is a quote, switch the quote status --->
<cfif char EQ '"'>
<cfset inQuotes = NOT inQuotes />
<!--- If char is escape character, skip the next character --->
<cfelseif char EQ "\" AND inQuotes>
<cfset i = i + 2 />
<cfset skipIncrement = true />
<!--- If char is a comma and is not in quotes, or if end of string, deal with data --->
<cfelseif (char EQ "," AND NOT inQuotes AND nestingLevel EQ 0) OR i EQ Len(_data)+1>
<cfset dataStr = Mid(_data, startPos, i-startPos) />
<!--- If data type is array, append data to the array --->
<cfif dataType EQ "array">
<cfset arrayappend( ar, deserializeFromJSON(dataStr, arguments.strictMapping) ) />
<!--- If data type is struct or query or queryByColumns... --->
<cfelseif dataType EQ "struct" OR dataType EQ "query" OR dataType EQ "queryByColumns">
<cfset dataStr = Mid(_data, startPos, i-startPos) />
<cfset colonPos = Find('":', dataStr) />
<cfif colonPos>
<cfset colonPos = colonPos + 1 />
<cfelse>
<cfset colonPos = Find(":", dataStr) />
</cfif>
<cfset structKey = Trim( Mid(dataStr, 1, colonPos-1) ) />
<!--- If needed, remove quotes from keys --->
<cfif Left(structKey, 1) EQ "'" OR Left(structKey, 1) EQ '"'>
<cfset structKey = Mid( structKey, 2, Len(structKey)-2 ) />
</cfif>
<cfset structVal = Mid( dataStr, colonPos+1, Len(dataStr)-colonPos ) />
<!--- If struct, add to the structure --->
<cfif dataType EQ "struct">
<cfset StructInsert( st, structKey, deserializeFromJSON(structVal, arguments.strictMapping) ) />
<!--- If query, build the query --->
<cfelseif dataType EQ "queryByColumns">
<cfif structKey EQ "rowcount">
<cfset qRows = deserializeFromJSON(structVal, arguments.strictMapping) />
<cfelseif structKey EQ "columns">
<cfset qCols = deserializeFromJSON(structVal, arguments.strictMapping) />
<cfset st = QueryNew(ArrayToList(qCols)) />
<cfif qRows>
<cfset QueryAddRow(st, qRows) />
</cfif>
<cfelseif structKey EQ "data">
<cfset qData = deserializeFromJSON(structVal, arguments.strictMapping) />
<cfset ar = StructKeyArray(qData) />
<cfloop from="1" to="#ArrayLen(ar)#" index="j">
<cfloop from="1" to="#st.recordcount#" index="qRows">
<cfset qCol = ar[j] />
<cfset QuerySetCell(st, qCol, qData[qCol][qRows], qRows) />
</cfloop>
</cfloop>
</cfif>
<cfelseif dataType EQ "query">
<cfif structKey EQ "columns">
<cfset qCols = deserializeFromJSON(structVal, arguments.strictMapping) />
<cfset st = QueryNew(ArrayToList(qCols)) />
<cfelseif structKey EQ "data">
<cfset qData = deserializeFromJSON(structVal, arguments.strictMapping) />
<cfloop from="1" to="#ArrayLen(qData)#" index="qRows">
<cfset QueryAddRow(st) />
<cfloop from="1" to="#ArrayLen(qCols)#" index="j">
<cfset qCol = qCols[j] />
<cfset QuerySetCell(st, qCol, qData[qRows][j], qRows) />
</cfloop>
</cfloop>
</cfif>
</cfif>
</cfif>
<cfset startPos = i + 1 />
<!--- If starting a new array or struct, add to nesting level --->
<cfelseif "{[" CONTAINS char AND NOT inQuotes>
<cfset nestingLevel = nestingLevel + 1 />
<!--- If ending an array or struct, subtract from nesting level --->
<cfelseif "]}" CONTAINS char AND NOT inQuotes>
<cfset nestingLevel = nestingLevel - 1 />
</cfif>
<cfif NOT skipIncrement>
<cfset i = i + 1 />
</cfif>
</cfloop>
<!--- Return appropriate value based on data type --->
<cfif dataType EQ "array">
<cfreturn ar />
<cfelse>
<cfreturn st />
</cfif>
<!--- INVALID JSON --->
<cfelse>
<cfthrow message="JSON parsing failure." />
</cfif>
</cffunction>
<cffunction
name="serializeToJSON"
access="public"
returntype="string"
output="false"
hint="Converts ColdFusion data into a JSON (JavaScript Object Notation) representation of the data.">
<cfargument
name="var"
type="any"
required="true"
hint="A ColdFusion data value or variable that represents one." />
<cfargument
name="serializeQueryByColumns"
type="boolean"
required="false"
default="false"
hint="A Boolean value that specifies how to serialize ColdFusion queries.
<ul>
<li><code>false</code>: (Default) Creates an object with two entries: an array of column names and an array of row arrays. This format is required by the HTML format cfgrid tag.</li>
<li><code>true</code>: Creates an object that corresponds to WDDX query format.</li>
</ul>">
<cfargument
name="strictMapping"
type="boolean"
required="false"
default="false"
hint="A Boolean value that specifies whether to convert the ColdFusion data strictly, as follows:
<ul>
<li><code>false:</code> (Default) Convert the ColdFusion data to a JSON string using ColdFusion data types.</li>
<li><code>true:</code> Convert the ColdFusion data to a JSON string using underlying Java/SQL data types.</li>
</ul>" />
<!--- VARIABLE DECLARATION --->
<cfset var jsonString = "" />
<cfset var tempVal = "" />
<cfset var arKeys = "" />
<cfset var colPos = 1 />
<cfset var md = "" />
<cfset var rowDel = "" />
<cfset var colDel = "" />
<cfset var className = "" />
<cfset var i = 1 />
<cfset var column = "" />
<cfset var datakey = "" />
<cfset var recordcountkey = "" />
<cfset var columnlist = "" />
<cfset var columnlistkey = "" />
<cfset var columnJavaTypes = "" />
<cfset var dJSONString = "" />
<cfset var escapeToVals = "\\,\"",\/,\b,\t,\n,\f,\r" />
<cfset var escapeVals = "\,"",/,#Chr(8)#,#Chr(9)#,#Chr(10)#,#Chr(12)#,#Chr(13)#" />
<cfset var _data = arguments.var />
<cfif arguments.strictMapping>
<!--- GET THE CLASS NAME --->
<cfset className = getClassName(_data) />
</cfif>
<!--- TRY STRICT MAPPING --->
<cfif Len(className) AND CompareNoCase(className,"java.lang.String") eq 0>
<cfreturn '"' & ReplaceList(_data, escapeVals, escapeToVals) & '"' />
<cfelseif Len(className) AND CompareNoCase(className,"java.lang.Boolean") eq 0>
<cfreturn ReplaceList(ToString(_data), 'YES,NO', 'true,false') />
<cfelseif Len(className) AND CompareNoCase(className,"java.lang.Integer") eq 0>
<cfreturn ToString(_data) />
<cfelseif Len(className) AND CompareNoCase(className,"java.lang.Long") eq 0>
<cfreturn ToString(_data) />
<cfelseif Len(className) AND CompareNoCase(className,"java.lang.Float") eq 0>
<cfreturn ToString(_data) />
<cfelseif Len(className) AND CompareNoCase(className,"java.lang.Double") eq 0>
<cfreturn ToString(_data) />
<!--- BINARY --->
<cfelseif IsBinary(_data)>
<cfthrow message="JSON serialization failure: Unable to serialize binary data to JSON." />
<!--- BOOLEAN --->
<cfelseif IsBoolean(_data) AND NOT IsNumeric(_data)>
<cfreturn ReplaceList(YesNoFormat(_data), 'Yes,No', 'true,false') />
<!--- NUMBER --->
<cfelseif IsNumeric(_data)>
<cfif getClassName(_data) eq "java.lang.String">
<cfreturn Val(_data).toString() />
<cfelse>
<cfreturn _data.toString() />
</cfif>
<!--- DATE --->
<cfelseif IsDate(_data)>
<cfreturn '"#DateFormat(_data, "mmmm, dd yyyy")# #TimeFormat(_data, "HH:mm:ss")#"' />
<!--- STRING --->
<cfelseif IsSimpleValue(_data)>
<cfreturn '"' & ReplaceList(_data, escapeVals, escapeToVals) & '"' />
<!--- RAILO XML --->
<cfelseif StructKeyExists(server,"railo") and IsXML(_data)>
<cfreturn '"' & ReplaceList(ToString(_data), escapeVals, escapeToVals) & '"' />
<!--- CUSTOM FUNCTION --->
<cfelseif IsCustomFunction(_data)>
<cfreturn serializeToJSON( GetMetadata(_data), arguments.serializeQueryByColumns, arguments.strictMapping) />
<!--- OBJECT --->
<cfelseif IsObject(_data)>
<cfreturn "{}" />
<!--- ARRAY --->
<cfelseif IsArray(_data)>
<cfset dJSONString = ArrayNew(1) />
<cfloop from="1" to="#ArrayLen(_data)#" index="i">
<cfset tempVal = serializeToJSON( _data[i], arguments.serializeQueryByColumns, arguments.strictMapping ) />
<cfset ArrayAppend(dJSONString,tempVal) />
</cfloop>
<cfreturn "[" & ArrayToList(dJSONString,",") & "]" />
<!--- STRUCT --->
<cfelseif IsStruct(_data)>
<cfset dJSONString = ArrayNew(1) />
<cfset arKeys = StructKeyArray(_data) />
<cfloop from="1" to="#ArrayLen(arKeys)#" index="i">
<cfset tempVal = serializeToJSON(_data[ arKeys[i] ], arguments.serializeQueryByColumns, arguments.strictMapping ) />
<cfset ArrayAppend(dJSONString,'"' & arKeys[i] & '":' & tempVal) />
</cfloop>
<cfreturn "{" & ArrayToList(dJSONString,",") & "}" />
<!--- QUERY --->
<cfelseif IsQuery(_data)>
<cfset dJSONString = ArrayNew(1) />
<!--- Add query meta data --->
<cfset recordcountKey = "ROWCOUNT" />
<cfset columnlistKey = "COLUMNS" />
<cfset columnlist = "" />
<cfset dataKey = "DATA" />
<cfset md = GetMetadata(_data) />
<cfset columnJavaTypes = StructNew() />
<cfloop from="1" to="#ArrayLen(md)#" index="column">
<cfset columnlist = ListAppend(columnlist,UCase(md[column].Name),',') />
<cfif StructKeyExists(md[column],"TypeName")>
<cfset columnJavaTypes[md[column].Name] = getJavaType(md[column].TypeName) />
<cfelse>
<cfset columnJavaTypes[md[column].Name] = "" />
</cfif>
</cfloop>
<cfif arguments.serializeQueryByColumns>
<cfset ArrayAppend(dJSONString,'"#recordcountKey#":' & _data.recordcount) />
<cfset ArrayAppend(dJSONString,',"#columnlistKey#":[' & ListQualify(columnlist, '"') & ']') />
<cfset ArrayAppend(dJSONString,',"#dataKey#":{') />
<cfset colDel = "">
<cfloop list="#columnlist#" delimiters="," index="column">
<cfset ArrayAppend(dJSONString,colDel) />
<cfset ArrayAppend(dJSONString,'"#column#":[') />
<cfset rowDel = "">
<cfloop from="1" to="#_data.recordcount#" index="i">
<cfset ArrayAppend(dJSONString,rowDel) />
<cfif (arguments.strictMapping or StructKeyExists(server,"railo")) AND Len(columnJavaTypes[column])>
<cfset tempVal = serializeToJSON( JavaCast(columnJavaTypes[column],_data[column][i]), arguments.serializeQueryByColumns, arguments.strictMapping ) />
<cfelse>
<cfset tempVal = serializeToJSON( _data[column][i], arguments.serializeQueryByColumns, arguments.strictMapping ) />
</cfif>
<cfset ArrayAppend(dJSONString,tempVal) />
<cfset rowDel = ",">
</cfloop>
<cfset ArrayAppend(dJSONString,']') />
<cfset colDel = ",">
</cfloop>
<cfset ArrayAppend(dJSONString,'}') />
<cfelse>
<cfset ArrayAppend(dJSONString,'"#columnlistKey#":[' & ListQualify(columnlist, '"') & ']') />
<cfset ArrayAppend(dJSONString,',"#dataKey#":[') />
<cfset rowDel = "">
<cfloop from="1" to="#_data.recordcount#" index="i">
<cfset ArrayAppend(dJSONString,rowDel) />
<cfset ArrayAppend(dJSONString,'[') />
<cfset colDel = "">
<cfloop list="#columnlist#" delimiters="," index="column">
<cfset ArrayAppend(dJSONString,colDel) />
<cfif (arguments.strictMapping or StructKeyExists(server,"railo")) AND Len(columnJavaTypes[column])>
<cfset tempVal = serializeToJSON( JavaCast(columnJavaTypes[column],_data[column][i]), arguments.serializeQueryByColumns, arguments.strictMapping ) />
<cfelse>
<cfset tempVal = serializeToJSON( _data[column][i], arguments.serializeQueryByColumns, arguments.strictMapping ) />
</cfif>
<cfset ArrayAppend(dJSONString,tempVal) />
<cfset colDel=","/>
</cfloop>
<cfset ArrayAppend(dJSONString,']') />
<cfset rowDel = "," />
</cfloop>
<cfset ArrayAppend(dJSONString,']') />
</cfif>
<cfreturn "{" & ArrayToList(dJSONString,"") & "}">
<!--- XML --->
<cfelseif IsXML(_data)>
<cfreturn '"' & ReplaceList(ToString(_data), escapeVals, escapeToVals) & '"' />
<!--- UNKNOWN OBJECT TYPE --->
<cfelse>
<cfreturn "{}" />
</cfif>
</cffunction>
<cffunction
name="getJavaType"
access="private"
returntype="string"
output="false"
hint="Maps SQL to Java types. Returns blank string for unhandled SQL types.">
<cfargument
name="sqlType"
type="string"
required="true"
hint="A SQL datatype." />
<cfswitch expression="#arguments.sqlType#">
<cfcase value="bit">
<cfreturn "boolean" />
</cfcase>
<cfcase value="tinyint,smallint,integer">
<cfreturn "int" />
</cfcase>
<cfcase value="bigint">
<cfreturn "long" />
</cfcase>
<cfcase value="real,float">
<cfreturn "float" />
</cfcase>
<cfcase value="double">
<cfreturn "double" />
</cfcase>
<cfcase value="char,varchar,longvarchar">
<cfreturn "string" />
</cfcase>
<cfdefaultcase>
<cfreturn "" />
</cfdefaultcase>
</cfswitch>
</cffunction>
<cffunction
name="getClassName"
access="private"
returntype="string"
output="false"
hint="Returns a variable's underlying java Class name.">
<cfargument
name="data"
type="any"
required="true"
hint="A variable." />
<!--- GET THE CLASS NAME --->
<cftry>
<cfreturn arguments.data.getClass().getName() />
<cfcatch type="any">
<cfreturn "" />
</cfcatch>
</cftry>
</cffunction>
</cfcomponent>
@@ -0,0 +1,16 @@
<cfcomponent extends="taffy.core.baseSerializer">
<cffunction
name="getAsJson"
output="false"
taffy:mime="application/json"
taffy:default="true">
<cfreturn variables.jsonUtil.serialize(variables.data) />
</cffunction>
<cffunction name="setJSONUtil" output="false">
<cfargument name="JSONUtil" required="true" />
<cfset variables.jsonUtil = arguments.JSONUtil />
</cffunction>
</cfcomponent>
@@ -0,0 +1,14 @@
<cfcomponent extends="taffy.core.resource" taffy_uri="/artist/{artistId}/art">
<cfset variables.dummyData = StructNew() />
<cfset variables.dummyData.whatever = true />
<cffunction name="get" access="public" output="false">
<cfreturn representationOf(variables.dummyData).withStatus(200) />
</cffunction>
<cffunction name="post" access="public" output="false">
<cfreturn representationOf(variables.dummyData).withStatus(200) />
</cffunction>
</cfcomponent>
@@ -0,0 +1,22 @@
<cfcomponent extends="taffy.core.resource" taffy_uri="/artist/{artistId}/art/{artId}">
<cfset variables.dummyData = StructNew() />
<cfset variables.dummyData.whatever = true />
<cffunction name="get" access="public" output="false">
<cfreturn representationOf(variables.dummyData).withStatus(200) />
</cffunction>
<cffunction name="post" access="public" output="false">
<cfreturn representationOf(variables.dummyData).withStatus(200) />
</cffunction>
<cffunction name="put" access="public" output="false">
<cfreturn representationOf(variables.dummyData).withStatus(200) />
</cffunction>
<cffunction name="delete" access="public" output="false">
<cfreturn representationOf(variables.dummyData).withStatus(200) />
</cffunction>
</cfcomponent>
@@ -0,0 +1,61 @@
<cfcomponent extends="taffy.core.resource" taffy_uri="/artists">
<cffunction name="get" access="public" output="false">
<cfset var q = "" />
<cfset var headers = structNew() />
<cfquery name="q" datasource="cfartgallery" cachedwithin="#createTimeSpan(0,0,0,1)#">
select * from artists
</cfquery>
<cfset headers["x-powered-by"] = "Taffy 1.1" />
<cfreturn representationOf(q).withStatus(200).withHeaders(headers) />
</cffunction>
<cffunction name="post" access="public" output="false">
<cfargument name="firstname" type="string" required="false" default="" />
<cfargument name="lastname" type="string" required="false" default="" />
<cfargument name="address" type="string" required="false" default="" />
<cfargument name="city" type="string" required="false" default="" />
<cfargument name="state" type="string" required="false" default="" />
<cfargument name="postalcode" type="string" required="false" default="" />
<cfargument name="email" type="string" required="false" default="" />
<cfargument name="phone" type="string" required="false" default="" />
<cfargument name="fax" type="string" required="false" default="" />
<cfargument name="thepassword" type="string" required="false" default="" />
<cfset var q = "" />
<cfquery name="q" datasource="cfartgallery">
insert into artists (firstname,lastname,address,city,state,postalcode,email,phone,fax,thepassword)
values (
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.firstname#" />,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.lastname#" />,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.address#" />,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.city#" />,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.state#" />,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.postalcode#" />,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.email#" />,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.phone#" />,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.fax#" />,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.thepassword#" />
)
</cfquery>
<cfquery name="q" datasource="cfartgallery">
select * from artists
where
firstname = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.firstname#" />
and lastname = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.lastname#" />
and address = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.address#" />
and city = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.city#" />
and state = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.state#" />
and postalcode = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.postalcode#" />
and email = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.email#" />
and phone = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.phone#" />
and fax = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.fax#" />
and thepassword = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.thepassword#" />
</cfquery>
<cfreturn representationOf(q).withStatus(200) />
</cffunction>
<!---
The DELETE and PUT verbs are not implemented, so those actions are not permitted.
--->
</cfcomponent>
@@ -0,0 +1,102 @@
<cfcomponent extends="taffy.core.resource" taffy_uri="/artist/{id}">
<cffunction name="get" access="public" output="false">
<cfargument name="id" type="numeric" required="true" />
<cfset var q = ""/>
<cfquery name="q" datasource="cfartgallery">
select * from artists where artistId = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.id#" />
</cfquery>
<cfreturn representationOf(q).withStatus(200) />
</cffunction>
<cffunction name="put" access="public" output="false">
<cfargument name="id" type="numeric" required="true" />
<cfargument name="firstname" type="string" required="false" default="" />
<cfargument name="lastname" type="string" required="false" default="" />
<cfargument name="address" type="string" required="false" default="" />
<cfargument name="city" type="string" required="false" default="" />
<cfargument name="state" type="string" required="false" default="" />
<cfargument name="postalcode" type="string" required="false" default="" />
<cfargument name="email" type="string" required="false" default="" />
<cfargument name="phone" type="string" required="false" default="" />
<cfargument name="fax" type="string" required="false" default="" />
<cfargument name="thepassword" type="string" required="false" default="" />
<cfset var q = "" />
<cfquery name="q" datasource="cfartgallery">
update artists
set artistid=artistid
<cfif len(arguments.firstname)>
,firstname = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.firstname#" />
</cfif>
<cfif len(arguments.lastname)>
,lastname = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.lastname#" />
</cfif>
<cfif len(arguments.address)>
,address = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.address#" />
</cfif>
<cfif len(arguments.city)>
,city = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.city#" />
</cfif>
<cfif len(arguments.state)>
,state = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.state#" />
</cfif>
<cfif len(arguments.postalcode)>
,postalcode = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.postalcode#" />
</cfif>
<cfif len(arguments.email)>
,email = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.email#" />
</cfif>
<cfif len(arguments.phone)>
,phone = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.phone#" />
</cfif>
<cfif len(arguments.fax)>
,fax = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.fax#" />
</cfif>
<cfif len(arguments.thepassword)>
,thepassword = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.thepassword#" />
</cfif>
where artistid = <cfqueryparam cfsqltype="cf_sql_numeric" value="#arguments.id#" />
</cfquery>
<cfreturn noData().withStatus(200) />
</cffunction>
<cffunction name="post" access="public" output="false">
<cfargument name="firstname" type="string" required="false" default="" />
<cfargument name="lastname" type="string" required="false" default="" />
<cfargument name="address" type="string" required="false" default="" />
<cfargument name="city" type="string" required="false" default="" />
<cfargument name="state" type="string" required="false" default="" />
<cfargument name="postalcode" type="string" required="false" default="" />
<cfargument name="email" type="string" required="false" default="" />
<cfargument name="phone" type="string" required="false" default="" />
<cfargument name="fax" type="string" required="false" default="" />
<cfargument name="thepassword" type="string" required="false" default="" />
<cfset var q = "" />
<cfquery name="q" datasource="cfartgallery">
insert into artists (firstname,lastname,address,city,state,postalcode,email,phone,fax,thepassword)
values (
<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.firstname#" />
,<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.lastname#" />
,<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.address#" />
,<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.city#" />
,<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.state#" />
,<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.postalcode#" />
,<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.email#" />
,<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.phone#" />
,<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.fax#" />
,<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.thepassword#" />
)
</cfquery>
<cfreturn noData().withStatus(201) />
</cffunction>
<cffunction name="delete" access="public" output="false">
<cfargument name="id" type="numeric" required="true" />
<cfset var q = "" />
<cfquery name="q" datasource="cfartgallery">
delete from artists where artistid = <cfqueryparam cfsqltype="cf_sql_numeric" value="#arguments.id#" />
</cfquery>
<cfreturn noData().withStatus(200) />
</cffunction>
</cfcomponent>
@@ -0,0 +1,72 @@
<cfcomponent extends="taffy.core.api">
<cfscript>
this.name = "rate_limiting_example";
function onApplicationStart(){
application.accessLog = queryNew('apiKey,accessTime','varchar,time');
application.accessLimit = 100; //requests
application.accessPeriod = 60; //seconds
return super.onApplicationStart();
}
function onTaffyRequest(verb, cfc, requestArguments, mimeExt){
var usage = 0;
//require some api key
if (!structKeyExists(requestArguments, "apiKey")){
return noData().withStatus(401, "API Key Required");
}
//check usage
usage = getAccessRate(requestArguments.apiKey);
if (usage lte application.accessLimit){
logAccess(requestArguments.apiKey);
return true;
}else{
return noData().withStatus(420, "Enhance your calm");
}
return true;
}
</cfscript>
<cffunction name="getAccessRate" access="private" output="false">
<cfargument name="apiKey" required="true" />
<cfset var local = structNew() />
<!--- now get matches for the current api key --->
<cfquery name="local.accessLookup" dbtype="query">
select accessTime
from application.accessLog
where apiKey = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.apiKey#" />
and accessTime > <cfqueryparam cfsqltype="cf_sql_timestamp" value="#dateAdd("s",(-1 * application.accessPeriod),now())#" />
</cfquery>
<!--- if access log is getting long, do some cleanup --->
<cfif local.accessLookup.recordCount gt application.accessLimit>
<cfset pruneAccessLog() />
</cfif>
<cfreturn local.accessLookup.recordCount />
</cffunction>
<cffunction name="logAccess" access="private" output="true">
<cfargument name="apiKey" required="true" type="string" />
<cfset var qLog = '' />
<cflock timeout="10" type="readonly" name="logging">
<cfset queryAddRow(application.accessLog)/>
<cfset querySetCell(application.accessLog, "accessTime", now()) />
<cfset querySetCell(application.accessLog, "apiKey", arguments.apiKey) />
</cflock>
</cffunction>
<cffunction name="pruneAccessLog" access="private" output="false">
<cflock timeout="10" type="readonly" name="logging">
<cfquery name="application.accessLog" dbtype="query">
delete
from application.accessLog
where accessTime < <cfqueryparam cfsqltype="cf_sql_timestamp" value="#dateAdd("s",(-1 * application.accessPeriod),now())#" />
</cfquery>
</cflock>
</cffunction>
</cfcomponent>
@@ -0,0 +1,6 @@
<!---
DO NOT DELETE THIS FILE
===============================
This file is necessary for Taffy to work, but should be blank.
All requests funnel through it, but are handled by framework internal functionality.
--->
@@ -0,0 +1,152 @@
<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="2.1">
<hashTree>
<TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Over Rate Limit" enabled="true">
<stringProp name="TestPlan.comments"></stringProp>
<boolProp name="TestPlan.functional_mode">false</boolProp>
<boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
<elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="TestPlan.user_define_classpath"></stringProp>
</TestPlan>
<hashTree>
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="My Users" enabled="true">
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
<boolProp name="LoopController.continue_forever">false</boolProp>
<intProp name="LoopController.loops">-1</intProp>
</elementProp>
<stringProp name="ThreadGroup.num_threads">30</stringProp>
<stringProp name="ThreadGroup.ramp_time">13</stringProp>
<longProp name="ThreadGroup.start_time">1300766515000</longProp>
<longProp name="ThreadGroup.end_time">1300766515000</longProp>
<boolProp name="ThreadGroup.scheduler">false</boolProp>
<stringProp name="ThreadGroup.duration"></stringProp>
<stringProp name="ThreadGroup.delay"></stringProp>
</ThreadGroup>
<hashTree>
<ConstantTimer guiclass="ConstantTimerGui" testclass="ConstantTimer" testname="Constant Timer" enabled="true">
<stringProp name="ConstantTimer.delay">1000</stringProp>
</ConstantTimer>
<hashTree/>
<HTTPSampler guiclass="HttpTestSampleGui" testclass="HTTPSampler" testname="HTTP Request" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain">localhost</stringProp>
<stringProp name="HTTPSampler.port">80</stringProp>
<stringProp name="HTTPSampler.connect_timeout">1000</stringProp>
<stringProp name="HTTPSampler.response_timeout">5000</stringProp>
<stringProp name="HTTPSampler.protocol">http</stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">/taffy/examples/api_rateLimited/index.cfm/artist/1?apikey=fdsa</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<boolProp name="HTTPSampler.monitor">false</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
</HTTPSampler>
<hashTree/>
</hashTree>
<ResultCollector guiclass="SummaryReport" testclass="ResultCollector" testname="Summary Report" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>true</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
<ResultCollector guiclass="GraphVisualizer" testclass="ResultCollector" testname="Graph Results" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>true</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
<ResultCollector guiclass="TableVisualizer" testclass="ResultCollector" testname="View Results in Table" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>true</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
</hashTree>
</hashTree>
</jmeterTestPlan>
@@ -0,0 +1,152 @@
<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="2.1">
<hashTree>
<TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Within Rate Limit" enabled="true">
<stringProp name="TestPlan.comments"></stringProp>
<boolProp name="TestPlan.functional_mode">false</boolProp>
<boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
<elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="TestPlan.user_define_classpath"></stringProp>
</TestPlan>
<hashTree>
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="My Users" enabled="true">
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
<boolProp name="LoopController.continue_forever">false</boolProp>
<intProp name="LoopController.loops">-1</intProp>
</elementProp>
<stringProp name="ThreadGroup.num_threads">1</stringProp>
<stringProp name="ThreadGroup.ramp_time">20</stringProp>
<longProp name="ThreadGroup.start_time">1300766515000</longProp>
<longProp name="ThreadGroup.end_time">1300766515000</longProp>
<boolProp name="ThreadGroup.scheduler">false</boolProp>
<stringProp name="ThreadGroup.duration"></stringProp>
<stringProp name="ThreadGroup.delay"></stringProp>
</ThreadGroup>
<hashTree>
<ConstantTimer guiclass="ConstantTimerGui" testclass="ConstantTimer" testname="Constant Timer" enabled="true">
<stringProp name="ConstantTimer.delay">1100</stringProp>
</ConstantTimer>
<hashTree/>
<HTTPSampler guiclass="HttpTestSampleGui" testclass="HTTPSampler" testname="HTTP Request" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain">localhost</stringProp>
<stringProp name="HTTPSampler.port">80</stringProp>
<stringProp name="HTTPSampler.connect_timeout">1000</stringProp>
<stringProp name="HTTPSampler.response_timeout">5000</stringProp>
<stringProp name="HTTPSampler.protocol">http</stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">/taffy/examples/api_rateLimited/index.cfm/artist/1?apikey=fdsa</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<boolProp name="HTTPSampler.monitor">false</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
</HTTPSampler>
<hashTree/>
</hashTree>
<ResultCollector guiclass="SummaryReport" testclass="ResultCollector" testname="Summary Report" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>true</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
<ResultCollector guiclass="GraphVisualizer" testclass="ResultCollector" testname="Graph Results" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>true</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
<ResultCollector guiclass="TableVisualizer" testclass="ResultCollector" testname="View Results in Table" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>true</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
</hashTree>
</hashTree>
</jmeterTestPlan>
@@ -0,0 +1,81 @@
<cfcomponent extends="taffy.core.resource" taffy:uri="/artist/{id}" hint="some hint about this resource">
<cffunction name="get" access="public" output="false">
<cfargument name="id" type="numeric" required="true" />
<cfset var q = ""/>
<cfset var col = "" />
<cfset var rtn = StructNew() />
<cfquery name="q" datasource="cfartgallery" cachedwithin="#createTimeSpan(0,0,1,0)#">
select * from artists where artistId = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.id#" />
</cfquery>
<cfif q.recordCount gt 0>
<cfloop list="#q.ColumnList#" index="col">
<cfset rtn[col] = q[col][1] />
</cfloop>
<cfreturn representationOf(rtn).withStatus(200) />
<cfelse>
<cfreturn noData().withStatus(404) />
</cfif>
</cffunction>
<cffunction name="put" access="public" output="false">
<cfargument name="id" type="numeric" required="true" />
<cfargument name="firstname" type="string" required="false" default="" />
<cfargument name="lastname" type="string" required="false" default="" />
<cfargument name="address" type="string" required="false" default="" hint="some hint about this parameter" />
<cfargument name="city" type="string" required="false" default="" />
<cfargument name="state" type="string" required="false" default="" />
<cfargument name="postalcode" type="string" required="false" default="" />
<cfargument name="email" type="string" required="false" default="" />
<cfargument name="phone" type="string" required="false" default="" />
<cfargument name="fax" type="string" required="false" default="" />
<cfargument name="thepassword" type="string" required="false" default="" />
<cfset var q = "" />
<cfquery name="q" datasource="cfartgallery">
update artists
set artistid=artistid
<cfif len(arguments.firstname)>
,firstname = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.firstname#" />
</cfif>
<cfif len(arguments.lastname)>
,lastname = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.lastname#" />
</cfif>
<cfif len(arguments.address)>
,address = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.address#" />
</cfif>
<cfif len(arguments.city)>
,city = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.city#" />
</cfif>
<cfif len(arguments.state)>
,state = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.state#" />
</cfif>
<cfif len(arguments.postalcode)>
,postalcode = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.postalcode#" />
</cfif>
<cfif len(arguments.email)>
,email = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.email#" />
</cfif>
<cfif len(arguments.phone)>
,phone = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.phone#" />
</cfif>
<cfif len(arguments.fax)>
,fax = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.fax#" />
</cfif>
<cfif len(arguments.thepassword)>
,thepassword = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.thepassword#" />
</cfif>
where artistid = <cfqueryparam cfsqltype="cf_sql_numeric" value="#arguments.id#" />
</cfquery>
<cfreturn noData().withStatus(200) />
</cffunction>
<cffunction name="delete" access="public" output="false">
<cfargument name="id" type="numeric" required="true" />
<cfset var q = "" />
<cfquery name="q" datasource="cfartgallery">
delete from artists where artistid = <cfqueryparam cfsqltype="cf_sql_numeric" value="#arguments.id#" />
</cfquery>
<cfreturn noData().withStatus(200) />
</cffunction>
</cfcomponent>
@@ -0,0 +1,19 @@
<cfcomponent extends="taffy.core.api">
<cfscript>
this.name = hash(getCurrentTemplatePath());
// this function is called after the request has been parsed and all request details are known
function onTaffyRequest(verb, cfc, requestArguments, mimeExt){
if(not structKeyExists(arguments.requestArguments, "apiKey")){
//unauthorized because they haven't included their API key
return noData().withStatus(401);
}
//api key found
return true;
}
</cfscript>
</cfcomponent>
@@ -0,0 +1,6 @@
<!---
DO NOT DELETE THIS FILE
===============================
This file is necessary for Taffy to work, but should be blank.
All requests funnel through it, but are handled by framework internal functionality.
--->
@@ -0,0 +1,81 @@
<cfcomponent extends="taffy.core.resource" taffy:uri="/artist/{id}" hint="some hint about this resource">
<cffunction name="get" access="public" output="false">
<cfargument name="id" type="numeric" required="true" />
<cfset var q = ""/>
<cfset var col = "" />
<cfset var rtn = StructNew() />
<cfquery name="q" datasource="cfartgallery">
select * from artists where artistId = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.id#" />
</cfquery>
<cfif q.recordCount gt 0>
<cfloop list="#q.ColumnList#" index="col">
<cfset rtn[col] = q[col][1] />
</cfloop>
<cfreturn representationOf(rtn).withStatus(200) />
<cfelse>
<cfreturn noData().withStatus(404) />
</cfif>
</cffunction>
<cffunction name="put" access="public" output="false">
<cfargument name="id" type="numeric" required="true" />
<cfargument name="firstname" type="string" required="false" default="" />
<cfargument name="lastname" type="string" required="false" default="" />
<cfargument name="address" type="string" required="false" default="" hint="some hint about this parameter" />
<cfargument name="city" type="string" required="false" default="" />
<cfargument name="state" type="string" required="false" default="" />
<cfargument name="postalcode" type="string" required="false" default="" />
<cfargument name="email" type="string" required="false" default="" />
<cfargument name="phone" type="string" required="false" default="" />
<cfargument name="fax" type="string" required="false" default="" />
<cfargument name="thepassword" type="string" required="false" default="" />
<cfset var q = "" />
<cfquery name="q" datasource="cfartgallery">
update artists
set artistid=artistid
<cfif len(arguments.firstname)>
,firstname = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.firstname#" />
</cfif>
<cfif len(arguments.lastname)>
,lastname = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.lastname#" />
</cfif>
<cfif len(arguments.address)>
,address = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.address#" />
</cfif>
<cfif len(arguments.city)>
,city = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.city#" />
</cfif>
<cfif len(arguments.state)>
,state = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.state#" />
</cfif>
<cfif len(arguments.postalcode)>
,postalcode = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.postalcode#" />
</cfif>
<cfif len(arguments.email)>
,email = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.email#" />
</cfif>
<cfif len(arguments.phone)>
,phone = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.phone#" />
</cfif>
<cfif len(arguments.fax)>
,fax = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.fax#" />
</cfif>
<cfif len(arguments.thepassword)>
,thepassword = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.thepassword#" />
</cfif>
where artistid = <cfqueryparam cfsqltype="cf_sql_numeric" value="#arguments.id#" />
</cfquery>
<cfreturn noData().withStatus(200) />
</cffunction>
<cffunction name="delete" access="public" output="false">
<cfargument name="id" type="numeric" required="true" />
<cfset var q = "" />
<cfquery name="q" datasource="cfartgallery">
delete from artists where artistid = <cfqueryparam cfsqltype="cf_sql_numeric" value="#arguments.id#" />
</cfquery>
<cfreturn noData().withStatus(200) />
</cffunction>
</cfcomponent>
@@ -0,0 +1,30 @@
<cfcomponent extends="taffy.core.api">
<cfscript>
this.name = hash(getCurrentTemplatePath());
variables.framework = {};
variables.framework.reloadKey = "reload";
/*
You should NOT create your bean factory instance out here because that would cause it to be
re-created for every request, which is not going to be efficient at all!
Because of the Taffy Request Lifecycle, onApplicationStart is called BEFORE inspecting
your framework default settings, so you can optionally set the bean factory into
variables.framework from inside onApplicationStart.
Note that this does not stop you from setting values above; as I've set the value for
reloadKey. You can mix implementations like this; but anything that will have a significant
load time should be done in onApplicationStart.
*/
function onApplicationStart(){
application.coldspring = createObject("component", "coldspring.beans.DefaultXMLBeanFactory");
application.coldspring.loadBeans('config/coldspring.xml');
variables.framework.beanFactory = application.coldspring;
return super.onApplicationStart();
}
</cfscript>
</cfcomponent>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans default-autowire="byName">
<bean id="fakeData" class="taffy.examples.shared.fakeData" />
</beans>
@@ -0,0 +1,6 @@
<!---
DO NOT DELETE THIS FILE
===============================
This file is necessary for Taffy to work, but should be blank.
All requests funnel through it, but are handled by framework internal functionality.
--->
@@ -0,0 +1,13 @@
<cfcomponent extends="taffy.core.resource" taffy_uri="/artfarts">
<cffunction name="get" access="public" output="false">
<cfreturn representationOf(variables.fakeData.getData()) />
</cffunction>
<!--- this will be called by the bean factory's autowire functionality --->
<cffunction name="setFakeData" access="public" output="false" returnType="void">
<cfargument name="fakeDataObj" type="any" required="true" hint="Shared FakeData object" />
<cfset variables.fakeData = arguments.fakeDataObj />
</cffunction>
</cfcomponent>
@@ -0,0 +1,17 @@
<cfcomponent extends="taffy.core.api">
<cfscript>
this.name = hash(getCurrentTemplatePath());
variables.framework = {};
variables.framework.serializer = "resources.CustomSerializer";
function onApplicationStart(){
application.JsonUtil = createObject("component", "resources.JSONUtil.JSONUtil");
application.AnythingToXML = createObject("component", "resources.AnythingToXML.AnythingToXML");
return super.onApplicationStart();
}
</cfscript>
</cfcomponent>
@@ -0,0 +1,6 @@
<!---
DO NOT DELETE THIS FILE
===============================
This file is necessary for Taffy to work, but should be blank.
All requests funnel through it, but are handled by framework internal functionality.
--->

Some files were not shown because too many files have changed in this diff Show More