/**
* The MIT License
*
* Copyright (c) 2010-2011 Sonatype, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
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 com.google.common.base.Preconditions;
import org.hudsonci.utils.tasks.JobUuid;
/**
* 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();
}
}