Add strategy for customizing ID/TIMESTAMP headers

Introduce MessageHeaderInitializer strategy for initializing a
MessageHeaderAccessor.

Add IdTimestampMessageHeaderInitializer implementation that provides
control over ID and timestamp header generation.

Disable ID and timestamp by default in SimpMessageHeaderAccessor and
therefore its sub-class StompHeaderAccessor.

Issue: SPR-11468
This commit is contained in:
Rossen Stoyanchev
2014-04-14 13:46:32 -04:00
parent 09248a0b37
commit 95e25d4e6f
11 changed files with 168 additions and 349 deletions

View File

@@ -1,70 +0,0 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* 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.springframework.messaging.simp;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.support.MessageHeaderAccessorFactorySupport;
import org.springframework.util.IdGenerator;
import java.util.UUID;
/**
* A default implementation of
* {@link org.springframework.messaging.simp.SimpMessageHeaderAccessorFactory}.
*
* @author Rossen Stoyanchev
* @since 4.1
*/
public class DefaultSimpMessageHeaderAccessorFactory extends MessageHeaderAccessorFactorySupport
implements SimpMessageHeaderAccessorFactory {
public DefaultSimpMessageHeaderAccessorFactory() {
super.setIdGenerator(ID_VALUE_NONE_GENERATOR);
}
@Override
public SimpMessageHeaderAccessor create() {
SimpMessageHeaderAccessor accessor = new SimpMessageHeaderAccessor(SimpMessageType.MESSAGE, null);
updateMessageHeaderAccessor(accessor);
return accessor;
}
@Override
public SimpMessageHeaderAccessor create(SimpMessageType messageType) {
SimpMessageHeaderAccessor accessor = new SimpMessageHeaderAccessor(messageType, null);
updateMessageHeaderAccessor(accessor);
return accessor;
}
@Override
public SimpMessageHeaderAccessor wrap(Message<?> message) {
SimpMessageHeaderAccessor accessor = new SimpMessageHeaderAccessor(message);
updateMessageHeaderAccessor(accessor);
return accessor;
}
private static final IdGenerator ID_VALUE_NONE_GENERATOR = new IdGenerator() {
@Override
public UUID generateId() {
return MessageHeaders.ID_VALUE_NONE;
}
};
}

View File

@@ -21,7 +21,7 @@ import java.util.List;
import java.util.Map;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.support.IdTimestampMessageHeaderInitializer;
import org.springframework.messaging.support.MessageHeaderAccessor;
import org.springframework.messaging.support.NativeMessageHeaderAccessor;
import org.springframework.util.Assert;
@@ -40,7 +40,13 @@ import org.springframework.util.Assert;
*/
public class SimpMessageHeaderAccessor extends NativeMessageHeaderAccessor {
private static final SimpMessageHeaderAccessorFactory factory = new DefaultSimpMessageHeaderAccessorFactory();
private static final IdTimestampMessageHeaderInitializer headerInitializer;
static {
headerInitializer = new IdTimestampMessageHeaderInitializer();
headerInitializer.setDisableIdGeneration();
headerInitializer.setEnableTimestamp(false);
}
// SiMP header names
@@ -77,6 +83,7 @@ public class SimpMessageHeaderAccessor extends NativeMessageHeaderAccessor {
super(externalSourceHeaders);
Assert.notNull(messageType, "MessageType must not be null");
setHeader(MESSAGE_TYPE_HEADER, messageType);
headerInitializer.initHeaders(this);
}
/**
@@ -85,6 +92,7 @@ public class SimpMessageHeaderAccessor extends NativeMessageHeaderAccessor {
*/
protected SimpMessageHeaderAccessor(Message<?> message) {
super(message);
headerInitializer.initHeaders(this);
}
@@ -93,7 +101,7 @@ public class SimpMessageHeaderAccessor extends NativeMessageHeaderAccessor {
* {@link org.springframework.messaging.simp.SimpMessageType} {@code MESSAGE}.
*/
public static SimpMessageHeaderAccessor create() {
return factory.create();
return new SimpMessageHeaderAccessor(SimpMessageType.MESSAGE, null);
}
/**
@@ -101,20 +109,20 @@ public class SimpMessageHeaderAccessor extends NativeMessageHeaderAccessor {
* {@link org.springframework.messaging.simp.SimpMessageType}.
*/
public static SimpMessageHeaderAccessor create(SimpMessageType messageType) {
return factory.create(messageType);
return new SimpMessageHeaderAccessor(messageType, null);
}
/**
* Create an instance from the payload and headers of the given Message.
*/
public static SimpMessageHeaderAccessor wrap(Message<?> message) {
return factory.wrap(message);
return new SimpMessageHeaderAccessor(message);
}
@Override
protected MessageHeaderAccessor createAccessor(Message<?> message) {
return factory.wrap(message);
return wrap(message);
}
public void setMessageTypeIfNotSet(SimpMessageType messageType) {

View File

@@ -1,48 +0,0 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* 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.springframework.messaging.simp;
import org.springframework.messaging.Message;
/**
* A factory for creating pre-configured instances of type
* {@link org.springframework.messaging.simp.SimpMessageHeaderAccessor}.
*
* @author Rossen Stoyanchev
* @since 4.1
*/
public interface SimpMessageHeaderAccessorFactory {
/**
* Create an instance with
* {@link org.springframework.messaging.simp.SimpMessageType} {@code MESSAGE}.
*/
SimpMessageHeaderAccessor create();
/**
* Create an instance with the given
* {@link org.springframework.messaging.simp.SimpMessageType}.
*/
SimpMessageHeaderAccessor create(SimpMessageType messageType);
/**
* Create an instance from the payload and headers of the given Message.
*/
SimpMessageHeaderAccessor wrap(Message<?> message);
}

View File

@@ -1,78 +0,0 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* 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.springframework.messaging.simp.stomp;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.support.MessageHeaderAccessorFactorySupport;
import org.springframework.util.IdGenerator;
import java.util.List;
import java.util.Map;
import java.util.UUID;
/**
* A default implementation of
* {@link org.springframework.messaging.simp.stomp.StompHeaderAccessorFactory}.
*
* @author Rossen Stoyanchev
* @since 4.1
*/
public class DefaultStompHeaderAccessorFactory extends MessageHeaderAccessorFactorySupport
implements StompHeaderAccessorFactory {
public DefaultStompHeaderAccessorFactory() {
super.setIdGenerator(ID_VALUE_NONE_GENERATOR);
}
@Override
public StompHeaderAccessor create(StompCommand command) {
StompHeaderAccessor accessor = new StompHeaderAccessor(command, null);
updateMessageHeaderAccessor(accessor);
return accessor;
}
@Override
public StompHeaderAccessor create(StompCommand command, Map<String, List<String>> headers) {
StompHeaderAccessor accessor = new StompHeaderAccessor(command, headers);
updateMessageHeaderAccessor(accessor);
return accessor;
}
@Override
public StompHeaderAccessor createForHeartbeat() {
StompHeaderAccessor accessor = new StompHeaderAccessor();
updateMessageHeaderAccessor(accessor);
return accessor;
}
@Override
public StompHeaderAccessor wrap(Message<?> message) {
StompHeaderAccessor accessor = new StompHeaderAccessor(message);
updateMessageHeaderAccessor(accessor);
return accessor;
}
private static final IdGenerator ID_VALUE_NONE_GENERATOR = new IdGenerator() {
@Override
public UUID generateId() {
return MessageHeaders.ID_VALUE_NONE;
}
};
}

View File

@@ -30,7 +30,6 @@ import org.springframework.messaging.support.MessageHeaderAccessor;
import org.springframework.util.Assert;
import org.springframework.util.MimeType;
import org.springframework.util.MimeTypeUtils;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
/**
@@ -59,8 +58,6 @@ import org.springframework.util.StringUtils;
*/
public class StompHeaderAccessor extends SimpMessageHeaderAccessor {
private static final StompHeaderAccessorFactory factory = new DefaultStompHeaderAccessorFactory();
private static final AtomicLong messageIdCounter = new AtomicLong();
private static final long[] DEFAULT_HEARTBEAT = new long[] {0, 0};
@@ -176,14 +173,14 @@ public class StompHeaderAccessor extends SimpMessageHeaderAccessor {
* Create an instance for the given STOMP command.
*/
public static StompHeaderAccessor create(StompCommand command) {
return factory.create(command);
return new StompHeaderAccessor(command, null);
}
/**
* Create an instance for the given STOMP command and headers.
*/
public static StompHeaderAccessor create(StompCommand command, Map<String, List<String>> headers) {
return factory.create(command, headers);
return new StompHeaderAccessor(command, headers);
}
/**
@@ -191,20 +188,20 @@ public class StompHeaderAccessor extends SimpMessageHeaderAccessor {
* have headers, a session id is needed for processing purposes at a minimum.
*/
public static StompHeaderAccessor createForHeartbeat() {
return factory.createForHeartbeat();
return new StompHeaderAccessor();
}
/**
* Create an instance from the payload and headers of the given Message.
*/
public static StompHeaderAccessor wrap(Message<?> message) {
return factory.wrap(message);
return new StompHeaderAccessor(message);
}
@Override
protected MessageHeaderAccessor createAccessor(Message<?> message) {
return factory.wrap(message);
return wrap(message);
}
Map<String, List<String>> getNativeHeaders() {

View File

@@ -1,55 +0,0 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* 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.springframework.messaging.simp.stomp;
import org.springframework.messaging.Message;
import java.util.List;
import java.util.Map;
/**
* A factory for creating pre-configured instances of type
* {@link org.springframework.messaging.simp.stomp.StompHeaderAccessor}.
*
* @author Rossen Stoyanchev
* @since 4.1
*/
public interface StompHeaderAccessorFactory {
/**
* Create an instance for the given STOMP command.
*/
StompHeaderAccessor create(StompCommand command);
/**
* Create an instance for the given STOMP command and headers.
*/
StompHeaderAccessor create(StompCommand command, Map<String, List<String>> headers);
/**
* Create headers for a heartbeat. While a STOMP heartbeat frame does not
* have headers, a session id is needed for processing purposes at a minimum.
*/
StompHeaderAccessor createForHeartbeat();
/**
* Create an instance from the payload and headers of the given Message.
*/
StompHeaderAccessor wrap(Message<?> message);
}

View File

@@ -0,0 +1,100 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* 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.springframework.messaging.support;
import org.springframework.messaging.MessageHeaders;
import org.springframework.util.IdGenerator;
import java.util.UUID;
/**
* A {@link org.springframework.messaging.support.MessageHeaderInitializer MessageHeaderInitializer}
* to customize the strategy for ID and TIMESTAMP message header generation.
*
* @author Rossen Stoyanchev
* @since 4.1
*/
public class IdTimestampMessageHeaderInitializer implements MessageHeaderInitializer {
private IdGenerator idGenerator;
private boolean enableTimestamp;
/**
* Configure the IdGenerator strategy to initialize {@code MessageHeaderAccessor}
* instances with.
*
* <p>By default this property is set to {@code null} in which case the default
* IdGenerator of {@link org.springframework.messaging.MessageHeaders} is used.
*
* <p>To have no id's generated at all, see {@@link #setDisableIdGeneration()}.
*/
public void setIdGenerator(IdGenerator idGenerator) {
this.idGenerator = idGenerator;
}
/**
* A shortcut for calling
* {@link #setIdGenerator(org.springframework.util.IdGenerator)} with an
* id generation strategy to
*
*/
public void setDisableIdGeneration() {
this.idGenerator = ID_VALUE_NONE_GENERATOR;
}
/**
* @return the configured {@code IdGenerator} if any.
*/
public IdGenerator getIdGenerator() {
return this.idGenerator;
}
/**
* Whether to enable the automatic addition of the
* {@link org.springframework.messaging.MessageHeaders#TIMESTAMP} header on
* {@code MessageHeaderAccessor} instances being initialized.
*
* <p>By default this property is set to false.
*/
public void setEnableTimestamp(boolean enableTimestamp) {
this.enableTimestamp = enableTimestamp;
}
/**
* @return Whether the timestamp header is enabled or not.
*/
public boolean isEnableTimestamp() {
return this.enableTimestamp;
}
@Override
public void initHeaders(MessageHeaderAccessor headerAccessor) {
headerAccessor.setIdGenerator(getIdGenerator());
headerAccessor.setEnableTimestamp(isEnableTimestamp());
}
private static final IdGenerator ID_VALUE_NONE_GENERATOR = new IdGenerator() {
@Override
public UUID generateId() {
return MessageHeaders.ID_VALUE_NONE;
}
};
}

View File

@@ -129,11 +129,6 @@ public class MessageHeaderAccessor {
public MessageHeaderAccessor(Message<?> message) {
if (message != null) {
this.headers = new MutableMessageHeaders(message.getHeaders());
MessageHeaderAccessor accessor = getAccessor(message, MessageHeaderAccessor.class);
if (accessor != null) {
this.idGenerator = accessor.idGenerator;
this.enableTimestamp = accessor.enableTimestamp;
}
}
else {
this.headers = new MutableMessageHeaders();
@@ -276,23 +271,24 @@ public class MessageHeaderAccessor {
}
/**
* A private mechanism for providing an alternate IdGenerator strategy.
* A package private mechanism to configure the IdGenerator strategy to use.
*
* <p>By default this property is not set in which case the default IdGenerator
* of {@link org.springframework.messaging.MessageHeaders} is used.
* in {@link org.springframework.messaging.MessageHeaders} is used.
*
* @see org.springframework.messaging.support.MessageHeaderAccessorFactorySupport
* @see org.springframework.messaging.support.IdTimestampMessageHeaderInitializer
*/
void setIdGenerator(IdGenerator idGenerator) {
this.idGenerator = idGenerator;
}
/**
* A private mechanism to enable having a timestamp added to every message.
* A package private mechanism to enables the automatic addition of the
* {@link org.springframework.messaging.MessageHeaders#TIMESTAMP} header.
*
* <p>By default this property is set to false.
*
* @see org.springframework.messaging.support.MessageHeaderAccessorFactorySupport
* @see org.springframework.messaging.support.IdTimestampMessageHeaderInitializer
*/
void setEnableTimestamp(boolean enableTimestamp) {
this.enableTimestamp = enableTimestamp;

View File

@@ -1,67 +0,0 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* 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.springframework.messaging.support;
import org.springframework.util.IdGenerator;
/**
* A support class for factories creating pre-configured instances of type
* {@link org.springframework.messaging.support.MessageHeaderAccessor}.
*
* @author Rossen Stoyanchev
* @since 4.1
*/
public class MessageHeaderAccessorFactorySupport {
private IdGenerator idGenerator;
private Boolean enableTimestamp;
protected MessageHeaderAccessorFactorySupport() {
}
/**
*
* @param idGenerator
*/
public void setIdGenerator(IdGenerator idGenerator) {
this.idGenerator = idGenerator;
}
public IdGenerator getIdGenerator() {
return this.idGenerator;
}
public void setEnableTimestamp(boolean enableTimestamp) {
this.enableTimestamp = enableTimestamp;
}
public boolean isEnableTimestamp() {
return this.enableTimestamp;
}
protected void updateMessageHeaderAccessor(MessageHeaderAccessor headerAccessor) {
if (this.idGenerator != null) {
headerAccessor.setIdGenerator(this.idGenerator);
}
if (this.enableTimestamp != null) {
headerAccessor.setEnableTimestamp(this.enableTimestamp);
}
}
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* 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.springframework.messaging.support;
/**
* Callback interface for initializing a
* {@link org.springframework.messaging.support.MessageHeaderAccessor MessageHeaderAccessor}.
*
* @author Rossen Stoyanchev
* @since 4.1
*/
public interface MessageHeaderInitializer {
/**
* Initialize the given {@code MessageHeaderAccessor}.
*
* @param headerAccessor the instance to initialize
*/
void initHeaders(MessageHeaderAccessor headerAccessor);
}