/******************************************************************************* * * Copyright (c) 2010-2011 Sonatype, Inc. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * * * * *******************************************************************************/ package org.hudsonci.service.internal; import static org.hudsonci.service.internal.ServicePreconditions.*; import hudson.matrix.MatrixConfiguration; import hudson.matrix.MatrixProject; import hudson.model.Item; import hudson.model.TopLevelItem; import hudson.model.AbstractProject; import hudson.model.Job; import java.io.IOException; import java.io.InputStream; import java.util.Collection; import java.util.List; import java.util.UUID; import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; import org.hudsonci.service.ProjectNotFoundException; import org.hudsonci.service.ProjectService; import org.hudsonci.service.SecurityService; import org.hudsonci.service.ServiceRuntimeException; import org.hudsonci.service.SystemIntegrityViolationException; import org.hudsonci.utils.tasks.JobUuid; import com.google.common.base.Preconditions; /** * Default {@link ProjectService} implementation. * * @since 2.1.0 */ @Named @Singleton public class ProjectServiceImpl extends ServiceSupport implements ProjectService { private final SecurityService securityService; @Inject ProjectServiceImpl(final SecurityService securityService) { this.securityService = Preconditions.checkNotNull(securityService); } public AbstractProject<?, ?> getProject(final UUID id) { AbstractProject<?, ?> project = findProject(id); if (project == null) { throw new ProjectNotFoundException(String.format("No project with UUID '%s' found.", id)); } return project; } public AbstractProject<?, ?> getProject(final String projectName) { AbstractProject<?, ?> project = findProject(projectName); if (project == null) { throw new ProjectNotFoundException(String.format("Project %s not found.", projectName)); } return project; } public AbstractProject<?, ?> getProjectByFullName(final String projectName) { AbstractProject<?, ?> p = findProjectByFullName(projectName); if (p == null) { throw new ProjectNotFoundException(String.format("Project %s not found.", projectName)); } return p; } public AbstractProject<?, ?> findProject(final UUID id) { checkNotNull(id, UUID.class); Job<?, ?> job = JobUuid.find(id); return (AbstractProject<?, ?>) job; } public AbstractProject<?, ?> findProject(final String projectName) { checkProjectName(projectName); // Handle matrix-project/configuration projects. // First part is matrix-project name, second part is // matrix-configuration name String[] parts = projectName.split("/", 2); if (parts.length == 2) { log.debug("Detected matrix name: {}", projectName); AbstractProject<?, ?> parent = findProject(parts[0]); if (parent instanceof MatrixProject) { for (MatrixConfiguration config : ((MatrixProject) parent).getItems()) { if (parts[1].equals(config.getName())) { log.debug("Selected matrix configuration: {}", config); // config.checkPermission(Item.READ); // TODO needed? return config; } } } } if (!getProjectNames().contains(projectName)) { log.debug("Project {} not in the list of job names.", projectName); return null; } AbstractProject<?, ?> project = getProjectByFullName(projectName); log.debug("Selected project: {}", project); return project; } public AbstractProject<?, ?> findProjectByFullName(final String projectName) { checkProjectName(projectName); AbstractProject<?, ?> p = getHudson().getItemByFullName(projectName, AbstractProject.class); if (p != null) { this.securityService.checkPermission(p, Item.READ); } return p; } @SuppressWarnings("rawtypes") public List<AbstractProject> getAllProjects() { // Hudson checks that items are readable by the current context (has Item.READ perms) return getHudson().getAllItems(AbstractProject.class); } public <T extends AbstractProject<?, ?>> T copyProject(final T src, final String targetProjectName) throws ServiceRuntimeException { checkNotNull(src, AbstractProject.class); checkProjectName(targetProjectName); this.securityService.checkPermission(Item.CREATE); this.securityService.checkPermission(src, Item.EXTENDED_READ); // caller should try to verify this themselves before calling me // TODO should this check really be performed here? if (projectExists(targetProjectName)) { throw new SystemIntegrityViolationException(String.format("Project %s already exists.", targetProjectName)); } try { return getHudson().copy(src, targetProjectName); } catch (IOException ex) { throw new ServiceRuntimeException(String.format("Project copy failed from %s to %s", src.getName(), targetProjectName), ex); } } public TopLevelItem createProjectFromXML(final String projectName, final InputStream xml) { checkProjectName(projectName); checkNotNull(xml, InputStream.class); this.securityService.checkPermission(Item.CREATE); // caller should verify this themselves before calling me // TODO should this check really be performed here? if (projectExists(projectName)) { throw new SystemIntegrityViolationException(String.format("Project %s already exists.", projectName)); } try { return getHudson().createProjectFromXML(projectName, xml); } catch (IOException ex) { throw new ServiceRuntimeException(String.format("Project creation failed for %s", projectName), ex); } } public boolean projectExists(final String projectName) { checkProjectName(projectName); // This only checks names that are readable by the current context (has Item.READ perms) return getProjectNames().contains(projectName); } public Collection<String> getProjectNames() { // Hudson only returns jobnames when the current context has Item.READ perms on it return getHudson().getJobNames(); } }