Git como boa prática de consultoria
Publicado por Rodrigo Ramalho da Silva em git em 01/04/2012
Últimamente tenho utilizado bastante o git, mas não usando convencionalmente versionando apenas projetos, mas sim diretórios que julgo que contenham arquivos que se modificados podem me render um bom trabalho, como o /etc por exemplo.
Gostei tanto dessa utilização que resolvi adotar como uma boa prática de consultoria. É muito comum clientes se queixando que o que você deixou funcionando a algum tempo parou de funcionar e quando você começa a analisar o problema ,as vezes com bastante custo, descobre que alguém resolveu por algum motivo alterar um arquivo ou adicionar uma biblioteca que não deveria. Com o uso do git conseguimos contornar isso.
O git trabalha de maneira que os commits são feitos apenas localmente e só quando feito um git push que os arquivos versionados serão enviados ao servidor. Logo como não adicionamos nenhum servidor para fazer push e nem iremos tentar fazer push não corremos o risco desses arquivos serem publicados. Segue um exemplo básico:
cd /opt/jboss7 git init Initialized empty Git repository in /opt/jboss7/.git/ git add * git status # On branch master # # Initial commit # # Changes to be committed: # (use "git rm --cached <file>..." to unstage) # # new file: LICENSE.txt # new file: README.txt ..... # new file: welcome-content/noconsole.html # new file: welcome-content/noredirect.html git commit -am 'Servidor de Aplicação Jboss AS 7.' -a = all files -m = commit message
Quando rodamos o git init o diretório oculto .git é criado de onde o comando foi invocado, é nesse diretório que ficam os metadados do git, logo vale a pena se atentar o tamanho que esse diretório pode ficar dependendo do tamanho do diretório é versionado, veja o tamanho que ficou para o versionamento do jboss7 completo.
[rodrigoramalho] /opt/jboss7 du -sh .git/ 75M .git/
Com o projeto versionado, se rodarmos um git status veremos que não há nada a ser comitado (se nada tiver sido alterado claro). Então é isso, a medida que alterações forem sendo feitas basta ir fazendo novos commits e quando acontecer a situação que mencionei no começo do post um simples git status já acusaria se algum arquivo foi adicionado/alterado/removido e ainda nos permitiria visualizar as alterações a até mesmo fazer um rollback.
Com os commits devidamente comentados caso outra pessoa assuma a consultoria, apenas pelos logs do git já consegue ter um bom resumo do que já foi feito.
Cola dos principais comandos:
# Exibe o log de uma forma melhor pra visualizar git log --oneline # Exibe o status de uma forma melhor pra visualizar git status -s git diff <commit hash> <filename> # o commit hash é exibido no git log. # Faz rollback no arquivo para a versão informada git reset <commit hash> <filename>
Remover Protetor de Link
Publicado por Rodrigo Ramalho da Silva em Java em 20/03/2012
Vira e mexe a gente se depara com uns problemas no dia dia bem irritantes, como por exemplo quando você vai baixar um episódio do seu seriado preferido abre uma página pedindo pra você cadastrar seu celular ou baixar um programa tipo “pcmegarápido” e só após disso o link para o download é disponibilizado:
Então fiz uma aplicação que descriptografa o link, devolvendo um novo contendo o caminho direto para o download, ou seja, sem precisar cadastrar o bendito celular ou baixar o “pcmegarapido.exe”.
Basta copiar a url “bloqueada” e colar no único campo que a aplicação apresenta.
Enfim, quem tiver interesse em saber como funciona sugiro dar uma olhada no README e no código no github, sintam-se a vontade pra colaborar d;-)
Configurando proxy no Git
Publicado por Rodrigo Ramalho da Silva em git em 14/03/2012
Quando estamos em ambientes corporativos é muito comum o uso de proxy e consequentemente acabamos tendo algum problema com o git. Aqui estão alguns passos para configurar proxy no git.
git config –global http.proxy meu.servidor:8080
As vezes o github não consegue validar o certificado digital, para desabilitar:
git config –global http.sslverify false
Geralmente adicionamos a url do repositório para usar o protocolo git (git remote add origin git@github.com:hodrigohamalho/blablabla.git), como setamos proxy apenas para http e https, se a url estiver para utilizar git devemos alterar.
Para visualizar a url atual:
git remote show origin
Para alterar:
git remote set-url origin https://github.com:hodrigohamalho/blablabla.git
Com essa alteração tudo já deveria estar funcionando.
Como as configurações são globais, todos os projetos irão utilizar o proxy setado, para remover utilize:
git config –unset –global http.proxy
git config –unset –global http.sslverify
That’s all folks ;P
Teste em aplicações Java com Rspec
Publicado por Rodrigo Ramalho da Silva em Java, ruby on rails em 13/03/2012
Durante o período que trabalhei na SEA Tecnologia, fui apresentado ao desenvolvimento Ágil e o desenvolvimento de aplicações usando TDD. No início participei de alguns projetos em Java, posteriormente conheci o Ruby on Rails e comecei a fazer testes com o RSpec, confesso que fiquei fascinado com a integração, facilidade e clareza que essa ferramenta de testes apresenta. Com o JRuby, projeto que compila código Ruby pra bytecode Java, podemos não só executar Ruby através da JVM, como fazer a integração com código Java. Existe um projeto que permite essa integração (Java x Ruby) utilizando maven. Então meu objetivo com esse post é mostrar como fazer essa integração, e escrever alguns testes em Ruby testando classes Java.
Pré requisito:
Maven
Instalação Jruby
Adicionar a variável de ambiente JRUBY_HOME
Edite o arquivo ~/.bash_profile, adicionando as seguintes linhas:
export JRUBY_HOME=/opt/jruby-1.3.1
Hands on, vamos começar a criação de um game, snake game o famoso jogo da cobrinha nos celulares mais antigos =P
Criando o projeto maven:
mvn archetype:generate -DarchetypeGroupId=org.apache.maven.archetypes -DgroupId=org.rodrigoramalho.snake-game -DartifactId=snake-game # Quando aparecer essa linha, apenas aperte enter. Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): 16: # Nessa também Define value for property 'version': 1.0-SNAPSHOT: :
Depois basta confirmar (Y) e pronto o projeto estará criado.
Entre no diretório e execute a task do maven para gerar os arquivos necessários para importamos o projeto no eclipse.
cd snake-game/ mvn eclipse:eclipse
Já com o projeto importado no eclipse, ediciona o plugin do RSpec no pom.xml
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>rspec-maven-plugin</artifactId>
<configuration>
<jrubyHome>${env.JRUBY_HOME}</jrubyHome>
<sourceDirectory>${basedir}/src/test/specs</sourceDirectory>
<outputDirectory>${basedir}/target</outputDirectory>
<systemProperties>
<property>
<name>testProp</name>
<value>testValue</value>
</property>
</systemProperties>
</configuration>
<executions>
<execution>
<id>test</id>
<phase>test</phase>
<goals>
<goal>spec</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Crie o diretório “specs” dentro da pasta test.
snake-game/src/test/specs Pronto, chegando aqui seu ambiente já está (ou deveria estar, rs) configurado para começar o desenvolvimento. Então, go go go!
Criando a classe de testes em Ruby: (Como o eclipse não tem syntax highlight nativo pro Ruby, eu prefiro usar um editor de texto comum: vim, gedit, textmate)
snake-game/src/test/specs/snake_spec.rb
import org.rodrigoramalho.snakegame.model.Snake; describe Snake do end
Para executar o teste, rode:
mvn test
O seguinte erro vai ocorrer:
[INFO] Running RSpec tests from /Users/rodrigoramalho/Documents/workspace/snake-game/src/test/specs
/opt/jruby-1.3.1/lib/ruby/1.8/optparse.rb:605:in `get_proxy_or_package_under_package’: cannot load Java class org.rodrigoramalho.snakegame.model.Snake (NameError)
….
Então vamos criar a classe Snake.
package org.rodrigoramalho.snakegame.model;
public class Snake {
}
Rodamos os testes novamente, com mvn test.
[INFO]
[INFO] — rspec-maven-plugin:1.0-beta-6:spec (test) @ snake-game —
[INFO] Running RSpec tests from /Users/rodrigoramalho/Documents/workspace/snake-game/src/test/specs
=========================================
TOTAL: 0 passing; 0 failing; 0 pending
Qualquer alteração feita nessa classe, não é necessário rodar a task “mvn test” novamente, dentro do diretório snake-game/target/ contém um arquivo com o nome de run-specs.sh que recompila as classes e executa os testes. Utilizando esse script é economizado um bom tempo, pois roda bem mais rápido que o “mvn test”.
Os relatórios dos testes são gerados no arquivo snake-game/target/rspec_report.html
Depois de fazer alguns testes segue o código da classe ruby. (A identação desse plugin ta zuada :/)
import org.rodrigoramalho.snakegame.model.Snake;
import org.rodrigoramalho.snakegame.model.Direcao;
describe Snake do
before(:each) do
@snake = Snake.new "3 5 5 NORTE"
end
context "com parametros válidos" do
it "deveria receber o comprimento e as coordenadas iniciais" do
@snake.comprimento.should == 3
@snake.posicao.x.should == 5
@snake.posicao.y.should == 5
@snake.posicao.direcao.should == Direcao::NORTE
end
end
context "com parametros invalidos" do
it "direção inválida" do
expect{ Snake.new "5 5 5 Rodrigo" }.should raise_error(java.lang.IllegalArgumentException)
end
it "comprimento negativo" do
expect{ Snake.new "-5 5 5 NORTE" }.should raise_error(java.lang.IllegalArgumentException)
end
it "posicao x negativa" do
expect{ Snake.new "5 -5 5 NORTE" }.should raise_error(java.lang.IllegalArgumentException)
end
it "posicao y negativa" do
expect{ Snake.new "5 5 -5 NORTE" }.should raise_error(java.lang.IllegalArgumentException)
end
end
context "movimentação" do
context "com movimentos possiveis" do
it "deveria virar para esquerda quando estiver na direcao norte" do
@snake.virarEsquerda();
@snake.posicao.direcao.should == Direcao::OESTE
end
it "deveria virar para esquerda quando estiver na direcao sul" do
@snake.posicao.direcao = Direcao::SUL
@snake.virarEsquerda();
@snake.posicao.direcao.should == Direcao::OESTE
end
it "deveria continuar apontando para esquerda ao tentar virar para esquerda" do
@snake.posicao.direcao = Direcao::OESTE
@snake.virarEsquerda();
@snake.posicao.direcao.should == Direcao::OESTE
end
it "deveria virar para direita quando estiver na direcao norte" do
@snake.virarDireita();
@snake.posicao.direcao.should == Direcao::LESTE
end
end
context "com movimentos impossíveis" do
it 'quando apontando para o LESTE não deveria virar para a ESQUERDA' do
@snake.posicao.direcao = Direcao::LESTE
@snake.virarEsquerda();
@snake.posicao.direcao.should == Direcao::LESTE
end
end
end
end
Classe Java (Se quiser visualizar com detalhes, veja o fonte do código no github)
package org.rodrigoramalho.snakegame.model;
import org.rodrigoramalho.util.ValidacaoUtil;
public class Snake {
private Integer comprimento;
private Posicao posicao;
public Snake(){}
public Snake(String coordenadas){
String[] args = coordenadas.split(" ");
this.comprimento = new Integer(args[0]);
getPosicao().setX(new Integer(args[1]));
getPosicao().setY(new Integer(args[2]));
getPosicao().setDirecao(Direcao.valueOf(args[3]));
if (ValidacaoUtil.isMenorQueZero(getComprimento(), getPosicao().getX(), getPosicao().getY()))
throw new IllegalArgumentException("Use apenas valores > 0");
}
public void virarEsquerda(){
if (getPosicao().getDirecao() != Direcao.LESTE){
getPosicao().setDirecao(Direcao.OESTE);
}
}
public Integer getComprimento() { return comprimento; }
public void setComprimento(Integer comprimento) { this.comprimento = comprimento; }
public Posicao getPosicao() {
if (posicao == null)
posicao = new Posicao();
return posicao;
}
public void setPosicao(Posicao posicao) { this.posicao = posicao; }
}
É isso ai! Depois aconselho a explorarem mais os testes com RSpec porque tem bastante coisa legal, e ainda tem o poder de fazer os testes usando 100% código Ruby, desfrutando de vários benefícios como Closures por exemplo
Inserir tag no cabeçalho html do Portal Gatein
Publicado por Rodrigo Ramalho da Silva em Java, portal em 17/01/2012
Esses dias precisei inserir uma tag no cabeçalho de todas as páginas que estivessem no portal gatein.
Existem duas maneiras de fazer isso:
1. Criando um portlet que insere essa tag no <head> da página, carregando pelo método doHeader.
o código do portlet deverá ser semelhante a esse:
public class HeaderExtension extends GenericPortlet {
@Override
protected void doHeaders(RenderRequest request, RenderResponse response) {
Element meta = response.createElement("meta");
meta.setAttribute("http-equiv", "X-UA-Compatible");
meta.setAttribute("content", "IE=edge");
response.addProperty(MimeResponse.MARKUP_HEAD_ELEMENT, meta);
}
@Override
public void doView(RenderRequest request, RenderResponse response) {
PortletRequestDispatcher prd = getPortletContext().getRequestDispatcher("/jsp/index.jsp");
try {
prd.include(request, response);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Com isso basta colocar este portlet no layout do site e ele irá colocar toda vez essa tag no cabeçalho da página. Pode ser usado também pra carregar css, javascript, etc.. (Veja mais)
Porém com essa abordagem tudo que for inserido aparece no final da tag head, ou seja, próximo ao /head. As vezes é necessário que a tag esteja no começo do head, como no caso da tag:
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
Que é utilizada para compatibilidade com o Internet Explorer.
Com este cenário temos que alterar o fonte do template groovy que o portal utiliza. O arquivo pode ser encontrado em:
$JBOSS_EPP_HOME/server/$SERVER_NAME/deploy/gatein-wcm-extension-2.1.5-CP02.ear/ecm-wcm-extension.war/groovy/portal/webui/workspace/UIPortalApplication.gtmpl
Ps: É necessário explodir o arquivo gatein-wcm-extension-2.1.5-CP02.ear e o ecm-wcm-extension.war
Feita a alteração neste template groovy basta reiniciar o portal.
Autenticação pelo Google utilizando OpenID
Publicado por Rodrigo Ramalho da Silva em Java em 12/01/2012
“A API de login federado do Google, com base no protocolo OpenID 2.0, permite que os usuários façam login no seu site ou aplicativo da web com suas Contas do Google. Quando o Google autentica uma conta de usuário, ele retorna um ID de usuário para o seu aplicativo, o que permite que você colete e armazene informações do usuário. O Login federado também permite que você obtenha acesso a determinadas informações sobre a conta do usuário, com a aprovação dele.” http://code.google.com/intl/pt-BR/apis/accounts/
Então… Hands ON! Cabe lembrar que da mesma maneira que faremos para o google podemos fazer para qualquer site que seja um provedor OpenID, como Yahoo, Flickr dentre outros.
Segue uma imagem que tenta representar como ficará o fluxo dessa autenticação.
- O usuário entra na tela de login, seleciona o botão para fazer autenticação pelo google.
- É feito um direcionamento para autenticação pela página do google.
- Ao efetuar a autenticação ocorre o redirecionamento de volta para a página da aplicação.
1. SETUP
Baixe a biblioteca openid4java.
No eclipse crie um projeto Dynamic Web Project.
Fiz comentários quase que linha a linha em todo o código para facilitar o entendimento.
2. ResultType.java
Criei um Enum pra indicar se a autenticação teve sucesso, não sucesso ou se foi redirecionada.
package org.rodrigoramalho.openid.autenticacao;
public enum ResultType {
AUTH_SUCCESS, AUTH_FAILURE, REDIRECT_TO_OPENID_PROVIDER_FAILURE
}
2. Consumer.java
Éssa classe que será responsável pela autenticação utilizando o openid.
O método a seguir authRequest é o método responsável pela ação de quando o usuário clicar no botão de autenticação com o google, fazer o request OpenID e direcionar para a página de autenticação do google.
public ResultType authRequest(HttpServletRequest request, HttpServletResponse response, ServletContext servletContext) throws IOException{
try{
// realm é a url da aplicação + porta ex: http://localhost:8080
String realm = getRealm(request);
// Definimos a url a qual o google deverá retornar após autenticar o usuário
String returnToUrl = new StringBuffer(realm).append(request.getContextPath()) + "/Auth";
// "descobre" o OpenID do fornecedor
List discoveries = manager.discover("https://www.google.com/accounts/o8/id");
// Tentativa de se conectar com o provedor OpenID
// e acessar um endpoint service pra se autenticar
DiscoveryInformation discovered = manager.associate(discoveries);
// Obtém a requisição de autorização que será mandada para o provedor OpenID
AuthRequest authReq = manager.authenticate(discovered, returnToUrl);
// Informa quais atributos deverão ser 'requeridos'
FetchRequest fetch = FetchRequest.createFetchRequest();
fetch.addAttribute("email", "http://axschema.org/contact/email", true);
fetch.addAttribute("firstName", "http://axschema.org/namePerson/first", true);
fetch.addAttribute("lastName", "http://axschema.org/namePerson/last", true);
authReq.addExtension(fetch);
authReq.setRealm(realm);
// coloca o objeto discovered na sessão do usuário
request.getSession().setAttribute("discovered", discovered);
request.getSession().setAttribute("checkResponse", true);
// Encaminha para a página de autenticação do google
response.sendRedirect(authReq.getDestinationUrl(true));
}
catch (OpenIDException e){
e.printStackTrace();
}
return ResultType.REDIRECT_TO_OPENID_PROVIDER_FAILURE;
}
Após fazer a autenticação pelo google, deve-se verificar se essa autenticação foi válida, para isso deve-se chamar o método verifyResponse
public ResultType verifyResponse(HttpServletRequest httpReq){
try{
// extrai os parametros que vem do HTTP request do OpenID provider.
ParameterList response = new ParameterList(httpReq.getParameterMap());
// Lembra que a gente colocou esse objeto na sessão?
DiscoveryInformation discovered = (DiscoveryInformation) httpReq.getSession().getAttribute("discovered");
// Extrai os parametros da url
StringBuffer receivingURL = httpReq.getRequestURL();
String queryString = httpReq.getQueryString();
if (queryString != null && queryString.length() > 0){
receivingURL.append("?").append(httpReq.getQueryString());
}
// Valida o response, verificar se o ConsumerManager é o mesmo que efetuou o request
VerificationResult verification = manager.verify(receivingURL.toString(), response, discovered);
// Analisa o resultado da verificação e extrai o identificador de verificação
Identifier verified = verification.getVerifiedId();
if (verified != null){
AuthSuccess authSuccess = (AuthSuccess) verification.getAuthResponse();
if (authSuccess.hasExtension(AxMessage.OPENID_NS_AX)){
// Extrai os atributos que fizemos a requisição (no fetchRequest)
FetchResponse fetchResp = (FetchResponse) authSuccess.getExtension(AxMessage.OPENID_NS_AX);
Map userAttributes = fetchResp.getAttributes();
User user = new User();
user.setEmail(userAttributes.get("email").toString());
String nome = userAttributes.get("firstName") + " "+ userAttributes.get("lastName");
user.setName(removeBrackets(nome));
// Coloca o usuário na sessão
httpReq.getSession().setAttribute("user", user);
}
return ResultType.AUTH_SUCCESS; // success
}
}catch (OpenIDException e){
e.printStackTrace();
}
httpReq.getSession().removeAttribute("checkResponse");
return ResultType.AUTH_FAILURE;
}
3. AuthServlet.java
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
if (request.getParameter("logout") != null) {
logoutUser(request, response);
}else{
Consumer consumer = new Consumer();
HttpSession session = request.getSession();
boolean checkResponse = session.getAttribute("checkResponse") != null ? true : false;
if (!checkResponse){
consumer.authRequest(request, response, getServletContext());
}else{
consumer.verifyResponse(request);
RequestDispatcher dispatcher = request.getRequestDispatcher("login.jsp");
dispatcher.forward(request, response);
}
}
} catch (ConsumerException e) {
e.printStackTrace();
}
}
4. login.jsp
<body>
<%@page import="org.rodrigoramalho.openid.beans.User"%>
<% User user = (User) request.getSession().getAttribute("user"); %>
<% if ( user == null){ %>
Sign in
<hr/>
<div><div id="login_por_terceiros">
<a href="Auth">
<div id="login_google"></div>
</a>
</div></div>
<% } else {%>
<p> Bem vindo <%= user.getName() %></p>
<p><a href="Auth?logout">Logout</a></p>
<%} %>
</body>
Bash Script find and replace
Publicado por Rodrigo Ramalho da Silva em Bash Script em 03/01/2012
find "/home/meu_diretorio" -type f -exec sed -i "" -e s/procure_por_isso/"substitua_por_isso"/g {} \;
.
FILES=$(find /home/procure_por_aqui -name "procure_por_isso")
for FILE in $FILES; do
NAME="$FILE"
NAME_REPLACED=$(echo $FILE | sed -e s/"procure_por_isso"/"substitua_por_isso"/g)
mv $NAME $NAME_REPLACED
done
FILES=$(find /home/procure_por_aqui -name *procure_por_isso*)
.
Introdução a Cluster
Publicado por Rodrigo Ramalho da Silva em cluster em 11/10/2011
Cluster ?
Cluster é o ato de de rodar a mesma aplicação em vários servidores de aplicação simultaneamente com cada aplicação estando ciente das outras que estão no cluster. Um servidor de aplicação em um cluster é chamado de nó.
Pra quê ?
Creio que a melhor forma de entender o por que? é com um exemplo, então:
O servidor em que minha aplicação está rodando suporta 1000 usuários simultâneos, porém hoje 2000 usuários simultâneos acessaram minha aplicação e o servidor caiu.
E agora José ? Temos 2 opções, ou adquiro recursos para o servidor que já está rodando ou adiciono outras máquinas para responderem esses requests, desafogando a primeiro servidor.
Cluster: Vertical x Horizontal
Clusters podem ser formados com nós rodando em uma máquina ou em várias máquinas. Essa formação do cluster é comumente se referida como topologia.
- Horizontal: Quando os nós do cluster estão em diferentes máquinas.
- Vertical: Quando os nós do clusters estão na mesma máquina
No cluster horizontal se acontece alguma falha com a máquina (ex: queda de energia, queimar algum periférico, etc) a outra máquina assume o cluster sem problemas. Se a máquina do cluster vertical ocorrer algum problema todos os servidores que estavam rodando nela, serão comprometidos. Em outras palavras um cluster horizontal é uma melhor opção para alta disponibilidade.
Balanceamento de Carga
Balanceamento de carga é a maneira de distribuir a carga de entrada entre os diferentes servidores de aplicação, fazendo com que sua aplicação seja escalável e tenha alta disponibilidade. Escalabilidade é o termo usado para descrever a habilidade de fazer com que sua aplicação manipule mais carga adicionando hardware e/ou criando instâncias redundantes sem alterar o código. Então um cluster sem balanceamento de carga faz pouco ou nenhum sentido.
Alta disponibilidade
Caso se tenha uma aplicação que seja toda stateless, pode-se garantir alta disponibilidade apenas colocando um balanceador de carga na frente de vários servidores com a mesma aplicação deployada (note, sem cluster). Esse mecanismo é conhecido como Failover. Cabe a ressalva que no failover nenhum tipo de estado da aplicação é replicado.
Porém se a aplicação for stateful o problema é mais em baixo, imagine que você esteja em um site de compras o seu carrinho já possui 10 itens derrepente o servidor cai, você não vai gostar nada de quando clicar no próximo botão cair em um tela de login e o seu carrinho aparecer zerado. O failover não replica estado então não seria adequado para esse tipo de situação para isso temos o mecanismo a seguir:
Replicação e Tolerância a falhas (Replication e Fault Tolerance)
Um servidor com tolerância a falhas promove alta disponibilidade e continua se comunicando com o cliente mesmo que o servidor caia, ou seja o estado do cliente é mantido. Então no exemplo anterior se o cluster tiver tolerância a falhas então o servidor cairá o cliente será balanceado para outro nó e continuará logado na aplicação com seu carrinho de compras com todos os itens como se nada tivesse acontecido.
Mas o que contém nesse estado do cliente?
Basicamente duas coisas: Dados de sessão e de entidades.
Dados de sessão (Session data) são mantidos em memória pela aplicação ou por mecanismos de cache habilitados pelo servidor de aplicação.
Dados de entidade (Entity data) são mantidos em banco de dados.
Para ser tolerante a falhas o estado associado a uma aplicação deve redundantemente disponível, ou seja, os nós devem replicar o estado entre cada nó do cluster
Fault tolerance = fail over + state replication

É muito comum escutarmos conversas de pessoas pensando em cluster como uma forma de melhorar performance, e como podemos ver cluster é sinônimo de disponibilidade e dependendo do cluster pode é trazer défict de performance devido o fato do servidor de aplicação ter que ficar replicando estado, sincronizando cache, etc.
Existem diferentes formas dessa replicação de estado acontecer em um cluster, mas para não deixar o post muito longo vou encerrando por aqui.
Fonte:
JBoss in Action – Chapter 12 – Understanding Cluster.
jQuery placeholder plugin (Twitter Like)
Publicado por Rodrigo Ramalho da Silva em jQuery em 28/09/2011
Recentemente programando com minha amiga Carolina Mascarenhas ela fez um placeholder bem parecido com o do twitter, apenas dei uma acabada no código e coloquei no formato de plugin.
Placeholder é quando o label de um campo input está localizado dentro do pŕoprio input. Como podemos ver na imagem abaixo:
Segue a página contendo o exemplo: http://jspace.com.br/jquery-placeholder-plugin/
Como utilizar:
Adicionar os arquivos jquery.js, jquery.placeholder.js e o placeholder.css a página.
<script type="text/javascript" src="jquery.min.js" ></script> <script type="text/javascript" src="jquery.placeholder.js" ></script> <link href="placeholder.css" type="text/css" rel="stylesheet" />
O html deve respeitar a seguinte estrutura:
<div class="holding username">
<input type="text" id="username" name="username" />
<span class="holder">Email</span> </div>
Onde o conteúdo que estiver dentro da tag <span> será o que aparecerá dentro do input.
Tendo isso como premissa, o código para adicionar o placeholder deverá ser o seguinte:
jQuery(".username").placeholder();
Onde “.username” é a classe da div. Também pode ser utilizado o id.
Algumas opções podem ser especificadas:
jQuery(".username").placeholder({
color_onfocus: "b9b9b9",
color_background_onfocus: "white" });
Cabe lembrar que o HTML5 tem suporte nativo ao placeholder bastando apenas colocar a propriedade placeholder=”Rodrigo Ramalho” dentro do input.
exemplo:
<input type="text" name="exemplo" placeholder="Demonstrando placeholder" />
Simples assim. Porém nem todos os browsers suportam HTML5 ainda.
Pra quem quiser contribuir e/ou entender melhor o projeto, o source está no meu github:
Cheat Sheets
Publicado por Rodrigo Ramalho da Silva em Cheat Sheet, ruby on rails em 08/07/2011
Para evitar o problema de ter que ficar dando uma googlada pra lembrar 'aquele' comando que está lhe falhando a memória, basta aprender a explorar os "cheat sheets". Cheat sheet é um resumo dos principais comandos de uma determinada API. Hoje precisei lembrar alguns comandos do heroku e achei esse cheat sheet no qual acrescentei algumas linhas. Heroku Cheat Sheet === General Commands help # show this usage version # show the gem version list # list your apps create [<name>] # create a new app keys # show your user's public keys keys:add [<path to keyfile>] # add a public key keys:remove <keyname> # remove a key by name (user@host) keys:clear # remove all keys ps # display process === App Commands (execute inside a checkout directory, or use --app <appname>) info # show app info, like web url and git repo open # open the app in a web browser rename <newname> # rename the app dynos <qty> # set the app to use the specified qty of dynos sharing:add <email> # add a collaborator sharing:remove <email> # remove a collaborator sharing:transfer <email> # transfers the app ownership domains:add <domain> # add a custom domain name domains:remove <domain> # remove a custom domain name domains:clear # remove all custom domains ssl:add <pem> <key> # add SSL cert to the app ssl:remove <domain> # removes SSL cert from the app domain rake <command> # remotely execute a rake command console <command> # remotely execute a single console command console # start an interactive console to the remote app restart # restart app servers logs # fetch recent log output for debugging logs:cron # fetch cron log output maintenance:on # put the app into maintenance mode maintenance:off # take the app out of maintenance mode config # display the app's config vars (environment) config:add key=val [...] # add one or more config vars config:remove key [...] # remove one or more config vars config:clear # clear user-set vars and reset to default db:pull [<database_url>] # pull the app's database into a local database db:push [<database_url>] # push a local database into the app's remote database db:reset # reset the database for the app -- Postgres databases --- pg:info # show db info pgbackups # list postgres backups pgbackups:url id # get url to download backup pgbackups:capture # capture a new backup pgbackups:destroy id # destroy bakup bundles # list bundles for the app bundles:capture [<bundle>] # capture a bundle of the app's code and data bundles:download # download most recent app bundle as a tarball bundles:download <bundle> # download the named bundle bundles:animate <bundle> # animate a bundle into a new app bundles:destroy <bundle> # destroy the named bundle addons # list addons addons:add name [key=value] # install addon (with zero or more config vars) addons:remove name # uninstall an addons addons:clear # uninstall all addons destroy # destroy the app permanently === Example: rails myapp cd myapp git init git add . git commit -m "my new app" heroku create git push heroku master




