| /* |
| * 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. |
| */ |
| package org.apache.usergrid.mq.cassandra; |
| |
| |
| import java.nio.ByteBuffer; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.UUID; |
| |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| import org.apache.usergrid.mq.Message; |
| import org.apache.usergrid.mq.Queue; |
| import org.apache.usergrid.mq.QueueQuery; |
| import org.apache.usergrid.utils.ConversionUtils; |
| import org.apache.usergrid.utils.JsonUtils; |
| import org.apache.usergrid.utils.UUIDUtils; |
| |
| import me.prettyprint.hector.api.beans.HColumn; |
| import me.prettyprint.hector.api.mutation.Mutator; |
| |
| import static me.prettyprint.hector.api.factory.HFactory.createColumn; |
| import static org.apache.usergrid.mq.Message.MESSAGE_ID; |
| import static org.apache.usergrid.mq.Message.MESSAGE_PROPERTIES; |
| import static org.apache.usergrid.mq.Message.MESSAGE_TYPE; |
| import static org.apache.usergrid.mq.Queue.QUEUE_NEWEST; |
| import static org.apache.usergrid.mq.Queue.QUEUE_OLDEST; |
| import static org.apache.usergrid.mq.Queue.QUEUE_PROPERTIES; |
| import static org.apache.usergrid.mq.QueuePosition.CONSUMER; |
| import static org.apache.usergrid.utils.ConversionUtils.bytebuffer; |
| import static org.apache.usergrid.utils.ConversionUtils.getLong; |
| import static org.apache.usergrid.utils.ConversionUtils.object; |
| import static org.apache.usergrid.persistence.cassandra.Serializers.*; |
| |
| |
| public class CassandraMQUtils { |
| |
| public static final Logger logger = LoggerFactory.getLogger( CassandraMQUtils.class ); |
| |
| /** Logger for batch operations */ |
| private static final Logger batch_logger = |
| LoggerFactory.getLogger( CassandraMQUtils.class.getPackage().getName() + ".BATCH" ); |
| |
| |
| public static void logBatchOperation( String operation, Object columnFamily, Object key, Object columnName, |
| Object columnValue, long timestamp ) { |
| |
| batch_logger.info( "{} cf={} key={} name={} value={}", |
| operation, columnFamily, key, columnName, columnValue |
| ); |
| } |
| |
| |
| /** |
| * Encode a message into a set of columns. JMS properties are encoded as strings and longs everything else is binary |
| * JSON. |
| */ |
| public static Map<ByteBuffer, ByteBuffer> serializeMessage( Message message ) { |
| if ( message == null ) { |
| return null; |
| } |
| Map<ByteBuffer, ByteBuffer> columns = new HashMap<ByteBuffer, ByteBuffer>(); |
| for ( Entry<String, Object> property : message.getProperties().entrySet() ) { |
| if ( property.getValue() == null ) { |
| columns.put( bytebuffer( property.getKey() ), null ); |
| } |
| else if ( MESSAGE_TYPE.equals( property.getKey() ) || MESSAGE_ID.equals( property.getKey() ) ) { |
| columns.put( bytebuffer( property.getKey() ), bytebuffer( property.getValue() ) ); |
| } |
| else { |
| columns.put( bytebuffer( property.getKey() ), JsonUtils.toByteBuffer( property.getValue() ) ); |
| } |
| } |
| return columns; |
| } |
| |
| |
| public static Mutator<ByteBuffer> addMessageToMutator( Mutator<ByteBuffer> m, Message message, long timestamp ) { |
| |
| Map<ByteBuffer, ByteBuffer> columns = serializeMessage( message ); |
| |
| if ( columns == null ) { |
| return m; |
| } |
| |
| for ( Map.Entry<ByteBuffer, ByteBuffer> column_entry : columns.entrySet() ) { |
| if ( ( column_entry.getValue() != null ) && column_entry.getValue().hasRemaining() ) { |
| HColumn<ByteBuffer, ByteBuffer> column = |
| createColumn( column_entry.getKey(), column_entry.getValue(), timestamp, be, be ); |
| m.addInsertion( bytebuffer( message.getUuid() ), QueuesCF.MESSAGE_PROPERTIES.toString(), column ); |
| } |
| else { |
| m.addDeletion( bytebuffer( message.getUuid() ), QueuesCF.MESSAGE_PROPERTIES.toString(), |
| column_entry.getKey(), be, timestamp ); |
| } |
| } |
| |
| return m; |
| } |
| |
| |
| public static Message deserializeMessage( List<HColumn<String, ByteBuffer>> columns ) { |
| Message message = null; |
| |
| Map<String, Object> properties = new HashMap<String, Object>(); |
| for ( HColumn<String, ByteBuffer> column : columns ) { |
| if ( MESSAGE_TYPE.equals( column.getName() ) || MESSAGE_ID.equals( column.getName() ) ) { |
| properties.put( column.getName(), |
| object( MESSAGE_PROPERTIES.get( column.getName() ), column.getValue() ) ); |
| } |
| else { |
| properties.put( column.getName(), JsonUtils.fromByteBuffer( column.getValue() ) ); |
| } |
| } |
| if ( !properties.isEmpty() ) { |
| message = new Message( properties ); |
| } |
| |
| return message; |
| } |
| |
| |
| public static Map<ByteBuffer, ByteBuffer> serializeQueue( Queue queue ) { |
| if ( queue == null ) { |
| return null; |
| } |
| Map<ByteBuffer, ByteBuffer> columns = new HashMap<ByteBuffer, ByteBuffer>(); |
| for ( Entry<String, Object> property : queue.getProperties().entrySet() ) { |
| if ( property.getValue() == null ) { |
| continue; |
| } |
| if ( Queue.QUEUE_ID.equals( property.getKey() ) || QUEUE_NEWEST.equals( property.getKey() ) || QUEUE_OLDEST |
| .equals( property.getKey() ) ) { |
| continue; |
| } |
| if ( QUEUE_PROPERTIES.containsKey( property.getKey() ) ) { |
| columns.put( bytebuffer( property.getKey() ), bytebuffer( property.getValue() ) ); |
| } |
| else { |
| columns.put( bytebuffer( property.getKey() ), JsonUtils.toByteBuffer( property.getValue() ) ); |
| } |
| } |
| return columns; |
| } |
| |
| |
| public static Queue deserializeQueue( List<HColumn<String, ByteBuffer>> columns ) { |
| Queue queue = null; |
| |
| Map<String, Object> properties = new HashMap<String, Object>(); |
| for ( HColumn<String, ByteBuffer> column : columns ) { |
| if ( QUEUE_PROPERTIES.containsKey( column.getName() ) ) { |
| properties |
| .put( column.getName(), object( QUEUE_PROPERTIES.get( column.getName() ), column.getValue() ) ); |
| } |
| else { |
| properties.put( column.getName(), JsonUtils.fromByteBuffer( column.getValue() ) ); |
| } |
| } |
| if ( !properties.isEmpty() ) { |
| queue = new Queue( properties ); |
| } |
| |
| return queue; |
| } |
| |
| |
| public static Mutator<ByteBuffer> addQueueToMutator( Mutator<ByteBuffer> m, Queue queue, long timestamp ) { |
| |
| Map<ByteBuffer, ByteBuffer> columns = serializeQueue( queue ); |
| |
| if ( columns == null ) { |
| return m; |
| } |
| |
| for ( Map.Entry<ByteBuffer, ByteBuffer> column_entry : columns.entrySet() ) { |
| if ( ( column_entry.getValue() != null ) && column_entry.getValue().hasRemaining() ) { |
| HColumn<ByteBuffer, ByteBuffer> column = |
| createColumn( column_entry.getKey(), column_entry.getValue(), timestamp, be, be ); |
| m.addInsertion( bytebuffer( queue.getUuid() ), QueuesCF.QUEUE_PROPERTIES.toString(), column ); |
| } |
| else { |
| m.addDeletion( bytebuffer( queue.getUuid() ), QueuesCF.QUEUE_PROPERTIES.toString(), |
| column_entry.getKey(), be, timestamp ); |
| } |
| } |
| |
| return m; |
| } |
| |
| |
| public static ByteBuffer getQueueShardRowKey( UUID uuid, long ts ) { |
| ByteBuffer bytes = ByteBuffer.allocate( 24 ); |
| bytes.putLong( uuid.getMostSignificantBits() ); |
| bytes.putLong( uuid.getLeastSignificantBits() ); |
| bytes.putLong( ts ); |
| return ( ByteBuffer ) bytes.rewind(); |
| } |
| |
| |
| /** Get a row key in format of queueId+clientId */ |
| public static ByteBuffer getQueueClientTransactionKey( UUID queueId, UUID clientId ) { |
| ByteBuffer bytes = ByteBuffer.allocate( 32 ); |
| bytes.putLong( queueId.getMostSignificantBits() ); |
| bytes.putLong( queueId.getLeastSignificantBits() ); |
| bytes.putLong( clientId.getMostSignificantBits() ); |
| bytes.putLong( clientId.getLeastSignificantBits() ); |
| return ( ByteBuffer ) bytes.rewind(); |
| } |
| |
| |
| public static UUID getUUIDFromRowKey( ByteBuffer bytes ) { |
| return ConversionUtils.uuid( bytes ); |
| } |
| |
| |
| public static long getLongFromRowKey( ByteBuffer bytes ) { |
| bytes = bytes.slice(); |
| return getLong( 16 ); |
| } |
| |
| |
| /** Get the queueId from the path */ |
| public static UUID getQueueId( String path ) { |
| String queuePath = Queue.normalizeQueuePath( path ); |
| if ( queuePath == null ) { |
| queuePath = "/"; |
| } |
| |
| if ( logger.isDebugEnabled() ) { |
| logger.debug( "QueueManagerFactoryImpl.getFromQueue: {}", queuePath ); |
| } |
| |
| return Queue.getQueueId( queuePath ); |
| } |
| |
| |
| /** Get the consumer Id from the queue id */ |
| public static UUID getConsumerId( UUID queueId, QueueQuery query ) { |
| UUID consumerId = queueId; |
| |
| if ( query.getPosition() == CONSUMER ) { |
| consumerId = query.getConsumerId(); |
| if ( ( consumerId == null ) && ( query.getPosition() == CONSUMER ) ) { |
| consumerId = UUIDUtils.newTimeUUID(); |
| } |
| } |
| return consumerId; |
| } |
| } |