/**
* Licensed to The Apereo Foundation under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
*
* The Apereo Foundation licenses this file to you under the Educational
* Community 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://opensource.org/licenses/ecl2.txt
*
* 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.opencastproject.index.service.message;
import org.opencastproject.index.IndexProducer;
import org.opencastproject.index.service.impl.index.AbstractSearchIndex;
import org.opencastproject.message.broker.api.BaseMessage;
import org.opencastproject.message.broker.api.MessageReceiver;
import org.opencastproject.message.broker.api.MessageSender;
import org.opencastproject.message.broker.api.MessageSender.DestinationType;
import org.opencastproject.message.broker.api.index.IndexRecreateObject;
import org.opencastproject.message.broker.api.index.IndexRecreateObject.Status;
import org.opencastproject.security.api.SecurityService;
import org.opencastproject.util.OsgiUtil;
import org.opencastproject.util.data.Effect2;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
public abstract class BaseMessageReceiverImpl<T extends Serializable> {
private static final String DESTINATION_ID_KEY = "destinationId";
private static final Logger logger = LoggerFactory.getLogger(BaseMessageReceiverImpl.class);
private final ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
private SecurityService securityService;
private MessageSender messageSender;
private MessageReceiver messageReceiver;
private MessageWatcher messageWatcher;
private AbstractSearchIndex index;
private MessageReceiverLockService lockService;
private String destinationId;
private MessageSender.DestinationType destinationType;
public BaseMessageReceiverImpl(MessageSender.DestinationType destinationType) {
this.destinationType = destinationType;
}
public void activate(ComponentContext cc) {
logger.info("Activating {}", this.getClass().getName());
destinationId = OsgiUtil.getComponentContextProperty(cc, DESTINATION_ID_KEY);
logger.info("The {} for this message receiver is '{}'", DESTINATION_ID_KEY, destinationId);
messageWatcher = new MessageWatcher(lockService);
singleThreadExecutor.execute(messageWatcher);
}
public void deactivate(ComponentContext cc) {
logger.info("Deactivating {}", this.getClass().getName());
if (messageWatcher != null)
messageWatcher.stopListening();
singleThreadExecutor.shutdown();
}
protected abstract void execute(T messageContent);
protected String getDestinationId() {
return destinationId;
}
protected DestinationType getDestinationType() {
return destinationType;
}
protected AbstractSearchIndex getSearchIndex() {
return index;
}
protected SecurityService getSecurityService() {
return securityService;
}
private class MessageWatcher implements Runnable {
private final Logger logger = LoggerFactory.getLogger(MessageWatcher.class);
private boolean listening = true;
private FutureTask<Serializable> future;
private final ExecutorService executor = Executors.newSingleThreadExecutor();
private final String clazzName = BaseMessageReceiverImpl.this.getClass().getName();
private final MessageReceiverLockService lockService;
MessageWatcher(MessageReceiverLockService lockService) {
this.lockService = lockService;
}
public void stopListening() {
this.listening = false;
future.cancel(true);
}
@Override
public void run() {
logger.info("Starting to listen for {} Messages", clazzName);
while (listening) {
future = messageReceiver.receiveSerializable(getDestinationId(), getDestinationType());
executor.execute(future);
try {
BaseMessage baseMessage = (BaseMessage) future.get();
if (baseMessage == null) {
continue;
}
securityService.setOrganization(baseMessage.getOrganization());
securityService.setUser(baseMessage.getUser());
if (baseMessage.getObject() instanceof IndexRecreateObject) {
IndexRecreateObject obj = (IndexRecreateObject) baseMessage.getObject();
if (Status.End.equals(obj.getStatus()))
messageSender.sendObjectMessage(IndexProducer.RESPONSE_QUEUE, MessageSender.DestinationType.Queue,
IndexRecreateObject.end(obj.getIndexName(), obj.getService()));
} else {
lockService.synchronize(baseMessage.getId().get(), execute.curry(baseMessage.getObject()).toFn());
}
} catch (InterruptedException e) {
logger.error("Problem while getting {} message events {}", clazzName, ExceptionUtils.getStackTrace(e));
} catch (ExecutionException e) {
logger.error("Problem while getting {} message events {}", clazzName, ExceptionUtils.getStackTrace(e));
} catch (CancellationException e) {
logger.trace("Listening for messages {} has been cancelled.", clazzName);
} catch (Throwable t) {
logger.error("Problem while getting {} message events {}", clazzName, ExceptionUtils.getStackTrace(t));
} finally {
securityService.setOrganization(null);
securityService.setUser(null);
}
}
logger.info("Stopping listening for {} Messages", clazzName);
}
}
private final Effect2<Serializable, String> execute = new Effect2<Serializable, String>() {
@Override
@SuppressWarnings("unchecked")
protected void run(Serializable message, String mpId) {
execute((T) message);
}
};
public void setSecurityService(SecurityService securityService) {
this.securityService = securityService;
}
public void setMessageSender(MessageSender messageSender) {
this.messageSender = messageSender;
}
public void setMessageReceiver(MessageReceiver messageReceiver) {
this.messageReceiver = messageReceiver;
}
public void setSearchIndex(AbstractSearchIndex index) {
this.index = index;
}
public void setMessageReceiverLockService(MessageReceiverLockService lockService) {
this.lockService = lockService;
}
}