/* * Copyright 2004-2010 Information & Software Engineering Group (188/1) * Institute of Software Technology and Interactive Systems * Vienna University of Technology, Austria * * 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.ifs.tuwien.ac.at/dm/somtoolbox/license.html * * 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 at.tuwien.ifs.somtoolbox.apps.viewer.controls.psomserver.httphandler; import java.awt.image.BufferedImage; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.util.List; import java.util.logging.Logger; import javax.imageio.ImageIO; import com.sun.net.httpserver.Headers; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import at.tuwien.ifs.somtoolbox.SOMToolboxException; import at.tuwien.ifs.somtoolbox.apps.viewer.CommonSOMViewerStateData; import at.tuwien.ifs.somtoolbox.apps.viewer.fileutils.ExportUtils; import at.tuwien.ifs.somtoolbox.apps.viewer.fileutils.PocketSOMFormatUtils; /** * The ConfigurationProvider provides sends all PocketSOM-Files via http: (psom, jpeg and list) * * @author Jakob Frank */ public class PocketSOMConfigProvider implements HttpHandler { protected static final String PSOM = ".psom"; protected static final String IMG = "image.png"; // protected static final String IMG = "visualisation"; protected static final String MAPPING = "mapping.list"; private static final String NL = "\n"; private static final boolean DEBUG = false; private static final String LOG_SEP = " - "; private final Logger log; private final int connectorEndpointPort; private final String musicContext; private final CommonSOMViewerStateData state; public PocketSOMConfigProvider(CommonSOMViewerStateData state, int port, String mapContentContext) { log = Logger.getLogger(this.getClass().getName()); this.state = state; this.musicContext = mapContentContext; connectorEndpointPort = port; } @Override public void handle(HttpExchange t) throws IOException { if (DEBUG) { printRequest(t); } String method = t.getRequestMethod(); if (method.equalsIgnoreCase("GET") || method.equalsIgnoreCase("HEAD")) { String f = t.getRequestURI().getPath(); if (f.endsWith(PSOM)) { sendPsomFile(t); } else if (f.endsWith(IMG)) { sendVisualisation(t); } else if (f.endsWith(MAPPING)) { sendMapping(t); } else { HttpErrorHandler.sendError(t, 404); } } else { HttpErrorHandler.sendError(t, 501); } } private void sendMapping(HttpExchange t) throws IOException { log.info("Delivering mapping"); StringBuilder response = new StringBuilder(); if (state != null && state.growingLayer != null) { response = PocketSOMFormatUtils.createPocketSomMapping(state.growingLayer); } else { response.append(2).append(NL); response.append(2).append(NL); response.append(1).append(NL); response.append(0 + " " + 0 + " null/null").append(NL); response.append(0 + " " + 1 + " null/eins").append(NL); response.append(1 + " " + 0 + " eins/null").append(NL); response.append(1 + " " + 1 + " eins/eins").append(NL); } // Send it back // FIXME: How should we handle non-ASCII chars? String answer = response.toString(); t.sendResponseHeaders(200, answer.length()); if (t.getRequestMethod().equalsIgnoreCase("GET")) { OutputStream os = t.getResponseBody(); // PrintStream ps = new PrintStream(os, false, "utf-8"); // ps.print(answer); os.write(answer.getBytes("utf-8")); // ps.close(); // ps.flush(); os.close(); } t.close(); log.info("Mapping delivered"); } private void sendVisualisation(HttpExchange t) throws IOException { log.info("Delivering Visualisation"); try { int unitW = 50; String format = "png"; if (getClient(t).matches(".*[iI][sS][oO][mM].*")) { unitW = 50; } // Check for size-request String query = t.getRequestURI().getQuery(); if (query != null) { String args[] = query.split("&"); for (String arg : args) { try { String kv[] = arg.split("=", 2); if (kv[0].equalsIgnoreCase("unitSize")) { unitW = Integer.parseInt(kv[1]); } else if (kv[0].equalsIgnoreCase("imageSize")) { if (state == null || state.growingLayer == null) { continue; } int pixels = Integer.parseInt(kv[1]); int units = Math.max(state.growingLayer.getXSize(), state.growingLayer.getYSize()); unitW = pixels / units; } else if (kv[0].equalsIgnoreCase("format")) { if (kv[1].equalsIgnoreCase("jpeg") || kv[1].equalsIgnoreCase("png")) { format = kv[1]; } } } catch (Exception e) { log.warning("Received invalid image-size argument: \"" + arg + "\""); } } } BufferedImage bi = ExportUtils.getVisualization(state, unitW); ByteArrayOutputStream bos = new ByteArrayOutputStream(); ImageIO.write(bi, format, bos); log.info(200 + LOG_SEP + t.getRequestURI().toString()); t.getResponseHeaders().add("Content-Type", "image/" + format); t.getResponseHeaders().add("Accept-Ranges", "bytes"); t.sendResponseHeaders(200, bos.size()); if (t.getRequestMethod().equalsIgnoreCase("GET")) { OutputStream os = t.getResponseBody(); os.write(bos.toByteArray()); os.close(); } t.close(); } catch (SOMToolboxException e) { e.printStackTrace(); log.warning("Delivering Visualisation failed!"); HttpErrorHandler.sendError(t, 500); } catch (IOException e) { e.printStackTrace(); log.warning("Delivering Visualisation failed!"); throw e; } } private String getClient(HttpExchange t) { String c = ""; List<String> cl = t.getRequestHeaders().get("User-agent"); for (String string : cl) { c += string + ", "; } return c; } private void sendPsomFile(HttpExchange t) throws IOException { log.info("Delivering PSOM-file"); final String host = t.getRequestHeaders().getFirst("Host"); String path = t.getRequestURI().getPath(); path = path.substring(0, path.lastIndexOf('/') + 1); StringBuilder response = new StringBuilder(); response.append("# PocketSOM 0.8 Collection file").append(NL); response.append(NL); if (host == null) { response.append("# All Paths not starting with \"http\" are server-urls").append(NL); response.append("relative=1").append(NL); } response.append(NL); response.append("# Collection URL").append(NL); response.append("collectionURL="); if (host != null) { response.append("http://").append(host); } response.append(musicContext).append('/').append(NL); response.append(NL); response.append("# image of the map (landscape) for visualization").append(NL); response.append("mapimage="); if (host != null) { response.append("http://").append(host); } response.append(path).append(IMG).append(NL); response.append(NL); response.append("# PockeSOM map data (data with locations on the map)").append(NL); response.append("mapdata="); if (host != null) { response.append("http://").append(host); } response.append(path).append(MAPPING).append(NL); response.append(NL); response.append("# Advanced configuration").append(NL); response.append("playSOM_Address="); int posOfClon = host.lastIndexOf(':'); String address = host; if (posOfClon > 0) { address = host.substring(0, posOfClon); } response.append(address).append(':').append(connectorEndpointPort).append(NL); response.append(NL); response.append(NL); // Send it. String answer = response.toString(); log.info(200 + LOG_SEP + t.getRequestURI().toString()); t.sendResponseHeaders(200, answer.length()); if (t.getRequestMethod().equalsIgnoreCase("GET")) { OutputStream os = t.getResponseBody(); os.write(answer.getBytes()); os.close(); } t.close(); } private void printRequest(HttpExchange t) throws IOException { System.out.println("Method: " + t.getRequestMethod()); System.out.println("URI: " + t.getRequestURI()); System.out.println("Scheme: " + t.getRequestURI().getScheme()); System.out.println("URI-Port: " + t.getRequestURI().getPort()); System.out.println("Local: " + t.getLocalAddress().getHostName()); System.out.println("LocalP: " + t.getLocalAddress().getPort()); System.out.println("Headers:"); Headers h = t.getRequestHeaders(); for (Object name : h.keySet()) { String key = (String) name; System.out.println(" " + key + ": " + h.getFirst(key)); } System.out.println("Body:"); InputStream is = t.getRequestBody(); BufferedReader sr = new BufferedReader(new InputStreamReader(is)); String line = ""; while ((line = sr.readLine()) != null) { System.out.println(" " + line); } } }