Skip to content

Commit

Permalink
Merge pull request #37 from futures/webhooks
Browse files Browse the repository at this point in the history
Webhooks
  • Loading branch information
cbeer committed Mar 15, 2013
2 parents f0e3103 + 24157f1 commit 4f9dc8f
Show file tree
Hide file tree
Showing 12 changed files with 561 additions and 0 deletions.
80 changes: 80 additions & 0 deletions fcrepo-webhooks/pom.xml
@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>fcrepo</artifactId>
<groupId>org.fcrepo</groupId>
<version>4.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>fcrepo-webhooks</artifactId>



<dependencies>

<dependency>
<groupId>org.fcrepo</groupId>
<artifactId>fcrepo-kernel</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.fcrepo</groupId>
<artifactId>fcrepo-http-commons</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>org.fcrepo</groupId>
<artifactId>fcrepo-http-api</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.fcrepo</groupId>
<artifactId>fcrepo-jms</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-extension-providers</artifactId>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<scope>compile</scope>
</dependency>


<!-- This dependency is for compile-time: it keeps this module independent
of any given choice of JAX-RS implementation. It must be _after_ the test
gear. Otherwise it will get loaded during test phase, but because this is
just an API, the tests will not be able to execute. -->
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
</dependency>
</dependencies>

</project>
168 changes: 168 additions & 0 deletions fcrepo-webhooks/src/main/java/org/fcrepo/webhooks/FedoraWebhooks.java
@@ -0,0 +1,168 @@
package org.fcrepo.webhooks;


import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.fcrepo.AbstractResource;
import org.fcrepo.messaging.legacy.LegacyMethod;
import org.fcrepo.observer.FedoraEvent;
import org.fcrepo.utils.FedoraTypesUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.inject.Inject;
import javax.jcr.LoginException;
import javax.jcr.NoSuchWorkspaceException;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.observation.Event;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;

import java.io.IOException;
import java.io.StringWriter;
import java.util.concurrent.TimeUnit;

import static javax.ws.rs.core.Response.created;
import static javax.ws.rs.core.Response.ok;

@Path("/webhooks")
public class FedoraWebhooks extends AbstractResource {

static final private Logger logger = LoggerFactory
.getLogger(FedoraWebhooks.class);


protected static final PoolingClientConnectionManager connectionManager =
new PoolingClientConnectionManager();

protected static HttpClient client;


@Inject
EventBus eventBus;

/**
* For use with non-mutating methods.
*/
private static Session readOnlySession;


static {
connectionManager.setMaxTotal(Integer.MAX_VALUE);
connectionManager.setDefaultMaxPerRoute(5);
connectionManager.closeIdleConnections(3, TimeUnit.SECONDS);
client = new DefaultHttpClient(connectionManager);
}

@PostConstruct
public void initialize() throws LoginException, NoSuchWorkspaceException,
RepositoryException {

eventBus.register(this);

final Session session = repo.login();
jcrTools.registerNodeTypes(session, "webhooks.cnd");
session.save();
session.logout();
}

public static void runHooks(final Node resource, final FedoraEvent event) throws RepositoryException {
final NodeIterator webhooksIterator = resource.getSession().getRootNode().getNodes("webhook:*");

while(webhooksIterator.hasNext()) {
final Node hook = webhooksIterator.nextNode();
final String callbackUrl = hook.getProperty("webhook:callbackUrl").getString();
HttpPost method = new HttpPost(callbackUrl);
LegacyMethod eventSerialization = new LegacyMethod(event, resource);
StringWriter writer = new StringWriter();

try {
eventSerialization.writeTo(writer);
method.setEntity(new StringEntity(writer.toString()));
} catch (IOException e) {
e.printStackTrace();
}

try {
logger.debug("Firing callback for" + hook.getName());
client.execute(method);
} catch (IOException e) {
e.printStackTrace();
}

}
}

@GET
public Response showWebhooks() throws RepositoryException {

final NodeIterator webhooksIterator = readOnlySession.getRootNode().getNodes("webhook:*");
StringBuilder str = new StringBuilder();

while(webhooksIterator.hasNext()) {
final Node hook = webhooksIterator.nextNode();
final String callbackUrl = hook.getProperty("webhook:callbackUrl").getString();
str.append(callbackUrl + ", ");
}

return ok(str.toString()).build();
}

@POST
@Path("{id}")
public Response registerWebhook(@PathParam("id") final String id, @FormParam("callbackUrl") final String callbackUrl) throws RepositoryException {

final Session session = repo.login();

Node n = jcrTools.findOrCreateChild(session.getRootNode(), "webhook:" + id, "webhook:callback");

n.setProperty("webhook:callbackUrl", callbackUrl);

session.save();
session.logout();

return created(uriInfo.getAbsolutePath()).build();
}



@Subscribe
public void newEvent(FedoraEvent event) {
try {
final Node resource = jcrTools.findOrCreateNode(readOnlySession, event.getPath());

runHooks(resource, event);
} catch (RepositoryException e) {
e.printStackTrace();
}
}

@PostConstruct
public final void getSession() {
try {
readOnlySession = repo.login();
} catch (RepositoryException e) {
throw new IllegalStateException(e);
}
}

@PreDestroy
public final void logoutSession() {
readOnlySession.logout();
}
}
12 changes: 12 additions & 0 deletions fcrepo-webhooks/src/main/resources/webhooks.cnd
@@ -0,0 +1,12 @@
/*
* Generic Fedora namespace
*/
<webhook = 'org.webhooks'>

/*
* Any Fedora resource.
*/
[webhook:resource] mixin abstract

[webhook:callback]
- webhook:callbackUrl (STRING) COPY
@@ -0,0 +1,57 @@

package org.fcrepo.webhooks;

import static java.lang.Integer.parseInt;
import static java.lang.System.getProperty;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
public abstract class AbstractResourceTest {

protected Logger logger;

@Before
public void setLogger() {
logger = LoggerFactory.getLogger(this.getClass());
}

protected static final int SERVER_PORT = parseInt(getProperty("test.port",
"8080"));

protected static final String HOSTNAME = "localhost";

protected static final String serverAddress = "http://" + HOSTNAME + ":" +
SERVER_PORT;

protected final PoolingClientConnectionManager connectionManager =
new PoolingClientConnectionManager();

protected static HttpClient client;

public AbstractResourceTest() {
connectionManager.setMaxTotal(Integer.MAX_VALUE);
connectionManager.setDefaultMaxPerRoute(5);
connectionManager.closeIdleConnections(3, TimeUnit.SECONDS);
client = new DefaultHttpClient(connectionManager);
}
protected int getStatus(HttpUriRequest method)
throws ClientProtocolException, IOException {
logger.debug("Executing: " + method.getMethod() + " to " +
method.getURI());
return client.execute(method).getStatusLine().getStatusCode();
}

}

0 comments on commit 4f9dc8f

Please sign in to comment.