Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #37 from futures/webhooks
Webhooks
- Loading branch information
Showing
12 changed files
with
561 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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
168
fcrepo-webhooks/src/main/java/org/fcrepo/webhooks/FedoraWebhooks.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
/* | ||
* Generic Fedora namespace | ||
*/ | ||
<webhook = 'org.webhooks'> | ||
|
||
/* | ||
* Any Fedora resource. | ||
*/ | ||
[webhook:resource] mixin abstract | ||
|
||
[webhook:callback] | ||
- webhook:callbackUrl (STRING) COPY |
57 changes: 57 additions & 0 deletions
57
fcrepo-webhooks/src/test/java/org/fcrepo/webhooks/AbstractResourceTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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(); | ||
} | ||
|
||
} |
Oops, something went wrong.