package com.rayo.storage.cassandra; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.apache.cassandra.thrift.Column; import org.apache.cassandra.thrift.ConsistencyLevel; import org.apache.cassandra.thrift.SlicePredicate; import org.apache.cassandra.thrift.SuperColumn; import org.apache.commons.lang.StringUtils; import org.scale7.cassandra.pelops.Bytes; import org.scale7.cassandra.pelops.Cluster; import org.scale7.cassandra.pelops.Mutator; import org.scale7.cassandra.pelops.Pelops; import org.scale7.cassandra.pelops.RowDeletor; import org.scale7.cassandra.pelops.Selector; import org.scale7.cassandra.pelops.exceptions.NotFoundException; import org.scale7.cassandra.pelops.exceptions.PelopsException; import com.rayo.server.storage.ApplicationAlreadyExistsException; import com.rayo.server.storage.ApplicationNotFoundException; import com.rayo.server.storage.DatastoreException; import com.rayo.server.storage.GatewayDatastore; import com.rayo.server.storage.RayoNodeAlreadyExistsException; import com.rayo.server.storage.RayoNodeNotFoundException; import com.rayo.server.storage.model.Application; import com.rayo.server.storage.model.GatewayCall; import com.rayo.server.storage.model.GatewayClient; import com.rayo.server.storage.model.GatewayMixer; import com.rayo.server.storage.model.GatewayVerb; import com.rayo.server.storage.model.RayoNode; import com.rayo.server.util.JIDUtils; import com.voxeo.logging.Loggerf; /** * <p>Cassandra based implementation of the {@link GatewayDatastore} interface.</p> * * <p>You can point this data store to any particular Cassandra installation by * just setting the hostname and port number properties. By default, this store * points to localhost/9160.</p> * * @author martin * */ public class CassandraDatastore implements GatewayDatastore { private final static Loggerf log = Loggerf.getLogger(CassandraDatastore.class); private String hostname = "localhost"; private String port = "9160"; private CassandraPrimer primer = null; private boolean overrideExistingSchema = true; private boolean primeTestData = false; private String schemaName = "rayo"; private CassandraSchemaHandler schemaHandler = new CassandraSchemaHandler(); public void init() throws Exception { log.debug("Initializing Cassandra Datastore on [%s:%s]", hostname, port); // Pelops throws an exception when no keyspaces are defined and automatic // discovery is turned on. So for the first check we disable auto discovery. Cluster cluster = new Cluster(hostname, Integer.parseInt(port), false); if (overrideExistingSchema || !schemaHandler.schemaExists(cluster, schemaName)) { // We will create the Cassandra schema if: // 1. The property that forces us to create a new schema is set, or // 2. The schema has not been created yet schemaHandler.buildSchema(cluster, schemaName); } else { // if the current schema is somehow screwed, try to fix it schemaHandler.buildSchema(cluster, schemaName, false); } // try to turn on auto-discovery cluster = new Cluster(hostname, Integer.parseInt(port), true); Pelops.addPool(schemaName, cluster, schemaName); if (primer != null) { if (primeTestData) { log.debug("Priming test data"); primer.prime(this); } else { log.debug("Test data will not be primed as per configuration settings"); } } } @Override public RayoNode storeNode(RayoNode node) throws DatastoreException { log.debug("Storing node: [%s]", node); RayoNode stored = getNode(node.getHostname()); if (stored != null) { log.error("Node [%s] already exists", node); throw new RayoNodeAlreadyExistsException(); } return store(node); } public RayoNode updateNode(RayoNode node) throws DatastoreException { log.debug("Updating node: [%s]", node); RayoNode stored = getNode(node.getHostname()); if (stored == null) { log.error("Node [%s] does not exist", node); throw new RayoNodeNotFoundException(); } return store(node); } private RayoNode store(RayoNode node) throws DatastoreException { Mutator mutator = Pelops.createMutator(schemaName); for (String platform: node.getPlatforms()) { mutator.writeSubColumns("nodes", platform, node.getHostname(), mutator.newColumnList( mutator.newColumn("priority", String.valueOf(node.getPriority())), mutator.newColumn("weight", String.valueOf(node.getWeight())), mutator.newColumn("ip", node.getIpAddress()), mutator.newColumn("consecutive-errors", String.valueOf(node.getConsecutiveErrors())), mutator.newColumn("blacklisted", String.valueOf(node.isBlackListed())) ) ); } mutator.writeColumn("ips", Bytes.fromUTF8(node.getIpAddress()), mutator.newColumn(Bytes.fromUTF8("node"), Bytes.fromUTF8(node.getHostname()))); try { mutator.execute(ConsistencyLevel.ONE); log.debug("Node [%s] stored successfully", node); } catch (Exception e) { log.error(e.getMessage(),e); throw new DatastoreException(String.format("Could not create node [%s]", node)); } return node; } @Override public RayoNode removeNode(String rayoNode) throws DatastoreException { log.debug("Removing node: [%s]", rayoNode); RayoNode node = getNode(rayoNode); if (node == null) { log.error("Node not found: [%s]", rayoNode); throw new RayoNodeNotFoundException(); } RowDeletor deletor = Pelops.createRowDeletor(schemaName); deletor.deleteRow("ips", node.getIpAddress(), ConsistencyLevel.ONE); Mutator mutator = Pelops.createMutator(schemaName); for (String platform: node.getPlatforms()) { mutator.deleteColumn("nodes", platform, rayoNode); } try { mutator.execute(ConsistencyLevel.ONE); log.debug("Node [%s] deleted successfully", rayoNode); } catch (Exception e) { log.error(e.getMessage(),e); throw new DatastoreException("Could not remove node"); } return node; } @Override public GatewayCall storeCall(GatewayCall call) throws DatastoreException { log.debug("Storing call: [%s]", call); RayoNode node = getNode(call.getNodeJid()); if (node == null) { log.debug("Node [%s] not found for call [%s]", call.getNodeJid(), call); throw new RayoNodeNotFoundException(); } Mutator mutator = Pelops.createMutator(schemaName); mutator.writeColumns("calls", Bytes.fromUTF8(call.getCallId()), mutator.newColumnList( mutator.newColumn(Bytes.fromUTF8("jid"), Bytes.fromUTF8(call.getClientJid())), mutator.newColumn(Bytes.fromUTF8("node"), Bytes.fromUTF8(call.getNodeJid())))); mutator.writeSubColumn("jids", "clients", Bytes.fromUTF8(call.getClientJid()), mutator.newColumn(Bytes.fromUTF8(call.getCallId()), Bytes.fromUTF8(call.getCallId()))); mutator.writeSubColumn("jids", "nodes", Bytes.fromUTF8(call.getNodeJid()), mutator.newColumn(Bytes.fromUTF8(call.getCallId()), Bytes.fromUTF8(call.getCallId()))); try { mutator.execute(ConsistencyLevel.ONE); log.debug("Call [%s] stored successfully", call); } catch (Exception e) { log.error(e.getMessage(),e); throw new DatastoreException("Could not store call"); } return call; } @Override public GatewayCall getCall(String id) { log.debug("Getting call with id [%s]", id); Selector selector = Pelops.createSelector(schemaName); try { List<Column> columns = selector.getColumnsFromRow("calls", id, false, ConsistencyLevel.ONE); return buildCall(columns, id); } catch (PelopsException pe) { log.error(pe.getMessage(),pe); return null; } } private GatewayCall buildCall(List<Column> columns, String id) { if (columns != null && columns.size() > 0) { GatewayCall call = new GatewayCall(); call.setCallId(id); for(Column column: columns) { String name = Bytes.toUTF8(column.getName()); if (name.equals("node")) { call.setNodeJid(Bytes.toUTF8(column.getValue())); } if (name.equals("jid")) { call.setClientJid(Bytes.toUTF8(column.getValue())); } } return call; } return null; } @Override public GatewayCall removeCall(String id) throws DatastoreException { log.debug("Removing call with id: [%s]", id); GatewayCall call = getCall(id); if (call != null) { Mutator mutator = Pelops.createMutator(schemaName); mutator.deleteSubColumns("jids", "clients", call.getClientJid(), id); mutator.deleteSubColumns("jids", "nodes", call.getNodeJid(), id); try { RowDeletor deletor = Pelops.createRowDeletor(schemaName); deletor.deleteRow("calls", Bytes.fromUTF8(id), ConsistencyLevel.ONE); mutator.execute(ConsistencyLevel.ONE); log.debug("Call [%s] removed successfully", id); } catch (Exception e) { log.error(e.getMessage(),e); throw new DatastoreException("Could not remove call"); } } return call; } @SuppressWarnings("unchecked") private Collection<String> getCalls(String jid, String type) { try { Selector selector = Pelops.createSelector(schemaName); List<Column> columns = selector.getSubColumnsFromRow("jids", type, jid, false, ConsistencyLevel.ONE); List<String> calls = new ArrayList<String>(); for(Column column: columns) { calls.add(Bytes.toUTF8(column.getValue())); } return calls; } catch (PelopsException pe) { log.error(pe.getMessage(),pe); return Collections.EMPTY_LIST; } } @Override public Collection<String> getCalls() { log.debug("Getting list with all active calls"); try { Selector selector = Pelops.createSelector(schemaName); List<String> calls = new ArrayList<String>(); List<SuperColumn> cols = selector.getSuperColumnsFromRow("jids", "nodes", false, ConsistencyLevel.ONE); for(SuperColumn col: cols) { List<Column> columns = col.getColumns(); for(Column column: columns) { calls.add(Bytes.toUTF8(column.getValue())); } } return calls; } catch (PelopsException pe) { log.error(pe.getMessage(),pe); return null; } } @Override public Collection<String> getCallsForNode(String rayoNode) { log.debug("Finding calls for node: [%s]", rayoNode); return getCalls(rayoNode, "nodes"); } @Override public Collection<String> getCallsForClient(String jid) { log.debug("Finding calls for client: [%s]", jid); return getCalls(jid, "clients"); } @Override public RayoNode getNode(String rayoNode) { log.debug("Getting node with id: [%s]", rayoNode); RayoNode node = null; try { Selector selector = Pelops.createSelector(schemaName); Map<String, List<SuperColumn>> rows = selector.getSuperColumnsFromRowsUtf8Keys( "nodes", Selector.newKeyRange("", "", 100), // 100 platforms limit should be enough :) Selector.newColumnsPredicate(rayoNode), ConsistencyLevel.ONE); Iterator<Entry<String, List<SuperColumn>>> it = rows.entrySet().iterator(); while (it.hasNext()) { Entry<String, List<SuperColumn>> element = it.next(); String currPlatform = element.getKey(); List<SuperColumn> platformOccurrences= element.getValue(); for (SuperColumn column: platformOccurrences) { if (node == null) { node = new RayoNode(); node = buildNode(column.getColumns()); node.setHostname(rayoNode); } node.addPlatform(currPlatform); } } } catch (PelopsException pe) { log.error(pe.getMessage(),pe); return null; } return node; } @Override public String getNodeForCall(String callId) { log.debug("Finding node for call: [%s]", callId); GatewayCall call = getCall(callId); if (call != null) { return call.getNodeJid(); } return null; } @Override public String getNodeForIpAddress(String ip) { try { log.debug("Finding node for IP address: [%s]", ip); Selector selector = Pelops.createSelector(schemaName); Column column = selector.getColumnFromRow("ips", ip, "node", ConsistencyLevel.ONE); if (column != null) { return Bytes.toUTF8(column.getValue()); } } catch (NotFoundException nfe) { log.debug("No node found for ip address: [%s]", ip); return null; } catch (PelopsException pe) { log.error(pe.getMessage(),pe); } return null; } @Override public List<String> getPlatforms() { log.debug("Returning list with all available platforms"); return getAllRowNames("nodes",0,false); } @SuppressWarnings("unchecked") public List<RayoNode> getRayoNodesForPlatform(String platformId) { try { log.debug("Finding rayo nodes for platform: [%s]", platformId); Set<String> platforms = new HashSet<String>(); platforms.add(platformId); List<RayoNode> nodes = new ArrayList<RayoNode>(); Selector selector = Pelops.createSelector(schemaName); List<SuperColumn> columns = selector.getSuperColumnsFromRow("nodes", platformId, false, ConsistencyLevel.ONE); for(SuperColumn column: columns) { String id = Bytes.toUTF8(column.getName()); RayoNode rayoNode = buildNode(column.getColumns()); rayoNode.setHostname(id); rayoNode.setPlatforms(platforms); nodes.add(rayoNode); } return nodes; } catch (PelopsException pe) { log.error(pe.getMessage(),pe); return Collections.EMPTY_LIST; } } @Override public Application storeApplication(Application application) throws DatastoreException { log.debug("Storing application: [%s]", application); if (getApplication(application.getBareJid()) != null) { log.error("Application [%s] already exists", application); throw new ApplicationAlreadyExistsException(); } return saveApplication(application); } @Override public Application updateApplication(Application application) throws DatastoreException { log.debug("Updating application: [%s]", application); if (getApplication(application.getBareJid()) == null) { log.error("Application [%s] does not exist", application); throw new ApplicationNotFoundException(); } return saveApplication(application); } private Application saveApplication(Application application) throws DatastoreException { Mutator mutator = Pelops.createMutator(schemaName); mutator.writeColumns("applications", application.getBareJid(), mutator.newColumnList( mutator.newColumn(Bytes.fromUTF8("appId"), Bytes.fromUTF8(application.getAppId())), mutator.newColumn(Bytes.fromUTF8("platformId"), Bytes.fromUTF8(application.getPlatform())), mutator.newColumn(Bytes.fromUTF8("name"), Bytes.fromUTF8(application.getName())), mutator.newColumn(Bytes.fromUTF8("accountId"), Bytes.fromUTF8(application.getAccountId())), mutator.newColumn(Bytes.fromUTF8("permissions"), Bytes.fromUTF8(application.getPermissions())))); try { mutator.execute(ConsistencyLevel.ONE); log.debug("Application [%s] stored successfully", application); } catch (Exception e) { log.error(e.getMessage(),e); throw new DatastoreException(String.format("Could not create application [%s]", application)); } return application; } private void populateApplicationData(Application application, List<Column> columns) { for (Column column: columns) { String name = Bytes.toUTF8(column.getName()); if (name.equals("appId")) { application.setAppId(Bytes.toUTF8((column.getValue()))); } if (name.equals("platformId")) { application.setPlatform(Bytes.toUTF8((column.getValue()))); } if (name.equals("name")) { application.setName(Bytes.toUTF8((column.getValue()))); } if (name.equals("accountId")) { application.setAccountId(Bytes.toUTF8((column.getValue()))); } if (name.equals("permissions")) { application.setPermissions(Bytes.toUTF8((column.getValue()))); } } } @Override public Application getApplication(String jid) { if (jid == null) return null; log.debug("Finding application with jid: [%s]", jid); Application application = null; Selector selector = Pelops.createSelector(schemaName); List<Column> columns = selector.getColumnsFromRow("applications", jid, false, ConsistencyLevel.ONE); if (columns.size() > 0) { application = new Application(jid); populateApplicationData(application, columns); } return application; } @SuppressWarnings("unchecked") @Override public List<Application> getApplications() { try { log.debug("Finding all applications"); List<Application> applications = new ArrayList<Application>(); Selector selector = Pelops.createSelector(schemaName); LinkedHashMap<Bytes, List<Column>> rows = selector.getColumnsFromRows( "applications", Selector.newKeyRange("", "", 10000), // 10000 applications limite, false, ConsistencyLevel.ONE); for(Map.Entry<Bytes, List<Column>> row: rows.entrySet()) { if (row.getValue().size() > 0) { Application application = new Application(row.getKey().toUTF8()); populateApplicationData(application, row.getValue()); applications.add(application); } } return applications; } catch (PelopsException pe) { log.error(pe.getMessage(),pe); return Collections.EMPTY_LIST; } } @Override public Application removeApplication(String jid) throws DatastoreException { log.debug("Removing application with id: [%s]", jid); Application application = getApplication(jid); if (application != null) { RowDeletor deletor = Pelops.createRowDeletor(schemaName); deletor.deleteRow("applications", jid, ConsistencyLevel.ONE); List<String> addresses = getAddressesForApplication(jid); removeAddresses(addresses); } else { log.debug("No application found with jid: [%s]", jid); throw new ApplicationNotFoundException(); } return application; } @Override public List<String> getAddressesForApplication(String jid) { log.debug("Finding addresses for application jid: [%s]", jid); return getAllRowNames("addresses", 1, true, jid); } @Override public Application getApplicationForAddress(String address) { log.debug("Finding application for address: [%s]", address); Selector selector = Pelops.createSelector(schemaName); List<Column> columns = selector.getColumnsFromRow("addresses", address, false, ConsistencyLevel.ONE); if (columns != null && columns.size() > 0) { Column column = columns.get(0); return getApplication(Bytes.toUTF8(column.getValue())); } log.debug("No application found for address: [%s]", address); return null; } @Override public void storeAddress(String address, String appId) throws DatastoreException { ArrayList<String> addresses = new ArrayList<String>(); addresses.add(address); storeAddresses(addresses, appId); } @Override public void storeAddresses(Collection<String> addresses, String jid) throws DatastoreException { log.debug("Storing addresses [%s] on application [%s]", addresses, jid); if (getApplication(jid) == null) { throw new ApplicationNotFoundException(); } Mutator mutator = Pelops.createMutator(schemaName); for (String address: addresses) { mutator.writeColumn("addresses", Bytes.fromUTF8(address), mutator.newColumn(jid, jid)); } try { mutator.execute(ConsistencyLevel.ONE); log.debug("Addresses [%s] stored successfully on application [%s]", addresses, jid); } catch (Exception e) { log.error(e.getMessage(),e); throw new DatastoreException(String.format("Could not add addresses [%s] to application [%s]", addresses, jid)); } } @Override public void removeAddress(String address) throws DatastoreException { Application application = getApplicationForAddress(address); if (application != null) { List<String> addresses = new ArrayList<String>(); addresses.add(address); removeAddresses(addresses); } } private void removeAddresses(List<String> addresses) throws DatastoreException { log.debug("Removing addresses [%s]", addresses); RowDeletor deletor = Pelops.createRowDeletor(schemaName); for (String address: addresses) { deletor.deleteRow("addresses", address, ConsistencyLevel.ONE); } } @Override public GatewayClient storeClient(GatewayClient client) throws DatastoreException { log.debug("Storing client: [%s]", client); Application application = getApplication(client.getBareJid()); if (application == null) { log.debug("Client [%s] already exists", client); throw new ApplicationNotFoundException(); } Mutator mutator = Pelops.createMutator(schemaName); mutator.writeColumns("clients", client.getBareJid(), mutator.newColumnList( mutator.newColumn(client.getResource(), client.getResource()))); try { mutator.execute(ConsistencyLevel.ONE); log.debug("Client [%s] stored successfully", client); } catch (Exception e) { log.error(e.getMessage(),e); throw new DatastoreException(String.format("Could not create client application [%s]", client)); } return client; } @Override public GatewayClient removeClient(String jid) throws DatastoreException { log.debug("Removing client with jid: [%s]", jid); GatewayClient client = getClient(jid); if (client != null) { Mutator mutator = Pelops.createMutator(schemaName); String bareJid = JIDUtils.getBareJid(jid); String resource = JIDUtils.getResource(jid); mutator.deleteColumn("clients", bareJid, resource); mutator.execute(ConsistencyLevel.ONE); List<String> resources = getClientResources(bareJid); if (resources.size() == 0) { RowDeletor deletor = Pelops.createRowDeletor(schemaName); deletor.deleteRow("clients", bareJid, ConsistencyLevel.ONE); } log.debug("Client with jid: [%s] removed successfully", jid); } return client; } @Override public GatewayClient getClient(String jid) { log.debug("Finding client with jid: [%s]", jid); GatewayClient client = null; try { String bareJid = JIDUtils.getBareJid(jid); String resource = JIDUtils.getResource(jid); boolean resourceFound = false; Selector selector = Pelops.createSelector(schemaName); List<Column> columns = selector.getColumnsFromRow("clients", bareJid, false, ConsistencyLevel.ONE); if (columns != null && columns.size() > 0) { for(Column column: columns) { String name = Bytes.toUTF8(column.getName()); if (name.equals(resource)) { resourceFound = true; } } } if (resourceFound) { Application application = getApplication(JIDUtils.getBareJid(jid)); if (application != null) { client = new GatewayClient(); client.setJid(jid); client.setPlatform(application.getPlatform()); } } } catch (PelopsException pe) { log.error(pe.getMessage(),pe); } return client; } @SuppressWarnings("unchecked") @Override public List<String> getClientResources(String bareJid) { try { log.debug("Finding resources for clients with jid: [%s]", bareJid); Selector selector = Pelops.createSelector(schemaName); List<Column> resourceColumn = selector.getColumnsFromRow("clients", bareJid, false, ConsistencyLevel.ONE); List<String> resources = new ArrayList<String>(); for(Column column: resourceColumn) { String name = Bytes.toUTF8(column.getName()); if (!name.equals("appId")) { resources.add(Bytes.toUTF8(column.getName())); } } return resources; } catch (PelopsException pe) { log.error(pe.getMessage(),pe); return Collections.EMPTY_LIST; } } private RayoNode buildNode(List<Column> columns) { if (columns != null && columns.size() > 0) { RayoNode node = new RayoNode(); for(Column column: columns) { String name = Bytes.toUTF8(column.getName()); if (name.equals("ip")) { node.setIpAddress(Bytes.toUTF8(column.getValue())); } if (name.equals("weight")) { node.setWeight(Integer.parseInt(Bytes.toUTF8(column.getValue()))); } if (name.equals("priority")) { node.setPriority(Integer.parseInt(Bytes.toUTF8(column.getValue()))); } if (name.equals("consecutive-errors")) { node.setConsecutiveErrors(Integer.parseInt(Bytes.toUTF8(column.getValue()))); } if (name.equals("blacklisted")) { node.setBlackListed(Boolean.valueOf(Bytes.toUTF8(column.getValue()))); } if (name.equals("platforms")) { node.setPlatforms(new HashSet<String>(Arrays.asList(StringUtils.split(Bytes.toUTF8(column.getValue()),",")))); } } return node; } return null; } @Override public List<String> getClients() { log.debug("Returning all clients"); return getAllRowNames("clients", 1, true); } private List<String> getAllRowNames(String columnFamily, int numColumns, boolean excludeIfLessColumns) { return getAllRowNames(columnFamily, numColumns, excludeIfLessColumns, null); } private List<String> getAllRowNames(String columnFamily, int numColumns, boolean excludeIfLessColumns, String colName) { List<String> result = new ArrayList<String>(); try { Selector selector = Pelops.createSelector(schemaName); final int PAGE_SIZE = 100; String currRow = ""; while (true) { SlicePredicate predicate = null; if (colName == null) { predicate = Selector.newColumnsPredicateAll(false, numColumns); } else { predicate = Selector.newColumnsPredicate(colName,colName,false,numColumns); } Map<String, List<Column>> rows = selector.getColumnsFromRowsUtf8Keys( columnFamily, Selector.newKeyRange(currRow, "", PAGE_SIZE), predicate, ConsistencyLevel.ONE); Iterator<Entry<String, List<Column>>> it = rows.entrySet().iterator(); while (it.hasNext()) { Entry<String, List<Column>> element = it.next(); if (excludeIfLessColumns && element.getValue().size() < numColumns) { continue; } currRow = element.getKey(); if (!result.contains(currRow)) { result.add(currRow); } } if (rows.keySet().size() < PAGE_SIZE) break; } } catch (PelopsException pe) { log.error(pe.getMessage(),pe); } return result; } @Override public GatewayMixer storeMixer(GatewayMixer mixer) throws DatastoreException { log.debug("Storing mixer: [%s]", mixer); Mutator mutator = Pelops.createMutator(schemaName); mutator.writeColumns("mixers", Bytes.fromUTF8(mixer.getName()), mutator.newColumnList( mutator.newColumn(Bytes.fromUTF8("node"), Bytes.fromUTF8(mixer.getNodeJid())))); try { mutator.execute(ConsistencyLevel.ONE); log.debug("Mixer [%s] stored successfully", mixer); } catch (Exception e) { log.error(e.getMessage(),e); throw new DatastoreException("Could not store mixer"); } return mixer; } @Override public GatewayMixer getMixer(String name) { log.debug("Getting mixer with name [%s]", name); Selector selector = Pelops.createSelector(schemaName); try { List<Column> columns = selector.getColumnsFromRow("mixers", name, false, ConsistencyLevel.ONE); return buildMixer(columns, name); } catch (PelopsException pe) { log.error(pe.getMessage(),pe); return null; } } @SuppressWarnings("unchecked") @Override public Collection<GatewayMixer> getMixers() { log.debug("Getting list with all active mixers"); try { List<GatewayMixer> mixers = new ArrayList<GatewayMixer>(); Selector selector = Pelops.createSelector(schemaName); LinkedHashMap<Bytes, List<Column>> rows = selector.getColumnsFromRows( "mixers", Selector.newKeyRange("", "", 10000), // 10000 mixers limit, false, ConsistencyLevel.ONE); for(Map.Entry<Bytes, List<Column>> row: rows.entrySet()) { if (row.getValue().size() > 0) { mixers.add(buildMixer(row.getValue(), row.getKey().toUTF8())); } } return mixers; } catch (PelopsException pe) { log.error(pe.getMessage(),pe); return Collections.EMPTY_LIST; } } private GatewayMixer buildMixer(List<Column> columns, String name) { String nodeJid = null; List<String> participants = new ArrayList<String>(); if (columns != null && columns.size() > 0) { for(Column column: columns) { String columnName = Bytes.toUTF8(column.getName()); if (columnName.equals("node")) { nodeJid = Bytes.toUTF8(column.getValue()); } else { participants.add(Bytes.toUTF8(column.getName())); } } if (nodeJid != null) { GatewayMixer mixer = new GatewayMixer(name, nodeJid); mixer.addCalls(participants); return mixer; } } return null; } @Override public GatewayMixer removeMixer(String name) throws DatastoreException { log.debug("Removing mixer with name: [%s]", name); GatewayMixer mixer = getMixer(name); Mutator mutator = Pelops.createMutator(schemaName); try { RowDeletor deletor = Pelops.createRowDeletor(schemaName); deletor.deleteRow("mixers", Bytes.fromUTF8(name), ConsistencyLevel.ONE); mutator.execute(ConsistencyLevel.ONE); log.debug("Mixer [%s] removed successfully", mixer); } catch (Exception e) { log.error(e.getMessage(),e); throw new DatastoreException("Could not remove mixer"); } return mixer; } @Override public void addCallToMixer(String callId, String mixerName) throws DatastoreException { log.debug("Adding call [%s] to mixer [%s]", callId, mixerName); Mutator mutator = Pelops.createMutator(schemaName); mutator.writeColumns("mixers", Bytes.fromUTF8(mixerName), mutator.newColumnList( mutator.newColumn(Bytes.fromUTF8(callId), Bytes.fromUTF8(callId)))); try { mutator.execute(ConsistencyLevel.ONE); log.debug("Call [%s] added successfully to mixer [%s]", callId, mixerName); } catch (Exception e) { log.error(e.getMessage(),e); throw new DatastoreException("Could not add call to mixer"); } } @Override public void removeCallFromMixer(String callId, String mixerName) throws DatastoreException { log.debug("Removing call [%s] from mixer [%s]", callId, mixerName); Mutator mutator = Pelops.createMutator(schemaName); mutator.deleteColumn("mixers", mixerName, callId); try { mutator.execute(ConsistencyLevel.ONE); log.debug("Call [%s] removed successfully from mixer [%s]", callId, mixerName); } catch (Exception e) { log.error(e.getMessage(),e); throw new DatastoreException("Could not remove call from mixer"); } } @Override public void removeVerbFromMixer(String verbId, String mixerName) throws DatastoreException { log.debug("Removing verb [%s] from mixer [%s]", verbId, mixerName); Mutator mutator = Pelops.createMutator(schemaName); mutator.deleteColumn("verbs", mixerName, verbId); try { mutator.execute(ConsistencyLevel.ONE); log.debug("Verb [%s] removed successfully from mixer [%s]", verbId, mixerName); } catch (Exception e) { log.error(e.getMessage(),e); throw new DatastoreException("Could not remove verb from mixer"); } } @SuppressWarnings("unchecked") @Override public List<GatewayVerb> getVerbs(String mixerName) { log.debug("Getting the list of active verbs for mixer [%s]", mixerName); List<GatewayVerb> ids = new ArrayList<GatewayVerb>(); Selector selector = Pelops.createSelector(schemaName); try { List<Column> columns = selector.getColumnsFromRow("verbs", mixerName, false, ConsistencyLevel.ONE); for (Column column: columns) { GatewayVerb verb = new GatewayVerb( mixerName, Bytes.toUTF8(column.getName()), Bytes.toUTF8(column.getValue())); ids.add(verb); } } catch (Exception e) { log.error(e.getMessage(),e); return Collections.EMPTY_LIST; } return ids; } @SuppressWarnings("unchecked") @Override public List<GatewayVerb> getVerbs() { log.debug("Getting list with all active verb"); try { List<GatewayVerb> verbs = new ArrayList<GatewayVerb>(); Selector selector = Pelops.createSelector(schemaName); LinkedHashMap<Bytes, List<Column>> rows = selector.getColumnsFromRows( "verbs", Selector.newKeyRange("", "", 10000), // 10000 mixers limit, false, ConsistencyLevel.ONE); for(Map.Entry<Bytes, List<Column>> row: rows.entrySet()) { if (row.getValue().size() > 0) { for (Column column: row.getValue()) { GatewayVerb verb = new GatewayVerb( row.getKey().toUTF8(), Bytes.toUTF8(column.getName()), Bytes.toUTF8(column.getValue())); verbs.add(verb); } } } return verbs; } catch (PelopsException pe) { log.error(pe.getMessage(),pe); return Collections.EMPTY_LIST; } } @Override public GatewayVerb getVerb(String mixerName, String id) { log.debug("Getting the verb [%s] from mixer [%s]", id, mixerName); Selector selector = Pelops.createSelector(schemaName); try { List<Column> columns = selector.getColumnsFromRow("verbs", mixerName, false, ConsistencyLevel.ONE); for (Column column: columns) { if (Bytes.toUTF8(column.getName()).equals(id)) { return new GatewayVerb(mixerName, id, Bytes.toUTF8(column.getValue())); } } } catch (Exception e) { log.error(e.getMessage(),e); } return null; } @Override public void addVerbToMixer(GatewayVerb verb, String mixerName) throws DatastoreException { log.debug("Adding verb [%s] to mixer [%s]", verb.getVerbId(), mixerName); Mutator mutator = Pelops.createMutator(schemaName); mutator.writeColumns("verbs", Bytes.fromUTF8(mixerName), mutator.newColumnList( mutator.newColumn(Bytes.fromUTF8(verb.getVerbId()), Bytes.fromUTF8(verb.getAppJid())))); try { mutator.execute(ConsistencyLevel.ONE); log.debug("Verb [%s] added successfully to mixer [%s]", verb.getVerbId(), mixerName); } catch (Exception e) { log.error(e.getMessage(),e); throw new DatastoreException("Could not add verb to mixer"); } } @Override public void createFilter(String jid, String id) throws DatastoreException { log.debug("Filering id [%s] for app [%s]", id, jid); Mutator mutator = Pelops.createMutator(schemaName); mutator.writeColumns("filters", Bytes.fromUTF8(id), mutator.newColumnList( mutator.newColumn(Bytes.fromUTF8(jid), Bytes.fromUTF8(jid)))); try { mutator.execute(ConsistencyLevel.ONE); log.debug("Id [%s] has been filtered for app [%s]", id, jid); } catch (Exception e) { log.error(e.getMessage(),e); throw new DatastoreException("Could not create new filter"); } } @Override public void removeFilter(String jid, String id) throws DatastoreException { log.debug("Unfiltering id [%s] for app [%s]", id, jid); Mutator mutator = Pelops.createMutator(schemaName); mutator.deleteColumn("filters", id, jid); try { mutator.execute(ConsistencyLevel.ONE); log.debug("Id [%s] has been removed from the filters of application [%s]", id, jid); } catch (Exception e) { log.error(e.getMessage(),e); throw new DatastoreException("Could not remove filter"); } } @Override public void removeFilters(String id) throws DatastoreException { log.debug("Removing all filters for id [%s]", id); try { RowDeletor deletor = Pelops.createRowDeletor(schemaName); deletor.deleteRow("filters", id, ConsistencyLevel.ONE); log.debug("Filters removed successfully for id [%s]", id); } catch (Exception e) { log.error(e.getMessage(),e); throw new DatastoreException("Could not remove filters"); } } @Override public List<String> getFilteredApplications(String id) throws DatastoreException { log.debug("Getting the list of filtered jids for id [%s]", id); List<String> ids = new ArrayList<String>(); Selector selector = Pelops.createSelector(schemaName); try { List<Column> columns = selector.getColumnsFromRow("filters", id, false, ConsistencyLevel.ONE); for (Column column: columns) { ids.add(Bytes.toUTF8(column.getName())); } } catch (Exception e) { log.error(e.getMessage(),e); return Collections.EMPTY_LIST; } return ids; } /** * Gets the domain that Cassandra is running on * * @return String Cassandra domain */ public String getHostname() { return hostname; } /** * Sets the domain that Cassandra is running on * * @param hostname Cassandra domain */ public void setHostname(String hostname) { this.hostname = hostname; } /** * Gets the port that Cassandra is running on * * @return int Cassandra port */ public String getPort() { return port; } /** * Sets the port Cassandra is running on * * @param port Cassandra port */ public void setPort(String port) { this.port = port; } /** * Tells is schema is going to be overriding on startup or not * * @return boolean Override schema */ public boolean isOverrideExistingSchema() { return overrideExistingSchema; } /** * <p>Sets whether the current Cassandra schema should be overriden after startup * or not. If <code>true</code> this Cassandra Datastore will drop the existing * schema and will create a new one on initialization. If <code>false</code> then * the Datastore will try to use the existing schema.</p> * * @param overrideExistingSchema */ public void setOverrideExistingSchema(boolean overrideExistingSchema) { this.overrideExistingSchema = overrideExistingSchema; } public void setSchemaName(String schemaName) { this.schemaName = schemaName; } public CassandraSchemaHandler getSchemaHandler() { return schemaHandler; } public void setSchemaHandler(CassandraSchemaHandler schemaHandler) { this.schemaHandler = schemaHandler; } public void setPrimer(CassandraPrimer primer) { this.primer = primer; } public boolean isPrimeTestData() { return primeTestData; } public void setPrimeTestData(boolean primeTestData) { this.primeTestData = primeTestData; } }