/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. 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. For additional information regarding * copyright in this work, please see the NOTICE file in the top level * directory of this distribution. */ package org.apache.usergrid.persistence.queue.impl; import com.datastax.driver.core.DataType; import com.datastax.driver.core.ProtocolVersion; import com.google.inject.Inject; import com.google.inject.Singleton; import com.google.inject.assistedinject.Assisted; import org.apache.usergrid.persistence.qakka.core.*; import org.apache.usergrid.persistence.qakka.core.Queue; import org.apache.usergrid.persistence.qakka.exceptions.QakkaRuntimeException; import org.apache.usergrid.persistence.qakka.serialization.queuemessages.DatabaseQueueMessage; import org.apache.usergrid.persistence.queue.LegacyQueueManager; import org.apache.usergrid.persistence.queue.LegacyQueueMessage; import org.apache.usergrid.persistence.queue.LegacyQueueScope; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.*; import java.nio.ByteBuffer; import java.util.*; public class QakkaQueueManager implements LegacyQueueManager { private static final Logger logger = LoggerFactory.getLogger( QakkaQueueManager.class ); private final LegacyQueueScope scope; private final QueueManager queueManager; private final QueueMessageManager queueMessageManager; private final Regions regions; private final Set<String> queueNames; @Inject public QakkaQueueManager( @Assisted LegacyQueueScope scope, QueueManager queueManager, QueueMessageManager queueMessageManager, Regions regions ) { this.scope = scope; this.queueManager = queueManager; this.queueMessageManager = queueMessageManager; this.regions = regions; this.queueNames = new HashSet<>(); // Can't create queue here, actor system may not yet be started //createQueueIfNecessary(); } private synchronized void createQueueIfNecessary() { if ( !queueNames.contains( scope.getName() ) && queueManager.getQueueConfig(scope.getName()) == null ) { // TODO: read defaults from config //queueManager.createQueue( new Queue( queueName, "test-type", region, region, 0L, 5, 10, null )); Queue queue = new Queue( scope.getName() ); queueManager.createQueue( queue ); queueNames.add( scope.getName() ); } } private <T extends Serializable> void doSendMessage( T body, List<String> regions ) throws IOException { createQueueIfNecessary(); ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(body); oos.flush(); oos.close(); ByteBuffer byteBuffer = ByteBuffer.wrap( bos.toByteArray() ); queueMessageManager.sendMessages( scope.getName(), regions, null, // delay millis null, // expiration seconds "application/octet-stream", DataType.serializeValue( byteBuffer, ProtocolVersion.NEWEST_SUPPORTED )); } @Override public <T extends Serializable> void sendMessageToLocalRegion(T body) throws IOException { List<String> regionsList = regions.getRegions( Regions.LOCAL ); logger.trace( "Sending message to queue {} local region {}", scope.getName(), regionsList ); doSendMessage( body, regionsList ); } @Override public <T extends Serializable> void sendMessageToAllRegions(T body) throws IOException { List<String> regionsList = regions.getRegions( Regions.ALL ); logger.trace( "Sending message to queue {} all regions {}", scope.getName(), regionsList ); doSendMessage( body, regionsList ); } @Override public List<LegacyQueueMessage> getMessages(int limit, Class klass) { createQueueIfNecessary(); List<LegacyQueueMessage> messages = new ArrayList<>(); List<QueueMessage> qakkaMessages = queueMessageManager.getNextMessages( scope.getName(), limit ); for ( QueueMessage qakkaMessage : qakkaMessages ) { Object body; try { ByteBuffer messageData = queueMessageManager.getMessageData( qakkaMessage.getMessageId() ); ByteBuffer bb = (ByteBuffer)DataType.blob().deserialize( messageData, ProtocolVersion.NEWEST_SUPPORTED ); ByteArrayInputStream bais = new ByteArrayInputStream( bb.array() ); ObjectInputStream ios = new ObjectInputStream( bais ); body = ios.readObject(); } catch (Throwable t) { throw new QakkaRuntimeException( "Error de-serializing object", t ); } LegacyQueueMessage legacyQueueMessage = new LegacyQueueMessage( qakkaMessage.getQueueMessageId().toString(), null, // handle body, null); // type messages.add( legacyQueueMessage ); } return messages; } @Override public long getQueueDepth() { createQueueIfNecessary(); return queueMessageManager.getQueueDepth( scope.getName(), DatabaseQueueMessage.Type.DEFAULT ); } @Override public void commitMessage(LegacyQueueMessage queueMessage) { createQueueIfNecessary(); if(logger.isTraceEnabled()){ logger.trace("Committing message with id: {}", queueMessage.getMessageId()); } UUID queueMessageId = UUID.fromString( queueMessage.getMessageId() ); queueMessageManager.ackMessage( scope.getName(), queueMessageId ); } @Override public void commitMessages(List<LegacyQueueMessage> queueMessages) { for ( LegacyQueueMessage message : queueMessages ) { commitMessage( message ); } } @Override public void sendMessages( List bodies ) throws IOException { for ( Object body : bodies ) { sendMessageToLocalRegion( (Serializable)body ); } } @Override public void deleteQueue() { queueManager.deleteQueue( scope.getName() ); } @Override public void clearQueueNameCache(){ queueNames.clear(); } }