Thursday, November 27, 2008

Script Python para consumir Web Services em .Net

Tive um desafio a poucos dias. Que foi consumir Web Services feitos em .Net a partir de um servidor Solaris 10 via processo.

De todas as soluções possíveis que estive a ver, a melhor foi usar Python.

Encontrei este exemplo:

http://users.skynet.be/pascalbotte/rcx-ws-doc/postxmlpython.htm

Assim fiz o WebServiceGenericClientNet.py:

#!/usr/bin/python

# by eduveks

import sys, httplib, array

try:
    host = ""
    url = ""
    namespace = ""
    header = ""
    method = ""
    params = {}

    for arg in sys.argv[1:]:
        if host == "" and arg.find("host=") == 0:
            host = arg[len("host="):]
        elif url  == "" and arg.find("url=") == 0:
            url  = arg[len("url="):]
        elif namespace == "" and arg.find("namespace=") == 0:
            namespace = arg[len("namespace="):]
        elif header == "" and arg.find("header=") == 0:
            header = arg[len("header="):]
        elif method == "" and arg.find("method=") == 0:
            method = arg[len("method="):]
        elif arg.find("param_") == 0:
            params[arg[len("param_"):arg.find("=")]] = arg[arg.find("=") + 1:]

    SOAP_Request = ""
    SOAP_Request += "<soap:Envelope"
    SOAP_Request += " soap:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\""
    SOAP_Request += " xmlns:xsi=\"http://www.w3.org/1999/XMLSchema-instance\""
    SOAP_Request += " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""
    SOAP_Request += " xmlns:xsd=\"http://www.w3.org/1999/XMLSchema\">"
    if header != "":
        SOAP_Request += "<soap:Header>"
        SOAP_Request += header
        SOAP_Request += "</soap:Header>"
    SOAP_Request += "<soap:Body>"
    SOAP_Request += "<"+ method +" xmlns=\""+ namespace +"\">"
    for param in params.keys():
        SOAP_Request += "<"+ param +">"+ params[param] +"</"+ param +">"
    SOAP_Request += "</"+ method +">"
    SOAP_Request += "</soap:Body>"
    SOAP_Request += "</soap:Envelope>"

    http = httplib.HTTP(host)
    http.putrequest("POST", url)
    http.putheader("Host", host)
    http.putheader("User-Agent", "Python")
    http.putheader("Content-type", "text/xml; charset=\"UTF-8\"")
    http.putheader("Content-length", "%d" % len(SOAP_Request))
    http.putheader("SOAPAction", "\""+ namespace + method +"\"")
    http.endheaders()
    http.send(SOAP_Request)

    http_response_statuscode, http_response_statusmessage, http_response_header = http.getreply()
    SOAP_Response = http.getfile().read()
    if http_response_statuscode == 200 and http_response_statusmessage == "OK":
        print SOAP_Response[SOAP_Response.find("<"+ method +"Result>") + len("<"+ method +"Result>"):SOAP_Response.find("</"+ method +"Result>")]
    else:
        print "### ERROR ###############"
        if SOAP_Response.find("<faultstring>") > -1:
            print SOAP_Response[SOAP_Response.find("<faultstring>")  + len("<faultstring>"):SOAP_Response.find("</faultstring>")]
        print "Response: ", http_response_statuscode, http_response_statusmessage
        print http_response_header
        print SOAP_Response

except:
    print "### ERROR ###############"
    for err in sys.exc_info():
        print err


Para executar o script basta dar permissões de execução e executar:

chmod +x WebServiceGenericClientNet.py
./WebServiceGenericClientNet.py host=localhost url=/HelloWorld.asmx namespace=http://tempuri.org/ method=HelloWorld param_strSay=HelloWorld


O output é:

HelloWorld


Os parâmetros do WebServiceGenericClientNet.py são:

host: Endereço do servidor
url: Endereço do web service
namespace: Namespace do web service, que pode ser encontrado vendo o WSDL, http://localhost/HelloWorld.asmx?WSDL
method: Método do web service a ser chamado
param_*NOME_DO_PARAMETRO*: Caso o método precise de parâmetros, podem ser definidos assim, atenção a ordem.

Além de usar este script no Solaris, também acabei por usar este script para chamar web services apartir do .Net/C#, pois são web services que serão atualizados constantemente, com novos métodos e talz, e em vez de ficar atualizando o WSDL, basta chamar diretamente com o script a queima-roupa, e a configuração da chamada dos web services pode ser feita a partir de configurações em base de dados. Para fazer isto no .Net/C# foi só lançar um processo assim:

System.Diagnostics.Process process = new System.Diagnostics.Process();
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.FileName = "C:\Python26\python.exe";
process.StartInfo.Arguments = "WebServiceGenericClientNet.py host=localhost url=/HelloWorld.asmx namespace=http://tempuri.org/ method=HelloWorld param_strSay=HelloWorld";
process.StartInfo.WorkingDirectory = "C:\Python26\";
process.Start();
string output = process.StandardOutput.ReadToEnd();

O script suporta a configuração do header, passando o argumento header=... para o script.

Para explorar e ver fácilmente os SOAPs enviados e recebidos na chamada de um web service, existe o WebServiceStudio:

Monday, September 15, 2008

Nvidia vs Ubuntu

O driver da Nvidia que vem por padrão no Ubuntu tem alguns bugs, como este:

http://www.nvnews.net/vbulletin/showthread.php?t=106790

Aqui estão os screenshots do bug:

http://home.arcor.de/cziepke/ut2004/



Para instalar o driver que resolve o problema, o NVIDIA-Linux-x86-177.13-pkg1.run, não é tão simples assim, eu pensava que era...

Baixei aqui o driver:

http://www.nvnews.net/vbulletin/showthread.php?t=118602

Consegui instalar, mas o Xorg ficou todo estragado, fiquei com a resoluão de 800x600 e o driver vesa, então procurei e encontrei a solução num forum francês:

http://forum.ubuntu-fr.org/viewtopic.php?id=249234

O que fiz então foi o seguinte:

Fiz logout, e mudei para o terminal 1 (ctrl + alt + F1), fiz o login, e matei o GDM:

# sudo killall gdm

Feito isto o Xorg deverá esta morto, verifique no terminal 7 (ctrl + alt + F7), se esta tudo preto.

Agora remova tudo que esta instalado da nvidia:

$ sudo apt-get remove --purge nvidia*

Instalar os headers do kernel e o xorg-dev:

$ sudo apt-get install build-essential linux-headers-`uname -r` xserver-xorg-dev

Faça um backup da configuração do Xorg:

$ sudo cp /etc/X11/xorg.conf /etc/X11/xorg.conf.good.backup

Agora é só instalar o driver, diga Yes para tudo:

$ sudo sh NVIDIA-Linux-x86-177.13-pkg1.run


Se durante a instalação der erro, dizendo que não consegue criar alguns arquivos, veja o caminho, provavelmente como aconteceu comigo será preciso criar a pasta:

$ sudo mkdir /usr/lib/nvidia

Depois é só voltar a executar a instalação e diga Yes para tudo mais uma vez:

$ sudo sh NVIDIA-Linux-x86-177.13-pkg1.run

Reiniciar o computador, e pronto, os gráficos deverão estar muito melhores, e o UT2004 sem bugs.

Guarde o arquivo de instalação, pois sempre que for instalado um novo kernel será preciso reinstalar o driver.

Friday, September 5, 2008

Unreal Tournament 2004 - Linux Dedicated Server

Nossa como é bom voltar a jogar UT2004 :P

Downloads

Servidor:
$ wget http://downloads.unrealadmin.org/UT2004/Server/DedicatedServer3323.zip
BonusPack:
$ wget http://downloads.unrealadmin.org/UT2004/Server/dedicatedserver3339-bonuspack.zip
Anticheater:
$ wget http://downloads.unrealadmin.org/UT2004/AntiCheat/UTSecure2K4-111.zip

Quem for jogar, convêm ter o MegaPack instalado, para evitar que fique fazendo download:

MegaPack - 12/13/05 - 205 MB

Instalação

$ unzip DedicatedServer3323.zip
$ mv UT2004-Dedicated-3323 UT2004srv
$ unzip -o dedicatedserver3339-bonuspack.zip -d UT2004srv
$ unzip -o UTSecure2K4-111.zip -d UT2004srv
$ chmod +x UT2004srv/System/ucc*

Configuração

Não apague nenhuma linha do arquivo, apenas altere as linhas indicadas abaixo.

Editar o UT2004.ini:

$ vim UT2004srv/System/UT2004.ini

Habilitar a administração web:

[UWeb.WebServer]
bEnabled=True
ListenPort=7775

Alterar o nome do servidor:

[Engine.GameReplicationInfo]
ServerName=Nome Do Teu Servidor
ShortName=Nome Servidor

Liberar para quem não tem o jogo original poder jogar, e desabilitar a verificação de keys:

[IpDrv.MasterServerUplink]
DoUplink=False
UplinkToGamespy=False
SendStats=False
ServerBehindNAT=False
DoLANBroadcast=False
bIgnoreUTANBans=True


Executar

$ cd UT2004srv/System
$ sudo ./ucc-bin server DM-Gael?game=XGame.xDeathMatch?mutator=XGame.MutQuadJump?AdminName=admin?AdminPassword=XXXXX?GamePassword=XXXXX ini=UT2004.ini log=UT2004.log -nohomedir


Os XXXXX são as senhas, a senha para entrar no servidor é a ?GamePassword=XXXXX, substitua os XXXXX por uma senha mais intuitiva do seu entender. Os parametros ?Admin* são os dados para entrar na administração web pelo endereço http://servidor:7775.

Se obtiver este erro:
./ucc-bin: error while loading shared libraries: libstdc++.so.5: cannot open shared object file: No such file or directory

Para resolver este erro é preciso fazer um link simbólico para a versão 5.* da libstdc++, que fica na pasta /usr/lib/libstdc++*, no meu caso fiz assim:

$ sudo ln -s /usr/lib/libstdc++.so.5.0.7 /usr/lib/libstdc++.so.5

Agora é só executar de novo!

Jogar

Para jogar no servidor, é só ir na lista de servidores online dentro do jogo e clicar com o botão direito e no menu que aparece ir em "Open Ip", e colocar o endereço do servidor!

Quem não tem o jogo original pode jogar no teu servidor usando este crack:

Unreal Tournament 2004 v3369 PRIVATE WINDOWS SERVER PATCH

Detalhes da Configuração

Na linha de execução tem os parâmetros:

DM-Gael?game=XGame.xDeathMatch?mutator=XGame.MutQuadJump

DM-Geal se refere ao Mapa, você pode colocar o nome de outro mapa, basta ver os mapas disponíveis em UT2004srv/Maps/*.

O game= XGame.xDeathMatch é o tipo de jogo, todos os tipos de jogos:

Assault: AS-MotherShip?game=UT2k4Assault.ASGameInfo
CTF: CTF-FaceClassic?game=XGame.xCTFGame
Bombing Run: BR-Serenity?game=XGame.xBombingRun
DoubleDomination: DOM-SunTemple?game=xGame.xDoubleDom
DeahtMatch: DM-Rankin?game=XGame.xDeathMatch
Invasion: DM-Antalus?game=SkaarjPack.Invasion
LastManStanding: DM-Morpheus3?game=BonusPack.xLastManStandingGame
Mutant: DM-Deck17?game=BonusPack.xMutantGame
Onslaught: ONS-Torlan?game=Onslaught.ONSOnslaughtGame
TeamDeathMatch: DM-Rankin?game=XGame.xTeamGame

O mutator=XGame.MutQuadJump é o mutator, pode remover isto se não quiser nenhum mutator, todos os tipos de mutators:

Arena: XWeapons.MutArena
Beserk: UnrealGame.MutBerserk
Big Head: UnrealGame.MutBigHead
Delayed Spawn: UnrealGame.MutDelayedSpawn
Float-Away Corpses: XGame.MutHeliumCorpses
InstaGib: XGame.MutInstaGib
Zoom InstaGib: XGame.MutZoomInstaGib
LowGravity: UnrealGame.MutLowGrav
No Adrenaline: XGame.MutNoAdrenaline
No Super Weapons: XWeapons.MutNoSuperWeapon
Quad Jump: XGame.MutQuadJump
AutoHealing: XGame.MutRegen
Slow Motion Deaths: XGame.MutSlomoDeath
Species Specific Stats: XGame.MutSpeciesStats
UDamage Reward: XGame.MutUDamageReward
Vampire :XGame.MutVampire
UTV2004S (UTV2004 in SeeAll mode): UTV2004s.utvMutator
UT2k3 Style Weapon Throwing/Boosting: XGame.MutFastWeapSwitch
UTClassic: UTClassic.MutUTClassic
Lightning Gun 2 Sniper Rifle: UTClassic.MutUseSniper
Sniper Rifle 2 Lightning Gun: UTClassic.MutUseLightning
Camouflage Combo (RRRR): Bonuspack.MutCrateCombo
Pint-sized combo (LLLL): Bonuspack.MutPintSizeCombo
BigWheels: Onslaught.MutBigWheels
Light Weight Vehicles: Onslaught.MutLightweightVehicles
Onslaught Weapons: Onslaught.MutOnslaughtWeapons
Jumping Vehicles: Onslaught.MutWheeledVehicleStunts
Vehicle Arena: OnslaughtFull.MutVehicleArena

Referência

DragonBe - Unreal Tournament 2004 Dedicated Server

Gentoo - UT2004 Dedicated Server Installation

LINUX; UT2004-bin: error while loading shared libraries: libstdc++.so.5

Compre o jogo orignal!

Este jogo esta barato e vale a pena ter o original.

É um excelente jogo, e é dos jogos que mais se preocupa em ter suporte nativo ao Linux, por isso também, não deixe de colaborar.

Monday, September 1, 2008

Nginx

Conheci o Nginx no forum do GUJ.com.br, depois com os resultados que o Fabio Kung postou no blog da Caelum, fiquei convencido que o Nginx seria a melhor solução para os meus problemas.

E depois que conheci o Nginx já não quero mais nada, estou extremamente satisfeito, excelente robustez.

Para instalar o Nginx fiz um artigo no VivaOLinux.com.br que ensina como fazer a instalação e os links do site e da documentação.

Consegui fazer uma configuração simples para configurar multiplos domínios virtuais, segue a configuração:


worker_processes 5;
error_log logs/error.log;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
gzip on;
gzip_min_length 1100;
gzip_buffers 16 8k;
gzip_types text/plain text/html text/xml text/xhtml text/css text/js application/x-javascript application/json;
error_page 500 502 503 504 /50x.html;
server {
listen 80;
server_name _;
root /home/websites/$host;
location / {
index index.html index.htm index.jsp;
}
location ~ \.jsp$ {
proxy_pass http://localhost:8080;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
}
}
}


Repare nesta linha:


root /home/websites/$host;


Ai em /home/websites/* eu tenho os atalhos para as pastas reais dos domínios.

Então por exemplo para acrescentar um novo domínio dominio.com:

ln -s /home/dominio.com /home/websites/dominio.com
ln -s /home/dominio.com /home/websites/www.dominio.com


Assim para configurar um novo domínio no Nginx é só adicionar um novo atalho no /home/websites neste caso.

Ativar compressão gzip:


gzip on;
gzip_min_length 1100;
gzip_buffers 16 8k;
gzip_types text/plain text/html text/xml text/xhtml text/css text/js application/x-javascript application/json;


Para o Nginx encaminhar os JSPs para o Jetty:


location ~ \.jsp$
proxy_pass http://localhost:8080;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
}

Thursday, August 21, 2008

Movie Clip Fit

Um problema básico hoje em dia para fazer resize em flash é posicionar os movieclips corretamente, existe este projeto que facilita a vida para fazer resize do flash dentro do browser:

http://swffit.millermedeiros.com/

Baseado neste projeto fiz este objeto que ajuda a ajusta as posições dos movieclips dentro do flash de acordo com o resize:


var fit = {
baseStageWidth: Stage.width,
baseStageHeight: Stage.height,
oldStageWidth: Stage.width,
oldStageHeight: Stage.height,
xLeft: 0,
xRight: 1,
yTop: 0,
yBottom: 1,
xMovies: new Array(),
xs: new Array(),
xAligns: new Array(),
x: function (mv:MovieClip, align:Number, x:Number) {
if (align == null) {
align = this.xLeft;
}
this.xMovies.push(mv);
if (x == null) {
if (align == this.xLeft) {
x = mv._x;
} else if (align == this.xRight) {
x = mv._x + mv._width;
}
}
this.xs.push(x);
this.xAligns.push(align);
},
yMovies: new Array(),
ys: new Array(),
yAligns: new Array(),
y: function (mv:MovieClip, align:Number, y:Number) {
if (align == null) {
align = this.yTop;
}
this.yMovies.push(mv);
if (y == null) {
if (align == this.yTop) {
y = mv._y;
} else if (align == this.yBottom) {
y = mv._y + mv._height;
}
}
this.ys.push(y);
this.yAligns.push(align);
},
widthMovies: new Array(),
widths: new Array(),
width: function (mv:MovieClip) {
this.widthMovies.push(mv);
this.widths.push(mv._width);
},
heightMovies: new Array(),
heights: new Array(),
height: function (mv:MovieClip) {
this.heightMovies.push(mv);
this.heights.push(mv._height);
},
proportionalMovies: new Array(),
proportionalWidths: new Array(),
proportionalHeights: new Array(),
proportional: function (mv:MovieClip) {
this.proportionalMovies.push(mv);
this.proportionalWidths.push(mv._width);
this.proportionalHeights.push(mv._height);
},
fix: function () {
for (var k:Number = 0; k < this.widthMovies.length; k++) {
this.widths[k] = (Stage.width * this.widths[k]) / this.oldStageWidth;
this.xMovies[k]._width = this.widths[k];
}
for (var k:Number = 0; k < this.heightMovies.length; k++) {
this.heights[k] = (Stage.height * this.heights[k]) / this.oldStageHeight;
this.heightMovies[k]._height = this.heights[k];
}
for (var k:Number = 0; k < this.proportionalMovies.length; k++) {
var ratioW = Stage.width / this.proportionalWidths[k];
var ratioH = Stage.height / this.proportionalHeights[k];
if (ratioW < ratioH ) {
this.proportionalWidths[k] = this.proportionalWidths[k] * ratioW;
this.proportionalHeights[k] = this.proportionalHeights[k] * ratioW;
} else {
this.proportionalWidths[k] = this.proportionalWidths[k] * ratioH;
this.proportionalHeights[k] = this.proportionalHeights[k] * ratioH;
}
this.proportionalMovies[k]._width = this.proportionalWidths[k];
this.proportionalMovies[k]._height = this.proportionalHeights[k];
}
for (var k:Number = 0; k < this.xMovies.length; k++) {
this.xs[k] = (Stage.width * this.xs[k]) / this.oldStageWidth;
if (Stage.align.indexOf("L") > -1) {
this.xMovies[k]._x = this.xs[k];
} else {
this.xMovies[k]._x = ((this.baseStageWidth - Stage.width) / 2) + this.xs[k];
}
if (this.xAligns[k] == this.xRight) {
this.xMovies[k]._x -= this.xMovies[k]._width;
}
}
for (var k:Number = 0; k < this.yMovies.length; k++) {
this.ys[k] = (Stage.height * this.ys[k]) / this.oldStageHeight;
if (Stage.align.indexOf("T") > -1) {
this.yMovies[k]._y = this.ys[k];
} else {
this.yMovies[k]._y = ((this.baseStageHeight - Stage.height) / 2) + this.ys[k];
}
if (this.yAligns[k] == this.yBottom) {
this.yMovies[k]._y -= this.yMovies[k]._height;
}
}
this.oldStageWidth = Stage.width;
this.oldStageHeight = Stage.height;
}
};


Se quiser que um movieclip fique sempre na posição x e y de acordo com o resize, basta passar a referência do movieclip para as funções x e y:


fit.x(MovieClip);
fit.y(MovieClip);


Ou então se precisar que um movieclip tenha o tamanho dinâmico de acordo com o resize, basta passar a referência do movieclip para as funções width e height:


fit.width(MovieClip);
fit.height(MovieClip);


Para fazer resize em porporção, ideal para imagens, use:


fit.proportional(MovieClip);


E para fazer alinhamentos, por exemplo alinhar um movieclip colado ao lado direito:


fit.x(MovieClip, fit.xRight);


E para alinhar colado a base:


fit.y(MovieClip, fit.yBottom);


Os alinhamentos suportados para o x são fit.xLeft(padrão) e fit.xRight, e para y são fit.yTop(padrão) e fit.yBottom.

O alinhamento esta preparado apenas para a configuração padrão de alinhamento do Flash e para o "TL" (alinhamento Top/Left):


Stage.scaleMode = "noScale";
Stage.align = "TL";


Outros parâmetros de alinhamento não foram testados.

No exemplo do swffit tem a função calcSize que é chamada quando cada resize é feito, é preciso adicionar a função fix, para cada vez que for feito o resize ajustar as posições:


function calcSize() {
fit.fix();
...
}


Veja o video que demonstra como utilizar:

Monday, June 9, 2008

GlassFish vs Apache

Gastei um tempinho para desvendar certos mistérios por trás desta configuração e contornar alguns problemas.

Para configurar segui o post do Jean-Francois Arcand's e da Amy Roh's.

Então vamos lá!

Primeiro no Apache, instalar o mod_jk:

apt-get install libapache2-mod-jk

Configurar o conteúdo do arquivo /etc/apache2/mods-available/jk.load:

# Modulo do mod_jk
LoadModule jk_module /usr/lib/apache2/modules/mod_jk.so
# Arquivo de configuração
JkWorkersFile /etc/apache2/mod_jk_worker.properties
# Arquivo de log
JkLogFile /var/log/apache2/mod_jk.log
# Nível de detalhe dos logs [debug/error/info]
JkLogLevel debug
# Formato das mensagens de log
JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
# JkOptions indica para enviar SSL KEY SIZE
JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories
# JkRequestLogFormat define o formato dos requests no Log
JkRequestLogFormat "%w %V %T"
# Envia todos jsp para o GlassFish
JkMount /*.jsp worker1
# Envia todos os acessos ao meu projeto web para o GlassFish
JkMount /WebApplication/* worker1

Na última linha, o WebApplication se refere ao nome do nosso projeto no GlassFish, coloque aqui o nome do teu projeto no GlassFish.

Agora falta configurar o /etc/apache2/mod_jk_worker.properties, com este conteúdo:

# Define 1 worker usando ajp13
worker.list=worker1
# Define as propriedades do worker1 (ajp13)
worker.worker1.type=ajp13
worker.worker1.host=localhost
worker.worker1.port=8009
worker.worker1.lbfactor=50
worker.worker1.cachesize=10
worker.worker1.cache_timeout=600
worker.worker1.socket_keepalive=1
worker.worker1.socket_timeout=300

Agora vamos ao GlassFish...

No Glassfish configurar as seguintes opções da JVM:

$GLASSFISH_HOME/bin/asadmin create-jvm-options -Dcom.sun.enterprise.web.connector.enableJK=8009

E também:

$GLASSFISH_HOME/bin/asadmin create-jvm-options -Dcom.sun.enterprise.web.connector.enableJK.propertyFile=/etc/apache2/mod_jk_worker.properties

Para confirmar se ficou bem configurado, verifique o arquivo:

$GLASSFISH_HOME/domains/domain1/config/domain.xml

Procurar neste arquivo por:

<jvm-options>-Dcom.sun.enterprise.web.connector.enableJK=8009</jvm-options>
<jvm-options>-Dcom.sun.enterprise.web.connector.enableJK.propertyFile=/etc/apache2/mod_jk_worker.properties</jvm-options>

Fazer o download do apache-tomcat-5.5.16.zip, e pegar o tomcat-ajp.jar, só serve o jar desta versão, os das versões superiores não funcionam, provocam o seguinte erro no GlassFish:

Caused by: java.lang.NoSuchMethodError: org.apache.coyote.Response.getContentLengthLong()J

Depois do download, procurar o tomcat-ajp.jar dentro do zip:

apache-tomcat-5.5.16/server/lib/tomcat-ajp.jar

E copiar este jar para dentro do GlassFish:

$GLASSFISH_HOME/lib/

Também são precisos os jars commons-modeler e commons-logging, que podem ser adquiridos aqui:

http://commons.apache.org/downloads/index.html

Modeler:
http://commons.apache.org/downloads/download_modeler.cgi

Logging:
http://commons.apache.org/downloads/download_logging.cgi

Copiar estes dois jars também para dentro do:

$GLASSFISH_HOME/lib/

Feito isto, é preciso reiniciar o Apache e o GlassFish, e agora deverá estar funcionando através do Apache:

http://localhost/WebApplication

Assim através do Apache da para acessar os projetos publicados no GlassFish!

O porto 8009 que configuramos para o JK não tem nada haver com o porto web do GlassFish, o mod JK usa um protocolo próprio para comunicar com o Tomcat/AJP, e o GlassFish o que faz é inicia um novo porto usando o JK do Tomcat para poder comunicar com o mod_jk no Apache, e para testar se este porto esta funcionando pode-se usar o telnet e ver se conecta:

telnet localhost 8009

Futuramente pretendo investigar sobre Load Balancing usando o Apache e Glassfish e espero falar sobre isto.

Friday, May 9, 2008

Backup

A alguns anos fiz um sistema de backups em ShellScript e hoje configurei ele num servidor novo, e reparei como ele tem sido útil e tem resultado muito bem, resolvi partilhar.

Criar as pastas:

# mkdir /backup
# mkdir /backup/log


Criar os seguintes arquivos:

# touch /backup/backup
# touch /backup/backup.start
# touch /backup/backup.end
# touch /backup/directory
# touch /backup/run


Dar permissões de execução:

# chmod +x /backup/backup
# chmod +x /backup/backup.start
# chmod +x /backup/backup.end
# chmod +x /backup/run


Os backups diários serão guardados dentro da pasta /backup/daily. E os mensais sempre no dia 1 serão guardados dentro da pasta /backup/monthly. Não é preciso criar estas pastas, elas são criadas automaticamente.

Colar este conteúdo no arquivo /backup/backup:

#!/bin/bash
echo ""
echo -e "\e[40;32;1m Backup \e[0m"
echo ""
echo -e "\e[44;33;1m Start \e[0m"
echo ""
dir1="/backup"
dir2=$1
echo -ne "\e[34;1mcomand.begin\e[0m \e[32mstart\e[0m \e[30;5m...\e[0m"
$dir1/backup.start
echo -e "\e[31;1m end \e[0m"
echo ""
dateDay=`date "+%d"`
dateMonth=`date "+%m"`
dateYear=`date "+%Y"`
folder1=$dir1/daily/$dateDay
folder2=$dir2/daily/$dateDay
echo -ne "\e[34;1mWork Folder\e[0m $folder1 \e[32mstart\e[0m \e[30;5m...\e[0m"
rm -dfr $folder1
mkdir -p $folder1
echo -e "\e[31;1m end \e[0m"
echo ""
if [[ $dir2 != "" ]]; then
echo -ne "\e[34;1mWork Folder\e[0m $folder2 \e[32mstart\e[0m \e[30;5m...\e[0m"
rm -dfr $folder2
mkdir -p $folder2
echo -e "\e[31;1m end \e[0m"
echo ""
fi
echo -e "\e[40;31;1m BACKUP: directory \e[0m"
echo " |"
_x=0
_to=""
for i in `cat /backup/directory`; do
if [ $_x = 0 ]; then
_to=$folder1/$i.tar.gz
echo -ne " | $i \e[32mstart\e[0m \e[30;5m...\e[0m"
_x=1
else
tar -czPf $_to $i
if [[ $dir2 != "" ]]; then
cp -rf $_to $folder2
fi
echo -e "\e[31;1m end \e[0m"
_x=0
fi
done
echo " |____________________________________________________"
echo ""
echo -ne "\e[34;1mcomand.end\e[0m \e[32mstart\e[0m \e[30;5m...\e[0m"
$dir1/backup.end $folder1
echo -e "\e[31;1m end \e[0m"
if [ $dateDay = 01 ]; then
folderMonthly1=$dir1/monthly/$dateYear.$dateMonth.$dateDay
echo -ne "\e[34;1mMonthly Backup]\e[0m $folderMonthly1 \e[32mstart\e[0m \e[30;5m...\e[0m"
mkdir -p $folderMonthly1
cp -rf $folder1 $folderMonthly1
echo -e "\e[31;1m end \e[0m"
if [[ $dir2 != "" ]]; then
folderMonthly2=$dir2/monthly/$dateYear.$dateMonth.$dateDay
echo -ne "\e[34;1mMonthly Backup]\e[0m $folderMonthly2 \e[32mstart\e[0m \e[30;5m...\e[0m"
mkdir -p $folderMonthly2
cp -rf $folder2 $folderMonthly2
fi
echo ""
fi
echo ""
echo -e "\e[44;33;1m End \e[0m"
echo ""
echo -e "\e[40;32;1m by eduveks \e[0m"
echo ""


O arquivo /backup/run é o que inicia o backup e grava o output no arquivo de log, colocar o seguinte conteúdo:


#!/bin/bash
logFileName=`date "+%Y-%m-%d_%H-%M-%S"`
/backup/backup "/mnt/backupmirror" > /backup/log/$logFileName


Atenção ao "/mnt/backupmirror/backup", esta opção é para fazer uma cópia do backup para outra pasta, no meu caso sempre uso um servidor secundário para ter um espelho do backup original, e esta pasta é uma pasta montada remotamente ao outro servidor.

Os arquivos /backup/backup.start e /backup/backup.end, servem para poder colocar comandos para serem executados antes e depois do backup respectivamente, por exemplo para fazer o mount e o umount de uma partilha remota, preparando o cenário da cópia secundária. Ou ainda para parar serviços e reinicia-los no fim, por exemplo para o MySql antes de começar o backup e no fim voltar a inicializa-lo. Gravar nestes arquivos o conteúdo:


#!/bin/bash


Finalmente o arquivo /backup/directory serve para dizer as pastas que deverá ser feito backup, adicionar aqui o nome que vai ter o arquivo.tar.gz e qual a pasta que vai ser armazenada neste arquivo, no seguinte formato:


DB_NAME     /var/lib/mysql/DB_NAME
USER1       /home/USER1


Depois de tudo afinado vamos executar o backup, assim podemos ver o output:

# /backup/backup


Se tudo correu bem, o backup deverá estar em:

# /backup/daily/01/DB_NAME.tar.gz
# /backup/daily/01/USER1.tar.gz


Onde o "01" é o número do dia do mês atual.

Assim a cada dia haverá uma pasta com os backups deste dia, e no dia 1 de cada mês, o backup deste dia estará em:

# /backup/monthly/2008.05.01/01/DB_NAME.tar.gz
# /backup/monthly/2008.05.01/01/USER1.tar.gz


E executar o backup passando uma pasta para ser o espelho do backup:

# /backup/backup /tmp


Poderá reparar que também dentro do /tmp passará a ter o conteúdo do backup.

Feito o teste, voltar a ver como esta o /backup/run, verificar se esta tudo certo, e testa-lo:

# /backup/run


Dentro da pasta /backup/log deverá ter o log do backup:

# cd /backup/log
# ls
# cat 2008-05-01_11-51-53


Agora só falta configurar no crond para executar o backup, criar um arquivo no /etc/cron.daily/backup, com o seguinte conteúdo:


#!/bin/sh
/backup/run


Pronto, agora o backup irá ser executado todos os dias, e assim temos uma solução bem simples e prática para fazer backups...