MXStudio » Coldfusion » Application.cfc uma de suas funcionalidades

Application.cfc uma de suas funcionalidades



Introdução

Na primeira quinzena do mês de junho (2006), respondi a uma questão sobre performance em instaciamentos de componentes (CFC), e a possibilidade de acelerar a criação de um objeto do tipo componente.
Mesmo sabendo que havia escrito um código que teria uma performance alta, ainda sim procurei algo que pudesse ser mais rápido ou que utiliza-se menos código.

Pré-requisito

ColdFusion MX 7.0.1, e conhecimentos sobre Application.cfc (livedocs).

Objetivo

Observar alguns métodos não documentados em alguns escopos.

Conceitos

Veremos então os scripts que enviei como resposta a questão, descrita no início, e em seguida os resultados da pesquisa baseada nas propriedades dos escopos.
Inicialmente tentei buscar algo na função getPageContext como em matéria anterior, logo depois na integração J2EE como já visto também em matérias enteriores (artigo 1 , artigo 2). A função não acrescetou muito ao código da resposta, porém na integração J2EE fui surpreendido com algumas propriedades não documentadas.

Conteúdo

Código enviado por mim como resposta, formado por três arquivos bem simples, apenas para demonstração, onde encontramos o arquivo Application.cfc que foi estendido do arquivo testeObjetos.cfc e instanciado no arquivo testeObjetos.cfm. Esta estrutura foi necessária para descartar o uso do createobject, com parâmetro component, para instanciar o componente testeObjetos.cfc, e estimulando a utilização do escopo request e do evento/método onRequestStart, para criar uma variável que contivesse os atributos e métodos do objeto testeObjetos

testeObjetos.cfc

<cfcomponent output=”no”>
<cfset this.id = 0 >
<cfscript>
function clear_trash(){
var i = “”;
for(i in this){
if(ucase(i) neq “ID” and ucase(i) neq “TESTEOBJETOS”){
structdelete(this,i);
}
}
}
function testeObjetos(id){
this.id = id;
return this;
}
</cfscript>
</cfcomponent>

Application.cfc

<cfcomponent extends=”testeObjetos”>
<cfscript>
this.name = ‘testecfc’;
this.sessionmanagement = true;
this.applicationtimeout = CreateTimeSpan(0,3,0,0);
this.sessiontimeout = CreateTimeSpan(0,3,0,0);
function onapplicationstart(){
application.author = ‘Pedro Claudio de Lima e Silva’;
application.email = ‘pcsilva@gmail.com’;
application.create = ‘04/06/06′;
return true;
}
function OnRequestStart(){
Request.cfcfamily = this;
Request.cfcfamily.clear_trash();
}
</cfscript>
</cfcomponent>

testeObjetos.cfc

<h1>O Application.cfc cria o objeto sempre</h1>
<cfscript>
if(isdefined(“Request.cfcfamily”)){
contador = 500;
inicioTickCount = getTickCount();
arrayTeste = arrayNew(1);
for (i=1; i LTE contador; i=i+1) {
id = randRange(1, contador^3);
arrayTeste[i] = id;
}
writeOutput(‘Array de inteiros: ‘ & getTickCount() – inicioTickCount & ‘ milisegundos<br>’); inicioTickCount = getTickCount();
arrayTeste = arrayNew(1);
for (i=1; i LTE contador; i=i+1) {
id = randRange(1, contador^3);
arrayTeste[i] = Request.cfcfamily.testeObjetos(id);
}
writeOutput(‘Array de objetos: ‘ & getTickCount() – inicioTickCount & ‘ milisegundos<br>’);
}else{
writeOutput(‘Sem objeto para instanciar’);
}
</cfscript>

Conhecendo mais

Porém esta solução geraria uma variável para cada requisição, e algumas delas não utilizariam esta variável, foi então que as surpresas (não documentadas) começaram.

Para os testes reescrevi o Application.cfc, e utilizei o mesmo componente testeObjetos.cfc.

Application.cfc

<cfcomponent extends=”testeObjetos”>
<cfscript>
this.name = ‘testecfc2′;
this.sessionmanagement = true;
this.applicationtimeout = CreateTimeSpan(0,3,0,0);
this.sessiontimeout = CreateTimeSpan(0,3,0,0);
</cfscript>
</cfcomponent>

Primeiro no escopo application, onde pude acessar os métodos do application.cfc de duas formas.

Através do método
getEventInvoker().

testeObjetos2.cfm

<cfdump var=”#application.getEventInvoker()#”>

table.cfdump_wddx, table.cfdump_xml, table.cfdump_struct, table.cfdump_array, table.cfdump_query, table.cfdump_cfc, table.cfdump_object, table.cfdump_binary, table.cfdump_udf, table.cfdump_udfbody, table.cfdump_udfarguments { font-size: xx-small; font-family: verdana, arial, helvetica, sans-serif; cell-spacing: 2px; }

table.cfdump_wddx th, table.cfdump_xml th, table.cfdump_struct th, table.cfdump_array th, table.cfdump_query th, table.cfdump_cfc th, table.cfdump_object th, table.cfdump_binary th, table.cfdump_udf th, table.cfdump_udfbody th, table.cfdump_udfarguments th { text-align: left; color: white; padding: 5px; }

table.cfdump_wddx td, table.cfdump_xml td, table.cfdump_struct td, table.cfdump_array td, table.cfdump_query td, table.cfdump_cfc td, table.cfdump_object td, table.cfdump_binary td, table.cfdump_udf td, table.cfdump_udfbody td, table.cfdump_udfarguments td { padding: 3px; background-color: #ffffff; vertical-align : top; }

table.cfdump_wddx { background-color: #000000; } table.cfdump_wddx th.wddx { background-color: #444444; }

table.cfdump_xml { background-color: #888888; } table.cfdump_xml th.xml { background-color: #aaaaaa; } table.cfdump_xml td.xml { background-color: #dddddd; }

table.cfdump_struct { background-color: #0000cc ; } table.cfdump_struct th.struct { background-color: #4444cc ; } table.cfdump_struct td.struct { background-color: #ccddff; }

table.cfdump_array { background-color: #006600 ; } table.cfdump_array th.array { background-color: #009900 ; } table.cfdump_array td.array { background-color: #ccffcc ; }

table.cfdump_query { background-color: #884488 ; } table.cfdump_query th.query { background-color: #aa66aa ; } table.cfdump_query td.query { background-color: #ffddff ; }

table.cfdump_cfc { background-color: #ff0000; } table.cfdump_cfc th.cfc{ background-color: #ff4444; } table.cfdump_cfc td.cfc { background-color: #ffcccc; }

table.cfdump_object { background-color : #ff0000; } table.cfdump_object th.object{ background-color: #ff4444; }

table.cfdump_binary { background-color : #eebb00; } table.cfdump_binary th.binary { background-color: #ffcc44; } table.cfdump_binary td { font-size: x-small; } table.cfdump_udf { background-color: #aa4400; } table.cfdump_udf th.udf { background-color: #cc6600; } table.cfdump_udfarguments { background-color: #dddddd; cell-spacing: 3; } table.cfdump_udfarguments th { background-color: #eeeeee; color: #000000; }

function dump ( obj ) { var out = \’\’ ; if ( typeof obj == “object” ) { for ( key in obj ) { if ( typeof obj[key] != “function” ) out += key + \’: \’ + obj[key] + \’
\’ ; } } }

function cfdump_toggleRow(source) { //target is the right cell if(document.all) target = source.parentElement.cells[1]; else target = source.parentNode.lastChild ;

cfdump_toggleTarget( target, cfdump_toggleSource( source ) ) ; }

function cfdump_toggleXmlDoc(source) {

var caption = source.innerHTML.split( \’ [\' ) ;

// toggle source (header) if ( source.style.fontStyle == \'italic\' ) { // closed -> short source.style.fontStyle = \'normal\' ; source.innerHTML = caption[0] + \’ [short version]\’ ; source.title = \’click to maximize\’ ; switchLongToState = \’closed\’ ; switchShortToState = \’open\’ ; } else if ( source.innerHTML.indexOf(\’[short version]\’) != -1 ) { // short -> full source.innerHTML = caption[0] + \’ [long version]\’ ; source.title = \’click to collapse\’ ; switchLongToState = \’open\’ ; switchShortToState = \’closed\’ ; } else { // full -> closed source.style.fontStyle = \’italic\’ ; source.title = \’click to expand\’ ; source.innerHTML = caption[0] ; switchLongToState = \’closed\’ ; switchShortToState = \’closed\’ ; }

// Toggle the target (everething below the header row). // First two rows are XMLComment and XMLRoot – they are part // of the long dump, the rest are direct children – part of the // short dump if(document.all) { var table = source.parentElement.parentElement ; for ( var i = 1; i < table.rows.length; i++ ) { target = table.rows[i] ; if ( i < 3 ) cfdump_toggleTarget( target, switchLongToState ) ; else cfdump_toggleTarget( target, switchShortToState ) ; } } else { var table = source.parentNode.parentNode ; var row = 1; for ( var i = 1; i < table.childNodes.length; i++ ) { target = table.childNodes[i] ; if( target.style ) { if ( row < 3 ) { cfdump_toggleTarget( target, switchLongToState ) ; } else { cfdump_toggleTarget( target, switchShortToState ) ; } row++; } } } }

function cfdump_toggleTable(source) {

var switchToState = cfdump_toggleSource( source ) ; if(document.all) { var table = source.parentElement.parentElement ; for ( var i = 1; i < table.rows.length; i++ ) { target = table.rows[i] ; cfdump_toggleTarget( target, switchToState ) ; } } else { var table = source.parentNode.parentNode ; for ( var i = 1; i < table.childNodes.length; i++ ) { target = table.childNodes[i] ; if(target.style) { cfdump_toggleTarget( target, switchToState ) ; } } } }

function cfdump_toggleSource ( source ) { if ( source.style.fontStyle == \’italic\’ || source.style.fontStyle == null) { source.style.fontStyle = \’normal\’ ; source.title = \’click to collapse\’ ; return \’open\’ ; } else { source.style.fontStyle = \’italic\’ ; source.title = \’click to expand\’ ; return \’closed\’ ; } }

function cfdump_toggleTarget ( target, switchToState ) { if ( switchToState == \’open\’ ) target.style.display = \’\’ ; else target.style.display = \’none\’ ; }

object of coldfusion.runtime.AppEventInvoker
Methods onApplicationStart (returns boolean)
onSessionStart (returns void)
onRequestStart (returns boolean)
isMethodPresent (returns boolean)
onRequest (returns void)
onRequestEnd (returns void)
onError (returns void)
onError (returns void)
onApplicationEnd (returns void)
onSessionEnd (returns void)
invoke (returns java.lang.Object)
invoke (returns java.lang.Object)
invoke (returns java.lang.Object)
invoke (returns java.lang.Object)
getMethod (returns coldfusion.runtime.UDFMethod)
flush (returns void)
createContext (returns coldfusion.filter.FusionContext)
setAutoFlush (returns void)
getThisScope (returns interface java.util.Map)
setApplicationExecution (returns void)
inInvoke (returns boolean)
setThisScope (returns void)
hashCode (returns int)
getClass (returns java.lang.Class)
wait (returns void)
wait (returns void)
wait (returns void)
equals (returns boolean)
notify (returns void)
notifyAll (returns void)
toString (returns java.lang.String)

Onde encontrei getThisScope()

testeObjetos3.cfm

<cfdump var=”#application.getEventInvoker().getThisScope()#”>

struct
APPLICATIONTIMEOUT 10800
CLEAR_TRASH
function clear_trash
Arguments: none
Return Type:  
Roles:  
Access: public
Output: Yes
CLIENTMANAGEMENT NO
CLIENTSTORAGE Registry
LOGINSTORAGE cookie
NAME testecfc2
SCRIPTPROTECT [empty string]
SESSIONMANAGEMENT true
SESSIONTIMEOUT 10800
SETCLIENTCOOKIES YES
SETDOMAINCOOKIES NO
TESTEOBJETOS
function testeObjetos
Arguments:

Name Required Type Default
ID Required Any  
Return Type:  
Roles:  
Access: public
Output: Yes

Encontrei também getApplicationSettings(), que retornará o mesmo valor contido em getEventInvoker().getThisScope().

testeObjetos4.cfm

<cfdump var=”#application.getApplicationSettings()#”>

Com isso podemos acessar os métodos diretamente, mas transforma o escopo this, deixando o objeto como um saco de funções.

testeObjetos5.cfm

<cfset obj = application.getEventInvoker().getThisScope().testeObjetos(1) >
<cfdump var=”#obj#”>
<cfset obj = application.getApplicationSettings().testeObjetos(1) >
<cfdump var=”#obj#”>

struct
ID 1
struct
ID 1

Uma outra forma seria utilizar o método invoke(), que acabaria sendo o mesmo que utilizar o createobject, é preciso ter cuidado na utilização deste método, veja porque.

testeObjetos6.cfm

<cfset obj = application.getEventInvoker().invoke(‘testeObjetos’,listtoarray(‘1′))>
<cfset obj.clear_trash() >
<cfdump var=”#obj#”><br />
<cfdump var=”#application.getApplicationSettings()#”><br />
<cfdump var=”#application.getEventInvoker().getThisScope()#”><br />

component Application
function testeObjetos
Arguments:

Name Required Type Default
ID Required Any  
Return Type:  
Roles:  
Access: public
Output: Yes
struct
TESTEOBJETOS
function testeObjetos
Arguments:

Name Required Type Default
ID Required Any  
Return Type:  
Roles:  
Access: public
Output: Yes
struct
ID 1
TESTEOBJETOS
function testeObjetos
Arguments:

Name Required Type Default
ID Required Any  
Return Type:  
Roles:  
Access: public
Output: Yes

E seguindo com as surpresas, um outro achado foi na udf.

testeObjetos7.cfm

<cfset funcao = structnew() >
<cfset funcao.funcao = application.getApplicationSettings().testeObjetos >
<cfset funcao.metadata = funcao.funcao.getMetaData() >
<cfset funcao.path = funcao.funcao.getPagePath() >
<cfset funcao.SuperScope = funcao.funcao.getSuperScope() >
<cfdump var=”#funcao#”>

struct
FUNCAO
function testeObjetos
Arguments:

Name Required Type Default
ID Required Any  
Return Type:  
Roles:  
Access: public
Output: Yes
METADATA
struct
NAME testeObjetos
PARAMETERS
array
1
struct
NAME ID
REQUIRED true
PATH C:\Arquivos de programas\Apache Software Foundation\Tomcat 5.0\webapps\cfusion\testeObjetos.cfc
SUPERSCOPE
struct
SUPER
object of coldfusion.runtime.SuperScope
Methods invoke (returns java.lang.Object)
main (returns void)
put (returns java.lang.Object)
clone (returns java.lang.Object)
get (returns java.lang.Object)
size (returns int)
remove (returns java.lang.Object)
clear (returns void)
keys (returns interface java.util.Enumeration)
containsKey (returns boolean)
entrySet (returns interface java.util.Set)
isEmpty (returns boolean)
search (returns void)
bind (returns coldfusion.runtime.Variable)
bind (returns coldfusion.runtime.Variable)
putCanonicalKey (returns java.lang.Object)
cloneScope (returns void)
getBacking (returns java.util.HashMap)
replaceBacking (returns void)
getCanonicalKey (returns java.lang.Object)
bindInternal (returns coldfusion.runtime.Variable)
bindInternal (returns coldfusion.runtime.Variable)
putVariable (returns void)
hashCode (returns int)
equals (returns boolean)
toString (returns java.lang.String)
values (returns interface java.util.Collection)
containsValue (returns boolean)
keySet (returns interface java.util.Set)
putAll (returns void)
getClass (returns java.lang.Class)
wait (returns void)
wait (returns void)
wait (returns void)
notify (returns void)
notifyAll (returns void)

Sem esquecer da função GetPageContext

testeObjetos8.cfm

<cfoutput>#GetPageContext().getFusionContext().getPagePath()#</cfoutput>

C:\Arquivos de programas\Apache Software Foundation\Tomcat 5.0\webapps\cfusion\testeEscopo.cfm

E ainda uma série de informações sobre a aplicação

testeObjetos9.cfm

<!— <cfapplication loginstorage=session > —>
<cfset application.setStoreloginCredentialInSession(‘YES’) > loginstorage está em session ? <cfoutput>#application.getStoreloginCredentialInSession()#</cfoutput>

applicationname = <cfoutput>#application.getName()#</cfoutput>

tempo de vida da aplicação = <cfoutput>#application.getElapsedTime()#</cfoutput>

último acesso = <cfoutput>#application.getTimeSinceLastAccess()#</cfoutput>

intervalo máximo de inatividade permitido = <cfoutput>#application.getMaxInactiveInterval()#</cfoutput>

<cfoutput>#application.getNames().next()#</cfoutput>

a aplicação expirou? <cfoutput>#application.expired()#</cfoutput>

é o primeiro acesso da aplicação? <cfoutput>#application.isNew()#</cfoutput>

aplicação foi iniciada? <cfoutput>#application.isInited()#</cfoutput>

<!—
<cfset application.setLastAccess()>
<cfset application.SetMaxInactiveInterval(0) >
<cfset application.cleanup() >
<cfset application.setIsInited(false) >
—>

Então a curiosidade aumentou, e na sessão o que poderia ser encontrado ?

testeObjetos10.cfm

<cfoutput>#session.IsJ2eeSession()#</cfoutput> <cfoutput>#session.getAppName()#</cfoutput>

<cfoutput>#session.getNames().next()#</cfoutput>

<cfoutput>#session.getElapsedTime()#</cfoutput>

<cfoutput>#session.getTimeSinceLastAccess()#</cfoutput>

<cfoutput>#session.getMaxInactiveInterval()#</cfoutput>

<cfoutput>#session.expired()#</cfoutput>

<cfoutput>#session.isNew()#</cfoutput>

E para terminar os testes.

testeObjetos11.cfm

<!— aplicável a struct e escopos —>
<cfset form.vazio = “”>
<cfset form.clear() >
<cfset form.key1 = “valor original”>
<cfset form.key2 = “”>
<cfset form.put(“key1″,”put retorna valor anterior”) >
<cfset form.key1old = form.put(“key1″,”put 2 “) >
<cfset form.acessando = form.get(‘key1′)>
<cfset form.Empty = form.isEmpty()>
<cfset form.struct = form.clone()>
<cfset form.remove(‘key2′) >
<cfset form.numItens = form.size()+1>
<cfdump var=”#form#”><br /> <!— aplicável apenas a array —>
<cfset array = listtoarray(‘valor será eliminado’) >
<cfset array.clear() >
<cfset arrayappend(array , “size = “&array.size() ) >
<cfset arrayappend(array , “getDimension = “&array.getDimension() ) >
<cfset arrayappend(array , “dimensionOf = “&array.dimensionOf(array) ) >
<cfset arrayappend(array , “isEmpty = “&array.isEmpty() ) >
<cfset arrayappend(array , “4″ ) >
<cfset arrayappend(array , array.get(0) ) >
<cfset arrayappend(array , array.clone() ) >
<cfset array.remove(4) >
<cfdump var=”#array#”>

struct
ACESSANDO put 2
EMPTY NO
KEY1 put 2
KEY1OLD put retorna valor anterior
NUMITENS 6
STRUCT
struct
ACESSANDO put 2
EMPTY NO
KEY1 put 2
KEY1OLD put retorna valor anterior
array
1 size = 0
2 getDimension = 1
3 dimensionOf = 1
4 isEmpty = NO
5 size = 0
6
array
1 size = 0
2 getDimension = 1
3 dimensionOf = 1
4 isEmpty = NO
5 4
6 size = 0

Conclusão

Os testes valeram apenas pelas agradáveis surpresas, porque o código que tornaria mais rápida a criação de objetos do tipo componente, é o que utilizei como resposta no mês de passado, com os arquivos Application.cfc, testeObjetos.cfc e testeObjeto.cfm. Apesar desta forma não estar presente em nenhuma framework, e muito menos documentada, assim como os métodos que demonstrei.


Pedro Claudio – pcsilva@mxstudio.com.br
visite o fórum MXStudio ColdFusion  

FormatCF(new Array(\’testeObjetos.cfc\’,\’Application.cfc\’,\’testeObjetos.cfm\’,\’Application.cfc2\’,\’testeObjetos2.cfm\’,\’testeObjetos3.cfm\’,\’testeObjetos4.cfm\’,\’testeObjetos5.cfm\’,\’testeObjetos6.cfm\’,\’testeObjetos7.cfm\’,\’testeObjetos8.cfm\’,\’testeObjetos9.cfm\’,\’testeObjetos10.cfm\’,\’testeObjetos11.cfm\’));


Deixe um Comentario

You can use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="">

Pedro Claudio

Últimos Artigos do Autor