Skip to content

Commit

Permalink
rfe10175: support dynamic catalogs
Browse files Browse the repository at this point in the history
<release-note>
rfe10175: support dynamic catalogs

With this change, the java client now supports dynamic creation and
deletion of catalogs with AGServer methods createCatalog, getCatalog
and deleteCatalog.  Note that the server needs to be started using
the DynamicCatalogs directive in the agraph.cfg file in order to
create or delete catalogs dynamically.
</release-note>

Added prepush test DynamicCatalogTests
make prepush passes
make javadoc runs clean

Change-Id: I1b64c8fa0dea9f2e322c2c2649b13e51ab8d0e96
Reviewed-on: https://gerrit.franz.com:9080/1200
Reviewed-by: Ahmon Dancy <dancy@franz.com>
Reviewed-by: Kevin Layer <layer@franz.com>
Tested-by: Kevin Layer <layer@franz.com>
  • Loading branch information
Bill Millar authored and dklayer committed Nov 16, 2011
1 parent 4848d0d commit cef0c0f
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 10 deletions.
13 changes: 13 additions & 0 deletions src/com/franz/agraph/http/AGHTTPClient.java
Expand Up @@ -301,6 +301,19 @@ protected final void releaseConnection(HttpMethod method) {
* Services *
*-----------*/

public void putCatalog(String catalogURL) throws AGHttpException {
if (logger.isDebugEnabled()) logger.debug("putCatalog: " + catalogURL);
Header[] headers = new Header[0];
NameValuePair[] params = new NameValuePair[0];
put(catalogURL,headers,params,null);
}

public void deleteCatalog(String catalogURL) throws AGHttpException {
Header[] headers = new Header[0];
NameValuePair[] params = new NameValuePair[0];
delete(catalogURL, headers, params);
}

public void putRepository(String repositoryURL) throws AGHttpException {
if (logger.isDebugEnabled()) logger.debug("putRepository: " + repositoryURL);
Header[] headers = new Header[0];
Expand Down
61 changes: 51 additions & 10 deletions src/com/franz/agraph/repository/AGServer.java
Expand Up @@ -14,6 +14,7 @@
import org.openrdf.OpenRDFException;
import org.openrdf.model.Value;
import org.openrdf.query.BindingSet;
import org.openrdf.query.QueryEvaluationException;
import org.openrdf.query.TupleQueryResult;

import com.franz.agraph.http.AGHTTPClient;
Expand Down Expand Up @@ -114,7 +115,7 @@ public AGCatalog getRootCatalog() {
* @return List of catalog ids.
* @throws OpenRDFException
*/
public List<String> listCatalogs() throws OpenRDFException {
public List<String> listCatalogs() throws AGHttpException {
String url = AGProtocol.getNamedCatalogsURL(serverURL);
TupleQueryResult tqresult = getHTTPClient().getTupleQueryResult(url);
List<String> result = new ArrayList<String>(5);
Expand All @@ -124,28 +125,31 @@ public List<String> listCatalogs() throws OpenRDFException {
Value id = bindingSet.getValue("id");
result.add(id.stringValue());
}
} finally {
tqresult.close();
}
} catch (QueryEvaluationException e) {
throw new AGHttpException(e);
}
return result;
}

/**
* Gets the catalog instance for a given catalog id.
*
* Returns the root catalog if the id is a root id.
* Returns the root catalog if the id is a root id. If
* the catalog Id is not found on the server, returns
* null.
*
* @param catalogID a catalog id.
* @return the corresponding catalog instance.
* @throws AGHttpException
*/
public AGCatalog getCatalog(String catalogID) {
AGCatalog catalog;
public AGCatalog getCatalog(String catalogID) throws AGHttpException {
if (AGCatalog.isRootID(catalogID)) {
catalog = getRootCatalog();
return rootCatalog;
} else if (listCatalogs().contains(catalogID)) {
return new AGCatalog(this, catalogID);
} else {
catalog = new AGCatalog(this, catalogID);
return null;
}
return catalog;
}

/**
Expand All @@ -157,6 +161,43 @@ public AGCatalog getCatalog() {
return rootCatalog;
}

/**
* Returns an AGCatalog instance for the given catalogID.
*
* If the catalog already exists on the server, an AGCatalog
* instance is simply returned. If the catalog does not exist,
* it is created if the server has been configured to allow
* <a href="http://www.franz.com/agraph/support/documentation/current/daemon-config.html#DynamicCatalogs">
* dynamic catalogs</a>; otherwise, an exception is thrown.
*
* @param catalogID the id (the name) of the catalog
* @return an AGCatalog instance.
* @throws AGHttpException
*/
public AGCatalog createCatalog(String catalogID) throws AGHttpException {
AGCatalog catalog = getCatalog(catalogID);
if (catalog==null) {
String catalogURL = AGProtocol.getNamedCatalogLocation(getServerURL(), catalogID);
getHTTPClient().putCatalog(catalogURL);
catalog = new AGCatalog(this, catalogID);
}
return catalog;
}

/**
* Deletes any catalog with the given repository id.
*
* This method only applies to dynamically created catalogs.
*
* @param catalogID the name of the catalog to delete.
* @throws AGHttpException
*/
public void deleteCatalog(String catalogID) throws AGHttpException {
String catalogURL = AGProtocol.getNamedCatalogLocation(getServerURL(),
catalogID);
getHTTPClient().deleteCatalog(catalogURL);
}

/**
* Creates a virtual repository with the given store specification.
* <p>
Expand Down
59 changes: 59 additions & 0 deletions src/test/DynamicCatalogTests.java
@@ -0,0 +1,59 @@
/******************************************************************************
** Copyright (c) 2008-2010 Franz 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
******************************************************************************/

package test;

import junit.framework.Assert;

import org.junit.Test;
import org.junit.experimental.categories.Category;

import com.franz.agraph.http.exception.AGHttpException;
import com.franz.agraph.repository.AGCatalog;

public class DynamicCatalogTests extends AGAbstractTest {

@Test
@Category(TestSuites.Prepush.class)
public void dynamicCatalogs_rfe10175() throws Exception {
String catalogID = "dynamicCatalog1";
String repoID = "repo1";
AGCatalog catalog = server.createCatalog(catalogID);
Assert.assertNotNull("missing the expected catalog", server.getCatalog(catalogID));
// should be ok to create an existing catalog
int numCatalogs = server.listCatalogs().size();
catalog = server.createCatalog(catalogID);
Assert.assertEquals("expected no change in catalogs", numCatalogs, server.listCatalogs().size());
catalog.createRepository(repoID);
Assert.assertTrue("expected repository", catalog.hasRepository(repoID));
server.deleteCatalog(catalogID);
Assert.assertNull("expected catalog to be deleted", server.getCatalog(catalogID));
try {
// catalog object shouldn't work either
catalog.hasRepository(repoID);
Assert.fail("expected catalog not found exception.");
} catch (AGHttpException e) {
// TODO: want a subclass of AGHttpException here?
}
// should be ok to delete a non-existent catalog
numCatalogs = server.listCatalogs().size();
server.deleteCatalog(catalogID);
Assert.assertEquals("expected no change in catalogs", numCatalogs, server.listCatalogs().size());
server.createCatalog(catalogID);
// catalog object now works again (allow that for now. TODO: reconsider?)
// When a catalog is deleted, repositories aren't accessible from the catalog
// TODO: check that repositories are also deleted from disk?
Assert.assertTrue("Expected no repositories in catalog.",!catalog.hasRepository(repoID));
server.deleteCatalog(catalogID);
Assert.assertNull("expected catalog to be deleted", server.getCatalog(catalogID));
// TODO confirm that these are indeed harmless
server.deleteCatalog("/");
server.deleteCatalog("blahdiblah");
}

}
1 change: 1 addition & 0 deletions src/test/TestSuites.java
Expand Up @@ -75,6 +75,7 @@ public static class Temp {}
AGConnPoolSessionTest.class,
BlankNodeTests.class,
MappingsTests.class,
DynamicCatalogTests.class,
SpinTest.class
})
public static class Prepush {}
Expand Down

0 comments on commit cef0c0f

Please sign in to comment.