de.metas.ui.web.vaadin.window.RestProxyWindowModel.java Source code

Java tutorial

Introduction

Here is the source code for de.metas.ui.web.vaadin.window.RestProxyWindowModel.java

Source

package de.metas.ui.web.vaadin.window;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.converter.MappingJackson2MessageConverter;
import org.springframework.messaging.simp.stomp.StompCommand;
import org.springframework.messaging.simp.stomp.StompFrameHandler;
import org.springframework.messaging.simp.stomp.StompHeaders;
import org.springframework.messaging.simp.stomp.StompSession;
import org.springframework.messaging.simp.stomp.StompSessionHandler;
import org.springframework.messaging.simp.stomp.StompSessionHandlerAdapter;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.socket.client.WebSocketClient;
import org.springframework.web.socket.client.standard.StandardWebSocketClient;
import org.springframework.web.socket.messaging.WebSocketStompClient;
import org.springframework.web.socket.sockjs.client.SockJsClient;
import org.springframework.web.socket.sockjs.client.Transport;
import org.springframework.web.socket.sockjs.client.WebSocketTransport;

import com.google.common.eventbus.EventBus;
import com.google.gwt.thirdparty.guava.common.base.Throwables;

import de.metas.logging.LogManager;
import de.metas.ui.web.config.WebSocketConfig;
import de.metas.ui.web.vaadin.VaadinClientApplication;
import de.metas.ui.web.window.PropertyNameSet;
import de.metas.ui.web.window.controller.WindowsRestController;
import de.metas.ui.web.window.datasource.SaveResult;
import de.metas.ui.web.window.model.WindowModel;
import de.metas.ui.web.window.shared.action.ActionsList;
import de.metas.ui.web.window.shared.command.ViewCommand;
import de.metas.ui.web.window.shared.command.ViewCommandResult;
import de.metas.ui.web.window.shared.datatype.PropertyPath;
import de.metas.ui.web.window.shared.datatype.PropertyPathSet;
import de.metas.ui.web.window.shared.datatype.PropertyPathValue;
import de.metas.ui.web.window.shared.datatype.PropertyPathValuesDTO;
import de.metas.ui.web.window.shared.datatype.PropertyValuesDTO;
import de.metas.ui.web.window.shared.descriptor.ViewPropertyDescriptor;
import de.metas.ui.web.window.shared.event.ModelEvent;

/*
 * #%L
 * metasfresh-webui-vaadin
 * %%
 * Copyright (C) 2016 metas GmbH
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program.  If not, see
 * <http://www.gnu.org/licenses/gpl-2.0.html>.
 * #L%
 */

public class RestProxyWindowModel implements WindowModel {
    private static final Logger logger = LogManager.getLogger(RestProxyWindowModel.class);

    private String restEndpointUrl = "http://localhost:8080" + WindowsRestController.ENDPOINT;

    private final EventBus eventBus = new EventBus(getClass().getName());

    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private TaskScheduler taskScheduler;

    private Integer windowNo;

    private ListenableFuture<StompSession> futureWebSocketSession;

    public RestProxyWindowModel() {
        super();
        VaadinClientApplication.autowire(this);

        // WebSocket connection
        {
            final List<Transport> transports = new ArrayList<>(1);
            transports.add(new WebSocketTransport(new StandardWebSocketClient()));
            final WebSocketClient transport = new SockJsClient(transports);
            final WebSocketStompClient stompClient = new WebSocketStompClient(transport);

            stompClient.setMessageConverter(new MappingJackson2MessageConverter());
            stompClient.setTaskScheduler(taskScheduler); // for heartbeats, receipts

            final String url = "ws://127.0.0.1:8080" + WebSocketConfig.ENDPOINT;
            final StompSessionHandler handler = new RestProxyWindowModel_StompSessionHandler();
            futureWebSocketSession = stompClient.connect(url, handler);
        }
    }

    private final void subscribeToWindowNoWebSocket(final int windowNo) {
        try {
            final StompSession session = futureWebSocketSession.get(10, TimeUnit.SECONDS);
            session.subscribe(WebSocketConfig.buildWindowTopicName(windowNo),
                    new RestProxyWindowModel_StompFrameHandler());
        } catch (final Exception e) {
            throw Throwables.propagate(e);
        }
    }

    private final String buildURL(final String path) {
        return restEndpointUrl + path;
    }

    private final String buildWindowNoURL(final String operation) {
        final String params = null;
        return buildWindowNoURL(operation, params);
    }

    private final String buildWindowNoURL(final String operation, final String params) {
        if (windowNo == null) {
            throw new IllegalStateException("Window not created yet");
        }
        String url = buildURL(operation + "/" + windowNo);

        if (params != null) {
            if (!params.startsWith("/")) {
                url += "/";
            }
            url += params;
        }

        return url;
    }

    @Override
    public void setRootPropertyDescriptorFromWindow(final int windowId) {
        final int windowNo = restTemplate.getForObject(buildURL("/openWindow/" + windowId), Integer.class);
        this.windowNo = windowNo;

        subscribeToWindowNoWebSocket(windowNo);
    }

    @Override
    public void subscribe(final Object subscriberObj) {
        eventBus.register(subscriberObj);
    }

    @Override
    public void unsubscribe(final Object subscriberObj) {
        eventBus.unregister(subscriberObj);
    }

    @Override
    public ViewPropertyDescriptor getViewRootPropertyDescriptor() {
        return restTemplate.getForObject(buildWindowNoURL("/getViewRootPropertyDescriptor"),
                ViewPropertyDescriptor.class);
    }

    @Override
    public boolean hasPreviousRecord() {
        return restTemplate.getForObject(buildWindowNoURL("/hasPreviousRecord"), Boolean.class);
    }

    @Override
    public boolean hasNextRecord() {
        return restTemplate.getForObject(buildWindowNoURL("/hasNextRecord"), Boolean.class);
    }

    @Override
    public PropertyValuesDTO getPropertyValuesDTO(final PropertyNameSet selectedPropertyNames) {
        return restTemplate.postForObject(buildWindowNoURL("/getPropertyValues"), selectedPropertyNames,
                PropertyValuesDTO.class);
    }

    @Override
    public PropertyPathValuesDTO getPropertyPathValuesDTO(final PropertyPathSet selectedPropertyPaths) {
        return restTemplate.postForObject(buildWindowNoURL("/getPropertyPathValues"), selectedPropertyPaths,
                PropertyPathValuesDTO.class);
    }

    @Override
    public boolean hasProperty(final PropertyPath propertyPath) {
        return restTemplate.postForObject(buildWindowNoURL("/hasProperty"), propertyPath, Boolean.class);
    }

    @Override
    public void setProperty(final PropertyPath propertyPath, final Object value) {
        final PropertyPathValue propertyPathValue = PropertyPathValue.of(propertyPath, value);
        restTemplate.postForObject(buildWindowNoURL("/setProperty"), propertyPathValue, Void.class);
    }

    @Override
    public Object getProperty(final PropertyPath propertyPath) {
        final PropertyPathSet selectedPropertyPaths = PropertyPathSet.of(propertyPath);
        final PropertyPathValuesDTO values = getPropertyPathValuesDTO(selectedPropertyPaths);
        if (!values.containsKey(propertyPath)) {
            throw new RuntimeException("ProperyPath " + propertyPath + " does not exist");
        }
        return values.get(propertyPath);
    }

    @Override
    public Object getPropertyOrNull(final PropertyPath propertyPath) {
        final PropertyPathSet selectedPropertyPaths = PropertyPathSet.of(propertyPath);
        final PropertyPathValuesDTO values = getPropertyPathValuesDTO(selectedPropertyPaths);
        return values.get(propertyPath);
    }

    @Override
    public void newRecordAsCopyById(final Object recordId) {
        // TODO Auto-generated method stub
        // NOTE: not needed
        throw new UnsupportedOperationException();
    }

    @Override
    public SaveResult saveRecord() {
        return restTemplate.getForObject(buildWindowNoURL("saveRecord"), SaveResult.class);
    }

    @Override
    public ActionsList getActions() {
        return restTemplate.getForObject(buildWindowNoURL("/getActions"), ActionsList.class);
    }

    @Override
    public ActionsList getChildActions(final String actionId) {
        return restTemplate.getForObject(buildWindowNoURL("/getChildActions", actionId), ActionsList.class);
    }

    @Override
    public void executeAction(final String actionId) {
        restTemplate.getForObject(buildWindowNoURL("/executeAction", actionId), Void.class);
    }

    @Override
    public ViewCommandResult executeCommand(final ViewCommand command) throws Exception {
        final String url = buildWindowNoURL("/executeCommand");

        logger.debug("Executing command {} on ", command, url);
        final ViewCommandResult result = restTemplate.postForObject(url, command, ViewCommandResult.class);
        logger.debug("Got result for command on {}: {}", command, result);

        return result;
    }

    private final class RestProxyWindowModel_StompSessionHandler extends StompSessionHandlerAdapter {
        @Override
        public void afterConnected(final StompSession session, final StompHeaders connectedHeaders) {
            System.out.println(
                    "websocket-client after connected: session=" + session + ", headers=" + connectedHeaders);
        }

        @Override
        public void handleFrame(final StompHeaders headers, final Object payload) {
            System.out.println("websocket-client handleFrame: headers=" + headers + ", payload=" + payload);
        }

        @Override
        public void handleException(final StompSession session, final StompCommand command,
                final StompHeaders headers, final byte[] payload, final Throwable exception) {
            System.err.println("websocket-client handleException: session=" + session + ", command=" + command
                    + ", headers=" + headers);
            exception.printStackTrace();
        }

        /**
         * This implementation is empty.
         */
        @Override
        public void handleTransportError(final StompSession session, final Throwable exception) {
            System.err.println("websocket-client handleTransportError: session=" + session);
            exception.printStackTrace();
        }

    }

    private final class RestProxyWindowModel_StompFrameHandler implements StompFrameHandler {

        @Override
        public Type getPayloadType(final StompHeaders headers) {
            return ModelEvent.class;
        }

        @Override
        public void handleFrame(final StompHeaders headers, final Object payload) {
            System.out.println(
                    "websocket-client - frame handler - handleFrame: headers=" + headers + ", payload=" + payload);

            final ModelEvent event = (ModelEvent) payload;
            eventBus.post(event);
        }

    }
}