// Last edited on 2014-12-17 02:52:24 by stolfilocal package quack; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.util.Collections; import java.util.Comparator; import java.util.LinkedList; import java.util.List; import java.util.UUID; import java.util.Calendar; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.Part; public final class ServerImpl implements Server { SessionTable sessionTable = null; // Conjunto de sessões abertas. Database database = null; // Conexão com a base de dados persistente. // As tabelas abaixo são cópias na memória dos objetos na base de dados. UserTable userTable = null; // Conjuto de usuários cadastrados. private Long nextUserId = new Long(0); private Long nextMessageId = new Long(0); long numContacts = 0; // Número total de contatos criados (incluindo long numSessions = 0; // Número total de sessões abertas no momento. HTML html; // Criador de páginas html. private static final int DEFAULT_USERS_PER_PAGE = 50; private static final int DEFAULT_MESSAGES_PER_PAGE = 50; @Override public Server initialize(String dbLoginName, String dbName, String dbPassword, ServletContext context) { // Cria a tabela de sessões abertas, vazia: this.sessionTable = new SessionTableImpl().initialize(); // Cria a tabela de usuários, vazia: this.userTable = new UserTableImpl().initialize(); if (dbName != null) { // Conecta com a base de dados persitente e carrega na memória: this.database = new DatabaseImpl().initialize(dbLoginName, dbName, dbPassword); // Carrega usuários, mensagens e contatos: this.database.loadDatabase(userTable, nextUserId, nextMessageId, context); } // Inicializa o criador de paginas html: html = new HTMLImpl().initialize(this); return this; } @Override public void processHomePageReq ( HttpServletRequest request, HttpServletResponse response, ServletContext context ) throws IOException, ServletException { try { // Obtém o dono da sessão: User requestor = getSessionOwnerFromRequest(request); html.homePage(response, requestor); } catch(ReqError e) { html.errorPage(response, e.errorMessage); return; } } @Override public void processRegistrationReq ( HttpServletRequest request, HttpServletResponse response, ServletContext context ) throws IOException, ServletException { try { // Obtém o nome de login e verifica se é aceitável e está disponível: String loginName = getRequiredParameter(request, "loginName"); if (! validLoginName(loginName)) { throw new ReqError("Nome de login inaceitável"); } if (this.userTable.getUserByLoginName(loginName) != null) { throw new ReqError("Nome de login já está em uso"); } // Obtém o email e verifica se é válido e específico deste usuário: String email = getRequiredParameter(request, "email"); if (! validEmail(email)) { throw new ReqError("Email inaceitável"); } if (this.userTable.getUserByEmail(email) != null) { throw new ReqError("Ja existe uma conta com este email"); } // Verifica se a senha é aceitável String password = getRequiredParameter(request, "password"); if (! validPassword(password)) { throw new ReqError("Senha inaceitável"); } // Obtém o nome completo do usuário e converte de Latin-1 para UTF-8: String fullNameLatin1 = getRequiredParameter(request, "fullName"); String fullName = new String(fullNameLatin1.getBytes("iso-8859-1"), "UTF-8"); // Cria o usuário e acrescenta à tabela: long dbIndex = this.nextUserId; long timestamp = currentTime(); User user = new UserImpl().initialize(loginName, email, fullName, password, timestamp, dbIndex); if (user == null) { throw new ReqError("Falha ao criar usuário"); } else { this.nextUserId++; this.database.addUser(user); this.userTable.add(user); this.html.loginPage(response); } return; } catch(ReqError e) { html.errorPage(response, e.errorMessage); return; } } @Override public void processLoginReq ( HttpServletRequest request, HttpServletResponse response, ServletContext context ) throws IOException, ServletException { try { // Obtem o nome de login e a senha do {request}: String loginName = getRequiredParameter(request, "loginName"); String password = getRequiredParameter(request, "password"); User user = this.userTable.getUserByLoginPassword(loginName, password); if (user != null) { // Cria uma sessao para o usuario: String cookie = UUID.randomUUID().toString(); Session session = new SessionImpl(); session.open(user, cookie); sessionTable.add(session); // Adiciona o cookie no browser: addCookie(response, COOKIE_NAME, cookie, COOKIE_AGE); html.homePage(response, user); } else { // Usuário inválido, mostra erro: throw new ReqError("Falha ao realizar login"); } return; } catch(ReqError e) { html.errorPage(response, e.errorMessage); return; } } @Override public void processLogoutReq ( HttpServletRequest request, HttpServletResponse response, ServletContext context ) throws IOException, ServletException { try { // Obtém a sessão de login: Session session = getSessionFromRequest(request); if (session == null) { throw new ReqError("Sessão não existe"); } // Remove a sessao do servidor: sessionTable.delete(session); // Remove o cookie do navegador: removeCookie(response, COOKIE_NAME); // Apresenta a página de login ao leitor: html.loginPage(response); return; } catch(ReqError e) { html.errorPage(response, e.errorMessage); return; } } @Override public void processListAllUsersReq ( HttpServletRequest request, HttpServletResponse response, ServletContext context ) throws IOException, ServletException { try { // Obtém o dono da sessão, se houver: User requestor = getSessionOwnerFromRequest(request); // Obtém a lista de todos os usuários do sistema: List list = this.userTable.getAllUsers(); // Obtém os parâmetros que especificam um trecho da lista: int dir = getOptionalDirParameter(request); int nAll = list.size(); int start = getOptionalStartParameter(request, dir, nAll); int n = getOptionalNParameter(request, start, dir, nAll, DEFAULT_USERS_PER_PAGE); start = (dir == +1 ? start : start - n + 1); assert((start >= 0) && (start + n < nAll)); // Monta a página de resposta: String title = "Usuários do sistema"; String requestMoreCmd = "ListAllUsers"; // Comando para pedir mais um lote. html.listPage(response, requestor, title, list, start, n, requestMoreCmd, null, DEFAULT_USERS_PER_PAGE); return; } catch(ReqError e) { html.errorPage(response, e.errorMessage); return; } } @Override public void processShowUserProfileReq ( HttpServletRequest request, HttpServletResponse response, ServletContext context ) throws IOException, ServletException { try { // Obtém o dono da sessão, se houver: User requestor = getSessionOwnerFromRequest(request); // Obtém o nome de login do usuário: String loginName = getNonEmptyParameter(request, "loginName"); if (loginName == null) { // Talvez o URL seja "Quack/{loginName}": String URL = request.getRequestURI(); String parseURL[] = URL.split("/"); int n = parseURL.length; if (parseURL[n-1].equals("")) { n--; } if (! parseURL[n-2].equals("Quack")) { throw new ReqError("URL inválida"); } loginName = parseURL[n-1]; } // Obtém o usuário a listar: User user = userTable.getUserByLoginName(loginName); if (user == null) { throw new ReqError("Usuario nao existe"); } // Obtém o contato entre os dois, se existir: Contact contact = requestor.getDirectContact(user); // Gera a página: html.userProfilePage(response, requestor, user, contact); return; } catch(ReqError e) { html.errorPage(response, e.errorMessage); return; } } @Override public void processModifyContactReq ( HttpServletRequest request, HttpServletResponse response, ServletContext context ) throws IOException, ServletException { try { // Obtém o dono da sessão: User requestor = getSessionOwnerFromRequest(request); if (requestor == null) { throw new ReqError("Sessão expirada ou usuário não está logado"); } // O usuário de origem é o dono da sessão: User source = requestor; // O usuário alvo é identificado nos parâmetros do {request}: String targetLoginName = getRequiredParameter(request, "loginName"); User target = userTable.getUserByLoginName(targetLoginName); if (target == null) { throw new ReqError("Usuario nao existe!"); } if (source == target) { throw new ReqError("Nao pode haver contato com si mesmo"); } // O novo estado é também especificado no {request}: String newStatus = getRequiredParameter(request, "status"); long timestamp = currentTime(); Contact c = source.getDirectContact(target); if (c != null){ //Contato ja existe assert(c != null); assert(c == target.getReverseContact(source)); c.setStatus(newStatus, timestamp); database.modifyContact(c); } else { //Contato ainda nao existe c = new ContactImpl().initialize(source, target, newStatus, timestamp); source.addDirectContact(c); target.addReverseContact(c); this.numContacts += 1; database.addContact(c); } html.userProfilePage(response, requestor, target, c); return; } catch(ReqError e) { html.errorPage(response, e.errorMessage); return; } } @Override public void processModifyUserReq ( HttpServletRequest request, HttpServletResponse response, ServletContext context ) throws IOException, ServletException { try { // Obtém o dono da sessão: User requestor = getSessionOwnerFromRequest(request); if (requestor == null) { throw new ReqError("Sessão expirada ou usuário não está logado"); } String newFullName = new String(getRequiredParameter(request, "fullName").getBytes("iso-8859-1"), "UTF-8"); String newPassword = getRequiredParameter(request, "newPassword"); String oldPassword = getRequiredParameter(request, "oldPassword"); // O usuário a ser alterado é o dono da sessão: User user = requestor; if (! newPassword.equals("")) { // Altera a senha do usuário: if (user.checkPassword(oldPassword) == false) { throw new ReqError("Senha antiga não confere"); } if (! validPassword(newPassword)) { throw new ReqError("Nova senha inválida"); } user.setPassword(newPassword); } if (! newFullName.equals("")) { // Altera o nome completo do usuário user.setFullName(newFullName); } database.modifyUser(user); html.userProfilePage(response, requestor, user, null); return; } catch(ReqError e) { html.errorPage(response, e.errorMessage); return; } } @Override public void processShowPostedMessagesReq ( HttpServletRequest request, HttpServletResponse response, ServletContext context ) throws IOException, ServletException { try { // Obtém o dono da sessão, se houver: User requestor = getSessionOwnerFromRequest(request); // Obtem o usuário cujas mensagens é preciso listar: String loginName = getRequiredParameter(request, "loginName"); User poster = userTable.getUserByLoginName(loginName); if (poster == null) { throw new ReqError("Usuario nao existe"); } // Obtém a lista de todas as mensagens do usuário: List list = poster.getPostedMessages(); int nAll = list.size(); // Obtém os parâmetros que especificam um trecho da lista: // !!{ Permitir também a opção {iniDate/FinDate} }!! int dir = getOptionalDirParameter(request); int start = getOptionalStartParameter(request, dir, nAll); int n = getOptionalNParameter(request, start, dir, nAll, DEFAULT_MESSAGES_PER_PAGE); start = (dir == +1 ? start : start - n + 1); assert((start >= 0) && (start + n < nAll)); // Lista o trecho especificado de mensagens: String title = "Messages posted by " + loginName + " (" + poster.getFullName() + ")"; String requestMoreCmd = "ShowPostedMessages"; // Comando para pedir mais um lote. html.listPage(response, requestor, title, list, start, n, requestMoreCmd, poster, DEFAULT_MESSAGES_PER_PAGE); } catch(ReqError e) { html.errorPage(response, e.errorMessage); return; } } @Override public void processShowReceivedMessagesReq ( HttpServletRequest request, HttpServletResponse response, ServletContext context ) throws IOException, ServletException { try { // Obtém o dono da sessão: User requestor = getSessionOwnerFromRequest(request); if (requestor == null) { throw new ReqError("Sessão expirada ou usuário não está logado"); } // O usuário cuja caixa de entrada deve ser listada é o dono da sessão: User user = requestor; // Obtém a lista de todas as mensagens recebidas pelo usuário: // !!{ Otimizar algum dia para obter só as necessárias para a página: }?? List list = user.getIncomingMessages(); int nAll = list.size(); // Obtém os parâmetros de paginação da lista: // !!{ Permitir também a opção {iniDate/FinDate} }!! int dir = getOptionalDirParameter(request); int start = getOptionalStartParameter(request, dir, nAll); int n = getOptionalNParameter(request, start, dir, nAll, DEFAULT_MESSAGES_PER_PAGE); start = (dir == +1 ? start : start - n + 1); assert((start >= 0) && (start + n < nAll)); // Lista o trecho especificado de mensagens: String loginName = user.getLoginName(); String fullName = user.getFullName(); String title = "Incoming messages " + loginName + " (" + fullName + ")"; String requestMoreCmd = "ShowReceivedMessages"; // Comando para pedir mais um lote. html.listPage(response, requestor, title, list, start, n, requestMoreCmd, user, DEFAULT_MESSAGES_PER_PAGE); } catch(ReqError e) { html.errorPage(response, e.errorMessage); return; } } @Override public void processSendMessageReq ( HttpServletRequest request, HttpServletResponse response, ServletContext context ) throws IOException, ServletException { processSendOrRepostMessageReq(request, response, context, false); } @Override public void processRepostMessageReq ( HttpServletRequest request, HttpServletResponse response, ServletContext context ) throws IOException, ServletException { processSendOrRepostMessageReq(request, response, context, true); } private void processSendOrRepostMessageReq ( HttpServletRequest request, HttpServletResponse response, ServletContext context, boolean repost ) throws IOException, ServletException { try { // Obtem o usuário dono da sessão: User requestor = getSessionOwnerFromRequest(request); if (requestor == null){ throw new ReqError("Sessão encerrada ou usuário não logado"); } // O postador é o dono da sessão: User poster = requestor; // Data de postagem: long timestamp = currentTime(); long dbIndex = this.nextMessageId; // Compose the message Message message = new MessageImpl(); if (repost) { // A mensagem a repostar é identificada pelo usuário postador e timestamp: String parentPosterLoginArg = getRequiredParameter(request, "author"); if (parentPosterLoginArg == null){ throw new ReqError("Falta parâmetro \"author\""); } User parentPoster = this.userTable.getUserByLoginName(parentPosterLoginArg); if (parentPoster == null) { throw new ReqError("Autor desconhecido"); } String parentTimestampArg = getRequiredParameter(request, "timestamp"); if (parentTimestampArg == null) { throw new ReqError("falta parâmetro \"timestamp\";"); } long parentTimestamp = Long.valueOf(parentTimestampArg); Message parent = parentPoster.getMessageByPostedTime(parentTimestamp); if (parent == null) { throw new ReqError("Mensagem inexistente"); } message.initialize(poster, parent, dbIndex, timestamp); } else { // O corpo da mensagem é passado no {request} String rawBody = getRequiredParameter(request, "messageText") ; if (rawBody == null) { throw new ReqError("Falta corpo da mensagem"); } String body = new String(getRequiredParameter(request, "messageText").getBytes("iso-8859-1"), "UTF-8"); message.initialize(poster, body, dbIndex, timestamp); } if (message == null) { throw new ReqError("Falha na criação da mensagem"); } this.nextMessageId++; database.addMessage(message); poster.addMessage(message); html.userProfilePage(response, requestor, poster, null); // !!{ Tratar mensagens de resposta a usuário(s). }!! return; } catch(ReqError e) { html.errorPage(response, e.errorMessage); return; } } @Override public void processShowContactsReq ( HttpServletRequest request, HttpServletResponse response, ServletContext context ) throws IOException, ServletException { processShowDirectOrReverseContactsReq(request, response, context, true); } @Override public void processShowReverseContactsReq ( HttpServletRequest request, HttpServletResponse response, ServletContext context ) throws IOException, ServletException { processShowDirectOrReverseContactsReq(request, response, context, false); } private void processShowDirectOrReverseContactsReq ( HttpServletRequest request, HttpServletResponse response, ServletContext context, boolean direct ) throws IOException, ServletException // Processa pedido para listar contatos diretos ou inversos do // usuário que é dono da sessão identificada no request}. { try { // Obtem o usuário dono da sessão: User requestor = getSessionOwnerFromRequest(request); if (requestor == null){ throw new ReqError("Sessão encerrada ou usuário não logado"); } // O usuário a ser listado é o dono da sessão: User user = requestor; // Obtém os contatos que tem {user} como alvo: List list = (direct ? user.getDirectContacts() : user.getReverseContacts()); int nAll = list.size(); // Obtém os parâmetros de paginação da lista: // !!{ Permitir também a opção {iniDate/FinDate} }!! int dir = getOptionalDirParameter(request); int start = getOptionalStartParameter(request, dir, nAll); int n = getOptionalNParameter(request, start, dir, nAll, DEFAULT_USERS_PER_PAGE); start = (dir == +1 ? start : start - n + 1); assert((start >= 0) && (start + n < nAll)); // Lista o trecho especificado de mensagens: String loginName = user.getLoginName(); String fullName = user.getFullName(); String titleWhich = (direct ? "Contacts" : "Reverse contacts"); String title = titleWhich + " of " + loginName + " (" + fullName + ")"; String requestMoreCmd = (direct ? "ShowContacts" : "ShowReverseContacts"); html.listPage(response, requestor, title, list, start, n, requestMoreCmd, user, DEFAULT_USERS_PER_PAGE); return; } catch(ReqError e) { html.errorPage(response, e.errorMessage); return; } } @Override public long getNumUsers() { return userTable.getUserCount(); } @Override public long getNumContacts() { return this.numContacts; } @Override public long getNumMessages() { return this.nextMessageId; } @Override public long getNumSessions() { return sessionTable.getSessionCount(); } @Override public long currentTime() { return Calendar.getInstance().getTimeInMillis() / 1000; } // ---------------------------------------------------------------------- // FUNÇÕES PARA TESTES public final HTML getHtmlFormatter() // Retorna o formatador de páginas {this.html}. { return this.html; } public final UserTable getUserTable() // Retorna a tabela de usuáriso cadastrados do sistema. { return this.userTable; } public final SessionTable getSessionTable() // Retorna a tabela de usuáriso cadastrados do sistema. { return this.sessionTable; } // ---------------------------------------------------------------------- // UTILITÁRIOS public final List getAllUsers() // Retorna uma lista {List} contendo todos os usuarios // cadastrados no sistema, ??{ Deveria ser em ordem alfabética? }??. { return this.userTable.getAllUsers(); } private final User getUserFromLoginName(String loginName) // Encontra o {User} com nome login {loginName}, procurando na tabela de usuários // que fica salva na instância de {Server}. Se não existir, retorna {null}. { return userTable.getUserByLoginName(loginName); } private static final boolean validLoginName(String loginName) // Devolve {true} se e somente se o {loginName} tem o tamanho e // formato válidos para um nome de login. { // !!{ Conferir se bate com os comentários na interface. }!! // Restringe os caracteres válidos de {loginName} para // dígitos de 0 a 9, letras de A a Z (maiúsculas ou // minúsculas) e o caractere '_'. for (int i = 0; i < loginName.length(); i++) { char c = loginName.charAt(i); if ((c < '0' || c > '9') && (c < 'A' || c > 'Z') && (c < 'a' || c > 'z') && c != '_') { return false; } } return true; } private static final boolean validEmail(String email) // Devolve {true} se e somente se o {email} tem o tamano e formato // válidos para um endereço de email. { // !!{ Conferir se bate com os comentários na interface. }!! // Restringe os caracteres válidos de {email} para // dígitos de 0 a 9, letras de A a Z (maiúsculas ou // minúsculas) e os caracteres '_', '.', '@', '-'. for (int i = 0; i < email.length(); i++) { char c = email.charAt(i); if ((c < '0' || c > '9') && (c < 'A' || c > 'Z') && (c < 'a' || c > 'z') && c != '_' && c != '-' && c != '.' && c != '@') { return false; } } return true; } private static final boolean validPassword(String password) // Devolve {true} se e somente se o {password} tem o tamano e // formato válidos para uma senha. { // !!{ Conferir se bate com os comentários na interface. }!! // Restringe os caracteres válidos de {password} para // qualquer caractere da tabela ASCII, exceto // caracteres de controle. for (int i = 0; i < password.length(); i++) { char c = password.charAt(i); if (c < ' ' || c > '~') { return false; } } return true; } private static final String getNonEmptyParameter(HttpServletRequest request, String name) // Equivale a {request.getParameter(name)} mas retorna {null} se o resultado // for uma cadeia vazia (ou se o parâmetro não foi especificado). { String arg = request.getParameter(name); if ((arg == null) || (arg.equals(""))) { return null; } return arg; } private static final String getRequiredParameter(HttpServletRequest request, String name) throws ReqError // Tenta obter o parâmetro de nome {name} no {request}. Se existir, devolve o seu valor (um // string). Senão atira a exeção {ReqError}. { String arg = getNonEmptyParameter(request, name); if (arg == null) { throw new ReqError("Faltou parâmetro \"" + name + "\""); } return arg; } private static final long getOptionalLongParameter(HttpServletRequest request, String name, long defaultVal) throws ReqError // Tenta obter o parâmetro de nome {name} no {request}. Se existir e for um valor {long} válido, // devolve o seu valor convertido para {long}. Se não existir ou for // vazio, devolve {defaultVal}. Senão atira a exeção {ReqError}. { String nArg = getNonEmptyParameter(request, name); if (nArg == null) { return defaultVal; } try { long n = Long.valueOf(nArg); return n; } catch (NumberFormatException e) { throw new ReqError("Inteiro inválido \"" + nArg + "\""); } } private static final int getOptionalIntParameter(HttpServletRequest request, String name, int defaultVal) throws ReqError // Tenta obter o parâmetro de nome {name} no {request}. Se existir e for um {int} válido, // devolve o seu valor convertido para {int}. Se não existir ou for // vazio, devolve {defaultVal}. Senão atira a exeção {ReqError}. { String nArg = getNonEmptyParameter(request, name); if (nArg == null) { return defaultVal; } try { int n = Integer.valueOf(nArg); return n; } catch (NumberFormatException e) { throw new ReqError("Inteiro inválido \"" + nArg + "\""); } } private static final int getOptionalDirParameter(HttpServletRequest request) throws ReqError // Tenta obter o parâmetro de nome "dir" no {request}. Se não existir, devolve {+1}. // Se existir, e seu valor for um inteiro {-1} ou {+1}, devolve esse valor. // Senão, atira a exeção {ReqError}. { int dir = getOptionalIntParameter(request, "dir", +1); if ((dir != -1) && (dir != +1)) { throw new ReqError("Parâmetro \"dir\" inválido"); } return dir; } private static final int getOptionalStartParameter(HttpServletRequest request, int dir, int nAll) throws ReqError // Tenta obter o parâmetro de nome "start" no {request}, ajustando-o // para ser um índice válido na lista. // // Supõe que {dir} é {-1} ou {+1}. // // Se o parâmetro "start" existir, e seu valor for um inteiro em // {0..nAll-1}, devolve esse valor. Se não existir, ou seu valor for // um inteiro fora desse intervalo, devolve {0} ou {nAll-1}, // conforme {dir} for {+1} ou {-1}. Senão, atira a exeção // {ReqError}. { assert((dir == -1) || (dir == +1)); int start = getOptionalIntParameter(request, "start", -1); // Default {-1} erá corrigido depois. if ((start >= 0) && (start < nAll)) { return start; } start = (dir > 0 ? 0 : nAll - 1); return start; } private static final int getOptionalNParameter(HttpServletRequest request, int start, int dir, int nAll, int nDefault) throws ReqError // Tenta obter o parâmetro de nome "n" (número de mensagens ou usuários a listar) // no {request}, ajustando-o para não exceder os elementos disponívels na lista. // // Supõe que {dir} é {-1} ou {+1}, {nAll} é um inteiro não negativo, // e, se {nAll>0}, {start} é um inteiro em {0..nAll-1}. Seja {nMax} // zero se {nAll} é zero; ou o número elementos desde {start}, // inclusive, até {0}, inclusive, se {dir} é {-1}; ou até {nAll-1}, // se {dir} é {+1}. // // Se o parâmetro "n" existir, e seu valor for um inteiro, // devolve esse inteiro, ajustdo para o intervalo {1..nMax}. Se não // existir, devolve {nDefault}, ajustdo para o intervalo {1..nMax}. Senão, // atira a exeção {ReqError}. { assert((dir == -1) || (dir == +1)); assert(nDefault > 0); int n = getOptionalIntParameter(request, "n", nDefault); if (n < 1) { n = 1; } int nMax; if (nAll == 0) { nMax = 0; } else { assert((start >= 0) && (start < nAll)); nMax = (dir < 0 ? start + 1 : nAll - start); } if (n > nMax) { n = nMax; } return n; } private static final String getFileName(final Part part) // Este metodo é chamado quando é necessário descobrir o nome de um // arquivo a ser enviado para o servidor. O parâmetro {part} // corresponde à uma parte (bloco de bytes) do arquivo. Retorna uma // string contendo o nome do arquivo. { final String partHeader = part.getHeader("content-disposition"); // LOGGER.log(Level.INFO, "Part Header = {0}", partHeader); for (String content : part.getHeader("content-disposition").split(";")) { if (content.trim().startsWith("filename")) { return content.substring(content.indexOf('=') + 1).trim().replace("\"", ""); } } return null; } private static final String COOKIE_NAME = "COOKIE_QUACK"; // Nome do nosso cookie. private static final int COOKIE_AGE = 2592000; // Tempo da validade do cookie, em segundos. private final Session getSessionFromRequest(HttpServletRequest request) throws ReqError // Retorna a sessão identifcada pelo cookie do sistema Quack que veio no {request}. // Retorna {null} se o cookie não está no {request}, ou // ele não corresponde a uma sessão aberta. { String cookie = getCookieValue(request, COOKIE_NAME); Session session = sessionTable.getSessionByCookie(cookie); return session; } private final User getSessionOwnerFromRequest(HttpServletRequest request) throws ReqError // Retorna o usuário que é dono da sessão identificada pelo cookie // do sistema Quack que veio no {request}. Retorna {null} se o // cookie não está no {request}, ou ele não corresponde a uma sessão // aberta. { Session session = getSessionFromRequest(request); User owner = (session == null ? null : session.getUser()); return owner; } private static final String getCookieValue(HttpServletRequest request, String name) // Recupera um cookie do {request}; retorna {null} se não encontrou. { Cookie[] cookies = request.getCookies(); if (cookies != null) { for (Cookie cookie : cookies) { if (name.equals(cookie.getName())) { return cookie.getValue(); } } } return null; } private static final void addCookie(HttpServletResponse response, String name, String value, int maxAge) // Adiciona um cookie novo ao {response}. { Cookie cookie = new Cookie(name, value); cookie.setPath("/"); cookie.setMaxAge(maxAge); response.addCookie(cookie); } private static final void removeCookie(HttpServletResponse response, String name) // Remove um cookie do {response}. { addCookie(response, name, null, 0); } }