1   /*
2    * Copyright 2017 LINE Corporation
3    *
4    * LINE Corporation licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  
17  package com.linecorp.centraldogma.server.command;
18  
19  import static com.google.common.base.Preconditions.checkArgument;
20  import static java.util.Objects.requireNonNull;
21  
22  import javax.annotation.Nullable;
23  
24  import com.fasterxml.jackson.annotation.JsonProperty;
25  import com.fasterxml.jackson.annotation.JsonSubTypes;
26  import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
27  import com.fasterxml.jackson.annotation.JsonTypeInfo;
28  import com.google.common.collect.ImmutableList;
29  
30  import com.linecorp.centraldogma.common.Author;
31  import com.linecorp.centraldogma.common.Change;
32  import com.linecorp.centraldogma.common.Markup;
33  import com.linecorp.centraldogma.common.Revision;
34  import com.linecorp.centraldogma.server.auth.Session;
35  import com.linecorp.centraldogma.server.management.ServerStatus;
36  import com.linecorp.centraldogma.server.storage.repository.Repository;
37  
38  /**
39   * A Central Dogma command which is used to mutate projects and repositories.
40   *
41   * @param <T> the result type of a {@link Command}
42   */
43  @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
44  @JsonSubTypes({
45          @Type(value = CreateProjectCommand.class, name = "CREATE_PROJECT"),
46          @Type(value = RemoveProjectCommand.class, name = "REMOVE_PROJECT"),
47          @Type(value = PurgeProjectCommand.class, name = "PURGE_PROJECT"),
48          @Type(value = UnremoveProjectCommand.class, name = "UNREMOVE_PROJECT"),
49          @Type(value = CreateRepositoryCommand.class, name = "CREATE_REPOSITORY"),
50          @Type(value = RemoveRepositoryCommand.class, name = "REMOVE_REPOSITORY"),
51          @Type(value = PurgeRepositoryCommand.class, name = "PURGE_REPOSITORY"),
52          @Type(value = UnremoveRepositoryCommand.class, name = "UNREMOVE_REPOSITORY"),
53          @Type(value = NormalizingPushCommand.class, name = "NORMALIZING_PUSH"),
54          @Type(value = PushAsIsCommand.class, name = "PUSH"),
55          @Type(value = CreateSessionCommand.class, name = "CREATE_SESSIONS"),
56          @Type(value = RemoveSessionCommand.class, name = "REMOVE_SESSIONS"),
57          @Type(value = UpdateServerStatusCommand.class, name = "UPDATE_SERVER_STATUS"),
58          @Type(value = ForcePushCommand.class, name = "FORCE_PUSH_COMMAND"),
59  })
60  public interface Command<T> {
61  
62      /**
63       * Returns a new {@link Command} which is used to create a new project.
64       *
65       * @param author the author who is creating the project
66       * @param name the name of the project which is supposed to be created
67       */
68      static Command<Void> createProject(Author author, String name) {
69          return createProject(null, author, name);
70      }
71  
72      /**
73       * Returns a new {@link Command} which is used to create a new project.
74       *
75       * @param timestamp the creation time of the project, in milliseconds
76       * @param author the author who is creating the project
77       * @param name the name of the project which is supposed to be created
78       */
79      static Command<Void> createProject(@Nullable Long timestamp, Author author, String name) {
80          requireNonNull(author, "author");
81          return new CreateProjectCommand(timestamp, author, name);
82      }
83  
84      /**
85       * Returns a new {@link Command} which is used to remove a project.
86       *
87       * @param author the author who is removing the project
88       * @param name the name of the project which is supposed to be removed
89       */
90      static Command<Void> removeProject(Author author, String name) {
91          return removeProject(null, author, name);
92      }
93  
94      /**
95       * Returns a new {@link Command} which is used to remove a project.
96       *
97       * @param timestamp the removal time of the project, in milliseconds
98       * @param author the author who is removing the project
99       * @param name the name of the project which is supposed to be removed
100      */
101     static Command<Void> removeProject(@Nullable Long timestamp, Author author, String name) {
102         requireNonNull(author, "author");
103         return new RemoveProjectCommand(timestamp, author, name);
104     }
105 
106     /**
107      * Returns a new {@link Command} which is used to restore a project that was removed before.
108      *
109      * @param author the author who is restoring the project
110      * @param name the name of the project which is supposed to be restored
111      */
112     static Command<Void> unremoveProject(Author author, String name) {
113         return unremoveProject(null, author, name);
114     }
115 
116     /**
117      * Returns a new {@link Command} which is used to restore a project that was removed before.
118      *
119      * @param timestamp the restoration time of the project, in milliseconds
120      * @param author the author who is restoring the project
121      * @param name the name of the project which is supposed to be restored
122      */
123     static Command<Void> unremoveProject(@Nullable Long timestamp, Author author, String name) {
124         requireNonNull(author, "author");
125         return new UnremoveProjectCommand(timestamp, author, name);
126     }
127 
128     /**
129      * Returns a new {@link Command} which is used to purge a project that was removed before.
130      *
131      * @param author the author who is restoring the project
132      * @param name the name of the project which is supposed to be restored
133      */
134     static Command<Void> purgeProject(Author author, String name) {
135         requireNonNull(author, "author");
136         return new PurgeProjectCommand(null, author, name);
137     }
138 
139     /**
140      * Returns a new {@link Command} which is used to purge a project that was removed before.
141      *
142      * @param timestamp the purging time of the project, in milliseconds
143      * @param author the author who is restoring the project
144      * @param name the name of the project which is supposed to be restored
145      */
146     static Command<Void> purgeProject(@Nullable Long timestamp, Author author, String name) {
147         requireNonNull(author, "author");
148         return new PurgeProjectCommand(timestamp, author, name);
149     }
150 
151     /**
152      * Returns a new {@link Command} which is used to create a new repository.
153      *
154      * @param author the author who is creating the repository
155      * @param projectName the name of the project that the new repository is supposed to belong to
156      * @param repositoryName the name of the repository which is supposed to be created
157      */
158     static Command<Void> createRepository(Author author, String projectName, String repositoryName) {
159         return createRepository(null, author, projectName, repositoryName);
160     }
161 
162     /**
163      * Returns a new {@link Command} which is used to create a new repository.
164      *
165      * @param timestamp the creation time of the repository, in milliseconds
166      * @param author the author who is creating the repository
167      * @param projectName the name of the project that the new repository is supposed to belong to
168      * @param repositoryName the name of the repository which is supposed to be created
169      */
170     static Command<Void> createRepository(@Nullable Long timestamp, Author author,
171                                           String projectName, String repositoryName) {
172         requireNonNull(author, "author");
173         return new CreateRepositoryCommand(timestamp, author, projectName, repositoryName);
174     }
175 
176     /**
177      * Returns a new {@link Command} which is used to remove a repository.
178      *
179      * @param author the author who is removing the repository
180      * @param projectName the name of the project
181      * @param repositoryName the name of the repository which is supposed to be removed
182      */
183     static Command<Void> removeRepository(Author author, String projectName, String repositoryName) {
184         return removeRepository(null, author, projectName, repositoryName);
185     }
186 
187     /**
188      * Returns a new {@link Command} which is used to remove a repository.
189      *
190      * @param timestamp the removal time of the repository, in milliseconds
191      * @param author the author who is removing the repository
192      * @param projectName the name of the project
193      * @param repositoryName the name of the repository which is supposed to be removed
194      */
195     static Command<Void> removeRepository(@Nullable Long timestamp, Author author,
196                                           String projectName, String repositoryName) {
197         requireNonNull(author, "author");
198         return new RemoveRepositoryCommand(timestamp, author, projectName, repositoryName);
199     }
200 
201     /**
202      * Returns a new {@link Command} which is used to restore a repository that was removed before.
203      *
204      * @param author the author who is restoring the repository
205      * @param projectName the name of the project
206      * @param repositoryName the name of the repository which is supposed to be restored
207      */
208     static Command<Void> unremoveRepository(Author author, String projectName, String repositoryName) {
209         return unremoveRepository(null, author, projectName, repositoryName);
210     }
211 
212     /**
213      * Returns a new {@link Command} which is used to restore a repository that was removed before.
214      *
215      * @param timestamp the restoration time of the project, in milliseconds
216      * @param author the author who is restoring the repository
217      * @param projectName the name of the project
218      * @param repositoryName the name of the repository which is supposed to be restored
219      */
220     static Command<Void> unremoveRepository(@Nullable Long timestamp, Author author,
221                                             String projectName, String repositoryName) {
222         requireNonNull(author, "author");
223         return new UnremoveRepositoryCommand(timestamp, author, projectName, repositoryName);
224     }
225 
226     /**
227      * Returns a new {@link Command} which is used to purge a repository.
228      *
229      * @param author the author who is removing the repository
230      * @param projectName the name of the project
231      * @param repositoryName the name of the repository which is supposed to be purged
232      */
233     static Command<Void> purgeRepository(Author author,
234                                          String projectName, String repositoryName) {
235         requireNonNull(author, "author");
236         return new PurgeRepositoryCommand(null, author, projectName, repositoryName);
237     }
238 
239     /**
240      * Returns a new {@link Command} which is used to purge a repository.
241      *
242      * @param timestamp the purging time of the repository, in milliseconds
243      * @param author the author who is removing the repository
244      * @param projectName the name of the project
245      * @param repositoryName the name of the repository which is supposed to be purged
246      */
247     static Command<Void> purgeRepository(@Nullable Long timestamp, Author author,
248                                          String projectName, String repositoryName) {
249         requireNonNull(author, "author");
250         return new PurgeRepositoryCommand(timestamp, author, projectName, repositoryName);
251     }
252 
253     /**
254      * Returns a new {@link Command} which is used to push the changes. The changes are normalized via
255      * {@link Repository#previewDiff(Revision, Iterable)} before they are applied.
256      * You can find the normalized changes from the {@link CommitResult#changes()} that is the result of
257      * {@link CommandExecutor#execute(Command)}.
258      *
259      * @param author the author who is pushing the changes
260      * @param projectName the name of the project
261      * @param repositoryName the name of the repository which is supposed to be restored
262      * @param baseRevision the revision which is supposed to apply the changes
263      * @param summary the summary of the changes
264      * @param detail the detail message of the changes
265      * @param markup the markup for the detail message
266      * @param changes the changes to be applied
267      */
268     static Command<CommitResult> push(Author author, String projectName, String repositoryName,
269                                       Revision baseRevision, String summary, String detail,
270                                       Markup markup, Change<?>... changes) {
271 
272         return push(null, author, projectName, repositoryName, baseRevision, summary, detail, markup, changes);
273     }
274 
275     /**
276      * Returns a new {@link Command} which is used to push the changes. The changes are normalized via
277      * {@link Repository#previewDiff(Revision, Iterable)} before they are applied.
278      * You can find the normalized changes from the {@link CommitResult#changes()} that is the result of
279      * {@link CommandExecutor#execute(Command)}.
280      *
281      * @param timestamp the time when pushing the changes, in milliseconds
282      * @param author the author who is pushing the changes
283      * @param projectName the name of the project
284      * @param repositoryName the name of the repository which is supposed to be restored
285      * @param baseRevision the revision which is supposed to apply the changes
286      * @param summary the summary of the changes
287      * @param detail the detail message of the changes
288      * @param markup the markup for the detail message
289      * @param changes the changes to be applied
290      */
291     static Command<CommitResult> push(@Nullable Long timestamp, Author author,
292                                       String projectName, String repositoryName,
293                                       Revision baseRevision, String summary, String detail,
294                                       Markup markup, Change<?>... changes) {
295         return push(timestamp, author, projectName, repositoryName, baseRevision,
296                     summary, detail, markup, ImmutableList.copyOf(changes));
297     }
298 
299     /**
300      * Returns a new {@link Command} which is used to push the changes. The changes are normalized via
301      * {@link Repository#previewDiff(Revision, Iterable)} before they are applied.
302      * You can find the normalized changes from the {@link CommitResult#changes()} that is the result of
303      * {@link CommandExecutor#execute(Command)}.
304      *
305      * @param author the author who is pushing the changes
306      * @param projectName the name of the project
307      * @param repositoryName the name of the repository which is supposed to be restored
308      * @param baseRevision the revision which is supposed to apply the changes
309      * @param summary the summary of the changes
310      * @param detail the detail message of the changes
311      * @param markup the markup for the detail message
312      * @param changes the changes to be applied
313      */
314     static Command<CommitResult> push(Author author, String projectName, String repositoryName,
315                                       Revision baseRevision, String summary, String detail,
316                                       Markup markup, Iterable<Change<?>> changes) {
317         return push(null, author, projectName, repositoryName, baseRevision, summary, detail, markup, changes);
318     }
319 
320     /**
321      * Returns a new {@link Command} which is used to push the changes. The changes are normalized via
322      * {@link Repository#previewDiff(Revision, Iterable)} before they are applied.
323      * You can find the normalized changes from the {@link CommitResult#changes()} that is the result of
324      * {@link CommandExecutor#execute(Command)}.
325      *
326      * @param timestamp the time when pushing the changes, in milliseconds
327      * @param author the author who is pushing the changes
328      * @param projectName the name of the project
329      * @param repositoryName the name of the repository which is supposed to be restored
330      * @param baseRevision the revision which is supposed to apply the changes
331      * @param summary the summary of the changes
332      * @param detail the detail message of the changes
333      * @param markup the markup for the detail message
334      * @param changes the changes to be applied
335      */
336     static Command<CommitResult> push(@Nullable Long timestamp, Author author,
337                                       String projectName, String repositoryName,
338                                       Revision baseRevision, String summary, String detail,
339                                       Markup markup, Iterable<Change<?>> changes) {
340         return new NormalizingPushCommand(timestamp, author, projectName, repositoryName, baseRevision,
341                                           summary, detail, markup, changes);
342     }
343 
344     /**
345      * Returns a new {@link Command} which is used to create a new session.
346      *
347      * @param session the session supposed to be created
348      */
349     static Command<Void> createSession(Session session) {
350         return new CreateSessionCommand(null, null, session);
351     }
352 
353     /**
354      * Returns a new {@link Command} which is used to remove an existing session.
355      *
356      * @param sessionId the session ID supposed to be removed
357      */
358     static Command<Void> removeSession(String sessionId) {
359         return new RemoveSessionCommand(null, null, sessionId);
360     }
361 
362     /**
363      * Returns a new {@link Command} which is used to update the status of the server.
364      */
365     static Command<Void> updateServerStatus(ServerStatus serverStatus) {
366         return new UpdateServerStatusCommand(null, null, serverStatus);
367     }
368 
369     /**
370      * Returns a new {@link Command} which is used to force-push {@link Command} even the server is in
371      * read-only mode. This command is useful for migrating the repository content during maintenance mode.
372      *
373      * <p>Note that {@link CommandType#NORMALIZING_PUSH} and {@link CommandType#PUSH} are allowed as the
374      * delegate.
375      */
376     static <T> Command<T> forcePush(Command<T> delegate) {
377         requireNonNull(delegate, "delegate");
378         checkArgument(delegate.type() == CommandType.NORMALIZING_PUSH || delegate.type() == CommandType.PUSH,
379                       "delegate: %s (expected: NORMALIZING_PUSH or PUSH)", delegate);
380         return new ForcePushCommand<>(delegate);
381     }
382 
383     /**
384      * Returns the {@link CommandType} of the command.
385      */
386     CommandType type();
387 
388     /**
389      * Returns the time when performing the command, in milliseconds.
390      */
391     @JsonProperty
392     long timestamp();
393 
394     /**
395      * Returns the author who initiated the command.
396      */
397     @JsonProperty
398     Author author();
399 
400     /**
401      * Returns the target that the command is supposed to affect, i.e. the project name for the commands
402      * affecting to the project, or the project and repository names for the commands affecting to the
403      * repository.
404      */
405     String executionPath();
406 }