Author: ivol37 at gmail.com Date: Tue Jan 11 12:45:54 2011 New Revision: 591
Log: simple cassandra client gadget, useful for testing Added: sandbox/ivol/cassandra-gadget/ sandbox/ivol/cassandra-gadget/pom.xml sandbox/ivol/cassandra-gadget/src/ sandbox/ivol/cassandra-gadget/src/main/ sandbox/ivol/cassandra-gadget/src/main/java/ sandbox/ivol/cassandra-gadget/src/main/java/org/ sandbox/ivol/cassandra-gadget/src/main/java/org/amdatu/ sandbox/ivol/cassandra-gadget/src/main/java/org/amdatu/cassandra/ sandbox/ivol/cassandra-gadget/src/main/java/org/amdatu/cassandra/gadget/ sandbox/ivol/cassandra-gadget/src/main/java/org/amdatu/cassandra/gadget/osgi/ sandbox/ivol/cassandra-gadget/src/main/java/org/amdatu/cassandra/gadget/osgi/Activator.java sandbox/ivol/cassandra-gadget/src/main/java/org/amdatu/cassandra/gadget/service/ sandbox/ivol/cassandra-gadget/src/main/java/org/amdatu/cassandra/gadget/service/CassandraClientGadgetImpl.java sandbox/ivol/cassandra-gadget/src/main/resources/ sandbox/ivol/cassandra-gadget/src/main/resources/jsp/ sandbox/ivol/cassandra-gadget/src/main/resources/jsp/CassandraClientGadget.jsp sandbox/ivol/cassandra-gadget/src/main/resources/static/ sandbox/ivol/cassandra-gadget/src/main/resources/static/images/ sandbox/ivol/cassandra-gadget/src/main/resources/static/images/cassandra.jpeg (contents, props changed) Added: sandbox/ivol/cassandra-gadget/pom.xml ============================================================================== --- (empty file) +++ sandbox/ivol/cassandra-gadget/pom.xml Tue Jan 11 12:45:54 2011 @@ -0,0 +1,75 @@ +<?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/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.amdatu</groupId> + <artifactId>org.amdatu.cassandra</artifactId> + <version>0.1.0-SNAPSHOT</version> + </parent> + <groupId>org.amdatu.cassandra</groupId> + <artifactId>gadget</artifactId> + <packaging>bundle</packaging> + <name>Amdatu Cassandra - Client gadget</name> + <description>Provides a cassandra client gadget</description> + + <dependencies> + <dependency> + <groupId>org.amdatu.web</groupId> + <artifactId>httpcontext</artifactId> + <version>${platform.version}</version> + <scope>provided</scope> + <type>bundle</type> + </dependency> + <dependency> + <groupId>org.amdatu.cassandra</groupId> + <artifactId>application</artifactId> + <scope>provided</scope> + <type>bundle</type> + </dependency> + <dependency> + <groupId>org.amdatu.opensocial</groupId> + <artifactId>shindig</artifactId> + <scope>provided</scope> + <version>${platform.version}</version> + <type>bundle</type> + </dependency> + <dependency> + <groupId>org.amdatu.opensocial</groupId> + <artifactId>gadgetmanagement</artifactId> + <version>${platform.version}</version> + <scope>provided</scope> + <type>bundle</type> + </dependency> + <dependency> + <groupId>org.json</groupId> + <artifactId>json</artifactId> + <version>20090211</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.amdatu.web.rest</groupId> + <artifactId>jaxrs</artifactId> + <version>${platform.version}</version> + <scope>provided</scope> + <type>bundle</type> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <configuration> + <instructions> + <Bundle-Activator>org.amdatu.cassandra.gadget.osgi.Activator</Bundle-Activator> + <Bundle-SymbolicName>org.amdatu.cassandra.gadget</Bundle-SymbolicName> + <Embed-Dependency>*;scope=compile</Embed-Dependency> + <Embed-Transitive>true</Embed-Transitive> + </instructions> + </configuration> + </plugin> + </plugins> + </build> +</project> Added: sandbox/ivol/cassandra-gadget/src/main/java/org/amdatu/cassandra/gadget/osgi/Activator.java ============================================================================== --- (empty file) +++ sandbox/ivol/cassandra-gadget/src/main/java/org/amdatu/cassandra/gadget/osgi/Activator.java Tue Jan 11 12:45:54 2011 @@ -0,0 +1,53 @@ +/* + Copyright (C) 2010 Amdatu.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.amdatu.cassandra.gadget.osgi; + +import org.amdatu.cassandra.application.CassandraDaemonService; +import org.amdatu.cassandra.gadget.service.CassandraClientGadgetImpl; +import org.amdatu.opensocial.gadgetmanagement.GadgetManagement; +import org.amdatu.web.httpcontext.HttpContextServiceFactory; +import org.amdatu.web.httpcontext.ResourceProvider; +import org.apache.felix.dm.DependencyActivatorBase; +import org.apache.felix.dm.DependencyManager; +import org.osgi.framework.BundleContext; +import org.osgi.service.log.LogService; + +/** + * This is the OSGi activator for this gadget bundle. + * @author ivol + */ +public class Activator extends DependencyActivatorBase { + // The resource identifier for this bundle. Resources are only considered to be 'ours' when + // it is prefixed with this id + public final static String RESOURCE_ID = "gadget/cassandra"; + + @Override + public void init(BundleContext context, DependencyManager manager) throws Exception { + // Create the LoginServiceImpl which has dependencies with the Log service + // and HTTP service + manager.add(createComponent().setInterface(ResourceProvider.class.getName(), null) + .setImplementation(CassandraClientGadgetImpl.class) + .add(createServiceDependency().setService(LogService.class).setRequired(true)) + .add(createServiceDependency().setService(GadgetManagement.class).setRequired(true)) + .add(createServiceDependency().setService(HttpContextServiceFactory.class).setRequired(true)) + .add(createServiceDependency().setService(CassandraDaemonService.class).setRequired(true))); + } + + @Override + public void destroy(BundleContext arg0, DependencyManager arg1) throws Exception { + } +} Added: sandbox/ivol/cassandra-gadget/src/main/java/org/amdatu/cassandra/gadget/service/CassandraClientGadgetImpl.java ============================================================================== --- (empty file) +++ sandbox/ivol/cassandra-gadget/src/main/java/org/amdatu/cassandra/gadget/service/CassandraClientGadgetImpl.java Tue Jan 11 12:45:54 2011 @@ -0,0 +1,205 @@ +/* + Copyright (C) 2010 Amdatu.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package org.amdatu.cassandra.gadget.service; + +import java.io.UnsupportedEncodingException; +import java.net.URL; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; + +import org.amdatu.cassandra.application.CassandraDaemonService; +import org.amdatu.cassandra.gadget.osgi.Activator; +import org.amdatu.opensocial.gadgetmanagement.GadgetManagement; +import org.amdatu.opensocial.shindig.GadgetCategory; +import org.amdatu.opensocial.shindig.GadgetDefinition; +import org.amdatu.web.httpcontext.HttpContextServiceFactory; +import org.amdatu.web.httpcontext.ResourceProvider; +import org.apache.cassandra.thrift.ColumnParent; +import org.apache.cassandra.thrift.ConsistencyLevel; +import org.apache.cassandra.thrift.InvalidRequestException; +import org.apache.cassandra.thrift.KeyRange; +import org.apache.cassandra.thrift.KeySlice; +import org.apache.cassandra.thrift.NotFoundException; +import org.apache.cassandra.thrift.SlicePredicate; +import org.apache.cassandra.thrift.SliceRange; +import org.apache.cassandra.thrift.TimedOutException; +import org.apache.cassandra.thrift.UnavailableException; +import org.apache.cassandra.thrift.Cassandra.Iface; +import org.apache.felix.dm.Component; +import org.apache.thrift.TException; +import org.osgi.framework.BundleContext; +import org.osgi.service.log.LogService; + +/** + * This service provides the cassandra client gadget. + * @author ivol + */ + at Path("cassandra/client") +public class CassandraClientGadgetImpl implements ResourceProvider { + // Service dependencies, injected by the Felix dependency manager + private volatile LogService m_logService; + private volatile BundleContext m_bundleContext; + private volatile HttpContextServiceFactory m_httpContextServiceFactory; + private volatile GadgetManagement m_gadgetManagement; + + private volatile CassandraDaemonService m_daemon; + + // The private HTTP context service for this bundle + private Component m_httpContextComponent; + + /** + * The init() method is invoked by the Felix dependency manager. + */ + public void start() { + // Create our own http context service which registers static resources and JSPs automatically + m_httpContextComponent = m_httpContextServiceFactory.create(m_bundleContext, this); + + // Register the gadget with the Gadget management service. Note that we can do this as + // many times as we want, since the gadget URL is the unique identifier + String gadgetSpecUrl = "/" + Activator.RESOURCE_ID + "/jsp/CassandraClientGadget.jsp"; + GadgetDefinition gadgetDef = new GadgetDefinition(gadgetSpecUrl, GadgetCategory.AMDATU_PLATFORM, true); + gadgetDef.setRank(0); + m_gadgetManagement.addGadget(gadgetDef); + m_logService.log(LogService.LOG_INFO, "Cassandra client gadget registered on URL '" + gadgetSpecUrl + "'"); + + m_logService.log(LogService.LOG_INFO, getClass().getName() + " service started"); + } + + // The destroy() method is automatically invoked by the Felix dependency manager + public void destroy() { + // Stop the HTTP context service we created ourselves + m_httpContextComponent.stop(); + } + + public URL getResource(String name) { + return null; + } + + public String getResourceId() { + return Activator.RESOURCE_ID; + } + + /** + * This method can be used to check the availability of the Login Service. + * + * @return The text "Login service online" + */ + @GET + @Produces( { MediaType.TEXT_HTML }) + public String getAll() { + try { + String html = "<table border=\"1\"><tr><th>keyspace</th><th>ColumnFamily</th><th>Rows</th></tr>"; + List<String> keyspaces = m_daemon.getKeyspaces(); + for (String keyspace : keyspaces) { + List<String> columnFamilies = m_daemon.getColumnFamilies(keyspace); + for (String columnFamily : columnFamilies) { + String rowKeyHtml = ""; + List<String> rowKeys = getRowKeys(keyspace, columnFamily); + int i=1; + for (String rowKey : rowKeys) { + rowKeyHtml += "("+i+") "+rowKey + "<br/>"; + i++; + } + html += "<tr><td>" + keyspace + "</td><td>" + columnFamily + "</td><td>" + rowKeyHtml + "</td></tr>"; + } + } + return html; + } + catch (TException e) { + e.printStackTrace(); + throw new WebApplicationException(e); + } + catch (InvalidRequestException e) { + e.printStackTrace(); + throw new WebApplicationException(e); + } + catch (NotFoundException e) { + e.printStackTrace(); + throw new WebApplicationException(e); + } + catch (UnsupportedEncodingException e) { + e.printStackTrace(); + throw new WebApplicationException(e); + } + catch (UnavailableException e) { + e.printStackTrace(); + throw new WebApplicationException(e); + } + catch (TimedOutException e) { + e.printStackTrace(); + throw new WebApplicationException(e); + } + } + + + // Maximum amount of rows to retrieve in queries + private final static int ROW_LIMIT = 1000000; + + // Maximum amount of columns to retrieve in queries + private final static int COLUMN_LIMIT = 1000000; + + // Empty byte array + private final static ByteBuffer EMPTY = ByteBuffer.wrap(new byte[0]); + + // Investigation pointed out that retrying succeeds after about 10 times. + private final static int MAX_RETRIES = 10; + + /** + * Returns all keys for a certain ColumnFamily (think of all primary keys of all records in a certain table) + * @throws TException + * @throws InvalidRequestException + * @throws TimedOutException + * @throws UnavailableException + * @throws UnsupportedEncodingException + */ + public List<String> getRowKeys(String keyspace, String columnFamilyName) throws InvalidRequestException, TException, UnavailableException, TimedOutException, UnsupportedEncodingException { + ColumnParent columnParent = new ColumnParent(columnFamilyName); + SlicePredicate p = new SlicePredicate(); + + // Create and set slice range with a maximum of COLUMN_LIMIT columns + SliceRange sliceRange = new SliceRange(EMPTY, EMPTY, false, COLUMN_LIMIT); + p.setSlice_range(sliceRange); + + // Set key range to maximum ROW_LIMIT results + KeyRange range = new KeyRange(ROW_LIMIT); + range.setStart_key(EMPTY); + range.setEnd_key(EMPTY); + + Iface cs = m_daemon.getCassandraServer(); + cs.set_keyspace(keyspace); + List<KeySlice> keySlices = cs.get_range_slices(columnParent, p, range, ConsistencyLevel.ONE); + + List<String> keys = new ArrayList<String>(); + for (KeySlice keySlice : keySlices) { + // This may be a bangling row key marked for removal, check that! + if (keySlice.getColumnsSize() > 0) { + keys.add(new String(keySlice.getKey(), "UTF-8")); + } + } + m_logService.log(LogService.LOG_DEBUG, "Found " + keys.size() + " keys for ColumnFamily '" + + columnFamilyName + + "' in getRowKeys"); + return keys; + } +} \ No newline at end of file Added: sandbox/ivol/cassandra-gadget/src/main/resources/jsp/CassandraClientGadget.jsp ============================================================================== --- (empty file) +++ sandbox/ivol/cassandra-gadget/src/main/resources/jsp/CassandraClientGadget.jsp Tue Jan 11 12:45:54 2011 @@ -0,0 +1,67 @@ +<%@ page language="java" session="false" buffer="none" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + +<c:set var="baseRestUrl" value="/rest/cassandra/client"/> +<c:set var="gadgetBaseUrl" value="/gadget/cassandra"/> + +<?xml version="1.0" encoding="UTF-8" ?> +<!-- + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. +--> + +<Module> + <ModulePrefs + title="Amdatu Cassandra Client Gadget" + description="Provides a cassandra client interface" + author="Ivo Ladage-van Doorn" + screenshot="${gadgetBaseUrl}/static/images/cassandra.jpeg" + icon="/static/images/cassandra.jpeg" + height="400"> + <Require feature="osapi"/> + <Require feature="dynamic-height"/> + </ModulePrefs> + <Content type="html"> + <![CDATA[ + <link rel="stylesheet" href="/dashboard/static/css/dashboard.css"> + + <script type="text/javascript" src="/dashboard/static/js/lib/jquery-1.4.2.min.js"></script> + <script type="text/javascript" src="/dashboard/static/js/lib/jquery-ui-1.8.2.custom.min.js"></script> + + <div id="result"></div> + + <script type="text/javascript"> + function getAll() { + var url = "${baseRestUrl}"; + jQuery.ajax({ + url: url, + type: "GET", + dataType: "html", + async:true, + success: function(response) { + document.getElementById("result").innerHTML = response; + gadgets.window.adjustHeight(); + } + } + ); + } + + getAll(); + </script> + ]]> + </Content> +</Module> Added: sandbox/ivol/cassandra-gadget/src/main/resources/static/images/cassandra.jpeg ============================================================================== Binary file. No diff available.
