diff options
Diffstat (limited to 'gerrit-server/src/main/java/com/google/gerrit/server/query/change/OutputStreamQuery.java')
-rw-r--r-- | gerrit-server/src/main/java/com/google/gerrit/server/query/change/OutputStreamQuery.java | 463 |
1 files changed, 0 insertions, 463 deletions
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OutputStreamQuery.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OutputStreamQuery.java deleted file mode 100644 index eef79b2edd..0000000000 --- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OutputStreamQuery.java +++ /dev/null @@ -1,463 +0,0 @@ -// Copyright (C) 2014 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.server.query.change; - -import static com.google.common.base.Preconditions.checkState; -import static java.nio.charset.StandardCharsets.UTF_8; - -import com.google.gerrit.common.TimeUtil; -import com.google.gerrit.common.data.LabelTypes; -import com.google.gerrit.index.query.QueryParseException; -import com.google.gerrit.index.query.QueryResult; -import com.google.gerrit.reviewdb.client.PatchSet; -import com.google.gerrit.reviewdb.client.Project; -import com.google.gerrit.reviewdb.server.ReviewDb; -import com.google.gerrit.server.CurrentUser; -import com.google.gerrit.server.config.TrackingFooters; -import com.google.gerrit.server.data.ChangeAttribute; -import com.google.gerrit.server.data.PatchSetAttribute; -import com.google.gerrit.server.data.QueryStatsAttribute; -import com.google.gerrit.server.events.EventFactory; -import com.google.gerrit.server.git.GitRepositoryManager; -import com.google.gerrit.server.project.SubmitRuleEvaluator; -import com.google.gson.Gson; -import com.google.gwtorm.server.OrmException; -import com.google.inject.Inject; -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import org.eclipse.jgit.lib.Repository; -import org.eclipse.jgit.revwalk.RevWalk; -import org.eclipse.jgit.util.io.DisabledOutputStream; -import org.joda.time.format.DateTimeFormat; -import org.joda.time.format.DateTimeFormatter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Change query implementation that outputs to a stream in the style of an SSH command. - * - * <p>Instances are one-time-use. Other singleton classes should inject a Provider rather than - * holding on to a single instance. - */ -public class OutputStreamQuery { - private static final Logger log = LoggerFactory.getLogger(OutputStreamQuery.class); - - private static final DateTimeFormatter dtf = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss zzz"); - - public enum OutputFormat { - TEXT, - JSON - } - - private final ReviewDb db; - private final GitRepositoryManager repoManager; - private final ChangeQueryBuilder queryBuilder; - private final ChangeQueryProcessor queryProcessor; - private final EventFactory eventFactory; - private final TrackingFooters trackingFooters; - private final CurrentUser user; - private final SubmitRuleEvaluator.Factory submitRuleEvaluatorFactory; - - private OutputFormat outputFormat = OutputFormat.TEXT; - private boolean includePatchSets; - private boolean includeCurrentPatchSet; - private boolean includeApprovals; - private boolean includeComments; - private boolean includeFiles; - private boolean includeCommitMessage; - private boolean includeDependencies; - private boolean includeSubmitRecords; - private boolean includeAllReviewers; - - private OutputStream outputStream = DisabledOutputStream.INSTANCE; - private PrintWriter out; - - @Inject - OutputStreamQuery( - ReviewDb db, - GitRepositoryManager repoManager, - ChangeQueryBuilder queryBuilder, - ChangeQueryProcessor queryProcessor, - EventFactory eventFactory, - TrackingFooters trackingFooters, - CurrentUser user, - SubmitRuleEvaluator.Factory submitRuleEvaluatorFactory) { - this.db = db; - this.repoManager = repoManager; - this.queryBuilder = queryBuilder; - this.queryProcessor = queryProcessor; - this.eventFactory = eventFactory; - this.trackingFooters = trackingFooters; - this.user = user; - this.submitRuleEvaluatorFactory = submitRuleEvaluatorFactory; - } - - void setLimit(int n) { - queryProcessor.setUserProvidedLimit(n); - } - - public void setStart(int n) { - queryProcessor.setStart(n); - } - - public void setIncludePatchSets(boolean on) { - includePatchSets = on; - } - - public boolean getIncludePatchSets() { - return includePatchSets; - } - - public void setIncludeCurrentPatchSet(boolean on) { - includeCurrentPatchSet = on; - } - - public boolean getIncludeCurrentPatchSet() { - return includeCurrentPatchSet; - } - - public void setIncludeApprovals(boolean on) { - includeApprovals = on; - } - - public void setIncludeComments(boolean on) { - includeComments = on; - } - - public void setIncludeFiles(boolean on) { - includeFiles = on; - } - - public boolean getIncludeFiles() { - return includeFiles; - } - - public void setIncludeDependencies(boolean on) { - includeDependencies = on; - } - - public boolean getIncludeDependencies() { - return includeDependencies; - } - - public void setIncludeCommitMessage(boolean on) { - includeCommitMessage = on; - } - - public void setIncludeSubmitRecords(boolean on) { - includeSubmitRecords = on; - } - - public void setIncludeAllReviewers(boolean on) { - includeAllReviewers = on; - } - - public void setOutput(OutputStream out, OutputFormat fmt) { - this.outputStream = out; - this.outputFormat = fmt; - } - - public void query(String queryString) throws IOException { - out = - new PrintWriter( // - new BufferedWriter( // - new OutputStreamWriter(outputStream, UTF_8))); - try { - if (queryProcessor.isDisabled()) { - ErrorMessage m = new ErrorMessage(); - m.message = "query disabled"; - show(m); - return; - } - - try { - final QueryStatsAttribute stats = new QueryStatsAttribute(); - stats.runTimeMilliseconds = TimeUtil.nowMs(); - - Map<Project.NameKey, Repository> repos = new HashMap<>(); - Map<Project.NameKey, RevWalk> revWalks = new HashMap<>(); - QueryResult<ChangeData> results = queryProcessor.query(queryBuilder.parse(queryString)); - try { - for (ChangeData d : results.entities()) { - show(buildChangeAttribute(d, repos, revWalks)); - } - } finally { - closeAll(revWalks.values(), repos.values()); - } - - stats.rowCount = results.entities().size(); - stats.moreChanges = results.more(); - stats.runTimeMilliseconds = TimeUtil.nowMs() - stats.runTimeMilliseconds; - show(stats); - } catch (OrmException err) { - log.error("Cannot execute query: " + queryString, err); - - ErrorMessage m = new ErrorMessage(); - m.message = "cannot query database"; - show(m); - - } catch (QueryParseException e) { - ErrorMessage m = new ErrorMessage(); - m.message = e.getMessage(); - show(m); - } - } finally { - try { - out.flush(); - } finally { - out = null; - } - } - } - - private ChangeAttribute buildChangeAttribute( - ChangeData d, Map<Project.NameKey, Repository> repos, Map<Project.NameKey, RevWalk> revWalks) - throws OrmException, IOException { - LabelTypes labelTypes = d.getLabelTypes(); - ChangeAttribute c = eventFactory.asChangeAttribute(db, d.change()); - eventFactory.extend(c, d.change()); - - if (!trackingFooters.isEmpty()) { - eventFactory.addTrackingIds(c, d.trackingFooters()); - } - - if (includeAllReviewers) { - eventFactory.addAllReviewers(db, c, d.notes()); - } - - if (includeSubmitRecords) { - eventFactory.addSubmitRecords( - c, submitRuleEvaluatorFactory.create(user, d).setAllowClosed(true).evaluate()); - } - - if (includeCommitMessage) { - eventFactory.addCommitMessage(c, d.commitMessage()); - } - - RevWalk rw = null; - if (includePatchSets || includeCurrentPatchSet || includeDependencies) { - Project.NameKey p = d.change().getProject(); - rw = revWalks.get(p); - // Cache and reuse repos and revwalks. - if (rw == null) { - Repository repo = repoManager.openRepository(p); - checkState(repos.put(p, repo) == null); - rw = new RevWalk(repo); - revWalks.put(p, rw); - } - } - - if (includePatchSets) { - eventFactory.addPatchSets( - db, - rw, - c, - d.patchSets(), - includeApprovals ? d.approvals().asMap() : null, - includeFiles, - d.change(), - labelTypes); - } - - if (includeCurrentPatchSet) { - PatchSet current = d.currentPatchSet(); - if (current != null) { - c.currentPatchSet = eventFactory.asPatchSetAttribute(db, rw, d.change(), current); - eventFactory.addApprovals(c.currentPatchSet, d.currentApprovals(), labelTypes); - - if (includeFiles) { - eventFactory.addPatchSetFileNames(c.currentPatchSet, d.change(), d.currentPatchSet()); - } - if (includeComments) { - eventFactory.addPatchSetComments(c.currentPatchSet, d.publishedComments()); - } - } - } - - if (includeComments) { - eventFactory.addComments(c, d.messages()); - if (includePatchSets) { - eventFactory.addPatchSets( - db, - rw, - c, - d.patchSets(), - includeApprovals ? d.approvals().asMap() : null, - includeFiles, - d.change(), - labelTypes); - for (PatchSetAttribute attribute : c.patchSets) { - eventFactory.addPatchSetComments(attribute, d.publishedComments()); - } - } - } - - if (includeDependencies) { - eventFactory.addDependencies(rw, c, d.change(), d.currentPatchSet()); - } - - c.plugins = queryProcessor.create(d); - return c; - } - - private static void closeAll(Iterable<RevWalk> revWalks, Iterable<Repository> repos) { - if (repos != null) { - for (Repository repo : repos) { - repo.close(); - } - } - if (revWalks != null) { - for (RevWalk revWalk : revWalks) { - revWalk.close(); - } - } - } - - private void show(Object data) { - switch (outputFormat) { - default: - case TEXT: - if (data instanceof ChangeAttribute) { - out.print("change "); - out.print(((ChangeAttribute) data).id); - out.print("\n"); - showText(data, 1); - } else { - showText(data, 0); - } - out.print('\n'); - break; - - case JSON: - out.print(new Gson().toJson(data)); - out.print('\n'); - break; - } - } - - private void showText(Object data, int depth) { - for (Field f : fieldsOf(data.getClass())) { - Object val; - try { - val = f.get(data); - } catch (IllegalArgumentException err) { - continue; - } catch (IllegalAccessException err) { - continue; - } - if (val == null) { - continue; - } - - showField(f.getName(), val, depth); - } - } - - private String indent(int spaces) { - if (spaces == 0) { - return ""; - } - return String.format("%" + spaces + "s", " "); - } - - private void showField(String field, Object value, int depth) { - final int spacesDepthRatio = 2; - String indent = indent(depth * spacesDepthRatio); - out.print(indent); - out.print(field); - out.print(':'); - if (value instanceof String && ((String) value).contains("\n")) { - out.print(' '); - // Idention for multi-line text is - // current depth indetion + length of field + length of ": " - indent = indent(indent.length() + field.length() + spacesDepthRatio); - out.print(((String) value).replaceAll("\n", "\n" + indent).trim()); - out.print('\n'); - } else if (value instanceof Long && isDateField(field)) { - out.print(' '); - out.print(dtf.print(((Long) value) * 1000L)); - out.print('\n'); - } else if (isPrimitive(value)) { - out.print(' '); - out.print(value); - out.print('\n'); - } else if (value instanceof Collection) { - out.print('\n'); - boolean firstElement = true; - for (Object thing : ((Collection<?>) value)) { - // The name of the collection was initially printed at the beginning - // of this routine. Beginning at the second sub-element, reprint - // the collection name so humans can separate individual elements - // with less strain and error. - // - if (firstElement) { - firstElement = false; - } else { - out.print(indent); - out.print(field); - out.print(":\n"); - } - if (isPrimitive(thing)) { - out.print(' '); - out.print(value); - out.print('\n'); - } else { - showText(thing, depth + 1); - } - } - } else { - out.print('\n'); - showText(value, depth + 1); - } - } - - private static boolean isPrimitive(Object value) { - return value instanceof String // - || value instanceof Number // - || value instanceof Boolean // - || value instanceof Enum; - } - - private static boolean isDateField(String name) { - return "lastUpdated".equals(name) // - || "grantedOn".equals(name) // - || "timestamp".equals(name) // - || "createdOn".equals(name); - } - - private List<Field> fieldsOf(Class<?> type) { - List<Field> r = new ArrayList<>(); - if (type.getSuperclass() != null) { - r.addAll(fieldsOf(type.getSuperclass())); - } - r.addAll(Arrays.asList(type.getDeclaredFields())); - return r; - } - - static class ErrorMessage { - public final String type = "error"; - public String message; - } -} |