Here is my coldfusion web service. When I use soapUI tool to call 'test', i am receiving this
"<ns1:stackTrace xmlns:ns1="http://xml.apache.org/axis/">org.xml.sax.SAXParseException: Premature end of file."
error.
can anyone help me on this issue? I already seached online, but no luck. any code issue?
do I need to use <cfproperty> tag?
<cfcomponent output="false">
<!--- initialisation --->
<cffunction
name="init"
output="false"
hint="return an initialized object.">
<!--- Return THIS reference. --->
<cfreturn THIS />
</cffunction>
<!--- ping --->
<cffunction
name="test"
access="remote"
returntype="numeric"
output="false"
hint="return an true = 0.">
<!--- declare local variables --->
<cfset var local = 0 />
<!--- Return 0. --->
<cfreturn local />
</cffunction>
</cfcomponent>
Couple questions: are you on CF9? What happens when you invoke it straight up (not through SoapUI, but as a http call in a browser)?
Also, I would strongly recommend against using "Local" as a variable name in a function - CF9 introduced some changes in how variables are scoped within a function and uses that as the name for that constrained scope.
Related
I've got the following code in a method:
<cffunction name="serviceTicketValidate" access="public" output="yes" returntype="void" hint="Validate the service ticket">
<cfargument name="service_ticket" type="string" required="yes" hint="The ST to validate" />
<!--- Contact the CAS server to validate the ticket --->
<cfhttp url="#Variables.cas_server#serviceValidate" method="get">
<cfhttpparam name="ticket" value="#Arguments.service_ticket#" type="url" />
<cfhttpparam name="service" value="#Variables.service#" type="url" />
</cfhttp>
<!--- Received a valid XML response --->
<cfif IsXML(cfhttp.FileContent)>
<cfset XMLobj = XmlParse(cfhttp.fileContent)>
<!--- Check for the cas:user tag --->
<cfset CASuser = XmlSearch(XMLobj, "cas:serviceResponse/cas:authenticationSuccess/cas:user")>
<!--- Set the username to the value --->
<cftry>
<cfif variables.username NEQ ''>
<cfdump var="#Variables.username#" /><cfreturn/>
</cfif>
<cfif ArrayLen(CASuser)>
<cfset Variables['username'] = CASuser[1].XmlText />
</cfif>
<cfcatch>
<cfdump var="#cfcatch#" /><cfabort/>
</cfcatch>
</cftry>
<!--- Search for cas:attributes --->
<cfset CASattributes = XmlSearch(XMLobj, "cas:serviceResponse/cas:authenticationSuccess/cas:attributes")>
<!--- Go through all the attributes and add them to the attributes struct --->
<cfif ArrayLen(CASattributes)>
<cfloop array=#CASattributes[1].XmlChildren# index="attribute">
<cfset StructInsert(Variables.attributes,RemoveChars(attribute.XmlName,1,Find(":",attribute.XmlName)),attribute.XmlText)/>
</cfloop>
</cfif>
</cfif>
Note I added the cftry and cfcatch to see what is going on exactly. I've also added the if username != blank to debug as well. This method is called in another method like so:
<cfinvoke method="serviceTicketValidate">
<cfinvokeargument name="service_ticket" value="#service_ticket#" />
</cfinvoke>
<cfdump var="test2" /><cfabort/>
Again I've added the dump and abort for testing. The variable.username is defied and set to an empty string when the component is initiated and the component is initiated into a session variable.
So get this... when the whole process runs the first time I get output on my screen test2 as expected. Then, the next time the same thing is run, the session exists, thus the variable.username is set to something. In the first code block I can dump variables.username and see the username. However if I try to use variables.username in a conditional expression (like in that if statement) or if I remove the if statement and let the script try to change the value of variable.username, there are no errors, it just breaks out of the script completely. It ends that method, and the method that called it and I don't see test2 like I would think. It all just ends for some reason.
If you need further details I can provide more code but I tried to trim out as much as I thought was relevant. All methods are in the same component, all methods are public. Why can't I change the value of variables.username and why is there no error?
EDIT:
I think it may have something to do with the cflock but I'm debugging some stuff right now. I had a redirect inside the code block that is inside the lock. So I guess it never unlocks. But I even waited after the timeout and it still remained locked. I thought the lock was supposed to expire after the timeout.
I'm a little confused but it seems like you're trying to use a cfc's variables scope to set caller variables. The variables scope is not available to the caller the way it seems you are trying to use it.
index.cfm
<cfoutput>
<cfset objTest = createObject("component", "testscope").init()><br><Br>
<cfset objTest.checkValue()><br><br>
Calling page is checking the existence of testvar: #isDefined("variables.testvar")#
</cfoutput>
testscope.cfm
<cfcomponent displayname="testscope">
<cffunction name="init" access="public">
init() just set variables.testvar.
<cfset variables.testvar = "Okay, set">
<cfreturn This>
</cffunction>
<!--- Set some more variables --->
<cffunction name="checkValue" access="public">=
<cfoutput>Checkvalue is checking the value of testvar: #variables.testvar#</cfoutput>
</cffunction>
</cfcomponent>
The output is
init() just set variables.testvar.
Checkvalue is checking the value of testvar: Okay, set
Calling page is checking the existence of testvar: false
I am getting the following error message. I have already created Uploads.cfc handler in handlers directory. Checked everything, can't find the solution.
Error Type: HandlerService.EventHandlerNotRegisteredException : [N/A]
Error Messages: The event: uploads is not valid registered event.
Here is the Uploads.cfc code:
<!--- Default Action --->
<cffunction name="index" returntype="string" output="false" hint="My main event">
<cfargument name="event">
<cfargument name="rc">
<cfargument name="prc">
<cfobject component="model.Uploader" name="fileUploader">
<cfset filesJson = fileUploader.Upload(rc.file)>
<cfreturn filesJson>
</cffunction>
Can you please suggest a solution?
You shouldn't have to restart the whole CF server. You just need to re-initialize ColdBox. Just add ?fwreint= or ?fwreint={password} to the URL. The password is set in ColdBox.cfc: "reinitpassword". You can also configure in ColdBox.cfc to not cache handlers in non-production environments.
If you're using ColdBox 3.6 or newer, you don't have to define event, rc and prc anymore.
<cffunction name="index" returntype="string" output="false" hint="My main event">
<cfobject component="model.Uploader" name="fileUploader">
<cfset filesJson = fileUploader.Upload(rc.file)>
<cfreturn filesJson>
</cffunction>
Secondly, you should use WireBox instead of creating objects on the fly as you're doing. And finally, don't define variables specific to a function into the variables scope of the handler CFC file. Prefix them with local to make sure that those variables are "function local": only available to the particular function that is using them.
<cffunction name="index" returntype="string" output="false" hint="My main event">
<cfset local.fileUploader = getModel("Uploader") >
<cfset local.filesJson = fileUploader.Upload(rc.file)>
<cfreturn local.filesJson>
</cffunction>
I have also encountered the same problem in the past. Try restart the ColdFusion Application Server.
iKnowKungFu misspelled ?fwreint= (missing i)
Should be ?fwreinit
I have a web form which uses the action attribute to call a CFC like this:
<form action="mycfc.cfc?method=registeruser">
The CFC processes the data in the form and then I want it to return a variable telling the user if their form submission has been successful or not.
So within my CFC, I put this:
<cffunction name="registeruser" access="remote" hint="registers a new user" returnformat="JSON">
... PROCESSES FORM HERE THEN...
<cfset Msg = 'Success'>
<cfreturn Msg>
<cflocation url = "/registrationpage.cfm">
</cffunction>
How do I display the Msg variable in the registrationpage.cfm page? My output is set to JSON so I guess I have to DeSerialize but I have no idea how to actually reference/access this output from the method.
My whole answer is for educationnal purposes only and I strongly advise you to use an existing framework rather than reinventing the Wheels. Have a look at Picking a ColdFusion MVC Framework
You can store the value in the session scope. A lot of frameworks does it using a flash memory concept, which is a temporary memory (implemented as a struct) that destroys members when accessed.
Have a look at http://cfwheels.org/docs/1-1/chapter/using-the-flash it's quite straight forward to implement an API that does this.
Client code could look like (depending on your implementation):
<cfset session.flash.set('importantMsg', 'some important msg')>
<cflocation ...>
Then from the other page:
<cfif session.flash.has('importantMsg')>
<!--- The following line should also destroy the 'importantMsg' key --->
#session.flash.get('importantMsg')#
</cfif>
Here's an implementation example (not that the implementation is not thread-safe):
FlashMemory.cfc
<cfcomponent>
<cffunction name="init" returntype="FlashMemory">
<cfset variables.instance = {flash = {}}>
</cffunction>
<cffunction name="set" returntype="void">
<cfargument name="key" type="string" required="true">
<cfargument name="value" type="any" required="true">
<cfset variables.instance.flash[arguments.key] = arguments.value>
</cffunction>
<cffunction name="get" returntype="any">
<cfargument name="key" type="string" required="true">
<cfset var v = variables.instance.flash[arguments.key]>
<cfset structDelete(variables.instance.flash, arguments.key)>
<cfreturn v>
</cffunction>
<cffunction name="has" returntype="boolean">
<cfargument name="key" type="string" required="true">
<cfreturn structKeyExists(variables.instance.flash, arguments.key)>
</cffunction>
</cfcomponent>
onSessionStart
<cfset session.flash = new FlashMemory()>
Also please note that in your case, your remote CFC methods shouldn't return anything. You will use the flash memory to pass data around instead. That means when the method has finished it's work you can simply redirect the client.
You probably shouldn't use remote CFC methods in this particular case:
I have never really used remote CFC methods as stateful web services. The various advantages of remote CFC methods like their ability to spit out data in multiple data-interchange formats (JSON, WDDX...) is lost with your implementation.
You could simply do something like:
registration.cfm
<cfset errors = session.flash.get('registrationErrors')>
<cfif arrayLen(errors)>
<!--- Display errors --->
</cfif>
<form method="post" action="register.cfm">
...
</form>
register.cfm
<cfset registration = new Registration(argumentcollection = form)>
<cfset validator = new RegistrationValidator(registration)>
<cfif validator.validate()>
<cfset application.userService.register(registration)>
<!--- You can also redirect to a page that represents the correct state --->
<cflocation url="registered.cfm" addtoken="no">
<cfelse>
<!--- Store the errors collection in the flash memory --->
<cfset session.flash.set('registrationErrors', validator.errors())>
<!--- Redirect to the page the user came from --->
<cflocation url="#cgi.http_referer#" addtoken="no">
</cfif>
Take the cflocation tag out of your function. It will not execute anyway because it's after the cfreturn tag.
Also, post your form to a .cfm page, not the .cfc. From that .cfm page, do this:
<cfset MyObject = CreateObject(stuff for your cfc goes here)>
<cfset MessageFromFunction = MyObject.registeruser()>
<cfoutput>#MessageFromFunction</cfoutput.
I am trying to convert an application I support from application.cfm to application.cfc. I followed Ben Nadel's ColdFusion Application.cfc Tutorial And Application.cfc Reference, but my pages cannot access any of the variables in the APPLICATION scope, without adding APPLICATION. to the variable. As a side note, this application uses 0 cfc's currently.
here is my application.cfc.
<cfcomponent displayname="Application" hint="Handle the application" output="true">
<cfset THIS.Name = "AAS" />
<cfset THIS.ApplicationTimeout = CreateTimeSpan( 0, 60, 0 , 0) />
<cfset THIS.SessionManagement = true />
<cfset THIS.setClientCookies = false />
<cfset THIS.versionNum = '1'>
<cfset THIS.genericUserID = 'o005265'>
<cfset THIS.genericPassword = 'zo005265'>
<cffunction
name="OnApplicationStart"
hint="Fires when the application is first created."
access="public"
output="false"
returntype="boolean">
<cfset APPLICATION.aasURL = 'http://127.0.0.1:8500/aaas'>
<cfset APPLICATION.dsn = 've0_aaas'>
<cfset APPLICATION.aas_system = 'development (studio)'>
<cfreturn true />
</cffunction>
</cfcomponent>
Basically I just copied what was in the application.cfm page, and figured it would work the same. I am guessing that I have to invoke this somewhere? That is the only thing that I can think of. Any help would be great.
--- EDIT ---
I have added the OnRequest and OnApplicationStart methods after #EvikJames answer
<cffunction name="OnApplicationStart" access="public" returntype="boolean" output="false" hint="Fires when the application is first created.">
<!--- Return out. --->
<cfset APPLICATION.aasURL = 'http://127.0.0.1:8500/aaas'>
<cfset APPLICATION.datasource = 've0_aaas'>
<cfset APPLICATION.aas_system = 'development (studio)'>
<cfreturn true />
</cffunction>
<cffunction name="OnRequest" access="public" returntype="void" output="true" hint="Fires after pre page processing is complete.">
<!--- Define arguments. --->
<cfargument name="TargetPage" type="string" required="true">
<!--- Include the requested page. --->
<cfinclude template="#ARGUMENTS.TargetPage#" />
<cfset VARIABLES.dsn = APPLICATION.dsn>
<cfset VARIABLES.aasURL = APPLICATION.aasURL>
<cfset VARIABLES.aas_system = APPLICATION.aas_system>
<!--- Return out. --->
<cfreturn />
</cffunction>
You aren't really trying to use "application" variables (which always need to be scoped). I suspect your old application.cfm page had something like.
<cfapplicatin name="blah"...>
<cfset dsn = 'mydsn'/>
And then you were able to do:
<cfquery datasource="#dsn#">
This approach does not utilze the application scope ... it is merely taking advantage of the fact that your application.cfm always runs no matter what. What it is actually doing is putting variables in the variables scope. Because CF always checks the "variables" scope first you soemthing like #dsn# works - but that is not the same as the application scope.
To mimic this behavior in Application.cfc (as has been suggested) you will need to put your variable in the "onRequest()" function instead of the "onApplicationstart()" function - like so:
<cffunction name="onRequest">
<cfset dsn = 'mydsn'/>
</cffunction>
That is expected. To reference application variables you need to prefix them with application.
In your onApplication start method, do this:
<cfset APPLICATION.datasource = 'MyDSN'>
In your onRequest method, do this:
<cfset VARIABLES.DSN = APPLICATION.datasource>
Then, this query will work:
<cfquery datasource="#dsn#">
// sql
</cfquery>
I should add that when you are fully upgraded, you can remove all of the code above just set the default datasource:
<cfset THIS.datasource = 'MyDSN'>
If the variable is in the application scope, you will always need to identify it that way in your .cfm pages. If you use a variable name without the scope prefix, the application scope is not looked at.
if you want to declare variables in the application.cfc that can be accessed without the application scope in your other pages, simply declare the variables outside of any functions.
<component>
<cfset this.name = "applicationName">
<cfset otherVar = 'something'>
<cfset otherVar2 = 'something else'>
<cffunction name="onApplicationStart>.....</cffunction>
</component>
otherVar and otherVar2 can be called without scope prefix on all .cfm pages.
It sounds like you were not originally using application scoped variables. If the variables were not originally scope with "application." then they were simply in "variables scope" (confusing wording I know) which is accessible by the cfm page hit and others included. That is one big change when moving between application.cfm and application.cfc. The general idea there follows the principle that included CFM files share variables scope and CFC files do not.
If the only change you have to make is changing #dsn# to #appplication.dsn# then just do it and get it over with. There are tools such as WinGrep or even Notepad++ which have find and replace across multiple files.
Problem: When requesting the WSDL for a CFC, I get the following error: Variable FORM is undefined. It happens in this line of code, in the OnRequestStart method in application.cfc
<cfif structKeyExists(form,'resetappvars')>
<cfset OnApplicationStart() />
</cfif>
If I request a specific method, it works fine. I have considered using cfparam to create a default form struct if none exists, but that seems like an ugly hack and I worry it will actually create the form struct in the variables or this scope of the CFC. Maybe this is a legitimate bug as well?
Note: This only happens when I request the WSDL, if I invoke a method directly - the code executes as expected without problems.
Update: Application.cfc code sample - just add any CFC to your app and request it with ?wsdl to see the issue. This has been tested (and failed) on ColdFusion 7 and ColdFusion 8.
<cfcomponent output="false">
<cffunction name="OnApplicationStart" access="public" returntype="boolean" output="false" hint="Fires when the application is first created.">
<cfset application.dsn = "my_dsn" />
<cfreturn true />
</cffunction>
<cffunction name="OnRequestStart" access="public" returntype="boolean" output="false" hint="Fires at first part of page processing.">
<cfargument name="TargetPage" type="string" required="true" />
<cfif structKeyExists(form,'resetappvars')>
<cfset OnApplicationStart() />
</cfif>
<cfreturn true />
</cffunction>
</cfcomponent>
Maybe try adding a:
<cfif IsDefined("form")>...</cfif>
around the above code?
You could also cfparam the variable you're looking for then just change your logic a little (assuming resetAppVars is a boolean:
<cfparam name="form.resetAppVars" default="false" />
...
<cfif form.resetAppVars>
<cfset OnApplicationStart() />
</cfif>
Edit: I'm not sure if the above code could be considered a hack, but it seems pretty standard CF, to me.
This post of Ben Nadel gives detailed list of scopes available for different types of requests.
By reading it you can easily find out that form scope is not available in given context, but url is.
I've heard it's just a matter of opinion, but it seems to me that it is improper to reference your form scope within a CFC, as there is no guarantee that the form scope will be available when your cfc is invoked and when your method is called. It is better to ensure that any data that needs to be available to the method is provided explicitly to your object. This can be done either by including an argument:
<cfargument name="resetAppVars" type="boolean" required="false" default="false" />
Then you check arguments.resetAppVars, and it is always defined, but defaulted to false.
Or by creating an attribute on your object and creating an explicit set method:
(at the top of your cfc)
<cfset this.resetAppVars = false />
<cffunction name="setResetAppVars" access="public" returnType="void" output="false">
<cfargument name="flagValue" type="boolean" required="true" />
<cfset this.resetAppVars = arguments.flagValue />
</cffunction>
In which case you will check against this.resetAppVars. You can also scope this locally using <cfset var resetAppVars = false /> as the declaration, which makes it a private attribute of your object, and is probably proper, so code that invokes the object cannot improperly overwrite this variable with a non-boolean type. In that case, you would simply refer directly to resetAppvars in your test, instead of using this scope.
You could also do this:
<cfif NOT isSoapRequest()>...
and stick your remaining logic inside that chunk.