Tag Archives: Spring Framework

Simple way to integrate BPMN activiti with Spring Integration


BPMN 2 is an popular business process definition and execution standard. Alfresco Activiti is one of the most famous provider. Using BPMN shorten the distance between business and development perspective. It also enable the visibility of any complex business logic. Additionally, it also increase the portability of the business logic with the underline execution engine and therefore make the workflow application become enough flexible to adapt with the rapid change of the business demand.

Continue reading

Spring JMS


Initialize project with ActiveQM Client

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-activemq</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
	</dependencies>	

Enable JMS configuration

@Configuration
@EnableJms
public class IntegrationConfiguration {

}

Add integration layer controller

@Component
public class EmployeeJms {

    @Autowired
    private EmployeeService service;

    @JmsListener(destination = "employee-info-request")
    @SendTo("employee-info-response")
    public String getDepartment(String employeeId) {
        return service.getDepartment(employeeId);
    }
}

Simulation for business

@Service
public class EmployeeService {

    private static final Logger LOGGER = LoggerFactory
        .getLogger(EmployeeService.class);

    public String getDepartment(String employeeId) {
        LOGGER.info("Begin get department info of employee [{}]", employeeId);
        simulateQuery(employeeId, 3);
        LOGGER.info("End get department info of employee [{}]", employeeId);
        return "Technology";
    }

    private void simulateQuery(String employeeId, int processTime) {
        try {
            TimeUnit.SECONDS.sleep(processTime);
        }
        catch (InterruptedException e) {
        }
    }

}

Configure to point to Message Broker

spring:
    application:
        name: spring-jms
    profiles.active: default
    activemq:
        in-memory: false
        broker-url: tcp://activemq-dev:61616
        user: admin
        password: admin
    jms:
        listener:
            auto-startup: true
            concurrency: 3
            max-concurrency: 3

Spring Cloud Config Server pushes local changes


Create the Spring Cloud Config Server application

Add configuration

spring:
    application:
        name: config-server
    profiles:
        active: default
    cloud:
        config:
            retry:
                initialInterval: 100000
                multiplier: 1.1
                maxInterval: 900000
                maxAttempts: 6
            server:
                git:
                    uri: https://gitserver.org/configuration-repository.git
                    label: dev-local
                    search-paths: '*'
                    skipSslValidation: false
                    ignoreLocalSshSettings: true
                    strictHostKeyChecking: false
                    clone-on-start: true
                    force-pull: true
                    basedir: ${user.home}/data/configuration-repository
                    username: test_gitlab
                    password: ENC(07b8RBlZEtbdwVMjUBtlyeFPWBIfoVBl)

Add some extended functions for pushing changes

public class ConfigurationManagementServiceImpl
        implements ConfigurationManagementService {

    private static final Logger LOGGER = LoggerFactory
        .getLogger(ConfigurationManagementServiceImpl.class);

    private Git git = null;

    @Autowired
    private MultipleJGitEnvironmentRepository repository;

    @Override
    public void commitAndPush(
        final String application,
        final String profile,
        final String label,
        final String message) throws Exception {

        this.init();

        // Make the local repository ready
        this.repository.getLocations(application, profile, label);

        this.git.commit().setAll(true).setMessage(message).call();

        this.git.push()
            .setCredentialsProvider(this.repository.getGitCredentialsProvider())
            .call();

        LOGGER.info("Pushed local repository with message [{}].", message);
    }

    @SuppressWarnings("unused")
    private File getWorkingDirectory() {
        return this.repository.getBasedir();
    }

    private void init() throws IOException {
        if (this.git != null) {
            return;
        }

        final String repoPath = this.repository.getBasedir().getPath();
        final Repository localRepo = new FileRepository(repoPath + "/.git");
        this.git = new Git(localRepo);
        LOGGER.info("Initialized local repository at path {}", repoPath);
    }

    @SuppressWarnings("unused")
    private void updateLocalRepo() throws Exception {
        LOGGER.info("Updating the local repository.");
        this.init();
        this.git.pull()
            .setCredentialsProvider(this.repository.getGitCredentialsProvider())
            .call();
    }
}

 

Spring cloud config ActiveMQ


Create a Config Server with following POM:


Add JMS binding for ActiveMQ

Please refer to this release

Update the POM


Update configuration

spring:
    cloud:
        config:
            server:
                git:
                    uri: git@gitserver.org:config-repo.git
                    skipSslValidation: true
                    searchPaths: '{application}'
                    ignoreLocalSshSettings: true
                    strictHostKeyChecking: false
                    host-key: AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKGyq3I/rmrUrmB8yPFogHsrBK/2rN7+WrNJwbaYQgWiY/iK32RVnO7RwslBOEPoODOF8b4CmNUP+z1L0Mo41ik=
                    hostKeyAlgorithm: ssh-rsa
                    clone-on-start: true
                    force-pull: true
                    basedir: ${user.home}/data/config-repo
                    privateKey: |
                        -----BEGIN RSA PRIVATE KEY-----
                        Rg3zqTBX6uSyR7JVwqZI04TOK3wWpRdCt67kjuWGnTclSS0ayg==
                        -----END RSA PRIVATE KEY-----
        bus:
            enabled: true
            trace:
                enabled: false
        stream:
            bindings:
                springCloudBusInput:
                    binder: activemq
                springCloudBusOutput:
                    binder: activemq
    activemq:
        broker-url: tcp://activemq-dev:61616
        in-memory: false
        user: admin
        password: admin

https://stackoverflow.com/questions/35601267/how-to-set-up-spring-cloud-bus-using-activemq

SockJS and WebSocket


WebSocket

Create a simple Spring WebSocket application

Add POM dependencies

  <dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-websocket</artifactId>
  <span data-mce-type="bookmark" id="mce_SELREST_start" data-mce-style="overflow:hidden;line-height:0" style="overflow:hidden;line-height:0" ></span></dependency><span data-mce-type="bookmark" id="mce_SELREST_end" data-mce-style="overflow:hidden;line-height:0" style="overflow:hidden;line-height:0" ></span>

Add WebSocket handler

@Configuration
@EnableWebSocket
public class WebSocketConfiguration implements WebSocketConfigurer {

    @Bean
    SimpleTextWebSocketHandler webSocketHandler() {
        return new SimpleTextWebSocketHandler();
    }

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry
            .addHandler(webSocketHandler(), "/echo")
            .setAllowedOrigins("*");
    }

}
<span data-mce-type="bookmark" id="mce_SELREST_start" data-mce-style="overflow:hidden;line-height:0" style="overflow:hidden;line-height:0" ></span>

In the above configuration, there is important line that is setAllowedOrigins(“*”), if we don’t have this, the WebSocket handshake request could respond with 403 request forbidden.

public class SimpleTextWebSocketHandler extends TextWebSocketHandler {

    private WebSocketSession session;

    @Override
    protected void handleTextMessage(
        WebSocketSession session,
        TextMessage message) throws Exception {
        super.handleTextMessage(session, message);

        System.out.println(message.getPayload());
        session.sendMessage(new TextMessage("Hi"));
    }
}<span data-mce-type="bookmark" id="mce_SELREST_start" data-mce-style="overflow:hidden;line-height:0" style="overflow:hidden;line-height:0" ></span>

Now I have just set up the WebSocket server. Continue, I will test it

Send message from client to server

I use the extension from Chrome for testing

websocket-debug-tool

Open the WebSocket connection

Send a “hii” message to the endpoint and I receive the response immediately

Send message from server to client

WebSocket is a full-duplex, bidirectional connection, so we will try to send a message from server side to client side

Customize the message handler so that I can keep the WebSocket session


public class SimpleTextWebSocketHandler extends TextWebSocketHandler {

    private WebSocketSession session;

    @Override
    protected void handleTextMessage(
        WebSocketSession session,
        TextMessage message) throws Exception {
        this.session = session;
        super.handleTextMessage(session, message);

        System.out.println(message.getPayload());
        session.sendMessage(new TextMessage("Hi"));
    }

    public void sendMessage(String message) {
        if(session!=null) {
            try {
                session.sendMessage(new TextMessage(message));
            }
            catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

By this way, I can send the message to client.

SockJS

Problem with WebSocket

Over the public Internet, restrictive proxies outside your control may preclude WebSocket interactions because:

  • They are not configured to pass on the Upgrade header
  • They close long lived connections that appear idle

Solution from SockJS

It allows applications use a WebSocket API but fall back to non-WebSocket alternatives when necessary at runtime, i.e. without the need to change the application code.

WebSocket

Create a simple Spring WebSocket application

Add POM dependencies

Add WebSocket handler

In the above configuration, there is important line that is setAllowedOrigins(“*”), if we don’t have this, the WebSocket handshake request could respond with 403 request forbidden.

Now I have just set up the WebSocket server. Continue, I will test it

Send message from client to server

I use the extension from Chrome for testing

Open the WebSocket connection

Send a “hii” message to the endpoint and I receive the response immediately

Send message from server to client

WebSocket is a full-duplex, bidirectional connection, so we will try to send a message from server side to client side

Customize the message handler so that I can keep the WebSocket session

By this way, I can send the message to client.

SockJS

Problem with WebSocket

Over the public Internet, restrictive proxies outside your control may preclude WebSocket interactions because:

  • They are not configured to pass on the Upgrade header
  • They close long lived connections that appear idle

Solution from SockJS

It allows applications use a WebSocket API but fall back to non-WebSocket alternatives when necessary at runtime, i.e. without the need to change the application code.

WebSocket problem

http://host:port/myApp/myEndpoint/server-id/session-id/transport

Test

@Bean
    public ServletServerContainerFactoryBean servletServerContainerFactoryBean() {
        final ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
        container
            .setMaxTextMessageBufferSize(
                this.webSocketProperties.getMaxTextBufferSize());
        container
            .setMaxBinaryMessageBufferSize(
                this.webSocketProperties.getMaxBinaryBufferSize());
        return container;
    }<span data-mce-type="bookmark" id="mce_SELREST_start" data-mce-style="overflow:hidden;line-height:0" style="overflow:hidden;line-height:0" ></span>

Test other paragraph

public Integer getMaxBinaryBufferSize() {
return maxBinaryBufferSize;
}

It concludes that…