blob: a560711cdc30978e556d337aab6ba98789bb2a13 [file] [log] [blame]
// 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 {
@Override
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') : [] }-*/;
}
}