Java tutorial
/* * Copyright (C) 2017 Google Inc. * * 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.gapid.models; import static java.util.Arrays.stream; import com.google.common.collect.Lists; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.gapid.proto.service.Service; import com.google.gapid.proto.service.path.Path; import com.google.gapid.server.Client; import com.google.gapid.util.Events; import org.eclipse.swt.widgets.Shell; import java.util.List; import java.util.Objects; import java.util.logging.Logger; /** * Model containing the different API contexts of a capture. */ public class ApiContext extends CaptureDependentModel<ApiContext.FilteringContext[], ApiContext.Listener> { private static final Logger LOG = Logger.getLogger(ApiContext.class.getName()); private FilteringContext selectedContext = FilteringContext.ALL; public ApiContext(Shell shell, Client client, Capture capture) { super(LOG, shell, client, Listener.class, capture); } @Override protected void reset(boolean maintainState) { super.reset(maintainState); if (!maintainState) { selectedContext = FilteringContext.ALL; } } @Override protected Path.Any getPath(Path.Capture capturePath) { return Path.Any.newBuilder().setContexts(Path.Contexts.newBuilder().setCapture(capturePath)).build(); } @Override protected ListenableFuture<FilteringContext[]> doLoad(Path.Any path) { return Futures.transform(Futures.transformAsync(client.get(path), val -> { List<ListenableFuture<ApiContext.IdAndContext>> contexts = Lists.newArrayList(); for (Path.Context ctx : val.getContexts().getListList()) { contexts.add(Futures.transform(client.get(Path.Any.newBuilder().setContext(ctx).build()), value -> new IdAndContext(ctx, value.getContext()))); } return Futures.allAsList(contexts); }), this::unbox); } private FilteringContext[] unbox(List<IdAndContext> contexts) { if (contexts.isEmpty()) { return new FilteringContext[0]; } else if (contexts.size() == 1) { return new FilteringContext[] { FilteringContext.withoutFilter(contexts.get(0)) }; } else { FilteringContext[] result = new FilteringContext[contexts.size() + 1]; result[0] = FilteringContext.ALL; for (int i = 0; i < contexts.size(); i++) { result[i + 1] = new FilteringContext(contexts.get(i)); } return result; } } @Override protected void fireLoadStartEvent() { // Do nothing. } @Override protected void fireLoadedEvent() { if (count() == 1) { selectedContext = getData()[0]; } else if (selectedContext != FilteringContext.ALL) { selectedContext = stream(getData()).filter(c -> c.equals(selectedContext)).findFirst() .orElse(FilteringContext.ALL); } listeners.fire().onContextsLoaded(); } public int count() { return isLoaded() ? getData().length : 0; } public FilteringContext getSelectedContext() { return selectedContext; } public void selectContext(FilteringContext context) { if (!Objects.equals(context, selectedContext)) { selectedContext = context; listeners.fire().onContextSelected(context); } } /* public void selectContextContaining(CommandRange atoms) { if (isLoaded() && !selectedContext.contains(last(atoms))) { for (FilteringContext context : getData()) { if (context != FilteringContext.ALL && context.contains(last(atoms))) { selectContext(context); return; } } // Fallback to selecting the ALL context. selectContext(FilteringContext.ALL); } } */ /** * A {@link com.google.gapid.proto.service.Service.Context} wrapper to allow filtering of the * command tree. */ public static class FilteringContext { public static final FilteringContext ALL = new FilteringContext(null, null) { @Override public Path.CommandTree.Builder commandTree(Path.CommandTree.Builder path) { return path.setGroupByContext(true).setIncludeNoContextGroups(true); } @Override public Path.Events.Builder events(Path.Events.Builder path) { return path; } @Override public Path.Report.Builder report(Path.Report.Builder path) { return path; } @Override public String toString() { return "All contexts"; } @Override public boolean equals(Object obj) { return obj == ALL; } @Override public int hashCode() { return 0; } }; private final Path.ID id; private final Service.Context context; public FilteringContext(IdAndContext context) { this(context.id, context.context); } protected FilteringContext(Path.ID id, Service.Context context) { this.id = id; this.context = context; } public static FilteringContext withoutFilter(IdAndContext context) { return new FilteringContext(context.id, context.context) { @Override public Path.CommandTree.Builder commandTree(Path.CommandTree.Builder path) { return path.setGroupByFrame(true).setGroupByDrawCall(true).setGroupByUserMarkers(true) .setAllowIncompleteFrame(true); } @Override public Path.Events.Builder events(Path.Events.Builder path) { return path; } @Override public Path.Report.Builder report(Path.Report.Builder path) { return path; } }; } public Path.CommandTree.Builder commandTree(Path.CommandTree.Builder path) { path.getFilterBuilder().setContext(id); return path.setGroupByFrame(true).setGroupByDrawCall(true).setGroupByUserMarkers(true) .setAllowIncompleteFrame(true); } public Path.Events.Builder events(Path.Events.Builder path) { path.getFilterBuilder().setContext(id); return path; } public Path.Report.Builder report(Path.Report.Builder path) { path.getFilterBuilder().setContext(id); return path; } @Override public String toString() { return context.getName(); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } else if (obj == ALL || !(obj instanceof FilteringContext)) { return false; } return Objects.equals(id, ((FilteringContext) obj).id); } @Override public int hashCode() { return id.hashCode(); } } @SuppressWarnings("unused") public static interface Listener extends Events.Listener { /** * Event indicating that the contexts have finished loading from the server. */ public default void onContextsLoaded() { /* empty */ } /** * Event indicating that the currently selected context has changed. */ public default void onContextSelected(FilteringContext context) { /* empty */ } } protected static class IdAndContext { public final Path.ID id; public final Service.Context context; public IdAndContext(Path.Context path, Service.Context context) { this.id = path.getId(); this.context = context; } } }