// Copyright 2010 Google Inc. All Rights Reseved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.google.testing.testify.risk.frontend.server.util; import com.google.appengine.api.taskqueue.Queue; import com.google.appengine.api.taskqueue.QueueFactory; import com.google.appengine.api.taskqueue.TaskOptions; import com.google.appengine.api.taskqueue.TransientFailureException; import com.google.appengine.api.utils.SystemProperty; import com.google.testing.testify.risk.frontend.server.InsufficientPrivlegesException; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.List; import java.util.Properties; import java.util.logging.Logger; import javax.jdo.PersistenceManager; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.Session; import javax.mail.Transport; import javax.mail.internet.AddressException; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; /** * Utility methods for servlets. * * @author jimr@google.com (Jim Reardon) */ public class ServletUtils { private static final String URL = System.getProperty("com.google.testing.testify.risk.frontend.url"); private static final Logger LOG = Logger.getLogger(ServletUtils.class.getName()); private static final int QUEUE_RETRIES = 10; private ServletUtils() {} // COV_NF_LINE /** * Throws an access exception if user doesn't have access to do the operation. EG: * ServerletUtils.requireAccess(userService.hasAccess(...)). * * @param hasAccess */ public static void requireAccess(boolean hasAccess) { // TODO(jimr): It'd be nice if this was less clunky. Figure out a way to do that. if (!hasAccess) { throw new InsufficientPrivlegesException("You don't have access to perform that action."); } } /** * Lists returned from GAE's PersistanceManager are a private type which cannot be marshalled to * client-side GWT code. This method simply copies elements from whatever input List<T> into a * GWT-friendly detached ArrayList<T>. * * @param inputList the list to safenize. * @param pm the persistence manager. This is needed in order to create a detached copy. * @return a copied, serialization-safe list. */ public static <T> List<T> makeGwtSafe(List<T> inputList, PersistenceManager pm) { List<T> copiedList = new ArrayList<T>(inputList.size()); for (T item : inputList) { copiedList.add(pm.detachCopy(item)); } return copiedList; } /** * Lists returned from GAE's PersistanceManager are a private type which cannot be marshalled to * client-side GWT code. This method simply copies elements from whatever input <T> into a * GWT-friendly detached <T>. * * @param input the item to safenize. * @param pm the persistence manager. This is needed in order to create a detached copy. * @return a copied, serialization-safe item. */ public static <T> T makeGwtSafe(T input, PersistenceManager pm) { return pm.detachCopy(input); } public static boolean queueWithRetries(String queueName, TaskOptions task, String description) { Queue queue = QueueFactory.getQueue(queueName); for (int i = 0; i < QUEUE_RETRIES; i++) { try { queue.add(task); return true; } catch (TransientFailureException e) { LOG.warning("Retrying queue add for task due to queue failure: " + description); } } LOG.severe("Could not enqueue task after " + QUEUE_RETRIES + "retries: " + description); return false; } public static void notifyRemovedAccess(String from, List<String> emails, String accessType, String project, String projectId) { notifyAccessChanged(from, emails, accessType, project, projectId, false); } public static void notifyAddedAccess(String from, List<String> emails, String accessType, String project, String projectId) { notifyAccessChanged(from, emails, accessType, project, projectId, true); } private static void notifyAccessChanged(String from, List<String> emails, String accessType, String project, String projectId, boolean isAdded) { LOG.info("Trying to message users about change in " + accessType + " access."); if (emails.size() < 1) { LOG.warning("No emails specified to notify."); return; } try { String url = URL + "/#/" + projectId +"/project-settings"; String verb = isAdded ? "added" : "removed"; String change = "You have been " + verb + " as an " + accessType + " of Test Analytics Project: " + project; Session session = Session.getDefaultInstance(new Properties(), null); for (String email : emails) { Message msg = new MimeMessage(session); msg.setFrom(new InternetAddress(from, "Test Analytics on behalf of " + from)); LOG.info("Sending email to " + email + "(" + change + ")"); msg.addRecipient(Message.RecipientType.TO, new InternetAddress(email)); msg.setSubject(change); msg.setText(change + "\n\nThis Test Analytics project's URL:\n\n" + url + "\n\nIf you believe this was a mistake, contact " + from + " who made the change."); if (SystemProperty.environment.value().equals( SystemProperty.Environment.Value.Production)) { Transport.send(msg); } else { LOG.info("Not actually sending email; not in production environment."); } } } catch (UnsupportedEncodingException e) { // COV_NF_START LOG.severe("Couldn't send email."); } catch (AddressException e) { LOG.severe("Couldn't send email."); } catch (MessagingException e) { LOG.severe("Couldn't send email."); } // COV_NF_END } }