D2010 e Data Snap - Por Bruno Lichot
Sobre o D2010:
Vale apena ficar antenado, Bruno Lichot esta publicando uma série de artigos sobre DataSnap 2010 na revista Acitve Delphi.
O exemplo publicado nesta edição pode ser baixado aqui!
Estamos estudando e o resultado disso postamos aqui. Sinceramente desejamos que o conteúdo aqui semeado possa ser útil para muitas pessoas.
Seja bem-vindo e fique à vontade para contribuir da forma que puder e quiser.
Bola pra frente ... :)
Sobre o D2010:
Vale apena ficar antenado, Bruno Lichot esta publicando uma série de artigos sobre DataSnap 2010 na revista Acitve Delphi.
O exemplo publicado nesta edição pode ser baixado aqui!
unit IWUnit1;
{PUBDIST}
interface
uses
IWAppForm, IWApplication, IWTypes, IWCompButton, Classes, Controls,
IWControl, IWCompEdit, IWCompLabel;
type
TformMain = class(TIWAppForm)
IWEdit1: TIWEdit;
IWButton1: TIWButton;
IWLabel1: TIWLabel;
EdtURLZN: TIWEdit;
IWLabel2: TIWLabel;
procedure IWAppFormCreate(Sender: TObject);
procedure IWButton1Click(Sender: TObject);
public
end;
implementation
{$R *.dfm}
uses
ServerController, SysUtils, IWForm;
procedure TformMain.IWAppFormCreate(Sender: TObject);
begin
IWEdit1.Text := '';
IWButton1.Caption := 'Enviar - ZN';
IWLabel1.Caption := 'Digite o valor que será enviado';
IWLabel2.Caption := 'Digite a URL da aplicação ISAPI que será chamada' +
'e exibirá o valor digitado acima.';
EdtURLZN.Text := '';
end;
procedure TformMain.IWButton1Click(Sender: TObject);
const
AJSComando = 'window.open("%s?estacaoZnValor=%s")';
begin
AddToInitProc(Format(AJSComando, [EdtURLZN.Text, IWEdit1.Text]));
end;
end.
library AppEstacaoZNSubmit;
uses
IWInitISAPI,
ServerController in 'ServerController.pas' {IWServerController: TIWServerControllerBase},
IWUnit1 in 'IWUnit1.pas' {formMain: TIWForm1};
{$R *.RES}
begin
IWRun(TFormMain, TIWServerController);
end.
unit IWUnit1;
{PUBDIST}
interface
uses
IWAppForm, IWApplication, IWTypes, Classes, Controls, IWControl,
IWCompLabel, IWCompListbox, IWCompMemo;
type
TformMain = class(TIWAppForm)
IWLabel1: TIWLabel;
procedure IWAppFormRender(Sender: TObject);
public
end;
implementation
{$R *.dfm}
uses
ServerController, IWForm, SysUtils;
procedure TformMain.IWAppFormRender(Sender: TObject);
const
ZnMsg = 'www.estacaozn.blogspot.com O Valor recebido de "%s" é: %s';
begin
IWLabel1.Caption := Format(ZnMsg,
[WebApplication.Request.RemoteAddr,
WebApplication.Request.QueryFields.Values['estacaoZnValor']]);
IWLabel1.Font.Size := 20;
end;
library AppRequestQueryFieldsEstacaoZN;
uses
IWInitISAPI,
ServerController in 'ServerController.pas' {IWServerController: TIWServerControllerBase},
IWUnit1 in 'IWUnit1.pas' {formMain: TIWForm1};
{$R *.RES}
begin
IWRun(TFormMain, TIWServerController);
end.
function Initialize() {
InitSubmitter();
StaticInit();
if (document.body.leftMargin < 0 && document.body.topMargin < 0) {
document.body.leftMargin = 0;
document.body.topMargin = 0;
}
InitRects(614, 451);
InitIWCLObjects();
window.open("http://localhost/requesestacaozn/?estacaoZnValor=Landjah Estação ZN")
}
Olá pessoal!
Dando manutenção em um sistema java web com interface jsp precisei usar uma treeview para apresentar as categorias de produtos para o usuário. Vou relatar aqui a experiência.
As categorias estão modeladas no banco em uma tabela com autorelacionamento.
No oracle para consultar uma table com autorelacionamento podemos utilizar a seguinte query:
select id, LEVEL, SYS_CONNECT_BY_PATH(nome, '@') as caminho
from categoria CONNECT BY parent_id = PRIOR id START WITH id = categoria_inicial
A categoria_inicial é a primeira categoria de uma árvore, nesse sistemas existem várias árvores de categorias.
O resultado fica assim para a categoria_inicial igual a 30:
id level caminho
30 1 @Material de escritório
31 2 @Material de escritório@Informática
34 3 @Material de escritório@Informática@Tinta
55 4 @Material de escritório@Informática@Tinta@Tinta Impressoras
60 3 @Material de escritório@Informática@Armazenamento
63 4 @Material de escritório@Informática@Armazenamento@DAT/DLT/DVD/DDS
64 4 @Material de escritório@Informática@Armazenamento@Disquetes
92 3 @Material de escritório@Informática@Teste
93 4 @Material de escritório@Informática@Teste@Teste1
113 4 @Material de escritório@Informática@Teste@Teste2
120 4 @Material de escritório@Informática@Teste@Test3
Ai no java criei uma classe para representar a estrutura da categoria, ficou assim:
public class CategoriaTreeView {
public String id;
public int level;
public String path;
public CategoriaTreeView(String id, int level, String path){
this.id = id;
this.level = level;
this.path = path;
}
}
Como essa classe vai ser utilizada somente como uma estrutura de dados para representar o dado que será exibido na tela ela não tem gets e sets. Nem toda classe java precisa ter gets e sets. Gets e sets aqui são desnecessários e não acresentam nada. Acredite. Mas isso é assunto para outro post.
Também tenho um DAO que acessa o banco e entrega um List com os objetos CategoriaTreeView.
Antes disso fiz uma pesquisa na internet sobre como criar uma treeview no jsp (ou html) e encontrei o jQuery plugin: Treeview que transforma uma lista não ordenada do html <ul> em uma árvore.
Agora o problema é transformar a minha coleção de CategoriaTreeView em uma lista não ordenada com <ul> e <li>. Para isso eu criei a seguinte função recursiva que retorna uma String que será utilizada dentro do html:
private String processa(int atual, List<CategoriaTreeView> lista){
if(lista == null) return "";
String out = "";
if(lista.size() == 0) {
if(atual > 0){
out += "</li>\n";
out += "</ul>\n";
out += processa(atual - 1, lista);
}
}else if(lista.size()>0){
CategoriaTreeView item = lista.remove(0);
if(item.level == atual){
out += "</li>\n";
out += "<li><span>" + subString(item.level, item.path) + "</span>\n";
out += processa(item.level, lista);
}else if(item.level > atual){
out += "<ul>\n";
out += "<li><span>" + subString(item.level, item.path) + "</span>\n";
out += processa(item.level, lista);
}else if(item.level < atual){
out += "</li>\n";
out += "</ul>\n";
// adiciono o cara de volta na lista pois ainda não foi processado. estou voltando um nivel na árvore.
lista.add(0, item);
out += processa(atual - 1, lista);
}
}
return out;
}
Também temos a função para retornar a categoria de dentro do caminho:
private String subString(int i, String s){
String[] ss = s.split("@");
return ss[i];
}
Dentro do meu servlet eu tenho o seguinte código:
ArrayList categorias = dao.categorias(categoria_inicial);
String treeView = processa(0, categorias);
treeView = treeView.replaceFirst("<ul>", "<ul id=\"browser\">");
request.setAttribute("treeView", treeView);
Para exibir a treeview no jsp eu utilizei o exemplo simple.html que vem no download do jQuery plugin: Treeview. A única mudança foi que eu fiz o download do jquery ao invés de usar o link direto do ajax.googleapis.com.
Adicionei o seguinte ao jsp:
<link rel="stylesheet" href="../jquery.treeview.css" />
<link rel="stylesheet" href="../red-treeview.css" />
<link rel="stylesheet" href="screen.css" />
<script type="text/javascript" src="jquery-1.3.2.min.js"></script>
<script src="../lib/jquery.cookie.js" type="text/javascript"></script>
<script src="../jquery.treeview.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function(){
$("#browser").treeview({control: "#treecontrol", animated:"normal", persist: "cookie"});
});
</script>
<%
String s = (String)request.getAttribute("treeView");
if(s != null && !s.trim().equals("")){
%>
<tr>
<td>
<br>
<div id="treecontrol">
<a title="Collapse the entire tree below" href="#">Fechar Tudo</a>
<a title="Expand the entire tree below" href="#">Abrir Tudo</a>
</div>
</td>
</tr>
<tr>
<td>
<br>
<div><%= s %></div>
</td>
</tr>
<%
}
%>
O resultado fica parecido com esse demo que está no site.
Abraços, Rodrigo Alencar.
Ver este post em Portugûes
Here I'm gonna show another technique to work with cursors in PL/SQL. I had to do something at work where it was very useful: cursor that take arguments.
The biggest advantages of parametrized queries is that the server doesn't have to pass through the parse and plan phases ever again (after the first time, of course) and the compile-time checking for syntax errors (when we use string queries we only know any syntax errors in runtime).
That said let's go to examples:
cursor ProductCursor(pname in varchar2) is
select *
from product
where name like pname;
Nice, isn't it? It's like a procedure in terms of syntax. And opening the cursor is like this:
open ProductCursor('A%');
It'll open the cursor with all the products which name starts with 'A'.
We can create a rowtype based var from this cursor:
prod ProductCursor%rowtype;
Now I'm gonna join it all in a script:
declare
-- Cursor
cursor ProductCursor(pname in varchar2) is
select *
from product
where name like pname;
-- Simple loop
prod ProductCursor%rowtype;
-- bulk collect loop
type Tprods is table of ProductCursor%rowtype;
prods Tprods;
i integer;
begin
-- simple loop
open ProductCursor('A%');
loop
fetch ProductCursor into prod;
exit when ProductCursor%notfound;
DBMS_OUTPUT.put_line(prod.nome);
-- other commands
end loop;
close ProductCursor;
-- bulk collect loop
open ProductCursor('A%');
fetch ProductCursor bulk collect into prods;
for i in prods.first .. prods.last loop
DBMS_OUTPUT.put_line(prods(i).nome);
-- another commands using prods(i)
end loop;
close ProductCursor;
end;
Cool, isn't it? See you next time.
View this post in English
Aqui vou mostrar outra técnica para trabalhar com cursores em PL/SQL. Eu tive que fazer um trabalho recentemente onde isso foi muito útil: Cursores que aceitam argumentos.
As maiores vantagem de usar queries parametrizadas no banco de dados é que o servidor não precisa fazer o parse e traçar um plano de execução (ele só faz isso na primeira vez que a query é executada) e ela fica certa em tempo de compilação (ao contrário das queries em string que nós só sabemos se há um erro de sintaxe em tempo de execução).
Dito isso vamos a um exemplo:
cursor ProdutoCursor(pnome in varchar2) is
select *
from produto
where nome like pnome;
Legal, não? A sintaxe fica muito parecida com uma procedure. E o método de abrir o cursor também é legal:
open ProdutoCursor('A%');
Aqui vai abrir o cursor trazendo todos os produtos onde o nome começa com a letra 'A'.
Podemos ainda criar um rowtype a partir deste cursor:
prod ProdutoCursor%rowtype;
Agora vou criar um script para juntar tudo:
declare
-- Cursor
cursor ProdutoCursor(pnome in varchar2) is
select *
from produto
where nome like pnome;
-- Para loop simples
prod ProdutoCursor%rowtype;
-- Para loop com bulk collect
type Tprods is table of ProdutoCursor%rowtype;
prods Tprods;
i integer;
begin
-- Loop simples
open ProdutoCursor('A%');
loop
fetch ProdutoCursor into prod;
exit when ProdutoCursor%notfound;
-- comandos a serem executados com o registro prod
DBMS_OUTPUT.put_line(prod.nome);
end loop;
close ProdutoCursor;
-- Loop com bulk collect
open ProdutoCursor('A%');
fetch ProdutoCursor bulk collect into prods;
for i in prods.first .. prods.last loop
-- comandos a serem executaos com o registro prods(i)
DBMS_OUTPUT.put_line(prods(i).nome);
end loop;
close ProdutoCursor;
end;
Muito legal, né? Até a próxima.
Ver este post em Portugûes
Hello. In this post I'll show something very nice about .Net: Generics.
First, I'll show a simple struct in order to explain the feature:
struct Person {
public string Name;
public string Address;
public string Zip;
}
struct Pair<TClass1, TClass2>
where TClass1 : class
where TClass2 : class {
public TClass1 obj1;
public TClass2 obj2;
}
class Customer {
public int ID;
public string Name;
public override string ToString() {
return string.Format("Customer ID = {0}, Name = {1}", ID, Name);
}
}
class Product {
public int ID;
public string Name;
public override string ToString() {
return string.Format("Product ID = {0}, Name = {1}", ID, Name);
}
}
struct Pair<TClass1, TClass2>
where TClass1 : class
where TClass2 : class {
public TClass1 obj1;
public TClass2 obj2;
}
class Program {
static void Main(string[] args) {
var c = new Customer { ID = 1, Name = "Felipe" };
var p = new Product { ID = 1, Name = "Caneta BIC" };
var pair = new Pair<Customer, Product>() { obj1 = c, obj2 = p };
Console.WriteLine(pair.obj1.ToString());
Console.WriteLine(pair.obj2.ToString());
}
}
View this post in English
Olá a todos. Neste post vou mostrar algo muito legal a respeito da .Net: Generics.
Primeiro vou preparar o terreno para explicar o recurso: Vamos ter como exemplo uma estrutura básica:
struct Pessoa {
public string Nome;
public string Endereco;
public string CEP;
}
struct Par<TClasse1, TClasse2>
where TClasse1 : class
where TClasse2 : class {
public TClasse1 obj1;
public TClasse2 obj2;
}
class Cliente {
public int ID;
public string Nome;
public override string ToString() {
return string.Format("Cliente ID = {0}, Nome = {1}", ID, Nome);
}
}
class Produto {
public int ID;
public string Nome;
public override string ToString() {
return string.Format("Produto ID = {0}, Nome = {1}", ID, Nome);
}
}
struct Par<TClasse1, TClasse2>
where TClasse1 : class
where TClasse2 : class {
public TClasse1 obj1;
public TClasse2 obj2;
}
class Program {
static void Main(string[] args) {
var c = new Cliente { ID = 1, Nome = "Felipe" };
var p = new Produto { ID = 1, Nome = "Caneta BIC" };
var par = new Par<Cliente, Produto>() { obj1 = c, obj2 = p };
Console.WriteLine(par.obj1.ToString());
Console.WriteLine(par.obj2.ToString());
}
}
Como o título já diz: eu já. A microsoft colocou o Internet Explorer 8 como atualização crítica para o Windows XP e cá estamos nós usuários deste maravilhoso sistema operacional atualizando.
O navegador é muito bonitinho: A interface é boa, tem depurador de Javascript (já dava para fazer isso anteriormente, mas agora está incorporado no navegador), etc. Mas um problema assola alguns usuários (como minha digníssima que ainda usa muito o Internet Explorer): o teclado.
Alguns usuários têm notado que no IE 8 o teclado não responde legal. Na minhma máquina acontece isso Neste link [forum.clubedohardware.com.br] há uma discussão do problema e possíveis causas e soluções.
Alguns males vêm para bem: Agora minha patroa já está começando a usar o querido por todos Firefox para navegar, graças as minhas insistentes investidas. Ha ha. Aproveitei essa hora para trazê-la ao lado da luz.
Abraços e até a próxima!
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Buttons;
type
TForm1 = class(TForm)
BitBtn1: TBitBtn;
procedure BitBtn1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses jclStrings, Math;
procedure TForm1.BitBtn1Click(Sender: TObject);
var
ZnDt, ZnNum: String;
ADay, AMonth, AYear: Word;
begin
DecodeDate(Date, AYear, AMonth, ADay);
ZnDt := Format('%s%s%s', [ StrPadLeft(IntToStr(ADay), 2, '0'),
StrPadLeft(IntToStr(AMonth), 2, '0'), IntToStr(AYear)]);
Self.Canvas.TextOut(12, 32, ZnDt);
Randomize;
ZnNum := IntToStr(RandomRange(0, 50000));
ZnNum := StrPadRight(ZnNum, 6, 'X');
Self.Canvas.TextOut(12, 52, ZnNum);
end;
ZnDt := Format('%s%s%s', [ StrPadLeft(IntToStr(ADay), 2, '0'),
StrPadLeft(IntToStr(AMonth), 2, '0'), IntToStr(AYear)]);
ZnDt := Format('%.2d%.2d%.4d', [ADay, AMonth, AYear]);
Você é aquele cara que, pra controlar as versões do seu sistema, zipa os fontes e nomeia com o número da versão? Ou paga um software caríssimo de controle de versão? Ou toma uma coça pra instalar um controlador gratuito? SEUS PROBLEMAS ACABARAM!!!
Apresento-lhes os dois softwares que vão resolver todos os seus problemas: VisualSVN + TortoiseSVN.
O primeiro é um servidor Windows de Subversion, um controlador de versões gratuito muito bom. Muito simples de instalar, esquema Windows: next, next, next, finish.
Muito fácil também de manusear. Basta criar os repositórios e os usuários que acessam esses repositórios.
Então aqui vai o link do VisualSVN: http://www.visualsvn.com/server/
O segundo é um cliente de Subversion muito, muito bom mesmo. Integra-se ao Windows Explorer e é super simples de usar também. Basicamente, você deve criar uma pasta que apontará para o repositório do VisualSVN. Depois do TortoiseSVN instalado, quando você clicar com o botão direito sobre a pasta pelo Windows Explorer, vai aparecer uma opção chamada "SVN Checkout...".
Colocou arquivos/diretórios novos dentro da pasta, "Add". Quer subir os fontes? "Commit". Quer atualizar seus fontes? "Update".
No próximo post sobre o assunto, eu vou dar uma passada mais detalhada sobre esta ferramenta.
Chega de blá, blá, blá. Lá vai o link: http://tortoisesvn.net/
Então é isso. Abraço a todos e até o próximo post!