/******************************************************************************* * Copyright (c) 2014, 2015 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.orion.internal.server.servlets.about; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; import java.text.Collator; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.orion.internal.server.servlets.Activator; import org.eclipse.orion.internal.server.servlets.ServletResourceHandler; import org.osgi.framework.Bundle; import org.osgi.framework.Constants; /** * Handler for requests for information about the orion server. Some implementation details of this class were extracted * from {@link org.eclipse.help.internal.webapp.servlet.AboutServlet} * * @author Anthony Hunter */ public class AboutHandler extends ServletResourceHandler<String> { private static final String XHTML_1 = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n<title>"; //$NON-NLS-1$ private static final String XHTML_2 = "</title>\n <style type = \"text/css\"> td { padding-right : 10px; }</style></head>\n<body>\n"; //$NON-NLS-1$ private static final String XHTML_3 = "</body>\n</html>"; //$NON-NLS-1$ protected static final int NUMBER_OF_COLUMNS = 4; protected class PluginDetails { public String[] columns = new String[NUMBER_OF_COLUMNS]; public PluginDetails(String[] columns) { this.columns = columns; for (int i = 0; i < NUMBER_OF_COLUMNS; i++) { if (columns[i] == null) { columns[i] = ""; //$NON-NLS-1$ } } } } protected class PluginComparator implements Comparator<PluginDetails> { public PluginComparator(int column) { this.column = column; } private int column; @Override public int compare(PluginDetails pd1, PluginDetails pd2) { return Collator.getInstance().compare(pd1.columns[column], pd2.columns[column]); } } protected ServletResourceHandler<IStatus> statusHandler; public AboutHandler(ServletResourceHandler<IStatus> statusHandler) { this.statusHandler = statusHandler; } private boolean handleGetRequest(HttpServletRequest request, HttpServletResponse response, String path) throws ServletException { response.setContentType("text/html; charset=UTF-8"); //$NON-NLS-1$ StringBuffer buf = computeAboutInfo(request); String output = buf.toString(); try { response.getWriter().write(output); } catch (IOException e) { // should not occur throw new RuntimeException(e); } return true; } private StringBuffer computeAboutInfo(HttpServletRequest request) { StringBuffer buf = new StringBuffer(); buf.append(XHTML_1); String sortParam = request.getParameter("sortColumn"); //$NON-NLS-1$ int sortColumn = 3; if (sortParam != null) { try { sortColumn = Integer.parseInt(sortParam); } catch (NumberFormatException e) { } } buf.append("About"); buf.append(XHTML_2); String app = System.getProperty("eclipse.application", "org.eclipse.orion.application"); //$NON-NLS-1$ String build = getBuildId(); if (app != null || build != null) { buf.append("<table><tr><td><img src=\"../webapp/orion-96.png\"/></td><td>"); //$NON-NLS-1$ buf.append("<p>"); //$NON-NLS-1$ if (app != null) buf.append("Application: " + app + "<br/>");//$NON-NLS-1$ //$NON-NLS-2$ if (build != null) buf.append("Build Id: " + build + "<br/>");//$NON-NLS-1$ //$NON-NLS-2$ buf.append("</p></td></tr></table>"); //$NON-NLS-1$ } buf.append("<table>"); //$NON-NLS-1$ List<PluginDetails> plugins = new ArrayList<PluginDetails>(); Bundle[] bundles = Activator.getDefault().getContext().getBundles(); for (int k = 0; k < bundles.length; k++) { plugins.add(pluginDetails(bundles[k])); } Comparator<PluginDetails> pluginComparator = new PluginComparator(sortColumn); Collections.sort(plugins, pluginComparator); String[] headerColumns = new String[] { "Provider", //$NON-NLS-1$ "PluginName", //$NON-NLS-1$ "Version", //$NON-NLS-1$ "Identifier" //$NON-NLS-1$ }; PluginDetails header = new PluginDetails(headerColumns); buf.append(headerRowFor(header)); for (Iterator<PluginDetails> iter = plugins.iterator(); iter.hasNext();) { PluginDetails details = iter.next(); buf.append(tableRowFor(details)); } buf.append("</table>"); //$NON-NLS-1$ buf.append(XHTML_3); return buf; } private String headerRowFor(PluginDetails details) { String row = "<tr>\n"; //$NON-NLS-1$ for (int i = 0; i < NUMBER_OF_COLUMNS; i++) { row += ("<td><a href = \"about.html?sortColumn="); //$NON-NLS-1$ row += i; row += "\">"; //$NON-NLS-1$ row += details.columns[i]; row += "</a></td>\n"; //$NON-NLS-1$ } row += "</tr>"; //$NON-NLS-1$ return row; } private String tableRowFor(PluginDetails details) { String row = "<tr>\n"; //$NON-NLS-1$ for (int i = 0; i < NUMBER_OF_COLUMNS; i++) { row += ("<td>"); //$NON-NLS-1$ row += details.columns[i]; row += "</td>\n"; //$NON-NLS-1$ } row += "</tr>"; //$NON-NLS-1$ return row; } protected PluginDetails pluginDetails(Bundle bundle) { String[] values = new String[] { getResourceString(bundle, Constants.BUNDLE_VENDOR), getResourceString(bundle, Constants.BUNDLE_NAME), getResourceString(bundle, Constants.BUNDLE_VERSION), bundle.getSymbolicName() }; PluginDetails details = new PluginDetails(values); return details; } private static String getResourceString(Bundle bundle, String headerName) { String value = bundle.getHeaders().get(headerName); return value == null ? null : Platform.getResourceString(bundle, value); } @Override public boolean handleRequest(HttpServletRequest request, HttpServletResponse response, String path) throws ServletException { switch (getMethod(request)) { case GET: return handleGetRequest(request, response, path); case HEAD: return handleHeadRequest(request, response, path); default: return false; } } private boolean handleHeadRequest(HttpServletRequest request, HttpServletResponse response, String path) { // same as GET except don't send the response body response.setContentType("text/html; charset=UTF-8"); //$NON-NLS-1$ StringBuffer buf = computeAboutInfo(request); response.setContentLength(buf.length()); return true; } /** * Get the build id for the orion application by using the about.properties from the org.eclipse.orion.server.core * plugin. The maven build assigns a property with the build timestamp when the build runs. * * @return the build id. */ private String getBuildId() { String version = System.getProperty("eclipse.buildId", "unknown"); //$NON-NLS-1$ try { URL url = new URL("platform:/plugin/org.eclipse.orion.server.core/about.properties"); InputStream inputStream = url.openConnection().getInputStream(); BufferedReader in = new BufferedReader(new InputStreamReader(inputStream)); String inputLine; while ((inputLine = in.readLine()) != null) { if (inputLine.startsWith("Build id:")) { break; } } in.close(); // The Build Id line is in the format: "Build id: 8.0.0-v20150223-1056\n\" if (inputLine.length() > 30) { version = inputLine.substring(inputLine.indexOf(':') + 1, inputLine.length() - 3); } } catch (IOException e) { // just ignore and use the calculated version from the property } return version; } }