/* * 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; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.TreeMap; import java.util.UUID; import javax.xml.bind.annotation.XmlRootElement; import org.apache.usergrid.utils.UUIDUtils; import com.fasterxml.jackson.annotation.JsonAnyGetter; import com.fasterxml.jackson.annotation.JsonAnySetter; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.uuid.UUIDComparator; import static org.apache.commons.collections.IteratorUtils.asEnumeration; import static org.apache.commons.collections.MapUtils.getBooleanValue; import static org.apache.commons.collections.MapUtils.getByteValue; import static org.apache.commons.collections.MapUtils.getDoubleValue; import static org.apache.commons.collections.MapUtils.getFloatValue; import static org.apache.commons.collections.MapUtils.getIntValue; import static org.apache.commons.collections.MapUtils.getLongValue; import static org.apache.commons.collections.MapUtils.getShortValue; import static org.apache.commons.collections.MapUtils.getString; import static org.apache.usergrid.utils.ClassUtils.cast; import static org.apache.usergrid.utils.ConversionUtils.bytes; import static org.apache.usergrid.utils.ConversionUtils.coerceMap; import static org.apache.usergrid.utils.ConversionUtils.getInt; import static org.apache.usergrid.utils.ConversionUtils.uuid; import static org.apache.usergrid.utils.MapUtils.hashMap; import static org.apache.usergrid.utils.UUIDUtils.getTimestampInMillis; import static org.apache.usergrid.utils.UUIDUtils.newTimeUUID; @XmlRootElement public class Message { public static final String MESSAGE_CORRELATION_ID = "correlation_id"; public static final String MESSAGE_DESTINATION = "destination"; public static final String MESSAGE_ID = "uuid"; public static final String MESSAGE_REPLY_TO = "reply_to"; public static final String MESSAGE_TIMESTAMP = "timestamp"; public static final String MESSAGE_TYPE = "type"; public static final String MESSAGE_CATEGORY = "category"; public static final String MESSAGE_INDEXED = "indexed"; public static final String MESSAGE_PERSISTENT = "persistent"; public static final String MESSAGE_TRANSACTION = "transaction"; @SuppressWarnings("rawtypes") public static final Map<String, Class> MESSAGE_PROPERTIES = hashMap( MESSAGE_CORRELATION_ID, ( Class ) String.class ).map( MESSAGE_DESTINATION, String.class ) .map( MESSAGE_ID, UUID.class ).map( MESSAGE_REPLY_TO, String.class ) .map( MESSAGE_TIMESTAMP, Long.class ).map( MESSAGE_TYPE, String.class ) .map( MESSAGE_CATEGORY, String.class ).map( MESSAGE_INDEXED, Boolean.class ) .map( MESSAGE_PERSISTENT, Boolean.class ).map( MESSAGE_TRANSACTION, UUID.class ); public static int compare( Message m1, Message m2 ) { if ( ( m1 == null ) && ( m2 == null ) ) { return 0; } else if ( m1 == null ) { return -1; } else if ( m2 == null ) { return 1; } return UUIDComparator.staticCompare( m1.getUuid(), m2.getUuid() ); } public static List<Message> fromList( List<Map<String, Object>> l ) { List<Message> messages = new ArrayList<Message>( l.size() ); for ( Map<String, Object> properties : l ) { messages.add( new Message( properties ) ); } return messages; } public static List<Message> sort( List<Message> messages ) { Collections.sort( messages, new Comparator<Message>() { @Override public int compare( Message m1, Message m2 ) { return Message.compare( m1, m2 ); } } ); return messages; } public static List<Message> sortReversed( List<Message> messages ) { Collections.sort( messages, new Comparator<Message>() { @Override public int compare( Message m1, Message m2 ) { return Message.compare( m2, m1 ); } } ); return messages; } protected Map<String, Object> properties = new TreeMap<String, Object>( String.CASE_INSENSITIVE_ORDER ); public Message() { } @SuppressWarnings("unchecked") public Message( Map<String, Object> properties ) { this.properties.putAll( coerceMap( ( Map<String, Class<?>> ) cast( MESSAGE_PROPERTIES ), properties ) ); } @SuppressWarnings("unchecked") public void addCounter( String name, int value ) { Map<String, Integer> counters = null; if ( properties.get( "counters" ) instanceof Map ) { counters = ( Map<String, Integer> ) properties.get( "counters" ); } else { counters = new HashMap<String, Integer>(); properties.put( "counters", counters ); } counters.put( name, value ); } public void clearBody() { properties.clear(); } public void clearProperties() { properties.clear(); } public boolean getBooleanProperty( String name ) { return getBooleanValue( properties, name ); } public byte getByteProperty( String name ) { return getByteValue( properties, name ); } @JsonIgnore public String getCategory() { return getString( properties, MESSAGE_CATEGORY ); } @JsonIgnore public String getCorrelationID() { return getString( properties, MESSAGE_CORRELATION_ID ); } @JsonIgnore public byte[] getCorrelationIDAsBytes() { return bytes( properties.get( MESSAGE_CORRELATION_ID ) ); } @JsonIgnore public Map<String, Integer> getCounters() { Map<String, Integer> counters = new HashMap<String, Integer>(); if ( properties.get( "counters" ) instanceof Map ) { @SuppressWarnings("unchecked") Map<String, Object> c = ( Map<String, Object> ) properties.get( "counters" ); for ( Entry<String, Object> e : c.entrySet() ) { counters.put( e.getKey(), getInt( e.getValue() ) ); } } return counters; } @JsonIgnore public int getDeliveryMode() { return 2; } @JsonIgnore public Queue getDestination() { return Queue.getDestination( getString( properties, MESSAGE_DESTINATION ) ); } public double getDoubleProperty( String name ) { return getDoubleValue( properties, name ); } @JsonIgnore public long getExpiration() { return 0; } public float getFloatProperty( String name ) { return getFloatValue( properties, name ); } public int getIntProperty( String name ) { return getIntValue( properties, name ); } public long getLongProperty( String name ) { return getLongValue( properties, name ); } @JsonIgnore public String getMessageID() { return getUuid().toString(); } public Object getObjectProperty( String name ) { return properties.get( name ); } @JsonIgnore public int getPriority() { return 0; } @JsonAnyGetter public Map<String, Object> getProperties() { sync(); return properties; } @JsonIgnore @SuppressWarnings("unchecked") public Enumeration<String> getPropertyNames() { return asEnumeration( properties.keySet().iterator() ); } @JsonIgnore public boolean getRedelivered() { return false; } @JsonIgnore public Queue getReplyTo() { return Queue.getDestination( getString( properties, MESSAGE_REPLY_TO ) ); } public short getShortProperty( String name ) { return getShortValue( properties, name ); } public String getStringProperty( String name ) { return getString( properties, name ); } @JsonIgnore public synchronized long getTimestamp() { if ( properties.containsKey( MESSAGE_TIMESTAMP ) ) { long ts = getLongValue( properties, MESSAGE_TIMESTAMP ); if ( ts != 0 ) { return ts; } } long timestamp = getTimestampInMillis( getUuid() ); properties.put( MESSAGE_TIMESTAMP, timestamp ); return timestamp; } @JsonIgnore public String getType() { return getString( properties, MESSAGE_TYPE ); } @JsonIgnore public synchronized UUID getUuid() { UUID uuid = uuid( properties.get( MESSAGE_ID ), null ); if ( uuid == null ) { if ( properties.containsKey( MESSAGE_TIMESTAMP ) ) { long ts = getLongValue( properties, MESSAGE_TIMESTAMP ); uuid = newTimeUUID( ts ); } else { uuid = newTimeUUID(); } properties.put( MESSAGE_ID, uuid ); properties.put( MESSAGE_TIMESTAMP, getTimestampInMillis( uuid ) ); } return uuid; } @JsonIgnore public boolean isIndexed() { return getBooleanValue( properties, MESSAGE_INDEXED ); } @JsonIgnore public boolean isPersistent() { return getBooleanValue( properties, MESSAGE_PERSISTENT ); } public boolean propertyExists( String name ) { return properties.containsKey( name ); } public void setBooleanProperty( String name, boolean value ) { properties.put( name, value ); } public void setByteProperty( String name, byte value ) { properties.put( name, value ); } public void setCategory( String category ) { if ( category != null ) { properties.put( MESSAGE_CATEGORY, category.toLowerCase() ); } } public void setCorrelationID( String correlationId ) { properties.put( MESSAGE_CORRELATION_ID, correlationId ); } public void setCorrelationIDAsBytes( byte[] correlationId ) { properties.put( MESSAGE_CORRELATION_ID, correlationId ); } public void setCounters( Map<String, Integer> counters ) { if ( counters == null ) { counters = new HashMap<String, Integer>(); } properties.put( "counters", counters ); } public void setDeliveryMode( int arg0 ) { } public void setDestination( Queue destination ) { properties.put( MESSAGE_CORRELATION_ID, destination.toString() ); } public void setDoubleProperty( String name, double value ) { properties.put( name, value ); } public void setExpiration( long expiration ) { } public void setFloatProperty( String name, float value ) { properties.put( name, value ); } public void setIndexed( boolean indexed ) { properties.put( MESSAGE_INDEXED, indexed ); } public void setIntProperty( String name, int value ) { properties.put( name, value ); } public void setLongProperty( String name, long value ) { properties.put( name, value ); } public void setMessageID( String id ) { if ( UUIDUtils.isUUID( id ) ) { properties.put( MESSAGE_ID, UUIDUtils.tryGetUUID( id ) ); } else { throw new RuntimeException( "Not a UUID" ); } } public void setObjectProperty( String name, Object value ) { properties.put( name, value ); } public void setPersistent( boolean persistent ) { properties.put( MESSAGE_PERSISTENT, persistent ); } public void setPriority( int priority ) { } @JsonAnySetter public void setProperty( String key, Object value ) { properties.put( key, value ); } public void setRedelivered( boolean redelivered ) { } public void setReplyTo( Queue destination ) { properties.put( MESSAGE_REPLY_TO, destination.toString() ); } public void setShortProperty( String name, short value ) { properties.put( name, value ); } public void setStringProperty( String name, String value ) { properties.put( name, value ); } public void setTimestamp( long timestamp ) { properties.put( MESSAGE_TIMESTAMP, timestamp ); } public void setType( String type ) { properties.put( MESSAGE_TYPE, type ); } public void setUuid( UUID uuid ) { properties.put(MESSAGE_ID, uuid); properties.put(MESSAGE_TIMESTAMP, UUIDUtils.getTimestampInMillis(uuid)); } public void setTransaction( UUID transaction ) { properties.put( MESSAGE_TRANSACTION, transaction ); } @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) public UUID getTransaction() { return ( UUID ) properties.get( MESSAGE_TRANSACTION ); } public void sync() { getUuid(); getTimestamp(); } }