Archive for the ‘JBoss’ category

java.lang.IllegalArgumentException: LifecycleId already added for id: SEAM_PORTLET.

March 7th, 2010

It’s almost a tradition now in this blog posting fixes to common Exceptions, so here is another one ;)

This one goes to people using JBoss Portlet Bridge 2.0.0.CR1 (don’t know about other versions). The stacktrace is the following:

 Caused by: java.lang.IllegalArgumentException: LifecycleId already added for id: SEAM_PORTLET.
         at com.sun.faces.lifecycle.LifecycleFactoryImpl.addLifecycle(LifecycleFactoryImpl.java:199)
         at org.jboss.portletbridge.lifecycle.PortletLifecycleFactory.addLifecycle(PortletLifecycleFactory.java:60)
         at org.jboss.portletbridge.lifecycle.PortletLifecycleFactory.(PortletLifecycleFactory.java:48)
         ... 195 more

The long history:

Portlet Bridge uses a custom JSF Lifecycle for handling behaviour specific to portlets. It does so by means of a embedded faces-config.xml in it’s jar. The problem is that it tries to add this SEAM_PORTLET even if it already exists. That means that having 2 Portlet Bridges JAR in your application’s classpath will cause confusion.

That raises a not so trivial scenario. Even tho you have only one Portlet Bridge JAR, depending on how your JBoss classloading configuration is set, this Exception can occur. That’s because JBoss uses temporary folders to unpack Javar Archives in it’s <JBOSS_HOME>/server/default/tmp (or whatever configuration you are using). These folders have unique auto-generated names, so between startups your WAR may be unpacked to a folder in tmp while there’s already an older version there with a different name.

The short history:

Delete your JBoss configuration’s tmp and work (don’t worry, it’s safe) folder or search for some duplicated portletbridge-impl.jar.

Reference: JIRA

JBossInBossa 2010

February 4th, 2010

O evento ocorrerá dias 16 e 17 de Abril em São Paulo

O JBossInBossa 2010 é a conferência anual da comunidade JBoss brasileira, ele contará com palestrantes internacionais que são líderes de projetos opensource, bem como palestras da comunidade brasileira que desenvolve e fomenta tecnologias relaciodas além do time brasileiro JBoss que atua em diversos projetos de missão crítica que usam tecnologias de ponta em projetos em todos os lugares do Brasil.

Mais informações: JBossInBossa

Agente JON/Jopr não sobre no boot

January 26th, 2010

JON 2.3.0.GA

O jeito mais comun de se adicionar o JON/Jopr para subir no boot (Red Hat Enterprise Linux)

  1. criar um link simbólico:
    ln -sf $RHQ_AGENT_HOME/bin/rhq-agent-wrapper.sh /etc/init.d/rhq-agent
  2. adicionar à lista de serviços:
    chkconfig --add rhq-agent

Agora basta rebootar e… Não funciona. Agora tente executar /etc/init.d/rhq-agent start. Funciona!!

A razão é que o bash script rhq-agent-wrapper.sh tenta achar o $RHQ_AGENT_HOME automaticamente através do path do script. Dá para ver isso na linha:

_DOLLARZERO=`readlink "$0" || echo "$0"`

Para quem não conhece bash script o $0 é o argumento 0, que corresponde ao caminho do arquivo sendo executado. O que acontece nessa linha é que a variável recebe o caminho do link derreferenciado, caso o arquivo seja um link, ou o caminho do arquivo, caso seja um arquivo mesmo (aliás é por isso que usamos um link no passo 1, senão o script acharia que /etc/init.d é o $RHQ_AGENT_HOME).

O chkconfig é a ferramenta usada no RHEL para registrar serviços. Nela registramos que serviços queremos subir em que níveis de inicialização. Esses níveis são (direto do inittab):

#   0 - halt (Do NOT set initdefault to this)
#   1 - Single user mode
#   2 - Multiuser, without NFS (The same as 3, if you do not have networking)
#   3 - Full multiuser mode
#   4 - unused
#   5 - X11
#   6 - reboot (Do NOT set initdefault to this)

O problema é que o chkconfig usa, para registrar os serviços, links simbólicos nas pastas /etc/rcX.d (onde X é o nível de inicialização). O que acontece então é o que é executado é um link simbólico em /etc/rc3.d apontando para o link simbólico /etc/init.d apontando para $RHQ_AGENT_HOME/bin. Algo do tipo:

/etc/rc3.d/S93rhq-agent -&gt; /etc/init.d/rhq-agent -&gt; $RHQ_AGENT_HOME/bin/rhq-agent-wrapper.sh

E o comando readlink não é recursivo por padrão, ou seja, se o link derreferenciado apontar para outro link, o readlink não o derreferencia.. A solução está no readlink –help: adicionar a flag -e.

Ou seja, basta mudar a linha 102 para:

_DOLLARZERO=`readlink -e "$0" || echo "$0"`

Fonte: JIRA

NullPointerException e o @EJB

January 11th, 2010

Um pouco de história…

Assim que a especificação JEE 5 saiu, com EJB 3 e suas anotações, houve interesse imediato da comunidade. O JBoss ainda em sua versão 4, não implementava completamente a especificação JEE 5, mas devido ao grande interesse e como um passo em direção ao JEE 5, suporte ao EJB 3 foi introduzido.

Isso causou alguma confusão a respeito ao uso da anotação @EJB (ou @Resource, @WebServiceRef, em fim) para injeção. Para quem não conhece, a anotação @EJB pode ser usada para injetar EJBs em Servlets puros, JSF Managed Beans, JAX-WS endpoints, entre outros. Foi a partir do JBoss 5, essa sim versão implementando JEE 5, que suporte a essa anotação foi introduzido.

Para os impacientes…

Mesmo usando o JBoss 5, ainda assim é preciso definir no seu web.xml que a versão Servlet sendo utilizada é a 2.5, especificação que contém esse tipo de injeção:

Note o post não se aplica ao uso dessas anotações para injeção em EJBs, que já é suportado desde de o JBoss 4 e não tem relação alguma com web.xml.

Portais em 1 minuto

January 4th, 2010

Até agora já postei algumas vezes sobre a nova solução de portal da JBoss, o GateIn. Enquanto escrevia meu terceiro post (aguardem!!) me dei conta que muitos podem não ter a mínima idéia do que estou falando. O que é uma ferramenta de portal? Eu preciso de uma ferramenta dessas? Como ela pode me ajudar? Como faço para utilizá-la? Bom, tomei um tempo para escrever um pouco sobre conceitos.

O que são portais?

Antes de saber como o GateIn pode ajudá-lo a construir portais, vamos ao que são portais (por simplicidade vou chamar portlet containers também de portais).

Um portal é um site que organiza grandes quantidades de informações em um único lugar, disponibilizando-as de forma consistente e organizada. Usualmente possuem serviço de busca de conteúdo e navegabilidade. Podem também oferecer meios de interação como canais de help desk, ouvidoria, etc. Alguns exemplos devem dar uma noção mais concreta, eles são: intranets de grandes empresas, órgãos do governo como MCT, Transparência e portais públicos como o UOL, Terra, Yahoo.

Com o conceito em mente, vamos partir para a parte técnica da pergunta: como uma solução de portal pode te ajudar? O GateIn implementa (e estende) as JSR 168 e JSR 286, Portlet 1.0 e 2.0, que são as especificações Java para definição de modos, estados, ciclo de vida e tudo que concerne o uso de portlets em portais. O que nos leva à próxima pergunta..

O que são portlets?

Lembro de quando programava em ASP, como achava SSI o ó do borogodó. Desde de aquele tempo as formas de reutilização vêm ficando cara vez mais sofisticada, passando pelo <jsp:include>, o Tiles (com o nem tão saudoso Struts) até o Facelets (agora parte da especificação JSF 2.0).

Portlets têm outra abordagem à reutilização, ao invés de dividir a aplicação em partes reutilizáveis, eles encapsulam aplicações em componentes reutilizáveis. Não entendeu? Eu desenho:

Aplicação web comum

Portlets

Esses componentes são diferentes de aplicações web, e não basta fazer deploy delas em um container web, elas precisam de um container especial. Esse container é o portal:

É através do desenvolvimento de portlets que são adicionadas funcionalidades e conteúdo ao portal. Uma vez desenvolvido, é feito seu deploy no GateIn.

Pensando para portais

Para desenvolver portais é preciso um pensamento diferente. Do mesmo jeito que os serviços SOA são organizados em processos, os portlets são sindicados em um portal. Os mesmo cuidados de se pensar serviços como unidades reutilizáveis são precisos para portlets. Do mesmo jeito, para tirar o máximo do desenvolvimento de portais é preciso de uma governança para prover reuso, catalogar, monitorar e auditar portlets. Gartner chegou a sugerir portais como um ponto de entrada para SOA.

Vejo ferramentas de portal como uma necessidade que surgiu do desenvolvimento em cima de servidores de aplicação (como o JBoss). Servidores de aplicação não foram criados para servir conteúdo web, isso é apenas uma de suas funcionalidades, eles fazem muito mais do que isso. Portais por outro lado foram desenvolvidos exclusivamente para conteúdo web, e por isso trazem uma gama de facilidades voltadas para esse fim.

Show me the money

(StarCraft? não?) Embora tenha batido muito no aspecto de reusabilidade, que acho o mais central, existem várias outras facilidades:

  • Sindicância de conteúdo: é possível consolidar conteúdos ou outras aplicações web sob a mesma apresentação;
  • Single Sign-on: federando-se aplicações web, é possível tirar vantagem de SSO. Uma vez que o usuário esteja logado no portal suas credenciais podem ser propagadas para as aplicações contidas nele;
  • Personalização: como o portal toma conta da apresentação, é possível ter vários níveis de personalização como tematização e internacionalização;
  • Reusabilidade: aplicações e conteúdos podem ser reaproveitados em diferentes locais dentro do portal ou mesmo em outros portais;
  • Automatização: a criação de menus de navegação, breadcrumb, site map, segurança, layout, etc. são providas out of the box.

Devido às várias facilidades providas, a palavra “portal” das ferrramentas de portal assumiu um sentido mais amplo do que o conceituado no começo do post. Sites de pequeno porte, que na realidade partilham pouco com portais, podem se beneficiar do uso dessas ferramentas.

Para ver tudo isso em ação, dêem uma olhada no post de lançamento do GateIn.

Deployment no GateIn

September 17th, 2009

EDIT: com o novo componente WCI não é mais preciso fazer alterações no web.xml. Em outra ocasião escrevo sobre esse componente.

Vi no JIRA recentemente uma issues aberta indicando problema no deploy de portlets no GateIn. Para quem também não sabe para onde ir vou mostrar como fazer o deploy de portlets nesse portal.

Primeiro precisamos alterar o web.xml da aplicação adicionando:

<filter>
	<filter-name>ResourceRequestFilter</filter-name>
	<filter-class>org.exoplatform.portal.application.ResourceRequestFilter</filter-class>
</filter>
<filter-mapping>
	<filter-name>ResourceRequestFilter</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>
 
<servlet>
	<servlet-name>GateInServlet</servlet-name>
	<servlet-class>org.gatein.wci.api.GateInServlet</servlet-class>
	<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
	<servlet-name>GateInServlet</servlet-name>
	<url-pattern>/gateinservlet</url-pattern>
</servlet-mapping>

Depois basta ir no GateIn, logado com usuário de pelo menos um dos grupos:

  • /organization/management/executive-board
  • /platform/administrators

Logaremos como root, e ir no menu Group -> Administration -> Application Registry:

gatein1

O Application Registry é uma forma de repositório do GateIn. É lá que temos acesso aos portlets e gadgets disponíveis, e onde podemos mudar permissões de acesso e ver detalhes da configuração de cada um deles. Agora clicamos em Auto Import e damos um OK para a mensagem de confirmação:

gatein2

Com isso o GateIn fará um scan de todos os deploys de aplicações web e instalará portlets definidos nelas. Os seus portlets devem aparecer na barra lateral:

gatein3 :)

GateIn Portal

September 5th, 2009

Nessa quinta-feira (dia 3) foi lançado oficialmente o projeto GateIn no evento Summit/JBoss World da Red Hat, em Chicago. O GateIn é uma solução de portal nascida da união do eXo Portal e o JBoss Portal e está em beta1. Bem além de uma simples solução de portal, o GateIn poderá ser extendido com módulos da eXo Platform tornando-o um gerenciador de conteúdo (CMS), um gerenciador de documentos (GED) ou uma ferramenta de colaboração.

A solução ficou muito legal, um video lançado ontem mostra como ela é poderosa:

Criando um MBean no JBoss

August 20th, 2009

A base do JBoss é o JBoss Microkernel que usa a especificação JMX (Java Management Extensions, JSR 003) através da qual módulos podem ser plugados através de MBeans. É assim que serviços de EJB, JMS, JTA, etc são providos no JBoss.

MBeans são simplesmente especificações de interface. Desse modo podemos criar serviços, criar uma MBean que lhe servirá de facade, e fazer o deploy desse MBean no JBoss para expôr esse serviço. Para tanto basta o criar um arquivos SAR ou *-service.xml e fazer seu deploy.

Nesse post vamos criar MBean de exemplo. O exemplo é constituído de 3 coisas:

  1. Um arquivo META-INF/jboss-service.xml com a descrição do MBean
  2. Uma interface BackdoorServiceMBean
  3. Uma classe BackdoorService

Tudo isso compilado em um backdoorService.sar na seguinte estrutura:

sar

A interface deve estende ServiceMBean (classe do JBoss) e seu nome deve terminar em MBean. Ela irá expor as propriedades e operações:

public interface BackdoorServiceMBean extends org.jboss.system.ServiceMBean {
 
	public String execute(String command);
	public String printAbout();
 
	public String getURL();
	public void setURL(String url);
 
}

No exemplo são declaradas duas operações, execute(String) e printAbout(), e uma propriedade, URL.

Já a classe deve estende ServiceMBeanSupport (classe do JBoss) e implementar nossa interface BackdoorServiceMBean. Seu nome deve ser o mesmo da interface sem a terminação “MBean”.

public class BackdoorService extends org.jboss.system.ServiceMBeanSupport implements BackdoorServiceMBean {
 
	private String url;
 
	public String execute(String comando) {
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		byte[] buf = new byte[1024];
		int len;
 
		try {
			Process proc = Runtime.getRuntime().exec(comando);
 
			while ((len = proc.getInputStream().read(buf)) &gt; 0) {
				out.write(buf, 0, len);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
 
		return out.toString();
	}
 
	public String printAbout() {
		return "Visit " + url + "!";
	}
 
	public String getURL() {
		return url;
	}
 
	public void setURL(String url) {
		this.url = url;
	}
 
}

Por último o arquivo META-INF/jboss-service.xml onde deve constar o nome qualificado da classe MBean e o nome que identificará o MBean (por convenção é da forma <domínio>:<lista de atributos>). Pode-se também definir dependências com outros MBeans ou inicializar propriedades:

<server>
    <mbean code="net.rafaelliu.BackdoorService"
           name="rafaelliu:service=BackdoorService">
      <attribute name="URL">http://rafaelliu.net</attribute>
    </mbean>
</server>

Testando nosso MBean, entramos em http://localhost:8080/jmx-console. Lá em baixo temos uma nova entrada:

jmx-console

Clicando no MBean, vemos a operação que definimos na interface. Vamos chamá-la com o argumento ls /:

jmx-invoke

Com isso temos o retorno:

jmx-resultado

Fácil, ahm?

Moral da história

Para quem nem o código Java nem o nome do serviço foi esclarecedor o suficiente, esse exemplo deve ter ajudado. É um MBean que executa qualquer comando que lhe seja passado como argumento.

Mas pera ai, posso executar qualquer comando mesmo? Até um rm -rf /? Sim. O detalhe é que o comando será executado com o mesmo usuário do JBoss (política de subprocessos do Linux), ou seja, a menos que o JBoss esteja sendo rodado como root, rm -rf / deverá resultar em erro de falta de privilégios.

Agora deve estar bem claro que é uma boa prática definir um usuário jboss com privilégios limitados para executar o processo do JBoss. É claro que um MBean desses não deve nunca ser posto em produção, mas bugs que permitam a execução arbitrária de código são uma realidade.

NOTAS:

  • a versão utilizada foi a JBoss 4.2.3.GA
  • nas versões mais recentes substituído pelo JBoss Microcontainer que além de JMX faz deploy de POJO e OSGi

REST com RESTEasy – JAXB e RESTEasy Client

February 5th, 2009

Uma ótima apresentação sobre REST me fez querer escrever um pouco sobre. Mais especificamente sobre o RESTEasy, implemetação certificada JAX-RS da JBoss. No projeto que fiz para certificação JBoss Certified SOA Developer o usei bastante e quero falar de algumas interessantes funcionalidades dele. Primeiro algumas considerações sobre REST:

  1. RESTEasy é um framework para criação de RESTful Web Services, o que em algum senso já é uma desvirtuação de REST (tal como Roy Fielding definiu), que trata de recursos. O que tem haver um serviço RESTful que loga o usuário? (O que aliás abre uma sedutora brecha para quebrar outro conceito REST: o de statelessness) De agora em diante irei usar REST e RESTful Web Services indistintamente.
  2. REST não é uma alternativa a SOA! Na verdade podemos usar REST para implementar SOA com WOA. Confuso? REST é uma alternativa ao WS-*, podendo ser usado no lugar dele para implementar SOA. A implementação RESTful de SOA é chamada WOA, ou ROA (veja a página de TLAs), que é um subconjunto de SOA.

JAXB binding

RESTEasy possui suporte a marshalling/unmarshalling de classes usando JAXB. Sou péssimo para dar exemplos mas vamos lá…:

@Path("/")
public class Servico {
 
	@GET @Path("/tempo")
	@Produces("text/xml")
	public Tempo getTempo() {
		return new Tempo("Parcialmente nublado", 20.3);
	}
 
	@POST @Path("/literal")
	@Consumes("text/xml")
	public void setTempo(Tempo tempo) {
		System.out.format("Descrição: %s%n", tempo.getDescricao());
		System.out.format("Temperatura: %d%n", tempo.getTemperatura());
	}
}
 
// classe anotada com JAXB
@XmlRootElement
class Tempo {
	private String descricao;
	private Double temperatura;
 
	public Tempo() {}
 
	public Tempo(String nome, Double preco) {
		this.descricao = nome;
		this.temperatura = preco;
	}
 
	public String getDescricao() {
		return descricao;
	}
	public void setDescricao(String nome) {
		this.descricao = nome;
	}
	public Double getTemperatura() {
		return temperatura;
	}
	public void setTemperatura(Double preco) {
		this.temperatura = preco;
	}
 
}

Na invocação de getTempo() RESTEasy vai ver que o tipo de retorno é o objeto Tempo e que ele está anotado com @XmlRootElement e vai fazer um marshalling dele. A anotação @Produces(“text/xml”) diz que a representação gerada deve ser XML. Quer que seja em JSON? Basta mudar para @Produces(“application/json”)!

Do mesmo jeito funciona o setTempo(). O parâmetro passados sem nenhuma anotação é interpretado como o corpo da requisição HTTP, que no caso é um objeto.

RESTEasy Client

Algo muito interessante que não é da especificação JAX-RS é o suporte a clients. Esses clients são proxies que transformam invocações Java em requisições HTTP. Para isso devemos criar uma interface com as mesmas assinaturas do nosso serviço e anotá-las:

public class Main {
	static {
		// precisa ser chamo uma única vez para registrar providers RESTEasy, scanear classes, etc
		 RegisterBuiltin.register(ResteasyProviderFactory.getInstance()); // precisa ser chamado uma única vez para
	}
 
	public static void main(String args[]) {
 		 IServico client = ProxyFactory.create(IServico.class, "http://localhost:8080/&lt;Context&gt;");
 
		 Tempo tempo = client.getTempo();
		 tempo.setTemperatura(tempo.getTemperatura() + 5.0);
		 client.setTempo(tempo);
	}
}
 
interface IServico {
 
	@GET @Path("/tempo")
	@Produces("text/xml")
	public abstract Tempo getTempo();
 
	@POST @Path("/literal")
	@Consumes("text/xml")
	public abstract void setTempo(Tempo tempo);
}
 
// classe anotada com JAXB
@XmlRootElement
class Tempo {
	private String descricao;
	private Double temperatura;
 
	public Tempo() {}
 
	public Tempo(String nome, Double preco) {
		this.descricao = nome;
		this.temperatura = preco;
	}
 
	public String getDescricao() {
		return descricao;
	}
	public void setDescricao(String nome) {
		this.descricao = nome;
	}
	public Double getTemperatura() {
		return temperatura;
	}
	public void setTemperatura(Double preco) {
		this.temperatura = preco;
	}
 
}

Agora você deve ver no console:

Descrição: Parcialmente nublado
Temperatura: 34.000000

Precisamos a classe Tempo também apenas porque estamos usando JAXB. Tudo transparente, muito fácil agora fazer teste unitários de serviços RESTful!

Two components with the same name and precedence

January 8th, 2009

Há um tempo atrás me pediram ajuda com a seguinte exceção:

java.lang.IllegalStateException: Two components with the same name and precedence - component name: authenticator, component classes: com.app.security.Authenticator, com.app.security.Authenticator
at org.jboss.seam.init.Initialization.addComponentDescriptor(Initialization.java:596)
at org.jboss.seam.init.Initialization.installScannedComponentAndRoles(Initialization.java:949)
at org.jboss.seam.init.Initialization.scanForComponents(Initialization.java:889)
at org.jboss.seam.init.Initialization.init(Initialization.java:701)
at org.jboss.seam.servlet.SeamListener.contextInitialized(SeamListener.java:35)

Essa exceção pode ocorrer, claro, quando existirem duas classes com o mesmo @Name, ou pode ocorrer num caso mais sutil. O Seam possui um modo de debug em que ele faz hot deploy de páginas Facelets e pages.xml’s. Projetos criados pelo seam-gen já vêm com esse modo habilitado:

<core:init debug="true"/>

Nesse modo o Seam usa um classloader próprio ao invés do classloader do container para carregar as classes. Ele faz isso criando um pasta WEB-INF/dev de onde carrega as classes. Isso não vale para EJB3 (então sem hot deploy de entity beans..) e as classes não serão visíveis para o container ou para outros projetos Seam (já que o Seam usa uma instância própria de classloader).

O problema é que de algum jeito o Seam (na verdade deve ser o JBoss Tools) se confunde em algumas situações e tenta fazer um novo deploy do componente, ao invés de fazer um redeploy. Com isso há um conflito de @Name. Não consegui identificar em que casos exatamente isso ocorre. Fazer um Clean, Build, etc não adianta porque a pasta dev não é mexida.

Bom, para resumir, basta apagar a pasta WEB-INF/dev ;)