Exemplo 1 Objetivo: Demonstrar como fazer um interpretador simples 1. 2. 3. 5. 6. 7. Criar novo projeto Java Criar arquivo conta.math Criar classe InterpretaMath.java Criar um LineNumberReader/FileReader para o arquivo de entrada Fazer o interpretador (cuidado com loop infinito) Fazer agora um gerador de código para este arquivo 7.1. Criar um PrintWriter/FileWriter para jogar o programa gerado Exemplo 2 Objetivo: Demonstrar o uso de uma AST. Criar uma árvore para onde serão jogados os valores antes de interpretar ou gerar código 1. Criar novo projeto Java 2. Criar arquivo conta.math 3. Criar uma AST para o domínio 3.1. Criar uma classe Termo (enum Operacao, e dois campos, operacao e valor) 3.2. Criar uma classe Conta (lista de termos) 4. Criar arquivo MathParser.java, com um método parse(arquivo) (nao esquecer de colocar linha.readLine no final) 5. Criar uma classe principal para usar o parser e interpretar a conta 6. Mudar o formato de entrada para ilustrar que o programa principal não precisa mudar 7. Adicionar uma checagem qualquer (divisão por zero não pode, mostrando a linha) Exemplo 3 Objetivo: Demonstrar o problema causado pelo uso de referências 1. Estender arquivo conta.math para incluir o armazenamento de uma variável, constante 2. Adicionar uma operacão e um campo para armazenar a variável, e modificar o tipo do valor public String valorOuVariavel; public String nomeVariavel; 3. Estender o parser 3.1. Método para interpretar a nova operacao 4. Estender o principal 4.2. Método pegaValor, pra buscar nas variaveis já definidas Exemplo 4 Objetivo: Demonstrar como um modelo orientado a objetos pode facilitar na hora de realizar ações. O parser continua precisando varrer em busca das referências, mas uma vez lido, fica mais fácil 1. Criar um metamodelo Conta (List<Termo> termos, List<Variavel> variaveis) Termo (enum Operacao, Operacao operacao, Conteudo conteudo) Variavel (String nome, Conteudo conteudo) Conteudo (int valor, Variavel variavel, boolean eVariavel) 2. Modificar o parser para ler nesse metamodelo 3. Modificar o principal para usar o metamodelo pra resolver a conta Exemplo 5 Objetivo: Demonstrar que hoje em dia é mais fácil fazer esse tipo de parser, com por exemplo xText 1. 2. 3. 4. Criar novo projeto xText Explicar mais ou menos o que tem no projeto Mostrar que sintaxe abstrata e concreta é junto Mostrar que gera o metamodelo OO (Ecore) Problema : (expressoes += Expressao)*; Expressao : Armazena | Operacao; Armazena : "Armazene" termo=INT; Operacao : sinal=SinalMatematico termo=INT; String SinalMatematico : "+" | "-" | "*" | "/"; 5. 6. 7. 8. Fazer deploy e testar Criar um novo projeto oaw vazio Criar o arquivo, e testar as features do editor Fazer um interpretador 8.1. Criar um arquivo de workflow <?xml version="1.0"?> <workflow> <component file="math/parser/Parser.oaw"> <modelFile value="conta.math"/> <outputSlot value="conta"/> </component> <component class="math.Executa" slotConta="conta" /> </workflow> 8.2. 8.3. 8.4. 8.5. Criar novo objeto que extends AbstractWorkflowComponent2 Implementar métodos abstratos No checkConfiguration, testar se slot está vazio Conteúdo do método invoke protected void invokeInternal(WorkflowContext ctx, ProgressMonitor monitor, Issues issues) { EObject conta = (EObject) ctx.get(slotConta); EList<EObject> conteudoRaiz = conta.eContents(); float resultado = 0; for (EObject expressao : conteudoRaiz) { Integer valor = (Integer) expressao.eGet(expressao.eClass() .getEStructuralFeature("termo")); if (expressao.eClass().getName().equals("Armazena")) { System.out.println(" Armazena " + valor); resultado = valor.floatValue(); } else { String sinal = (String) expressao.eGet(expressao.eClass() .getEStructuralFeature("sinal")); if (sinal.equals("+")) { System.out.println(" Soma " + valor); resultado = resultado + valor.floatValue(); } else ... } System.out.println("=" + resultado); } } Exemplo 6 Objetivo: Demonstrar como XML pode ser usado para interpretar modelos 1. Fazer um exemplo de XML <conta> <inicial>10</inicial> <soma>20</soma> <subtracao>10</subtracao> </conta> 2. Fazer um interpretador XML baseado em DOM Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse("bla"); NodeList list = doc.getFirstChild().getChildNodes(); for(int i=0 ; i<list.getLength(); i++) { Node n = list.item(i); if(n.getNodeName().equals("inicial")) System.out.println("inicial "+n.getTextContent()); else if(n.getNodeName().equals("soma")) System.out.println("soma "+n.getTextContent()); else if(n.getNodeName().equals("subtracao")) System.out.println("subtracao "+n.getTextContent()); } Exemplo 7 Objetivo: Demonstrar os conceitos de metamodelagem na ferramenta GME 1. Fazer o seguinte metamodelo 2. Explicar os conceitos da ferramenta, de metamodelagem, atributos, aspectos, ícones, constraints, etc, etc... 3. Fazer devagar, um elemento de cada vez 4. Deixar por último a parte da referência Exemplo 8 Objetivo: Demonstrar o uso da API BON de metamodelagem para interpretar modelos no GME 1. Criar novo projeto Java 2. Adicionar referência para gme.jar 3. Criar uma nova classe que implementa BonComponent 3.1. Implementar os métodos faltantes 4. Registrar o componente e testar 4.1. Não esqueça de rodar o programa de registro como administrador O componente vai escrever um arquivo de saída (no desktop). - Listar organograma completo (com superiores, e papéis) - Listar atividades, tarefas e papéis associados - Listar tarefas de cada pessoa - ... Começo do interpretador: Vector<JBuilderModel> v = builder.getRootFolder().getRootModels(); for (JBuilderModel model : v) { if (model.getMeta().getName().equals("ModeloDeAtividades")) interpretarModeloAtividades(model); else if (model.getMeta().getName().equals("Organograma")) interpretarOrganograma(model); } pw.flush(); pw.close(); JOptionPane.showMessageDialog(null, "Pronto!"); Exemplo 9 Objetivo: Demonstrar como realizar transformações procedurais utilizando EMF e xText 1. Criar novo projeto openArchitectureWare 2. Criar uma classe que estende AbstractWorkflowComponent2 EObject conta = (EObject) ctx.get(slotConta); EList<EObject> conteudoRaiz = conta.eContents(); // Soma dois quando armazena // Transforma adição em subtração // Duplica o valor da multiplicação for (EObject expressao : conteudoRaiz) { Integer valor = (Integer) expressao.eGet(expressao.eClass() .getEStructuralFeature("termo")); if (expressao.eClass().getName().equals("Armazena")) { expressao.eSet(expressao.eClass().getEStructuralFeature( "termo"), valor + 2); } else { String sinal = (String) expressao.eGet(expressao.eClass() .getEStructuralFeature("sinal")); if (sinal.equals("+")) { expressao.eSet(expressao.eClass().getEStructuralFeature( "sinal"), "-"); } else if (sinal.equals("*")) { expressao.eSet(expressao.eClass().getEStructuralFeature( "termo"), valor * 2); } } } 3. Criar o workflow <?xml version="1.0"?> <workflow> <component file="math/parser/Parser.oaw"> <modelFile value="model.math"/> <outputSlot value="conta"/> </component> <component class="math.Executa" slotConta="conta" /> </workflow> 4. Para testar, copia o executa do exemplo 5 4.1. E atualiza o workflow Exemplo 10 Objetivo: Demonstrar como é feita a transformação declarativa utilizando xTend 1. Cria novo projeto openArchitectureWare 2. Cria uma nova transformação.ext 2.1. Crie o seguinte arquivo (UMA REGRA DE CADA VEZ!) import math; transforma (Problema problema) : problema.expressoes.incrementaArmazena() -> problema.expressoes.select(e|e.metaType == Operacao).trocaSomaPorSubtracao() -> problema.expressoes.select(e|e.metaType == Operacao).dobraValorDeMultiplicacao() -> problema.adicionaExpressao(); incrementaArmazena(Expressao expressao) : if (expressao.metaType == Armazena) then expressao.setTermo(expressao.termo + 2); trocaSomaPorSubtracao(Expressao expressao) : if (((Operacao)expressao).sinal == "+") then ((Operacao)expressao).setSinal("-"); dobraValorDeMultiplicacao(Expressao expressao) : if (((Operacao)expressao).sinal == "*") then expressao.setTermo(expressao.termo * 2); adicionaExpressao(Problema problema): let e = new Operacao: e.setSinal("+") -> e.setTermo(1234) -> problema.expressoes.add(e); 3. Copia o Executa e Workflow do Exemplo9 3.1. Acrescenta a chamada para a transformação <component id="transforma2" class="oaw.xtend.XtendComponent"> <metaModel id="mm" class="org.eclipse.m2t.type.emf.EmfRegistryMetaModel"/> <invoke value="Transforma2::transforma(conta)"/> </component> Exemplo 11 Objetivo: Demonstrar transformações mais complexas utilizando xText / xTend 1. Criar um novo projeto xText 2. Criar uma dsl para modelos OO e modelos ER // specify your DSL grammar rules here ... // IMPORTANT: You should change the property 'overwrite.pluginresources=true' in the properties file to 'overwrite.pluginresources=false' AFTER first generation Modelo : ModeloOO | ModeloER; ModeloOO: "ModeloOO" name=ID "[" (classes+=Classe)* "]"; Classe: "classe" name=ID "{" (membros+=Membro ";")* "}"; Membro: Atributo | Referencia; Atributo: tipo=TipoOO name=ID; Referencia: "->" ref=[Classe] name=ID; // Deixar sem a String, pra mostrar String TipoOO: "texto" | "inteiro" | "real"; ModeloER: "ModeloER" name=ID "[" (tabelas+=Tabela)* "]"; Tabela: "tabela" name=ID ":" (colunas+=Coluna ";")* (restricoes+=Restricao ";")* ";"; Coluna: name=ID tipo=TipoER; // Deixar sem a String, pra mostrar String TipoER: "VARCHAR" | "INT" | "REAL"; Restricao: RestricaoChavePrimaria | RestricaoChaveEstrangeira; RestricaoChavePrimaria: "PRIM" coluna=[Coluna]; RestricaoChaveEstrangeira: "ESTR" coluna=[Coluna] "->" tabelaEstrangeira=[Tabela] "." colunaEstrangeira=[Coluna]; 3. Fazer um interpretador (AbstractWorkflowComponent2) que imprime os modelos 4. Fazer uma transformação OO->ER (UMA PARTE DE CADA VEZ) import linguagemooer; create ModeloER transformaOOER (ModeloOO modeloOO) : this.setName(modeloOO.name+"Gerado") -> this.tabelas.addAll(modeloOO.classes.tabela()) ; create Tabela tabela(Classe classe) : this.setName("Tabela_"+classe.name) -> this.colunas.add(chavePrimaria(classe)) -> this.restricoes.add(restricaoChavePrimaria(chavePrimaria(classe))) -> this.colunas.addAll(classe.membros.select(e|e.metaType.name=="linguagemooer::Atributo").c oluna()) -> this.colunas.addAll(classe.membros.select(e|e.metaType.name=="linguagemooer::Referencia") .colunaChaveEstrangeira()) -> this.restricoes.addAll(classe.membros.select(e|e.metaType.name=="linguagemooer::Referenci a").restricaoChaveEstrangeira()) ; create Coluna chavePrimaria(Classe classe) : this.setName(classe.name + "Id") -> this.setTipo("INT") ; create RestricaoChavePrimaria restricaoChavePrimaria(Coluna coluna) : this.setColuna(coluna) ; create Coluna coluna(Membro membro) : this.setName("Coluna_"+membro.name) -> this.setTipo(tipoER((Atributo)membro)) ; String tipoER(Atributo atributo) : if(atributo.tipo == "texto") then "VARCHAR" else if(atributo.tipo == "inteiro") then "INT" else "REAL" ; create Coluna colunaChaveEstrangeira(Membro referencia) : this.setName(referencia.name) -> this.setTipo("INT") ; create RestricaoChaveEstrangeira restricaoChaveEstrangeira(Membro referencia) : this.setColuna(colunaChaveEstrangeira(referencia)) -> this.setTabelaEstrangeira(tabela(((Referencia)referencia).ref)) -> this.setColunaEstrangeira(chavePrimaria(((Referencia)referencia).ref)) ; 5. Fazer o workflow <?xml version="1.0"?> <workflow> <component file="ooer/parser/Parser.oaw"> <modelFile value="modeloOO.ooer"/> <outputSlot value="modeloOO"/> </component> <component id="transforma" class="oaw.xtend.XtendComponent"> <metaModel id="mm" class="org.eclipse.m2t.type.emf.EmfRegistryMetaModel"/> <invoke value="transforma::transformaOOER(modeloOO)"/> <outputSlot value="modeloERGerado"/> </component> <component class="principal.ImprimeModelo" slotModelo="modeloERGerado" /> </workflow> Exemplo 12 Objetivo: Demonstrar a geração de código com GME public class GeraQuestionario implements BONComponent { PrintWriter pw; public GeraQuestionario() { try { pw = new PrintWriter(new FileWriter("Questionario.java")); } catch (IOException e) { e.printStackTrace(); JOptionPane.showMessageDialog(null, e.getMessage()); } } @Override public void invokeEx(JBuilder builder, JBuilderObject focus, Collection selected, int param) { Vector<JBuilderModel> v = builder.getRootFolder().getRootModels(); for (JBuilderModel model : v) { if (model.getMeta().getName().equals("ModeloDeDecisoes")) { geraQuestionario(model); } } pw.flush(); pw.close(); JOptionPane.showMessageDialog(null, "Pronto!"); } private void geraQuestionario(JBuilderModel modeloDecisoes) { pw.println("import java.io.*;"); pw.println("public class Questionario {"); pw.println("static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));"); Vector<JBuilderObject> elementos = modeloDecisoes.getChildren(); for (JBuilderObject elemento : elementos) { if (elemento.getMeta().getName().equals("Questao")) geraMetodoQuestao((JBuilderAtom) elemento); else if (elemento.getMeta().getName().equals("Mensagem")) geraMetodoMensagem((JBuilderAtom) elemento); } pw.println("public static void main(String[] args) throws IOException {"); Vector<JBuilderAtom> inicio = modeloDecisoes.getAtoms("Inicio"); Vector<JBuilderConnection> inicioConexao = inicio.firstElement() .getOutConnections("InicioConexao"); JBuilderAtom elemento = (JBuilderAtom) inicioConexao.firstElement() .getDestination(); pw.println(arrumaNome(elemento.getName()) + "();"); pw.println("}"); pw.println("}"); } private void geraMetodoQuestao(JBuilderAtom questao) { pw.println("private static void " + arrumaNome(questao.getName()) + "() throws IOException {"); pw.print("System.out.println(\""); pw.print(questao.getName()); pw.println("\");"); Vector<JBuilderConnection> respostasConnections = questao .getOutConnections("Resposta"); int i = 1; for (JBuilderConnection resposta : respostasConnections) { pw.println("System.out.println(\"" + (i++) + ": " + resposta.getName() + "\");"); } pw.println("int op = Integer.parseInt(br.readLine());"); i = 1; for (JBuilderConnection resposta : respostasConnections) { pw.println("if(op == " + (i++) + ") {"); pw.println(arrumaNome(resposta.getDestination().getName()) + "();"); pw.println("return;"); pw.println("}"); } pw.println("}"); } private void geraMetodoMensagem(JBuilderAtom mensagem) { pw.println("private static void " + arrumaNome(mensagem.getName()) + "() throws IOException {"); pw.println("System.out.println(\"" + mensagem.getName() + "\");"); pw.println("br.readLine();"); Vector<JBuilderConnection> links = mensagem.getOutConnections("Link"); if (!links.isEmpty()) pw.println(arrumaNome(links.firstElement().getDestination() .getName()) + "();"); pw.println("}"); } private String arrumaNome(String nome) { return nome.replaceAll(" ", "").replaceAll("\\?", "").replaceAll("!", "").replaceAll("ç", "c").replaceAll("ê", "e").replaceAll(",", "").replaceAll("ã", "a").replaceAll("-", ""); } @Override public void registerCustomClasses() { // TODO Auto-generated method stub } } Exemplo 13 Objetivo: Demonstrar a geração de código com GME, usando patterns (templates) $!EVAL_FORALL("R:Mensagem","$!TO_FILE("html/$Name.html")\ <html>\n\ <body>\n\ $Name<br/>\n\ $!EVAL_FORALL("Dst:Link","<a href=\"\ $Name.html\ \">Continua</a><br/>\n")\ </body>\n\ </html>\n") $!EVAL_FORALL("R:Questao","$!TO_FILE("html/$Name.html")\ <html>\n\ <body>\n\ $Name?<br/>\n\ $!DEFINE("CONT","1")\ $!EVAL_FORALL("Dst:Resposta","<a href=\"\ $Name.html\ \">Opção $!POSTINCR(CONT)</a><br/>\n")\ </body>\n\ </html>\n") Exemplo 14 Objetivo: Demonstrar o uso do GMF para criação de linguagens e ferramentas de modelagem visual 1. Criar novo projeto GMF 2. Criar uma máquina de estados simples, pra começar 3. Mudar para ficar redondo os retângulos, e as transições terem setas 4. Adicionar características do estado 4.1. Modificar para ter um compartimento nos estados com as características 4.1.1. gmftool: novo creation tool 4.1.2. gmfgraph: novo diagram label, novo compartment 4.1.3. gmfmap: novo compart mapping, novo child ref, novo node mapping, novo label mapping 5.Modificar os ícones 5.1. Substituir os gifs no edit 5.2. Apagar o projeto do diagram, apagar os plugins .jar 5.3. Gerar de novo, sem nenhum plugin instalado 6. Adicionar estados inicial e final 6.1. Não esquecer de transformar Estado em abstract 6.2. Modificar os nós Estado para EstadoIntermediario 6.3. Criar as ferramentas, graphs e mappings para os novos estados 7. Adicionar link constraints para não criar transições erradas nos estados inicial e final if (source instanceof maquinaEstados.EstadoFinal) return false; if (target instanceof maquinaEstados.EstadoInicial) return false; if (source instanceof maquinaEstados.EstadoInicial) { java.util.List<maquinaEstados.Transicao> todasTransicoes = container.getTransicoes(); for(maquinaEstados.Transicao t:todasTransicoes) { if(t.getOrigem() == source) return false; } } 8. Adicionar um audit constraint para não deixar criar mais de um estado inicial java.util.List<maquinaEstados.Estado> estados = context.getEstados(); int cont = 0; for(maquinaEstados.Estado e : estados) { if(e instanceof maquinaEstados.EstadoInicial) cont++; } if(cont > 1) return org.eclipse.core.runtime.Status.CANCEL_STATUS; return org.eclipse.core.runtime.Status.OK_STATUS; 9. Para comparar com GME, fazer um exemplo de modelo de decisões Exemplo 15 Objetivo: Demonstrar as funcionalidades da linguagem xText 1. Criar novo projeto xText 2. Criar linguagem para máquina de estados MaquinaDeEstados : (eventos+=Evento)* (estados+=Estado)*; Evento : "evento" name=ID ";"; Estado : "estado" tipo=TipoEstado name=ID "{" "caracteristicas" ":" (caracteristicas+=Caracteristica ";")* "transicoes" ":" (transicoes+=Transicao ";")* "}" ; String TipoEstado : "inicial" | "intermediario" | "final" ; Caracteristica : name=STRING ":" expressao=STRING ; Transicao : evento=[Evento] "->" estado=[Estado] ; 3. Criar checagens – UMA DE CADA VEZ context Transicao ERROR "Não pode existir transição para o estado inicial!" : this.estado.tipo != "inicial"; //context Transicao if(this.estado.tipo == "inicial") ERROR "Não pode existir transição para o estado inicial 2!" : // false; context Transicao ERROR "Não pode existir transição partindo de estado final!" : ((Estado)this.eContainer).tipo != "final"; //context Estado ERROR "Não podem existir transições partindo do estado final 2!" : // this.tipo == "final"?this.transicoes.isEmpty:true; context MaquinaDeEstados ERROR "Deve haver um (e somente um) estado inicial!" : this.estados.select(e|e.tipo == "inicial").size == 1; //context Estado if(this.tipo=="inicial") ERROR "Deve haver um (e somente um) estado inicial 2!" : // ((MaquinaDeEstados)this.eContainer).estados.select(e|e.tipo == "inicial").size == 1; context Estado ERROR "Deve existir uma (e somente uma) transição saindo do estado inicial!" : this.tipo == "inicial"?this.transicoes.size==1:true; context Evento ERROR "Não podem existir dois eventos com o mesmo nome: " + this.name : ((MaquinaDeEstados)this.eContainer).eventos.select(e|e.name == this.name).size == 1; context Estado ERROR "Não podem existir dois estados com o mesmo nome: " + this.name : ((MaquinaDeEstados)this.eContainer).estados.select(e|e.name == this.name).size == 1; context Estado if(this.tipo!="inicial") WARNING "Não há nenhuma transição para este estado: "+this.name : ((MaquinaDeEstados)this.eContainer).estados.transicoes.exists(t|t.estado == this); context Transicao ERROR "Já existe outra transição para o mesmo evento!" : ((Estado)this.eContainer).transicoes.select(t|t.evento == this.evento).size == 1; 4. Fazer ícones especiais, e corrigir os labels padrão 4.1. EditorExtensions.ext label(Estado this): "estado" + this.name; label(Evento this): "evento" + this.name; label(Transicao this): this.evento.name + "->" + this.estado.name; image(Estado this): this.tipo == "inicial" ? "keyword.gif" : "default.gif"; 5. Estender o auto-complete: List[Proposal] completeTransicao_estado(Transicao t, String prefix) : t.allVisibleElements().typeSelect(Estado).select(e|e.tipo != "inicial").collect(x|newProposal(x.label(),x.id(),x.image())); List[Proposal] completeTransicao_evento(Estado estado, String prefix) : estado.allVisibleElements().typeSelect(Evento).select(e|estado.transicoes.forAll(t2|t2.ev ento != e)).collect(x|newProposal(x.label(),x.id(),x.image())); //estado.allVisibleElements().typeSelect(Evento).removeAll(estado.transicoes.collect(t2|t 2.evento)).collect(x|newProposal(x.label(),x.id(),x.image())); 6. Para comparar com GMF/GME, fazer modelo de decisões Exemplo 16 Objetivo: Demonstrar as funcionalidades da linguagem ATL 1. Criar novo projeto ATL 2. Criar dois metamodelos: familias e pessoas 3. Criar um novo ATL file module familiasParaPessoas; -- Module Template create SAIDA : pessoas from ENTRADA : familias; helper context familias!Membro def: eMulher() : Boolean = self.eMae() or self.eFilha(); helper context familias!Membro def: eMae() : Boolean = if (not self.refImmediateComposite().mae.oclIsUndefined()) then if (self.refImmediateComposite().mae = self) then true else false endif else false endif; helper context familias!Membro def: eFilha() : Boolean = if (self.refImmediateComposite().filhas.includes(self)) then true else false endif; helper context familias!Membro def: sobrenome() : String = self.refImmediateComposite().sobrenome; rule MembroParaHomem { from m : familias!Membro (not m.eMulher()) to h : pessoas!Homem ( nomeCompleto <- m.nome + ' ' +m.sobrenome() ) } rule MembroParaMulher { from m : familias!Membro (m.eMulher()) to h : pessoas!Mulher ( nomeCompleto <- m.nome + ' ' +m.sobrenome() ) } 4. Criar um novo Run configuration Exemplo 17 Objetivo: Demonstrar as funcionalidades da linguagem xTend 1. Criar novo projeto oaw 2. Criar extensões import maquinaestados; adicionaEstadoEmergencia( MaquinaDeEstados this ): this.eventos.add(eventoEmergencia()) -> this.estados.add(estadoEmergencia()) -> this.estados.adicionaTransicaoParaEmergencia(); create Evento eventoEmergencia(): this.setName("emergencia"); create Estado estadoEmergencia(): this.setName("emergencia"); create Transicao adicionaTransicaoParaEmergencia(Estado estado): estado.transicoes.add(this) -> this.setEvento(eventoEmergencia()) -> this.setEstado(estadoEmergencia()); import maquinaEstados; adicionaEstadoEmergencia( MaquinaDeEstados this ): this.estados.add(estadoEmergencia()) -> this.estados.adicionaTransicaoParaEmergencia(); create EstadoIntermediario estadoEmergencia(): this.setNome("emergencia"); create Transicao adicionaTransicaoParaEmergencia(Estado estado): ((MaquinaDeEstados)estado.eContainer).transicoes.add(this) -> this.setNome("emergencia") -> this.setOrigem(estado) -> this.setDestino(estadoEmergencia()); 3. Criar workflow <workflow> <component file="me/parser/Parser.oaw"> <modelFile value="maquinaEstados.me"/> <outputSlot value="maquinaEstados"/> </component> <component id="xmiParser" class="org.openarchitectureware.emf.XmiReader"> <modelFile value="maquinaEstados.maquinaEstados"/> <metaModelPackage value="maquinaEstados.MaquinaEstadosPackage"/> <outputSlot value="maquinaEstados2"/> <firstElementOnly value="true"/> </component> <component id="transforma" class="oaw.xtend.XtendComponent"> <metaModel id="mm" class="org.eclipse.m2t.type.emf.EmfRegistryMetaModel"/> <invoke value="transforma::adicionaEstadoEmergencia(maquinaEstados)"/> </component> <component id="transforma" class="oaw.xtend.XtendComponent"> <metaModel id="mm" class="org.eclipse.m2t.type.emf.EmfRegistryMetaModel"/> <invoke value="transforma2::adicionaEstadoEmergencia(maquinaEstados2)"/> </component> <component id="write" class="org.eclipse.mwe.emf.Writer"> <useSingleGlobalResourceSet value="true"/> <modelSlot value="maquinaEstados"/> <uri value="/Users/daniel/Desktop/workspace/Exemplo17/dump.xmi"/> </component> <component id="write" class="org.eclipse.mwe.emf.Writer"> <useSingleGlobalResourceSet value="true"/> <modelSlot value="maquinaEstados2"/> <uri value="/Users/daniel/Desktop/workspace/Exemplo17/dump2.xmi"/> </component> </workflow> 4. Exercícios 4.1. Não criar transicao a partir do estado inicial 4.2. Não criar transicao a partir do estado de emergencia Exemplo 18 Objetivo: Demonstrar as funcionalidades do JET 1. 2. 3. 4. Criar novo projeto Java Adicionar natureza JET ao projeto Ajustar as propriedades JET do projeto Criar novo arquivo helloworld.txtjet <%@ jet package="hello" class="HelloWorldTemplate" %> Hello, world! 5. Criar uma classe principal e executar o exemplo HelloWorldTemplate helloworld = new HelloWorldTemplate(); String result = helloworld.generate(null); System.out.println(result); 6. Mostrar <%=argument%> String (novo arquivo) 7. Mostrar <%=argument%> List, criando um XML com conteúdo (novo arquivo) 8. E se for gerar um JSP? startTag=”<$” endTag=”$>” (novo arquivo) 8.1. Mostrar rodando, e explicar com calma 9. Mostrar mais detalhes sobre o gerador gerado, objetos que dá pra usar (stringBuffer) (novo arquivo) 10. Mostrar como mudar o gerador gerado (skeleton) public class CLASS implements IGerador { /* Minha classe geradora */ public String gerar(Object argumento) { return ""; } } 11. Mostrar include <%@ include file=”bla” %> 11.1. Mostrar inclusão de .txt 11.2. Mostrar inclusão de .jetf 12. O include anterior é chamado durante tradução. E se eu quiser executar o template e copiar o resultado? 12.1. Inserir scriplets pra chamar a classe gerada explicitamente Exemplo 19 Objetivo: Demonstrar o uso do JET e as tags 1. 2. 3. 4. Criar novo projeto JET Adicionar model loader org.eclipse.jet.emfxml no plugin.xml Criar um conteúdo no sample.xml Criar um gerador de exemplo <c:iterate select="/root/familia" var="familia"> Familia: <c:get select="$familia/@sobrenome" /> Pai: <c:get select="$familia/pai/@nome" /> Mãe: <c:get select="$familia/mae/@nome" /> <c:if test="$familia/filho"> Filhos: <c:iterate select="$familia/filho" var="filho" delimiter="," ><c:get select="$filho/@nome" /></c:iterate> </c:if> </c:iterate> 5. Mostrar como incluir outros templates <c:include template="templates/anotacoes.jet" /> 6. Mostrar como é possível anotar o modelo de entrada 6.1. Mostrar o dump.xml para ver a saída <c:iterate select="/root/familia" var="familia"> <c:set select="$familia/pai" name="nomeCompleto"><c:get select="$familia/pai/@nome" /> <c:get select="$familia/@sobrenome" /></c:set> <c:set select="$familia/mae" name="nomeCompleto"><c:get select="$familia/mae/@nome" /> <c:get select="$familia/@sobrenome" /></c:set> <c:iterate select="$familia/filho" var="filho"> <c:set select="$filho" name="nomeCompleto"><c:get select="$filho/@nome" /> <c:get select="$familia/@sobrenome" /></c:set> </c:iterate> <c:addElement select="/root" name="pessoa" var="pessoaPai" /> <c:set select="$pessoaPai" name="genero">Homem</c:set> <c:set select="$pessoaPai" name="nome"><c:get select="$familia/pai/@nome" /></c:set> <c:set select="$pessoaPai" name="sobrenome"><c:get select="$familia/@sobrenome" /></c:set> <c:addElement select="/root" name="pessoa" var="pessoaMae" /> <c:set select="$pessoaMae" name="genero">Mulher</c:set> <c:set select="$pessoaMae" name="nome"><c:get select="$familia/mae/@nome" /></c:set> <c:set select="$pessoaMae" name="sobrenome"><c:get select="$familia/@sobrenome" /></c:set> <c:iterate select="$familia/filho" var="filho"> <c:addElement select="/root" name="pessoa" var="pessoaFilho" /> <c:set select="$pessoaFilho" name="genero">Homem</c:set> <c:set select="$pessoaFilho" name="nome"><c:get select="$filho/@nome" /></c:set> <c:set select="$pessoaFilho" name="sobrenome"><c:get select="$familia/@sobrenome" /></c:set> </c:iterate> </c:iterate> 7. Mostrar as tags ws:project e ws:folder Exemplo 20 Objetivo: Mostrar como gerar código Java 1. Criar novo projeto JET 2. Fazer um diagrama de classes no sample.xml 3. Gerar JavaBeans 3.1. Gerar setters e getters (usar anotações nos atributos) 4. Criar métodos abstratos no sample.xml 4.1. Adicionar parametros, exceções, visibilidade, modificador static 5. Demonstrar o uso do userRegion 5.1. Tag unmodifiedMarker="@generated" Exemplo 21 Objetivo: Mostrar como gerar código a partir de modelo EMF 1. 2. 3. 4. 5. Criar novo projeto JET Estender a ferramenta de estados para incluir ações Criar um modelo de exemplo (refrigerador) Adicionar model loader org.eclipse.jet.emf no plugin.xml Criar templates para anotações e uma classe da máquina de estados Anotações: <c:iterate select="/MaquinaDeEstados/EstadoInicial" var="estado"> <c:set select="$estado" name="nome">INICIAL</c:set> <c:set select="$estado" name="constante">0</c:set> </c:iterate> <% int constanteEstado = 1; %> <c:iterate select="/MaquinaDeEstados/EstadoIntermediario" var="estado"> <c:set select="$estado" name="constante"><%=constanteEstado++%></c:set> </c:iterate> <c:iterate select="/MaquinaDeEstados/EstadoFinal" var="estado"> <c:set select="$estado" name="constante"><%=constanteEstado++%></c:set> </c:iterate> <% constanteEstado = 1; %> <c:iterate select="/MaquinaDeEstados/EstadoFinal" var="estado"> <c:if test="not($estado/@nome)"> <c:set select="$estado" name="nome">FINAL_<%=constanteEstado++%></c:set> </c:if> </c:iterate> <c:iterate select="/MaquinaDeEstados/estados" var="estado"> <c:iterate select="$estado/acoes" var="acao"> <c:set select="$acao" name="metodoAcao"><f:replaceAll value=" " replacement="_"><c:get select="$acao/@nome" /></f:replaceAll></c:set> </c:iterate> </c:iterate> Template da máquina de estados: package gerado; import java.util.HashMap; import java.util.Map.Entry; public class MaquinaEstados { // estado inicial private final static int INICIAL = 0; // estados intermediarios e finais <c:iterate select="/MaquinaDeEstados/EstadoIntermediario" var="estado"> private final static int <f:uc><c:get select="$estado/@nome" /></f:uc> = <c:get select="$estado/@constante" />; </c:iterate> <c:iterate select="/MaquinaDeEstados/EstadoFinal" var="estado"> private final static int <f:uc><c:get select="$estado/@nome" /></f:uc> = <c:get select="$estado/@constante" />; </c:iterate> private int estadoAtual = 0; private HashMap<String,String> caracteristicas = new HashMap<String,String>(); public void disparaEvento(String evento) { System.out.println("Evento:" + evento); <c:iterate select="/MaquinaDeEstados/transicoes" var="transicao" delimiter=" if(evento.equals("<c:get select="$transicao/@nome"/>") && estadoAtual == <f:uc><c:get select="$transicao/origem/@nome" /></f:uc>) else"> estadoAtual = <f:uc><c:get select="$transicao/destino/@nome" /></f:uc>; </c:iterate> mudaCaracteristicas(); executaAcoes(); } private void mudaCaracteristicas() { <c:iterate select="/MaquinaDeEstados/estados" var="estado" delimiter=" else"> if(estadoAtual == <f:uc><c:get select="$estado/@nome" /></f:uc>) { <c:iterate select="$estado/caracteristicas" var="caracteristica"> caracteristicas.put("<c:get select="$caracteristica/@nome"/>","<c:get select="$caracteristica/@expressao"/>"); </c:iterate> } </c:iterate> } private void executaAcoes() { <c:iterate select="/MaquinaDeEstados/estados" var="estado"> <c:if test="$estado/acoes"> if(estadoAtual == <f:uc><c:get select="$estado/@nome" /></f:uc>) { <c:iterate select="$estado/acoes" var="acao"> <c:get select="$acao/@metodoAcao"/>(); </c:iterate> } </c:if> </c:iterate> } <c:iterate select="/MaquinaDeEstados/estados" var="estado"> <c:iterate select="$estado/acoes" var="acao"> private void <c:get select="$acao/@metodoAcao"/>() { <c:userRegion> // inicio <c:get select="$acao/@metodoAcao"/> <c:initialCode> // ... insira o código aqui ... </c:initialCode> // fim <c:get select="$acao/@metodoAcao"/> </c:userRegion> } </c:iterate> </c:iterate> public void imprimeEstadoAtual() { <c:iterate select="/MaquinaDeEstados/estados" var="estado" delimiter=" else"> if(estadoAtual == <f:uc><c:get select="$estado/@nome" /></f:uc>) System.out.println("Estado atual: <c:get select="$estado/@nome" />"); </c:iterate> } public void imprimeCaracteristicas() { for(Entry<String,String> e : caracteristicas.entrySet()) { System.out.println(e.getKey()+": "+e.getValue()); } } } 6. Fazer a versão abstrata 7. Demonstrar que dá pra incluir um template no outro <f:indent text=" " depth="1"> /* * Máquina de estados gerada * Data: <f:formatNow pattern="dd/MM/yyyy : EEE" /> * Número de estados: <c:get select="count(/MaquinaDeEstados/estados)" /> * Número de estados finais: <c:get select="count(/MaquinaDeEstados/EstadoFinal)" /> * Número de estados intermediários: <c:get select="count(/MaquinaDeEstados/EstadoIntermediario)" /> * Número de transições: <c:get select="count(/MaquinaDeEstados/transicoes)" /> */ </f:indent> 8. Fazer o gerador de htmls para o exercício do modelo de decisões Exemplo 22 Objetivo: Demonstrar a linguagem xPand, usando um modelo xText 1. Criar novo projeto xText (deixar pra gerar o generator) 2. Criar uma linguagem simples para famílias Familias : (familias += Familia)*; Familia : "Familia" sobrenome=STRING "(" pai=Pai mae=Mae (filhos += Filho)* ")" ; Pai: "pai" "=" nome=STRING; Mae: "mae" "=" nome=STRING; Filho: "filho" "=" nome=STRING; 3. Criar um gerador simples «IMPORT familia» «DEFINE main FOR Familias» «FILE "familias.txt"» «FOREACH this.familias AS f-» «EXPAND familia FOR f-» «ENDFOREACH-» «ENDFILE-» «ENDDEFINE» «DEFINE familia FOR Familia-» ====== Família «sobrenome» ========== Pai: «pai.nome» Mãe: «mae.nome» «IF !filhos.isEmpty-» =========== Filhos ============= «FOREACH filhos AS filho-» «filho.nome» «ENDFOREACH-» «ENDIF-» «ENDDEFINE» 4. Mostrar que dá pra transformar pra ajudar na geração transforma(Familias f) : f.familias.criaFilho() -> f.familias.trocaEsposa(); create Filho criaFilho(Familia f) : f.filhos.add(this) -> this.setNome("Filho da familia "+f.sobrenome); trocaEsposa(Familia f) : f.mae.setNome("Nova esposa"); 5. Mostrar que dá pra fazer extensões e ajudar na geração numeroFilhos(Familia f) : f.filhos.size; sobrenome(emf::EObject o): ((Familia)o.eContainer).sobrenome; nomeCompleto(Pai p) : p.nome + " " + p.sobrenome(); nomeCompleto(Mae m) : m.nome + " " + m.sobrenome(); nomeCompleto(Filho f) : f.nome + " " + f.sobrenome(); nomeCitacao(Pai p) : p.sobrenome().toUpperCase()+", "+p.nome.subString(0,1)+"." ; Exemplo 23 Objetivo: Demonstrar a linguagem xPand, usando um modelo xText mais complexo (máquina de estados) 1. Criar novo projeto oAW 2. Modificar o exemplo para ter ações 3. Criar um exemplo de máquina de estados textual (despertador) evento evento evento evento evento evento liga; ligaAlarme; desligaAlarme; toca; soneca; fimsoneca; estado inicial inicio { caracteristicas: transicoes: liga -> ligado; acoes: } estado intermediario ligado { caracteristicas: "horario" : "nenhum"; "caixa de som" : "desligada"; transicoes: ligaAlarme -> alarmeLigado; acoes: } estado intermediario alarmeLigado { caracteristicas: "horario" : "especificado"; "caixa de som" : "desligada"; transicoes: desligaAlarme -> ligado; toca -> tocando; acoes: especificaHorario; } estado intermediario tocando { caracteristicas: "horario" : "especificado"; "caixa de som" : "ligada"; transicoes: soneca -> soneca; desligaAlarme -> ligado; acoes: tocaSom; } estado intermediario soneca { caracteristicas: "horario" : "especificado"; "caixa de som" : "desligada"; transicoes: fimsoneca -> tocando; desligaAlarme -> ligado; acoes: comecaContagemSoneca; } 4. Criar um gerador similar ao exemplo21 «IMPORT maquinaestados» «EXTENSION me::Extensions» «DEFINE main FOR MaquinaDeEstados» «FILE "MaquinaDeEstadosAbstrata.java"-» import java.util.HashMap; import java.util.Map.Entry; public abstract class MaquinaDeEstadosAbstrata { public enum Estado {«FOREACH estados AS estado SEPARATOR ","-» «estado.nomeConstanteEstado()-»«ENDFOREACH-» }; private Estado estadoAtual = Estado.«estados.selectFirst(estado|estado.tipo == "inicial").nomeConstanteEstado()»; private HashMap<String,String> caracteristicas = new HashMap<String,String>(); «FOREACH eventos AS evento-» public void «evento.name»() { «FOREACH estados AS estado-» «FOREACH estado.transicoes.select(t|t.evento == evento) AS transicao-» if(estadoAtual == Estado.«estado.nomeConstanteEstado()-») { estadoAtual = Estado.«transicao.estado.nomeConstanteEstado()-»; «FOREACH transicao.estado.acoes AS acao-» «acao.name»(); «ENDFOREACH-» «FOREACH transicao.estado.caracteristicas AS caracteristica-» caracteristicas.put("«caracteristica.name»","«caracteristica.expressao»"); «ENDFOREACH-» } «ENDFOREACH-» «ENDFOREACH-» } «ENDFOREACH-» «FOREACH estados.acoes AS acao-» protected abstract void «acao.name»(); «ENDFOREACH» public void imprimeEstadoAtual() { System.out.println("Estado:"+ estadoAtual); for(Entry<String,String> e : caracteristicas.entrySet()) { System.out.println(e.getKey()+": "+e.getValue()); } } } «ENDFILE» «ENDDEFINE» 5. Testar o exemplo 6. Adicionar estado final e transições import maquinaestados; adicionaEstadoFinal(MaquinaDeEstados me) : me.eventoFinal() -> me.estadoFinal() -> me.estados.select(e|e.tipo == "intermediario").transicaoParaEstadoFinal(); create Evento eventoFinal(MaquinaDeEstados me) : me.eventos.add(this) -> this.setName("desliga"); create Estado estadoFinal(MaquinaDeEstados me) : me.estados.add(this) -> this.setName("desligado") -> this.setTipo("final"); create Transicao transicaoParaEstadoFinal(Estado e) : this.setEvento(eventoFinal((MaquinaDeEstados)e.eContainer)) -> this.setEstado(estadoFinal((MaquinaDeEstados)e.eContainer)) -> e.transicoes.add(this); 6. Questão: como garantir que a classe abstrata será implementada? 6.1. Opção 1: hack static { if(false) { MaquinaDeEstadosAbstrata me = new MaquinaDeEstadosConcreta(); } } 7. Recipes 7.1. Adicionar referências aos plugins *recipe 7.2. Criar um RecipeCreator package recipes; public class RecipeCreator extends RecipeCreationComponent { @Override protected Collection<org.openarchitectureware.recipe.core.Check> createRecipes( Object modelSlotContent, String appProject) { List<Check> checks = new ArrayList<Check>(); CompositeCheck cc = new CompositeCheck( "Implementação concreta da máquina de estados.", "Implementação concreta da máquina de estados."); JavaClassExistenceCheck javaClassExistenceCheck = new JavaClassExistenceCheck( "Você deve prover uma implementação concreta", appProject, "principal.MaquinaDeEstadosConcreta"); javaClassExistenceCheck .setLongDescription("Você deve prover uma implementação concreta"); JavaSupertypeCheck javaSuperclassCheck = new JavaSupertypeCheck( "A implementação concreta deve estender MaquinaDeEstadosAbstrata", appProject, "principal.MaquinaDeEstadosConcreta", "gerado.MaquinaDeEstadosAbstrata"); cc.addChild(javaClassExistenceCheck); cc.addChild(javaSuperclassCheck); checks.add(cc); return checks; } } 7.3. Adicionar chamada no workflow <component id="recipe" class="recipes.RecipeCreator"> <appProject value="Exemplo23"/> <modelSlot value="theModel"/> <recipeFile value="recipes.recipes"/> </component> 7.4. Testar 7.5. Mostrar as possíveis checks no próprio Eclipse Exemplo 24 Objetivo: Demonstrar a linguagem xPand, usando um modelo EMF (máquina de estados) 1. Criar novo projeto oAW 1.1. Copiar a máquina de estados de outro exemplo 1.2. Inserir dependência com Exemplo14 2. Criar um workflow <?xml version="1.0"?> <workflow> <property name='modelFile' value='src/default.maquinaestados' /> <property name='targetDir' value='src-gen/'/> <!-- set up EMF for standalone execution --> <bean class="org.eclipse.mwe.emf.StandaloneSetup" > <platformUri value=".."/> </bean> <!-- ler modelo de dados --> <component class="org.eclipse.mwe.emf.Reader"> <uri value="${modelFile}" /> <modelSlot value="modelo" /> </component> <component id="transforma" class="oaw.xtend.XtendComponent"> <metaModel id="mm" class="org.eclipse.m2t.type.emf.EmfRegistryMetaModel"/> <invoke value="transforma::corrigeNomeEstados(modelo)"/> </component> <!-- gerar codigo para modelo de dados --> <component class="org.openarchitectureware.xpand2.Generator"> <metaModel id="mm" class="org.openarchitectureware.type.emf.EmfMetaModel"> <metaModelFile value="model/maquinaEstados.ecore"/> </metaModel> <expand value="Main::main FOR modelo" /> <genPath value='${targetDir}'/> </component> </workflow> 3. Transformação para corrigir nomes de estados em branco <?xml version="1.0"?> <workflow> <property name='modelFile' value='src/default.maquinaestados' /> <property name='targetDir' value='src-gen/'/> <!-- set up EMF for standalone execution --> <bean class="org.eclipse.mwe.emf.StandaloneSetup" > <platformUri value=".."/> </bean> <!-- ler modelo de dados --> <component class="org.eclipse.mwe.emf.Reader"> <uri value="${modelFile}" /> <modelSlot value="modelo" /> </component> <component id="transforma" class="oaw.xtend.XtendComponent"> <metaModel id="mm" class="org.eclipse.m2t.type.emf.EmfRegistryMetaModel"/> <invoke value="transforma::corrigeNomeEstados(modelo)"/> </component> <!-- gerar codigo para modelo de dados --> <component class="org.openarchitectureware.xpand2.Generator"> <metaModel id="mm" class="org.openarchitectureware.type.emf.EmfMetaModel"> <metaModelFile value="model/maquinaEstados.ecore"/> </metaModel> <expand value="Main::main FOR modelo" /> <genPath value='${targetDir}'/> </component> </workflow> 4. Extensões para ajudar import maquinaEstados; corrigeNome(String str) : str.replaceAll(" ","_"); 5. Template principal «IMPORT maquinaEstados» «EXTENSION extensions» «DEFINE main FOR MaquinaDeEstados» «FILE "gerado/MaquinaDeEstadosAbstrata.java"-» package gerado; import java.util.HashMap; import java.util.Map.Entry; public abstract class MaquinaDeEstadosAbstrata { public enum Estado {«FOREACH estados AS estado SEPARATOR ","-» «estado.nome-»«ENDFOREACH-» }; private Estado estadoAtual = Estado.«estados.typeSelect(EstadoInicial).first().nome»; private HashMap<String,String> caracteristicas = new HashMap<String,String>(); «FOREACH transicoes.collect(t|t.nome).toSet() AS evento-» public void evento_«evento.corrigeNome()»() { System.out.println("Evento: «evento.corrigeNome()»"); «FOREACH estados AS estado-» «FOREACH transicoes.select(t|t.nome == evento && t.origem == estado) AS transicao» if(estadoAtual == Estado.«estado.nome-») { estadoAtual = Estado.«transicao.destino.nome-»; «FOREACH transicao.destino.acoes AS acao-» «acao.nome.corrigeNome()»(); «ENDFOREACH-» «FOREACH transicao.destino.caracteristicas AS caracteristica-» caracteristicas.put("«caracteristica.nome»","«caracteristica.expressao»"); «ENDFOREACH-» } «ENDFOREACH-» «ENDFOREACH-» } «ENDFOREACH-» «FOREACH estados.acoes AS acao-» protected abstract void «acao.nome.corrigeNome()»(); «ENDFOREACH» public void imprimeEstadoAtual() { System.out.println("Estado:"+ estadoAtual); for(Entry<String,String> e : caracteristicas.entrySet()) { System.out.println(e.getKey()+": "+e.getValue()); } } } «ENDFILE» «ENDDEFINE» 6. Fazer o exemplo do modelo de decisões, para comparar, gerando um html Exemplo 25 Objetivo: Demonstrar as possibilidades de padrões para integração entre código gerado e não-gerado 1. Criar novo projeto JET 2. Criar um projeto JET.Gerado 3. Código gerado chama código não-gerado 3.1. Criar uma classe ListaOrdenada, e gerar código pra ela 4. Código não-gerado chama código gerado 4.1. Fazer uma classe ListaOrdenada2, e gerar os comparators 5. Factory 5.1. Fazer exemplo de DAO 5.1.1. sample.xml 5.1.2. Fazer DAO abstrato e fábrica abstrata 5.1.3. Fazer templates dos DAOs concretos e fábricas concretas 5.1.4. Testar 5.1.5. Fazer um template de criador de fábricas concretas