title: how to run a chat application with jhipster
body: <p>i'm trying to build a chat application with jhipster 5 using spring websocket.
  those are the files that i created and configured : </p>
  
  <p>backend:</p>
  
  <p>// WebsocketConfiguration.java</p>
  
  <pre><code>
      public static final String IP_ADDRESS = "IP_ADDRESS";
  
      private final JHipsterProperties jHipsterProperties;
  
      public WebsocketConfiguration(JHipsterProperties jHipsterProperties) {
          this.jHipsterProperties = jHipsterProperties;
      }
  
      @Override
      public void configureMessageBroker(MessageBrokerRegistry config) {
          config.enableSimpleBroker("/topic", "/chat");
      }
  
      @Override
      public void registerStompEndpoints(StompEndpointRegistry registry) {
          String[] allowedOrigins = Optional.ofNullable(jHipsterProperties.getCors().getAllowedOrigins()).map(origins -&gt; origins.toArray(new String[0])).orElse(new String[0]);
          registry.addEndpoint("/websocket/tracker", "/websocket/chat")
              .setHandshakeHandler(defaultHandshakeHandler())
              .setAllowedOrigins(allowedOrigins)
              .withSockJS()
              .setInterceptors(httpSessionHandshakeInterceptor());
      }
  
      @Bean
      public HandshakeInterceptor httpSessionHandshakeInterceptor() {
          return new HandshakeInterceptor() {
  
              @Override
              public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map&lt;String, Object&gt; attributes) throws Exception {
                  if (request instanceof ServletServerHttpRequest) {
                      ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
                      attributes.put(IP_ADDRESS, servletRequest.getRemoteAddress());
                  }
                  return true;
              }
  
              @Override
              public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {
  
              }
          };
      }
  
      private DefaultHandshakeHandler defaultHandshakeHandler() {
          return new DefaultHandshakeHandler() {
              @Override
              protected Principal determineUser(ServerHttpRequest request, WebSocketHandler wsHandler, Map&lt;String, Object&gt; attributes) {
                  Principal principal = request.getPrincipal();
                  if (principal == null) {
                      Collection&lt;SimpleGrantedAuthority&gt; authorities = new ArrayList&lt;&gt;();
                      authorities.add(new SimpleGrantedAuthority(AuthoritiesConstants.ANONYMOUS));
                      principal = new AnonymousAuthenticationToken("WebsocketConfiguration", "anonymous", authorities);
                  }
                  return principal;
              }
          };
      }
  }
  </code></pre>
  
  <p>// ChatService.java</p>
  
  <pre><code>    private static final Logger log = LoggerFactory.getLogger(ChatService.class);
  
      private DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
  
      private final SimpMessageSendingOperations messagingTemplate;
  
      public ChatService(SimpMessageSendingOperations messagingTemplate) {
          this.messagingTemplate = messagingTemplate;
      }
  
  
      @SubscribeMapping("/chat/public")
      public void subscribe(StompHeaderAccessor stompHeaderAccessor, Principal principal) {
          String login =principal.getName();
          String ipAddress = stompHeaderAccessor.getSessionAttributes().get(IP_ADDRESS).toString();
          log.debug("User {} subscribed to Chat from IP {}", login, ipAddress);
          MessageDTO messageDTO = new MessageDTO();
          messageDTO.setUserLogin("System");
          messageDTO.setTime(dateTimeFormatter.format(ZonedDateTime.now()));
          messageDTO.setMessage(login + " joined the chat");
          messagingTemplate.convertAndSend("/chat/public", messageDTO);
      }
  
      @MessageMapping("/chat")
      @SendTo("/chat/public")
      public MessageDTO sendChat(@Payload MessageDTO messageDTO, StompHeaderAccessor stompHeaderAccessor, Principal principal) {
          messageDTO.setUserLogin(principal.getName());
          return setupMessageDTO(messageDTO, stompHeaderAccessor, principal);
      }
  
      @Override
      public void onApplicationEvent(SessionDisconnectEvent event) {
          // when the user disconnects, send a message saying that hey are leaving
          log.info("{} disconnected from the chat websockets", event.getUser().getName());
          MessageDTO messageDTO = new MessageDTO();
          messageDTO.setUserLogin("System");
          messageDTO.setTime(dateTimeFormatter.format(ZonedDateTime.now()));
          messageDTO.setMessage(event.getUser().getName() + " left the chat");
          messagingTemplate.convertAndSend("/chat/public", messageDTO);
      }
  
      private MessageDTO setupMessageDTO (MessageDTO messageDTO, StompHeaderAccessor stompHeaderAccessor, Principal principal) {
          messageDTO.setTime(dateTimeFormatter.format(ZonedDateTime.now()));
          log.debug("Sending user chat data {}", messageDTO);
          return messageDTO;
      }
  }
  </code></pre>
  
  <p>frontend :</p>
  
  <p>//chat.service.ts</p>
  
  <pre><code>    constructor(
          private router: Router,
          private authServerProvider: AuthServerProvider,
          private $document: Document,
          private $window: Window,
          private csrfService: CSRFService
      ) {
          this.connection = this.createConnection();
          this.listener = this.createListener();
      }
  
      connect() {
          if (this.connectedPromise === null) {
            this.connection = this.createConnection();
          }
          // building absolute path so that websocket doesnt fail when 
       deploying with a context path
          const loc = this.$window.location;
          let url = '//' + loc.host + loc.pathname + 'websocket/chat';
          const authToken = this.authServerProvider.getToken();
          if (authToken) {
              url += '?access_token=' + authToken;
          }
          const socket = new SockJS(url);
          this.stompClient = Stomp.over(socket);
          const headers = {};
          this.stompClient.connect(headers, () =&gt; {
              this.connectedPromise('success');
              this.connectedPromise = null;
              this.subscribe();
              if (!this.alreadyConnectedOnce) {
                  this.alreadyConnectedOnce = true;
              }
          });
      }
  
      disconnect() {
          if (this.stompClient !== null) {
              this.stompClient.disconnect();
              this.stompClient = null;
          }
          if (this.subscription) {
              this.subscription.unsubscribe();
              this.subscription = null;
          }
          this.alreadyConnectedOnce = false;
      }
  
      receive() {
          return this.listener;
      }
  
      sendMessage(message) {
          if (this.stompClient !== null &amp;&amp; this.stompClient.connected) {
              this.stompClient.send(
                  '/chat', // destination
                  JSON.stringify({'message': message}), // body
                  {} // header
              );
          }
      }
  
      subscribe() {
          this.connection.then(() =&gt; {
              this.subscriber = this.stompClient.subscribe('/chat/public', data 
      =&gt; {
                  this.listenerObserver.next(JSON.parse(data.body));
              });
          });
      }
  
      unsubscribe() {
          if (this.subscriber !== null) {
              this.subscriber.unsubscribe();
          }
          this.listener = this.createListener();
      }
  
      private createListener(): Observable&lt;any&gt; {
          return new Observable(observer =&gt; {
              this.listenerObserver = observer;
          });
      }
  
      private createConnection(): Promise&lt;any&gt; {
          return new Promise((resolve, reject) =&gt; this.connectedPromise = 
      resolve);
      }
  </code></pre>
  
  <p>//chat.component.ts</p>
  
  <pre><code>messages: Array&lt;Object&gt; = [];
      message = '';
      constructor(private chatService: ChatService) { }
  
     ngOnInit() {
          this.chatService.connect();
  
          this.chatService.receive().subscribe(message =&gt; {
              this.messages.push(message);
          });
     }
  
      ngOnDestroy() {
          this.chatService.unsubscribe();
      }
  
      sendMessage(message) {
          if (message.length === 0) {
              return;
          }
          this.chatService.sendMessage(message);
          this.message = '';
      }    
  
  </code></pre>
  
  <p>when i run ./mvnw or npm start a blank page appears. i can't find the problem. </p>
  
  <p>this is the error on my console browser :</p>
  
  <pre><code>ERROR Error: Uncaught (in promise): Error: StaticInjectorError(ChatFinalAppModule)[Document]: 
    StaticInjectorError(Platform: core)[Document]: 
      NullInjectorError: No provider for Document!
  Error: StaticInjectorError(ChatFinalAppModule)[Document]: 
    StaticInjectorError(Platform: core)[Document]: 
      NullInjectorError: No provider for Document!
      at NullInjector.get (core.js?09c9:8894)
      at resolveToken (core.js?09c9:9139)
      at tryResolveToken (core.js?09c9:9083)
      at StaticInjector.get (core.js?09c9:8980)
      at resolveToken (core.js?09c9:9139)
      at tryResolveToken (core.js?09c9:9083)
      at StaticInjector.get (core.js?09c9:8980)
      at resolveNgModuleDep (core.js?09c9:21119)
      at NgModuleRef_.get (core.js?09c9:21808)
      at injectInjectorOnly (core.js?09c9:1772)
      at resolvePromise (zone.js?d135:831)
      at resolvePromise (zone.js?d135:788)
      at eval (zone.js?d135:892)
      at ZoneDelegate.invokeTask (zone.js?d135:423)
      at Object.onInvokeTask (core.js?09c9:17279)
      at ZoneDelegate.invokeTask (zone.js?d135:422)
      at Zone.runTask (zone.js?d135:195)
      at drainMicroTaskQueue (zone.js?d135:601)
      at ZoneTask.invokeTask (zone.js?d135:502)
      at ZoneTask.invoke (zone.js?d135:487)
  </code></pre>
  
  <p>this is my mvnw error :</p>
  
  <pre><code>2019-04-28 23:28:43.153 DEBUG 12652 --- [  XNIO-2 task-2] c.p.a.aop.logging.LoggingAspect          : Enter: com.pu.askanexpert.repository.CustomAuditEventRepository.add() with argument[s] = [AuditEvent [timestamp=2019-04-28T21:28:43.136Z, principal=anonymousUser, type=AUTHORIZATION_FAILURE, data={details=org.springframework.security.web.authentication.WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: null, type=org.springframework.security.access.AccessDeniedException, message=Access is denied}]]
  2019-04-28 23:28:43.163 DEBUG 12652 --- [  XNIO-2 task-2] c.p.a.aop.logging.LoggingAspect          : Exit: com.pu.askanexpert.repository.CustomAuditEventRepository.add() with result = null
  2019-04-28 23:28:43.179  WARN 12652 --- [  XNIO-2 task-2] o.z.problem.spring.common.AdviceTrait    : Unauthorized: Full authentication is required to access this resource
  2019-04-28 23:28:43.294  WARN 12652 --- [  XNIO-2 task-2] .m.m.a.ExceptionHandlerExceptionResolver : Resolved exception caused by handler execution: org.springframework.security.authentication.InsufficientAuthenticationException: Full authentication is required to access this resource
  </code></pre>
  
  <p>this is my mvn logs when i sign in with admin account :</p>
  
  <pre><code>2019-04-29 09:55:46.638 DEBUG 8356 --- [  XNIO-2 task-5] c.p.a.aop.logging.LoggingAspect          : Enter: com.pu.askanexpert.web.rest.AccountResource.getAccount() with argument[s] = []
  2019-04-29 09:55:46.650 DEBUG 8356 --- [  XNIO-2 task-5] c.p.a.aop.logging.LoggingAspect          : Enter: com.pu.askanexpert.service.UserService.getUserWithAuthorities() with argument[s] = []
  2019-04-29 09:55:46.680 DEBUG 8356 --- [  XNIO-2 task-5] c.p.a.aop.logging.LoggingAspect          : Exit: com.pu.askanexpert.service.UserService.getUserWithAuthorities() with result = Optional[User{login='admin', firstName='Administrator', lastName='Administrator', email='admin@localhost', imageUrl='', activated='true', langKey='en', activationKey='null'}]
  2019-04-29 09:55:46.684 DEBUG 8356 --- [  XNIO-2 task-5] c.p.a.aop.logging.LoggingAspect          : Exit: com.pu.askanexpert.web.rest.AccountResource.getAccount() with result = UserDTO{login='admin', firstName='Administrator', lastName='Administrator', email='admin@localhost', imageUrl='', activated=true, langKey='en', createdBy=system, createdDate=null, lastModifiedBy='system', lastModifiedDate=null, authorities=[ROLE_USER, ROLE_ADMIN]}
  2019-04-29 09:55:47.025 DEBUG 8356 --- [nboundChannel-4] c.p.a.web.websocket.ActivityService      : Sending user tracking data ActivityDTO{sessionId='yycjs1vs', userLogin='admin', ipAddress='/127.0.0.1:14640', page='/', time='2019-04-29T07:55:47.025Z'}
  2019-04-29 09:58:27.638  INFO 8356 --- [   XNIO-2 I/O-1] c.p.a.web.websocket.ChatService          : admin disconnected from the chat websockets
  </code></pre>