Skip to content

Commit

Permalink
Merge pull request devhub-tud#7 from devhub-tud/build-deployment
Browse files Browse the repository at this point in the history
Preparing for build-server deployment.
  • Loading branch information
michaeldejong committed Apr 9, 2014
2 parents 2371332 + 4e51aa0 commit 5934e6a
Show file tree
Hide file tree
Showing 23 changed files with 787 additions and 21 deletions.
6 changes: 3 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
.project
.settings

**/.classpath
**/target/
**/*.db
.classpath
target/
*.db
10 changes: 10 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,16 @@
<artifactId>guava</artifactId>
<version>15.0</version>
</dependency>
<dependency>
<groupId>nl.tudelft.ewi.build</groupId>
<artifactId>build-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.directory.api</groupId>
<artifactId>api-ldap-client-all</artifactId>
<version>1.0.0-M21</version>
</dependency>
</dependencies>

<build>
Expand Down
7 changes: 7 additions & 0 deletions src/main/java/nl/tudelft/ewi/devhub/server/DevhubServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import javax.servlet.DispatcherType;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;

import lombok.extern.slf4j.Slf4j;

Expand All @@ -27,6 +28,12 @@
@Slf4j
public class DevhubServer {

public static String getHostUrl(HttpServletRequest request) {
String fullUrl = request.getRequestURL().toString();
String pathUrl = request.getRequestURI();
return fullUrl.substring(0, fullUrl.indexOf(pathUrl));
}

private static File determineRootFolder() {
File developmentFolder = new File("src/main/resources");
if (developmentFolder.exists()) {
Expand Down
163 changes: 163 additions & 0 deletions src/main/java/nl/tudelft/ewi/devhub/server/backend/BuildsBackend.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
package nl.tudelft.ewi.devhub.server.backend;

import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import javax.inject.Inject;
import javax.ws.rs.NotFoundException;

import lombok.extern.slf4j.Slf4j;
import nl.tudelft.ewi.build.client.BuildServerBackend;
import nl.tudelft.ewi.build.jaxrs.models.BuildRequest;
import nl.tudelft.ewi.devhub.server.database.controllers.BuildServers;
import nl.tudelft.ewi.devhub.server.database.entities.BuildServer;
import nl.tudelft.ewi.devhub.server.web.errors.ApiError;

import com.google.common.collect.Queues;
import com.google.inject.Provider;
import com.google.inject.persist.Transactional;
import com.google.inject.persist.UnitOfWork;

/**
* The {@link BuildServerClient} allows you to query and manipulate data from the build-server.
*/
@Slf4j
public class BuildsBackend {

private final BuildServers buildServers;
private final Provider<BuildSubmitter> submitters;
private final ConcurrentLinkedQueue<BuildRequest> buildQueue;
private final ScheduledExecutorService executor;
private final AtomicBoolean running;

@Inject
BuildsBackend(BuildServers buildServers, Provider<BuildSubmitter> submitters) {
this.buildServers = buildServers;
this.submitters = submitters;
this.buildQueue = Queues.newConcurrentLinkedQueue();
this.executor = new ScheduledThreadPoolExecutor(1);
this.running = new AtomicBoolean(false);
}

public List<BuildServer> listActiveBuildServers() {
return buildServers.listAll();
}

public boolean authenticate(String name, String secret) {
try {
buildServers.findByCredentials(name, secret);
return true;
}
catch (NotFoundException e) {
return false;
}
}

public void addBuildServer(BuildServer server) throws ApiError {
try {
buildServers.persist(server);
}
catch (Throwable e) {
throw new ApiError("error.could-not-add-build-server");
}
}

@Transactional
public void deleteBuildServer(long serverId) throws ApiError {
try {
BuildServer server = buildServers.findById(serverId);
buildServers.delete(server);
}
catch (Throwable e) {
throw new ApiError("error.could-not-remove-build-server");
}
}

public void offerBuild(BuildRequest request) {
synchronized (running) {
buildQueue.offer(request);
if (running.compareAndSet(false, true)) {
BuildSubmitter task = submitters.get();
task.initialize(this);
executor.submit(task);
}
}
}

public void shutdown() throws InterruptedException {
executor.shutdown();
executor.awaitTermination(1, TimeUnit.MINUTES);
}

private static class BuildSubmitter extends RunnableInUnitOfWork {

private static final int NO_CAPACITY_DELAY = 5000;

private final Provider<BuildServers> buildServersProvider;

private BuildsBackend backend;

@Inject
BuildSubmitter(Provider<BuildServers> buildServersProvider, Provider<UnitOfWork> workProvider) {
super(workProvider);
this.buildServersProvider = buildServersProvider;
}

void initialize(BuildsBackend backend) {
this.backend = backend;
}

@Override
@Transactional
protected void runInUnitOfWork() {
ConcurrentLinkedQueue<BuildRequest> buildQueue = backend.buildQueue;
AtomicBoolean running = backend.running;
BuildServers buildServers = buildServersProvider.get();

try {
while (!buildQueue.isEmpty()) {
boolean delivered = false;
BuildRequest buildRequest = buildQueue.peek();
List<BuildServer> allBuildServers = buildServers.listAll();

while (!allBuildServers.isEmpty()) {
BuildServer buildServer = allBuildServers.remove(0);
String host = buildServer.getHost();
String name = buildServer.getName();
String secret = buildServer.getSecret();

BuildServerBackend backend = new BuildServerBackend(host, name, secret);
if (backend.offerBuildRequest(buildRequest)) {
delivered = true;
buildQueue.poll();
log.info("One build request was succesfully handed to: {}", name);
break;
}
}

if (!delivered) {
try {
log.info("All {} build servers at capacity. Queue size: {}",
allBuildServers.size(), buildQueue.size());

Thread.sleep(NO_CAPACITY_DELAY);
}
catch (InterruptedException e) {
log.warn("Sleep was interrupted...");
}
}
}
}
finally {
synchronized (running) {
running.set(false);
}
}
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package nl.tudelft.ewi.devhub.server.backend;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import com.google.inject.Provider;
import com.google.inject.persist.UnitOfWork;

/**
* A wrapper for a {@link java.lang.Runnable} where the call method is run within a
* {@link com.google.inject.persist.UnitOfWork};
*/
@Slf4j
@AllArgsConstructor
public abstract class RunnableInUnitOfWork implements Runnable {

private final Provider<UnitOfWork> workProvider;

@Override
public final void run() {
UnitOfWork work = workProvider.get();
try {
log.trace("Starting");
work.begin();
runInUnitOfWork();
}
catch (Throwable e) {
log.error(e.getMessage(), e);
}
finally {
work.end();
log.trace("Finished");
}
}

protected abstract void runInUnitOfWork();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package nl.tudelft.ewi.devhub.server.database.controllers;

import java.util.List;

import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.ws.rs.NotFoundException;

import nl.tudelft.ewi.devhub.server.database.entities.BuildServer;
import nl.tudelft.ewi.devhub.server.database.entities.QBuildServer;

import com.google.inject.persist.Transactional;

public class BuildServers extends Controller<BuildServer> {

@Inject
public BuildServers(EntityManager entityManager) {
super(entityManager);
}

@Transactional
public List<BuildServer> listAll() {
return query().from(QBuildServer.buildServer)
.orderBy(QBuildServer.buildServer.name.asc())
.list(QBuildServer.buildServer);
}

@Transactional
public BuildServer findById(long id) {
BuildServer buildServer = query().from(QBuildServer.buildServer)
.where(QBuildServer.buildServer.id.eq(id))
.singleResult(QBuildServer.buildServer);

if (buildServer == null) {
throw new NotFoundException();
}
return buildServer;
}

@Transactional
public BuildServer findByCredentials(String name, String secret) {
BuildServer buildServer = query().from(QBuildServer.buildServer)
.where(QBuildServer.buildServer.name.eq(name))
.where(QBuildServer.buildServer.secret.eq(secret))
.singleResult(QBuildServer.buildServer);

if (buildServer == null) {
throw new NotFoundException();
}
return buildServer;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public T persist(T entity) {
@Transactional
public T delete(T entity) {
entityManager.remove(entity);
entityManager.detach(entity);
entityManager.flush();
return entity;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package nl.tudelft.ewi.devhub.server.database.entities;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;

import lombok.Data;

@Data
@Entity
@Table(name = "build_servers")
public class BuildServer {

@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;

@NotNull
@Column(name = "name")
private String name;

@NotNull
@Column(name = "secret")
private String secret;

@NotNull
@Column(name = "host")
private String host;

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@ public class User {
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;

@Column(name = "student_number")
private long studentNumber;

@NotNull
@Column(name = "net_id")
private String netId;
Expand Down
Loading

0 comments on commit 5934e6a

Please sign in to comment.