segunda-feira, 27 de julho de 2015

Liferay 6.1 (6.2 ?) quem tem este papel?

h1. Papéis atrelados à usuários e webcontents

Justificativa:
- Ausência de ferramentas no Liferay para identificar quais são os usuários de um determinado papel (role)
- Dificuldade em encontrar os webcontent que possuem permissão de um determinado papel

Solução
- Feita em velocity com Estrutura e Modelo de Webcontent para nao ter deploy de portlet
- Ambas foram criadas no contexto Global para poder ser incluída em qualquer site
- A busca é feita no site em que o webcontent (com a estrutura e modelo) está sendo executado
- utiliza somente serviços expostos pelo liferay
- não verifica permissão do usuário logado

Como Usar:
- Basta digitar o nome completo do Papel e apertar enter (submeter o formulário)

Informações ténicas:
- A Estrutura possui apenas um campo texto (não indexado) chamado void (ou qq outro nome).
- O modelo tem o seguinte código:

#set ($portletId = $request.theme-display.portlet-display.id)
#set ($roleName = $getterUtil.getString($request.get("parameters").get("roleName")))
<form method="get">
<input type="hidden" name="p_p_id" value="$portletId">
<label class="aui-field-label" for="roleName"> Role:
    <span class="taglib-icon-help">
    <img alt="" aria-labelledby="kzka" onblur="Liferay.Portal.ToolTip.hide();" onfocus="Liferay.Portal.ToolTip.show(this);" onmouseover="Liferay.Portal.ToolTip.show(this);" src="http://portal-d.tjsc.jus.br/portal-servidor-theme/images/portlet/help.png" tabindex="0">
    <span class="aui-helper-hidden-accessible tooltip-text" id="kzka">
    Digite o nome completo das roles separadas por ponto e vírgula sem espaço entre elas</span></span>
</label>
<input name="roleName" id="roleName" class="aui-field-input aui-field-input-text" style="width: 100%;" value="$roleName">
</form><BR>

#set($roleLocalService = $serviceLocator.findService("com.liferay.portal.service.RoleLocalService"))
#set ($companyId = $getterUtil.getLong($companyId))

#set ($groupId = $getterUtil.getLong($groupId))
#set($userLocalService = $serviceLocator.findService("com.liferay.portal.service.UserLocalService"))
#set($userGroupRoleLocalService = $serviceLocator.findService("com.liferay.portal.service.UserGroupRoleLocalService"))
#set($resourcePermissionLocalService = $serviceLocator.findService("com.liferay.portal.service.ResourcePermissionLocalService"))
#set($journalArticleLocalService = $serviceLocator.findService("com.liferay.portlet.journal.service.JournalArticleLocalService"))

#foreach($role in $roleName.split(";"))
    #set($role_u1 = "")
    #set($role_u1_id = 0)
    #set($role_u1 = $roleLocalService.getRole($companyId, $role))
    #set($role_u1_id = $role_u1.getRoleId())
    #if (!($role_u1_id > 1))
    Role <b>$role</b> não encontrada<BR>
    #else
        Role <b>$role</b> (id $role_u1_id) encontrada:<BR>
        #set($usersInRole = "")
        #set($siteUserGroupRoles = "")
        #set($siteUserGroupRoles = $userGroupRoleLocalService.getUserGroupRolesByGroupAndRole($groupId, $role_u1_id))
        #if ($siteUserGroupRoles.size() > 0) ##site role
            Total de usuarios: $siteUserGroupRoles.size()<br>
            #foreach($userGroupRole in $siteUserGroupRoles)
                #set($usr = $userGroupRole.getUser())
                    - $usr.getFullName()<BR>
            #end
        #else ##organization role
            Global Role detected!<BR>
            #set($siteUserGroupRoles = "")
            #set($users = $userLocalService.getRoleUsers($role_u1_id))
            Total de usuarios: $users.size()<br>
            #foreach($usr in $users)
                    - $usr.getFullName()<BR>
            #end
        #end
        #set($resources = $resourcePermissionLocalService.getRoleResourcePermissions($role_u1_id))
        Total de objetos (incluindo web contents): $resources.size()<br>
        Lista de Web Contents:<BR>
        #foreach($rscr in $resources)
            #if ($rscr.getName()=="com.liferay.portlet.journal.model.JournalArticle" && $rscr.getPrimKey()!=$companyId)
                #set ($artPrimKey = $getterUtil.getLong($rscr.getPrimKey()))
                #set($ja = $journalArticleLocalService.getLatestArticle($artPrimKey))
                - $artPrimKey - <a href="$ja.getUrlTitle()">$ja.getTitle($ja.getDefaultLocale())</a><BR>
            #end
        #end

    #end
    <hr>
#end



Pontos de Atenção:
- Não é possível "esconder" (retirar as permissões) de todos pois alguns papéis tem direito de ver qualquer webcontent e/ou qualquer publicador de conteudo web. É bom estar atento mas não há nenhuma criticidade em mostrar quais usuários possuem quais papéis

Melhorias futuras:
- exibir link com URL da página em que o webcontent está
- numa versao futura poderia haver seleção do site ou buscar em todos, assim seria possível buscar por qualquer role a partir de qualquer site.

sexta-feira, 16 de janeiro de 2015

Passando o Pool de Conexões de Banco de Dados do Liferay 6.1 e para o Tomcat 7

Em teoria, a única diferença entre ter um container gerenciador do pool de conexões com o banco de dados ao invés de tê-lo na aplicação é ter possibilidade de monitorar a carga do pool usando interfaces padrão (JBoss console, ou visualVM). Dessa forma o administrador da aplicação pode avaliar e tomar decisão de aumentar o pool, caso necessário. Outra vantagem é poder trocar de servidor de banco de dados (Oracle para MySQL, por exemplo). A desvantagem é que se você usa spring, você vai ter mais trabalho para configurar testes do data source JNDI na suas unit tests (veja aqui)

Utilizamos a mesma classe (com.mchange.v2.c3p0.ComboPooledDataSource) que o liferay utiliza porém sem a customização que Liferay faz para incluir logs e já notamos alguma melhora na performance. Há outros gerenciadores de pool de conexões JNDI mas não chegamos a fazer testes com nenhum deles.

Para remover pool de conexões do Liferay 6.1 e passar para o Tomcat precisamos:

1) Parar o Liferay

2) Criar (ou editar caso já exista) o arquivo
liferay/apache-tomcat-7.x.xx/conf/Catalina/localhost/ROOT.xml
(não se se faz diferença, mas ROOT.xml maiúsculo!)

<Context path="" crossContext="true">
<Resource name="jdbc/liferayPool" auth="Container" type="com.mchange.v2.c3p0.ComboPooledDataSource"
maxPoolSize="100" minPoolSize="10" acquireIncrement="5" initialPoolSize="20" maxIdleTimeExcessConnections="3600"
idleConnectionTestPeriod="180"
debugUnreturnedConnectionStackTraces="true" unreturnedConnectionTimeout="300"
factory="org.apache.naming.factory.BeanFactory" description="Liferay JNDI Pool"
user="user" password="password" driverClass="oracle.jdbc.driver.OracleDriver"
jdbcUrl="jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=host)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=service_name)))"/>
</Context>


3) Editar o arquivo portal-ext.properties
- comentar os parâmetros:
#jdbc.default.driverClassName
#jdbc.default.url
#jdbc.default.username
#jdbc.default.password
- incluir o parâmetro
jdbc.default.jndi.name=jdbc/liferayPool

Note que o jndi.name é o mesmo nome dado no Resource do arquivo ROOT.xml

5) Iniciar o Liferay

Saravá!

Mais informações nas documentações oficiais:
http://tomcat.apache.org/tomcat-7.0-doc/jdbc-pool.html
http://tomcat.apache.org/tomcat-7.0-doc/jndi-resources-howto.html
http://tomcat.apache.org/tomcat-7.0-doc/jndi-datasource-examples-howto.html
http://www.mchange.com/projects/c3p0/

Dicas extras:
http://javaguru.fi/blog/-/blogs/configuring-c3p0-connection-pool-for-liferay-on-tomcat
https://www.liferay.com/pt/web/pmesotten/blog/-/blogs/database-connection-pool-sharing-between-portal-and-portlets
http://www.tomcatexpert.com/blog/2010/04/01/configuring-jdbc-pool-high-concurrency

quarta-feira, 10 de dezembro de 2014

Backup do Liferay 6.1 - Cópia do ambiente Produção para Homologação

Neste post anoto passo a passo como foi feita a cópia do ambiente de produção para homologação
Antes de tudo, foi feito um backup da base de dados e de toda a instalação do Liferay do ambiente de homologação. Não foi necessário parar o ambiente de produção em nenhum momento.
  • Paramos o ambiente de homologação
  • Mantivemos em homologação os arquivos de configuração que não poderiam ser sobrescritos pelos de produção:
  liferay/portal-ext.properties
  liferay/apache-tomcat-7.xxx/bin/setenv.sh
  liferay/apache-tomcat-7.xxx/conf/server.xml
  liferay/apache-tomcat-7.xxx/conf/web.xml
  liferay/apache-tomcat-7.xxx/webapps/ROOT/WEB-INF/classes/system-ext.properties
  liferay/data/license (toda a pasta)

Como não paramos o ambiente de produção, a ordem dos próximos passo é fundamental:
  • Copiamos o banco de dados de produção sobre o de homologação
  • Copiamos a pasta liferay/data/ de PRD para HML
  • Copiamos toda a pasta liferay/apache-tomcat-7.xxx de PRD para HML
  • Devolvemos para a origem em HML todos os arquivos que reservamos no segundo passo.
  • Update na tabela dos web contents para alterar alguma URL que não tivesse endereço relativo
    • update journalarticle set content = replace(content,'endereco-do-portal-de-producao.com.br','endereco-do-portal-de-homologacao.com.br') where content like '%endereco-do-portal-de-producao.com.br%';
Com isso trouxemos todos os deploys e dados do ambiente de produção para homologação, tendo uma cópia real do ambiente ; )

#saravá

quarta-feira, 3 de dezembro de 2014

Liferay Plugin EXT com possibilidade de undeploy

O Liferay é tão flexível que podemos sobrescrever suas classes apenas substituindo-as em um plugin EXT. Entretanto, esse tipo de ação sempre foi desencorajada nos cursos, treinamentos e documentações da Liferay e deve ser usado apenas em último caso e apenas caso não seja possível fazê-lo com um hook ou criando seu próprio portlet. Além disso, sobrescrever uma classe é um caminho sem volta e remover o EXT implicariam em reinstalar o Liferay do zero.

Antes de criar qualquer Plugin EXT leia bem o tópico no link a seguir:
https://www.liferay.com/pt/documentation/liferay-portal/6.1/development/-/ai/ext-plugi-4
Eu aprendi da pior maneira que tinha que apagar todos os arquivos em docroot/WEB-INF/ext-web/docroot/WEB-INF que não estão sendo customizados!

Assim, este post registra como criar um plugin EXT apenas estendendo as funcionalidades do Liferay, criando um ext-spring.xml onde alteramos o comportamento de um bean específico fazendo o Liferay utilizar a nossa nova classe ao invés de sobrescrever uma classe original.

Todos os beans de classes do Liferay estão disponíveis no portal-impl/src/META-INF/portal-spring.xml do fonte. Basta ir até esse arquivo,

  1. copiar apenas o bean que gostaria de estender
  2. colar no seu docroot/WEB-INF/ext-impl/src/META-INF/ext-spring.xml (não se esqueça de copiar a tag <beans> mais externa!) 
  3. alterar o nome da classe que implementa esse bean!
Para fazer o deploy basta gerar o war, copia-lo para a pasta deploy e reiniciar o liferay

Já para o undeploy o Liferay é meio burrinho. É preciso parar o Liferay e apagar tudo manualmente (ou por script). Mas note que o "undeploy" só é possível porque não fizemos nenhuma modificação nas classes do Liferay, estamos apenas incluindo um novo comportamento.


tomcat_home="./tomcat"
app_name="$1"

rm -rf $tomcat_home/temp
rm -rf $tomcat_home/work
rm -rf $tomcat_home/webapps/$app_name-ext
rm -rf $tomcat_home/webapps/ROOT/html/portlet/ext
rm -f $tomcat_home/lib/ext/ext-$app_name-ext-service.jar
rm -f $tomcat_home/webapps/ROOT/WEB-INF/lib/ext-$app_name-ext-util-bridges.jar
rm -f $tomcat_home/webapps/ROOT/WEB-INF/lib/ext-$app_name-ext-util-taglib.jar
rm -f $tomcat_home/webapps/ROOT/WEB-INF/lib/ext-$app_name-ext-util-java.jar
rm -f $tomcat_home/webapps/ROOT/WEB-INF/lib/ext-$app_name-ext-impl.jar
rm -f $tomcat_home/webapps/ROOT/WEB-INF/ext-$app_name-ext.xml
rm -f $tomcat_home/webapps/ROOT/WEB-INF/tiles-defs-ext.xml



fontes:

quarta-feira, 26 de novembro de 2014

Encontrando todas as paginas de um web content

Encontrando todas as paginas em que um determinado web content é exibido
Find all pages where an specified web content is showed

select pp.portletid, l.groupid, l.friendlyurl, l.typesettings 
from portletpreferences pp join layout l 
using (plid) 
where pp.portletid like '56_INSTANCE%' 
and xmltype(pp.preferences).extract('/portlet-preferences/preference[name="articleId"]/value/text()').getStringVal() = YOUR_WEBCONTENT_ID  
and l.typesettings like '%' || pp.portletid || '%' 
order by l.groupid

(SQL for Oracle)

quarta-feira, 18 de junho de 2014

Como colocar SyntaxHighlighter no blogspot / blogger

Nas configurações do Modeleo, edite o HTML e inclua essas linha antes do </head>



depois é só usar a tag <pre class="brush: javascript"> substituindo "javascript" pela linguagem adequada e zaz!

#saravá

Intro

Primeiro post! Usarei esse esse espaço para anotar e compartilhar minhas buscas por tecnologias e soluções. Post rápidos e diretos. A ideia é não ter que procurar duas vezes a mesma coisa. Quando eu pensar: "humm, acho q já fiz isso alguma vez na vida", venho aqui para procurar primeiro.

iiiits time!! (Bruce Buffer anunciando a presença de código)
Já nem me lembro quantas vezes procurei expressão regular pra validar email e data. Então (já estou com a tela aberta!) lá vai a primeira nota para javascript, mas vale pra quase tudo com alguma adaptação.
function isEmail(currentFieldValue){
  var emailregex = /^([a-zA-Z0-9_.+-])+\@(([a-zA-Z0-9-])+\.)+([a-zA-Z0-9]{2,4})+$/;
  return emailregex.test(currentFieldValue);
}
http://regexr.com/3912g

Essa de data é bruta! Valida formatos de data com dois dígitos para dia e mes e ano com 4 dígitos dd/mm/aaaa e valida até ano bissexto!!
var dataregex = ^(((0[1-9]|[12]\d|3[01])\/(0[13578]|1[02])\/((19|[2-9]\d)\d{2}))|((0[1-9]|[12]\d|30)\/(0[13456789]|1[012])\/((19|[2-9]\d)\d{2}))|((0[1-9]|1\d|2[0-8])\/02\/((19|[2-9]\d)\d{2}))|(29\/02\/((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))))$;
http://regexr.com/3912a

Ah! Já que comecei falando de javascript, outro dia encontrei esse site, o regexr.com pra validar e testar expressões regulares! Muito bom! Também encontrei esse outro, o http://regexlib.com/, com um memorável banco de expressões regulares.

http://regexr.com
http://regexlib.com/


#SaraváTech