Navigation Menu

Skip to content

Commit

Permalink
Merge pull request #169 from stalehd/consolidate_interface
Browse files Browse the repository at this point in the history
Simplify core interface
  • Loading branch information
stalehd committed Jan 20, 2016
2 parents f332408 + 0497f45 commit 61fd8d5
Show file tree
Hide file tree
Showing 18 changed files with 584 additions and 644 deletions.
6 changes: 4 additions & 2 deletions a3/src/main/java/org/cloudname/a3/A3Client.java
Expand Up @@ -77,8 +77,9 @@ private void ensureOpened() {
*
* @param in an InputStream which contains valid JSON user database.
* @return an A3Client instance backed by MemoryStorage
* @deprecated does not specify how to convert bytes to
* characters, use a Reader instead of InputStream.
* @deprecated does not specify how to convert bytes to characters, use a Reader instead of
* InputStream.
* @throws IOException if there's an error reading from the memory storage
*/
public static A3Client newMemoryOnlyClient(InputStream in) throws IOException {
return new A3Client(MemoryStorage.fromInputStream(in));
Expand All @@ -90,6 +91,7 @@ public static A3Client newMemoryOnlyClient(InputStream in) throws IOException {
*
* @param in a Reader which contains a valid JSON user database.
* @return an A3Client instance backed by MemoryStorage
* @throws IOException if there's an error reading from the storage
*/
public static A3Client newMemoryOnlyClient(Reader in) throws IOException {
return new A3Client(MemoryStorage.fromReader(in));
Expand Down
Expand Up @@ -103,8 +103,8 @@ public String getPathPrefix(String namespace, boolean includeInstance) {
/**
* Get the path prefix for a Service coordinate.
*
* @param namespace {@see getPathPrefix(String,boolean)}
* @return
* @param namespace THe namespace for the path prefix
* @return a ZooKeeper path prefix
*/
public String getPathPrefix(String namespace) {
return getPathPrefix(namespace, false);
Expand Down
17 changes: 14 additions & 3 deletions a3/src/main/java/org/cloudname/a3/domain/User.java
Expand Up @@ -45,7 +45,16 @@ public User() {
* This constructor is mainly used by Jackson in order to create
* instances of the User object from JSON.
*
* The Set<String> of roles should be lowercase role names.
* The Set[string] of roles should be lowercase role names.
*
* @param username user name
* @param password user's password
* @param oldPassword old password for user
* @param oldPasswordExpiry expiry date for old password
* @param realName User's real name
* @param email User's email
* @param roles User roles
* @param properties User properties
*/
@JsonCreator
public User(@JsonProperty("username") String username,
Expand Down Expand Up @@ -177,7 +186,9 @@ public String toJson() {
}

/**
* Create a User instance from a JSON string.
* @param json JSON String
* @return User instance from a JSON string.
* @throws IOException if there's an error reading from JSON
*/
public static User fromJson(String json) throws IOException {
final ObjectMapper mapper = new ObjectMapper();
Expand All @@ -189,4 +200,4 @@ public static User fromJson(String json) throws IOException {
public String toString() {
return toJson();
}
}
}
Expand Up @@ -31,12 +31,12 @@
* (the user might me trying to access a publicly available resource). However if
* the user is specified but the username or password is wrong then we let the user know.
*
* <h4>Dependencies</h4>
* <strong>Dependencies</strong>
* The filter expects an {@link A3Client} instance to be provided by Jersey. For that to work
* you need to have a @{@link javax.ws.rs.ext.Provider.Provider} creating it available somewhere where Jersey can
* you need to have a @{@link javax.ws.rs.ext.Provider} creating it available somewhere where Jersey can
* find it.
*
* <h4>Configuration</h4>
* <strong>Configuration</strong>
* <p>
* You need to configure Jersey to use this filter - set its init parameter
* <code>com.sun.jersey.spi.container.ContainerRequestFilters</code>
Expand Down
Expand Up @@ -4,6 +4,7 @@
import org.cloudname.core.CloudnamePath;
import org.cloudname.core.LeaseHandle;
import org.cloudname.core.LeaseListener;
import org.cloudname.core.LeaseType;

import java.util.Arrays;
import java.util.HashSet;
Expand All @@ -12,6 +13,7 @@
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Logger;

/**
* This is a basic implementation of a CloudName backend. It uses the KV store for all data since
Expand All @@ -22,6 +24,8 @@
* @author stalehd@gmail.com
*/
public class ConsulBackend implements CloudnameBackend {
private static final Logger LOG = Logger.getLogger(ConsulBackend.class.getName());

final Consul consul;

private static final int SESSION_TTL = 10;
Expand All @@ -31,8 +35,6 @@ public class ConsulBackend implements CloudnameBackend {
private final Map<LeaseListener, ConsulWatch> watches = new ConcurrentHashMap<>();
private static final char SEPARATOR = '/';
private static final String CN_PREFIX = "cn";
private static final String EPHEMERAL_PREFIX = "ephemeral";
private static final String PERMANENT_PREFIX = "permanent";

/**
* Convert a cloudname path to a session name.
Expand All @@ -42,17 +44,10 @@ private String pathToSession(final CloudnamePath path) {
}

/**
* Convert a cloudname path to an ephemeral KV key name.
* Convert a cloudname path to a KV key name.
*/
private String pathToEphemeralKv(final CloudnamePath path) {
return CN_PREFIX + SEPARATOR + EPHEMERAL_PREFIX + SEPARATOR + path.join(SEPARATOR);
}

/**
* Convert cloudname path to permanent KV key.
*/
private String pathToPermanentKv(final CloudnamePath path) {
return CN_PREFIX + SEPARATOR + PERMANENT_PREFIX + SEPARATOR + path.join(SEPARATOR);
private String pathToKv(final CloudnamePath path) {
return CN_PREFIX + SEPARATOR + SEPARATOR + path.join(SEPARATOR);
}

/**
Expand Down Expand Up @@ -102,8 +97,7 @@ private String getRandomInstanceId() {
}
}

@Override
public LeaseHandle createTemporaryLease(final CloudnamePath path, final String data) {
private LeaseHandle createTemporary(final CloudnamePath path, final String data) {
// Create session with TTL set to <something> and Behavior=delete. The session isn't
// used to uniquely identify the client but to create ephemeral values in the KV store.
final ConsulSession session
Expand All @@ -115,7 +109,7 @@ public LeaseHandle createTemporaryLease(final CloudnamePath path, final String d
while (!leaseAcquired) {
instancePath.set(new CloudnamePath(path, getRandomInstanceId()));
leaseAcquired = consul.writeSessionData(
pathToEphemeralKv(instancePath.get()), data, session.getId());
pathToKv(instancePath.get()), data, session.getId());
}

sessions.put(instancePath.get(), session);
Expand All @@ -124,12 +118,12 @@ public LeaseHandle createTemporaryLease(final CloudnamePath path, final String d

return new LeaseHandle() {
@Override
public boolean writeLeaseData(final String data) {
public boolean writeData(final String data) {
if (session.isClosed()) {
return false;
}
return consul.writeSessionData(
pathToEphemeralKv(instancePath.get()), data, session.getId());
pathToKv(instancePath.get()), data, session.getId());
}

@Override
Expand All @@ -150,82 +144,102 @@ public void close() throws Exception {
}

@Override
public boolean writeTemporaryLeaseData(final CloudnamePath path, final String data) {
public boolean writeLeaseData(final CloudnamePath path, final String data) {
final ConsulSession session = sessions.get(path);
if (session == null) {
return false;
}
return consul.writeSessionData(pathToEphemeralKv(path), data, session.getId());
return consul.writeSessionData(pathToKv(path), data, session.getId());
}

@Override
public String readTemporaryLeaseData(final CloudnamePath path) {
public String readLeaseData(final CloudnamePath path) {
if (path == null) {
return null;
}
return consul.readData(pathToEphemeralKv(path));
return consul.readData(pathToKv(path));
}

@Override
public void addTemporaryLeaseListener(
final CloudnamePath pathToWatch, final LeaseListener listener) {
final ConsulWatch watch = consul.createWatch(pathToEphemeralKv(pathToWatch));
watches.put(listener, watch);
watch.startWatching(new ConsulWatch.ConsulWatchListener() {
@Override
public void created(final String valueName, final String value) {
listener.leaseCreated(kvNameToCloudnamePath(valueName), value);
}

@Override
public void changed(final String valueName, final String value) {
listener.dataChanged(kvNameToCloudnamePath(valueName), value);
}
public LeaseHandle createLease(
final LeaseType type, final CloudnamePath path, final String data) {
switch (type) {
case PERMANENT:
if (consul.createPermanentData(pathToKv(path), data)) {
return new LeaseHandle() {
@Override
public boolean writeData(final String data) {
return writeLeaseData(path, data);
}

@Override
public CloudnamePath getLeasePath() {
return path;
}

@Override
public void close() throws Exception {
// nothing to do
}
};
}
return null;

@Override
public void removed(final String valueName) {
listener.leaseRemoved(kvNameToCloudnamePath(valueName));
}
});
}
case TEMPORARY:
return createTemporary(path, data);

@Override
public void removeTemporaryLeaseListener(final LeaseListener listener) {
// Remove watcher
final ConsulWatch watch = watches.get(listener);
if (watch != null) {
watch.stop();
default:
LOG.severe("Uknown lease type: " + type
+ " - don't know how to create that kind of lease"
+ " (path = " + path + ", data = " + data + ")");
return null;
}
}

@Override
public boolean createPermanantLease(final CloudnamePath path, final String data) {
return consul.createPermanentData(pathToPermanentKv(path), data);
}

@Override
public boolean removePermanentLease(final CloudnamePath path) {
final String consulPath = pathToPermanentKv(path);
public boolean removeLease(final CloudnamePath path) {
final String consulPath = pathToKv(path);
if (consul.readData(consulPath) == null) {
return false;
}
return consul.removePermanentData(consulPath);
}

@Override
public boolean writePermanentLeaseData(final CloudnamePath path, final String data) {
return consul.writePermanentData(pathToPermanentKv(path), data);
}
public void addLeaseListener(final CloudnamePath leaseToObserve, final LeaseListener listener) {
final ConsulWatch watch = consul.createWatch(pathToKv(leaseToObserve));
watches.put(listener, watch);
watch.startWatching(new ConsulWatch.ConsulWatchListener() {
@Override
public void created(final String valueName, final String value) {
final CloudnamePath path = kvNameToCloudnamePath(valueName);
if (path.equals(leaseToObserve)) {
listener.leaseCreated(path, value);
}
}

@Override
public String readPermanentLeaseData(final CloudnamePath path) {
return consul.readData(pathToPermanentKv(path));
@Override
public void changed(final String valueName, final String value) {
final CloudnamePath path = kvNameToCloudnamePath(valueName);
if (path.equals(leaseToObserve)) {
listener.dataChanged(path, value);
}
}

@Override
public void removed(final String valueName) {
final CloudnamePath path = kvNameToCloudnamePath(valueName);
if (path.equals(leaseToObserve)) {
listener.leaseRemoved(path);
}
}
});
}

@Override
public void addPermanentLeaseListener(
public void addLeaseCollectionListener(
final CloudnamePath pathToObserve, final LeaseListener listener) {
final ConsulWatch watch = consul.createWatch(pathToPermanentKv(pathToObserve));
final ConsulWatch watch = consul.createWatch(pathToKv(pathToObserve));
watches.put(listener, watch);
watch.startWatching(new ConsulWatch.ConsulWatchListener() {
@Override
Expand All @@ -246,7 +260,7 @@ public void removed(final String valueName) {
}

@Override
public void removePermanentLeaseListener(final LeaseListener listener) {
public void removeLeaseListener(final LeaseListener listener) {
final ConsulWatch watch = watches.get(listener);
if (watch != null) {
watch.stop();
Expand Down

0 comments on commit 61fd8d5

Please sign in to comment.