/*
* Copyright (c) 2005-2008, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.wso2.carbon.registry.eventing;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNamespace;
import org.apache.axis2.AxisFault;
import org.apache.axis2.Constants;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.transport.base.BaseConstants;
import org.apache.axis2.transport.mail.MailConstants;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.event.core.Message;
import org.wso2.carbon.event.core.subscription.Subscription;
import org.wso2.carbon.event.ws.internal.notify.WSEventDispatcher;
import org.wso2.carbon.event.ws.internal.util.EventingConstants;
import org.wso2.carbon.registry.common.eventing.RegistryEvent;
import org.wso2.carbon.registry.core.session.UserRegistry;
import org.wso2.carbon.registry.eventing.events.DispatchEvent;
import org.wso2.carbon.registry.eventing.internal.Utils;
import org.wso2.carbon.user.core.UserCoreConstants;
import org.wso2.carbon.user.core.UserStoreManager;
import java.io.Serializable;
import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class RegistryEventDispatcher extends WSEventDispatcher {
private ConfigurationContext configContext = null;
private Map<String, Queue<DigestEntry>> digestQueues;
private static final Log log = LogFactory.getLog(RegistryEventDispatcher.class);
public static final class DigestEntry implements Serializable {
private static final long serialVersionUID = -1805410413253360172L;
private String message;
private String endpoint;
private long time;
public DigestEntry(String message, String endpoint, long time) {
this.message = message;
this.endpoint = endpoint;
this.time = time;
}
public String getMessage() {
return message;
}
public String getEndpoint() {
return endpoint;
}
public long getTime() {
return time;
}
}
public RegistryEventDispatcher() {
digestQueues = new LinkedHashMap<String,Queue<DigestEntry>>();
for (String s : new String[]{"h", "d", "w", "f", "m", "y"}) {
//TODO: Identify Queuing mechanisms.
digestQueues.put(s, new ConcurrentLinkedQueue<DigestEntry>());
}
final ScheduledExecutorService executorService =
Executors.newSingleThreadScheduledExecutor();
executorService.scheduleAtFixedRate(new Runnable() {
public void run() {
GregorianCalendar utc = new GregorianCalendar(SimpleTimeZone.getTimeZone("UTC"));
Map<String, List<DigestEntry>> digestEntries =
new HashMap<String, List<DigestEntry>>();
try {
addToDigestEntryQueue(digestEntries, "h");
if (utc.get(Calendar.HOUR_OF_DAY) == 0) {
addToDigestEntryQueue(digestEntries, "d");
if (utc.get(Calendar.DAY_OF_WEEK) == 1) {
addToDigestEntryQueue(digestEntries, "w");
if (utc.get(Calendar.WEEK_OF_YEAR) % 2 != 0) {
addToDigestEntryQueue(digestEntries, "f");
}
}
if (utc.get(Calendar.DAY_OF_MONTH) == 1) {
addToDigestEntryQueue(digestEntries, "m");
if (utc.get(Calendar.DAY_OF_YEAR) == 1) {
addToDigestEntryQueue(digestEntries, "y");
}
}
}
for (Map.Entry<String, List<DigestEntry>> e : digestEntries.entrySet()) {
List<DigestEntry> value = e.getValue();
Collections.sort(value, new Comparator<DigestEntry>() {
public int compare(DigestEntry o1,
DigestEntry o2) {
if (o1.getTime() > o2.getTime()) {
return -1;
} else if (o1.getTime() < o2.getTime()) {
return 1;
}
return 0;
}
});
StringBuffer buffer = new StringBuffer();
for (DigestEntry entry : value) {
buffer.append(entry.getMessage()).append("/n/n");
}
RegistryEvent<String> re = new RegistryEvent<String>(buffer.toString());
re.setTopic("DigestEvent");
DispatchEvent de = new DispatchEvent(re, e.getKey(), true);
Subscription subscription = new Subscription();
subscription.setTopicName(re.getTopic());
publishEvent(de, subscription, e.getKey(), true);
}
} catch (Exception ignored) {
}
}
}, System.currentTimeMillis() % (1000 * 60 * 60), 1, TimeUnit.HOURS);
try {
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
executorService.shutdownNow();
}
});
} catch (IllegalStateException e) {
executorService.shutdownNow();
throw new IllegalStateException("Unable to create registry event dispatcher during " +
"shutdown process.");
}
}
private void addToDigestEntryQueue(Map<String, List<DigestEntry>> digestEntries,
String digestType) {
Queue<DigestEntry> digestQueue = getDigestQueue(digestType);
while (!digestQueue.isEmpty()) {
DigestEntry entry = digestQueue.poll();
String endpoint = entry.getEndpoint();
List<DigestEntry> digestEntriesForEndpoint;
if (!digestEntries.containsKey(endpoint)) {
digestEntriesForEndpoint = new LinkedList<DigestEntry>();
digestEntries.put(endpoint, digestEntriesForEndpoint);
} else {
digestEntriesForEndpoint = digestEntries.get(endpoint);
}
digestEntriesForEndpoint.add(entry);
}
}
private Queue<DigestEntry> getDigestQueue(String digestType) {
Queue<DigestEntry> entryQueue = digestQueues.get(digestType);
if (entryQueue != null) {
return entryQueue;
}
String msg = "Invalid Digest Type: " + digestType;
log.error(msg);
throw new RuntimeException(msg);
}
public void notify(Message event, Subscription subscription) {
if (subscription == null) {
return;
}
String endpoint = subscription.getEventSinkURL();
if (endpoint == null || !(event.getMessage() instanceof OMElement)) {
return;
}
if (subscription.getProperties() != null) {
int tenantId = subscription.getTenantId();
/*int tenantIdOfEventObj = SuperTenantCarbonContext.getCurrentContext(
((MessageContext)event.getMessage())).getTenantId();*/
if (event instanceof DispatchEvent) {
int tenantIdOfEventObj = ((DispatchEvent)event).getTenantId();
if (tenantId != tenantIdOfEventObj) {
log.warn("TenantId for subscription doesn't match with the logged-in tenant");
return;
}
}
}
String topic = subscription.getTopicName();
boolean doRest = (subscription.getProperties() != null &&
subscription.getProperties().get(
RegistryEventingConstants.DO_REST) != null &&
(subscription.getProperties().get(
RegistryEventingConstants.DO_REST)).equals(
Boolean.toString(Boolean.TRUE)));
if (endpoint.toLowerCase().startsWith("digest://")) {
String digestType = endpoint.substring(9, 10);
endpoint = endpoint.substring(11);
OMElement payload = event.getMessage();
if (payload != null && payload.getFirstElement() != null) {
String path = topic.substring(RegistryEventingConstants.TOPIC_PREFIX.length(),
topic.lastIndexOf("/"));
String eventName = topic.substring(topic.lastIndexOf("/") + 1, topic.length());
String time = ((OMElement) payload.getFirstElement().getNextOMSibling()).getText();
String message = time + ": [" + eventName + "] at path " + path + ":/n " +
payload.getFirstElement().getText();
getDigestQueue(digestType).add(
new DigestEntry(message, endpoint, System.currentTimeMillis()));
return;
}
}
if (endpoint.toLowerCase().startsWith("mailto:")) {
if (subscription.getProperties() != null &&
Boolean.toString(true).equals(subscription.getProperties().get(
RegistryEventingConstants.NOT_VERIFIED))) {
String email = endpoint.toLowerCase().substring("mailto:".length());
log.warn("Unable to send notification. The e-mail address " + email +
" has not been verified.");
return;
}
log.debug("Sending Notification to: " + endpoint);
publishEvent(event, subscription, endpoint, true);
} else if (endpoint.toLowerCase().startsWith("user://")) {
String email = null;
try {
String username = endpoint.substring(7);
if (Utils.getRegistryService() != null) {
UserRegistry registry = Utils.getRegistryService().getConfigSystemRegistry();
if (registry != null && registry.getUserRealm() != null &&
registry.getUserRealm().getUserStoreManager() != null) {
UserStoreManager reader = registry.getUserRealm().getUserStoreManager();
email = "mailto:" + reader.getUserClaimValue(username,
UserCoreConstants.ClaimTypeURIs.EMAIL_ADDRESS,
UserCoreConstants.DEFAULT_PROFILE);
}
}
} catch (Exception e) {
log.error("Failed Sending Notification to: " + endpoint);
return;
}
log.debug("Sending Notification to: " + email);
publishEvent(event, subscription, email, true);
} else if (endpoint.toLowerCase().startsWith("role://")) {
List<String> emails = new LinkedList<String>();
try {
String roleName = endpoint.substring(7);
if (Utils.getRegistryService() != null) {
UserRegistry registry = Utils.getRegistryService().getConfigSystemRegistry();
if (registry != null && registry.getUserRealm() != null &&
registry.getUserRealm().getUserStoreManager() != null) {
UserStoreManager reader = registry.getUserRealm().getUserStoreManager();
for (String username : reader.getUserListOfRole(roleName)) {
String temp = reader.getUserClaimValue(username,
UserCoreConstants.ClaimTypeURIs.EMAIL_ADDRESS,
UserCoreConstants.DEFAULT_PROFILE);
if (temp != null && temp.length() > 0) {
emails.add("mailto:" + temp);
}
}
}
}
} catch (Exception e) {
log.error("Failed Sending Notification to: " + endpoint);
return;
}
for (String email : emails) {
log.debug("Sending Notification to: " + email);
publishEvent(event, subscription, email, true);
}
} else {
log.debug("Sending Notification to: " + endpoint);
publishEvent(event, subscription, endpoint, doRest);
}
}
public void init(ConfigurationContext configContext) {
this.configContext = configContext;
}
private OMElement buildPayload(OMFactory factory, Message event, boolean isEmail) {
OMElement messageElement = event.getMessage();
if (!isEmail) {
return event.getMessage();
}
try {
// E-mail scenario
OMElement payload = factory.createOMElement(BaseConstants.DEFAULT_TEXT_WRAPPER, null);
String poweredBy = "This message is automatically generated by the WSO2 "
+ "Carbon Registry.";
String signature = "\n--\n" + poweredBy;
String registryURL = Utils.getDefaultEventingServiceURL();
if (registryURL != null && registryURL.indexOf(
"/services/RegistryEventingService") > -1) {
registryURL = registryURL.substring(0, registryURL.length() -
"/services/RegistryEventingService".length()) +
"/carbon";
}
if (registryURL != null) {
signature += " URL: " + registryURL;
}
payload.setText(messageElement.getFirstElement().getText() + signature);
return payload;
} catch (Exception e) {
log.error("Unable to Build Payload for " + messageElement.getText(), e);
return null;
}
}
private OMElement buildTopic(OMFactory factory, String topic) {
OMNamespace topicNs = factory.createOMNamespace(
EventingConstants.NOTIFICATION_NS_URI,
EventingConstants.NOTIFICATION_NS_PREFIX);
OMElement topicEle = factory.createOMElement(RegistryEventingConstants.WSE_EN_TOPIC,
topicNs);
topicEle.setText(topic);
return topicEle;
}
@SuppressWarnings("unchecked")
public void publishEvent(Message message, Subscription subscription, String endpoint,
boolean doRest) {
OMFactory factory = OMAbstractFactory.getOMFactory();
OMElement topicEle = buildTopic(factory, subscription.getTopicName());
boolean isEmail = false;
if (endpoint == null) {
endpoint = this.getEndpoint();
} else {
isEmail = doRest && endpoint.startsWith("mailto:");
}
OMElement payload = buildPayload(factory, message, isEmail);
if (endpoint != null) {
try {
if (doRest) {
if (configContext == null) {
MessageContext messageContext = MessageContext.getCurrentMessageContext();
if (messageContext != null) {
configContext = messageContext.getConfigurationContext();
}
}
ServiceClient serviceClient;
if (configContext != null) {
serviceClient = new ServiceClient(configContext, null);
} else {
serviceClient = new ServiceClient();
}
Options options = new Options();
serviceClient.engageModule("addressing");
options.setTo(new EndpointReference(endpoint));
options.setProperty(Constants.Configuration.ENABLE_REST, Constants.VALUE_TRUE);
if (endpoint.toLowerCase().startsWith("mailto:")) {
Map headerMap = new HashMap();
String topicText = topicEle.getText();
if (topicText != null && topicText.lastIndexOf("/") > 0) {
String path = topicText
.substring(RegistryEventingConstants.TOPIC_PREFIX.length(),
topicText.lastIndexOf("/"));
String event = topicText
.substring(topicText.lastIndexOf("/") + 1, topicText.length());
headerMap.put(MailConstants.MAIL_HEADER_SUBJECT,
"[" + event + "] at path: " + path);
}
options.setProperty(MessageContext.TRANSPORT_HEADERS, headerMap);
options.setProperty(MailConstants.TRANSPORT_MAIL_FORMAT,
MailConstants.TRANSPORT_FORMAT_TEXT);
}
options.setProperty(MessageContext.CLIENT_API_NON_BLOCKING, Boolean.TRUE);
options.setAction(RegistryEventingConstants.WSE_PUBLISH);
serviceClient.setOptions(options);
serviceClient.fireAndForget(payload);
} else {
super.sendNotification(topicEle, payload, endpoint);
}
} catch (AxisFault e) {
log.error("Unable to send message", e);
}
}
}
public String getEndpoint() {
return Utils.getDefaultEventingServiceURL();
}
}