Programação para a Plataforma Android – Aula 9 Comunicação via Sockets • O que são sockets? • O que são data access objects? • Como criar servidores de serviços distribuídos? • Aplicações mulB‐threading simples • O padrão de projetos command • O que é o princípio da inversão de dependências? Sockets • Sockets são uma abstração de endereços de comunicação: – Um nome de host, mais um número de porta. • Esse Bpo de dados é a abstração de comunicação básica em várias linguagens de programação. – Java não é exceção. Banco de Dados Distribuído Serviço de notas de estudantes: Implemente um banco de dados distribuído que informe a nota de um estudante. • Estudantes são encontrados por um id – um inteiro do tipo longo que os identifica unicamente. • O banco de dados deve ser acessado via um DAO (Data Access Object) • As operação aceitas são add, get, delete e update. • O servidor de dados deve receber conexões na porta 4444. • O servidor deve criar uma thread para tratar cada conexão recebida. • O banco de dados deve receber conexões de clientes android. Data Access Object • Um DAO é um objeto que faz a intermediação entre a lógica de serviço, e o sistema de banco de dados. – É o “intermediário”. • Operações Bpicamente fornecidas por um DAO são adicionar, atualizar, remover e pesquisar. Como • Em termos de padrões de projeto descrever o a? v a um DAO é um adaptador. J m e O A D Data Access Object server/DAO.java package server; public interface DAO<K, V> { V get(K key); void add(K key, V value); O que são esses ‘K’s e ‘V’s? O nosso banco de dados irá armazenar estudantes. void delete(K key); void update(K key, V value); } O que é um estudante? Estudantes public class Student { public Student(long key, String name, double grade) { this.name = name; Instâncias this.grade = grade; dessa classe this.key = key; deverão ser a } passadas vi Qual proprie rede. public final String name; dade objetos public final double grade; “passáveis” v public final long key; ia rede devem ter? public String toString() { return name + "" + "(" + key + "): " + grade; } } server/Student.java Estudantes import java.io.Serializable; public class Student implements Serializable { public Student(long key, String name, double grade) { this.name = name; this.grade = grade; Como será n this.key = key; osso servidor de } b public final String name; anco de dados? public final double grade; public final long key; public String toString() { return name + "" + "(" + key + "): " + grade; } } server/Student.java server/server1/GradeServer.java O Servidor public staBc void main(String[] args) { Map<Long, Student> students = new HashMap<Long, Student>(); loadDB(students); Precisamos ServerSocket serverSocket = null; implementar um boolean listening = true; stub para te star try { nosso progra ma. serverSocket = new ServerSocket(4444); System.out.println("WaiBng for connecBon"); while (listening) { new StudentHandlerThread(serverSocket.accept(), students).start(); } serverSocket.close(); } catch (IOExcepBon e) { E como será a ? e.printStackTrace(); implementação O que é um stub System.exit(‐1); de nosso stub? } } Um Stub muito Simples private staBc void loadDB(Map<Long, Student> students) { students.put(200934878L, new Student(200934878L, "Alberico", 90.5)); students.put(200755120L, new Student(200755120L, "Bernadino", 71.0)); students.put(200723139L, new Student(200723139L, "Romao", 84.0)); } server/server1/GradeServer.java O Servidor public staBc void main(String[] args) { Map<Long, Student> students = new HashMap<Long, Student>(); loadDB(students); Agora ServerSocket serverSocket = null; precisamos boolean listening = true; implementar try { essa thread serverSocket = new ServerSocket(4444); System.out.println("WaiBng for connecBon"); while (listening) { new StudentHandlerThread(serverSocket.accept(), students).start(); } E como serverSocket.close(); uma é e u q implement O } catch (IOExcepBon e) { ar ? d a e threads em thr e.printStackTrace(); Java? System.exit(‐1); } } server/server1/StudentHandlerThread.java public class StudentHandlerThread extends Thread { private Socket socket = null; Map<Long, Student> students; A Thread :o e t n e m a v o N que é uma thread? public StudentHandlerThread(Socket socket, Map<Long, Student> students) { System.out.println("Got conecBon!"); this.socket = socket; te java r o p u s e u Como inicia-se a Q this.students = students; execução de uma dá para } thread? programação ad? e r h t i t l u m public void run() { ... Como agem t n a v a l a u Q } ar implementar o de se program } método run? com threads? server/server1/StudentHandlerThread.java public void run() { try { ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream()); ObjectInputStream in = new ObjectInputStream(socket.getInputStream()); Long key = (Long) in.readObject(); while (key.longValue() != 0L) { Que tipo de System.out.println("Received " + key); serviço essa if (students.containsKey(key)) { thread provê? out.writeObject(students.get(key)); } else { O que aconte ce out.writeObject(new Student(‐1, "", 0.0)); quando um i d não } está present key = (Long) in.readObject(); e no b anco de dado } s? out.close(); Quantas vezes in.close(); sa thread s e socket.close(); Precisamos sse e ê v o r p } catch (ExcepBon e) { implementar o ? o iç v ser e.printStackTrace(); lado cliente da } aplicação } O Lado Cliente public class Dao1 implements DAO<Long, Student> { public Student get(Long key) {...} public void add(Long key, Student value) {...} Por enquan to, vamos prov er somente o g et. public void update(Long key, Student value) {...} public void delete(Long key) {...} } server/server1/Dao1.java a E como seria ão implementaç do get? Implementação do DAO public Student get(Long key) { server/server1/Dao1.java Student s = null; Socket socket; ObjectOutputStream out; ObjectInputStream in; try { socket = new Socket("10.0.2.2", 4444); out = new ObjectOutputStream(socket.getOutputStream()); in = new ObjectInputStream(socket.getInputStream()); out.writeObject(new Long(key)); s = (Student) in.readObject(); out.writeObject(new Long(0L)); socket.close(); out.close(); in.close(); Comecemos } catch (ExcepBon e) { então pelo e.printStackTrace(); layout! } return s; } Que endere ço é esse? Olhando para cliente e servidor, qual é o protocolo de comunicação? ora é g a s a m , k O esse r a s u o s i c pre um cliente em telefone… Aviso importante: Setup • Para que nosso cliente funcione, ele precisa “enxergar” o servidor. – Botão direito no projeto ‐> build path ‐> configure build path – Lembre‐se de exportar o pacote server com a aplicação, ou ela será compilada, mas não executará corretamente. Layout do Cliente Como criar esse layout em X ML? <LinearLayout xmlns:android="h7p://schemas.android.com/apk/res/ android" android:id="@+id/root" android:orientaBon="ver>cal" android:layout_width="fill_parent" android:layout_height="wrap_content"> <EditText android:id="@+id/txtId" android:focusable="true" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1"/> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/lblResults"/> <LinearLayout android:orientaBon="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content"> <EditText android:id="@+id/txtName" android:focusable="true" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="0.3"/> <EditText android:id="@+id/txtGrade" android:focusable="true" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1"/> </LinearLayout> <Bu|on android:id="@+id/read" android:text="@string/read" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1"/> </LinearLayout> r a s i c e r p Vamos as m u g l a de ts constan . strings… main.xml Layout do Cliente <LinearLayout xmlns:android="h7p://schemas.android.com/apk/res/ android" android:id="@+id/root" android:orientaBon="ver>cal" android:layout_width="fill_parent" android:layout_height="wrap_content"> <EditText android:id="@+id/txtId" android:focusable="true" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1"/> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/lblResults"/> <LinearLayout android:orientaBon="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content"> <EditText android:id="@+id/txtName" android:focusable="true" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="0.3"/> <EditText android:id="@+id/txtGrade" android:focusable="true" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1"/> </LinearLayout> <Bu|on android:id="@+id/read" android:text="@string/read" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1"/> </LinearLayout> strings.xml Layout do Cliente <?xml version="1.0" encoding="u}‐8"?> <resources> <string name="app_name">Aula9</string> <string name="client_name">DaoClient</string> <string name="read">R</string> <string name="write">W</string> <string name="lblResults">Nome e Nota:</string> <string name="get">G</string> <string name="add">A</string> <string name="upd">U</string> <string name="del">D</string> <string name="cln">C</string> <string name="siz">S</string> </resources> main.xml E como implementa ra atividate? @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); final EditText txtId = (EditText) findViewById(R.id.txtId); final EditText txtName = (EditText) findViewById(R.id.txtName); final EditText txtGrade = (EditText) findViewById(R.id.txtGrade); Essa ativid ade ((Bu|on) findViewById(R.id.read)) precisa de .setOnClickListener(new Bu|on.OnClickListener() { p ermissões public void onClick(View arg0) { especiais. Q uais? String strId = txtId.getText().toString(); long id = Long.parseLong(strId); Dao1 d = new Dao1(); E como Student s = d.get(id); icamos que d n i txtName.setText(s.name); s permissões a s s e txtGrade.setText(String.valueOf(s.grade)); s? a i r á s s e c e n o sã } }); } AulaAcBvity9.java manifest.xml Manifesto! Agora temo s de testar noss a atividade! Como? <?xml version="1.0" encoding="u}‐8"?> <manifest xmlns:android="h|p://schemas.android.com/apk/res/android" package="com.aula9" android:versionCode="1" android:versionName="1.0" > <applicaBon android:icon="@drawable/icon" android:label="@string/app_name"> <acBvity android:name=".AulaAciBvity9" android:label="@string/app_name"> <intent‐filter> <acBon android:name="android.intent.acBon.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent‐filter> </acBvity> </applicaBon> <uses‐sdk android:minSdkVersion="2" /> <uses‐permission android:name="android.permission.INTERNET" /> </manifest> Objetos Remotos • Note que nosso DAO funciona como um objeto remoto. Ele é usado como se seus dados esBvessem disponíveis localmente, ainda que esses dados estejam distribuídos! A mágica de programar para as interfaces. nte Simplesme sse e a r a p o d n olha ível s s o p é o ã n código, eto é j b o o e u q r sabe remoto. public void onClick(View arg0) { String strId = txtId.getText().toString(); long id = Long.parseLong(strId); Dao1 d = new Dao1(); Student s = d.get(id); txtName.setText(s.name); txtGrade.setText(String.valueOf(s.grade)); } Ligando o Servidor • Podemos abrir uma nova instância de Eclipse, ou simplesmente iniciar o servidor a parBr da linha de comando: ~/workspace/server$ cd bin/ ~/workspace/server/bin$ java server.server1.GradeServer Waiting for connection Agora já podemos us ar o cliente! Testando a Aplicação Precisamos implementa r os outros méto dos: add, update , delete. Mas o nosso programa possui várias falhas de projeto! Quais? Existem Mas também falhas no existem falhas servidor… no cliente! Analisando a Camada de Comunicação public Student get(Long key) { Student s = null; Socket socket; ObjectOutputStream out; ObjectInputStream in; try { socket = new Socket("10.0.2.2", 4444); out = new ObjectOutputStream(socket.getOutputStream()); in = new ObjectInputStream(socket.getInputStream()); out.writeObject(new Long(key)); s = (Student) in.readObject(); out.writeObject(new Long(0L)); socket.close(); out.close(); in.close(); } catch (ExcepBon e) { e.printStackTrace(); } return s; } server/server1/Dao1.java Há um grande desperdício de recursos aqui. ício d r e p s e d Que é esse? Analisando a Camada de Comunicação public Student get(Long key) { Há um grande Student s = null; Socket socket; desperdício de ObjectOutputStream out; recursos aqui. ObjectInputStream in; try { socket = new Socket("10.0.2.2", 4444); ício d r e p s e d Que out = new ObjectOutputStream(socket.getOutputStream()); é esse? in = new ObjectInputStream(socket.getInputStream()); out.writeObject(new Long(key)); E como reusa s = (Student) in.readObject(); r os out.writeObject(new Long(0L)); canais de socket.close(); comunicação ? out.close(); in.close(); Como garantir que } catch (ExcepBon e) { o canal aberto seja e.printStackTrace(); } eventualmente return s; fechado? } server/server1/Dao1.java O padrão Command server/server2/Command.java public interface Command { void execute(Dao6 d); } Temos um “miniarcabouço”. Vocês lembram o que é um arcabouço? Esse padrão é uma forma de inversão de dependências. O que é isso? public class Invoker { … public void invoke(Dao6 d, Command c) { openConnecBon(); d.setChannels(out, in); c.execute(d); closeConnecBon(); } } server/server2/Invoker.java O padrão Command server/server2/Command.java public interface Command { void execute(Dao6 d); } Como estão sendo divididas as responsabilidades? public class Invoker { … public void invoke(Dao6 d, Command c) { openConnecBon(); d.setChannels(out, in); c.execute(d); closeConnecBon(); } } server/server2/Invoker.java Command Como transcrever esses elementos para nossa aplicação? server/server2/Invoker.java O Invocador public class Invoker { public void invoke(Dao6 d, Command c) {...} private void openConnecBon() {...} private void closeConnecBon() {...} public Invoker(String host, int port) { this.host = host; this.port = port; } public class Invoker { } … public void invoke(Dao6 d, Command c) { openConnecBon(); d.setChannels(out, in); c.execute(d); closeConnecBon(); } } O Invocador private void openConnecBon() { try { socket = new Socket(host, port); out = new ObjectOutputStream(socket.getOutputStream()); in = new ObjectInputStream(socket.getInputStream()); } catch (ExcepBon e) { e.printStackTrace(); private void closeConnecBon() { } try { } out.writeObject(new Integer(EOF)); out.flush(); socket.close(); out.close(); in.close(); } catch (ExcepBon e) { e.printStackTrace(); } } server/server2/Invoker.java s Quais os campo de objetos invokers? Como seria o construtor da classe Invoker? public void invoke(Dao6 d, Command c) { openConnecBon(); d.setChannels(out, in); c.execute(d); closeConnecBon(); } Ainda o Invocador public class Invoker { private staBc final int EOF = ‐1; private String host; private int port; private Socket socket = null; Quais são as private ObjectOutputStream out = null; es responsabilidad private ObjectInputStream in = null; do DAO? public Invoker(String host, int port) { this.host = host; this.port = port; } private void closeConnecBon() {} private void openConnecBon() {} public void invoke() {} } Inversão de Dependência • Antes o DAO Bnha a responsabilidade de abrir a conexão de rede. – O DAO dependia da conexão de rede para funcionar. – Agora o DAO recebe uma conexão já aberta. A dependência não mais existe. – A enBdade responsável por abrir essas conexões, o Invoker, agora depende do DAO. – A criação e liberação de recursos já não é mais responsabilidades dos usuários do DAO. server/server2/Dao6.java public class Dao6 implements DAO<Long, Student> { private ObjectOutputStream out; private ObjectInputStream in; public void setChannels (ObjectOutputStream out, ObjectInputStream in) { this.out = out; this.in = in; } Qual é o protocolo public Student get(Long key) { de comunicação? Student s = null; try { out.writeObject(new Integer(DAO.GET)); out.writeObject(new Long(key)); s = (Student) in.readObject(); Que constante é out.flush(); essa aqui? Para } catch (ExcepBon e) { que ela serve? e.printStackTrace(); } return s; } } O Novo DAO Constantes para a Comunicação public interface DAO<K, V> { final int GET = 1; final int ADD = 2; final int DELETE = 3; final int UPDATE = 4; final int SIZE = 5; final int PORT = 4444; final String HOST = "10.0.2.2"; V get(K key); void add(K key, V value); void delete(K key); void update(K key, V value); int size(); } server/DAO.java Nós já vimos a implementação desse método. Como ficam os outros? server/server2/Dao6.java O Novo DAO public void add(Long key, Student value) { try { out.writeObject(new Integer(DAO.ADD)); out.writeObject(new Long(key)); out.writeObject(value); out.flush(); } catch (ExcepBon e) { e.printStackTrace(); } } public void update(Long key, Student value) { try { out.writeObject(new Integer(DAO.UPDATE)); out.writeObject(new Long(key)); out.writeObject(value); out.flush(); } catch (ExcepBon e) { e.printStackTrace(); } } public void delete(Long key) { try { out.writeObject(new Integer(DAO.DELETE)); out.writeObject(new Long(key)); out.flush(); } catch (ExcepBon e) { e.printStackTrace(); } } Como é a implementação do protocolo no lado servidor? public void run() { try { Integer request = (Integer) in.readObject(); boolean isWorking = true; while (isWorking) { switch (request.intValue()) { case DAO.GET: out.writeObject(get((Long) in.readObject())); public Student get(Long key) { break; case DAO.DELETE: Student s = null; delete((Long) in.readObject()); if (students.containsKey(key)) { break; case DAO.UPDATE: s = students.get(key); update((Long) in.readObject(), (Student)in.readObject()); break; } else { case DAO.ADD: s = new Student(‐1, "", 0.0); add((Long) in.readObject(), (Student)in.readObject()); break; } default: return s; isWorking = false; return; } } request = (Integer) in.readObject(); } out.close(); private Socket socket = null; in.close(); Fecho, mas private Map<Long, Student> students; socket.close(); onde abro? } catch (ExcepBon e) { private ObjectOutputStream out; e.printStackTrace(); private ObjectInputStream in; } } O Servidor server/server2/StudentHandlerThread.java public void run() { try { Integer request = (Integer) in.readObject(); boolean isWorking = true; while (isWorking) { switch (request.intValue()) { case DAO.GET: out.writeObject(get((Long) in.readObject())); break; Temos, é claro, case DAO.DELETE: outros métodos delete((Long) in.readObject()); break; para case DAO.UPDATE: implementar… update((Long) in.readObject(), (Student)in.readObject()); break; case DAO.ADD: add((Long) in.readObject(), (Student)in.readObject()); break; default: public StudentHandlerThread(Socket socket, Map<Long, Student> students) { isWorking = false; System.out.println("Got conecBon!"); return; this.socket = socket; } this.students = students; request = (Integer) in.readObject(); try { } out = new ObjectOutputStream(socket.getOutputStream()); out.close(); in = new ObjectInputStream(socket.getInputStream()); in.close(); } catch (ExcepBon e) { socket.close(); e.printStackTrace(); } catch (ExcepBon e) { } e.printStackTrace(); } } } O Servidor server/server2/StudentHandlerThread.java O Servidor public void add(Long key, Student value) { this.students.put(key, value); } public void update(Long key, Student value) { add(key, value); } public void delete(Long key) { this.students.remove(key); } server/server2/StudentHandlerThread.java gora, Prcisamos, a vo escrever o no cliente. Temos quatro eventos para tratar. Quais são eles? E como seria o layout do novo programa? Quatro Botões m Como fazer u ? layout assim Quantos layouts lineares temos aqu i? E como seria a e? atividade client s Quantos evento precisam ser tratados? Layout Escreva agora a classe que a implementa ess atividade. <LinearLayout xmlns:android= "h|p://schemas.android.com/apk/res/android" android:id="@+id/root" android:orientaBon="verBcal" android:layout_width="fill_parent" android:layout_height="wrap_content"> <EditText android:id="@+id/txtId" android:focusable="true" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1"/> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/lblResults"/> <LinearLayout android:orientaBon="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content"> <EditText android:id="@+id/txtName" android:focusable="true" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="0.3"/> <EditText android:id="@+id/txtGrade" android:focusable="true" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1"/> </LinearLayout> client.xml <LinearLayout android:orientaBon="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content"> <Bu|on android:id="@+id/get" android:text="@string/get" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1"/> <Bu|on android:id="@+id/add" android:text="@string/add" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1"/> <Bu|on android:id="@+id/del" android:text="@string/del" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1"/> <Bu|on android:id="@+id/upd" android:text="@string/upd" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1"/> <Bu|on android:id="@+id/cln" android:text="@string/cln" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1"/> </LinearLayout> </LinearLayout> @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.client); txtId = (EditText) findViewById(R.id.txtId); txtName = (EditText) findViewById(R.id.txtName); txtGrade = (EditText) findViewById(R.id.txtGrade); onCreate ((Bu|on) findViewById(R.id.get)).setOnClickListener(new GetCmd()); ((Bu|on) findViewById(R.id.add)).setOnClickListener(new AddCmd()); ((Bu|on) findViewById(R.id.upd)).setOnClickListener(new UpdCmd()); ((Bu|on) findViewById(R.id.del)).setOnClickListener(new DelCmd()); ((Bu|on) findViewById(R.id.cln)) .setOnClickListener(new Bu|on.OnClickListener() { public void onClick(View arg0) { txtId.setText(""); txtName.setText(""); txtGrade.setText(""); } }); } Client2.java Precimos implementar todos esses eventos! class UpdCmd implements Command, Bu|on.OnClickListener { public void onClick(View arg0) { Invoker i = new Invoker(DAO.HOST, DAO.PORT); Já podemos Dao6 d = new Dao6(); testar nossa i.invoke(d, this); } aplicação! public void execute(Dao6 d) { long id = Long.parseLong(txtId.getText().toString()); String name = txtName.getText().toString(); double grade = Double.parseDouble(txtGrade.getText().toString()); Student std = new Student(id, name, grade); d.update(id, std); class GetCmd implements Command, Bu|on.OnClickListener { } public void onClick(View arg0) { } Invoker i = new Invoker(DAO.HOST, DAO.PORT); iva é t a Dao6 d = new Dao6(); n r e t l a a s s E nte. i.invoke(d, this); a d n u d e r o t i mu } public void execute(Dao6 d) { String strId = txtId.getText().toString(); long id = Long.parseLong(strId); Como fatora r Student s = d.get(id); onClick(…) ? txtName.setText(s.name); txtGrade.setText(String.valueOf(s.grade)); } } Client2.java Classes Abstratas abstract class AbstractCommand implements Command, Bu|on.OnClickListener { public abstract void execute(Dao6 d); dores a t a r t s o s o d To o usar ã v o t n e v e e d lick C n o o d o t é m esse public void onClick(View arg0) { Invoker i = new Invoker(DAO.HOST, DAO.PORT); Dao6 d = new Dao6(); i.invoke(d, this); Eles terão somente Como seria o } de implementar o tratador do e método execute. } vento de adição de novo dado? Client2.java AddCmd class AddCmd extends AbstractCommand implements Command { public void execute(Dao6 d) { long id = Long.parseLong(txtId.getText().toString()); String name = txtName.getText().toString(); double grade = Double.parseDouble(txtGrade.getText().toString()); Student std = new Student(id, name, grade); d.add(id, std); } } il: Agora está fác como ficaria o comando para ID? m u r a s i u q s e p getCmd Client2.java class GetCmd extends AbstractCommand implements Command { public void execute(Dao6 d) { String strId = txtId.getText().toString(); ara long id = Long.parseLong(strId); E o comando p em? t i m u r a z i l a u Student s = d.get(id); at txtName.setText(s.name); txtGrade.setText(String.valueOf(s.grade)); } } Não se es queçam d o comando par apagar um a item! UpdCmd Client2.java class UpdCmd extends AbstractCommand implements Command { public void execute(Dao6 d) { long id = Long.parseLong(txtId.getText().toString()); String name = txtName.getText().toString(); double grade = Double.parseDouble(txtGrade.getText().toString()); Student std = new Student(id, name, grade); d.update(id, std); } } DelCmd Client2.java class DelCmd extends AbstractCommand implements Command { public void execute(Dao6 d) { long id = Long.parseLong(txtId.getText().toString()); d.delete(id); } } Exercício: Size • Modifique a sua aplicação para que ela seja capaz de informar o número de elementos presentes no banco de dados. • Será preciso modificar a interface DAO. • Será também necessário modificar o layout do cliente. public interface DAO<K, V> { final int GET = 1; final int ADD = 2; final int DELETE = 3; final int UPDATE = 4; final int SIZE = 5; final int PORT = 4444; final String HOST = "10.0.2.2"; V get(K key); void add(K key, V value); void delete(K key); void update(K key, V value); int size(); } Exercício: Size • Adicione um botão size à interface do cliente. Quando esse botão receber um clique, o número de elementos armazenados no banco de dados deverá ser impresso na caixa de texto em que são impressas as notas: