/* * Copyright 2015-2016 Red Hat, Inc. and/or its affiliates * and other contributors as indicated by the @author tags. * * 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.hawkular.inventory.websocket; import java.io.IOException; import java.util.Arrays; import java.util.Map; import java.util.Optional; import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; import javax.websocket.OnClose; import javax.websocket.OnError; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; import org.hawkular.inventory.api.Action; import org.hawkular.inventory.api.Interest; import org.hawkular.inventory.api.Inventory; import org.hawkular.inventory.paths.SegmentType; import org.hawkular.inventory.rest.RestEvents; import org.hawkular.inventory.rest.Utils; import org.hawkular.inventory.rest.cdi.AutoTenant; import org.hawkular.inventory.rest.cdi.Our; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.Maps; import rx.Subscription; /** * @author Jirka Kremser */ @ApplicationScoped @ServerEndpoint("/ws/events") public class WebsocketEvents { private Map<Session, Subscription> subscriptions = Maps.newHashMap(); @Inject @AutoTenant protected Inventory inventory; @Inject @Our protected ObjectMapper mapper; @OnOpen public void open(Session session) { WebsocketApiLogger.LOGGER.sessionOpened(session.getId()); Map<String, String> queryParamStringMap = parseQueryParams(session); final String type = queryParamStringMap.getOrDefault(QueryParam.type.name(), QueryParam.type.getDefaultValue()); final String actionString = queryParamStringMap.getOrDefault(QueryParam.action.name(), QueryParam.action.getDefaultValue()); final String tenantId = queryParamStringMap.getOrDefault(QueryParam.tenantId.name(), QueryParam.tenantId.getDefaultValue()); if (tenantId == null) { session.getAsyncRemote().sendText("Provide the tenantId query parameter."); closeSession(session); return; } SegmentType st = Utils.getSegmentTypeFromSimpleName(type); Class cls = Inventory.types().bySegment(st).getElementType(); if (cls == null) { session.getAsyncRemote().sendText("Unknown type: " + type); closeSession(session); return; } Action.Enumerated actionEnumItem; try { actionEnumItem = Action.Enumerated.valueOf(actionString.toUpperCase()); } catch (IllegalArgumentException iae) { Optional<String> allowedValues = Arrays.stream(Action.Enumerated.values()) .map((a) -> a.name().toLowerCase() + " ") .reduce(String::concat); session.getAsyncRemote().sendText("Unknown action: " + actionString + ", allowed values: " + allowedValues.get()); closeSession(session); return; } Action<?, ?> action = actionEnumItem.getAction(); final Subscription subscription = inventory.observable(Interest.in(cls).being(action)) .filter(RestEvents.getFilter(action, tenantId)) .subscribe((x) -> { try { session.getAsyncRemote().sendText(mapper.writeValueAsString(x)); } catch (JsonProcessingException e) { session.getAsyncRemote().sendText("Unable to serialize JSON."); WebsocketApiLogger.LOGGER.serializationFailed(e); closeSession(session); } }); subscriptions.put(session, subscription); } @OnClose public void close(Session session) { WebsocketApiLogger.LOGGER.sessionClosed(session.getId()); Subscription subscription = subscriptions.get(session); if (subscription != null && !subscription.isUnsubscribed()) { subscription.unsubscribe(); } } @OnError public void onError(Throwable error) { WebsocketApiLogger.LOGGER.errorHappened(error); } @OnMessage public void handleMessage(String message, Session session) { WebsocketApiLogger.LOGGER.onMessage(session.getId(), message); } private void closeSession(Session session) { try { session.close(); } catch (IOException exception) { WebsocketApiLogger.LOGGER.sessionCloseFailed(exception); } } private Map<String, String> parseQueryParams(Session session) { Map<String, String> retMap = Maps.newHashMap(); String query = session.getQueryString(); if (query != null) { String[] params = query.split("&"); for (String param : params) { String[] nameval = param.split("="); retMap.put(nameval[0], nameval[1]); } } return retMap; } public static Map<String, String> getQueryMap(String query) { Map<String, String> map = Maps.newHashMap(); if (query != null) { String[] params = query.split("&"); for (String param : params) { String[] nameval = param.split("="); map.put(nameval[0], nameval[1]); } } return map; } private enum QueryParam { tenantId, type("resource"), action("created"); private String defaultValue; QueryParam() { this(null); } QueryParam(String defaultValue) { this.defaultValue = defaultValue; } public String getDefaultValue() { return defaultValue; } } }