Friday, August 6, 2010Scuzi, questo articolo non sta disponibile in italiano.
Scuzi, questo articolo non sta disponibile in italiano.
Scuzi, questo articolo non sta disponibile in italiano.
Quick Tip, la configurazione di Ubuntu keyboard layout inglese internazionale(EUA).
sudo gedit /usr/lib/gtk-2.0/2.10.0/immodule-files.d/libgtk2.0-0.immodules
Trova la riga qui sotto e aggiungere :en alla fine della riga come segue:
"/usr/lib/gtk-2.0/2.10.0/immodules/im-cedilla.so" "cedilla" "Cedilla" "gtk20" "/usr/share/locale" "az:ca:co:fr:gv:oc:pt:sq:tr:wa:en"
Salva il file, a questo punto, le applicazioni GTK, ora fissata per applicazioni QT.
Cambia il file "Compose" cambianto tutte le ocorenze de ć e Ć para ç e Ç.
sudo gedit /usr/share/X11/locale/en_US.UTF-8/Compose
Dopo aver cambiato tutte le istanze fai reboot del tuo sistema.
Abbracci.
Ronaldo.
Ciao amici.
Esempio di una classe denominata SharedObjectManager, che è il controllo di accesso di un utente in una applicazione Flex, che memorizza i dati di login di un utente SharedObject nella macchina dell'utente, in cui per chiudere la finestra o premere F5 nel browser , l'utente rimane connesso.
Nota: Utilizzare questa classe con due moduli (Login e Main) in Main modulo è la principale applicazione. Questa classe è possibile implementare la logica di business che hanno bisogno.
LoginModelo è un semplice VO che memorizza le informazioni degli utenti, è necessario personalizzare in base alle vostre necessità.
package br.com.ronaldorigoni.model{
import mx.collections.ArrayCollection;
public class LoginModelo{
private var _id:uint;
public function set id (value:uint):void{
{
_id = value;
}
public function get id ():uint{
return _id;
}
private var _login:String;
public function set login (value:String):void{
{
_login = value;
}
public function get login ():String{
return _login;
}
private var _password:String;
public function set password (value:String):void{
{
_password = value;
}
public function get password ():String{
return _password;
}
private var _permissions:ArrayCollection;
public function set permissions (value:ArrayCollection):void{
{
_permissions = value;
}
public function get permissions ():ArrayCollection{
return _permissions;
}
}
}
E la classe SharedObjectManager:
package br.com.ronaldorigoni.sharedObject{
import br.com.ronaldorigoni.model.LoginModelo;
import flash.net.SharedObject;
/**
* Classe que faz o controle de login de um usuário na aplicação.
* Basea-se em carregamento de dois modulos, login e main.
* @autor Ronaldo Rigoni.
**/
public class SharedObjectManager{
/**
* Objeto SharedObjetc privado.
**/
private static const SHARED_OBJECT:SharedObject = SharedObject.getLocal("userSharedObject");
public function SharedObjectManager(){
}
/**
* Funcao init(). Verifica se o usuário ja está autenticado na aplicação
* E controla qual modulo será carregado.
* Se ja estiver logado será o modulo principal.
* Caso contrario será exibido a tela de login.
**/
public function init():void{
if(verificarStatusLogin()){
loadMainModule();
}
else{
loadLoginModule();
}
}
/**
* Limpa o sharedObject se o mesmo não estiver nulo.
**/
private function clearSharedObject(event:Event):void{
if(SHARED_OBJECT != null){
SHARED_OBJECT.clear();
SHARED_OBJECT.flush();
}
}
/**
* Verifica status de login na aplicação.
* Aqui você pode aplicar outras regras de negocio
* para validar se o usuário esta logado ou nao,
* como por ex: tempo do ultimo login se ainda está valido...
**/
private function verificarStatusLogin():Boolean{
if(SHARED_OBJECT != null){
if(SHARED_OBJECT.data.loginModelo)
return true;
}
return false;
}
/**
* Carrega o modulo de login.
**/
private function loadLoginModule():void{
// codigo para carregar seu modulo de login
}
/**
* Carrega o modulo principal da aplicação se o usuário
* estiver autenticado.
**/
private function loadMainModule(loginModelo:LoginModelo = null):void{
// se loginModelo for null significa que usuário já está logado.
if(loginModelo != null){
saveLoginModelo(loginModelo);
}
// aqui codigo para carregar seu modulo principal
}
/**
* Salva os dados de login do usuário.
* @param loginModelo LoginModelo
**/
private function saveLoginModelo(loginModelo:LoginModelo):void{
SHARED_OBJECT.data.loginModelo = loginModelo;
SHARED_OBJECT.flush();
}
/**
* Recupera as informacoes de login.
* @return <code>loginModelo</code> caso estiver autenticado
* <code>null</code> caso não estiver autenticado
**/
public function retrieveLoginModelo():LoginModelo{
if(SHARED_OBJECT != null){
var modelo:LoginModelo = SHARED_OBJECT.data.loginModelo as LoginModelo;
return modelo;
}else{
return null;
}
}
}
}
Un abbraccio e fin'altro post.
Ronaldo.
Ciao amici,
Quick Tip,
Se si desidera eseguire un JAR da console in modo che il console non si "blocca", questo spesso accade quando si avvia un servizio remoto java è necessario chiudere i flussi in uscita del sistema di classe Java System come giù.
/**
* Fecha o fluxo de saida para o console.
*/
private static void closeOutStreams(){
System.out.close();
System.err.close();
}
Doppo questo, puoi inicializare il tuo Jar come giù.
java -jar mio.jar &
Ronaldo.
Ciao amici,
Affrontiamo una serie di post su JQuery, in quanto l'introduzione di avanzate layout effetti e Ajax e la personalizzazione di plugin.
Cosa sei JQuery?
Qual è la finalitá di JQuery?
JQuery è in conformità con tutti gli standard fissati dal W3C Web, offre un supporto completo per CSS3, la libreria è compatibile con qualsiasi browser (cross browser). JQuery mira ad aumentare gradualmente e non ostruttiva di usabilità e accessibilità.
Nota: Questo non significa che tutto il codice scritto con Jquery è un codice valido secondo Standard WEB, che è per ogni developer di scrivere i loro codici in conformità con gli standard e l'accessibilità.
Caratteristiche principali:
JQuery non ha bisogno di installazione, si utilizza la libreria semplicemente accedere al sito Jquery.com scaricare la versione "minified", che è un file compresso, al momento di scrivere questo post la versione stabile attuale è la 1.3.1, dopo aver scaricato il libreria per il collegamento JS file devono farlo entro questo modo:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <script type="text/javascript" charset="UTF-8" src="js/jquery-1.3.1.min.js"></script> <title>Hello word JQuery</title> </head> <body> </body> </html>
Dopo questo si crea un altro file JavaScript che creare il nostro primo HelloWord in Jquery. Crea la directory del vostro progetto un js file chiamato helloword.js, e aggiungere il seguente codice al suo interno:
/**
* O Construtor da jquery é baseado no caracter $
* Todo seletor deve passar por ele, neste caso estamos passando
* o próprio document e quando o document terminar de carregar oque
* estiver dentro da função passada como parametro será executado.
*/
$(document).ready(function(){
// Exibindo mensagem logo apost termino de carregamento
// da página
alert('A pagina terminou de carregar, Hello Word');
});
Per questo a lavorare per cambiare la head della pagina HTML, come di seguito:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <script type="text/javascript" charset="UTF-8" src="js/jquery-1.3.1.min.js"></script> <script type="text/javascript" charset="UTF-8" src="js/helloword.js"></script> <title>Hello word JQuery</title> </head> <body> </body> </html>
Nel prossimo post ci sarà abordiamo la JQuery sintassi, e come l'utilizzare i selettori JQuery.
Abbracci e fin'altro post.
Ronaldo.
Verzione in italiano.
Ciao a tutti, semplice modo di lavorare con Xml Sockets tra Java e Flex.
Chesto post facciamo um exempio di uso del framework Apache Mina che implementa la nuova API di Java NIO, che è stato molto ottimizzato il trattamento di IO in Java.
Apache MINA ( A Multi-purpose Infrastructure for Network Applications).
Cosa sei Xml Sockets?
Ci sono due tipi di connessioni possibili presa in ActionScript 3.0: Connessioni tramite XML Sockets e Binaty Socket. Il XML vi permette di connettersi a un server remoto e creare una connessione al server che rimane aperta fino al esplicitamente chiusa. Ciò permette lo scambio di dati XML tra un server e un client senza la necessità di aprire nuove connessioni al server. Un altro vantaggio di usare XML è necessario che l'utente non esplicitamente richiesta dati. È possibile inviare i dati dal server senza richieste e inviare i dati ad ogni client collegato al Socket XML.
Le connessioni socket XML, richiedono la presenza di una politica di Socket sul server di destinazione.
Fai il download del Apache mina Mina qui
Creare un progetto Java e aggiungere i vasi di mine nel tuo classpath.
La miniera ha già attuato una Procolo chiamato TextLineCodecFactory basato su Procolo di puro testo, dove alla fine di ogni richiesta è un \n o uno INVIO.
Ma questo non ci aiuta molto, per attuare a la nostra volontà di facciamo un protocollo chiamato XmlProtocolCodecFactory e poi attuare il nostro server e Handler riceverà processo e le richieste.
Qui la creazione di XmlDecoder, responsabile per la decodifica e l'elaborazione di una richiesta e fare il Cat a un Document.
package br.com.ronaldorigoni.mina.codec;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolDecoderAdapter;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
/**
* Decoder de XML, responsável por interceptar a requisiçao do usuário
* e transformar a mesma em um Objeto DOM, e passar o mesmo para o Handler
* manipular.
* @author Ronaldo Rigoni
*/
public class XmlDecoder extends ProtocolDecoderAdapter {
/**
* Decodifica a requisiçao e passa a mesma para o handler.
*/
public void decode(IoSession session, IoBuffer buffer, ProtocolDecoderOutput output) throws Exception {
output.write(parserXML(buffer));
}
/**
* Efetua o parser dos bits recebidos e transforma em um Document
* @param xmlBuffer O Buffer de entrada.
* @return O documento xml
* @throws ParserConfigurationException Caso nao consiga efetuar o parser.
* @throws SAXException Caso houver erro da biblioteca SAX
* @throws IOException Caso ouver erro de IO
*/
public Object parserXML(IoBuffer xmlBuffer) throws ParserConfigurationException, SAXException, IOException {
// captura os bits da requisicao e aloca
byte[] data = new byte[xmlBuffer.limit()];
xmlBuffer.get(data);
// transforma em string removendo espacoes em branco
String xml = new String(data).trim();
// cria o documento e retorna.
Document document = DocumentBuilderFactory.newInstance().
newDocumentBuilder().parse(new ByteArrayInputStream(xml.getBytes()));
return (document);
}
}
Qui il XMLEncoder responsabile per la scrittura di bits al client.
package br.com.ronaldorigoni.mina.codec;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.AttributeKey;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoderAdapter;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
import org.apache.mina.filter.codec.textline.LineDelimiter;
/**
* Encoder de XML, responsavel por transformar a saida ao usuário e escrever a mesma.
* @author Ronaldo Rigoni
*/
public class XmlEncoder extends ProtocolEncoderAdapter {
/**
* ENCODER final
*/
private final AttributeKey ENCODER = new AttributeKey(getClass(), "encoder");
/**
* Charset da Requisição
*/
private final Charset charset;
/**
* Delimitador da requisição.
*/
private final LineDelimiter delimiter;
/**
* Tamanho máximo da requisição.
*/
private int maxLineLength = Integer.MAX_VALUE;
/**
* Construtor do Encoder
* Define o Charset e o Delimitador
*/
public XmlEncoder() {
this.charset = this.charset = Charset.forName("UTF-8");
this.delimiter = new LineDelimiter("\0");
}
/**
* Retorna o tamanho maximo da requisição.
* @return O Tamanho maximo da requisição.
*/
public int getMaxLineLength() {
return maxLineLength;
}
/**
* Codifica a saida ao Usuário.
*/
public void encode(IoSession session, Object message,ProtocolEncoderOutput out) throws Exception {
// capturando o charset da sessao.
CharsetEncoder encoder = (CharsetEncoder) session.getAttribute(ENCODER);
// caso for nulo é criado e setado na sessão do usuário.
if (encoder == null) {
encoder = charset.newEncoder();
session.setAttribute(ENCODER, encoder);
}
// mensagem a ser escrita.
// Por se tratar de XML e nao ser nada mais que uma string
// pegamos o toString() dela.
String value = message.toString();
//Cria o buffer de saida.
IoBuffer buf = IoBuffer.allocate(value.length()).setAutoExpand(true);
// adiciona ao buffer de saida a mensagem e o charset
buf.putString(value, encoder);
if (buf.position() > maxLineLength) {
throw new IllegalArgumentException("Tamanho da linha muito grande: " + buf.position());
}
// seta o delimitador \0
buf.putString(delimiter.getValue(), encoder);
// fecha o buffer
buf.flip();
// escreve na saida.
out.write(buf);
}
}
Adesso la nostra fabbrica per la produzione di oggetti per le richieste.
package br.com.ronaldorigoni.mina.codec;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFactory;
import org.apache.mina.filter.codec.ProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolEncoder;
/**
* Classe Factory para Encoder e Decoder de XML utilizando Apache MINA
* @author Ronaldo Rigoni
*/
public class XmlProtocolCodecFactory implements ProtocolCodecFactory {
/**
* Cria um novo Encoder de XML
*/
public ProtocolEncoder getEncoder(IoSession arg0) throws Exception {
return new XmlEncoder();
}
/**
* Cria um novo Decoder de XML
*/
public ProtocolDecoder getDecoder(IoSession arg0) throws Exception {
return new XmlDecoder();
}
}
Adesso la classe del server , che sarà responsabile per l'apertura del PORT per il server per ricevere le richieste degli utenti.
package br.com.ronaldorigoni.mina.core;
import java.net.InetSocketAddress;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;
import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.filter.logging.MdcInjectionFilter;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
import br.com.ronaldorigoni.bingo.codec.XmlProtocolCodecFactory;
import br.com.ronaldorigoni.bingo.config.Config;
/**
* Inicializa o servidor.
*
* @author Ronaldo Rigoni
*/
public class Server {
static Logger logger = Logger.getLogger(Server.class);
private static void start(){
try {// objeto que receberá novas conecoes
NioSocketAcceptor acceptor = new NioSocketAcceptor();
// filtro de requisicoes
DefaultIoFilterChainBuilder chain = acceptor.getFilterChain();
// logger
LoggingFilter loggingFilter = new LoggingFilter();
chain.addLast("logging", loggingFilter);
// injecao do filtro
MdcInjectionFilter mdcInjectionFilter = new MdcInjectionFilter();
chain.addLast("mdc", mdcInjectionFilter);
// atribuicao do protocolo de parser de XML que criamos.
chain.addLast("codec", new ProtocolCodecFilter(new XmlProtocolCodecFactory()));
// adicionando logger.
addLogger(chain);
// adicionando Handler, que tratará as requisiçoes
acceptor.setHandler(new ChatServerHandler());
// setando porta para ouvir.
acceptor.bind(new InetSocketAddress(8090));
logger.debug("Servidor de chat ouvindo na porta:" + 8090);
} catch (Exception e) {
logger.error("Erro ao inicializar servidor de chat.",e);
}
}
/**
* Adiciona um logger para o filtro de requisicoes.
**/
private static void addLogger(DefaultIoFilterChainBuilder chain) throws Exception {
chain.addLast("logger", new LoggingFilter());
}
/**
* Inicializa o servidor de chat.
**/
public static void main(String[] args) {
try {
start();
} catch (Exception e) {
e.printStackTrace();
System.exit(0);
}
}
}
Adesso creare un oggetto a integrare la richiesta chiamata Request , dove si facciono il parser dela richiesta per conoscere il tipo di richiesta ed i parametri in esso contenuti.
package br.com.ronaldorigoni.mina.codec;
import java.io.IOException;
import java.io.StringReader;
import java.util.HashMap;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* Classe para encapsular uma requisição.
* @author Ronaldo Rigoni
*/
public class Request {
private static final Logger logger = Logger.getLogger(Request.class);
//Possíveis campos de um input
public static final String FIELD_USER_NAME = "userName";
public static final String FIELD_USER_LOGIN = "login";
public static final String FIELD_USER_PASSWORD = "password";
public static final String FIELD_TO = "to";
public static final String FIELD_FROM = "from";
public static final String FIELD_MESSAGE = "message";
public static final String OPERATION_CHAT_USER_IN ="add-user-in-chat-room";
public static final String OPERATION_CHAT_USER_IN ="remove-user-in-chat-room";
public static final String OPERATION_CHAT_SEND_MESSAGE ="chat-send-message";
public static final String OPERATION_XML_POLICY ="<policy-file-request/>";
private String operation;
private HashMap<String, String> parameters = new HashMap<String, String>();
private String inputText;
public Request(Document document) {
parseDocument(document);
}
/**
* @return the operation
*/
public String getOperation() {
return operation;
}
/**
* @param operation the operation to set
*/
public void setOperation(String operation) {
this.operation = operation;
}
/**
* @return the parameters
*/
public HashMap<String, String> getParameters() {
return parameters;
}
/**
* @param parameters the parameters to set
*/
public void setParameters(HashMap<String, String> parameters) {
this.parameters = parameters;
}
/**
* @return the inputText
*/
public String getInputText() {
return inputText;
}
/**
* @param inputText the inputText to set
*/
public void setInputText(String inputText) {
this.inputText = inputText;
}
private void parseDocument(Document document){
if(document == null)
throw new NullPointerException("Documento nulo.");
else{
NodeList nodes = document.getDocumentElement().getChildNodes();
for (int i = 0; i < nodes.getLength(); i++) {
if(nodes.item(i).getFirstChild() != null){
logger.debug(nodes.item(i).getNodeName()+","+ nodes.item(i).getFirstChild().getNodeValue());
parameters.put(nodes.item(i).getNodeName(), nodes.item(i).getFirstChild().getNodeValue());
}
}
if(document.getDocumentElement() != null){
this.setOperation("<"+document.getDocumentElement().getTagName()+"/>");
logger.debug("Operation:"+document.getDocumentElement().getTagName());
}
}
}
@Override
public String toString() {
return "Operation:"+getOperation()+",parameters{"+getParameters()+"}";
}
}
Ora creiamo il gestore per le richieste che sarà incaricata di trattare con tutte le richieste da parte degli utenti di entrata e di uscita, accedere a chat, invio di messaggio e l'uscita degli utenti.
package br.com.ronaldorigoni.mina.core;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.log4j.Logger;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.w3c.dom.Document;
import br.com.ronaldorigoni.mina.codec.Request;
/**
* Classe manipuladora de requisiçoes, é onde toda a lógica do chat acontece.
* É nela que toda requisição após passar pelo Codec XML é encaminhado para cá/
* @author Ronaldo Rigoni rrigoni@gmail.com
*
*/
public class ChatHandler extends IoHandlerAdapter {
/** Logger estatico do Handler **/
private static final Logger logger = Logger.getLogger(ChatHandler.class);
/**
* Constante para armazenamento do usuario na sessao.
*/
private static final String USER_NAME = "username";
/**
* XML policy caso a requisicao venha de outro host diferente ao do servidor.
*/
private static final String XML_POLICY = "<cross-domain-policy><allow-access-from domain=\"*\" to-ports=\"8090\"/></cross-domain-policy>";
/**
* Lista para armazenar todas as sessoes de chat.
* Esta lista necessita estar sincronizada pois em um ambiente multi-thread precisamos
* proteger acesso concorrente a mesma.
*/
private List<IoSession> sessions = Collections.synchronizedList(new ArrayList<IoSession>());
/**
* Metodo invocado quando ocorrer alguma exception na escrita de mensagens ou
* no recebimento.
* @param session Sessao do usuario.
* @param cause Exception lancada
*/
@Override
public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
super.exceptionCaught(session, cause);
}
/**
* Metodo que valida um usuario baseado nos seguintes criterios para poder ingressar no chat.
* 1 - Nao pode haver a sessao do usuario na lista de chat.
* 2 - Nao pode haver uma sessao com o mesmo atributo <code>username</code> que a do usuario
* que esta tentando logar.
* @param session A sessao do usuario que requisitou login.
* @return <code>true</code> caso esta apto a ingressar no chat,
* <code>false</code> caso nao esta apto.
*/
private boolean loginUser(IoSession session){
boolean isValid = true;
String userLogin = (String) session.getAttribute(USER_NAME);
if(userLogin != null && userLogin.length() > 5){
if(!sessions.contains(session)){
synchronized (session) {
for(IoSession ses : sessions){
// capturando login da sessao
String username = (String)session.getAttribute(USER_NAME);
if(username.equalsIgnoreCase(userLogin)){
isValid = false;
}
}
}
}
}else{
isValid = false;
}
return isValid;
}
/**
* Invocado a cada mensagem recebida.
* Pelo fato de construirmos um Codec XML o objeto message sempre ser'a uma instancia
* de org.w3c.dom.Document, caso nao for a mensagem ser'a ignorada.
* @param session Sessao do usuario.
* @param message Mensagem recebida.
*/
@Override
public void messageReceived(IoSession session, Object message) throws Exception {
if(message instanceof org.w3c.dom.Document){
// efetuando a conversao do documento recebido.
Document document = (Document) message;
Request request = new Request(document);
if (request.getOperation().equalsIgnoreCase(Request.OPERATION_XML_POLICY)) {
session.write(XML_POLICY);
} else if (request.getOperation().trim().equalsIgnoreCase(Request.OPERATION_CHAT_USER_IN)) {
// adiciona o username na sessao e envia para login.
session.setAttribute(USER_NAME,request.getParameters().get(USER_NAME));
boolean logged = loginUser(session);
if(!logged){
session.write("<forbiden/>");
}else{
// adiciona usuario nas sessoes do chat.
sessions.add(session);
//processa entrada do usuario.
processUserEnterInChat(session);
}
}else if(request.getOperation().trim().equalsIgnoreCase(Request.OPERATION_CHAT_USER_EXIT)){
// remove sessao do usuario da lista de sessoes do chat.
sessions.remove(session);
// processa saida do usuario
processUserExitInChat(session);
// fecha sessao do usuario.
session.close(true);
}else if(request.getOperation().trim().equalsIgnoreCase(Request.OPERATION_CHAT_SEND_MESSAGE)){
String chatMessage = request.getParameters().get(Request.FIELD_MESSAGE);
// processa mensagem de chat.
processChatMessage(chatMessage, session);
}
}else{
logger.error("Formato da requisicao invalido.");
}
}
/**
* Processa o envio de uma mensagem de chat.
* @param message Mensagem
* @param session Sessao do usuario que est'a enviando.
*/
private void processChatMessage(String message, IoSession session){
logger.debug("Usuario:"+session.getAttribute(USER_NAME)+" enviou mensagem:"+message);
writeBroadCastChatMessage(message);
}
/**
* Processa a entrada de um usu'ario no chat.
* @param session Sessao do usuario.
*/
private void processUserEnterInChat(IoSession session){
StringBuffer buff = new StringBuffer("<response>");
buff.append("<type>user-enter-in-chat</type>");
buff.append("<username>"+session.getAttribute(USER_NAME)+"</username>");
buff.append("</response>");
writeBroadCastChatMessage(buff.toString());
}
/**
* Processa a sa'ida de um usu'ario no chat.
* @param session Sessao do usuario.
*/
private void processUserExitInChat(IoSession session){
StringBuffer buff = new StringBuffer("<response>");
buff.append("<type>user-exit-in-chat</type>");
buff.append("<username>"+session.getAttribute(USER_NAME)+"</username>");
buff.append("</response>");
writeBroadCastChatMessage(buff.toString());
}
/**
* Envia uma mensagem de chat para todos os usuarios.
* @param message A mensagem.
*/
private void writeBroadCastChatMessage(String message){
synchronized (sessions) {
for(IoSession session : sessions){
session.write(message);
}
}
}
/**
* Invocao apos uma mensagem ser enviada com sucesso.
* Aqui poderemos estar efetuando um log das mensagens que foram enviadas, ou descartarmos.
* @param session Sessao de destino da mensagem
* @param message Mensagem enviada.
*/
@Override
public void messageSent(IoSession session, Object message) throws Exception {
logger.debug(session+" envia >>> "+message);
}
/**
* Metodo invocado quando a sessao do usuario for fechada, quando o socket do cliente for fechado ou
* pelo servidor de chat ou pelo cliente.
* Aqui poderemos remover atributos da sessao do usuario, ou quaisquer operacoes que precisarmos quando
* o mesmo se desconectar.
* @param session Sessao do Usuario.
*/
@Override
public void sessionClosed(IoSession session) throws Exception {
// quando conexao fechada 'e processado a saida do usuario.
logger.debug("Sessao fechada:"+session);
processUserExitInChat(session);
}
/**
* Metodo invocado quando um usuario solicitar uma conexao, (quando ela for criada).
* @param session Sessao do usuario.
*/
@Override
public void sessionCreated(IoSession session) throws Exception {
logger.debug("Sessao criada:"+session);
super.sessionCreated(session);
}
/**
* Invocado quando uma sessao entrar em timeout.
* @param session Sessao do usuario
* @param status Status da sessao.
*/
@Override
public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
logger.debug("Sessao em timeout:"+session);
super.sessionIdle(session, status);
}
/**
* Metodo invocado quando uma sessao for aberta.
* @param session Sessao do usuario.
*/
@Override
public void sessionOpened(IoSession session) throws Exception {
logger.debug("Sessao aberta:"+session);
super.sessionOpened(session);
}
}
<span>
Tutta la partei server è stata completata, in un prossimo post facciamo il client in Adobe Flex e la integrazione del server con il client.
Abbraccio, Ronaldo.
Dubbi ? ronaldo@ronaldorigoni.com.br
[/sourcecode]
[/sourcecode]
Verzione in italiano.
Dopo molti post e tutoriai in internet, per generare video FLV a partire dei formati AVI, MPEG, MPG, WMV, MOV, ha creato una classe per convertire i video e la generazione di immagini dal video (tumbnails di video), al di sotto del codice di condividere con voi.
Per prima cosa è necessario avere installato sul proprio sistema (Linux) le seguenti librerie, eseguire il seguente comando come user root sulla console:
sudo apt-get install libfaad-dev libmp3lame-dev libmp3lame0 libfaac-dev libfaad2-dev
Só agora instale o ffmpeg:
sudo apt-get install ffmpeg
La classe di seguito utilizza il Singleton Design Pattern, dove solo una singola istanza del convertitore di video sarà attivo perché si tratta di un processo che utilizza molte funzioni del sistema operativo è stato scelto di creare un thread che converte un video alla volta, gli altri sono in lista d'attesa.
La seguente classe in questione, sottolineando che non è stata affrontata qui il JavaBean Media, che contiene solo due attributi "path" e "destinazione" con i loro Getters e setter. Proprio questo fagiolo e modificare il codice della thread.
package br.com.ronaldorigoni.videoconverter.util;
import br.gov.mec.portaldoprofessor.client.cms.JornalRemote;
import br.gov.mec.portaldoprofessor.client.vo.MidiaAProcessar;
import java.io.IOException;
import java.io.InputStream;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.naming.InitialContext;
import org.apache.log4j.Logger;
/**
* Classe utilitária para conversão de vídeos usando a biblioteca natíva <code>ffmpeg</code>.
* Utiliza o mecanismo de pool de conversão.
* Para um correto funcionamento deve-se instalar a biblioteca com as seguintes dependências.
* ffmpeg - A própria biblioteca
* libfaad-dev - Biblioteca de desenvolvimento de áudio é vídeo.
* libfaac-dev - Biblioteca de desenvolvimento para otimizaçãoes no streaming de áudio.
* libfaad2-dev - Biblioteca de desenvolvimento de áudio e vídeo versão dois.
* Testado em ambiente Ubuntu - Debian
* @author Ronaldo Rigoni
*/
public class VideoConverter {
/**
* Logger statico para o Conversor de Vídeo
*/
private static final Logger logger = Logger.getLogger(VideoConverter.class);
/**
* Pool de mídias a converter.
*/
private static final List<Midia> midiasAProcessar = new ArrayList<Midia>();
/**
* Adiciona uma midia no pool.
* @param midia Midia a converter.
*/
public void addMediaInPool(MidiaAProcessar midia) {
midiasAProcessar.add(midia);
}
/**
* Thread responsável por verificar a todo momento se existem vídeos a serem convertidos
* Caso possuir algum vídeo, efetua a conversão gera as imágens do respectivo vídeo,
* atualiza em banco as informaçãoes da mídia e notifica ao usuário que inseriu este vídeo.
*/
private Runnable worker = new Runnable() {
public void run() {
while (true) {
if (!midiasAProcessar.isEmpty() &amp;amp;&amp;amp; midiasAProcessar.get(0) != null) {
MidiaAProcessar midiaAProcessar = midiasAProcessar.get(0);
String command = command(midiaAProcessar.getCaminho(), midiaAProcessar.getDestino());
String commandCropImagemMedia = commandImagemMedia(midiaAProcessar.getDestino());
String commandCropImagemMicro = commandImagemMicro(midiaAProcessar.getDestino());
Process videoProcess = null;
Process imageMediaProcess = null;
Process imageMicroProcess = null;
try {
videoProcess = Runtime.getRuntime().exec(command);
int code = videoProcess.waitFor();
if (code == 0) {
logger.debug"Gerado video com sucesso.");
} else {
logger.error("Erro ao converter video");
processConsoleOut(videoProcess.getErrorStream());
}
if (code == 0) {
imageMediaProcess = Runtime.getRuntime().exec(commandCropImagemMedia);
int imageMediaCode = imageMediaProcess.waitFor();
if (imageMediaCode == 0) {
logger.debug("Imagem media gerada com sucesso.");
} else {
logger.error("Erro ao gerar imagem media." );
processConsoleOut(imageMediaProcess.getErrorStream());
}
}
logger.debug(" Executando:" amp;amp;quot; + commandCropImagemMicro);
if (code == 0) {
imageMicroProcess = Runtime.getRuntime().exec(commandCropImagemMicro);
int imageMicroCode = imageMediaProcess.waitFor();
if (imageMicroCode == 0) {
logger.debug(" Imagem micro gerada com sucesso." );
} else {
logger.error(" Erro ao gerar imagem micro." );
processConsoleOut(imageMicroProcess.getErrorStream());
}
}
// codigo de saida igual a zero significa sucesso.
if (code == 0) {
// aqui voce pode notificar o usuário que solicitou ao conversão do vídeo
// de que o mesmo ja se encontra disponível, ou tratar de alguma forma
// a conversao com sucesso.
}
} catch (Exception e) {
e.printStackTrace();
}
midiasAProcessar.remove(0);
}
}
}
};
private static VideoConverter instance;
private VideoConverter() {
init();
}
/**
* Inicializa o mecanizmo de conversão de videos.
*/
private void init() {
new Thread(worker).start();
logger.info(" Mecanizmo de vídeos inicializado com sucesso." );
}
/**
* Retorna uma instância singleton do conversor de vídeos.
* @return Instancia singleton VideoConverter
*/
public static synchronized VideoConverter getInstance() {
if (instance == null) {
instance = new VideoConverter();
}
return instance;
}
/**
* Formato MPEG
*/
public static final String MPEG_FORMAT = " mpeg";
/**
* Formato MPG
*/
public static final String MPG_FORMAT = "mpg";
/**
* Formato AVI
*/
public static final String AVI_FORMAT = "avi";
/**
* Formato MOV
*/
public static final String MOV_FORMAT = "mov";
/**Formato WMV **/
public static final String WMV_FORMAT = "wmv";
/**
* Representa o comando para conversão de vídeos AVI
* {0} = Caminho completo do arquivo em disco ( vídeo de entrada).
* {1} = Caminho completo com extenção do arquivo de saída.
* Importante: para otimizar qualidade apenas modifique os parâmetros -qmin e -qmax
* -qmin 0 a 30
* -qmax 0 a 30
* Em todas as hipotezes -qmax deve ser um valor maior que -qmin, -qmin reduz o tamanho do video
* e -qmax assegura manter a qualidade, portando deve ser alto e alterar prefeferivelmente -qmin.
*/
private static final String COMMAND_AVI = "ffmpeg -i {0} -qmin 6 -qmax 26 -ar 22050 -f flv -y {1}";
/**
* Representa o comando para converter um vídeo no formato MOV para FLV.
* {0} = Caminho completo do arquivo em disco ( vídeo de entrada).
* {1} = Caminho completo com extenção do arquivo de saída.
* Apenas altere os parâmetros -qmin e -qmax.
* -qmin 0 a 30
* -qmax 0 a 30
* -s significa o tamanho da saida do vídeo, resolução.
*/
private static final String COMMAND_MOV = " ffmpeg -y -i {0} -vcodec flv -b 400kb -s 500x376 -qmin 10 -qmax 30 -ar 22050 -ac 1 {1} ";
/**
* Representa o comando para converter um vídeo no formato MPG ou MPEG para FLV.
* {0} = Caminho completo do arquivo em disco ( vídeo de entrada).
* {1} = Caminho completo com extenção do arquivo de saída.
* -r frames por segundo
* -s tamanho de saida do vídeo.
*/
private static final String COMMAND_MPG_MPEG = " ffmpeg -i {0} -y -r 25 -b 500k -ar 22050 -s 500x376 -ab 24k {1}";
/**
* Representa o comando para efetuar o crop da imagem media de um vídeo.
* {0} = Caminho completo do arquivo em disco ( vídeo de entrada).
* {1} = Caminho completo com extenção do arquivo de saída.
* -itsoffset representa o segundo em que será efetuado o crop
* -vframes significa o respectivo frame para o segundo expecificado acima
* -s tamanho da imagem. Só aceita medidas pares.
*/
private static final String COMMAND_CROP_VIDEO_IMAGEM_MEDIA = "ffmpeg -itsoffset -10 -i {0} -vcodec mjpeg -vframes 1 -an -f rawvideo -s 130x96 -y {1}";
/**
* Representa o comando para efetuar o crop da imagem pequena de um vídeo.
* {0} = Caminho completo do arquivo em disco ( vídeo de entrada).
* {1} = Caminho completo com extenção do arquivo de saída.
* -itsoffset representa o segundo em que será efetuado o crop
* -vframes significa o respectivo frame para o segundo expecificado acima
* -s tamanho da imagem. Só aceita medidas pares.
*/
private static final String COMMAND_CROP_VIDEO_MICRO_IMAGEM = "ffmpeg -itsoffset -10 -i {0} -vcodec mjpeg -vframes 1 -an -f rawvideo -s 60x46 -y {1}";
/**
* Representa comando de conversão de videos WMV para FLV.
* {0} = Caminho completo do arquivo em disco ( vídeo de entrada).
* {1} = Caminho completo com extenção do arquivo de saída.
* -s = Tamanho do vídeo ( resolução), só aceita medidas pares.
* -qmin e -qmax são parâmetros de qualidade.
* -qmin 0 a 30
* -qmax 0 a 30
*/
private static final String COMMAND_WMV = "ffmpeg -y -i {0} -ar 22050 -ab 32 -s 500x376 -qmin 6 -qmax 26 -f flv -s 320x320 {1}";
/**
* Gera o comando expecífico de acordo com a extenção do arquivo.
* @param videoIn Caminho de entrada do vídeo.
* @param videoOut Caminho de saída do video.
* @return O comando formatado.
*/
private static String command(String videoIn, String videoOut) {
String command = "";
String fileName = videoIn.substring(videoIn.lastIndexOf("/") + 1, videoIn.length());
String extension = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length());
// formato AVI
if (extension.equalsIgnoreCase(AVI_FORMAT)) {
command = new MessageFormat(COMMAND_AVI).format(new Object[]{videoIn, videoOut});
// formato MOV
} else if (extension.equalsIgnoreCase(MOV_FORMAT)) {
command = new MessageFormat(COMMAND_MOV).format(new Object[]{videoIn, videoOut});
// formato MPEG ou MPG
} else if (extension.equalsIgnoreCase(MPEG_FORMAT) || extension.equalsIgnoreCase(MPG_FORMAT)) {
command = new MessageFormat(COMMAND_MPG_MPEG).format(new Object[]{videoIn, videoOut});
// formato WMV
}else if(extension.equalsIgnoreCase(WMV_FORMAT)){
command = new MessageFormat(COMMAND_WMV).format(new Object[]{videoIn, videoOut});
}else {
throw new IllegalArgumentException("Formato de arquivo não suportado:"+extension);
}
return command;
}
/**
* Processa o stream de saída de erros caso alguma conversão não tenha ocorrido com sucesso.
* @param is InputStream
* @throws java.io.IOException Em caso de excessão de IO
*/
private void processConsoleOut(InputStream is) throws IOException {
byte[] buffer = new byte[512];
int bytes = 0;
StringBuffer stringBuffer = new StringBuffer();
do {
buffer = new byte[512];
bytes = is.read(buffer);
if (bytes > 0) {
stringBuffer.append(new String(Arrays.copyOf(buffer, bytes)));
}
} while (bytes >= buffer.length);
String output = stringBuffer.toString();
logger.error(output);
}
/**
* Gera o comando de crop para uma imagem tamanho médio.
* IMPORTANTE: Altere o tamanho para geraçao da sua imagem média para -s alturaXlargura
* @param videoOut Caminho do vídeo.
* @return Comando formatado para crop de imagem média.
*/
private static String commandImagemMedia(String videoOut) {
String imagenOut = videoOut + ".media.jpeg";
String commandImagemMedia = new MessageFormat(COMMAND_CROP_VIDEO_IMAGEM_MEDIA).format(new Object[]{videoOut, imagenOut});
return commandImagemMedia;
}
/**
* Gera o comando de crop para uma imagem micro.
* @param videoOut O caminho completo do vídeo de entrada.
* @return O Comando de crop de imagem micro formatado.
*/
private static String commandImagemMicro(String videoOut) {
String imageOut = videoOut + ".micro.jpeg";
String commandImagemMicro = new MessageFormat(COMMAND_CROP_VIDEO_MICRO_IMAGEM).format(new Object[]{videoOut, imageOut});
return commandImagemMicro;
}
}
Aiutare in qualsiasi modo e avere successo nella loro conversione a video.
Il qualcuno dubbio, ronaldo@ronaldorigoni.com.br
Versione in italiano.
Ciao a tutti.
Che developer non ha iniziato i lavori per rendere unione tra le versioni di un progetto tra due repository di SVN oppure CVS? Un compito spesso difficile, soprattutto se si combinano variazioni quantitative tra i due rami in uno solo.
Per prima cosa istalar il software, verde la console e digita il comando seguinte:
sudo apt-get install meld
Dopo il processo di installazione è stata completato, aprire il software con il comando:
sudo meld
Perché aprire come super user?
Se avete il repository CVS o controllate da Subversion, è necessario per consentire permizione di root per cambiare.
Sotto mostro il lavoro di fondere in un progetto con più file, selezionare la directory come immagine qui sotto:
Dopo di che quando si fa clic su OK, il MELD farà un'analisi di tutti i file e diretori su i due progetti e risultati sul display.
I file che anno conflitto sono segnate in rosso e devono essere risolti, i file segnate in verde sono nuovi file, se questo file è su un progetto e non in un altro.
Per risolvere un conflitto tra due file, fare doppio clic su il file per visualizzare, l'Meld aprira un editor dove è possibile effettuare le modifiche tra i due file per renderli pari schermo come segue:
Per riprodurre i cambiamenti da un luogo all'altro è sufficiente fare clic sulla freccia nel testo segnate in verde.
Per i nuovi file contrassegnati in verde, è sufficiente fare clic su di esso con il tasto destro del mouse e selezionare "Copy to Left" o "Copy to Right",
Meld fà la copia del file su l'altro progetto.
Il Meld mostra tutta la struttura di file e directory che hanno qualche differenza rispetto agli altri progetti.
Dopo aver completato l'intero processo, puoi chiudere la Meld e aprire il tuo progetto con il vostro IDE, e fare il tuo commit.
Importante: Il Meld non modifica i file per il controllo del SVN oppure CVS, poi, quando sincronizzata con il repository CVS o l'SNV individuare cambiamenti nel file ed è possibile effettuare il commit.
Semplice, ma uno software di grande aiuto in caso di grandi progetti e delle differenze, ha salvato la mia vitta più de una volta.
Mi auguro di poter contribuire in qualche modo.
Abbraccio e fino altro post. dubbi? ronaldo@ronaldorigoni.com.br
Ciao.
Salve galera.
Hoje vamos abordar uma forma simples de trabalhar com MVC no Flex com Eventos.
Primeiramente oque é MVC?
Com o aumento da complexidade das aplicações desenvolvidas torna-se fundamental a separação entre os dados (Model) e o layout (View). Esta forma permite que trabalhamos separadamente entre layout e manipulação de dados, tornando flexível alterações no layout sem afetar o Controller e vice-versa.
O MVC resolve um dos maiores problemas entre acoplamento das camadas de acesso a dados e lógica de negócio da aplicação e apresentação de dados ao usuário, pois introduz um componente entre as duas camadas (dados e interface) chamada Controller, o Design Patter MVC está mais ligado a arquitetura da aplicação do que um tipo de padrão de projeto, pois afeta a maneira de como a aplicação será organizada e estruturada.
O MVC não abrange a camada de acesso a dados, pois supõe-se que ela esteja encapsulada dentro do model.
OBS: Camadas dizem como separar os componentes, mas MVC diz como os componentes interagem entre si.
As camadas:
O diagrama representa as seguintes associações:
Fluxo:
Bem vamos a parte prática:
Crie a seguinte estrutura de pacotes:
Agora vamos criar os componentes MXML dentro do pacote view:
&lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot;?&gt;
&lt;mx:Panel title=&amp;quot;Listagem&amp;quot; creationComplete=&amp;quot;init()&amp;quot; xmlns:mx=&amp;quot;http://www.adobe.com/2006/mxml&amp;quot; width=&amp;quot;400&amp;quot; height=&amp;quot;300&amp;quot;&gt;
&lt;mx:List id=&amp;quot;list&amp;quot; width=&amp;quot;100%&amp;quot; dataProvider=&amp;quot;{model.clients}&amp;quot; labelField=&amp;quot;name&amp;quot; height=&amp;quot;100%&amp;quot; /&gt;
&lt;mx:ApplicationControlBar&gt;
&lt;mx:Button id=&amp;quot;btList&amp;quot; label=&amp;quot;Listar&amp;quot; /&gt;
&lt;mx:Button id=&amp;quot;btClear&amp;quot; label=&amp;quot;Limpar&amp;quot; /&gt;
&lt;/mx:ApplicationControlBar&gt;
&lt;mx:Script&gt;
&lt;![CDATA[
import br.com.ronaldorigoni.controller.ListagemController;
import br.com.ronaldorigoni.model.ListagemModel;
[Bindable]
public var model:ListagemModel = null;
public var controller:ListagemController = null;
private function init():void{
model = new ListagemModel();
controller = new ListagemController(this);
}
]]&gt;
&lt;/mx:Script&gt;
&lt;/mx:Panel&gt;
Sublistagem.mlxml
&lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot;?&gt;
&lt;mx:Panel title=&amp;quot;Sublistagem&amp;quot; creationComplete=&amp;quot;init()&amp;quot; xmlns:mx=&amp;quot;http://www.adobe.com/2006/mxml&amp;quot; width=&amp;quot;400&amp;quot; height=&amp;quot;300&amp;quot;&gt;
&lt;mx:Form&gt;
&lt;mx:FormItem label=&amp;quot;ID:&amp;quot;&gt;
&lt;mx:TextInput editable=&amp;quot;false&amp;quot; id=&amp;quot;clientId&amp;quot; text=&amp;quot;{model.client.id}&amp;quot; /&gt;
&lt;/mx:FormItem&gt;
&lt;mx:FormItem label=&amp;quot;Name&amp;quot;&gt;
&lt;mx:TextInput editable=&amp;quot;false&amp;quot; id=&amp;quot;clientName&amp;quot; text=&amp;quot;{model.client.name}&amp;quot;/&gt;
&lt;/mx:FormItem&gt;
&lt;/mx:Form&gt;
&lt;mx:Script&gt;
&lt;![CDATA[
import br.com.ronaldorigoni.controller.SublistagemController;
import br.com.ronaldorigoni.model.SublistagemModel;
[Bindable]
public var model:SublistagemModel = null;
public var controller:SublistagemController = null;
private function init():void{
model = new SublistagemModel();
controller = new SublistagemController(this);
}
]]&gt;
&lt;/mx:Script&gt;
&lt;/mx:Panel&gt;
Em seguida criaremos os controllers para cada componente da camada view:
ListagemController.as
package br.com.ronaldorigoni.controller{
import br.com.ronaldorigoni.event.ListagemEvento;
import br.com.ronaldorigoni.view.Listagem;
import br.com.ronaldorigoni.vo.Client;
import flash.events.MouseEvent;
import mx.collections.ArrayCollection;
import mx.events.ListEvent;
public class ListagemController{
// instancia da camada view para o controller poder manipulá-la
private var view:Listagem = null;
/**
* Contrutor do controller
* @param _view A instancia da view
*/
public function ListagemController(_view:Listagem){
// atribue a instancia da view a instancia local
this.view = _view;
// adiciona evento de clique para listar clientes
view.btList.addEventListener(MouseEvent.CLICK, listClients);
// adiciona evento para limpar a listagem de clientes
view.btClear.addEventListener(MouseEvent.CLICK, clearClients);
// adiciona evento de selecao de um cliente
this.view.list.addEventListener(ListEvent.ITEM_CLICK, dispatchEvent);
}
/**
* Invoca preenchimento do modelo de clientes.
* Lembrando que em uma aplicacao real isso deve ser
* feito por uma linguagem de servidor, geralmente com acesso
* a banco de dados.
*/
private function listClients(event:MouseEvent):void{
fillClients();
}
/**
* Limpa a lista de clientes.
*/
private function clearClients(event:MouseEvent):void{
view.model.clearModel();
}
/**
* Preenche a lista de clientes.
* Sendo quem em uma aplicação real estes dados devem ser alimentados
* por uma linguagem de servidor. *
*/
private function fillClients():void{
for(var i:int = 0; i &lt; 10; i ++){
var client:Client = new Client();
client.name = &amp;quot;Client &amp;quot;+i;
client.id = i;
view.model.addClient(client);
}
}
/**
* Dispara um evento para o componente pai da listagem, e este
* terá adicionado os listeners para este tipo de evento.
* Onde fará a invocação das funcoes.
*/
private function dispatchEvent(event:ListEvent):void{
// setando o cliente selecionado dentro do modelo de listagem
view.model.selected = view.list.selectedItem as Client;
var listagemEvento:ListagemEvento = new ListagemEvento(ListagemEvento.EVENT_CLIENT_SELECTED);
// inserindo dentro do objeto de evento o cliente selecionado.
listagemEvento.sublistagemModel.client = view.model.selected;
// invoca o componente pai da view no caso a application
// para disparar um evento, sendo que nela esta definido um ouvinte para este
// tipo de evento, e a funcao será invocada, internamente no evento existe os dados
// que a visão necessita para exibir.
view.parent.dispatchEvent(listagemEvento);
}
}
}
SublistagemController.as
package br.com.ronaldorigoni.controller{
import br.com.ronaldorigoni.event.ListagemEvento;
import br.com.ronaldorigoni.view.Sublistagem;
import mx.controls.Alert;
public class SublistagemController{
/**
* Instancia da camada view
*/
private var view:Sublistagem = null;
/**
* Construtor do controller, recebe instancia da camada view para
* poder manipulá-la
*/
public function SublistagemController(_view:Sublistagem){
view = _view;
}
/**
* Manipula o evento de cliente selecionado.
*/
public function handleEventSelected(event:ListagemEvento):void{
// seta o titulo do painel de sublistagem
view.title = &amp;quot;Sublistagem Evento recebido:&amp;quot;+event.type;
// seta o model da sublistagem
// quando o model é setado ele é automaticamente renderizado
// na view, pois está marcado com o [Bindable]
view.model = event.sublistagemModel;
}
}
}
Agora vamos criar as Classes de Modelo para os dois componentes visuais da camada View:
ListagemModel.as
package br.com.ronaldorigoni.model{
import br.com.ronaldorigoni.vo.Client;
import mx.collections.ArrayCollection;
public class ListagemModel{
/**
* Array de clientes que será exibido na listagem.
*/
private var _clients:ArrayCollection = new ArrayCollection();
private var _selected:Client;
public function ListagemModel(){
}
/**
* Defina o arrayCollection de clientes.
*/
public function set clients(clients:ArrayCollection):void{
this._clients = clients;
}
/**
* Retorna o arrayCollection de clientes
*/
public function get clients():ArrayCollection{
return _clients;
}
/**
* Limpa o array de clientes.
*/
public function clearModel():void{
this._clients.removeAll();
}
public function addClient(client:Client):void{
_clients.addItem(client);
}
public function set selected(selected:Client):void{
this._selected = selected;
}
public function get selected():Client{
return _selected;
}
}
}
E SublistagemModel.as
package br.com.ronaldorigoni.model{
import br.com.ronaldorigoni.vo.Client;
public class SublistagemModel{
/**
* Representa o cliente atualmente selecionado.
*/
private var _client:Client = new Client();
public function SublistagemModel(){
}
/**
* Seta o cliente atualmente selecionado.
*/
public function set client(client:Client):void{
this._client = client;
}
/**
* Recupera o cliente atual selecionado.
*/
public function get client():Client{
return _client;
}
}
}
Agora vamos criar a classe de Eventos que armazenará uma instância de SublistagemModel para notificar o controller de Sublistagem.
&lt;/pre&gt;
package br.com.ronaldorigoni.event{
import br.com.ronaldorigoni.model.SublistagemModel;
import flash.events.Event;
/**
* Classe de eventos para operacoes de listagem.
* Armazena o cliente atual selecionado.
*/
public class ListagemEvento extends Event{
/**
* Representa um evendo de cliente selecionado.
*/
public static const EVENT_CLIENT_SELECTED:String = &amp;quot;clientSelected&amp;quot;;
private var _sublistagemModel:SublistagemModel = new SublistagemModel();
public function ListagemEvento(tipo:String){
super(tipo,true);
}
/**
* Define o modelo selecionado a sublistagem
*/
public function set sublistagemModel(sublistagemModel:SublistagemModel):void{
this._sublistagemModel = sublistagemModel;
}
/**
* Recupera o modelo da sublistagem
*/
public function get sublistagemModel():SublistagemModel{
return _sublistagemModel;
}
}
}
Esta classe de evento mantem uma propriedade do tipo cliente que alimentará o model de Sublistagem.
Agora vamos criar a classe de VO Client.as, que armazena as informações de cada cliente.
package br.com.ronaldorigoni.vo{
/**
* VO de cliente.
*/
public class Client{
private var _id:uint;
private var _name:String;
public function Client(){
}
/**
* seta o nome do cliente
*/
public function set name(name:String):void{
this._name = name;
}
/**
* Seta o id do cliente;
*/
public function set id(id:uint):void{
this._id = id;
}
/**
* Retorna o atual nome do cliente
*/
public function get name():String{
return _name;
}
/**
* Retorna o id do cliente
*/
public function get id():uint{
return _id;
}
}
}
E por fim nosso código do nosso application ExemploMVC.mxml:
&lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot;?&gt;
&lt;mx:Application creationComplete=&amp;quot;init()&amp;quot; xmlns:mx=&amp;quot;http://www.adobe.com/2006/mxml&amp;quot; layout=&amp;quot;horizontal&amp;quot; xmlns:view=&amp;quot;br.com.ronaldorigoni.view.*&amp;quot;&gt;
&lt;mx:HBox&gt;
&lt;view:Listagem id=&amp;quot;listagem&amp;quot;/&gt;
&lt;view:Sublistagem id=&amp;quot;sublistagem&amp;quot;/&gt;
&lt;/mx:HBox&gt;
&lt;mx:Script&gt;
&lt;![CDATA[
import br.com.ronaldorigoni.event.ListagemEvento;
/**
* Funcao é disparada quando a aplicacao terminar de carregar.
*/
private function init():void{
/**
* Adiciona o listener de evento, para quando for disparado um
* evento deste tipo a funcao para manipular seja invocada.
*/
addEventListener(ListagemEvento.EVENT_CLIENT_SELECTED,
sublistagem.controller.handleEventSelected);
}
]]&gt;
&lt;/mx:Script&gt;
&lt;/mx:Application&gt;
No application tem um listener adicionado para quando for disparado um evento do tipo "ListagemEvento.EVENT_CLIENT_SELECTED", que dispara a função "SublistagemConroller.handleEventSelected", que captura dentro do evento o cliente selecionado atravéz da propriedade "selected", e atualiza o modelo de sublistagem fazendo com que o cliente selecionado chege até a sublistagem sem que os componentes esteja acoplados.
Para testarmos o funcionamento rode a aplicação como Flex Application, clique sobre "Listar", onde o controller manipula este clique e lista os clientes, quando for clicado sobre um cliente na List da Listagem.mxml será criado uma instância de ListagemEvento e adicionado o Client selecionado dentro deste evento e é disparado através do componente pai de Listagem.xml o evento criado, como temos um listener para este tipo de evento em ExemploMVC.mxml ele dispara a função com este evento como um parâmetro, e la é feita a manipulação e atualização do model de Sublistagem.
A grande vantagem de se programar desta forma é que os componentes não ficam acoplados e não se conhecem em tempo de compilação. Já esta estrutura de MVC permite que possamos futuramente efetuar alterações em cada camada sem que outra camada seja afetada ou alterado o funcionamento. Ex, se precisarmos alterar o layout da aplicação o controller não precisa saber disso.
Com o uso da anotação de metadados "Bindable", nos modelos dentro da view, faz com que qualquer alteração pelo Controller sobre o model ela seja automaticamente exibida na camada view, e no caso inverso, quando o usuário altera algum dado apresentado na camada view, ele já é autimaticamente atualizado no model, sendo assim o controller tem total controle sobre a exibição e alteração dos dados.
Aparentemente com esta estrutura temos mais código, mas isso é relativamente incomparável quando for um sistema relativamente grande e que necessite de constante manutenção, pois será alterado apenas as partes que necessitam sem afetar as demais.
Todas as classes estão comentadas e explicadas, qualquer dúvida crítica ou sugestão me escreva ronaldo arroba ronaldorigoni.com.br
Segue link para download do projeto.
Abraços e até um próximo post.
Ola galera,
Lançameto do Google Developer Day, acontecerá em SP dia 29/06. Para maiores informações e inscrições acesse http://code.google.com/intl/pt-BR/events/developerday/2009/about.html
Uma das palestras ocorridas em 2008, outras palestras estão disponíveis em http://www.youtube.com/googlebrasil .
vagas limitadas e inscrição gratuita. Eu vou.
e você?
Ronaldo