// Copyright (C) 2013 The Android Open Source Project // // 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.gerrit.client.api; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.JavaScriptException; import com.google.gwt.core.client.JsArrayString; /** * Determines the name a plugin has been installed under. * * This implementation guesses the name a plugin runs under by looking at the * JavaScript call stack and identifying the URL of the script file calling * {@code Gerrit.install()}. The simple approach applied here is looking at * the source URLs and extracting the name out of the string, e.g.: * {@code "http://localhost:8080/plugins/{name}/static/foo.js"}. */ class PluginName { private static final String UNKNOWN = "<unknown>"; private static String baseUrl() { return GWT.getHostPageBaseURL() + "plugins/"; } static String getCallerUrl() { return GWT.<PluginName> create(PluginName.class).findCallerUrl(); } static String fromUrl(String url) { String baseUrl = baseUrl(); if (url != null && url.startsWith(baseUrl)) { int s = url.indexOf('/', baseUrl.length()); if (s > 0) { return url.substring(baseUrl.length(), s); } } return UNKNOWN; } String findCallerUrl() { JavaScriptException err = makeException(); if (hasStack(err)) { return PluginNameMoz.getUrl(err); } String baseUrl = baseUrl(); StackTraceElement[] trace = getTrace(err); for (int i = trace.length - 1; i >= 0; i--) { String u = trace[i].getFileName(); if (u != null && u.startsWith(baseUrl)) { return u; } } return UNKNOWN; } private static StackTraceElement[] getTrace(JavaScriptException err) { if (err.getStackTrace().length == 0) { err.fillInStackTrace(); } return err.getStackTrace(); } protected static final native JavaScriptException makeException() /*-{ try { null.a() } catch (e) { return e } }-*/; private static final native boolean hasStack(JavaScriptException e) /*-{ return !!e.stack }-*/; /** Extracts URL from the stack frame. */ static class PluginNameMoz extends PluginName { String findCallerUrl() { return getUrl(makeException()); } private static String getUrl(JavaScriptException e) { String baseUrl = baseUrl(); JsArrayString stack = getStack(e); for (int i = stack.length() - 1; i >= 0; i--) { String frame = stack.get(i); int at = frame.indexOf(baseUrl); if (at >= 0) { int end = frame.indexOf(':', at + baseUrl.length()); if (end < 0) { end = frame.length(); } return frame.substring(at, end); } } return UNKNOWN; } private static final native JsArrayString getStack(JavaScriptException e) /*-{ return e.stack ? e.stack.split('\n') : [] }-*/; } }