// Copyright (C) 2008 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; import static com.google.gerrit.common.PageLinks.ADMIN_GROUPS; import static com.google.gerrit.common.PageLinks.ADMIN_PROJECTS; import static com.google.gerrit.common.PageLinks.MINE; import static com.google.gerrit.common.PageLinks.REGISTER; import static com.google.gerrit.common.PageLinks.SETTINGS; import static com.google.gerrit.common.PageLinks.SETTINGS_AGREEMENTS; import static com.google.gerrit.common.PageLinks.SETTINGS_CONTACT; import static com.google.gerrit.common.PageLinks.SETTINGS_HTTP_PASSWORD; import static com.google.gerrit.common.PageLinks.SETTINGS_MYGROUPS; import static com.google.gerrit.common.PageLinks.SETTINGS_NEW_AGREEMENT; import static com.google.gerrit.common.PageLinks.SETTINGS_PREFERENCES; import static com.google.gerrit.common.PageLinks.SETTINGS_PROJECTS; import static com.google.gerrit.common.PageLinks.SETTINGS_SSHKEYS; import static com.google.gerrit.common.PageLinks.SETTINGS_WEBIDENT; import static com.google.gerrit.common.PageLinks.op; import com.google.gerrit.client.account.MyAgreementsScreen; import com.google.gerrit.client.account.MyContactInformationScreen; import com.google.gerrit.client.account.MyGroupsScreen; import com.google.gerrit.client.account.MyIdentitiesScreen; import com.google.gerrit.client.account.MyPasswordScreen; import com.google.gerrit.client.account.MyPreferencesScreen; import com.google.gerrit.client.account.MyProfileScreen; import com.google.gerrit.client.account.MySshKeysScreen; import com.google.gerrit.client.account.MyWatchedProjectsScreen; import com.google.gerrit.client.account.NewAgreementScreen; import com.google.gerrit.client.account.RegisterScreen; import com.google.gerrit.client.account.ValidateEmailScreen; import com.google.gerrit.client.admin.AccountGroupScreen; import com.google.gerrit.client.admin.GroupListScreen; import com.google.gerrit.client.admin.ProjectAccessScreen; import com.google.gerrit.client.admin.ProjectBranchesScreen; import com.google.gerrit.client.admin.ProjectInfoScreen; import com.google.gerrit.client.admin.ProjectListScreen; import com.google.gerrit.client.admin.ProjectScreen; import com.google.gerrit.client.auth.openid.OpenIdSignInDialog; import com.google.gerrit.client.auth.userpass.UserPassSignInDialog; import com.google.gerrit.client.changes.AccountDashboardScreen; import com.google.gerrit.client.changes.ChangeScreen; import com.google.gerrit.client.changes.PatchTable; import com.google.gerrit.client.changes.PublishCommentScreen; import com.google.gerrit.client.changes.QueryScreen; import com.google.gerrit.client.patches.PatchScreen; import com.google.gerrit.client.ui.Screen; import com.google.gerrit.common.auth.SignInMode; import com.google.gerrit.common.data.PatchSetDetail; import com.google.gerrit.reviewdb.Account; import com.google.gerrit.reviewdb.AccountGroup; import com.google.gerrit.reviewdb.Change; import com.google.gerrit.reviewdb.Patch; import com.google.gerrit.reviewdb.PatchSet; import com.google.gerrit.reviewdb.Project; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.RunAsyncCallback; import com.google.gwtorm.client.KeyUtil; public class Dispatcher { public static String toPatchSideBySide(final Patch.Key id) { return toPatch("sidebyside", id); } public static String toPatchUnified(final Patch.Key id) { return toPatch("unified", id); } public static String toPatch(final String type, final Patch.Key id) { return "patch," + type + "," + id.toString(); } public static String toAccountGroup(final AccountGroup.Id id) { return "admin,group," + id.toString(); } public static String toProjectAdmin(final Project.NameKey n, final String tab) { return "admin,project," + n.toString() + "," + tab; } static final String RELOAD_UI = "reload-ui,"; private static boolean wasStartedByReloadUI; void display(String token) { assert token != null; try { try { if (token.startsWith(RELOAD_UI)) { wasStartedByReloadUI = true; token = skip(RELOAD_UI, token); } select(token); } finally { wasStartedByReloadUI = false; } } catch (RuntimeException err) { GWT.log("Error parsing history token: " + token, err); Gerrit.display(token, new NotFoundScreen()); } } private static void select(final String token) { if (token.startsWith("patch,")) { patch(token, null, 0, null, null); } else if (token.startsWith("change,publish,")) { publish(token); } else if (MINE.equals(token) || token.startsWith("mine,")) { Gerrit.display(token, mine(token)); } else if (token.startsWith("all,")) { Gerrit.display(token, all(token)); } else if (token.startsWith("project,")) { Gerrit.display(token, project(token)); } else if (SETTINGS.equals(token) // || REGISTER.equals(token) // || token.startsWith("settings,") // || token.startsWith("register,") // || token.startsWith("VE,") // || token.startsWith("SignInFailure,")) { settings(token); } else if (token.startsWith("admin,")) { admin(token); } else { Gerrit.display(token, core(token)); } } private static Screen mine(final String token) { if (MINE.equals(token)) { if (Gerrit.isSignedIn()) { return new AccountDashboardScreen(Gerrit.getUserAccount().getId()); } else { final Screen r = new AccountDashboardScreen(null); r.setRequiresSignIn(true); return r; } } else if ("mine,starred".equals(token)) { return QueryScreen.forQuery("is:starred"); } else if ("mine,drafts".equals(token)) { return QueryScreen.forQuery("has:draft"); } else { String p = "mine,watched,"; if (token.startsWith(p)) { return QueryScreen.forQuery("is:watched status:open", skip(p, token)); } return new NotFoundScreen(); } } private static Screen all(final String token) { String p; p = "all,abandoned,"; if (token.startsWith(p)) { return QueryScreen.forQuery("status:abandoned", skip(p, token)); } p = "all,merged,"; if (token.startsWith(p)) { return QueryScreen.forQuery("status:merged", skip(p, token)); } p = "all,open,"; if (token.startsWith(p)) { return QueryScreen.forQuery("status:open", skip(p, token)); } return new NotFoundScreen(); } private static Screen project(final String token) { String p; p = "project,open,"; if (token.startsWith(p)) { final String s = skip(p, token); final int c = s.indexOf(','); Project.NameKey proj = Project.NameKey.parse(s.substring(0, c)); return QueryScreen.forQuery( // "status:open " + op("project", proj.get()), // s.substring(c + 1)); } p = "project,merged,"; if (token.startsWith(p)) { final String s = skip(p, token); final int c = s.indexOf(','); Project.NameKey proj = Project.NameKey.parse(s.substring(0, c)); return QueryScreen.forQuery( // "status:merged " + op("project", proj.get()), // s.substring(c + 1)); } p = "project,abandoned,"; if (token.startsWith(p)) { final String s = skip(p, token); final int c = s.indexOf(','); Project.NameKey proj = Project.NameKey.parse(s.substring(0, c)); return QueryScreen.forQuery( // "status:abandoned " + op("project", proj.get()), // s.substring(c + 1)); } return new NotFoundScreen(); } private static Screen core(final String token) { String p; p = "change,"; if (token.startsWith(p)) return new ChangeScreen(Change.Id.parse(skip(p, token))); p = "dashboard,"; if (token.startsWith(p)) return new AccountDashboardScreen(Account.Id.parse(skip(p, token))); p = "q,"; if (token.startsWith(p)) { final String s = skip(p, token); final int c = s.indexOf(','); return new QueryScreen(s.substring(0, c), s.substring(c + 1)); } return new NotFoundScreen(); } private static void publish(String token) { new AsyncSplit(token) { public void onSuccess() { Gerrit.display(token, select()); } private Screen select() { String p = "change,publish,"; if (token.startsWith(p)) return new PublishCommentScreen(PatchSet.Id.parse(skip(p, token))); return new NotFoundScreen(); } }.onSuccess(); } public static void patch(String token, final Patch.Key id, final int patchIndex, final PatchSetDetail patchSetDetail, final PatchTable patchTable) { GWT.runAsync(new AsyncSplit(token) { public void onSuccess() { Gerrit.display(token, select()); } private Screen select() { String p; p = "patch,sidebyside,"; if (token.startsWith(p)) { return new PatchScreen.SideBySide( // id != null ? id : Patch.Key.parse(skip(p, token)), // patchIndex, // patchSetDetail, // patchTable // ); } p = "patch,unified,"; if (token.startsWith(p)) { return new PatchScreen.Unified( // id != null ? id : Patch.Key.parse(skip(p, token)), // patchIndex, // patchSetDetail, // patchTable // ); } return new NotFoundScreen(); } }); } private static void settings(String token) { GWT.runAsync(new AsyncSplit(token) { public void onSuccess() { Gerrit.display(token, select()); } private Screen select() { String p; if (token.equals(SETTINGS)) { return new MyProfileScreen(); } if (token.equals(SETTINGS_PREFERENCES)) { return new MyPreferencesScreen(); } if (token.equals(SETTINGS_PROJECTS)) { return new MyWatchedProjectsScreen(); } if (token.equals(SETTINGS_CONTACT)) { return new MyContactInformationScreen(); } if (token.equals(SETTINGS_SSHKEYS)) { return new MySshKeysScreen(); } if (token.equals(SETTINGS_WEBIDENT)) { return new MyIdentitiesScreen(); } if (token.equals(SETTINGS_HTTP_PASSWORD)) { return new MyPasswordScreen(); } if (token.equals(SETTINGS_MYGROUPS)) { return new MyGroupsScreen(); } if (token.equals(SETTINGS_AGREEMENTS) && Gerrit.getConfig().isUseContributorAgreements()) { return new MyAgreementsScreen(); } p = "register,"; if (token.startsWith(p)) { return new RegisterScreen(skip(p, token)); } else if (REGISTER.equals(token)) { return new RegisterScreen(MINE); } p = "VE,"; if (token.startsWith(p)) return new ValidateEmailScreen(skip(p, token)); p = "SignInFailure,"; if (token.startsWith(p)) { final String[] args = skip(p, token).split(","); final SignInMode mode = SignInMode.valueOf(args[0]); final String msg = KeyUtil.decode(args[1]); final String to = MINE; switch (Gerrit.getConfig().getAuthType()) { case OPENID: new OpenIdSignInDialog(mode, to, msg).center(); break; case LDAP: case LDAP_BIND: new UserPassSignInDialog(to, msg).center(); break; default: return null; } switch (mode) { case SIGN_IN: return QueryScreen.forQuery("status:open"); case LINK_IDENTIY: return new MyIdentitiesScreen(); } } if (SETTINGS_NEW_AGREEMENT.equals(token)) return new NewAgreementScreen(); p = SETTINGS_NEW_AGREEMENT + ","; if (token.startsWith(p)) { return new NewAgreementScreen(skip(p, token)); } return new NotFoundScreen(); } }); } private static void admin(String token) { GWT.runAsync(new AsyncSplit(token) { public void onSuccess() { Gerrit.display(token, select()); } private Screen select() { String p; p = "admin,group,"; if (token.startsWith(p)) return new AccountGroupScreen(AccountGroup.Id.parse(skip(p, token))); p = "admin,project,"; if (token.startsWith(p)) { p = skip(p, token); final int c = p.indexOf(','); final Project.NameKey k = Project.NameKey.parse(p.substring(0, c)); final boolean isWild = k.equals(Gerrit.getConfig().getWildProject()); p = p.substring(c + 1); if (ProjectScreen.INFO.equals(p)) { return new ProjectInfoScreen(k); } if (!isWild && ProjectScreen.BRANCH.equals(p)) { return new ProjectBranchesScreen(k); } if (ProjectScreen.ACCESS.equals(p)) { return new ProjectAccessScreen(k); } return new NotFoundScreen(); } if (ADMIN_GROUPS.equals(token)) { return new GroupListScreen(); } if (ADMIN_PROJECTS.equals(token)) { return new ProjectListScreen(); } return new NotFoundScreen(); } }); } private static String skip(final String prefix, final String in) { return in.substring(prefix.length()); } private static abstract class AsyncSplit implements RunAsyncCallback { private final boolean isReloadUi; protected final String token; protected AsyncSplit(String token) { this.isReloadUi = wasStartedByReloadUI; this.token = token; } public final void onFailure(Throwable reason) { if (!isReloadUi && "HTTP download failed with status 404".equals(reason.getMessage())) { // The server was upgraded since we last download the main script, // so the pointers to the splits aren't valid anymore. Force the // page to reload itself and pick up the new code. // Gerrit.upgradeUI(token); } else { new ErrorDialog(reason).center(); } } } }