plugins/base2/net.sf.basedb.illumina/trunk/src/net/sf/basedb/illumina/servlet/IlluminaPlotServlet.java

Code
Comments
Other
Rev Date Author Line
1133 18 Jun 09 martin 1 /**
1133 18 Jun 09 martin 2   $Id$
1133 18 Jun 09 martin 3
1133 18 Jun 09 martin 4   Copyright (C) 2009 Martin Svensson
1133 18 Jun 09 martin 5
1133 18 Jun 09 martin 6   This file is part of BASE - BioArray Software Environment.
1133 18 Jun 09 martin 7   Available at http://base.thep.lu.se/
1133 18 Jun 09 martin 8
1133 18 Jun 09 martin 9   BASE is free software; you can redistribute it and/or
1133 18 Jun 09 martin 10   modify it under the terms of the GNU General Public License
1133 18 Jun 09 martin 11   as published by the Free Software Foundation; either version 3
1133 18 Jun 09 martin 12   of the License, or (at your option) any later version.
1133 18 Jun 09 martin 13
1133 18 Jun 09 martin 14   BASE is distributed in the hope that it will be useful,
1133 18 Jun 09 martin 15   but WITHOUT ANY WARRANTY; without even the implied warranty of
1133 18 Jun 09 martin 16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1133 18 Jun 09 martin 17   GNU General Public License for more details.
1133 18 Jun 09 martin 18
1133 18 Jun 09 martin 19   You should have received a copy of the GNU General Public License
1133 18 Jun 09 martin 20   along with BASE. If not, see <http://www.gnu.org/licenses/>.
1133 18 Jun 09 martin 21 */
1133 18 Jun 09 martin 22
1133 18 Jun 09 martin 23 package net.sf.basedb.illumina.servlet;
1133 18 Jun 09 martin 24
1133 18 Jun 09 martin 25 import net.sf.basedb.core.Application;
1133 18 Jun 09 martin 26 import net.sf.basedb.core.BioAssay;
1133 18 Jun 09 martin 27 import net.sf.basedb.core.BioAssaySet;
1133 18 Jun 09 martin 28 import net.sf.basedb.core.DbControl;
1133 18 Jun 09 martin 29 import net.sf.basedb.core.DynamicResultIterator;
1133 18 Jun 09 martin 30 import net.sf.basedb.core.DynamicSpotQuery;
1133 18 Jun 09 martin 31 import net.sf.basedb.core.ItemQuery;
1133 18 Jun 09 martin 32 import net.sf.basedb.core.SessionControl;
1135 23 Jun 09 martin 33 import net.sf.basedb.core.query.Dynamic;
1135 23 Jun 09 martin 34 import net.sf.basedb.core.query.Expression;
1135 23 Jun 09 martin 35 import net.sf.basedb.core.query.Expressions;
1135 23 Jun 09 martin 36 import net.sf.basedb.core.query.JoinType;
1133 18 Jun 09 martin 37 import net.sf.basedb.core.query.Restriction;
1133 18 Jun 09 martin 38 import net.sf.basedb.core.query.Restrictions;
1133 18 Jun 09 martin 39 import net.sf.basedb.core.query.Selects;
1133 18 Jun 09 martin 40 import net.sf.basedb.core.query.SqlResult;
1133 18 Jun 09 martin 41 import net.sf.basedb.util.FileUtil;
1133 18 Jun 09 martin 42 import net.sf.basedb.util.StaticCache;
1133 18 Jun 09 martin 43 import net.sf.basedb.util.Values;
1133 18 Jun 09 martin 44
1133 18 Jun 09 martin 45 import java.awt.Color;
1133 18 Jun 09 martin 46 import java.awt.Font;
1133 18 Jun 09 martin 47 import java.awt.Graphics2D;
1133 18 Jun 09 martin 48 import java.awt.font.FontRenderContext;
1133 18 Jun 09 martin 49 import java.awt.geom.Rectangle2D;
1133 18 Jun 09 martin 50 import java.awt.image.BufferedImage;
1133 18 Jun 09 martin 51 import java.awt.image.RenderedImage;
1133 18 Jun 09 martin 52 import java.io.IOException;
1133 18 Jun 09 martin 53 import java.io.InputStream;
1133 18 Jun 09 martin 54 import java.io.OutputStream;
1133 18 Jun 09 martin 55 import java.util.ArrayList;
1133 18 Jun 09 martin 56 import java.util.List;
1133 18 Jun 09 martin 57
1133 18 Jun 09 martin 58 import javax.imageio.ImageIO;
1133 18 Jun 09 martin 59 import javax.servlet.ServletConfig;
1133 18 Jun 09 martin 60 import javax.servlet.ServletException;
1133 18 Jun 09 martin 61 import javax.servlet.http.HttpServlet;
1133 18 Jun 09 martin 62 import javax.servlet.http.HttpServletRequest;
1133 18 Jun 09 martin 63 import javax.servlet.http.HttpServletResponse;
1133 18 Jun 09 martin 64
1133 18 Jun 09 martin 65 import org.apache.commons.io.output.TeeOutputStream;
1133 18 Jun 09 martin 66 import org.jfree.chart.JFreeChart;
1135 23 Jun 09 martin 67 import org.jfree.chart.axis.CategoryAxis;
1135 23 Jun 09 martin 68 import org.jfree.chart.axis.CategoryLabelPositions;
1133 18 Jun 09 martin 69 import org.jfree.chart.axis.NumberAxis;
1133 18 Jun 09 martin 70 import org.jfree.chart.labels.StandardCategoryToolTipGenerator;
1133 18 Jun 09 martin 71 import org.jfree.chart.plot.CategoryPlot;
1133 18 Jun 09 martin 72 import org.jfree.chart.renderer.category.CategoryItemRenderer;
1133 18 Jun 09 martin 73 import org.jfree.chart.renderer.category.LineAndShapeRenderer;
1133 18 Jun 09 martin 74 import org.jfree.chart.title.TextTitle;
1133 18 Jun 09 martin 75 import org.jfree.data.category.DefaultCategoryDataset;
1133 18 Jun 09 martin 76 import org.jfree.data.statistics.Statistics;
1133 18 Jun 09 martin 77
1133 18 Jun 09 martin 78 /**
1141 24 Jun 09 martin 79    This servlet can plot the controls summary for a Illumina bioassay set. 
1141 24 Jun 09 martin 80    The generated plot contains one dataset for perfectmatch report and 
1141 24 Jun 09 martin 81    one dataset for housekeeping report. 
1141 24 Jun 09 martin 82    It uses  the JFreePlot package to generate the plots. 
1141 24 Jun 09 martin 83    This servlet accepts the following parameters:
1141 24 Jun 09 martin 84    
1141 24 Jun 09 martin 85    <table border="1" cellspacing="0" cellpadding="2">
1141 24 Jun 09 martin 86    <tr>
1141 24 Jun 09 martin 87      <th>Parameter</th>
1141 24 Jun 09 martin 88      <th>Required</th>
1141 24 Jun 09 martin 89      <th>Default value</th>
1141 24 Jun 09 martin 90      <th>Description</th>
1141 24 Jun 09 martin 91    </tr>
1141 24 Jun 09 martin 92    
1141 24 Jun 09 martin 93    <tr>
1141 24 Jun 09 martin 94      <td>ID</td>
1141 24 Jun 09 martin 95      <td>yes</td>
1141 24 Jun 09 martin 96      <td></td>
1141 24 Jun 09 martin 97      <td>The SessionControl ID. See {@link Application#getSessionControl(String, String)}.</td>
1141 24 Jun 09 martin 98    </tr>
1141 24 Jun 09 martin 99    
1141 24 Jun 09 martin 100    <tr>
1141 24 Jun 09 martin 101      <td>bioassayset_id</td>
1141 24 Jun 09 martin 102      <td>yes</td>
1141 24 Jun 09 martin 103      <td></td>
1141 24 Jun 09 martin 104      <td>The ID of the bioassay set to plot.</td>
1141 24 Jun 09 martin 105    </tr>
1141 24 Jun 09 martin 106   
1141 24 Jun 09 martin 107   <tr>
1141 24 Jun 09 martin 108      <td>format</td>
1141 24 Jun 09 martin 109      <td>no</td>
1141 24 Jun 09 martin 110      <td>png</td>
1141 24 Jun 09 martin 111      <td>
1141 24 Jun 09 martin 112        The format of the image, "png" and "jpg" are the only supported values. 
1141 24 Jun 09 martin 113      </td>
1141 24 Jun 09 martin 114    </tr>
1141 24 Jun 09 martin 115    
1141 24 Jun 09 martin 116    <tr>
1141 24 Jun 09 martin 117      <td>cacheBase</td>
1141 24 Jun 09 martin 118      <td>no</td>
1141 24 Jun 09 martin 119      <td>plots/</td>
1141 24 Jun 09 martin 120      <td>The base-directory where cached images should be stored.</td          
1141 24 Jun 09 martin 121    </tr>
1133 18 Jun 09 martin 122  
1133 18 Jun 09 martin 123     @author martin
1133 18 Jun 09 martin 124     @since 1.4
1133 18 Jun 09 martin 125  */
1133 18 Jun 09 martin 126
1133 18 Jun 09 martin 127 public final class IlluminaPlotServlet
1133 18 Jun 09 martin 128   extends HttpServlet
1133 18 Jun 09 martin 129 {
1141 24 Jun 09 martin 130   private static final long serialVersionUID = -2969496770778710927L;
1141 24 Jun 09 martin 131   
1141 24 Jun 09 martin 132   private int width = 800;
1141 24 Jun 09 martin 133   private int height = 600;  
1133 18 Jun 09 martin 134   private String defaultFormat = "png";
1133 18 Jun 09 martin 135   private String cacheBase = "plots/";
1133 18 Jun 09 martin 136   
1133 18 Jun 09 martin 137   @Override
1133 18 Jun 09 martin 138   public void init()
1133 18 Jun 09 martin 139     throws ServletException
1133 18 Jun 09 martin 140   {
1133 18 Jun 09 martin 141     ServletConfig cfg = getServletConfig();
1133 18 Jun 09 martin 142     defaultFormat = Values.getString(cfg.getInitParameter("defaultFormat"), defaultFormat);
1133 18 Jun 09 martin 143     cacheBase = Values.getString(cfg.getInitParameter("cacheBase"), cacheBase);
1133 18 Jun 09 martin 144   }
1133 18 Jun 09 martin 145   
1133 18 Jun 09 martin 146   @Override
1133 18 Jun 09 martin 147   public void doGet(HttpServletRequest request, HttpServletResponse response)
1133 18 Jun 09 martin 148     throws IOException, ServletException
1133 18 Jun 09 martin 149   {
1133 18 Jun 09 martin 150     final String ID = request.getParameter("ID");
1133 18 Jun 09 martin 151     
1133 18 Jun 09 martin 152     // Where to get the source data
1141 24 Jun 09 martin 153     final int bioAssaySetId = Values.getInt(request.getParameter("bioassayset_id"));    
1133 18 Jun 09 martin 154     String cacheKey = Values.getStringOrNull(request.getParameter("cache"));
1141 24 Jun 09 martin 155     
1141 24 Jun 09 martin 156     // Image settings and format
1133 18 Jun 09 martin 157     String format = Values.getString(request.getParameter("format"), defaultFormat);
1133 18 Jun 09 martin 158     if (!format.equals("jpeg") && !format.equals("png"))
1133 18 Jun 09 martin 159     {
1133 18 Jun 09 martin 160       format = defaultFormat;
1133 18 Jun 09 martin 161     }
1133 18 Jun 09 martin 162     
1133 18 Jun 09 martin 163     // Axis, legends and titles
1178 20 Oct 09 jari 164     String title = "Control summary";
1141 24 Jun 09 martin 165     String subTitle = null;    
1133 18 Jun 09 martin 166       
1133 18 Jun 09 martin 167     StaticCache cache = Application.getStaticCache();
1133 18 Jun 09 martin 168     if (cacheKey != null) cacheKey = cacheBase + cacheKey;
1133 18 Jun 09 martin 169     InputStream cachedImageIn = null;
1133 18 Jun 09 martin 170     OutputStream cachedImageOut = null;
1133 18 Jun 09 martin 171     RenderedImage image = null;
1133 18 Jun 09 martin 172     DbControl dc = null;
1133 18 Jun 09 martin 173     boolean wasError = false;
1141 24 Jun 09 martin 174     
1141 24 Jun 09 martin 175     // Get the cached image
1133 18 Jun 09 martin 176     try
1133 18 Jun 09 martin 177     {
1133 18 Jun 09 martin 178       if (cacheKey != null)
1133 18 Jun 09 martin 179       {
1133 18 Jun 09 martin 180         try
1133 18 Jun 09 martin 181         {
1133 18 Jun 09 martin 182           cachedImageIn = cache.read(cacheKey, 500);
1133 18 Jun 09 martin 183         }
1133 18 Jun 09 martin 184         catch (IOException ex)
1133 18 Jun 09 martin 185         {
1133 18 Jun 09 martin 186           ex.printStackTrace();
1133 18 Jun 09 martin 187         }
1133 18 Jun 09 martin 188       }
1133 18 Jun 09 martin 189       try
1133 18 Jun 09 martin 190       {
1133 18 Jun 09 martin 191         if (cachedImageIn == null)
1133 18 Jun 09 martin 192         {
1133 18 Jun 09 martin 193           // Only reload the image if there is no cached version
1133 18 Jun 09 martin 194           final SessionControl sc = Application.getSessionControl(ID, request.getRemoteAddr());
1133 18 Jun 09 martin 195           dc = sc.newDbControl();
1133 18 Jun 09 martin 196           
1135 23 Jun 09 martin 197           String perfectMatch = ":pm";
1135 23 Jun 09 martin 198           String houseKeeping = "housekeeping";
1135 23 Jun 09 martin 199           String restrictionColumn = "controlGroupId";
1135 23 Jun 09 martin 200           String meanColumn = "mean";
1133 18 Jun 09 martin 201           
1141 24 Jun 09 martin 202           // Prepare chart and datasets          
1141 24 Jun 09 martin 203           DefaultCategoryDataset pmDataset = new DefaultCategoryDataset();
1141 24 Jun 09 martin 204           DefaultCategoryDataset houseKeepingDataset = new DefaultCategoryDataset();
1141 24 Jun 09 martin 205                     
1141 24 Jun 09 martin 206           BioAssaySet bas = BioAssaySet.getById(dc, bioAssaySetId);
1141 24 Jun 09 martin 207           ItemQuery<BioAssay> bioassayQuery = bas.getBioAssays();  
1141 24 Jun 09 martin 208           subTitle = bas.getName();
1141 24 Jun 09 martin 209           
1141 24 Jun 09 martin 210           // Prepare filter restrictions and select expression
1135 23 Jun 09 martin 211           Restriction pmRestriction = Restrictions.like(Dynamic.reporter(restrictionColumn), Expressions.string("%"+perfectMatch+"%"));
1135 23 Jun 09 martin 212           Restriction hkRestriction = Restrictions.like(Dynamic.reporter(restrictionColumn), Expressions.string("%"+houseKeeping+"%"));
1135 23 Jun 09 martin 213           Restriction restrictions = Restrictions.or(pmRestriction, hkRestriction);
1135 23 Jun 09 martin 214           Expression yExpression = Dynamic.rawData("mean");
1135 23 Jun 09 martin 215           
1141 24 Jun 09 martin 216           // Get plot data for each bioassay
1141 24 Jun 09 martin 217           List<BioAssay> bioassays = bioassayQuery.list(dc);
1135 23 Jun 09 martin 218           for (BioAssay ba : bioassays)
1133 18 Jun 09 martin 219           {
1135 23 Jun 09 martin 220             List<Number> perfectMatchSpots = new ArrayList<Number>();
1135 23 Jun 09 martin 221             List<Number> houseKeepingSpots = new ArrayList<Number>();
1135 23 Jun 09 martin 222             
1135 23 Jun 09 martin 223             // Configure query restrictions and selection
1133 18 Jun 09 martin 224             DynamicSpotQuery query = ba.getSpotData();
1135 23 Jun 09 martin 225             query.setAutoJoinType(JoinType.INNER);
1133 18 Jun 09 martin 226             query.restrict(restrictions);
1135 23 Jun 09 martin 227             query.select(Selects.expression(yExpression, meanColumn));
1135 23 Jun 09 martin 228             query.select(Selects.expression(Dynamic.reporter("controlGroupId"), restrictionColumn));
1135 23 Jun 09 martin 229             
1141 24 Jun 09 martin 230             // Work through the iteration result to get the wanted plot values
1135 23 Jun 09 martin 231             DynamicResultIterator result = query.iterate(dc);            
1135 23 Jun 09 martin 232             int cgiIndex = result.getIndex(restrictionColumn);
1135 23 Jun 09 martin 233             int meanIndex = result.getIndex(meanColumn);
1135 23 Jun 09 martin 234             while (result.hasNext())
1133 18 Jun 09 martin 235             {
1135 23 Jun 09 martin 236               SqlResult data = result.next();
1135 23 Jun 09 martin 237               if (data.getString(cgiIndex).contains(perfectMatch))
1135 23 Jun 09 martin 238               {
1135 23 Jun 09 martin 239                 perfectMatchSpots.add(data.getFloat(meanIndex));
1135 23 Jun 09 martin 240               }
1135 23 Jun 09 martin 241               if (data.getString(cgiIndex).contains(houseKeeping))
1135 23 Jun 09 martin 242               {
1135 23 Jun 09 martin 243                 houseKeepingSpots.add(data.getFloat(meanIndex));
1135 23 Jun 09 martin 244               }
1133 18 Jun 09 martin 245             }
1141 24 Jun 09 martin 246             // Calculate the mean for each filtered data list and add it to corresponding dataset. 
1135 23 Jun 09 martin 247             pmDataset.addValue(Statistics.calculateMean(perfectMatchSpots), "Perfect match", ba.getName());
1135 23 Jun 09 martin 248             houseKeepingDataset.addValue(Statistics.calculateMean(houseKeepingSpots), "Housekeeping", ba.getName());
1133 18 Jun 09 martin 249           }
1135 23 Jun 09 martin 250           
1141 24 Jun 09 martin 251           // Configure chart settings and create plot-image
1141 24 Jun 09 martin 252           CategoryItemRenderer renderer1 = new LineAndShapeRenderer();
1141 24 Jun 09 martin 253           CategoryItemRenderer renderer2 = new LineAndShapeRenderer();
1133 18 Jun 09 martin 254           NumberAxis axis = new NumberAxis("Signal");
1133 18 Jun 09 martin 255           axis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
1141 24 Jun 09 martin 256           axis.setLabelFont(new Font("SansSerif", Font.BOLD, 14));          
1135 23 Jun 09 martin 257           
1135 23 Jun 09 martin 258           renderer1.setSeriesPaint(0, Color.red);
1135 23 Jun 09 martin 259           renderer2.setSeriesPaint(0, Color.blue);
1135 23 Jun 09 martin 260               renderer1.setBaseToolTipGenerator(new StandardCategoryToolTipGenerator());
1133 18 Jun 09 martin 261               
1141 24 Jun 09 martin 262               CategoryAxis domainAxis = new CategoryAxis("Bioassays");
1141 24 Jun 09 martin 263               domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_45);
1141 24 Jun 09 martin 264               domainAxis.setLabelFont(new Font("SansSerif", Font.BOLD, 14));
1141 24 Jun 09 martin 265               CategoryPlot subplot1 = new CategoryPlot(pmDataset, domainAxis, axis, renderer1);               
1135 23 Jun 09 martin 266               subplot1.setRenderer(1, renderer2);
1135 23 Jun 09 martin 267               subplot1.setDataset(1, houseKeepingDataset);
1141 24 Jun 09 martin 268               subplot1.setDomainGridlinesVisible(true);
1141 24 Jun 09 martin 269               
1141 24 Jun 09 martin 270               JFreeChart chart = new JFreeChart(
1133 18 Jun 09 martin 271                       null, new Font("SansSerif", Font.BOLD, 12),
1141 24 Jun 09 martin 272                       subplot1, true);
1133 18 Jun 09 martin 273           if (title != null) chart.setTitle(title);
1133 18 Jun 09 martin 274           
1141 24 Jun 09 martin 275           chart.addSubtitle(new TextTitle(subTitle));
1133 18 Jun 09 martin 276           image = chart.createBufferedImage(width, height);
1141 24 Jun 09 martin 277         }        
1133 18 Jun 09 martin 278       }
1133 18 Jun 09 martin 279       catch (Throwable t)
1133 18 Jun 09 martin 280       {
1133 18 Jun 09 martin 281         wasError = true;
1133 18 Jun 09 martin 282         t.printStackTrace();
1141 24 Jun 09 martin 283         // Generate error image
1141 24 Jun 09 martin 284         try
1133 18 Jun 09 martin 285         {
1141 24 Jun 09 martin 286           BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
1141 24 Jun 09 martin 287           Graphics2D graphics = img.createGraphics();
1141 24 Jun 09 martin 288           graphics.setBackground(Color.WHITE);
1141 24 Jun 09 martin 289           graphics.clearRect(0, 0, width, height);
1141 24 Jun 09 martin 290           graphics.setColor(Color.RED);
1141 24 Jun 09 martin 291           FontRenderContext context = graphics.getFontRenderContext();
1141 24 Jun 09 martin 292
1141 24 Jun 09 martin 293           Font topFont = new Font("SansSerif", Font.BOLD, 12);
1141 24 Jun 09 martin 294           Font stackTraceFont = new Font("SansSerif", Font.PLAIN, 12);
1141 24 Jun 09 martin 295
1141 24 Jun 09 martin 296           float x = .0f;
1141 24 Jun 09 martin 297           float y = .0f;
1141 24 Jun 09 martin 298           String causedBy = "";
1141 24 Jun 09 martin 299           do
1133 18 Jun 09 martin 300           {
1141 24 Jun 09 martin 301             graphics.setFont(topFont);
1141 24 Jun 09 martin 302             String msg = causedBy + t.getClass().getSimpleName() + ": " + t.getMessage();
1141 24 Jun 09 martin 303             x = 5.0f;
1141 24 Jun 09 martin 304             Rectangle2D bounds = topFont.getStringBounds(msg, context);
1141 24 Jun 09 martin 305             y += bounds.getHeight()+5;
1141 24 Jun 09 martin 306             if (bounds.getWidth() > width - x)
1133 18 Jun 09 martin 307             {
1141 24 Jun 09 martin 308               msg = cutMiddle(msg, (width - x) / bounds.getWidth());
1141 24 Jun 09 martin 309             }
1141 24 Jun 09 martin 310             graphics.drawString(msg, x, y);
1141 24 Jun 09 martin 311             
1141 24 Jun 09 martin 312             graphics.setFont(stackTraceFont);
1141 24 Jun 09 martin 313             x = 15.0f;
1141 24 Jun 09 martin 314             for (StackTraceElement st : t.getStackTrace())
1141 24 Jun 09 martin 315             {
1141 24 Jun 09 martin 316               msg = "at " + st.getClassName() + "." + st.getMethodName() + 
1141 24 Jun 09 martin 317                 ":" + st.getLineNumber();
1141 24 Jun 09 martin 318               bounds = stackTraceFont.getStringBounds(msg, context);
1141 24 Jun 09 martin 319               y += bounds.getHeight();
1133 18 Jun 09 martin 320               if (bounds.getWidth() > width - x)
1133 18 Jun 09 martin 321               {
1133 18 Jun 09 martin 322                 msg = cutMiddle(msg, (width - x) / bounds.getWidth());
1133 18 Jun 09 martin 323               }
1133 18 Jun 09 martin 324               graphics.drawString(msg, x, y);
1141 24 Jun 09 martin 325             }
1141 24 Jun 09 martin 326             t = t.getCause();
1141 24 Jun 09 martin 327             causedBy = "Caused by: ";
1141 24 Jun 09 martin 328           } while (t != null && y < height);
1141 24 Jun 09 martin 329           image = img;
1133 18 Jun 09 martin 330         }
1141 24 Jun 09 martin 331         catch (Throwable t2)
1133 18 Jun 09 martin 332         {
1141 24 Jun 09 martin 333           t2.printStackTrace();
1133 18 Jun 09 martin 334         }
1133 18 Jun 09 martin 335       }
1133 18 Jun 09 martin 336       
1133 18 Jun 09 martin 337       if (image != null || cachedImageIn != null)
1133 18 Jun 09 martin 338       {
1133 18 Jun 09 martin 339         // Send image on HTTP response
1133 18 Jun 09 martin 340         response.setContentType("image/" + format);
1133 18 Jun 09 martin 341         response.setHeader("Cache-Control", "max-age=3600");
1133 18 Jun 09 martin 342         OutputStream out = response.getOutputStream();
1133 18 Jun 09 martin 343         if (cachedImageIn != null)
1133 18 Jun 09 martin 344         {
1133 18 Jun 09 martin 345           FileUtil.copy(cachedImageIn, out);        
1133 18 Jun 09 martin 346         }
1133 18 Jun 09 martin 347         else if (image != null)
1133 18 Jun 09 martin 348         {
1133 18 Jun 09 martin 349           if (cacheKey != null && !wasError) cachedImageOut = cache.write(cacheKey, 100);
1133 18 Jun 09 martin 350           if (cachedImageOut != null)
1133 18 Jun 09 martin 351           {
1133 18 Jun 09 martin 352             out = new TeeOutputStream(out, cachedImageOut);
1133 18 Jun 09 martin 353           }
1133 18 Jun 09 martin 354           ImageIO.write(image, format, out);
1133 18 Jun 09 martin 355         }
1133 18 Jun 09 martin 356         out.flush();
1133 18 Jun 09 martin 357         out.close();
1133 18 Jun 09 martin 358       }
1133 18 Jun 09 martin 359       else
1133 18 Jun 09 martin 360       {
1141 24 Jun 09 martin 361         // Something went wrong when genering the error image - send redirect to a predefined image
1141 24 Jun 09 martin 362         response.sendRedirect(request.getContextPath() + "/images/plot_error.gif");
1133 18 Jun 09 martin 363       }
1133 18 Jun 09 martin 364     }
1133 18 Jun 09 martin 365     finally
1133 18 Jun 09 martin 366     {
1133 18 Jun 09 martin 367       if (dc != null) dc.close();
1133 18 Jun 09 martin 368       if (cachedImageIn != null) cachedImageIn.close();
1133 18 Jun 09 martin 369       if (cachedImageOut != null) cachedImageOut.close();
1133 18 Jun 09 martin 370     }
1133 18 Jun 09 martin 371   }
1133 18 Jun 09 martin 372   
1133 18 Jun 09 martin 373   /**
1133 18 Jun 09 martin 374      Forwards requests to {@link #doGet(HttpServletRequest, HttpServletResponse)}
1133 18 Jun 09 martin 375    */
1133 18 Jun 09 martin 376   @Override
1133 18 Jun 09 martin 377   public void doPost(HttpServletRequest request, HttpServletResponse response)
1133 18 Jun 09 martin 378     throws IOException, ServletException
1133 18 Jun 09 martin 379   {
1133 18 Jun 09 martin 380     doGet(request, response);
1133 18 Jun 09 martin 381   }
1133 18 Jun 09 martin 382     
1133 18 Jun 09 martin 383   
1133 18 Jun 09 martin 384   private String cutMiddle(String msg, double fraction)
1133 18 Jun 09 martin 385   {
1133 18 Jun 09 martin 386     int charactersToCut = (int)(msg.length() * (1 - fraction)) + 3;
1133 18 Jun 09 martin 387     int beginAt = (msg.length() - charactersToCut) / 2;
1133 18 Jun 09 martin 388     return msg.substring(0, beginAt) + "..." + msg.substring(beginAt + charactersToCut);
1133 18 Jun 09 martin 389   }
1178 20 Oct 09 jari 390 }