/*
* Copyright 2015-2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed 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.hawkular.inventory.bus.api;
import java.util.HashMap;
import java.util.Map;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.TextMessage;
import org.hawkular.bus.common.AbstractMessage;
import org.hawkular.inventory.api.Action;
import org.hawkular.inventory.api.model.AbstractElement;
import org.hawkular.inventory.api.model.DataEntity;
import org.hawkular.inventory.api.model.Environment;
import org.hawkular.inventory.api.model.Feed;
import org.hawkular.inventory.api.model.Metric;
import org.hawkular.inventory.api.model.MetricType;
import org.hawkular.inventory.api.model.Relationship;
import org.hawkular.inventory.api.model.Resource;
import org.hawkular.inventory.api.model.ResourceType;
import org.hawkular.inventory.api.model.Tenant;
/**
* @author Lukas Krejci
* @since 0.0.1
*/
public abstract class InventoryEvent<T extends AbstractElement<?, ?>> extends InventoryAbstractMessage {
private Action.Enumerated action;
private Tenant tenant;
private T object;
public static Class<? extends InventoryEvent<?>> determineEventType(Message message) {
try {
String entityType = message.getStringProperty("entityType");
if (entityType == null) {
throw new IllegalArgumentException("Cannot determine inventory message type. " +
"'entityType' header property is missing.");
}
switch (entityType) {
case "relationship":
return RelationshipEvent.class;
case "tenant":
return TenantEvent.class;
case "environment":
return EnvironmentEvent.class;
case "resourceType":
return ResourceTypeEvent.class;
case "metricType":
return MetricTypeEvent.class;
case "feed":
return FeedEvent.class;
case "resource":
return ResourceEvent.class;
case "metric":
return MetricEvent.class;
case "dataEntity":
return DataEntityEvent.class;
default:
throw new IllegalArgumentException("Failed to determine inventory event type from the " +
"'entityType' property: " + entityType);
}
} catch (JMSException e) {
throw new IllegalArgumentException("Failed to read inventory event type.", e);
}
}
public static InventoryEvent<?> decode(Message message) {
try {
String body = ((TextMessage) message).getText();
return AbstractMessage.fromJSON(body, determineEventType(message));
} catch (JMSException e) {
throw new IllegalArgumentException("Failed to decode inventory event.", e);
}
}
public static InventoryEvent<?> from(Action<?, ?> action, Tenant tenant, Object object) {
if (object == null) {
throw new IllegalArgumentException("object == null");
}
if (action == null) {
throw new IllegalArgumentException("action == null");
}
if (object instanceof Tenant) {
return new TenantEvent(action.asEnum(), (Tenant) object);
} else if (object instanceof Environment) {
return new EnvironmentEvent(action.asEnum(), tenant, (Environment) object);
} else if (object instanceof Feed) {
return new FeedEvent(action.asEnum(), tenant, (Feed) object);
} else if (object instanceof Metric) {
return new MetricEvent(action.asEnum(), tenant, (Metric) object);
} else if (object instanceof MetricType) {
return new MetricTypeEvent(action.asEnum(), tenant, (MetricType) object);
} else if (object instanceof Resource) {
return new ResourceEvent(action.asEnum(), tenant, (Resource) object);
} else if (object instanceof ResourceType) {
return new ResourceTypeEvent(action.asEnum(), tenant, (ResourceType) object);
} else if (object instanceof Relationship) {
return new RelationshipEvent(action.asEnum(), tenant, (Relationship) object);
} else if (object instanceof DataEntity) {
return new DataEntityEvent(action.asEnum(), tenant, (DataEntity) object);
} else if (object instanceof Action.Update) {
@SuppressWarnings("unchecked")
AbstractElement<?, AbstractElement.Update> updated =
(AbstractElement<?, AbstractElement.Update>) ((Action.Update) object).getOriginalEntity();
updated.update().with((AbstractElement.Update) ((Action.Update) object).getUpdate());
//TODO should we instead send the whole update object? No time for that now, but it'd be preferable I think
return from(action, tenant, updated);
} else {
throw new IllegalArgumentException("Unsupported entity type: " + object.getClass());
}
}
protected InventoryEvent() {
}
protected InventoryEvent(Action.Enumerated action, Tenant tenant, T object) {
this.action = action;
this.tenant = tenant;
this.object = object;
}
public Action.Enumerated getAction() {
return action;
}
public void setAction(Action.Enumerated action) {
this.action = action;
}
public Tenant getTenant() {
return tenant;
}
public void setTenant(Tenant tenant) {
this.tenant = tenant;
}
public T getObject() {
return object;
}
public void setObject(T object) {
this.object = object;
}
public Map<String, String> createMessageHeaders() {
HashMap<String, String> headers = new HashMap<>();
headers.put("action", action.name());
if (object != null) {
headers.put("entityType", firstLetterLowercased(object.getClass().getSimpleName()));
headers.put("path", object.getPath().toString());
}
return headers;
}
private static String firstLetterLowercased(String source) {
return Character.toLowerCase(source.charAt(0)) + source.substring(1);
}
}