Plugin API: Add create project API

Change-Id: Ibc4de0747f10336eaa51a818672e01cfd55c4a16
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/project/ProjectIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/project/ProjectIT.java
index 54afd0b..5a84264 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/project/ProjectIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/project/ProjectIT.java
@@ -17,6 +17,7 @@
 import com.google.gerrit.acceptance.AbstractDaemonTest;
 import com.google.gerrit.acceptance.NoHttpd;
 import com.google.gerrit.extensions.api.projects.BranchInput;
+import com.google.gerrit.extensions.api.projects.ProjectInput;
 import com.google.gerrit.extensions.restapi.RestApiException;
 
 import org.eclipse.jgit.api.errors.GitAPIException;
@@ -28,6 +29,22 @@
 public class ProjectIT extends AbstractDaemonTest  {
 
   @Test
+  public void createProjectFoo() throws RestApiException {
+    gApi.projects()
+        .name("foo")
+        .create();
+  }
+
+  @Test(expected = RestApiException.class)
+  public void createProjectFooBar() throws RestApiException {
+    ProjectInput in = new ProjectInput();
+    in.name = "bar";
+    gApi.projects()
+        .name("foo")
+        .create(in);
+  }
+
+  @Test
   public void createBranch() throws GitAPIException,
       IOException, RestApiException {
     gApi.projects()
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ProjectApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ProjectApi.java
index 1c7209d..295b414 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ProjectApi.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ProjectApi.java
@@ -14,6 +14,10 @@
 
 package com.google.gerrit.extensions.api.projects;
 
+import com.google.gerrit.extensions.restapi.RestApiException;
+
 public interface ProjectApi {
+  ProjectApi create() throws RestApiException;
+  ProjectApi create(ProjectInput in) throws RestApiException;
   BranchApi branch(String ref);
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/ProjectApiImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/ProjectApiImpl.java
index 14b05b6..47b4964 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/ProjectApiImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/ProjectApiImpl.java
@@ -14,29 +14,94 @@
 
 package com.google.gerrit.server.api.projects;
 
+import com.google.gerrit.common.errors.ProjectCreationFailedException;
 import com.google.gerrit.extensions.api.projects.BranchApi;
 import com.google.gerrit.extensions.api.projects.ProjectApi;
+import com.google.gerrit.extensions.api.projects.ProjectInput;
+import com.google.gerrit.extensions.restapi.BadRequestException;
+import com.google.gerrit.extensions.restapi.ResourceConflictException;
+import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
+import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.extensions.restapi.TopLevelResource;
+import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
+import com.google.gerrit.server.project.CreateProject;
 import com.google.gerrit.server.project.ProjectResource;
-import com.google.inject.Inject;
+import com.google.gerrit.server.project.ProjectsCollection;
+import com.google.inject.Provider;
 import com.google.inject.assistedinject.Assisted;
+import com.google.inject.assistedinject.AssistedInject;
+
+import java.io.IOException;
 
 public class ProjectApiImpl implements ProjectApi {
   interface Factory {
     ProjectApiImpl create(ProjectResource project);
+    ProjectApiImpl create(String name);
   }
 
+  private final Provider<CreateProject.Factory> createProjectFactory;
+  private final ProjectApiImpl.Factory projectApi;
+  private final ProjectsCollection projects;
   private final ProjectResource project;
+  private final String name;
   private final BranchApiImpl.Factory branchApi;
 
-  @Inject
-  ProjectApiImpl(
+  @AssistedInject
+  ProjectApiImpl(Provider<CreateProject.Factory> createProjectFactory,
+      ProjectApiImpl.Factory projectApi,
+      ProjectsCollection projects,
       BranchApiImpl.Factory branchApiFactory,
       @Assisted ProjectResource project) {
+    this(createProjectFactory, projectApi, projects, branchApiFactory, project,
+        null);
+  }
+
+  @AssistedInject
+  ProjectApiImpl(Provider<CreateProject.Factory> createProjectFactory,
+      ProjectApiImpl.Factory projectApi,
+      ProjectsCollection projects,
+      BranchApiImpl.Factory branchApiFactory,
+      @Assisted String name) {
+    this(createProjectFactory, projectApi, projects, branchApiFactory, null,
+        name);
+  }
+
+  private ProjectApiImpl(Provider<CreateProject.Factory> createProjectFactory,
+      ProjectApiImpl.Factory projectApi,
+      ProjectsCollection projects,
+      BranchApiImpl.Factory branchApiFactory,
+      ProjectResource project,
+      String name) {
+    this.createProjectFactory = createProjectFactory;
+    this.projectApi = projectApi;
+    this.projects = projects;
     this.project = project;
+    this.name = name;
     this.branchApi = branchApiFactory;
   }
 
   @Override
+  public ProjectApi create() throws RestApiException {
+    return create(new ProjectInput());
+  }
+
+  @Override
+  public ProjectApi create(ProjectInput in) throws RestApiException {
+    try {
+      if (in.name != null && !name.equals(in.name)) {
+        throw new RestApiException("name must match input.name");
+      }
+      createProjectFactory.get().create(name)
+          .apply(TopLevelResource.INSTANCE, in);
+      return projectApi.create(projects.parse(name));
+    } catch (BadRequestException | UnprocessableEntityException
+        | ResourceConflictException | ResourceNotFoundException
+        | ProjectCreationFailedException | IOException e) {
+      throw new RestApiException("Cannot create project", e);
+    }
+  }
+
+  @Override
   public BranchApi branch(String ref) {
     return branchApi.create(project, ref);
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/ProjectsImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/ProjectsImpl.java
index bd5e2ac..fc0396d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/ProjectsImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/ProjectsImpl.java
@@ -37,7 +37,9 @@
   public ProjectApi name(String name) throws RestApiException {
     try {
       return api.create(projects.parse(name));
-    } catch (IOException | UnprocessableEntityException e) {
+    } catch (UnprocessableEntityException e) {
+      return api.create(name);
+    } catch (IOException e) {
       throw new RestApiException("Cannot retrieve project");
     }
   }